First tests for serializing breakpoints.

Plus a few bug fixes I found along the way.

llvm-svn: 281690
This commit is contained in:
Jim Ingham 2016-09-16 01:41:27 +00:00
parent 6c7a0bc3d9
commit 6d1e4696a2
8 changed files with 276 additions and 36 deletions

View File

@ -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);

View File

@ -0,0 +1,5 @@
LEVEL = ../../../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules

View File

@ -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)

View File

@ -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 <stdio.h>
// This simple program is to demonstrate the capability of the lldb command
// "breakpoint modify -i <count> 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 <count>'.
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;
}

View File

@ -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);

View File

@ -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<std::recursive_mutex> 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;

View File

@ -30,7 +30,7 @@ using namespace lldb_private;
BreakpointResolverFileRegex::BreakpointResolverFileRegex(
Breakpoint *bkpt, RegularExpression &regex,
const std::unordered_set<std::string> &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) {
}

View File

@ -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);