blob: 0b6c9b722904a8b3036f34972018b52b77b6c02d [file] [edit]
"""
Test lldb-dap module request
"""
import platform
import re
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import line_number
from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
from lldbsuite.test.tools.lldb_dap.types import (
CompileUnitsArgs,
LaunchArgs,
ModuleEvent,
ModuleReason,
)
@skipIfTargetDoesNotSupportSharedLibraries()
@skipIf(
oslist=lldbplatformutil.getDarwinOSTriples(),
bugnumber="https://github.com/llvm/llvm-project/issues/216150",
)
class TestDAP_module(DAPTestCaseBase):
def run_test(self, symbol_basename: str, expect_debug_info_size: bool):
session = self.build_and_create_session()
program_basename = "a.out.stripped"
program = self.getBuildArtifact(program_basename)
with session.configure(LaunchArgs(program)) as ctx:
# This breakpoint will be resolved only when the libfoo module is loaded.
breakpoints = session.set_function_breakpoints(["foo"]).body.breakpoints
self.assertEqual(len(breakpoints), 1, "expect one breakpoint.")
foo_bp_id = self.expect_not_none(breakpoints[0].id)
self.assertFalse(breakpoints[0].verified)
session.verify_stopped_on_breakpoint(foo_bp_id, after=ctx.process_event)
active_modules = session.get_modules()
program_module = active_modules[program_basename]
self.assertIn(
program_basename,
active_modules,
f"{program_basename} module is in active modules",
)
self.assertEqual(program_basename, program_module.name)
self.assertIsNotNone(program_module.path, "make sure path is in module")
self.assertEqual(program, program_module.path)
self.assertIsNone(
program_module.symbolFilePath, "Make sure a.out.stripped has no debug info"
)
symbols_path = self.getBuildArtifact(symbol_basename)
event_before_mod_change = session.last_event()
session.evaluate(
f'''`target symbols add -s "{program}" "{symbols_path}"''', context="repl"
)
# Make sure we got an update event for the program module when the
# symbols got added.
changed_event = session.verify_next_module_event(
ModuleReason.CHANGED, after=event_before_mod_change
)
changed_module = changed_event.body.module
self.assertEqual(program_module.name, changed_module.name)
self.assertIsNotNone(changed_module.symbolFilePath)
changed_symbols_path = self.expect_not_none(changed_module.symbolFilePath)
self.assertIn(symbols_path, changed_symbols_path)
if expect_debug_info_size:
changed_debug_size = self.expect_not_none(changed_module.debugInfoSize)
size_regex = re.compile(r"[0-9]+(\.[0-9]*)?[KMG]?B")
self.assertRegex(
changed_debug_size, size_regex, "expect has debug info size"
)
active_modules = session.get_modules()
program_module = active_modules[program_basename]
self.assertEqual(program_basename, program_module.name)
self.assertEqual(program, program_module.path)
self.assertIsNotNone(program_module.addressRange)
# Collect all the modules added before we changed the program module.
new_module_names = []
def seen_module_changed_event(event: ModuleEvent):
if event.body.reason == ModuleReason.NEW:
new_module_names.append(event.body.module.name)
return event.seq == changed_event.seq
init_resp = ctx.init_response
session.wait_for_module_event(after=init_resp, until=seen_module_changed_event)
# Make sure we got an event for every active module.
self.assertNotEqual(len(new_module_names), 0)
for module in active_modules:
self.assertIn(module, new_module_names)
session.continue_to_exit()
@skipIfWindows
def test_modules(self):
"""
Mac or linux.
On mac, if we load a.out as our symbol file, we will use DWARF with .o files and we will
have debug symbols, but we won't see any debug info size because all of the DWARF
sections are in .o files.
On other platforms, we expect a.out to have debug info, so we will expect a size.
"""
return self.run_test(
"a.out", expect_debug_info_size=platform.system() != "Darwin"
)
@requireDarwin
def test_modules_dsym(self):
"""
Darwin only test with dSYM file.
On mac, if we load a.out.dSYM as our symbol file, we will have debug symbols and we
will have DWARF sections added to the module, so we will expect a size.
"""
return self.run_test("a.out.dSYM", expect_debug_info_size=True)
@skipIfWindows
def test_compile_units(self):
session = self.build_and_create_session()
program = self.getBuildArtifact("a.out")
source = "main.cpp"
main_source_path = self.getSourcePath(source)
with session.configure(LaunchArgs(program)) as ctx:
breakpoint1_line = line_number(source, "// breakpoint 1")
bp_ids = session.resolve_source_breakpoints(source, [breakpoint1_line])
process_event = ctx.process_event
session.verify_stopped_on_breakpoint(bp_ids, after=process_event)
module_id = session.get_modules()["a.out"].id
response = session.send_request(CompileUnitsArgs(module_id)).result()
cu_paths = [cu.compileUnitPath for cu in response.body.compileUnits]
self.assertIn(main_source_path, cu_paths, "Real path to main.cpp matches")
session.continue_to_exit()
@skipIfWindows
def test_modules_paging(self):
"""Test modules paging using startModule and moduleCount."""
session = self.build_and_create_session()
program = self.getBuildArtifact("a.out")
source = "main.cpp"
with session.configure(LaunchArgs(program)) as ctx:
breakpoint1_line = line_number(source, "// breakpoint 1")
bp_ids = session.resolve_source_breakpoints(source, [breakpoint1_line])
session.verify_stopped_on_breakpoint(bp_ids, after=ctx.process_event)
all_modules = list(session.get_modules().values())
self.assertGreater(len(all_modules), 1, "Expected multiple modules loaded")
page = session.get_modules(startModule=0, moduleCount=1)
self.assertEqual(len(page), 1)
module = next(iter(page.values()))
self.assertEqual(module.name, all_modules[0].name)
self.assertEqual(module.id, all_modules[0].id)
page = session.get_modules(startModule=1, moduleCount=1)
self.assertEqual(len(page), 1)
module = next(iter(page.values()))
self.assertEqual(module.name, all_modules[1].name)
self.assertEqual(module.id, all_modules[1].id)
page = session.get_modules(startModule=1, moduleCount=100)
self.assertEqual(len(page), len(all_modules) - 1)
session.continue_to_exit()