yinghuitan created this revision.
yinghuitan added reviewers: clayborg, labath, jingham, jdoerfert, JDevlieghere, 
aadsm, kusmour, fixathon.
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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D135798

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.h
  lldb/tools/lldb-vscode/lldb-vscode.cpp

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,81 @@
                                  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");
+    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");
+    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");
+    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 place the breakpoint");
+    return error;
+  }
+  entry_breakpoint.SetOneShot(true);
+
+  // Holder class to ensure async flag is restored during unwinding.
+  class DebuggerAsyncFlagHolder {
+    bool m_old_async_flag;
+  public:
+    DebuggerAsyncFlagHolder() {
+      m_old_async_flag = g_vsc.debugger.GetAsync();
+    }
+
+    ~DebuggerAsyncFlagHolder() {
+      g_vsc.debugger.SetAsync(m_old_async_flag);
+    }
+  };
+
+  // Synchronously run to binary entry one time breakpoint and scoped to restore
+  // the async flag.
+  {
+    DebuggerAsyncFlagHolder _asyncFlagHolder;
+    g_vsc.debugger.SetAsync(false);
+    error = target.GetProcess().Continue();
+    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::Console,
+                     "RunToBinaryEntry failed: process stopped not at the "
+                     "binary's entry point");
+  else
+    g_vsc.SendOutput(OutputType::Console,
+                     "RunToBinaryEntry success: Process stopped successfully "
+                     "at the binary's entry point");
+  return error;
+}
+
 // "LaunchRequest": {
 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
 //     "type": "object",
@@ -1659,6 +1734,7 @@
   std::vector<std::string> 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);
 
@@ -1741,6 +1817,9 @@
     error = g_vsc.WaitForProcessToStop(timeout_seconds);
   }
 
+  if (error.Success())
+    error = RunToBinaryEntry();
+
   if (error.Fail()) {
     response["success"] = llvm::json::Value(false);
     EmplaceSafeString(response, "message", std::string(error.GetCString()));
Index: lldb/tools/lldb-vscode/VSCode.h
===================================================================
--- lldb/tools/lldb-vscode/VSCode.h
+++ lldb/tools/lldb-vscode/VSCode.h
@@ -144,6 +144,7 @@
   lldb::tid_t focus_tid;
   bool sent_terminated_event;
   bool stop_at_entry;
+  bool run_to_binary_entry = false;
   bool is_attach;
   bool configuration_done_sent;
   uint32_t reverse_request_seq;
Index: lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py
===================================================================
--- lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py
+++ lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py
@@ -78,6 +78,29 @@
                         reason != 'breakpoint',
                         'verify stop isn\'t "main" breakpoint')
 
+    @skipIfWindows
+    @skipIfRemote
+    def test_runToBinaryEntry(self):
+        '''
+            Tests the runToBinaryEntry option can successfully launch a simple
+            program and hit a breakpoint and does not interupt the launch.
+        '''
+        program = self.getBuildArtifact("a.out")
+        self.build_and_launch(program, runToBinaryEntry=True)
+        self.set_function_breakpoints(['main'])
+        stopped_events = self.continue_to_next_stop()
+        console_output = self.get_console()
+        self.assertIn("Process stopped successfully at the binary's entry point", console_output)
+
+        for stopped_event in stopped_events:
+            if 'body' in stopped_event:
+                body = stopped_event['body']
+                if 'reason' in body:
+                    reason = body['reason']
+                    self.assertTrue(
+                        reason == 'breakpoint',
+                        'verify successfully stop at "main" breakpoint')
+
     @skipIfWindows
     @skipIfRemote
     def test_cwd(self):
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
@@ -644,7 +644,7 @@
                        terminateCommands=None ,sourcePath=None,
                        debuggerRoot=None, launchCommands=None, sourceMap=None,
                        runInTerminal=False, expectFailure=False,
-                       postRunCommands=None):
+                       postRunCommands=None, runToBinaryEntry=False):
         args_dict = {
             'program': program
         }
@@ -656,6 +656,8 @@
             args_dict['env'] = env
         if stopOnEntry:
             args_dict['stopOnEntry'] = stopOnEntry
+        if runToBinaryEntry:
+            args_dict['runToBinaryEntry'] = runToBinaryEntry
         if disableASLR:
             args_dict['disableASLR'] = disableASLR
         if disableSTDIO:
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
@@ -286,7 +286,7 @@
                stopCommands=None, exitCommands=None, terminateCommands=None,
                sourcePath=None, debuggerRoot=None, sourceInitFile=False, launchCommands=None,
                sourceMap=None, disconnectAutomatically=True, runInTerminal=False,
-               expectFailure=False, postRunCommands=None):
+               expectFailure=False, postRunCommands=None, runToBinaryEntry=False):
         '''Sending launch request to vscode
         '''
 
@@ -323,7 +323,8 @@
             sourceMap=sourceMap,
             runInTerminal=runInTerminal,
             expectFailure=expectFailure,
-            postRunCommands=postRunCommands)
+            postRunCommands=postRunCommands,
+            runToBinaryEntry=runToBinaryEntry)
 
         if expectFailure:
             return response
@@ -346,7 +347,7 @@
                          terminateCommands=None, sourcePath=None,
                          debuggerRoot=None, sourceInitFile=False, runInTerminal=False,
                          disconnectAutomatically=True, postRunCommands=None,
-                         lldbVSCodeEnv=None):
+                         lldbVSCodeEnv=None, runToBinaryEntry=False):
         '''Build the default Makefile target, create the VSCode debug adaptor,
            and launch the process.
         '''
@@ -359,4 +360,5 @@
                     terminateCommands, sourcePath, debuggerRoot, sourceInitFile,
                     runInTerminal=runInTerminal,
                     disconnectAutomatically=disconnectAutomatically,
-                    postRunCommands=postRunCommands)
+                    postRunCommands=postRunCommands,
+                    runToBinaryEntry=runToBinaryEntry)
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to