Skip to content

Commit d0f5039

Browse files
committed
Reland "Add a test for evicting unreachable modules from the global module cache (llvm#74894)"
This reverts commit 35dacf2. And relands the original change with two additions so I can debug the failure on Arm/AArch64: * Enable lldb step logging in the tests. * Assert that the current plan is not the base plan at the spot I believe is calling PopPlan. These will be removed and replaced with a proper fix once I see some failures on the bots, I couldn't reproduce it locally. (also, no sign of it on the x86_64 bot)
1 parent 78accaf commit d0f5039

File tree

5 files changed

+191
-0
lines changed

5 files changed

+191
-0
lines changed

lldb/source/Target/Thread.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ bool Thread::ShouldStop(Event *event_ptr) {
831831
do {
832832
if (should_stop)
833833
current_plan->WillStop();
834+
assert(!current_plan->IsBasePlan() && "Cannot pop base plan!");
834835
PopPlan();
835836
} while ((current_plan = GetCurrentPlan()) != prev_plan_ptr);
836837
// Now, if the responsible plan was not "Okay to discard" then
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include Makefile.rules
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
"""
2+
Test the use of the global module cache in lldb
3+
"""
4+
5+
import lldb
6+
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
import os
11+
import shutil
12+
from pathlib import Path
13+
import time
14+
15+
class GlobalModuleCacheTestCase(TestBase):
16+
# NO_DEBUG_INFO_TESTCASE = True
17+
18+
def check_counter_var(self, thread, value):
19+
frame = thread.frames[0]
20+
var = frame.FindVariable("counter")
21+
self.assertTrue(var.GetError().Success(), "Got counter variable")
22+
self.assertEqual(var.GetValueAsUnsigned(), value, "This was one-print")
23+
24+
def copy_to_main(self, src, dst):
25+
# We are relying on the source file being newer than the .o file from
26+
# a previous build, so sleep a bit here to ensure that the touch is later.
27+
time.sleep(2)
28+
try:
29+
shutil.copy(src, dst)
30+
except:
31+
self.fail(f"Could not copy {src} to {dst}")
32+
Path(dst).touch()
33+
34+
# The rerun tests indicate rerunning on Windows doesn't really work, so
35+
# this one won't either.
36+
@skipIfWindows
37+
def test_OneTargetOneDebugger(self):
38+
self.do_test(True, True)
39+
40+
# This behaves as implemented but that behavior is not desirable.
41+
# This test tests for the desired behavior as an expected fail.
42+
@skipIfWindows
43+
@expectedFailureAll
44+
def test_TwoTargetsOneDebugger(self):
45+
self.do_test(False, True)
46+
47+
@skipIfWindows
48+
@expectedFailureAll
49+
def test_OneTargetTwoDebuggers(self):
50+
self.do_test(True, False)
51+
52+
def do_test(self, one_target, one_debugger):
53+
# Here to debug flakiness on Arm, remove later!
54+
log_cmd_result = lldb.SBCommandReturnObject()
55+
interp = self.dbg.GetCommandInterpreter()
56+
interp.HandleCommand("log enable lldb step", log_cmd_result)
57+
58+
# Make sure that if we have one target, and we run, then
59+
# change the binary and rerun, the binary (and any .o files
60+
# if using dwarf in .o file debugging) get removed from the
61+
# shared module cache. They are no longer reachable.
62+
debug_style = self.getDebugInfo()
63+
64+
# Before we do anything, clear the global module cache so we don't
65+
# see objects from other runs:
66+
lldb.SBDebugger.MemoryPressureDetected()
67+
68+
# Set up the paths for our two versions of main.c:
69+
main_c_path = os.path.join(self.getBuildDir(), "main.c")
70+
one_print_path = os.path.join(self.getSourceDir(), "one-print.c")
71+
two_print_path = os.path.join(self.getSourceDir(), "two-print.c")
72+
main_filespec = lldb.SBFileSpec(main_c_path)
73+
74+
# First copy the one-print.c to main.c in the build folder and
75+
# build our a.out from there:
76+
self.copy_to_main(one_print_path, main_c_path)
77+
self.build(dictionary={"C_SOURCES": main_c_path, "EXE": "a.out"})
78+
79+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
80+
self, "return counter;", main_filespec
81+
)
82+
83+
# Make sure we ran the version we intended here:
84+
self.check_counter_var(thread, 1)
85+
process.Kill()
86+
87+
# Now copy two-print.c over main.c, rebuild, and rerun:
88+
# os.unlink(target.GetExecutable().fullpath)
89+
self.copy_to_main(two_print_path, main_c_path)
90+
91+
self.build(dictionary={"C_SOURCES": main_c_path, "EXE": "a.out"})
92+
error = lldb.SBError()
93+
if one_debugger:
94+
if one_target:
95+
(_, process, thread, _) = lldbutil.run_to_breakpoint_do_run(
96+
self, target, bkpt
97+
)
98+
else:
99+
(target2, process2, thread, bkpt) = lldbutil.run_to_source_breakpoint(
100+
self, "return counter;", main_filespec
101+
)
102+
else:
103+
if one_target:
104+
new_debugger = lldb.SBDebugger().Create()
105+
self.old_debugger = self.dbg
106+
self.dbg = new_debugger
107+
def cleanupDebugger(self):
108+
lldb.SBDebugger.Destroy(self.dbg)
109+
self.dbg = self.old_debugger
110+
self.old_debugger = None
111+
112+
self.addTearDownHook(cleanupDebugger)
113+
(target2, process2, thread, bkpt) = lldbutil.run_to_source_breakpoint(
114+
self, "return counter;", main_filespec
115+
)
116+
117+
# In two-print.c counter will be 2:
118+
self.check_counter_var(thread, 2)
119+
120+
# If we made two targets, destroy the first one, that should free up the
121+
# unreachable Modules:
122+
if not one_target:
123+
target.Clear()
124+
125+
num_a_dot_out_entries = 1
126+
# For dSYM's there will be two lines of output, one for the a.out and one
127+
# for the dSYM.
128+
if debug_style == "dsym":
129+
num_a_dot_out_entries += 1
130+
131+
error = self.check_image_list_result(num_a_dot_out_entries, 1)
132+
# Even if this fails, MemoryPressureDetected should fix this.
133+
lldb.SBDebugger.MemoryPressureDetected()
134+
error_after_mpd = self.check_image_list_result(num_a_dot_out_entries, 1)
135+
fail_msg = ""
136+
if error != "":
137+
fail_msg = "Error before MPD: " + error
138+
139+
if error_after_mpd != "":
140+
fail_msg = fail_msg + "\nError after MPD: " + error_after_mpd
141+
if fail_msg != "":
142+
self.fail(fail_msg)
143+
144+
def check_image_list_result(self, num_a_dot_out, num_main_dot_o):
145+
# Check the global module list, there should only be one a.out, and if we are
146+
# doing dwarf in .o file, there should only be one .o file. This returns
147+
# an error string on error - rather than asserting, so you can stage this
148+
# failing.
149+
image_cmd_result = lldb.SBCommandReturnObject()
150+
interp = self.dbg.GetCommandInterpreter()
151+
interp.HandleCommand("image list -g", image_cmd_result)
152+
if self.TraceOn():
153+
print(f"Expected: a.out: {num_a_dot_out} main.o: {num_main_dot_o}")
154+
print(image_cmd_result)
155+
156+
image_list_str = image_cmd_result.GetOutput()
157+
image_list = image_list_str.splitlines()
158+
found_a_dot_out = 0
159+
found_main_dot_o = 0
160+
161+
for line in image_list:
162+
# FIXME: force this to be at the end of the string:
163+
if "a.out" in line:
164+
found_a_dot_out += 1
165+
if "main.o" in line:
166+
found_main_dot_o += 1
167+
168+
if num_a_dot_out != found_a_dot_out:
169+
return f"Got {found_a_dot_out} number of a.out's, expected {num_a_dot_out}"
170+
171+
if found_main_dot_o > 0 and num_main_dot_o != found_main_dot_o:
172+
return f"Got {found_main_dot_o} number of main.o's, expected {num_main_dot_o}"
173+
174+
return ""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <stdio.h>
2+
3+
int main() {
4+
int counter = 0;
5+
printf("I only print one time: %d.\n", counter++);
6+
return counter;
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <stdio.h>
2+
3+
int main() {
4+
int counter = 0;
5+
printf("I print one time: %d.\n", counter++);
6+
printf("I print two times: %d.\n", counter++);
7+
return counter;
8+
}

0 commit comments

Comments
 (0)