yinghuitan created this revision.
yinghuitan added reviewers: clayborg, labath, jingham, jdoerfert, JDevlieghere,
kusmour, GeorgeHuyubo.
Herald added a project: All.
yinghuitan requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
This patch adds a new runToBinaryEntry option which sets a one-shot breakpoint
at program entry. This option is useful for synchronizing module loading with
dynamic loader to measure debugger startup performance: when program entry
one-short breakpoint hits most of the dependency modules should have been
loaded so this provides a good sample point for debugger startup time.
More explicitly for lldb-vscode, when this option is enabled, "Initialized" DAP
event is synchronously sent after most dependency modules are loaded.
Note: this is re-submission of https://reviews.llvm.org/D135798
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D138589
Files:
lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py
lldb/tools/lldb-vscode/VSCode.cpp
lldb/tools/lldb-vscode/VSCode.h
lldb/tools/lldb-vscode/lldb-vscode.cpp
lldb/tools/lldb-vscode/package.json
Index: lldb/tools/lldb-vscode/package.json
===
--- lldb/tools/lldb-vscode/package.json
+++ lldb/tools/lldb-vscode/package.json
@@ -157,6 +157,11 @@
"description": "Automatically stop after launch.",
"default": false
},
+ "runToBinaryEntry": {
+"type": "boolean",
+"description": "run to program entry one-shot breakpoint during launch to ensure dependency modules are loaded.",
+"default": false
+ },
"disableASLR": {
"type": "boolean",
"description": "Enable or disable Address space layout randomization if the debugger supports it.",
Index: lldb/tools/lldb-vscode/lldb-vscode.cpp
===
--- lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -1610,6 +1610,68 @@
error.GetCString());
}
+lldb::SBError RunToBinaryEntry() {
+ lldb::SBError error;
+ if (!g_vsc.run_to_binary_entry)
+return error;
+
+ if (g_vsc.stop_at_entry) {
+g_vsc.SendOutput(OutputType::Console,
+ "RunToBinaryEntry is ignored due to StopOnEntry\n");
+return error;
+ }
+
+ lldb::SBTarget target = g_vsc.debugger.GetSelectedTarget();
+ if (!target.IsValid())
+return error;
+ lldb::SBFileSpec exe_file = target.GetExecutable();
+ if (!exe_file.IsValid())
+return error;
+ lldb::SBModule exe_module = target.FindModule(exe_file);
+ if (!exe_module.IsValid()) {
+g_vsc.SendOutput(OutputType::Console,
+ "RunToBinaryEntry failed: invalid executable module\n");
+return error;
+ }
+
+ lldb::SBAddress entry_point = exe_module.GetObjectFileEntryPointAddress();
+ if (!entry_point.IsValid()) {
+g_vsc.SendOutput(OutputType::Console,
+ "RunToBinaryEntry failed: can't find entry point\n");
+return error;
+ }
+ lldb::SBBreakpoint entry_breakpoint =
+ target.BreakpointCreateBySBAddress(entry_point);
+ if (!entry_breakpoint.IsValid() || entry_breakpoint.GetNumLocations() == 0) {
+g_vsc.SendOutput(OutputType::Console,
+ "RunToBinaryEntry failed: can't resolve the entry point breakpoint\n");
+return error;
+ }
+
+ uint32_t old_stop_id = target.GetProcess().GetStopID();
+ entry_breakpoint.SetOneShot(true);
+ error = target.GetProcess().Continue();
+ if (error.Fail())
+return error;
+
+ const uint64_t timeout_seconds = 600;
+ error = g_vsc.WaitForProcessToStop(timeout_seconds, old_stop_id);
+ if (error.Fail())
+return error;
+
+ // Successfully got a process stop; we still need to check if the stop is what
+ // we expected.
+ if (entry_breakpoint.GetHitCount() == 0)
+g_vsc.SendOutput(OutputType::Telemetry,
+ "RunToBinaryEntry failed: process stopped not at the "
+ "binary's entry point\n");
+ else
+g_vsc.SendOutput(OutputType::Telemetry,
+ "RunToBinaryEntry success: Process stopped successfully "
+ "at the binary's entry point\n");
+ return error;
+}
+
// "LaunchRequest": {
// "allOf": [ { "$ref": "#/definitions/Request" }, {
// "type": "object",
@@ -1659,6 +1721,7 @@
std::vector postRunCommands =
GetStrings(arguments, "postRunCommands");
g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
+ g_vsc.run_to_binary_entry = GetBoolean(arguments, "runToBinaryEntry", false);
const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot");
const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30);