diff options
Diffstat (limited to 'lldb/test/API')
75 files changed, 1480 insertions, 292 deletions
diff --git a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py index 0cc505aedc4b..759b620105c4 100644 --- a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py +++ b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py @@ -215,8 +215,20 @@ note: candidate function not viable: requires single argument 'x', but 2 argumen details = diags.GetValueForKey("details") - # Detail 1/2: undeclared 'a' + # Detail 1/3: note: requested expression language diag = details.GetItemAtIndex(0) + self.assertEqual(str(diag.GetValueForKey("severity")), "note") + self.assertIn("Ran expression as 'C++", str(diag.GetValueForKey("message"))) + self.assertIn( + "Ran expression as 'C++", str(diag.GetValueForKey("rendered")) + ) + self.assertEqual(str(diag.GetValueForKey("source_location")), "") + self.assertEqual(str(diag.GetValueForKey("file")), "") + self.assertFalse(diag.GetValueForKey("hidden").GetBooleanValue()) + self.assertFalse(diag.GetValueForKey("in_user_input").GetBooleanValue()) + + # Detail 2/3: undeclared 'a' + diag = details.GetItemAtIndex(1) severity = diag.GetValueForKey("severity") message = diag.GetValueForKey("message") @@ -234,8 +246,8 @@ note: candidate function not viable: requires single argument 'x', but 2 argumen self.assertFalse(hidden.GetBooleanValue()) self.assertTrue(in_user_input.GetBooleanValue()) - # Detail 1/2: undeclared 'b' - diag = details.GetItemAtIndex(1) + # Detail 3/3: undeclared 'b' + diag = details.GetItemAtIndex(2) message = diag.GetValueForKey("message") self.assertIn("undeclared identifier 'b'", str(message)) diff --git a/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py index ed028a1a4ea3..4aea8009058b 100644 --- a/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py @@ -11,6 +11,9 @@ class TestCase(TestBase): @add_test_categories(["libc++"]) @skipIf(compiler=no_match("clang")) @skipIf(macos_version=["<", "15.0"]) + @skipIf( + bugnumber="ASTImport of lambdas not supported: https://github.com/llvm/llvm-project/issues/149477" + ) def test(self): self.build() diff --git a/lldb/test/API/commands/expression/import-std-module/deque-basic/TestDequeFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/deque-basic/TestDequeFromStdModule.py index 0fb6e883597d..5e819b7f6e16 100644 --- a/lldb/test/API/commands/expression/import-std-module/deque-basic/TestDequeFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/deque-basic/TestDequeFromStdModule.py @@ -11,6 +11,9 @@ class TestBasicDeque(TestBase): @add_test_categories(["libc++"]) @skipIf(compiler=no_match("clang")) @skipIf(macos_version=["<", "15.0"]) + @skipIf( + bugnumber="ASTImport of lambdas not supported: https://github.com/llvm/llvm-project/issues/149477" + ) def test(self): self.build() diff --git a/lldb/test/API/commands/expression/import-std-module/deque-dbg-info-content/TestDbgInfoContentDequeFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/deque-dbg-info-content/TestDbgInfoContentDequeFromStdModule.py index e631a8737637..e8676b21bced 100644 --- a/lldb/test/API/commands/expression/import-std-module/deque-dbg-info-content/TestDbgInfoContentDequeFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/deque-dbg-info-content/TestDbgInfoContentDequeFromStdModule.py @@ -12,6 +12,9 @@ class TestDbgInfoContentDeque(TestBase): @skipIf(compiler=no_match("clang")) @skipIf(compiler="clang", compiler_version=["<", "18.0"]) @skipIf(macos_version=["<", "15.0"]) + @skipIf( + bugnumber="ASTImport of lambdas not supported: https://github.com/llvm/llvm-project/issues/149477" + ) def test(self): self.build() diff --git a/lldb/test/API/commands/expression/import-std-module/forward_list/TestForwardListFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/forward_list/TestForwardListFromStdModule.py index a6ba0810e68e..9581155be204 100644 --- a/lldb/test/API/commands/expression/import-std-module/forward_list/TestForwardListFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/forward_list/TestForwardListFromStdModule.py @@ -11,6 +11,9 @@ class TestBasicForwardList(TestBase): @add_test_categories(["libc++"]) @skipIf(compiler=no_match("clang")) @skipIf(macos_version=["<", "15.0"]) + @skipIf( + bugnumber="ASTImport of lambdas not supported: https://github.com/llvm/llvm-project/issues/149477" + ) def test(self): self.build() diff --git a/lldb/test/API/commands/expression/import-std-module/list-dbg-info-content/TestDbgInfoContentListFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/list-dbg-info-content/TestDbgInfoContentListFromStdModule.py index b26bd7dedda8..923551ca64c3 100644 --- a/lldb/test/API/commands/expression/import-std-module/list-dbg-info-content/TestDbgInfoContentListFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/list-dbg-info-content/TestDbgInfoContentListFromStdModule.py @@ -13,6 +13,9 @@ class TestDbgInfoContentList(TestBase): @skipIf(compiler=no_match("clang")) @skipIf(compiler="clang", compiler_version=["<", "12.0"]) @skipIf(macos_version=["<", "15.0"]) + @skipIf( + bugnumber="ASTImport of lambdas not supported: https://github.com/llvm/llvm-project/issues/149477" + ) def test(self): self.build() diff --git a/lldb/test/API/commands/expression/import-std-module/list/TestListFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/list/TestListFromStdModule.py index 6253a35e926d..d6c88926e3e4 100644 --- a/lldb/test/API/commands/expression/import-std-module/list/TestListFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/list/TestListFromStdModule.py @@ -11,6 +11,9 @@ class TestBasicList(TestBase): @add_test_categories(["libc++"]) @skipIf(compiler=no_match("clang")) @skipIf(macos_version=["<", "15.0"]) + @skipIf( + bugnumber="ASTImport of lambdas not supported: https://github.com/llvm/llvm-project/issues/149477" + ) def test(self): self.build() diff --git a/lldb/test/API/commands/protocol/TestMCPUnixSocket.py b/lldb/test/API/commands/protocol/TestMCPUnixSocket.py index ea9255cc60ef..9edb97eb791b 100644 --- a/lldb/test/API/commands/protocol/TestMCPUnixSocket.py +++ b/lldb/test/API/commands/protocol/TestMCPUnixSocket.py @@ -32,3 +32,16 @@ class MCPUnixSocketCommandTestCase(TestBase): startstr="MCP server started with connection listeners:", substrs=[f"unix-connect://{socket_file}"], ) + + self.expect( + "protocol-server get MCP", + startstr="MCP server connection listeners:", + substrs=[f"unix-connect://{socket_file}"], + ) + + self.runCmd("protocol-server stop MCP", check=False) + self.expect( + "protocol-server get MCP", + error=True, + substrs=["MCP server is not running"], + ) diff --git a/lldb/test/API/driver/quit_speed/TestQuitWithProcess.py b/lldb/test/API/driver/quit_speed/TestQuitWithProcess.py index 2412b295bfb5..305e3cc397cf 100644 --- a/lldb/test/API/driver/quit_speed/TestQuitWithProcess.py +++ b/lldb/test/API/driver/quit_speed/TestQuitWithProcess.py @@ -33,3 +33,28 @@ class DriverQuitSpeedTest(PExpectTest): child.sendline("quit") print("sent quit") child.expect(pexpect.EOF, timeout=15) + + @skipIfAsan + def test_run_quit_with_prompt(self): + """Test that the lldb driver's batch mode works correctly with trailing space in confimation.""" + import pexpect + + self.build() + + exe = self.getBuildArtifact("a.out") + + self.launch(executable=exe) + child = self.child + + # Launch the process without a TTY so we don't have to interrupt: + child.sendline("process launch -n") + print("launched process") + child.expect(r"Process ([\d]*) launched:") + print("Got launch message") + child.sendline("quit") + print("sent quit") + + child.expect(r".*LLDB will kill one or more processes.*") + # add trailing space to the confirmation. + child.sendline("yEs ") + child.expect(pexpect.EOF, timeout=15) diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py index 85c734012761..95868486b8cb 100644 --- a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py +++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py @@ -51,7 +51,6 @@ class Resolver: def get_short_help(self): return "I am a python breakpoint resolver" - class ResolverModuleDepth(Resolver): def __get_depth__(self): return lldb.eSearchDepthModule diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile new file mode 100644 index 000000000000..695335e068c0 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -std=c99 + +include Makefile.rules diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py new file mode 100644 index 000000000000..2e176239facf --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py @@ -0,0 +1,102 @@ +""" +Test the WasHit feature of scripted breakpoints +""" + +import os +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + + +class TestWasHit(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") + def test_was_hit_resolver(self): + """Use facade breakpoints to emulate hitting some locations""" + self.build() + self.do_test() + + def make_target_and_import(self): + target = lldbutil.run_to_breakpoint_make_target(self) + self.import_resolver_script() + return target + + def import_resolver_script(self): + interp = self.dbg.GetCommandInterpreter() + error = lldb.SBError() + + script_name = os.path.join(self.getSourceDir(), "bkpt_resolver.py") + + command = "command script import " + script_name + self.runCmd(command) + + def make_extra_args(self, sym_name, num_locs, loc_to_miss): + return f" -k symbol -v {sym_name} -k num_locs -v {num_locs} -k loc_to_miss -v {loc_to_miss} " + + def do_test(self): + """This reads in a python file and sets a breakpoint using it.""" + + target = self.make_target_and_import() + extra_args = self.make_extra_args("stop_symbol", 4, 2) + + bkpt_no = lldbutil.run_break_set_by_script( + self, "bkpt_resolver.FacadeExample", extra_args, 4 + ) + + # Make sure the help text shows up in the "break list" output: + self.expect( + "break list", + substrs=["I am a facade resolver - sym: stop_symbol - num_locs: 4"], + msg="Help is listed in break list", + ) + + bkpt = target.FindBreakpointByID(bkpt_no) + self.assertTrue(bkpt.IsValid(), "Found the right breakpoint") + + # Now continue. We should hit locations 1, 3 and 4: + (target, process, thread, bkpt) = lldbutil.run_to_breakpoint_do_run( + self, target, bkpt + ) + # This location should be bkpt_no.1: + self.assertEqual( + thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint" + ) + self.assertEqual(thread.stop_reason_data[1], 1, "First location hit is 1") + + for loc in [3, 4]: + process.Continue() + self.assertEqual( + thread.stop_reason, lldb.eStopReasonBreakpoint, "Hit breakpoint" + ) + self.assertEqual( + thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint" + ) + self.assertEqual( + thread.stop_reason_data[1], loc, f"Hit the right location: {loc}" + ) + + # At this point we should have hit three of the four locations, and not location 1.2. + # Check that that is true, and that the descriptions for the location are the ones + # the resolver provided. + self.assertEqual(bkpt.hit_count, 3, "Hit three locations") + for loc_id in range(1, 4): + bkpt_loc = bkpt.FindLocationByID(loc_id) + self.assertTrue(bkpt_loc.IsValid(), f"{loc_id} was invalid.") + if loc_id != 2: + self.assertEqual( + bkpt_loc.hit_count, 1, f"Loc {loc_id} hit count was wrong" + ) + else: + self.assertEqual(bkpt_loc.hit_count, 0, "We didn't skip loc 2") + stream = lldb.SBStream() + self.assertTrue( + bkpt_loc.GetDescription(stream, lldb.eDescriptionLevelFull), + f"Didn't get description for {loc_id}", + ) + self.assertIn( + f"Location index: {loc_id}", + stream.GetData(), + f"Wrong desciption for {loc_id}", + ) diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py new file mode 100644 index 000000000000..acc8513e3e3e --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py @@ -0,0 +1,49 @@ +import lldb + + +class FacadeExample: + def __init__(self, bkpt, extra_args, dict): + self.bkpt = bkpt + self.extra_args = extra_args + self.base_sym = None + self.facade_locs = [] + self.facade_locs_desc = [] + self.cur_facade_loc = 1 + + self.sym_name = extra_args.GetValueForKey("symbol").GetStringValue(100) + self.num_locs = extra_args.GetValueForKey("num_locs").GetIntegerValue(5) + self.loc_to_miss = extra_args.GetValueForKey("loc_to_miss").GetIntegerValue( + 10000 + ) + + def __callback__(self, sym_ctx): + self.base_sym = sym_ctx.module.FindSymbol(self.sym_name, lldb.eSymbolTypeCode) + if self.base_sym.IsValid(): + self.bkpt.AddLocation(self.base_sym.GetStartAddress()) + # Locations are 1 based, so to keep things simple, I'm making + # the array holding locations 1 based as well: + self.facade_locs_desc.append( + "This is the zero index, you shouldn't see this" + ) + self.facade_locs.append(None) + for i in range(1, self.num_locs + 1): + self.facade_locs_desc.append(f"Location index: {i}") + self.facade_locs.append(self.bkpt.AddFacadeLocation()) + + def get_short_help(self): + return f"I am a facade resolver - sym: {self.sym_name} - num_locs: {self.num_locs} - locs_to_miss: {self.loc_to_miss}" + + def was_hit(self, frame, bp_loc): + tmp_loc = self.cur_facade_loc + + self.cur_facade_loc = self.cur_facade_loc + 1 + if self.cur_facade_loc == self.num_locs + 1: + self.cur_facade_loc = 1 + + if tmp_loc == self.loc_to_miss: + return None + + return self.facade_locs[tmp_loc] + + def get_location_description(self, bp_loc, desc_level): + return self.facade_locs_desc[bp_loc.id] diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c new file mode 100644 index 000000000000..b8f977e49351 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c @@ -0,0 +1,14 @@ +#include <stdio.h> + +int stop_symbol() { + static int s_cnt = 0; + printf("I am in the stop symbol: %d\n", s_cnt++); + return s_cnt; +} + +int main() { + for (int i = 0; i < 100; i++) { + stop_symbol(); + } + return 0; +} diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/Makefile new file mode 100644 index 000000000000..99998b20bcb0 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/TestDataFormatterInvalidAtomic.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/TestDataFormatterInvalidAtomic.py new file mode 100644 index 000000000000..76b8e7b40f44 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/TestDataFormatterInvalidAtomic.py @@ -0,0 +1,45 @@ +""" +Test formatting of `std::atomic`s not from any STL +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class InvalidAtomicDataFormatterTestCase(TestBase): + def test(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "Set break point at this line.", lldb.SBFileSpec("main.cpp") + ) + + self.expect_expr( + "a", + result_children=[ + ValueCheck(name="foo", value="1"), + ValueCheck(name="bar", value="2"), + ], + ) + self.expect_expr( + "b", + result_children=[ + ValueCheck(name="foo", value="3"), + ValueCheck(name="bar", value="4"), + ], + ) + + self.expect_expr( + "c", + result_children=[ + ValueCheck(name="foo", value="5"), + ValueCheck(name="bar", value="6"), + ], + ) + self.expect_expr( + "d", + result_children=[ + ValueCheck(name="foo", value="7"), + ValueCheck(name="bar", value="8"), + ], + ) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/main.cpp new file mode 100644 index 000000000000..7b4c51c921a9 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic-simulators/invalid-atomic/main.cpp @@ -0,0 +1,23 @@ +namespace std { +template <typename T> struct atomic { + int foo; + int bar; +}; + +namespace __1 { +template <typename T> struct atomic { + int foo; + int bar; +}; +} // namespace __1 +} // namespace std + +int main() { + std::atomic<int> a{1, 2}; + std::atomic<void> b{3, 4}; + + std::__1::atomic<int> c{5, 6}; + std::__1::atomic<void> d{7, 8}; + + return 0; // Set break point at this line. +} diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered_map-iterator/TestDataFormatterStdUnorderedMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered_map-iterator/TestDataFormatterStdUnorderedMap.py index 1e920faab639..45f7b5be465c 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered_map-iterator/TestDataFormatterStdUnorderedMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered_map-iterator/TestDataFormatterStdUnorderedMap.py @@ -124,11 +124,6 @@ class StdUnorderedMapDataFormatterTestCase(TestBase): self.check_ptr_ptr("ptr5") self.check_ptr_ptr("ptr6") - @expectedFailureAll( - bugnumber="https://github.com/llvm/llvm-project/issues/146040", - compiler="clang", - compiler_version=["<", "21"], - ) @add_test_categories(["libc++"]) def test_ptr_libcxx(self): self.build(dictionary={"USE_LIBCPP": 1}) diff --git a/lldb/test/API/functionalities/json/symbol-file/Makefile b/lldb/test/API/functionalities/json/symbol-file/Makefile index 13bc164582ee..5d05d95fc842 100644 --- a/lldb/test/API/functionalities/json/symbol-file/Makefile +++ b/lldb/test/API/functionalities/json/symbol-file/Makefile @@ -1,4 +1,5 @@ C_SOURCES := main.c +CFLAGS_EXTRAS := -no-pie all: stripped.out diff --git a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py index f06c9ae14bb7..d7249df350fc 100644 --- a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py +++ b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py @@ -1,6 +1,7 @@ # Test the SBAPI for GetStatistics() import json + import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * @@ -54,6 +55,11 @@ class TestStatsAPI(TestBase): stats_json, 'Make sure the "frameVariable" key in in target.GetStatistics()["targets"][0]', ) + self.assertNotIn( + "loadCoreTime", + stats_json, + "LoadCoreTime should not be present in a live, non-coredump target", + ) expressionEvaluation = stats_json["expressionEvaluation"] self.assertIn( "successes", @@ -157,3 +163,25 @@ class TestStatsAPI(TestBase): stats_force.GetAsJSON(stream_force) debug_stats_force = json.loads(stream_force.GetData()) self.assertEqual(debug_stats_force["totalDebugInfoByteSize"], 445) + + def test_core_load_time(self): + """ + Test to see if the coredump path is included in statistics dump. + """ + yaml_file = "arm64-minidump-build-ids.yaml" + src_dir = self.getSourceDir() + minidump_path = self.getBuildArtifact(os.path.basename(yaml_file) + ".dmp") + self.yaml2obj(os.path.join(src_dir, yaml_file), minidump_path) + target = self.dbg.CreateTarget(None) + process = target.LoadCore(minidump_path) + self.assertTrue(process.IsValid()) + + stats_options = lldb.SBStatisticsOptions() + stats = target.GetStatistics(stats_options) + stream = lldb.SBStream() + stats.GetAsJSON(stream) + debug_stats = json.loads(stream.GetData()) + self.assertTrue("targets" in debug_stats) + target_info = debug_stats["targets"][0] + self.assertTrue("loadCoreTime" in target_info) + self.assertTrue(float(target_info["loadCoreTime"]) > 0.0) diff --git a/lldb/test/API/functionalities/stats_api/arm64-minidump-build-ids.yaml b/lldb/test/API/functionalities/stats_api/arm64-minidump-build-ids.yaml new file mode 100644 index 000000000000..4acbc409d808 --- /dev/null +++ b/lldb/test/API/functionalities/stats_api/arm64-minidump-build-ids.yaml @@ -0,0 +1,19 @@ +--- !minidump +Streams: + - Type: SystemInfo + Processor Arch: ARM + Platform ID: Linux + CSD Version: '15E216' + CPU: + CPUID: 0x00000000 + - Type: ModuleList + Modules: + - Base of Image: 0x0000000000001000 + Size of Image: 0x00001000 + Module Name: '/tmp/a' + CodeView Record: 4C4570420102030405060708090A0B0C0D0E0F1011121314 + - Base of Image: 0x0000000000001000 + Size of Image: 0x00001000 + Module Name: '/tmp/b' + CodeView Record: 4C4570420A141E28323C46505A646E78828C96A0AAB4BEC8 +... diff --git a/lldb/test/API/functionalities/thread/step_out_line0/Makefile b/lldb/test/API/functionalities/thread/step_out_line0/Makefile new file mode 100644 index 000000000000..10495940055b --- /dev/null +++ b/lldb/test/API/functionalities/thread/step_out_line0/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/functionalities/thread/step_out_line0/TestThreadStepOutLine0.py b/lldb/test/API/functionalities/thread/step_out_line0/TestThreadStepOutLine0.py new file mode 100644 index 000000000000..2707ca852f66 --- /dev/null +++ b/lldb/test/API/functionalities/thread/step_out_line0/TestThreadStepOutLine0.py @@ -0,0 +1,35 @@ +""" +Test stepping out of a function when the return location is an unsuitable +stopping point. +""" + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ThreadStepOutLine0TestCase(TestBase): + def test(self): + self.build() + target, process, thread, _ = lldbutil.run_to_source_breakpoint( + self, "// Set breakpoint here", lldb.SBFileSpec("main.c") + ) + correct_stepped_out_line = line_number("main.c", "// Should stop here") + return_statement_line = line_number("main.c", "// Ran too far") + safety_bp = target.BreakpointCreateByLocation( + lldb.SBFileSpec("main.c"), return_statement_line + ) + self.assertTrue(safety_bp.IsValid()) + + error = lldb.SBError() + thread.StepOut(error) + self.assertTrue(error.Success()) + + frame = thread.GetSelectedFrame() + self.assertEqual( + frame.line_entry.GetLine(), + correct_stepped_out_line, + "Step-out lost control of execution, ran too far", + ) diff --git a/lldb/test/API/functionalities/thread/step_out_line0/main.c b/lldb/test/API/functionalities/thread/step_out_line0/main.c new file mode 100644 index 000000000000..ad0c1c05d695 --- /dev/null +++ b/lldb/test/API/functionalities/thread/step_out_line0/main.c @@ -0,0 +1,11 @@ +int step_out_of_here(int a) { + return a + 5; // Set breakpoint here +} + +int main() { +#line 0 + int v = step_out_of_here(3) + 7; +#line 9 + v += 11; // Should stop here + return v; // Ran too far +} diff --git a/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py b/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py index 768dd6fe6867..50ea17370524 100644 --- a/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py +++ b/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py @@ -12,21 +12,7 @@ from lldbsuite.test import lldbutil class TestCortexMExceptionUnwind(TestBase): NO_DEBUG_INFO_TESTCASE = True - # on the lldb-remote-linux-ubuntu CI, the binary.json's triple of - # armv7m-apple is not being set in the Target triple, and we're - # picking the wrong ABI plugin, ABISysV_arm. - # ABISysV_arm::CreateDefaultUnwindPlan() doesn't have a way to detect - # arm/thumb for a stack frame, or even the Target's triple for a - # Cortex-M part that is always thumb. It hardcodes r11 as the frame - # pointer register, which is correct for arm code but not thumb. - # It is never correct # on a Cortex-M target. - # The Darwin ABIMacOSX_arm diverges from AAPCS and always uses r7 for - # the frame pointer -- the thumb convention -- whether executing arm or - # thumb. So its CreateDefaultUnwindPlan picks the correct register for - # the frame pointer, and we can walk the stack. - # ABISysV_arm::CreateDefaultUnwindPlan will only get one frame and - # not be able to continue. - @skipIfRemote + @skipIfLLVMTargetMissing("ARM") def test_no_fpu(self): """Test that we can backtrace correctly through an ARM Cortex-M Exception return stack""" @@ -42,6 +28,9 @@ class TestCortexMExceptionUnwind(TestBase): core = self.getBuildArtifact("core") self.yaml2macho_core("armv7m-nofpu-exception.yaml", core, exe_uuid) + if self.TraceOn(): + self.runCmd("log enable lldb unwind") + process = target.LoadCore(core) self.assertTrue(process.IsValid()) @@ -55,14 +44,9 @@ class TestCortexMExceptionUnwind(TestBase): thread = process.GetThreadAtIndex(0) self.assertTrue(thread.IsValid()) - # We have 4 named stack frames and two unnamed - # frames above that. The topmost two stack frames - # were not interesting for this test, so I didn't - # create symbols for them. - self.assertEqual(thread.GetNumFrames(), 6) + self.assertEqual(thread.GetNumFrames(), 3) stackframe_names = [ "exception_catcher", - "exception_catcher", "exception_thrower", "main", ] diff --git a/lldb/test/API/functionalities/unwind/cortex-m-exception/armv7m-nofpu-exception.yaml b/lldb/test/API/functionalities/unwind/cortex-m-exception/armv7m-nofpu-exception.yaml index 9ce5ff49d9b6..0b4e1f8fac3e 100644 --- a/lldb/test/API/functionalities/unwind/cortex-m-exception/armv7m-nofpu-exception.yaml +++ b/lldb/test/API/functionalities/unwind/cortex-m-exception/armv7m-nofpu-exception.yaml @@ -2,8 +2,8 @@ cpu: armv7m threads: - regsets: - flavor: gpr - registers: [{name: sp, value: 0x2000fe70}, {name: r7, value: 0x2000fe80}, - {name: pc, value: 0x0020392c}, {name: lr, value: 0x0020392d}] + registers: [{name: sp, value: 0x2000fe88}, {name: r7, value: 0x2000fe88}, + {name: pc, value: 0x00203916}, {name: lr, value: 0x0020392d}] memory-regions: # stack memory fetched via # (lldb) p/x $sp @@ -14,7 +14,7 @@ memory-regions: 0x0000002a, 0x20010e58, 0x00203923, 0x00000001, 0x2000fe88, 0x00203911, 0x2000ffdc, 0xfffffff9, 0x00000102, 0x00000002, 0x000003f0, 0x0000002a, - 0x20012620, 0x00203215, 0x00203366, 0x81000200, + 0x20012620, 0x00203215, 0x00202a92, 0x81000200, 0x00203215, 0x200128b0, 0x0024928d, 0x2000fecc, 0x002491ed, 0x20010e58, 0x20010e4c, 0x2000ffa0, 0x200107a0, 0x0000003c, 0x200116e8, 0x200108b0, @@ -62,3 +62,26 @@ memory-regions: 0x98, 0xae, 0x28, 0x00 ] + # exception_thrower + # (lldb) disass -b -c 12 -n exception_thrower + # 0x202a88 <+0>: 0xb5f0 push {r4, r5, r6, r7, lr} + # 0x202a8a <+2>: 0xaf03 add r7, sp, #0xc + # 0x202a8c <+4>: 0xe92d0f00 push.w {r8, r9, r10, r11} + # 0x202a90 <+8>: 0xb0c3 sub sp, #0x10c + # 0x202a92 <+10>: 0xf7ffffd9 bl 0x202a48 + - addr: 0x202a88 + UInt8: [ + 0xf0, 0xb5, 0x03, 0xaf, 0x2d, 0xe9, 0x00, 0x0f, + 0xc3, 0xb0, 0xff, 0xf7, 0xd9, 0xff, 0xff, 0xf7 + ] + + # main: + # 0x202a7e <+0>: push {r7, lr} + # 0x202a80 <+2>: mov r7, sp + # 0x202a82 <+4>: bl 0x202a88 ; exception_thrower + # 0x202a86 <+8>: nop + - addr: 0x202a7e + UInt8: [ + 0x80, 0xb5, 0x6f, 0x46, 0x00, 0xf0, 0x01, 0xf8, + 0x00, 0xbf + ] diff --git a/lldb/test/API/functionalities/unwind/cortex-m-exception/binary.json b/lldb/test/API/functionalities/unwind/cortex-m-exception/binary.json index 8fcd5307ff82..0de0169f7adb 100644 --- a/lldb/test/API/functionalities/unwind/cortex-m-exception/binary.json +++ b/lldb/test/API/functionalities/unwind/cortex-m-exception/binary.json @@ -1,5 +1,5 @@ { - "triple": "armv7m-apple", + "triple": "armv7m--", "uuid": "2D157DBA-53C9-3AC7-B5A1-9D336EC831CB", "type": "executable", "sections": [ @@ -28,13 +28,13 @@ { "name": "exception_catcher", "type": "code", - "size": 44, + "size": 32, "address": 2111760 }, { "name": "exception_thrower", "type": "code", - "size": 2652, + "size": 16, "address": 2108040 } ] diff --git a/lldb/test/API/lang/cpp/abi_tag_structors/TestAbiTagStructors.py b/lldb/test/API/lang/cpp/abi_tag_structors/TestAbiTagStructors.py index 87d8adb42b82..2d3e4f7cdd47 100644 --- a/lldb/test/API/lang/cpp/abi_tag_structors/TestAbiTagStructors.py +++ b/lldb/test/API/lang/cpp/abi_tag_structors/TestAbiTagStructors.py @@ -10,6 +10,11 @@ from lldbsuite.test import lldbutil class AbiTagStructorsTestCase(TestBase): + @skipIf( + compiler="clang", + compiler_version=["<", "22"], + bugnumber="Required Clang flag not supported", + ) @expectedFailureAll(oslist=["windows"]) def test_with_structor_linkage_names(self): self.build(dictionary={"CXXFLAGS_EXTRAS": "-gstructor-decl-linkage-names"}) @@ -73,7 +78,16 @@ class AbiTagStructorsTestCase(TestBase): Test that without linkage names on structor declarations we can't call ABI-tagged structors. """ - self.build(dictionary={"CXXFLAGS_EXTRAS": "-gno-structor-decl-linkage-names"}) + # In older versions of Clang the -gno-structor-decl-linkage-names + # behaviour was the default. + if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion( + [">=", "22.0"] + ): + self.build( + dictionary={"CXXFLAGS_EXTRAS": "-gno-structor-decl-linkage-names"} + ) + else: + self.build() lldbutil.run_to_source_breakpoint( self, "Break here", lldb.SBFileSpec("main.cpp", False) @@ -105,12 +119,23 @@ class AbiTagStructorsTestCase(TestBase): "expression TaggedLocal()", error=True, substrs=["Couldn't look up symbols"] ) + @skipIf(compiler="clang", compiler_version=["<", "22"]) @expectedFailureAll(oslist=["windows"]) - def test_nested_no_structor_linkage_names(self): + def test_nested_with_structor_linkage_names(self): self.build(dictionary={"CXXFLAGS_EXTRAS": "-gstructor-decl-linkage-names"}) self.do_nested_structor_test() @expectedFailureAll(oslist=["windows"]) - def test_nested_with_structor_linkage_names(self): - self.build(dictionary={"CXXFLAGS_EXTRAS": "-gno-structor-decl-linkage-names"}) + def test_nested_no_structor_linkage_names(self): + # In older versions of Clang the -gno-structor-decl-linkage-names + # behaviour was the default. + if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion( + [">=", "22.0"] + ): + self.build( + dictionary={"CXXFLAGS_EXTRAS": "-gno-structor-decl-linkage-names"} + ) + else: + self.build() + self.do_nested_structor_test() diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py index c0545c70c84e..b3bed43c7587 100644 --- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py +++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py @@ -6,6 +6,11 @@ from lldbsuite.test import lldbutil class ExprDefinitionInDylibTestCase(TestBase): + @skipIf( + compiler="clang", + compiler_version=["<", "22"], + bugnumber="Required Clang flag not supported", + ) @skipIfWindows def test_with_structor_linkage_names(self): """ @@ -74,7 +79,16 @@ class ExprDefinitionInDylibTestCase(TestBase): Tests that if structor declarations don't have linkage names, we can't call ABI-tagged constructors. But non-tagged ones are fine. """ - self.build(dictionary={"CXXFLAGS_EXTRAS": "-gno-structor-decl-linkage-names"}) + # In older versions of Clang the -gno-structor-decl-linkage-names + # behaviour was the default. + if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion( + [">=", "22.0"] + ): + self.build( + dictionary={"CXXFLAGS_EXTRAS": "-gno-structor-decl-linkage-names"} + ) + else: + self.build() target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) self.assertTrue(target, VALID_TARGET) @@ -95,6 +109,6 @@ class ExprDefinitionInDylibTestCase(TestBase): self.expect_expr("Foo(10)", result_type="Foo") - self.expect("Base()", error=True) + self.expect("expr Base()", error=True) - self.expect("Bar()", error=True) + self.expect("expr Bar()", error=True) diff --git a/lldb/test/API/lang/cpp/floating-types-specialization/Makefile b/lldb/test/API/lang/cpp/floating-types-specialization/Makefile new file mode 100644 index 000000000000..99998b20bcb0 --- /dev/null +++ b/lldb/test/API/lang/cpp/floating-types-specialization/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/floating-types-specialization/TestCppFloatingTypesSpecialization.py b/lldb/test/API/lang/cpp/floating-types-specialization/TestCppFloatingTypesSpecialization.py new file mode 100644 index 000000000000..979391f3681f --- /dev/null +++ b/lldb/test/API/lang/cpp/floating-types-specialization/TestCppFloatingTypesSpecialization.py @@ -0,0 +1,37 @@ +import lldb +import lldbsuite.test.lldbplatformutil as lldbplatformutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestCase(TestBase): + @skipIf(compiler="clang", compiler_version=["<", "17.0"]) + def test(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// break here", lldb.SBFileSpec("main.cpp", False) + ) + + # On 32-bit Arm, you have to have the bfloat16 extension, or an FPU while + # not using the soft float mode. The target we assume has none of that + # so instead of __bf16 we get __fp16. + is_arm_32_bit = lldbplatformutil.getArchitecture() == "arm" + + self.expect_expr( + "f0", result_type=("Foo<__fp16>" if is_arm_32_bit else "Foo<__bf16>") + ) + + # When __bf16 is actually __fp16, f1 looks like it inherits from itself. + # Which clang allows but LLDB fails to evaluate. + if not is_arm_32_bit: + self.expect_expr("f1", result_type="Foo<__fp16>") + + # Test sizeof to ensure while computing layout we don't do + # infinite recursion. + v = self.frame().EvaluateExpression("sizeof(f0)") + self.assertEqual(v.GetValueAsUnsigned() > 0, True) + + if not is_arm_32_bit: + v = self.frame().EvaluateExpression("sizeof(f1)") + self.assertEqual(v.GetValueAsUnsigned() > 0, True) diff --git a/lldb/test/API/lang/cpp/floating-types-specialization/main.cpp b/lldb/test/API/lang/cpp/floating-types-specialization/main.cpp new file mode 100644 index 000000000000..e3e8a3767fef --- /dev/null +++ b/lldb/test/API/lang/cpp/floating-types-specialization/main.cpp @@ -0,0 +1,11 @@ +template <typename T> struct Foo; + +template <> struct Foo<__bf16> {}; + +template <> struct Foo<_Float16> : Foo<__bf16> {}; + +int main() { + Foo<__bf16> f0; + Foo<_Float16> f1; + return 0; // break here +} diff --git a/lldb/test/API/lang/cpp/function-call-from-object-file/Makefile b/lldb/test/API/lang/cpp/function-call-from-object-file/Makefile new file mode 100644 index 000000000000..285bbfbbca4f --- /dev/null +++ b/lldb/test/API/lang/cpp/function-call-from-object-file/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp lib1.cpp lib2.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/function-call-from-object-file/TestFunctionCallFromObjectFile.py b/lldb/test/API/lang/cpp/function-call-from-object-file/TestFunctionCallFromObjectFile.py new file mode 100644 index 000000000000..f0a7aef182a6 --- /dev/null +++ b/lldb/test/API/lang/cpp/function-call-from-object-file/TestFunctionCallFromObjectFile.py @@ -0,0 +1,29 @@ +""" +Tests that we can call functions that have definitions in multiple +CUs in the debug-info (which is the case for functions defined in headers). +The linker will most likely de-duplicate the functiond definitions when linking +the final executable. On Darwin, this will create a debug-map that LLDB will use +to fix up object file addresses to addresses in the linked executable. However, +if we parsed the DIE from the object file whose functiond definition got stripped +by the linker, LLDB needs to ensure it can still resolve the function symbol it +got for it. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestFunctionCallFromObjectFile(TestBase): + def test_lib1(self): + self.build() + lldbutil.run_to_name_breakpoint(self, "lib1_func") + + self.expect_expr("Foo{}.foo()", result_type="int", result_value="15") + + def test_lib2(self): + self.build() + lldbutil.run_to_name_breakpoint(self, "lib2_func") + + self.expect_expr("Foo{}.foo()", result_type="int", result_value="15") diff --git a/lldb/test/API/lang/cpp/function-call-from-object-file/common.h b/lldb/test/API/lang/cpp/function-call-from-object-file/common.h new file mode 100644 index 000000000000..76e23be6b97a --- /dev/null +++ b/lldb/test/API/lang/cpp/function-call-from-object-file/common.h @@ -0,0 +1,8 @@ +#ifndef COMMON_H_IN +#define COMMON_H_IN + +struct Foo { + int foo() { return 15; } +}; + +#endif // COMMON_H_IN diff --git a/lldb/test/API/lang/cpp/function-call-from-object-file/lib1.cpp b/lldb/test/API/lang/cpp/function-call-from-object-file/lib1.cpp new file mode 100644 index 000000000000..b97bcc1b712b --- /dev/null +++ b/lldb/test/API/lang/cpp/function-call-from-object-file/lib1.cpp @@ -0,0 +1,8 @@ +#include "common.h" + +// Parameter "Foo*" forces LLDB to parse "Foo" from the object +// file that it is stopped in. +void lib1_func(Foo *) { + // Force definition into lib1.o debug-info. + Foo{}.foo(); +} diff --git a/lldb/test/API/lang/cpp/function-call-from-object-file/lib2.cpp b/lldb/test/API/lang/cpp/function-call-from-object-file/lib2.cpp new file mode 100644 index 000000000000..2f9d81a8bdf4 --- /dev/null +++ b/lldb/test/API/lang/cpp/function-call-from-object-file/lib2.cpp @@ -0,0 +1,6 @@ +#include "common.h" + +void lib2_func(Foo *) { + // Force definition into lib2.o debug-info. + Foo{}.foo(); +} diff --git a/lldb/test/API/lang/cpp/function-call-from-object-file/main.cpp b/lldb/test/API/lang/cpp/function-call-from-object-file/main.cpp new file mode 100644 index 000000000000..61ca798daf1d --- /dev/null +++ b/lldb/test/API/lang/cpp/function-call-from-object-file/main.cpp @@ -0,0 +1,10 @@ +struct Foo; + +extern void lib1_func(Foo *); +extern void lib2_func(Foo *); + +int main() { + lib1_func(nullptr); + lib2_func(nullptr); + return 0; +} diff --git a/lldb/test/API/lang/cpp/structured-binding/TestStructuredBinding.py b/lldb/test/API/lang/cpp/structured-binding/TestStructuredBinding.py index 5f939ecfbef2..882c91d1ce8c 100644 --- a/lldb/test/API/lang/cpp/structured-binding/TestStructuredBinding.py +++ b/lldb/test/API/lang/cpp/structured-binding/TestStructuredBinding.py @@ -99,16 +99,21 @@ class TestStructuredBinding(TestBase): self.expect_expr("ty2", result_value="'z'") self.expect_expr("tz2", result_value="10") - self.expect( - "frame variable", - substrs=[ - "tx1 =", - "ty1 =", - "tz1 =", - "tx2 =", - "ty2 =", - "tz2 =", - "mp1 =", - "mp2 =", - ], - ) + # Older versions of Clang marked structured binding variables + # as artificial, and thus LLDB wouldn't display them. + if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion( + [">=", "22.0"] + ): + self.expect( + "frame variable", + substrs=[ + "tx1 =", + "ty1 =", + "tz1 =", + "tx2 =", + "ty2 =", + "tz2 =", + "mp1 =", + "mp2 =", + ], + ) diff --git a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py index eac7b5ef1099..83c057220410 100644 --- a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py +++ b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py @@ -1,4 +1,5 @@ import lldb +import lldbsuite.test.lldbplatformutil as lldbplatformutil from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil @@ -82,8 +83,12 @@ class TestCase(TestBase): value = self.expect_expr("temp7", result_type="Foo<__fp16, __fp16>") self.assertFalse(value.GetType().GetTemplateArgumentValue(target, 1)) - value = self.expect_expr("temp8", result_type="Foo<__fp16, __fp16>") - self.assertFalse(value.GetType().GetTemplateArgumentValue(target, 1)) + # The target we use when evaluating these expressions for Arm leads to there + # not being a __bf16 type in the AST so we fall back to __fp16 and evaluating + # this fails. + if lldbplatformutil.getArchitecture() != "arm": + value = self.expect_expr("temp8", result_type="Foo<__bf16, __bf16>") + self.assertFalse(value.GetType().GetTemplateArgumentValue(target, 1)) value = self.expect_expr("temp9", result_type="Bar<double, 1.200000e+00>") template_param_value = value.GetType().GetTemplateArgumentValue(target, 1) diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/Makefile b/lldb/test/API/lang/objc/ivar-in-framework-base/Makefile new file mode 100644 index 000000000000..c7947fc138c1 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/Makefile @@ -0,0 +1,6 @@ +OBJC_SOURCES := main.m lib.m +LD_EXTRAS = -framework Foundation + +include Makefile.rules + +lib.o: CFLAGS = $(CFLAGS_NO_DEBUG) diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/TestIvarInFrameworkBase.py b/lldb/test/API/lang/objc/ivar-in-framework-base/TestIvarInFrameworkBase.py new file mode 100644 index 000000000000..40fc6b7a6899 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/TestIvarInFrameworkBase.py @@ -0,0 +1,39 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestIvarInFrameworkBase(TestBase): + """ + Tests whether LLDB's data inspection commands can correctly retrieve + information about ivars from the Objective-C runtime. + In this test-case we have a base class type for which we don't have access + to the debug-info of the implementation (mimicking the scenario of subclassing + a type from a system framework). LLDB won't be able to see the backing ivar for + 'fooProp' from just debug-info, but it will fall back on the runtime to get the + necessary information. + """ + + def test_frame_var(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.m")) + self.expect("frame variable *bar", substrs=["_fooProp = 10", "_barProp = 15"]) + + def test_expr(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.m")) + self.expect_expr( + "*bar", + result_type="Bar", + result_children=[ + ValueCheck( + name="Foo", + children=[ + ValueCheck(name="NSObject"), + ValueCheck(name="_fooProp", value="10"), + ], + ), + ValueCheck(name="_barProp", value="15"), + ], + ) diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/lib.h b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.h new file mode 100644 index 000000000000..31ceb53dc688 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.h @@ -0,0 +1,6 @@ +#import <Foundation/Foundation.h> + +@interface Foo : NSObject +@property int fooProp; +- (id)init; +@end diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/lib.m b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.m new file mode 100644 index 000000000000..e1bf80ac4bd4 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.m @@ -0,0 +1,8 @@ +#import "lib.h" + +@implementation Foo +- (id)init { + self.fooProp = 10; + return self; +} +@end diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/main.m b/lldb/test/API/lang/objc/ivar-in-framework-base/main.m new file mode 100644 index 000000000000..1fd352ec92c5 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/main.m @@ -0,0 +1,22 @@ +#import "lib.h" +#include <stdio.h> + +@interface Bar : Foo +@property int barProp; +- (id)init; +@end + +@implementation Bar + +- (id)init { + self = [super init]; + self.barProp = 15; + return self; +} +@end + +int main() { + Bar *bar = [Bar new]; + puts("break here"); + return 0; +} diff --git a/lldb/test/API/macosx/debugserver-multimemread/Makefile b/lldb/test/API/macosx/debugserver-multimemread/Makefile new file mode 100644 index 000000000000..10495940055b --- /dev/null +++ b/lldb/test/API/macosx/debugserver-multimemread/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py b/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py new file mode 100644 index 000000000000..6caa5f85c284 --- /dev/null +++ b/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py @@ -0,0 +1,102 @@ +""" +Tests debugserver support for MultiMemRead. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +@skipUnlessDarwin +@skipIfOutOfTreeDebugserver +class TestCase(TestBase): + def send_process_packet(self, packet_str): + self.runCmd(f"proc plugin packet send {packet_str}", check=False) + # The output is of the form: + # packet: <packet_str> + # response: <response> + reply = self.res.GetOutput().split("\n") + packet = reply[0].strip() + response = reply[1].strip() + + self.assertTrue(packet.startswith("packet: ")) + self.assertTrue(response.startswith("response: ")) + return response[len("response: ") :] + + def check_invalid_packet(self, packet_str): + reply = self.send_process_packet("packet_str") + self.assertEqual(reply, "E03") + + def test_packets(self): + self.build() + source_file = lldb.SBFileSpec("main.c") + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( + self, "break here", source_file + ) + + reply = self.send_process_packet("qSupported") + self.assertIn("MultiMemRead+", reply) + + mem_address_var = thread.frames[0].FindVariable("memory") + self.assertTrue(mem_address_var) + mem_address = mem_address_var.GetValueAsUnsigned() + 42 + + # no ":" + self.check_invalid_packet("MultiMemRead") + # missing ranges + self.check_invalid_packet("MultiMemRead:") + # needs at least one range + self.check_invalid_packet("MultiMemRead:ranges:") + # needs at least one range + self.check_invalid_packet("MultiMemRead:ranges:,") + # a range is a pair of numbers + self.check_invalid_packet("MultiMemRead:ranges:10") + # a range is a pair of numbers + self.check_invalid_packet("MultiMemRead:ranges:10,") + # range list must end with ; + self.check_invalid_packet("MultiMemRead:ranges:10,2") + self.check_invalid_packet("MultiMemRead:ranges:10,2,") + self.check_invalid_packet("MultiMemRead:ranges:10,2,3") + # ranges are pairs of numbers. + self.check_invalid_packet("MultiMemRead:ranges:10,2,3;") + # unrecognized field + self.check_invalid_packet("MultiMemRead:ranges:10,2;blah:;") + # unrecognized field + self.check_invalid_packet("MultiMemRead:blah:;ranges:10,2;") + + # Zero-length reads are ok. + reply = self.send_process_packet("MultiMemRead:ranges:0,0;") + self.assertEqual(reply, "0;") + + # Debugserver is permissive with trailing commas. + reply = self.send_process_packet("MultiMemRead:ranges:10,2,;") + self.assertEqual(reply, "0;") + reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},2,;") + self.assertEqual(reply, "2;ab") + + reply = self.send_process_packet("MultiMemRead:ranges:10,2;") + self.assertEqual(reply, "0;") + reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},0;") + self.assertEqual(reply, "0;") + reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},2;") + self.assertEqual(reply, "2;ab") + reply = self.send_process_packet( + f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4;" + ) + self.assertEqual(reply, "2,4;abcdef") + reply = self.send_process_packet( + f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4,{mem_address+6:x},8;" + ) + self.assertEqual(reply, "2,4,8;abcdefghijklmn") + + # Test zero length in the middle. + reply = self.send_process_packet( + f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},0,{mem_address+6:x},8;" + ) + self.assertEqual(reply, "2,0,8;abghijklmn") + # Test zero length in the end. + reply = self.send_process_packet( + f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4,{mem_address+6:x},0;" + ) + self.assertEqual(reply, "2,4,0;abcdef") diff --git a/lldb/test/API/macosx/debugserver-multimemread/main.c b/lldb/test/API/macosx/debugserver-multimemread/main.c new file mode 100644 index 000000000000..44cdd475b550 --- /dev/null +++ b/lldb/test/API/macosx/debugserver-multimemread/main.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <string.h> + +int main(int argc, char **argv) { + char *memory = malloc(1024); + memset(memory, '-', 1024); + // Write "interesting" characters at an offset from the memory filled with + // `-`. This way, if we read outside the range in either direction, we should + // find `-`s`. + int offset = 42; + for (int i = offset; i < offset + 14; i++) + memory[i] = 'a' + (i - offset); + return 0; // break here +} diff --git a/lldb/test/API/macosx/mte/Makefile b/lldb/test/API/macosx/mte/Makefile new file mode 100644 index 000000000000..d614e0f0a3bc --- /dev/null +++ b/lldb/test/API/macosx/mte/Makefile @@ -0,0 +1,15 @@ +C_SOURCES := main.c + +EXE := uaf + +binary-plain: uaf +binary-entitled: uaf sign + +all: binary-entitled + +include Makefile.rules + +sign: mte-entitlements.plist uaf +ifeq ($(OS),Darwin) + codesign -s - -f --entitlements $^ +endif diff --git a/lldb/test/API/macosx/mte/TestDarwinMTE.py b/lldb/test/API/macosx/mte/TestDarwinMTE.py new file mode 100644 index 000000000000..a70b4b4aed26 --- /dev/null +++ b/lldb/test/API/macosx/mte/TestDarwinMTE.py @@ -0,0 +1,122 @@ +"""Test MTE Memory Tagging on Apple platforms""" + +import lldb +import re +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbsuite.test.cpu_feature as cpu_feature + +exe_name = "uaf" # Must match Makefile + + +class TestDarwinMTE(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_process_launch_memory_tagging(self): + self.build(make_targets=["binary-plain"]) + self.createTestTarget(self.getBuildArtifact(exe_name)) + + self.expect("process launch", substrs=["exited with status = 0"]) + + self.expect( + "process launch --memory-tagging", + substrs=["stopped", "stop reason = EXC_ARM_MTE_TAG_FAULT"], + ) + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_tag_fault(self): + self.build() + exe = self.getBuildArtifact(exe_name) + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + process = target.LaunchSimple(None, None, None) + self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + + self.expect( + "thread info", + substrs=[ + "stop reason = EXC_ARM_MTE_TAG_FAULT", + "MTE tag mismatch detected", + ], + ) + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_memory_region(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name + ) + + # (lldb) memory region ptr + # [0x00000001005ec000-0x00000001009ec000) rw- + # memory tagging: enabled + # Modified memory (dirty) page list provided, 2 entries. + # Dirty pages: 0x1005ec000, 0x1005fc000. + self.expect("memory region ptr", substrs=["memory tagging: enabled"]) + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_memory_read_show_tags(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name + ) + + # (lldb) memory read ptr-16 ptr+48 --show-tags + # 0x7d2c00930: 00 00 00 00 00 00 00 00 d0 e3 a5 0a 02 00 00 00 ................ (tag: 0x3) + # 0x7d2c00940: 48 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 Hello........... (tag: 0xb) + # 0x7d2c00950: 57 6f 72 6c 64 00 00 00 00 00 00 00 00 00 00 00 World........... (tag: 0xb) + # 0x7d2c00960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ (tag: 0x9) + self.expect( + "memory read ptr-16 ptr+48 --show-tags", + substrs=[" Hello...........", " World..........."], + patterns=[r"(.*\(tag: 0x[0-9a-f]\)\n){4}"], + ) + + def _parse_pointer_tag(self, output): + return re.search(r"Logical tag: (0x[0-9a-f])", output).group(1) + + def _parse_memory_tags(self, output, expected_tag_count): + tags = re.findall(r"\): (0x[0-9a-f])", output) + self.assertEqual(len(tags), expected_tag_count) + return tags + + @skipUnlessFeature(cpu_feature.AArch64.MTE) + def test_memory_tag_read(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name + ) + + # (lldb) memory tag read ptr-1 ptr+33 + # Logical tag: 0x5 + # Allocation tags: + # [0x100a65a40, 0x100a65a50): 0xf (mismatch) + # [0x100a65a50, 0x100a65a60): 0x5 + # [0x100a65a60, 0x100a65a70): 0x5 + # [0x100a65a70, 0x100a65a80): 0x2 (mismatch) + self.expect( + "memory tag read ptr-1 ptr+33", + substrs=["Logical tag: 0x", "Allocation tags:", "(mismatch)"], + patterns=[r"(\[.*\): 0x[0-9a-f].*\n){4}"], + ) + output = self.res.GetOutput() + self.assertEqual(output.count("(mismatch)"), 2) + ptr_tag = self._parse_pointer_tag(output) + tags = self._parse_memory_tags(output, 4) + self.assertEqual(tags[1], ptr_tag) + self.assertEqual(tags[2], ptr_tag) + self.assertNotEqual(tags[0], ptr_tag) # Memory that comes before/after + self.assertNotEqual(tags[3], ptr_tag) # allocation has different tag. + + # Continue running until MTE fault + self.expect("process continue", substrs=["stop reason = EXC_ARM_MTE_TAG_FAULT"]) + + self.runCmd("memory tag read ptr-1 ptr+33") + output = self.res.GetOutput() + self.assertEqual(output.count("(mismatch)"), 4) + tags = self._parse_memory_tags(output, 4) + self.assertTrue(all(t != ptr_tag for t in tags)) diff --git a/lldb/test/API/macosx/mte/main.c b/lldb/test/API/macosx/mte/main.c new file mode 100644 index 000000000000..f9f6b1594ef4 --- /dev/null +++ b/lldb/test/API/macosx/mte/main.c @@ -0,0 +1,28 @@ +#include <malloc/malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// Produce some names on the trace +const size_t tag_granule = 16; +static uint8_t *my_malloc(void) { return malloc(2 * tag_granule); } +static uint8_t *allocate(void) { return my_malloc(); } + +static void my_free(void *ptr) { free(ptr); } +static void deallocate(void *ptr) { my_free(ptr); } + +static void touch_memory(uint8_t *ptr) { ptr[7] = 1; } // invalid access +static void modify(uint8_t *ptr) { touch_memory(ptr); } + +int main() { + uint8_t *ptr = allocate(); + + strncpy((char *)ptr, "Hello", 16); + strncpy((char *)ptr + 16, "World", 16); + + deallocate(ptr); // before free + + modify(ptr); // use-after-free + + return 0; +} diff --git a/lldb/test/API/macosx/mte/mte-entitlements.plist b/lldb/test/API/macosx/mte/mte-entitlements.plist new file mode 100644 index 000000000000..6de5d5634d87 --- /dev/null +++ b/lldb/test/API/macosx/mte/mte-entitlements.plist @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.hardened-process</key> + <true/> + <key>com.apple.security.hardened-process.checked-allocations</key> + <true/> +</dict> +</plist> diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py index 43f45f330ee2..44b118328801 100644 --- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py +++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py @@ -294,3 +294,150 @@ class DebuggerAPITestCase(TestBase): self.assertEqual(instance_str, class_str) self.assertEqual(class_str, property_str) + + def test_find_target_with_unique_id(self): + """Test SBDebugger.FindTargetByGloballyUniqueID() functionality.""" + + # Test with invalid ID - should return invalid target + invalid_target = self.dbg.FindTargetByGloballyUniqueID(999999) + self.assertFalse(invalid_target.IsValid()) + + # Test with ID 0 - should return invalid target + zero_target = self.dbg.FindTargetByGloballyUniqueID(0) + self.assertFalse(zero_target.IsValid()) + + # Build a real executable and create target with it + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + self.assertTrue(target.IsValid()) + + # Find the target using its unique ID + unique_id = target.GetGloballyUniqueID() + self.assertNotEqual(unique_id, lldb.LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID) + found_target = self.dbg.FindTargetByGloballyUniqueID(unique_id) + self.assertTrue(found_target.IsValid()) + self.assertEqual( + self.dbg.GetIndexOfTarget(target), self.dbg.GetIndexOfTarget(found_target) + ) + self.assertEqual(found_target.GetGloballyUniqueID(), unique_id) + + def test_target_unique_id_uniqueness(self): + """Test that Target.GetGloballyUniqueID() returns unique values across multiple targets.""" + + # Create multiple targets and verify they all have unique IDs + self.build() + exe = self.getBuildArtifact("a.out") + targets = [] + unique_ids = set() + + for i in range(10): + target = self.dbg.CreateTarget(exe) + self.assertTrue(target.IsValid()) + + unique_id = target.GetGloballyUniqueID() + self.assertNotEqual(unique_id, 0) + + # Verify this ID hasn't been used before + self.assertNotIn( + unique_id, unique_ids, f"Duplicate unique ID found: {unique_id}" + ) + + unique_ids.add(unique_id) + targets.append(target) + + # Verify all targets can still be found by their IDs + for target in targets: + unique_id = target.GetGloballyUniqueID() + found = self.dbg.FindTargetByGloballyUniqueID(unique_id) + self.assertTrue(found.IsValid()) + self.assertEqual(found.GetGloballyUniqueID(), unique_id) + + def test_target_unique_id_uniqueness_after_deletion(self): + """Test finding targets have unique ID after target deletion.""" + # Create two targets + self.build() + exe = self.getBuildArtifact("a.out") + target1 = self.dbg.CreateTarget(exe) + target2 = self.dbg.CreateTarget(exe) + self.assertTrue(target1.IsValid()) + self.assertTrue(target2.IsValid()) + + unique_id1 = target1.GetGloballyUniqueID() + unique_id2 = target2.GetGloballyUniqueID() + self.assertNotEqual(unique_id1, 0) + self.assertNotEqual(unique_id2, 0) + self.assertNotEqual(unique_id1, unique_id2) + + # Verify we can find them initially + found_target1 = self.dbg.FindTargetByGloballyUniqueID(unique_id1) + found_target2 = self.dbg.FindTargetByGloballyUniqueID(unique_id2) + self.assertTrue(found_target1.IsValid()) + self.assertTrue(found_target2.IsValid()) + target2_index = self.dbg.GetIndexOfTarget(target2) + + # Delete target 2 + deleted = self.dbg.DeleteTarget(target2) + self.assertTrue(deleted) + + # Try to find the deleted target - should not be found + not_found_target = self.dbg.FindTargetByGloballyUniqueID(unique_id2) + self.assertFalse(not_found_target.IsValid()) + + # Create a new target + target3 = self.dbg.CreateTarget(exe) + self.assertTrue(target3.IsValid()) + # Target list index of target3 should be the same as target2's + # since it was deleted, but it should have a distinct unique ID + target3_index = self.dbg.GetIndexOfTarget(target3) + unique_id3 = target3.GetGloballyUniqueID() + self.assertEqual(target3_index, target2_index) + self.assertNotEqual(unique_id3, unique_id2) + self.assertNotEqual(unique_id3, unique_id1) + # Make sure we can find the new target + found_target3 = self.dbg.FindTargetByGloballyUniqueID( + target3.GetGloballyUniqueID() + ) + self.assertTrue(found_target3.IsValid()) + + def test_target_globally_unique_id_across_debuggers(self): + """Test that target IDs are globally unique across multiple debuggers.""" + self.build() + exe = self.getBuildArtifact("a.out") + + # Create two debuggers with targets each + debugger1 = lldb.SBDebugger.Create() + debugger2 = lldb.SBDebugger.Create() + self.addTearDownHook(lambda: lldb.SBDebugger.Destroy(debugger1)) + self.addTearDownHook(lambda: lldb.SBDebugger.Destroy(debugger2)) + + # Create 2 targets per debugger + targets_d1 = [debugger1.CreateTarget(exe), debugger1.CreateTarget(exe)] + targets_d2 = [debugger2.CreateTarget(exe), debugger2.CreateTarget(exe)] + targets = targets_d1 + targets_d2 + + # Get all IDs and verify they're unique + ids = [target.GetGloballyUniqueID() for target in targets] + self.assertEqual( + len(set(ids)), len(ids), f"IDs should be globally unique: {ids}" + ) + self.assertTrue( + all(uid != lldb.LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID for uid in ids), + "All IDs should be valid", + ) + + # Verify targets can be found by their IDs in respective debuggers + for debugger, target_pair in [ + (debugger1, targets[:2]), + (debugger2, targets[2:]), + ]: + for target in target_pair: + found = debugger.FindTargetByGloballyUniqueID( + target.GetGloballyUniqueID() + ) + self.assertTrue( + found.IsValid(), "Target should be found by its unique ID" + ) + self.assertEqual( + found.GetGloballyUniqueID(), target.GetGloballyUniqueID() + ) diff --git a/lldb/test/API/python_api/default-constructor/sb_filespec.py b/lldb/test/API/python_api/default-constructor/sb_filespec.py index 4ab5c49c37eb..5dd78b1ace98 100644 --- a/lldb/test/API/python_api/default-constructor/sb_filespec.py +++ b/lldb/test/API/python_api/default-constructor/sb_filespec.py @@ -10,5 +10,5 @@ def fuzz_obj(obj): obj.ResolveExecutableLocation() obj.GetFilename() obj.GetDirectory() - obj.GetPath(None, 0) + obj.GetPath(1) obj.GetDescription(lldb.SBStream()) diff --git a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py index 1029bdc3096d..01ed11a5a112 100644 --- a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py +++ b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py @@ -1,4 +1,4 @@ -"""Test the SBCommandInterpreter APIs.""" +"""tESt the SBCommandInterpreter APIs.""" import json import lldb @@ -156,13 +156,15 @@ class CommandInterpreterAPICase(TestBase): self.assertEqual(transcript[0]["error"], "") # (lldb) an-unknown-command - self.assertEqual(transcript[1], + self.assertEqual( + transcript[1], { "command": "an-unknown-command", # Unresolved commands don't have "commandName"/"commandArguments" "output": "", "error": "error: 'an-unknown-command' is not a valid command.\n", - }) + }, + ) # (lldb) br s -f main.c -l <line> self.assertEqual(transcript[2]["command"], "br s -f main.c -l %d" % self.line) @@ -175,14 +177,17 @@ class CommandInterpreterAPICase(TestBase): self.assertEqual(transcript[2]["error"], "") # (lldb) p a - self.assertEqual(transcript[3], + self.assertEqual( + transcript[3], { "command": "p a", "commandName": "dwim-print", "commandArguments": "-- a", "output": "", - "error": "error: <user expression 0>:1:1: use of undeclared identifier 'a'\n 1 | a\n | ^\n", - }) + "error": "note: Falling back to default language. Ran expression as 'Objective C++'.\n" + "error: <user expression 0>:1:1: use of undeclared identifier 'a'\n 1 | a\n | ^\n", + }, + ) # (lldb) statistics dump self.assertEqual(transcript[4]["command"], "statistics dump") @@ -203,7 +208,10 @@ class CommandInterpreterAPICase(TestBase): self.assertTrue(ci, VALID_COMMAND_INTERPRETER) # The setting's default value should be "false" - self.runCmd("settings show interpreter.save-transcript", "interpreter.save-transcript (boolean) = false\n") + self.runCmd( + "settings show interpreter.save-transcript", + "interpreter.save-transcript (boolean) = false\n", + ) def test_save_transcript_setting_off(self): ci = self.dbg.GetCommandInterpreter() @@ -250,17 +258,37 @@ class CommandInterpreterAPICase(TestBase): structured_data_1 = ci.GetTranscript() self.assertTrue(structured_data_1.IsValid()) self.assertEqual(structured_data_1.GetSize(), 1) - self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100), "version") + self.assertEqual( + structured_data_1.GetItemAtIndex(0) + .GetValueForKey("command") + .GetStringValue(100), + "version", + ) # Run some more commands and get the transcript as structured data again self.runCmd("help") structured_data_2 = ci.GetTranscript() self.assertTrue(structured_data_2.IsValid()) self.assertEqual(structured_data_2.GetSize(), 2) - self.assertEqual(structured_data_2.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100), "version") - self.assertEqual(structured_data_2.GetItemAtIndex(1).GetValueForKey("command").GetStringValue(100), "help") + self.assertEqual( + structured_data_2.GetItemAtIndex(0) + .GetValueForKey("command") + .GetStringValue(100), + "version", + ) + self.assertEqual( + structured_data_2.GetItemAtIndex(1) + .GetValueForKey("command") + .GetStringValue(100), + "help", + ) # Now, the first structured data should remain unchanged self.assertTrue(structured_data_1.IsValid()) self.assertEqual(structured_data_1.GetSize(), 1) - self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100), "version") + self.assertEqual( + structured_data_1.GetItemAtIndex(0) + .GetValueForKey("command") + .GetStringValue(100), + "version", + ) diff --git a/lldb/test/API/python_api/sbtype_basic_type/TestSBTypeBasicType.py b/lldb/test/API/python_api/sbtype_basic_type/TestSBTypeBasicType.py index 535d8b900673..f8594dfc6b78 100644 --- a/lldb/test/API/python_api/sbtype_basic_type/TestSBTypeBasicType.py +++ b/lldb/test/API/python_api/sbtype_basic_type/TestSBTypeBasicType.py @@ -28,3 +28,11 @@ class TestCase(TestBase): self.assertEqual(b.GetType().GetBasicType(), int_basic_type) self.assertEqual(c.GetType().GetBasicType(), int_basic_type) self.assertEqual(d.GetType().GetBasicType(), int_basic_type) + + # Check the size of the chosen basic types. + self.assertEqual(self.target().FindFirstType("__int128").size, 16) + self.assertEqual(self.target().FindFirstType("unsigned __int128").size, 16) + + # Check the size of the chosen aliases of basic types. + self.assertEqual(self.target().FindFirstType("__int128_t").size, 16) + self.assertEqual(self.target().FindFirstType("__uint128_t").size, 16) diff --git a/lldb/test/API/tools/lldb-dap/attach-commands/Makefile b/lldb/test/API/tools/lldb-dap/attach-commands/Makefile new file mode 100644 index 000000000000..10495940055b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/attach-commands/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py b/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py new file mode 100644 index 000000000000..9e29f07db80f --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py @@ -0,0 +1,145 @@ +""" +Test lldb-dap attach commands +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import time + + +class TestDAP_attachCommands(lldbdap_testcase.DAPTestCaseBase): + @skipIfNetBSD # Hangs on NetBSD as well + def test_commands(self): + """ + Tests the "initCommands", "preRunCommands", "stopCommands", + "exitCommands", "terminateCommands" and "attachCommands" + that can be passed during attach. + + "initCommands" are a list of LLDB commands that get executed + before the target is created. + "preRunCommands" are a list of LLDB commands that get executed + after the target has been created and before the launch. + "stopCommands" are a list of LLDB commands that get executed each + time the program stops. + "exitCommands" are a list of LLDB commands that get executed when + the process exits + "attachCommands" are a list of LLDB commands that get executed and + must have a valid process in the selected target in LLDB after + they are done executing. This allows custom commands to create any + kind of debug session. + "terminateCommands" are a list of LLDB commands that get executed when + the debugger session terminates. + """ + program = self.build_and_create_debug_adapter_for_attach() + + # Here we just create a target and launch the process as a way to test + # if we are able to use attach commands to create any kind of a target + # and use it for debugging + attachCommands = [ + 'target create -d "%s"' % (program), + "process launch --stop-at-entry", + ] + initCommands = ["target list", "platform list"] + preRunCommands = ["image list a.out", "image dump sections a.out"] + postRunCommands = ["help trace", "help process trace"] + stopCommands = ["frame variable", "thread backtrace"] + exitCommands = ["expr 2+3", "expr 3+4"] + terminateCommands = ["expr 4+2"] + self.attach( + program=program, + attachCommands=attachCommands, + initCommands=initCommands, + preRunCommands=preRunCommands, + stopCommands=stopCommands, + exitCommands=exitCommands, + terminateCommands=terminateCommands, + postRunCommands=postRunCommands, + ) + # Get output from the console. This should contain both the + # "initCommands" and the "preRunCommands". + output = self.get_console() + # Verify all "initCommands" were found in console output + self.verify_commands("initCommands", output, initCommands) + # Verify all "preRunCommands" were found in console output + self.verify_commands("preRunCommands", output, preRunCommands) + # Verify all "postRunCommands" were found in console output + self.verify_commands("postRunCommands", output, postRunCommands) + + functions = ["main"] + breakpoint_ids = self.set_function_breakpoints(functions) + self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") + self.continue_to_breakpoints(breakpoint_ids) + output = self.collect_console(pattern=stopCommands[-1]) + self.verify_commands("stopCommands", output, stopCommands) + + # Continue after launch and hit the "pause()" call and stop the target. + # Get output from the console. This should contain both the + # "stopCommands" that were run after we stop. + self.do_continue() + time.sleep(0.5) + self.dap_server.request_pause() + self.dap_server.wait_for_stopped() + output = self.collect_console(pattern=stopCommands[-1]) + self.verify_commands("stopCommands", output, stopCommands) + + # Continue until the program exits + self.continue_to_exit() + # Get output from the console. This should contain both the + # "exitCommands" that were run after the second breakpoint was hit + # and the "terminateCommands" due to the debugging session ending + output = self.collect_console( + pattern=terminateCommands[0], + ) + self.verify_commands("exitCommands", output, exitCommands) + self.verify_commands("terminateCommands", output, terminateCommands) + + def test_attach_command_process_failures(self): + """ + Tests that a 'attachCommands' is expected to leave the debugger's + selected target with a valid process. + """ + program = self.build_and_create_debug_adapter_for_attach() + attachCommands = ['script print("oops, forgot to attach to a process...")'] + resp = self.attach( + program=program, + attachCommands=attachCommands, + expectFailure=True, + ) + self.assertFalse(resp["success"]) + self.assertIn( + "attachCommands failed to attach to a process", + resp["body"]["error"]["format"], + ) + + @skipIfNetBSD # Hangs on NetBSD as well + def test_terminate_commands(self): + """ + Tests that the "terminateCommands", that can be passed during + attach, are run when the debugger is disconnected. + """ + program = self.build_and_create_debug_adapter_for_attach() + + # Here we just create a target and launch the process as a way to test + # if we are able to use attach commands to create any kind of a target + # and use it for debugging + attachCommands = [ + 'target create -d "%s"' % (program), + "process launch --stop-at-entry", + ] + terminateCommands = ["expr 4+2"] + self.attach( + program=program, + attachCommands=attachCommands, + terminateCommands=terminateCommands, + disconnectAutomatically=False, + ) + self.get_console() + # Once it's disconnected the console should contain the + # "terminateCommands" + self.dap_server.request_disconnect(terminateDebuggee=True) + output = self.collect_console( + pattern=terminateCommands[0], + ) + self.verify_commands("terminateCommands", output, terminateCommands) diff --git a/lldb/test/API/tools/lldb-dap/attach-commands/main.c b/lldb/test/API/tools/lldb-dap/attach-commands/main.c new file mode 100644 index 000000000000..f56d5d53afa0 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/attach-commands/main.c @@ -0,0 +1,30 @@ +#include "attach.h" +#include <stdio.h> +#ifdef _WIN32 +#include <process.h> +#include <windows.h> +#else +#include <unistd.h> +#endif + +int main(int argc, char const *argv[]) { + lldb_enable_attach(); + + if (argc >= 2) { + // Create the synchronization token. + FILE *f = fopen(argv[1], "wx"); + if (!f) + return 1; + fputs("\n", f); + fflush(f); + fclose(f); + } + + printf("pid = %i\n", getpid()); +#ifdef _WIN32 + Sleep(10 * 1000); +#else + sleep(10); +#endif + return 0; // breakpoint 1 +} diff --git a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py index c54e21c1b973..5331a9f94ef1 100644 --- a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py +++ b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py @@ -11,50 +11,35 @@ import threading import time -def spawn_and_wait(program, delay): - if delay: - time.sleep(delay) - process = subprocess.Popen( - [program], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - process.wait() - - class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase): - def set_and_hit_breakpoint(self, continueToExit=True): - source = "main.c" - breakpoint1_line = line_number(source, "// breakpoint 1") - lines = [breakpoint1_line] - # Set breakpoint in the thread function so we can step the threads - breakpoint_ids = self.set_source_breakpoints(source, lines) - self.assertEqual( - len(breakpoint_ids), len(lines), "expect correct number of breakpoints" - ) - # Test binary will sleep for 10s, offset the breakpoint timeout - # accordingly. - timeout_offset = 10 - self.continue_to_breakpoints( - breakpoint_ids, timeout=timeout_offset + self.DEFAULT_TIMEOUT + def spawn(self, args): + self.process = subprocess.Popen( + args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, ) - if continueToExit: - self.continue_to_exit() - @skipIfNetBSD # Hangs on NetBSD as well + def spawn_and_wait(self, program, delay): + time.sleep(delay) + self.spawn([program]) + self.process.wait() + + def continue_and_verify_pid(self): + self.do_continue() + out, _ = self.process.communicate("foo") + self.assertIn(f"pid = {self.process.pid}", out) + def test_by_pid(self): """ Tests attaching to a process by process ID. """ program = self.build_and_create_debug_adapter_for_attach() - self.process = subprocess.Popen( - [program], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) + self.spawn([program]) self.attach(pid=self.process.pid) - self.set_and_hit_breakpoint(continueToExit=True) + self.continue_and_verify_pid() - @skipIfNetBSD # Hangs on NetBSD as well def test_by_name(self): """ Tests attaching to a process by process name. @@ -65,24 +50,20 @@ class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase): pid_file_path = lldbutil.append_to_process_working_directory( self, "pid_file_%d" % (int(time.time())) ) - - popen = self.spawnSubprocess(program, [pid_file_path]) + self.spawn([program, pid_file_path]) lldbutil.wait_for_file_on_target(self, pid_file_path) self.attach(program=program) - self.set_and_hit_breakpoint(continueToExit=True) + self.continue_and_verify_pid() - @skipUnlessDarwin - @skipIfNetBSD # Hangs on NetBSD as well def test_by_name_waitFor(self): """ - Tests attaching to a process by process name and waiting for the - next instance of a process to be launched, ignoring all current - ones. + Tests waiting for, and attaching to a process by process name that + doesn't exist yet. """ program = self.build_and_create_debug_adapter_for_attach() self.spawn_thread = threading.Thread( - target=spawn_and_wait, + target=self.spawn_and_wait, args=( program, 1.0, @@ -90,140 +71,4 @@ class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase): ) self.spawn_thread.start() self.attach(program=program, waitFor=True) - self.set_and_hit_breakpoint(continueToExit=True) - - @skipIfNetBSD # Hangs on NetBSD as well - def test_commands(self): - """ - Tests the "initCommands", "preRunCommands", "stopCommands", - "exitCommands", "terminateCommands" and "attachCommands" - that can be passed during attach. - - "initCommands" are a list of LLDB commands that get executed - before the target is created. - "preRunCommands" are a list of LLDB commands that get executed - after the target has been created and before the launch. - "stopCommands" are a list of LLDB commands that get executed each - time the program stops. - "exitCommands" are a list of LLDB commands that get executed when - the process exits - "attachCommands" are a list of LLDB commands that get executed and - must have a valid process in the selected target in LLDB after - they are done executing. This allows custom commands to create any - kind of debug session. - "terminateCommands" are a list of LLDB commands that get executed when - the debugger session terminates. - """ - program = self.build_and_create_debug_adapter_for_attach() - - # Here we just create a target and launch the process as a way to test - # if we are able to use attach commands to create any kind of a target - # and use it for debugging - attachCommands = [ - 'target create -d "%s"' % (program), - "process launch --stop-at-entry", - ] - initCommands = ["target list", "platform list"] - preRunCommands = ["image list a.out", "image dump sections a.out"] - postRunCommands = ["help trace", "help process trace"] - stopCommands = ["frame variable", "thread backtrace"] - exitCommands = ["expr 2+3", "expr 3+4"] - terminateCommands = ["expr 4+2"] - self.attach( - program=program, - attachCommands=attachCommands, - initCommands=initCommands, - preRunCommands=preRunCommands, - stopCommands=stopCommands, - exitCommands=exitCommands, - terminateCommands=terminateCommands, - postRunCommands=postRunCommands, - ) - # Get output from the console. This should contain both the - # "initCommands" and the "preRunCommands". - output = self.get_console() - # Verify all "initCommands" were found in console output - self.verify_commands("initCommands", output, initCommands) - # Verify all "preRunCommands" were found in console output - self.verify_commands("preRunCommands", output, preRunCommands) - # Verify all "postRunCommands" were found in console output - self.verify_commands("postRunCommands", output, postRunCommands) - - functions = ["main"] - breakpoint_ids = self.set_function_breakpoints(functions) - self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") - self.continue_to_breakpoints(breakpoint_ids) - output = self.collect_console(timeout=10, pattern=stopCommands[-1]) - self.verify_commands("stopCommands", output, stopCommands) - - # Continue after launch and hit the "pause()" call and stop the target. - # Get output from the console. This should contain both the - # "stopCommands" that were run after we stop. - self.do_continue() - time.sleep(0.5) - self.dap_server.request_pause() - self.dap_server.wait_for_stopped() - output = self.collect_console(timeout=10, pattern=stopCommands[-1]) - self.verify_commands("stopCommands", output, stopCommands) - - # Continue until the program exits - self.continue_to_exit() - # Get output from the console. This should contain both the - # "exitCommands" that were run after the second breakpoint was hit - # and the "terminateCommands" due to the debugging session ending - output = self.collect_console( - timeout=10.0, - pattern=terminateCommands[0], - ) - self.verify_commands("exitCommands", output, exitCommands) - self.verify_commands("terminateCommands", output, terminateCommands) - - def test_attach_command_process_failures(self): - """ - Tests that a 'attachCommands' is expected to leave the debugger's - selected target with a valid process. - """ - program = self.build_and_create_debug_adapter_for_attach() - attachCommands = ['script print("oops, forgot to attach to a process...")'] - resp = self.attach( - program=program, - attachCommands=attachCommands, - expectFailure=True, - ) - self.assertFalse(resp["success"]) - self.assertIn( - "attachCommands failed to attach to a process", - resp["body"]["error"]["format"], - ) - - @skipIfNetBSD # Hangs on NetBSD as well - def test_terminate_commands(self): - """ - Tests that the "terminateCommands", that can be passed during - attach, are run when the debugger is disconnected. - """ - program = self.build_and_create_debug_adapter_for_attach() - - # Here we just create a target and launch the process as a way to test - # if we are able to use attach commands to create any kind of a target - # and use it for debugging - attachCommands = [ - 'target create -d "%s"' % (program), - "process launch --stop-at-entry", - ] - terminateCommands = ["expr 4+2"] - self.attach( - program=program, - attachCommands=attachCommands, - terminateCommands=terminateCommands, - disconnectAutomatically=False, - ) - self.get_console() - # Once it's disconnected the console should contain the - # "terminateCommands" - self.dap_server.request_disconnect(terminateDebuggee=True) - output = self.collect_console( - timeout=1.0, - pattern=terminateCommands[0], - ) - self.verify_commands("terminateCommands", output, terminateCommands) + self.continue_and_verify_pid() diff --git a/lldb/test/API/tools/lldb-dap/attach/main.c b/lldb/test/API/tools/lldb-dap/attach/main.c index f56d5d53afa0..e14cf71a7044 100644 --- a/lldb/test/API/tools/lldb-dap/attach/main.c +++ b/lldb/test/API/tools/lldb-dap/attach/main.c @@ -2,7 +2,6 @@ #include <stdio.h> #ifdef _WIN32 #include <process.h> -#include <windows.h> #else #include <unistd.h> #endif @@ -20,11 +19,9 @@ int main(int argc, char const *argv[]) { fclose(f); } + // Wait on input from stdin. + getchar(); + printf("pid = %i\n", getpid()); -#ifdef _WIN32 - Sleep(10 * 1000); -#else - sleep(10); -#endif - return 0; // breakpoint 1 + return 0; } diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 151ad761a504..beab4d6c1f5a 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -82,14 +82,14 @@ class TestDAP_breakpointEvents(lldbdap_testcase.DAPTestCaseBase): ) # Flush the breakpoint events. - self.dap_server.wait_for_breakpoint_events(timeout=5) + self.dap_server.wait_for_breakpoint_events() # Continue to the breakpoint self.continue_to_breakpoints(dap_breakpoint_ids) verified_breakpoint_ids = [] unverified_breakpoint_ids = [] - for breakpoint_event in self.dap_server.wait_for_breakpoint_events(timeout=5): + for breakpoint_event in self.dap_server.wait_for_breakpoint_events(): breakpoint = breakpoint_event["body"]["breakpoint"] id = breakpoint["id"] if breakpoint["verified"]: diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py index e722fcea9283..14789a669468 100644 --- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py +++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py @@ -46,7 +46,7 @@ class TestDAP_cancel(lldbdap_testcase.DAPTestCaseBase): # Use a relatively short timeout since this is only to ensure the # following request is queued. - blocking_seq = self.async_blocking_request(duration=1.0) + blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 10) # Use a longer timeout to ensure we catch if the request was interrupted # properly. pending_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) diff --git a/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py index e61d2480ea4b..f53813a8a48f 100644 --- a/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py +++ b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py @@ -23,7 +23,6 @@ class TestDAP_commands(lldbdap_testcase.DAPTestCaseBase): exitCommands=["?" + command_quiet, command_not_quiet], ) full_output = self.collect_console( - timeout=1.0, pattern=command_not_quiet, ) self.assertNotIn(command_quiet, full_output) @@ -51,7 +50,6 @@ class TestDAP_commands(lldbdap_testcase.DAPTestCaseBase): expectFailure=True, ) full_output = self.collect_console( - timeout=1.0, pattern=command_abort_on_error, ) self.assertNotIn(command_quiet, full_output) diff --git a/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py index af5c62a8c4eb..9fbe9aaee8c6 100644 --- a/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py +++ b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py @@ -44,7 +44,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase): """ process = self.launch() process.stdin.close() - self.assertEqual(process.wait(timeout=5.0), EXIT_SUCCESS) + self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_SUCCESS) def test_invalid_header(self): """ @@ -54,7 +54,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase): process = self.launch() process.stdin.write(b"not the correct message header") process.stdin.close() - self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE) + self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE) def test_partial_header(self): """ @@ -64,7 +64,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase): process = self.launch() process.stdin.write(b"Content-Length: ") process.stdin.close() - self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE) + self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE) def test_incorrect_content_length(self): """ @@ -74,7 +74,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase): process = self.launch() process.stdin.write(b"Content-Length: abc") process.stdin.close() - self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE) + self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE) def test_partial_content_length(self): """ @@ -84,4 +84,4 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase): process = self.launch() process.stdin.write(b"Content-Length: 10\r\n\r\n{") process.stdin.close() - self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE) + self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE) diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index ceef95dfcd0d..8db2316e73fc 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -632,7 +632,27 @@ class TestDAP_launch(lldbdap_testcase.DAPTestCaseBase): program = self.getBuildArtifact("a.out") with tempfile.NamedTemporaryFile("rt") as f: - self.launch(program, stdio=[None, f.name, None]) + self.launch(program, stdio=[None, f.name]) + self.continue_to_exit() + lines = f.readlines() + self.assertIn( + program, lines[0], "make sure program path is in first argument" + ) + + @skipIfAsan + @skipIfWindows + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) + def test_stdio_redirection_and_console(self): + """ + Test stdio redirection and console. + """ + self.build_and_create_debug_adapter() + program = self.getBuildArtifact("a.out") + + with tempfile.NamedTemporaryFile("rt") as f: + self.launch( + program, console="integratedTerminal", stdio=[None, f.name, None] + ) self.continue_to_exit() lines = f.readlines() self.assertIn( diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py index bb835af12f5e..1f4afabbd161 100644 --- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py +++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py @@ -23,15 +23,15 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): self.continue_to_breakpoints(breakpoint_ids) # We're now stopped at breakpoint 1 before the dlopen. Flush all the module events. - event = self.dap_server.wait_for_event(["module"], 0.25) + event = self.dap_server.wait_for_event(["module"]) while event is not None: - event = self.dap_server.wait_for_event(["module"], 0.25) + event = self.dap_server.wait_for_event(["module"]) # Continue to the second breakpoint, before the dlclose. self.continue_to_breakpoints(breakpoint_ids) # Make sure we got a module event for libother. - event = self.dap_server.wait_for_event(["module"], 5) + event = self.dap_server.wait_for_event(["module"]) self.assertIsNotNone(event, "didn't get a module event") module_name = event["body"]["module"]["name"] module_id = event["body"]["module"]["id"] @@ -42,7 +42,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): self.continue_to_breakpoints(breakpoint_ids) # Make sure we got a module event for libother. - event = self.dap_server.wait_for_event(["module"], 5) + event = self.dap_server.wait_for_event(["module"]) self.assertIsNotNone(event, "didn't get a module event") reason = event["body"]["reason"] self.assertEqual(reason, "removed") @@ -55,8 +55,4 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): self.assertListEqual(list(module_data.keys()), required_keys) self.assertEqual(module_data["name"], "", "expects empty name.") - # Make sure we do not send another event - event = self.dap_server.wait_for_event(["module"], 3) - self.assertIsNone(event, "expects no events.") - self.continue_to_exit() diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index c5a68372d822..0ed53dac5d86 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -67,7 +67,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): # Collect all the module names we saw as events. module_new_names = [] module_changed_names = [] - module_event = self.dap_server.wait_for_event(["module"], 1) + module_event = self.dap_server.wait_for_event(["module"]) while module_event is not None: reason = module_event["body"]["reason"] if reason == "new": @@ -75,7 +75,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): elif reason == "changed": module_changed_names.append(module_event["body"]["module"]["name"]) - module_event = self.dap_server.wait_for_event(["module"], 1) + module_event = self.dap_server.wait_for_event(["module"]) # Make sure we got an event for every active module. self.assertNotEqual(len(module_new_names), 0) diff --git a/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py b/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py index fe978a9a7335..0065258920ec 100644 --- a/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py +++ b/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py @@ -29,7 +29,7 @@ class TestDAP_output(lldbdap_testcase.DAPTestCaseBase): self.continue_to_breakpoints(breakpoint_ids) # Ensure partial messages are still sent. - output = self.collect_stdout(timeout=1.0, pattern="abcdef") + output = self.collect_stdout(pattern="abcdef") self.assertTrue(output and len(output) > 0, "expect program stdout") self.continue_to_exit() diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py index 67483798f226..e1ad1425a993 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py @@ -105,7 +105,7 @@ class TestDAP_restart_console(lldbdap_testcase.DAPTestCaseBase): # Restart and check that we still get a stopped event before reaching # main. self.dap_server.request_restart() - stopped_events = self.dap_server.wait_for_stopped(timeout=20) + stopped_events = self.dap_server.wait_for_stopped() self.verify_stopped_on_entry(stopped_events) # continue to main diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py index 08c225b3cada..6008a0cb0237 100644 --- a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py @@ -29,7 +29,7 @@ class TestDAP_stackTraceMissingSourcePath(lldbdap_testcase.DAPTestCaseBase): """ Build the program and run until the breakpoint is hit, and return the stack frames. """ - other_source_file = "other.c" + other_source_file = self.getBuildArtifact("other.c") with delete_file_on_exit(other_source_file): with open(other_source_file, "w") as f: f.write(OTHER_C_SOURCE_CODE) @@ -169,3 +169,4 @@ class TestDAP_stackTraceMissingSourcePath(lldbdap_testcase.DAPTestCaseBase): self.verify_frames_source( frames, main_frame_assembly=False, other_frame_assembly=False ) + self.continue_to_exit() diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py index 13a694602f23..977d6ce9dac8 100644 --- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py +++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py @@ -65,6 +65,11 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase): self.assertNotIn( key, actual, 'key "%s" is not expected in %s' % (key, actual) ) + isReadOnly = verify_dict.get("readOnly", False) + attributes = actual.get("presentationHint", {}).get("attributes", []) + self.assertEqual( + isReadOnly, "readOnly" in attributes, "%s %s" % (verify_dict, actual) + ) hasVariablesReference = "variablesReference" in actual varRef = None if hasVariablesReference: @@ -179,8 +184,9 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase): "children": { "x": {"equals": {"type": "int", "value": "11"}}, "y": {"equals": {"type": "int", "value": "22"}}, - "buffer": {"children": buffer_children}, + "buffer": {"children": buffer_children, "readOnly": True}, }, + "readOnly": True, }, "x": {"equals": {"type": "int"}}, } @@ -444,8 +450,10 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase): "buffer": { "children": buffer_children, "equals": {"indexedVariables": 16}, + "readOnly": True, }, }, + "readOnly": True, }, "x": { "equals": {"type": "int"}, @@ -528,7 +536,7 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase): "children": { "x": {"equals": {"type": "int", "value": "11"}}, "y": {"equals": {"type": "int", "value": "22"}}, - "buffer": {"children": buffer_children}, + "buffer": {"children": buffer_children, "readOnly": True}, }, } @@ -622,11 +630,17 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase): # "[raw]" child. raw_child_count = 1 if enableSyntheticChildDebugging else 0 verify_locals = { - "small_array": {"equals": {"indexedVariables": 5}}, - "large_array": {"equals": {"indexedVariables": 200}}, - "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}}, - "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}}, - "pt": {"missing": ["indexedVariables"]}, + "small_array": {"equals": {"indexedVariables": 5}, "readOnly": True}, + "large_array": {"equals": {"indexedVariables": 200}, "readOnly": True}, + "small_vector": { + "equals": {"indexedVariables": 5 + raw_child_count}, + "readOnly": True, + }, + "large_vector": { + "equals": {"indexedVariables": 200 + raw_child_count}, + "readOnly": True, + }, + "pt": {"missing": ["indexedVariables"], "readOnly": True}, } self.verify_variables(verify_locals, locals) @@ -640,7 +654,10 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase): "[4]": {"equals": {"type": "int", "value": "0"}}, } if enableSyntheticChildDebugging: - verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},) + verify_children["[raw]"] = { + "contains": {"type": ["vector"]}, + "readOnly": True, + } children = self.dap_server.request_variables(locals[2]["variablesReference"])[ "body" @@ -660,7 +677,7 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase): return_name: {"equals": {"type": "int", "value": "300"}}, "argc": {}, "argv": {}, - "pt": {}, + "pt": {"readOnly": True}, "x": {}, "return_result": {"equals": {"type": "int"}}, } diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py index 13c4a85f51f7..ef1d546cf171 100644 --- a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py +++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py @@ -2,6 +2,7 @@ import random from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * +from lldbsuite.support import seven from fork_testbase import GdbRemoteForkTestBase diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py index c01f6d83fafe..f1c0519ae56d 100644 --- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py +++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py @@ -22,7 +22,9 @@ from lldbsuite.test.lldbtest import * from lldbsuite.test.lldbdwarf import * from lldbsuite.test import lldbutil, lldbplatformutil - +# On Linux systems with Yama ptrace_scope = 1 there is a race condition when the +# debugee enables tracing. See https://github.com/llvm/llvm-project/issues/161510. +@skipIfLinux class LldbGdbServerTestCase( gdbremote_testcase.GdbRemoteTestCaseBase, DwarfOpcodeParser ): diff --git a/lldb/test/API/tools/lldb-server/main.cpp b/lldb/test/API/tools/lldb-server/main.cpp index 0e9323cce88c..7e84552b0f25 100644 --- a/lldb/test/API/tools/lldb-server/main.cpp +++ b/lldb/test/API/tools/lldb-server/main.cpp @@ -5,6 +5,7 @@ #include <cstdlib> #include <cstring> #include <errno.h> +#include <fstream> #include <future> #include <inttypes.h> #include <memory> @@ -265,7 +266,11 @@ int main(int argc, char **argv) { // Process command line args. for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; - if (consume_front(arg, "stderr:")) { + if (consume_front(arg, "syncfile:")) { + // Write to this file to tell test framework that attaching is now + // possible. + std::ofstream(arg).close(); + } else if (consume_front(arg, "stderr:")) { // Treat remainder as text to go to stderr. fprintf(stderr, "%s\n", arg.c_str()); } else if (consume_front(arg, "retval:")) { |
