-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[lldb] Add SB API to make a breakpoint a hardware breakpoint #146602
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,7 +61,7 @@ Breakpoint::Breakpoint(Target &new_target, const Breakpoint &source_bp) | |
Breakpoint::~Breakpoint() = default; | ||
|
||
BreakpointSP Breakpoint::CopyFromBreakpoint(TargetSP new_target, | ||
const Breakpoint& bp_to_copy_from) { | ||
const Breakpoint &bp_to_copy_from) { | ||
if (!new_target) | ||
return BreakpointSP(); | ||
|
||
|
@@ -163,7 +163,7 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData( | |
std::make_shared<SearchFilterForUnconstrainedSearches>(target_sp); | ||
else { | ||
filter_sp = SearchFilter::CreateFromStructuredData(target_sp, *filter_dict, | ||
create_error); | ||
create_error); | ||
if (create_error.Fail()) { | ||
error = Status::FromErrorStringWithFormat( | ||
"Error creating breakpoint filter from data: %s.", | ||
|
@@ -174,7 +174,7 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData( | |
|
||
std::unique_ptr<BreakpointOptions> options_up; | ||
StructuredData::Dictionary *options_dict; | ||
Target& target = *target_sp; | ||
Target &target = *target_sp; | ||
success = breakpoint_dict->GetValueForKeyAsDictionary( | ||
BreakpointOptions::GetSerializationKey(), options_dict); | ||
if (success) { | ||
|
@@ -192,8 +192,8 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData( | |
success = breakpoint_dict->GetValueForKeyAsBoolean( | ||
Breakpoint::GetKey(OptionNames::Hardware), hardware); | ||
|
||
result_sp = target.CreateBreakpoint(filter_sp, resolver_sp, false, | ||
hardware, true); | ||
result_sp = | ||
target.CreateBreakpoint(filter_sp, resolver_sp, false, hardware, true); | ||
|
||
if (result_sp && options_up) { | ||
result_sp->m_options = *options_up; | ||
|
@@ -251,6 +251,45 @@ const lldb::TargetSP Breakpoint::GetTargetSP() { | |
|
||
bool Breakpoint::IsInternal() const { return LLDB_BREAK_ID_IS_INTERNAL(m_bid); } | ||
|
||
llvm::Error Breakpoint::SetIsHardware(bool is_hardware) { | ||
if (is_hardware == m_hardware) | ||
return llvm::Error::success(); | ||
|
||
// Disable all non-hardware breakpoint locations. | ||
std::vector<BreakpointLocationSP> locations; | ||
for (BreakpointLocationSP location_sp : m_locations.BreakpointLocations()) { | ||
if (!location_sp || !location_sp->IsEnabled()) | ||
continue; | ||
|
||
lldb::BreakpointSiteSP breakpoint_site_sp = | ||
location_sp->GetBreakpointSite(); | ||
if (!breakpoint_site_sp || | ||
breakpoint_site_sp->GetType() == BreakpointSite::eHardware) | ||
continue; | ||
|
||
locations.push_back(location_sp); | ||
location_sp->SetEnabled(false); | ||
} | ||
|
||
// Toggle the hardware mode. | ||
m_hardware = is_hardware; | ||
|
||
// Re-enable all breakpoint locations. | ||
size_t num_failures = 0; | ||
for (BreakpointLocationSP location_sp : locations) { | ||
if (!location_sp->SetEnabled(true)) | ||
num_failures++; | ||
} | ||
|
||
if (num_failures != 0) | ||
return llvm::createStringError( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The locations we didn't convert to hardware will be left disabled. That's a useful but not obvious bit of information, which it would be good to include in the error string. Other than that this looks okay to me. |
||
"%ull out of %ull breakpoint locations left disabled because they " | ||
"couldn't be converted to hardware", | ||
num_failures, locations.size()); | ||
|
||
return llvm::Error::success(); | ||
} | ||
|
||
BreakpointLocationSP Breakpoint::AddLocation(const Address &addr, | ||
bool *new_location) { | ||
return m_locations.AddLocation(addr, m_resolve_indirect_symbols, | ||
|
@@ -952,8 +991,7 @@ void Breakpoint::GetResolverDescription(Stream *s) { | |
m_resolver_sp->GetDescription(s); | ||
} | ||
|
||
bool Breakpoint::GetMatchingFileLine(ConstString filename, | ||
uint32_t line_number, | ||
bool Breakpoint::GetMatchingFileLine(ConstString filename, uint32_t line_number, | ||
BreakpointLocationCollection &loc_coll) { | ||
// TODO: To be correct, this method needs to fill the breakpoint location | ||
// collection | ||
|
@@ -1010,19 +1048,32 @@ void Breakpoint::SendBreakpointChangedEvent( | |
|
||
const char *Breakpoint::BreakpointEventTypeAsCString(BreakpointEventType type) { | ||
switch (type) { | ||
case eBreakpointEventTypeInvalidType: return "invalid"; | ||
case eBreakpointEventTypeAdded: return "breakpoint added"; | ||
case eBreakpointEventTypeRemoved: return "breakpoint removed"; | ||
case eBreakpointEventTypeLocationsAdded: return "locations added"; | ||
case eBreakpointEventTypeLocationsRemoved: return "locations removed"; | ||
case eBreakpointEventTypeLocationsResolved: return "locations resolved"; | ||
case eBreakpointEventTypeEnabled: return "breakpoint enabled"; | ||
case eBreakpointEventTypeDisabled: return "breakpoint disabled"; | ||
case eBreakpointEventTypeCommandChanged: return "command changed"; | ||
case eBreakpointEventTypeConditionChanged: return "condition changed"; | ||
case eBreakpointEventTypeIgnoreChanged: return "ignore count changed"; | ||
case eBreakpointEventTypeThreadChanged: return "thread changed"; | ||
case eBreakpointEventTypeAutoContinueChanged: return "autocontinue changed"; | ||
case eBreakpointEventTypeInvalidType: | ||
return "invalid"; | ||
case eBreakpointEventTypeAdded: | ||
return "breakpoint added"; | ||
case eBreakpointEventTypeRemoved: | ||
return "breakpoint removed"; | ||
case eBreakpointEventTypeLocationsAdded: | ||
return "locations added"; | ||
case eBreakpointEventTypeLocationsRemoved: | ||
return "locations removed"; | ||
case eBreakpointEventTypeLocationsResolved: | ||
return "locations resolved"; | ||
case eBreakpointEventTypeEnabled: | ||
return "breakpoint enabled"; | ||
case eBreakpointEventTypeDisabled: | ||
return "breakpoint disabled"; | ||
case eBreakpointEventTypeCommandChanged: | ||
return "command changed"; | ||
case eBreakpointEventTypeConditionChanged: | ||
return "condition changed"; | ||
case eBreakpointEventTypeIgnoreChanged: | ||
return "ignore count changed"; | ||
case eBreakpointEventTypeThreadChanged: | ||
return "thread changed"; | ||
case eBreakpointEventTypeAutoContinueChanged: | ||
return "autocontinue changed"; | ||
}; | ||
llvm_unreachable("Fully covered switch above!"); | ||
} | ||
|
@@ -1060,7 +1111,7 @@ void Breakpoint::BreakpointEventData::Dump(Stream *s) const { | |
BreakpointEventType event_type = GetBreakpointEventType(); | ||
break_id_t bkpt_id = GetBreakpoint()->GetID(); | ||
s->Format("bkpt: {0} type: {1}", bkpt_id, | ||
BreakpointEventTypeAsCString(event_type)); | ||
BreakpointEventTypeAsCString(event_type)); | ||
} | ||
|
||
const Breakpoint::BreakpointEventData * | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/Makefile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
C_SOURCES := main.c | ||
|
||
ifeq ($(CC_TYPE), icc) | ||
CFLAGS_EXTRAS := -debug inline-debug-info | ||
endif | ||
|
||
include Makefile.rules |
50 changes: 50 additions & 0 deletions
50
...nalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import lldb | ||
from lldbsuite.test.decorators import * | ||
from lldbsuite.test.lldbtest import * | ||
from lldbsuite.test import lldbutil | ||
|
||
from functionalities.breakpoint.hardware_breakpoints.base import * | ||
|
||
|
||
class SimpleHWBreakpointTest(HardwareBreakpointTestBase): | ||
def does_not_support_hw_breakpoints(self): | ||
# FIXME: Use HardwareBreakpointTestBase.supports_hw_breakpoints | ||
if super().supports_hw_breakpoints() is None: | ||
return "Hardware breakpoints are unsupported" | ||
return None | ||
|
||
@skipTestIfFn(does_not_support_hw_breakpoints) | ||
def test(self): | ||
"""Test SBBreakpoint::SetIsHardware""" | ||
self.build() | ||
|
||
# Set a breakpoint on main. | ||
target, process, _, main_bp = lldbutil.run_to_source_breakpoint( | ||
self, "main", lldb.SBFileSpec("main.c") | ||
) | ||
|
||
break_on_me_bp = target.BreakpointCreateByLocation("main.c", 1) | ||
|
||
self.assertFalse(main_bp.IsHardware()) | ||
self.assertFalse(break_on_me_bp.IsHardware()) | ||
self.assertGreater(break_on_me_bp.GetNumResolvedLocations(), 0) | ||
|
||
error = break_on_me_bp.SetIsHardware(True) | ||
|
||
# Regardless of whether we succeeded in updating all the locations, the | ||
# breakpoint will be marked as a hardware breakpoint. | ||
self.assertTrue(break_on_me_bp.IsHardware()) | ||
|
||
if super().supports_hw_breakpoints(): | ||
self.assertSuccess(error) | ||
|
||
# Continue to our Hardware breakpoint and verify that's the reason | ||
# we're stopped. | ||
process.Continue() | ||
self.expect( | ||
"thread list", | ||
STOPPED_DUE_TO_BREAKPOINT, | ||
substrs=["stopped", "stop reason = breakpoint"], | ||
) | ||
else: | ||
self.assertFailure(error) |
7 changes: 7 additions & 0 deletions
7
lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/main.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
int break_on_me() { | ||
int i = 10; | ||
i++; | ||
return i; | ||
} | ||
|
||
int main() { return break_on_me(); } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good here to document how this can fail. If you enable a HW breakpoint after you've used up all the resources with other breakpoints is the only case I can think of, but that's not entirely obvious. That's the only way this can fail that I can think of. If there are other ways this could fail, we should return an SBError to distinguish between them.