Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions lldb/source/API/SBThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't there an AddressRanges::ContainsLoadAddress? Seems silly to have to write this loop by hand.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AddressRanges is a typedef for vector.

How about using Block::GetRangeContainingLoadAddress (Function::GetAddressRanges just returns the data from the function Block) for this instead (see new version of the patch)? Other possibilities might be:

  • add Function::GetRangeContainingLoadAddress or Function::ContainsLoadAddress
  • add a free function (ContainsLoadAddress(ArrayRef<AddressRange>, addr_t, Target))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels awkward to have to manually dial up the function block to see if an address exists in that function. I'd vote for Function::GetRangeContainingLoadAddress - that just seems like something a Function should be able to tell you.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SG

return r.ContainsLoadAddress(step_addr, target);
}))
step_over_until_addrs.push_back(step_addr);
else
all_in_function = false;
Expand Down
134 changes: 134 additions & 0 deletions lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
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()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!call_me
3 changes: 3 additions & 0 deletions lldb/test/API/functionalities/thread/step_until/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
Loading