Skip to content

Commit 2b92dd1

Browse files
authored
Merge pull request #10145 from jimingham/alloc_init-step
Handle stepping through language thunks that call other functions than the target
2 parents 8535cf3 + 72acc23 commit 2b92dd1

File tree

7 files changed

+129
-8
lines changed

7 files changed

+129
-8
lines changed

lldb/include/lldb/Target/ThreadPlanShouldStopHere.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class ThreadPlanShouldStopHere {
5959
eNone = 0,
6060
eAvoidInlines = (1 << 0),
6161
eStepInAvoidNoDebug = (1 << 1),
62-
eStepOutAvoidNoDebug = (1 << 2)
62+
eStepOutAvoidNoDebug = (1 << 2),
63+
eStepOutPastThunks = (1 << 3)
6364
};
6465

6566
// Constructors and Destructors

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,9 +525,12 @@ static lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
525525
GetThunkKindName(thunk_kind));
526526
AddressRange sym_addr_range(sc.symbol->GetAddress(),
527527
sc.symbol->GetByteSize());
528-
return std::make_shared<ThreadPlanStepInRange>(thread, sym_addr_range, sc,
528+
ThreadPlanSP new_plan_sp = std::make_shared<ThreadPlanStepInRange>(thread, sym_addr_range, sc,
529529
nullptr, eOnlyDuringStepping,
530530
eLazyBoolNo, eLazyBoolNo);
531+
static_cast<ThreadPlanStepInRange *>(new_plan_sp.get())
532+
->GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutPastThunks);
533+
return new_plan_sp;
531534
}
532535
}
533536

lldb/source/Target/ThreadPlanShouldStopHere.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "lldb/Target/ThreadPlanShouldStopHere.h"
1010
#include "lldb/Symbol/Function.h"
1111
#include "lldb/Symbol/Symbol.h"
12+
#include "lldb/Target/Language.h"
1213
#include "lldb/Target/LanguageRuntime.h"
1314
#include "lldb/Target/Process.h"
1415
#include "lldb/Target/RegisterContext.h"
@@ -86,8 +87,14 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
8687
if (symbol) {
8788
ProcessSP process_sp(current_plan->GetThread().GetProcess());
8889
for (auto *runtime : process_sp->GetLanguageRuntimes()) {
89-
if (runtime->IsSymbolARuntimeThunk(*symbol))
90+
if (runtime->IsSymbolARuntimeThunk(*symbol) &&
91+
flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) {
92+
LLDB_LOGF(
93+
log, "Stepping out past a language thunk %s for: %s",
94+
frame->GetFunctionName(),
95+
Language::GetNameForLanguageType(runtime->GetLanguageType()));
9096
should_stop_here = false;
97+
}
9198
}
9299
}
93100
}
@@ -139,11 +146,14 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
139146
if (sc.symbol) {
140147
ProcessSP process_sp(current_plan->GetThread().GetProcess());
141148
for (auto *runtime : process_sp->GetLanguageRuntimes()) {
142-
if (runtime->IsSymbolARuntimeThunk(*sc.symbol)) {
143-
if (log)
144-
log->Printf("In runtime thunk %s - stepping out.",
145-
sc.symbol->GetName().GetCString());
149+
if (runtime->IsSymbolARuntimeThunk(*sc.symbol) &&
150+
flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) {
151+
LLDB_LOGF(
152+
log, "Stepping out past a language thunk %s for: %s",
153+
frame->GetFunctionName(),
154+
Language::GetNameForLanguageType(runtime->GetLanguageType()));
146155
just_step_out = true;
156+
break;
147157
}
148158
}
149159
// If the whole function is marked line 0 just step out, that's easier &

lldb/source/Target/ThreadPlanStepInRange.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ using namespace lldb;
2929
using namespace lldb_private;
3030

3131
uint32_t ThreadPlanStepInRange::s_default_flag_values =
32-
ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
32+
ThreadPlanShouldStopHere::eStepInAvoidNoDebug |
33+
ThreadPlanShouldStopHere::eStepOutPastThunks;
3334

3435
// ThreadPlanStepInRange: Step through a stack range, either stepping over or
3536
// into based on the value of \a type.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SWIFT_SOURCES := main.swift
2+
include Makefile.rules
3+
4+
cleanup:
5+
rm -f Makefile *.d
6+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
import lldbsuite.test.lldbtest as lldbtest
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import os
6+
import platform
7+
8+
class TestStepThroughAllocatingInit(lldbtest.TestBase):
9+
mydir = lldbtest.TestBase.compute_mydir(__file__)
10+
11+
@swiftTest
12+
def test_swift_stepping_api(self):
13+
"""Test that step in using the Python API steps through thunk."""
14+
self.build()
15+
self.do_test(True)
16+
17+
@swiftTest
18+
def test_swift_stepping_cli(self):
19+
"""Same test with the cli - it goes a slightly different path than
20+
the API."""
21+
self.build()
22+
self.do_test(False)
23+
24+
def setUp(self):
25+
lldbtest.TestBase.setUp(self)
26+
self.main_source = "main.swift"
27+
self.main_source_spec = lldb.SBFileSpec(self.main_source)
28+
# If you are running against a debug swift you are going to
29+
# end up stepping into the stdlib and that will make stepping
30+
# tests impossible to write. So avoid that.
31+
32+
if platform.system() == 'Darwin':
33+
lib_name = "libswiftCore.dylib"
34+
else:
35+
lib_name = "libswiftCore.so"
36+
37+
self.dbg.HandleCommand(
38+
"settings set "
39+
"target.process.thread.step-avoid-libraries {}".format(lib_name))
40+
41+
def do_test(self, use_api):
42+
"""Tests that we can step reliably in swift code."""
43+
exe_name = "a.out"
44+
exe = self.getBuildArtifact(exe_name)
45+
46+
target, process, thread, breakpoint = lldbutil.run_to_source_breakpoint(self,
47+
'Break here to step into init', self.main_source_spec)
48+
49+
# Step into the function.
50+
if use_api:
51+
thread.StepInto()
52+
else:
53+
self.runCmd("thread step-in")
54+
frame_0 = thread.frames[0]
55+
self.assertIn('Foo.init()', frame_0.GetFunctionName())
56+
57+
# Check that our parent frame is indeed allocating_init (otherwise we aren't
58+
# testing what we think we're testing...
59+
frame_1 = thread.frames[1]
60+
self.assertIn("allocating_init", frame_1.GetFunctionName())
61+
62+
# Step one line so some_string is initialized, make sure we can
63+
# get its value:
64+
if use_api:
65+
thread.StepOver()
66+
else:
67+
self.runCmd("thread step-over")
68+
69+
frame_0 = thread.frames[0]
70+
self.assertIn('Foo.init()', frame_0.GetFunctionName())
71+
var = frame_0.FindVariable("some_string")
72+
self.assertTrue(var.GetError().Success())
73+
self.assertEqual(var.GetSummary(), '"foo"')
74+
75+
# Now make sure that stepping out steps past the thunk:
76+
if use_api:
77+
thread.StepOut()
78+
else:
79+
self.runCmd("thread step-out")
80+
81+
frame_0 = thread.frames[0]
82+
self.assertIn("doSomething", frame_0.GetFunctionName())
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class Foo {
2+
init() {
3+
let some_string = "foo"
4+
print(some_string)
5+
}
6+
}
7+
8+
func bar(_ _: Foo) {
9+
print("bar")
10+
}
11+
12+
func doSomething()
13+
{
14+
let f = Foo() // Break here to step into init
15+
bar(f)
16+
}
17+
18+
doSomething()

0 commit comments

Comments
 (0)