From 6d1e4696a26965c780814f28340cc5eb1117e47d Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 16 Sep 2016 01:41:27 +0000 Subject: [PATCH] First tests for serializing breakpoints. Plus a few bug fixes I found along the way. llvm-svn: 281690 --- lldb/include/lldb/API/SBBreakpoint.h | 4 + .../functionalities/breakpoint/serialize/Makefile | 5 + .../serialize/TestBreakpointSerialization.py | 147 +++++++++++++++++++++ .../functionalities/breakpoint/serialize/main.c | 54 ++++++++ lldb/scripts/interface/SBBreakpoint.i | 6 + lldb/source/API/SBBreakpoint.cpp | 29 +++- .../Breakpoint/BreakpointResolverFileRegex.cpp | 2 +- lldb/source/Core/SearchFilter.cpp | 65 +++++---- 8 files changed, 276 insertions(+), 36 deletions(-) create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/Makefile create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/main.c diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index 0bfd9f3..a93050a 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -104,6 +104,8 @@ public: bool GetDescription(lldb::SBStream &description); + bool GetDescription(lldb::SBStream &description, bool include_locations); + static bool EventIsBreakpointEvent(const lldb::SBEvent &event); static lldb::BreakpointEventType @@ -152,6 +154,8 @@ public: SBBreakpoint GetBreakpointAtIndex(size_t idx); + SBBreakpoint FindBreakpointByID(lldb::break_id_t); + void Append(const SBBreakpoint &sb_file); bool AppendIfUnique(const SBBreakpoint &sb_file); diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/Makefile new file mode 100644 index 0000000..b09a579 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py new file mode 100644 index 0000000..3f8a393 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py @@ -0,0 +1,147 @@ +""" +Test breakpoint ignore count features. +""" + +from __future__ import print_function + + +import os +import time +import re +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class BreakpointSerialization(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(['pyapi']) + def test_resolvers(self): + """Use Python APIs to test that we serialize resolvers.""" + self.build() + self.setup_targets_and_cleanup() + self.do_check_resolvers() + + def not_test_filters(self): + """Use Python APIs to test that we serialize search filters correctly.""" + self.build() + self.setup_targets_and_cleanup() + self.check_filters() + + def not_test_options(self): + """Use Python APIs to test that we serialize breakpoint options correctly.""" + self.build() + self.setup_targets_and_cleanup() + self.check_filters() + + def not_test_complex(self): + """Use Python APIs to test that we serialize complex breakpoints correctly.""" + self.build() + self.setup_targets_and_cleanup() + self.check_filters() + + def setup_targets_and_cleanup(self): + def cleanup (): + #self.RemoveTempFile(self.bkpts_file_path) + + if self.orig_target.IsValid(): + self.dbg.DeleteTarget(self.orig_target) + self.dbg.DeleteTarget(self.copy_target) + + self.addTearDownHook(cleanup) + #self.RemoveTempFile(self.bkpts_file_path) + + exe = os.path.join(os.getcwd(), "a.out") + + # Create a targets we are making breakpoint in and copying to: + self.orig_target = self.dbg.CreateTarget(exe) + self.assertTrue(self.orig_target, VALID_TARGET) + + self.copy_target = self.dbg.CreateTarget(exe) + self.assertTrue(self.copy_target, VALID_TARGET) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + self.bkpts_file_path = os.path.join(os.getcwd(), "breakpoints.json") + self.bkpts_file_spec = lldb.SBFileSpec(self.bkpts_file_path) + + def do_check_resolvers(self): + """Use Python APIs to check serialization of breakpoint resolvers""" + + empty_module_list = lldb.SBFileSpecList() + empty_cu_list = lldb.SBFileSpecList() + blubby_file_spec = lldb.SBFileSpec(os.path.join(os.getcwd(), "blubby.c")) + + # It isn't actually important for these purposes that these breakpoint + # actually have locations. + source_bps = lldb.SBBreakpointList(self.orig_target) + source_bps.Append(self.orig_target.BreakpointCreateByLocation("blubby.c", 666)) + source_bps.Append(self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list)) + source_bps.Append(self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeFull, empty_module_list,empty_cu_list)) + source_bps.Append(self.orig_target.BreakpointCreateBySourceRegex("dont really care", blubby_file_spec)) + + error = lldb.SBError() + error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec) + self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) + + copy_bps = lldb.SBBreakpointList(self.copy_target) + error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps) + self.assertTrue(error.Success(), "Failed reading breakpoints from file: %s"%(error.GetCString())) + + num_source_bps = source_bps.GetSize() + num_copy_bps = copy_bps.GetSize() + self.assertTrue(num_source_bps == num_copy_bps, "Didn't get same number of input and output breakpoints - orig: %d copy: %d"%(num_source_bps, num_copy_bps)) + + for i in range(0, num_source_bps): + source_bp = source_bps.GetBreakpointAtIndex(i) + source_desc = lldb.SBStream() + source_bp.GetDescription(source_desc, False) + source_text = source_desc.GetData() + + # I am assuming here that the breakpoints will get written out in breakpoint ID order, and + # read back in ditto. That is true right now, and I can't see any reason to do it differently + # but if we do we can go to writing the breakpoints one by one, or sniffing the descriptions to + # see which one is which. + copy_id = source_bp.GetID() + copy_bp = copy_bps.FindBreakpointByID(copy_id) + self.assertTrue(copy_bp.IsValid(), "Could not find copy breakpoint %d."%(copy_id)) + + copy_desc = lldb.SBStream() + copy_bp.GetDescription(copy_desc, False) + copy_text = copy_desc.GetData() + + # These two should be identical. + print ("Source test for %d is %s."%(i, source_text)) + self.assertTrue (source_text == copy_text, "Source and dest breakpoints are not identical: \nsource: %s\ndest: %s"%(source_text, copy_text)) + + def check_filters(self): + """Use Python APIs to check serialization of breakpoint filters.""" + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + def check_options(self): + """Use Python APIs to check serialization of breakpoint options.""" + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + def check_resolvers(self): + """Use Python APIs to check serialization of breakpoint resolvers.""" + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + + diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/main.c b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/main.c new file mode 100644 index 0000000..b74b37b --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/main.c @@ -0,0 +1,54 @@ +//===-- main.c --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include + +// This simple program is to demonstrate the capability of the lldb command +// "breakpoint modify -i breakpt-id" to set the number of times a +// breakpoint is skipped before stopping. Ignore count can also be set upon +// breakpoint creation by 'breakpoint set ... -i '. + +int a(int); +int b(int); +int c(int); + +int a(int val) +{ + if (val <= 1) + return b(val); + else if (val >= 3) + return c(val); // a(3) -> c(3) Find the call site of c(3). + + return val; +} + +int b(int val) +{ + return c(val); +} + +int c(int val) +{ + return val + 3; // Find the line number of function "c" here. +} + +int main (int argc, char const *argv[]) +{ + int A1 = a(1); // a(1) -> b(1) -> c(1) + printf("a(1) returns %d\n", A1); + + int B2 = b(2); // b(2) -> c(2) Find the call site of b(2). + printf("b(2) returns %d\n", B2); + + int A3 = a(3); // a(3) -> c(3) Find the call site of a(3). + printf("a(3) returns %d\n", A3); + + int C1 = c(5); // Find the call site of c in main. + printf ("c(5) returns %d\n", C1); + return 0; +} diff --git a/lldb/scripts/interface/SBBreakpoint.i b/lldb/scripts/interface/SBBreakpoint.i index f360277..9098c6e 100644 --- a/lldb/scripts/interface/SBBreakpoint.i +++ b/lldb/scripts/interface/SBBreakpoint.i @@ -221,6 +221,9 @@ public: bool GetDescription (lldb::SBStream &description); + bool + GetDescription(lldb::SBStream &description, bool include_locations); + bool operator == (const lldb::SBBreakpoint& rhs); @@ -276,6 +279,9 @@ public: SBBreakpoint GetBreakpointAtIndex(size_t idx); + + SBBreakpoint + FindBreakpointByID(lldb::break_id_t); void Append(const SBBreakpoint &sb_bkpt); diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 800ad0a..7276713 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -449,14 +449,20 @@ size_t SBBreakpoint::GetNumLocations() const { } bool SBBreakpoint::GetDescription(SBStream &s) { + return GetDescription(s, true); +} + +bool SBBreakpoint::GetDescription(SBStream &s, bool include_locations) { if (m_opaque_sp) { std::lock_guard guard( m_opaque_sp->GetTarget().GetAPIMutex()); s.Printf("SBBreakpoint: id = %i, ", m_opaque_sp->GetID()); m_opaque_sp->GetResolverDescription(s.get()); m_opaque_sp->GetFilterDescription(s.get()); - const size_t num_locations = m_opaque_sp->GetNumLocations(); - s.Printf(", locations = %" PRIu64, (uint64_t)num_locations); + if (include_locations) { + const size_t num_locations = m_opaque_sp->GetNumLocations(); + s.Printf(", locations = %" PRIu64, (uint64_t)num_locations); + } return true; } s.Printf("No value"); @@ -702,6 +708,18 @@ public: return target_sp->GetBreakpointList().FindBreakpointByID(bp_id); } + BreakpointSP FindBreakpointByID(lldb::break_id_t desired_id) { + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return BreakpointSP(); + + for (lldb::break_id_t &break_id : m_break_ids) { + if (break_id == desired_id) + return target_sp->GetBreakpointList().FindBreakpointByID(break_id); + } + return BreakpointSP(); + } + bool Append(Breakpoint &bkpt) { TargetSP target_sp = m_target_wp.lock(); if (!target_sp) @@ -772,6 +790,13 @@ SBBreakpoint SBBreakpointList::GetBreakpointAtIndex(size_t idx) { return SBBreakpoint(bkpt_sp); } +SBBreakpoint SBBreakpointList::FindBreakpointByID(lldb::break_id_t id) { + if (!m_opaque_sp) + return SBBreakpoint(); + BreakpointSP bkpt_sp = m_opaque_sp->FindBreakpointByID(id); + return SBBreakpoint(bkpt_sp); +} + void SBBreakpointList::Append(const SBBreakpoint &sb_bkpt) { if (!sb_bkpt.IsValid()) return; diff --git a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp index ae2e094..780817d2 100644 --- a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp @@ -30,7 +30,7 @@ using namespace lldb_private; BreakpointResolverFileRegex::BreakpointResolverFileRegex( Breakpoint *bkpt, RegularExpression ®ex, const std::unordered_set &func_names, bool exact_match) - : BreakpointResolver(bkpt, BreakpointResolver::FileLineResolver), + : BreakpointResolver(bkpt, BreakpointResolver::FileRegexResolver), m_regex(regex), m_exact_match(exact_match), m_function_names(func_names) { } diff --git a/lldb/source/Core/SearchFilter.cpp b/lldb/source/Core/SearchFilter.cpp index 1b6e08e..8c4a3fe 100644 --- a/lldb/source/Core/SearchFilter.cpp +++ b/lldb/source/Core/SearchFilter.cpp @@ -37,7 +37,7 @@ const char *SearchFilter::FilterTyToName(enum FilterTy type) { } SearchFilter::FilterTy SearchFilter::NameToFilterTy(const char *name) { - for (size_t i = 0; i < LastKnownFilterType; i++) { + for (size_t i = 0; i <= LastKnownFilterType; i++) { if (strcmp(name, g_ty_to_name[i]) == 0) return (FilterTy)i; } @@ -163,8 +163,13 @@ SearchFilter::WrapOptionsDict(StructuredData::DictionarySP options_dict_sp) { void SearchFilter::SerializeFileSpecList( StructuredData::DictionarySP &options_dict_sp, OptionNames name, FileSpecList &file_list) { - StructuredData::ArraySP module_array_sp(new StructuredData::Array()); size_t num_modules = file_list.GetSize(); + + // Don't serialize empty lists. + if (num_modules == 0) + return; + + StructuredData::ArraySP module_array_sp(new StructuredData::Array()); for (size_t i = 0; i < num_modules; i++) { module_array_sp->AddItem(StructuredData::StringSP( new StructuredData::String(file_list.GetFileSpecAtIndex(i).GetPath()))); @@ -630,22 +635,19 @@ SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData( StructuredData::Array *modules_array; bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), modules_array); - if (!success) { - error.SetErrorString("SFBM::CFSD: Could not find the module list key."); - return nullptr; - } - - size_t num_modules = modules_array->GetSize(); FileSpecList modules; - for (size_t i = 0; i < num_modules; i++) { - std::string module; - success = modules_array->GetItemAtIndexAsString(i, module); - if (!success) { - error.SetErrorStringWithFormat( - "SFBM::CFSD: filter module item %zu not a string.", i); - return nullptr; + if (success) { + size_t num_modules = modules_array->GetSize(); + for (size_t i = 0; i < num_modules; i++) { + std::string module; + success = modules_array->GetItemAtIndexAsString(i, module); + if (!success) { + error.SetErrorStringWithFormat( + "SFBM::CFSD: filter module item %zu not a string.", i); + return nullptr; + } + modules.Append(FileSpec(module.c_str(), false)); } - modules.Append(FileSpec(module.c_str(), false)); } return SearchFilterSP( @@ -694,29 +696,26 @@ SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default; lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData( Target &target, const StructuredData::Dictionary &data_dict, Error &error) { - StructuredData::Array *modules_array; + StructuredData::Array *modules_array = nullptr; SearchFilterSP result_sp; bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), modules_array); - if (!success) { - error.SetErrorString("SFBM::CFSD: Could not find the module list key."); - return result_sp; - } - - size_t num_modules = modules_array->GetSize(); FileSpecList modules; - for (size_t i = 0; i < num_modules; i++) { - std::string module; - success = modules_array->GetItemAtIndexAsString(i, module); - if (!success) { - error.SetErrorStringWithFormat( - "SFBM::CFSD: filter module item %zu not a string.", i); - return result_sp; + if (success) { + size_t num_modules = modules_array->GetSize(); + for (size_t i = 0; i < num_modules; i++) { + std::string module; + success = modules_array->GetItemAtIndexAsString(i, module); + if (!success) { + error.SetErrorStringWithFormat( + "SFBM::CFSD: filter module item %zu not a string.", i); + return result_sp; + } + modules.Append(FileSpec(module.c_str(), false)); } - modules.Append(FileSpec(module.c_str(), false)); } - StructuredData::Array *cus_array; + StructuredData::Array *cus_array = nullptr; success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::CUList), cus_array); if (!success) { @@ -728,7 +727,7 @@ lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData( FileSpecList cus; for (size_t i = 0; i < num_cus; i++) { std::string cu; - success = modules_array->GetItemAtIndexAsString(i, cu); + success = cus_array->GetItemAtIndexAsString(i, cu); if (!success) { error.SetErrorStringWithFormat( "SFBM::CFSD: filter cu item %zu not a string.", i); -- 2.7.4