"""
Test the use of the global module cache in lldb
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
import os
import shutil
from pathlib import Path
import time
class GlobalModuleCacheTestCase(TestBase):
def check_counter_var(self, thread, value):
frame = thread.frames[0]
var = frame.FindVariable("counter")
self.assertTrue(var.GetError().Success(), "Got counter variable")
self.assertEqual(var.GetValueAsUnsigned(), value, "This was one-print")
def copy_to_main(self, src, dst):
time.sleep(2)
try:
subprocess.run(
["chmod", "777", dst],
stdin=None,
capture_output=False,
encoding="utf-8",
)
shutil.copy(src, dst)
except:
self.fail(f"Could not copy {src} to {dst}")
Path(dst).touch()
@skipIfWindows
@skipIf(oslist=["linux"], archs=["arm", "aarch64"])
def test_OneTargetOneDebugger(self):
self.do_test(True, True)
@skipIfWindows
@expectedFailureAll
@skipIf(oslist=["linux"], archs=["arm", "aarch64"])
def test_TwoTargetsOneDebugger(self):
self.do_test(False, True)
@skipIfWindows
@expectedFailureAll
@skipIf(oslist=["linux"], archs=["arm", "aarch64"])
def test_OneTargetTwoDebuggers(self):
self.do_test(True, False)
def do_test(self, one_target, one_debugger):
debug_style = self.getDebugInfo()
lldb.SBDebugger.MemoryPressureDetected()
main_c_path = os.path.join(self.getBuildDir(), "main.c")
one_print_path = os.path.join(self.getSourceDir(), "one-print.c")
two_print_path = os.path.join(self.getSourceDir(), "two-print.c")
main_filespec = lldb.SBFileSpec(main_c_path)
self.copy_to_main(one_print_path, main_c_path)
self.build(dictionary={"C_SOURCES": main_c_path, "EXE": "a.out"})
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "return counter;", main_filespec
)
self.check_counter_var(thread, 1)
process.Kill()
self.copy_to_main(two_print_path, main_c_path)
self.build(dictionary={"C_SOURCES": main_c_path, "EXE": "a.out"})
error = lldb.SBError()
if one_debugger:
if one_target:
(_, process, thread, _) = lldbutil.run_to_breakpoint_do_run(
self, target, bkpt
)
else:
(target2, process2, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "return counter;", main_filespec
)
else:
if one_target:
new_debugger = lldb.SBDebugger().Create()
new_debugger.SetAsync(False)
self.old_debugger = self.dbg
self.dbg = new_debugger
def cleanupDebugger(self):
lldb.SBDebugger.Destroy(self.dbg)
self.dbg = self.old_debugger
self.old_debugger = None
self.addTearDownHook(cleanupDebugger)
(target2, process2, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "return counter;", main_filespec
)
self.check_counter_var(thread, 2)
if not one_target:
target.Clear()
num_a_dot_out_entries = 1
if debug_style == "dsym":
num_a_dot_out_entries += 1
error = self.check_image_list_result(num_a_dot_out_entries, 1)
lldb.SBDebugger.MemoryPressureDetected()
error_after_mpd = self.check_image_list_result(num_a_dot_out_entries, 1)
fail_msg = ""
if error != "":
fail_msg = "Error before MPD: " + error
if error_after_mpd != "":
fail_msg = fail_msg + "\nError after MPD: " + error_after_mpd
if fail_msg != "":
self.fail(fail_msg)
def check_image_list_result(self, num_a_dot_out, num_main_dot_o):
image_cmd_result = lldb.SBCommandReturnObject()
interp = self.dbg.GetCommandInterpreter()
interp.HandleCommand("image list -g", image_cmd_result)
if self.TraceOn():
print(f"Expected: a.out: {num_a_dot_out} main.o: {num_main_dot_o}")
print(image_cmd_result)
image_list_str = image_cmd_result.GetOutput()
image_list = image_list_str.splitlines()
found_a_dot_out = 0
found_main_dot_o = 0
for line in image_list:
if "a.out" in line:
found_a_dot_out += 1
if "main.o" in line:
found_main_dot_o += 1
if num_a_dot_out != found_a_dot_out:
return f"Got {found_a_dot_out} number of a.out's, expected {num_a_dot_out}"
if found_main_dot_o > 0 and num_main_dot_o != found_main_dot_o:
return (
f"Got {found_main_dot_o} number of main.o's, expected {num_main_dot_o}"
)
return ""