Skip to content

Control the "step out through thunk" logic explicitly when pushing thread plans #129301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 28, 2025

Conversation

jimingham
Copy link
Collaborator

Jonas recently added a trampoline handling strategy for simple language thunks that does: "step through language thunks stepping in one level deep and stopping if you hit user code". That was actually pulled over from the swift implementation. However, this strategy and the strategy we have to "step out past language thunks" when stepping out come into conflict if the thunk you are stepping through calls some other function before dispatching to the intended method. When you step out of the called function back into the thunk, should you keep stepping out past the thunk or not?

In most cases, you want to step out past the thunk, but in this particular case you don't.

This patch adds a way to inform the thread plan (or really it's ShouldStopHere behavior) of which behavior it should have, and passes the don't step through thunks to the step through plan it uses to step through thunks.

I didn't add a test for this because I couldn't find a C++ thunk that calls another function before getting to the target function. I asked the clang folks here if they could think of a case where clang would do this, and they couldn't. If anyone can think of such a construct, it will be easy to write the step through test for it...

This does happen in swift, however, so when I cherry-pick this to the swift fork I'll test it there.

…read plans.

That allow the thread plan that is trying to step through a thunk to its target
to step out of a function it has stepped into without also stepping out past
the thunk we were trying to step through.
@jimingham jimingham requested review from medismailben and removed request for JDevlieghere February 28, 2025 20:25
@llvmbot llvmbot added the lldb label Feb 28, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 28, 2025

@llvm/pr-subscribers-lldb

Author: None (jimingham)

Changes

Jonas recently added a trampoline handling strategy for simple language thunks that does: "step through language thunks stepping in one level deep and stopping if you hit user code". That was actually pulled over from the swift implementation. However, this strategy and the strategy we have to "step out past language thunks" when stepping out come into conflict if the thunk you are stepping through calls some other function before dispatching to the intended method. When you step out of the called function back into the thunk, should you keep stepping out past the thunk or not?

In most cases, you want to step out past the thunk, but in this particular case you don't.

This patch adds a way to inform the thread plan (or really it's ShouldStopHere behavior) of which behavior it should have, and passes the don't step through thunks to the step through plan it uses to step through thunks.

I didn't add a test for this because I couldn't find a C++ thunk that calls another function before getting to the target function. I asked the clang folks here if they could think of a case where clang would do this, and they couldn't. If anyone can think of such a construct, it will be easy to write the step through test for it...

This does happen in swift, however, so when I cherry-pick this to the swift fork I'll test it there.


Full diff: https://github.com/llvm/llvm-project/pull/129301.diff

3 Files Affected:

  • (modified) lldb/include/lldb/Target/ThreadPlanShouldStopHere.h (+2-1)
  • (modified) lldb/source/Target/ThreadPlanShouldStopHere.cpp (+11-4)
  • (modified) lldb/source/Target/ThreadPlanStepInRange.cpp (+2-1)
diff --git a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
index 54b30291c3995..d0094c90b91a5 100644
--- a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
+++ b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
@@ -59,7 +59,8 @@ class ThreadPlanShouldStopHere {
     eNone = 0,
     eAvoidInlines = (1 << 0),
     eStepInAvoidNoDebug = (1 << 1),
-    eStepOutAvoidNoDebug = (1 << 2)
+    eStepOutAvoidNoDebug = (1 << 2),
+    eStepOutPastThunks = (1 << 3)
   };
 
   // Constructors and Destructors
diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
index fa6bc08a9914d..be6bd981c72bc 100644
--- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp
+++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
@@ -8,6 +8,7 @@
 
 #include "lldb/Target/ThreadPlanShouldStopHere.h"
 #include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Language.h"
 #include "lldb/Target/LanguageRuntime.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/Thread.h"
@@ -83,7 +84,11 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
     if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) {
       ProcessSP process_sp(current_plan->GetThread().GetProcess());
       for (auto *runtime : process_sp->GetLanguageRuntimes()) {
-        if (runtime->IsSymbolARuntimeThunk(*symbol)) {
+        if (runtime->IsSymbolARuntimeThunk(*symbol)
+             && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) {
+         LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s",
+                   frame->GetFunctionName(),
+                   Language::GetNameForLanguageType(runtime->GetLanguageType()));
           should_stop_here = false;
           break;
         }
@@ -131,9 +136,11 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
       // because it's marked line 0.
       bool is_thunk = false;
       for (auto *runtime : process_sp->GetLanguageRuntimes()) {
-        if (runtime->IsSymbolARuntimeThunk(*sc.symbol)) {
-          LLDB_LOGF(log, "In runtime thunk %s - stepping out.",
-                    sc.symbol->GetName().GetCString());
+        if (runtime->IsSymbolARuntimeThunk(*sc.symbol)
+             && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) {
+          LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s",
+                   frame->GetFunctionName(),
+                   Language::GetNameForLanguageType(runtime->GetLanguageType()));
           is_thunk = true;
           break;
         }
diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp
index 109d1b6b3435b..3affeae1ee388 100644
--- a/lldb/source/Target/ThreadPlanStepInRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -27,7 +27,8 @@ using namespace lldb;
 using namespace lldb_private;
 
 uint32_t ThreadPlanStepInRange::s_default_flag_values =
-    ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
+    ThreadPlanShouldStopHere::eStepInAvoidNoDebug | 
+    ThreadPlanShouldStopHere::eStepOutPastThunks;
 
 // ThreadPlanStepInRange: Step through a stack range, either stepping over or
 // into based on the value of \a type.

Copy link

github-actions bot commented Feb 28, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@felipepiovezan felipepiovezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@jimingham jimingham merged commit ddbce2f into llvm:main Feb 28, 2025
6 of 9 checks passed
@jimingham jimingham deleted the thunk-step-out branch February 28, 2025 21:44
@medismailben
Copy link
Member

Sorry for the delay, LGTM

jimingham added a commit to jimingham/from-apple-llvm-project that referenced this pull request Mar 1, 2025
…read plans (llvm#129301)

Jonas recently added a trampoline handling strategy for simple language
thunks that does: "step through language thunks stepping in one level
deep and stopping if you hit user code". That was actually pulled over
from the swift implementation. However, this strategy and the strategy
we have to "step out past language thunks" when stepping out come into
conflict if the thunk you are stepping through calls some other function
before dispatching to the intended method. When you step out of the
called function back into the thunk, should you keep stepping out past
the thunk or not?

In most cases, you want to step out past the thunk, but in this
particular case you don't.

This patch adds a way to inform the thread plan (or really it's
ShouldStopHere behavior) of which behavior it should have, and passes
the don't step through thunks to the step through plan it uses to step
through thunks.

I didn't add a test for this because I couldn't find a C++ thunk that
calls another function before getting to the target function. I asked
the clang folks here if they could think of a case where clang would do
this, and they couldn't. If anyone can think of such a construct, it
will be easy to write the step through test for it...

This does happen in swift, however, so when I cherry-pick this to the
swift fork I'll test it there.

(cherry picked from commit ddbce2f)
jimingham added a commit to swiftlang/llvm-project that referenced this pull request Mar 6, 2025
…read plans (llvm#129301)

Jonas recently added a trampoline handling strategy for simple language
thunks that does: "step through language thunks stepping in one level
deep and stopping if you hit user code". That was actually pulled over
from the swift implementation. However, this strategy and the strategy
we have to "step out past language thunks" when stepping out come into
conflict if the thunk you are stepping through calls some other function
before dispatching to the intended method. When you step out of the
called function back into the thunk, should you keep stepping out past
the thunk or not?

In most cases, you want to step out past the thunk, but in this
particular case you don't.

This patch adds a way to inform the thread plan (or really it's
ShouldStopHere behavior) of which behavior it should have, and passes
the don't step through thunks to the step through plan it uses to step
through thunks.

I didn't add a test for this because I couldn't find a C++ thunk that
calls another function before getting to the target function. I asked
the clang folks here if they could think of a case where clang would do
this, and they couldn't. If anyone can think of such a construct, it
will be easy to write the step through test for it...

This does happen in swift, however, so when I cherry-pick this to the
swift fork I'll test it there.

(cherry picked from commit ddbce2f)
(cherry picked from commit 169fb46)
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
…read plans (llvm#129301)

Jonas recently added a trampoline handling strategy for simple language
thunks that does: "step through language thunks stepping in one level
deep and stopping if you hit user code". That was actually pulled over
from the swift implementation. However, this strategy and the strategy
we have to "step out past language thunks" when stepping out come into
conflict if the thunk you are stepping through calls some other function
before dispatching to the intended method. When you step out of the
called function back into the thunk, should you keep stepping out past
the thunk or not?

In most cases, you want to step out past the thunk, but in this
particular case you don't.

This patch adds a way to inform the thread plan (or really it's
ShouldStopHere behavior) of which behavior it should have, and passes
the don't step through thunks to the step through plan it uses to step
through thunks.

I didn't add a test for this because I couldn't find a C++ thunk that
calls another function before getting to the target function. I asked
the clang folks here if they could think of a case where clang would do
this, and they couldn't. If anyone can think of such a construct, it
will be easy to write the step through test for it...

This does happen in swift, however, so when I cherry-pick this to the
swift fork I'll test it there.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants