https://github.com/labath updated https://github.com/llvm/llvm-project/pull/123046
>From 74d436310319d17cb43ba598836b70a92c827111 Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Wed, 15 Jan 2025 12:41:23 +0100 Subject: [PATCH 1/7] [lldb] Fix SBThread::StepOverUntil for discontinuous functions I think the only issue here was that we would erroneously consider functions which are "in the middle" of the function were stepping to as a part of the function, and would try to step into them (likely stepping out of the function instead) instead of giving up early. --- lldb/source/API/SBThread.cpp | 6 +- .../thread/step_until/TestStepUntilAPI.py | 135 ++++++++++++++++++ .../thread/step_until/function.list | 1 + .../functionalities/thread/step_until/main.c | 3 + .../thread/step_until/symbol.order | 7 + 5 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py create mode 100644 lldb/test/API/functionalities/thread/step_until/function.list create mode 100644 lldb/test/API/functionalities/thread/step_until/symbol.order diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 4e61c83889b0b0..4481d1113d89e2 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -842,7 +842,7 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, // appropriate error message. bool all_in_function = true; - AddressRange fun_range = frame_sc.function->GetAddressRange(); + AddressRanges fun_ranges = frame_sc.function->GetAddressRanges(); std::vector<addr_t> step_over_until_addrs; const bool abort_other_plans = false; @@ -859,7 +859,9 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, addr_t step_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(target); if (step_addr != LLDB_INVALID_ADDRESS) { - if (fun_range.ContainsLoadAddress(step_addr, target)) + if (llvm::any_of(fun_ranges, [&](const AddressRange &r) { + return r.ContainsLoadAddress(step_addr, target); + })) step_over_until_addrs.push_back(step_addr); else all_in_function = false; diff --git a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py new file mode 100644 index 00000000000000..95f3552d8968b7 --- /dev/null +++ b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py @@ -0,0 +1,135 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class StepUntilTestCase(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + super().setUp() + + self.main_source = "main.c" + self.main_spec = lldb.SBFileSpec(self.main_source) + self.less_than_two = line_number("main.c", "Less than 2") + self.greater_than_two = line_number("main.c", "Greater than or equal to 2.") + self.back_out_in_main = line_number("main.c", "Back out in main") + self.in_foo = line_number("main.c", "In foo") + + def _build_dict_for_discontinuity(self): + return dict( + CFLAGS_EXTRAS="-funique-basic-block-section-names " + + "-ffunction-sections -fbasic-block-sections=list=" + + self.getSourcePath("function.list"), + LD_EXTRAS="-Wl,--section-ordering-file=" + + self.getSourcePath("symbol.order"), + ) + + def _do_until(self, build_dict, args, until_line, expected_line): + self.build(dictionary=build_dict) + launch_info = lldb.SBLaunchInfo(args) + _, _, thread, _ = lldbutil.run_to_source_breakpoint( + self, "At the start", self.main_spec, launch_info + ) + + self.assertSuccess( + thread.StepOverUntil(self.frame(), self.main_spec, until_line) + ) + + self.runCmd("process status") + + line = self.frame().GetLineEntry().GetLine() + self.assertEqual( + line, expected_line, "Did not get the expected stop line number" + ) + + def _assertDiscontinuity(self): + target = self.target() + foo = target.FindFunctions("foo") + self.assertEqual(len(foo), 1) + foo = foo[0] + + call_me = self.target().FindFunctions("call_me") + self.assertEqual(len(call_me), 1) + call_me = call_me[0] + + foo_addr = foo.function.GetStartAddress().GetLoadAddress(target) + found_before = False + found_after = False + for range in call_me.function.GetRanges(): + addr = range.GetBaseAddress().GetLoadAddress(target) + if addr < foo_addr: + found_before = True + if addr > foo_addr: + found_after = True + + self.assertTrue( + found_before and found_after, + "'foo' is not between 'call_me'" + str(foo) + str(call_me), + ) + + def test_hitting(self): + """Test SBThread.StepOverUntil - targeting a line and hitting it.""" + self._do_until(None, None, self.less_than_two, self.less_than_two) + + @skipIf(oslist=lldbplatformutil.getDarwinOSTriples() + ["windows"]) + def test_hitting_discontinuous(self): + """Test SBThread.StepOverUntil - targeting a line and hitting it -- with + discontinuous functions""" + self._do_until( + self._build_dict_for_discontinuity(), + None, + self.less_than_two, + self.less_than_two, + ) + self._assertDiscontinuity() + + def test_missing(self): + """Test SBThread.StepOverUntil - targeting a line and missing it by stepping out to call site""" + self._do_until( + None, ["foo", "bar", "baz"], self.less_than_two, self.back_out_in_main + ) + + @skipIf(oslist=lldbplatformutil.getDarwinOSTriples() + ["windows"]) + def test_missing_discontinuous(self): + """Test SBThread.StepOverUntil - targeting a line and missing it by + stepping out to call site -- with discontinuous functions""" + self._do_until( + self._build_dict_for_discontinuity(), + ["foo", "bar", "baz"], + self.less_than_two, + self.back_out_in_main, + ) + self._assertDiscontinuity() + + def test_bad_line(self): + """Test that we get an error if attempting to step outside the current + function""" + self.build() + _, _, thread, _ = lldbutil.run_to_source_breakpoint( + self, "At the start", self.main_spec + ) + self.assertIn( + "step until target not in current function", + thread.StepOverUntil( + self.frame(), self.main_spec, self.in_foo + ).GetCString(), + ) + + @skipIf(oslist=lldbplatformutil.getDarwinOSTriples() + ["windows"]) + def test_bad_line_discontinuous(self): + """Test that we get an error if attempting to step outside the current + function -- and the function is discontinuous""" + self.build(dictionary=self._build_dict_for_discontinuity()) + _, _, thread, _ = lldbutil.run_to_source_breakpoint( + self, "At the start", self.main_spec + ) + self.assertIn( + "step until target not in current function", + thread.StepOverUntil( + self.frame(), self.main_spec, self.in_foo + ).GetCString(), + ) + self._assertDiscontinuity() diff --git a/lldb/test/API/functionalities/thread/step_until/function.list b/lldb/test/API/functionalities/thread/step_until/function.list new file mode 100644 index 00000000000000..5900fe8c350695 --- /dev/null +++ b/lldb/test/API/functionalities/thread/step_until/function.list @@ -0,0 +1 @@ +!call_me diff --git a/lldb/test/API/functionalities/thread/step_until/main.c b/lldb/test/API/functionalities/thread/step_until/main.c index bb866079cf5f54..4c52308f030e98 100644 --- a/lldb/test/API/functionalities/thread/step_until/main.c +++ b/lldb/test/API/functionalities/thread/step_until/main.c @@ -4,6 +4,9 @@ * unrelated to the program, just to achieve consistent * debug line tables, across platforms, that are not * dependent on compiler optimzations. */ + +int foo(int x) { return x; /* In foo */ } + int call_me(int argc) { printf ("At the start, argc: %d.\n", argc); diff --git a/lldb/test/API/functionalities/thread/step_until/symbol.order b/lldb/test/API/functionalities/thread/step_until/symbol.order new file mode 100644 index 00000000000000..72519faefdc787 --- /dev/null +++ b/lldb/test/API/functionalities/thread/step_until/symbol.order @@ -0,0 +1,7 @@ +.text : { + *(.text.call_me) + *(.text.foo) + *(.text.call_me.call_me.__part.1) + *(.text.call_me.call_me.__part.2) + *(.text.call_me.call_me.__part.3) +} >From 160a68dbdfc97a816173e4280e6a6ca80b320f5a Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Wed, 15 Jan 2025 12:55:06 +0100 Subject: [PATCH 2/7] reformat --- .../API/functionalities/thread/step_until/TestStepUntilAPI.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py index 95f3552d8968b7..c15077d8a8f2bf 100644 --- a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py +++ b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py @@ -5,7 +5,6 @@ class StepUntilTestCase(TestBase): - NO_DEBUG_INFO_TESTCASE = True def setUp(self): >From da52a02ea3cc45dbefc7026565e4bab5ff0a4be3 Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Thu, 16 Jan 2025 10:07:11 +0100 Subject: [PATCH 3/7] feedback --- lldb/source/API/SBThread.cpp | 10 ++++++---- .../thread/step_until/TestStepUntilAPI.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 4481d1113d89e2..a1eb5c04e2030b 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -841,8 +841,10 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, // function, and then if there are no addresses remaining, give an // appropriate error message. + // Function block range information is valid even without parsing the entire + // block. + Block &fun_block = frame_sc.function->GetBlock(/*can_create=*/false); bool all_in_function = true; - AddressRanges fun_ranges = frame_sc.function->GetAddressRanges(); std::vector<addr_t> step_over_until_addrs; const bool abort_other_plans = false; @@ -859,9 +861,9 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, addr_t step_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(target); if (step_addr != LLDB_INVALID_ADDRESS) { - if (llvm::any_of(fun_ranges, [&](const AddressRange &r) { - return r.ContainsLoadAddress(step_addr, target); - })) + AddressRange unused_range; + if (fun_block.GetRangeContainingLoadAddress(step_addr, *target, + unused_range)) step_over_until_addrs.push_back(step_addr); else all_in_function = false; diff --git a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py index c15077d8a8f2bf..f6307bd0cf0046 100644 --- a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py +++ b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py @@ -4,7 +4,7 @@ from lldbsuite.test import lldbutil -class StepUntilTestCase(TestBase): +class TestStepUntilAPI(TestBase): NO_DEBUG_INFO_TESTCASE = True def setUp(self): >From b9fb10867fdb7d82fc7ee9068191e749382957ad Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Thu, 16 Jan 2025 13:02:40 +0100 Subject: [PATCH 4/7] compatibility with older GNU ld --- .../thread/step_until/TestStepUntilAPI.py | 2 +- .../thread/step_until/symbol.order | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py index f6307bd0cf0046..19a676be2c8f5f 100644 --- a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py +++ b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py @@ -22,7 +22,7 @@ def _build_dict_for_discontinuity(self): CFLAGS_EXTRAS="-funique-basic-block-section-names " + "-ffunction-sections -fbasic-block-sections=list=" + self.getSourcePath("function.list"), - LD_EXTRAS="-Wl,--section-ordering-file=" + LD_EXTRAS="-Wl,--script=" + self.getSourcePath("symbol.order"), ) diff --git a/lldb/test/API/functionalities/thread/step_until/symbol.order b/lldb/test/API/functionalities/thread/step_until/symbol.order index 72519faefdc787..c664a548a53c6e 100644 --- a/lldb/test/API/functionalities/thread/step_until/symbol.order +++ b/lldb/test/API/functionalities/thread/step_until/symbol.order @@ -1,7 +1,9 @@ -.text : { - *(.text.call_me) - *(.text.foo) - *(.text.call_me.call_me.__part.1) - *(.text.call_me.call_me.__part.2) - *(.text.call_me.call_me.__part.3) -} +SECTIONS { + .text : { + *(.text.call_me) + *(.text.foo) + *(.text.call_me.call_me.__part.1) + *(.text.call_me.call_me.__part.2) + *(.text.call_me.call_me.__part.3) + } +} INSERT BEFORE .text; >From cd3d78761229df41acfe984ff699e5c683ac728c Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Thu, 16 Jan 2025 13:07:00 +0100 Subject: [PATCH 5/7] ..and with lld --- lldb/test/API/functionalities/thread/step_until/symbol.order | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/functionalities/thread/step_until/symbol.order b/lldb/test/API/functionalities/thread/step_until/symbol.order index c664a548a53c6e..dcc9607a4188fe 100644 --- a/lldb/test/API/functionalities/thread/step_until/symbol.order +++ b/lldb/test/API/functionalities/thread/step_until/symbol.order @@ -1,5 +1,5 @@ SECTIONS { - .text : { + .text.ordered : { *(.text.call_me) *(.text.foo) *(.text.call_me.call_me.__part.1) >From a00392edfa4d33bda3711f0b9269de92bc970547 Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Thu, 16 Jan 2025 13:08:13 +0100 Subject: [PATCH 6/7] and format --- .../API/functionalities/thread/step_until/TestStepUntilAPI.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py index 19a676be2c8f5f..de3892ed278f80 100644 --- a/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py +++ b/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py @@ -22,8 +22,7 @@ def _build_dict_for_discontinuity(self): CFLAGS_EXTRAS="-funique-basic-block-section-names " + "-ffunction-sections -fbasic-block-sections=list=" + self.getSourcePath("function.list"), - LD_EXTRAS="-Wl,--script=" - + self.getSourcePath("symbol.order"), + LD_EXTRAS="-Wl,--script=" + self.getSourcePath("symbol.order"), ) def _do_until(self, build_dict, args, until_line, expected_line): >From b25701757258c9535a104f3d6f13f4517ceb970d Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Fri, 17 Jan 2025 11:17:50 +0100 Subject: [PATCH 7/7] Add GetRangeContainingLoadAddress --- lldb/include/lldb/Symbol/Function.h | 5 +++++ lldb/source/API/SBThread.cpp | 7 ++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index 157c007bdf0e84..d0b27269568b04 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -454,6 +454,11 @@ class Function : public UserID, public SymbolContextScope { /// and variables). const Address &GetAddress() const { return m_address; } + bool GetRangeContainingLoadAddress(lldb::addr_t load_addr, Target &target, + AddressRange &range) { + return m_block.GetRangeContainingLoadAddress(load_addr, target, range); + } + lldb::LanguageType GetLanguage() const; /// Find the file and line number of the source location of the start of the /// function. This will use the declaration if present and fall back on the diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index a1eb5c04e2030b..cc848076dab5fa 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -841,9 +841,6 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, // function, and then if there are no addresses remaining, give an // appropriate error message. - // Function block range information is valid even without parsing the entire - // block. - Block &fun_block = frame_sc.function->GetBlock(/*can_create=*/false); bool all_in_function = true; std::vector<addr_t> step_over_until_addrs; @@ -862,8 +859,8 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, sc.line_entry.range.GetBaseAddress().GetLoadAddress(target); if (step_addr != LLDB_INVALID_ADDRESS) { AddressRange unused_range; - if (fun_block.GetRangeContainingLoadAddress(step_addr, *target, - unused_range)) + if (frame_sc.function->GetRangeContainingLoadAddress(step_addr, *target, + unused_range)) step_over_until_addrs.push_back(step_addr); else all_in_function = false; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits