Skip to content

Commit 7aa60d7

Browse files
ylndvbuka
authored andcommitted
[lldb] Introduce internal stop hooks (llvm#164506)
Introduce the concept of internal stop hooks. These are similar to LLDB's internal breakpoints: LLDB itself will add them and users of LLDB will not be able to add or remove them. This change adds the following 3 independently-useful concepts: * Maintain a list of internal stop hooks that will be populated by LLDB and cannot be added to or removed from by users. They are managed in a separate list in `Target::m_internal_stop_hooks`. * `StopHookKind:CodeBased` and `StopHookCoded` represent a stop hook defined by a C++ code callback (instead of command line expressions or a Python class). * Stop hooks that do not print any output can now also suppress the printing of their header and description when they are hit via `StopHook::GetSuppressOutput`. Combining these 3 concepts we can model "internal stop hooks" which serve the same function as LLDB's internal breakpoints: executing built-in, LLDB-defined behavior, leveraging the existing mechanism of stop hooks. This change also simplifies `Target::RunStopHooks`. We already have to materialize a new list for combining internal and user stop hooks. Filter and only add active hooks to this list to avoid the need for "isActive?" checks later on.
1 parent a2c6645 commit 7aa60d7

File tree

7 files changed

+241
-68
lines changed

7 files changed

+241
-68
lines changed

lldb/include/lldb/Target/Target.h

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,7 +1356,11 @@ class Target : public std::enable_shared_from_this<Target>,
13561356
StopHook(const StopHook &rhs);
13571357
virtual ~StopHook() = default;
13581358

1359-
enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased };
1359+
enum class StopHookKind : uint32_t {
1360+
CommandBased = 0,
1361+
ScriptBased,
1362+
CodeBased,
1363+
};
13601364
enum class StopHookResult : uint32_t {
13611365
KeepStopped = 0,
13621366
RequestContinue,
@@ -1403,6 +1407,12 @@ class Target : public std::enable_shared_from_this<Target>,
14031407

14041408
bool GetRunAtInitialStop() const { return m_at_initial_stop; }
14051409

1410+
void SetSuppressOutput(bool suppress_output) {
1411+
m_suppress_output = suppress_output;
1412+
}
1413+
1414+
bool GetSuppressOutput() const { return m_suppress_output; }
1415+
14061416
void GetDescription(Stream &s, lldb::DescriptionLevel level) const;
14071417
virtual void GetSubclassDescription(Stream &s,
14081418
lldb::DescriptionLevel level) const = 0;
@@ -1414,6 +1424,7 @@ class Target : public std::enable_shared_from_this<Target>,
14141424
bool m_active = true;
14151425
bool m_auto_continue = false;
14161426
bool m_at_initial_stop = true;
1427+
bool m_suppress_output = false;
14171428

14181429
StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid);
14191430
};
@@ -1433,8 +1444,8 @@ class Target : public std::enable_shared_from_this<Target>,
14331444

14341445
private:
14351446
StringList m_commands;
1436-
// Use CreateStopHook to make a new empty stop hook. The GetCommandPointer
1437-
// and fill it with commands, and SetSpecifier to set the specifier shared
1447+
// Use CreateStopHook to make a new empty stop hook. Use SetActionFromString
1448+
// to fill it with commands, and SetSpecifier to set the specifier shared
14381449
// pointer (can be null, that will match anything.)
14391450
StopHookCommandLine(lldb::TargetSP target_sp, lldb::user_id_t uid)
14401451
: StopHook(target_sp, uid) {}
@@ -1460,19 +1471,56 @@ class Target : public std::enable_shared_from_this<Target>,
14601471
StructuredDataImpl m_extra_args;
14611472
lldb::ScriptedStopHookInterfaceSP m_interface_sp;
14621473

1463-
/// Use CreateStopHook to make a new empty stop hook. The GetCommandPointer
1464-
/// and fill it with commands, and SetSpecifier to set the specifier shared
1465-
/// pointer (can be null, that will match anything.)
1474+
/// Use CreateStopHook to make a new empty stop hook. Use SetScriptCallback
1475+
/// to set the script to execute, and SetSpecifier to set the specifier
1476+
/// shared pointer (can be null, that will match anything.)
14661477
StopHookScripted(lldb::TargetSP target_sp, lldb::user_id_t uid)
14671478
: StopHook(target_sp, uid) {}
14681479
friend class Target;
14691480
};
14701481

1482+
class StopHookCoded : public StopHook {
1483+
public:
1484+
~StopHookCoded() override = default;
1485+
1486+
using HandleStopCallback = StopHookResult(ExecutionContext &exc_ctx,
1487+
lldb::StreamSP output);
1488+
1489+
void SetCallback(llvm::StringRef name, HandleStopCallback *callback) {
1490+
m_name = name;
1491+
m_callback = callback;
1492+
}
1493+
1494+
StopHookResult HandleStop(ExecutionContext &exc_ctx,
1495+
lldb::StreamSP output) override {
1496+
return m_callback(exc_ctx, output);
1497+
}
1498+
1499+
void GetSubclassDescription(Stream &s,
1500+
lldb::DescriptionLevel level) const override {
1501+
s.Indent();
1502+
s.Printf("%s (built-in)\n", m_name.c_str());
1503+
}
1504+
1505+
private:
1506+
std::string m_name;
1507+
HandleStopCallback *m_callback;
1508+
1509+
/// Use CreateStopHook to make a new empty stop hook. Use SetCallback to set
1510+
/// the callback to execute, and SetSpecifier to set the specifier shared
1511+
/// pointer (can be null, that will match anything.)
1512+
StopHookCoded(lldb::TargetSP target_sp, lldb::user_id_t uid)
1513+
: StopHook(target_sp, uid) {}
1514+
friend class Target;
1515+
};
1516+
1517+
void RegisterInternalStopHooks();
1518+
14711519
typedef std::shared_ptr<StopHook> StopHookSP;
14721520

14731521
/// Add an empty stop hook to the Target's stop hook list, and returns a
1474-
/// shared pointer to it in new_hook. Returns the id of the new hook.
1475-
StopHookSP CreateStopHook(StopHook::StopHookKind kind);
1522+
/// shared pointer to the new hook.
1523+
StopHookSP CreateStopHook(StopHook::StopHookKind kind, bool internal = false);
14761524

14771525
/// If you tried to create a stop hook, and that failed, call this to
14781526
/// remove the stop hook, as it will also reset the stop hook counter.
@@ -1484,8 +1532,6 @@ class Target : public std::enable_shared_from_this<Target>,
14841532
// control over the process for the first time.
14851533
bool RunStopHooks(bool at_initial_stop = false);
14861534

1487-
size_t GetStopHookSize();
1488-
14891535
bool SetSuppresStopHooks(bool suppress) {
14901536
bool old_value = m_suppress_stop_hooks;
14911537
m_suppress_stop_hooks = suppress;
@@ -1504,19 +1550,7 @@ class Target : public std::enable_shared_from_this<Target>,
15041550

15051551
void SetAllStopHooksActiveState(bool active_state);
15061552

1507-
size_t GetNumStopHooks() const { return m_stop_hooks.size(); }
1508-
1509-
StopHookSP GetStopHookAtIndex(size_t index) {
1510-
if (index >= GetNumStopHooks())
1511-
return StopHookSP();
1512-
StopHookCollection::iterator pos = m_stop_hooks.begin();
1513-
1514-
while (index > 0) {
1515-
pos++;
1516-
index--;
1517-
}
1518-
return (*pos).second;
1519-
}
1553+
const std::vector<StopHookSP> GetStopHooks(bool internal = false) const;
15201554

15211555
lldb::PlatformSP GetPlatform() { return m_platform_sp; }
15221556

@@ -1656,6 +1690,7 @@ class Target : public std::enable_shared_from_this<Target>,
16561690
typedef std::map<lldb::user_id_t, StopHookSP> StopHookCollection;
16571691
StopHookCollection m_stop_hooks;
16581692
lldb::user_id_t m_stop_hook_next_id;
1693+
std::vector<StopHookSP> m_internal_stop_hooks;
16591694
uint32_t m_latest_stop_hook_id; /// This records the last natural stop at
16601695
/// which we ran a stop-hook.
16611696
bool m_valid;

lldb/source/Commands/CommandCompletions.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -777,13 +777,11 @@ void CommandCompletions::StopHookIDs(CommandInterpreter &interpreter,
777777
if (!target_sp)
778778
return;
779779

780-
const size_t num = target_sp->GetNumStopHooks();
781-
for (size_t idx = 0; idx < num; ++idx) {
780+
for (auto &stophook_sp : target_sp->GetStopHooks()) {
782781
StreamString strm;
783782
// The value 11 is an offset to make the completion description looks
784783
// neater.
785784
strm.SetIndentLevel(11);
786-
const Target::StopHookSP stophook_sp = target_sp->GetStopHookAtIndex(idx);
787785
stophook_sp->GetDescription(strm, lldb::eDescriptionLevelInitial);
788786
request.TryCompleteCurrentArg(std::to_string(stophook_sp->GetID()),
789787
strm.GetString());

lldb/source/Commands/CommandObjectBreakpoint.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,9 +1114,7 @@ class CommandObjectBreakpointList : public CommandObjectParsed {
11141114
CommandObjectBreakpointList(CommandInterpreter &interpreter)
11151115
: CommandObjectParsed(
11161116
interpreter, "breakpoint list",
1117-
"List some or all breakpoints at configurable levels of detail.",
1118-
nullptr) {
1119-
CommandArgumentData bp_id_arg;
1117+
"List some or all breakpoints at configurable levels of detail.") {
11201118

11211119
// Define the first (and only) variant of this arg.
11221120
AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional);

lldb/source/Commands/CommandObjectTarget.cpp

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5223,33 +5223,72 @@ class CommandObjectTargetStopHookEnableDisable : public CommandObjectParsed {
52235223
#pragma mark CommandObjectTargetStopHookList
52245224

52255225
// CommandObjectTargetStopHookList
5226+
#define LLDB_OPTIONS_target_stop_hook_list
5227+
#include "CommandOptions.inc"
52265228

52275229
class CommandObjectTargetStopHookList : public CommandObjectParsed {
52285230
public:
52295231
CommandObjectTargetStopHookList(CommandInterpreter &interpreter)
52305232
: CommandObjectParsed(interpreter, "target stop-hook list",
5231-
"List all stop-hooks.", "target stop-hook list") {}
5233+
"List all stop-hooks.") {}
52325234

52335235
~CommandObjectTargetStopHookList() override = default;
52345236

5237+
Options *GetOptions() override { return &m_options; }
5238+
5239+
class CommandOptions : public Options {
5240+
public:
5241+
CommandOptions() = default;
5242+
~CommandOptions() override = default;
5243+
5244+
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
5245+
ExecutionContext *execution_context) override {
5246+
Status error;
5247+
const int short_option = m_getopt_table[option_idx].val;
5248+
5249+
switch (short_option) {
5250+
case 'i':
5251+
m_internal = true;
5252+
break;
5253+
default:
5254+
llvm_unreachable("Unimplemented option");
5255+
}
5256+
5257+
return error;
5258+
}
5259+
5260+
void OptionParsingStarting(ExecutionContext *execution_context) override {
5261+
m_internal = false;
5262+
}
5263+
5264+
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
5265+
return llvm::ArrayRef(g_target_stop_hook_list_options);
5266+
}
5267+
5268+
// Instance variables to hold the values for command options.
5269+
bool m_internal = false;
5270+
};
5271+
52355272
protected:
52365273
void DoExecute(Args &command, CommandReturnObject &result) override {
52375274
Target &target = GetTarget();
52385275

5239-
size_t num_hooks = target.GetNumStopHooks();
5240-
if (num_hooks == 0) {
5241-
result.GetOutputStream().PutCString("No stop hooks.\n");
5242-
} else {
5243-
for (size_t i = 0; i < num_hooks; i++) {
5244-
Target::StopHookSP this_hook = target.GetStopHookAtIndex(i);
5245-
if (i > 0)
5246-
result.GetOutputStream().PutCString("\n");
5247-
this_hook->GetDescription(result.GetOutputStream(),
5248-
eDescriptionLevelFull);
5249-
}
5276+
bool printed_hook = false;
5277+
for (auto &hook : target.GetStopHooks(m_options.m_internal)) {
5278+
if (printed_hook)
5279+
result.GetOutputStream().PutCString("\n");
5280+
hook->GetDescription(result.GetOutputStream(), eDescriptionLevelFull);
5281+
printed_hook = true;
52505282
}
5283+
5284+
if (!printed_hook)
5285+
result.GetOutputStream().PutCString("No stop hooks.\n");
5286+
52515287
result.SetStatus(eReturnStatusSuccessFinishResult);
52525288
}
5289+
5290+
private:
5291+
CommandOptions m_options;
52535292
};
52545293

52555294
#pragma mark CommandObjectMultiwordTargetStopHooks

lldb/source/Commands/Options.td

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ let Command = "breakpoint list" in {
7777
// FIXME: We need to add an "internal" command, and then add this sort of
7878
// thing to it. But I need to see it for now, and don't want to wait.
7979
def blist_internal : Option<"internal", "i">,
80-
Desc<"Show debugger ${i}nternal breakpoints">;
80+
Desc<"Show debugger ${i}nternal breakpoints.">;
8181
def blist_brief : Option<"brief", "b">,
8282
Group<1>,
8383
Desc<"Give a ${b}rief description of the breakpoint (no "
@@ -1686,7 +1686,7 @@ let Command = "target modules lookup" in {
16861686
"match, if a best match is available.">;
16871687
}
16881688

1689-
let Command = "target stop hook add" in {
1689+
let Command = "target stop_hook add" in {
16901690
def target_stop_hook_add_one_liner
16911691
: Option<"one-liner", "o">,
16921692
GroupRange<1, 3>,
@@ -1762,6 +1762,12 @@ let Command = "target stop hook add" in {
17621762
"Defaults to true.">;
17631763
}
17641764

1765+
let Command = "target stop_hook list" in {
1766+
def target_stop_hook_list_internal
1767+
: Option<"internal", "i">,
1768+
Desc<"Show debugger ${i}nternal stop hooks.">;
1769+
}
1770+
17651771
let Command = "thread backtrace" in {
17661772
def thread_backtrace_count : Option<"count", "c">,
17671773
Group<1>,

0 commit comments

Comments
 (0)