forked from OSchip/llvm-project
Add a "scripted" breakpoint type to lldb.
This change allows you to write a new breakpoint type where the logic for setting breakpoints is determined by a Python callback written using the SB API's. Differential Revision: https://reviews.llvm.org/D51830 llvm-svn: 342185
This commit is contained in:
parent
d2316d756e
commit
3815e702e7
|
@ -82,6 +82,7 @@ public:
|
|||
|
||||
protected:
|
||||
friend class SBBlock;
|
||||
friend class SBBreakpoint;
|
||||
friend class SBBreakpointLocation;
|
||||
friend class SBFrame;
|
||||
friend class SBFunction;
|
||||
|
|
|
@ -23,6 +23,8 @@ public:
|
|||
|
||||
SBBreakpoint(const lldb::SBBreakpoint &rhs);
|
||||
|
||||
SBBreakpoint(const lldb::BreakpointSP &bp_sp);
|
||||
|
||||
~SBBreakpoint();
|
||||
|
||||
const lldb::SBBreakpoint &operator=(const lldb::SBBreakpoint &rhs);
|
||||
|
@ -127,14 +129,16 @@ public:
|
|||
static uint32_t
|
||||
GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp);
|
||||
|
||||
// Can only be called from a ScriptedBreakpointResolver...
|
||||
SBError
|
||||
AddLocation(SBAddress &address);
|
||||
|
||||
private:
|
||||
friend class SBBreakpointList;
|
||||
friend class SBBreakpointLocation;
|
||||
friend class SBBreakpointName;
|
||||
friend class SBTarget;
|
||||
|
||||
SBBreakpoint(const lldb::BreakpointSP &bp_sp);
|
||||
|
||||
lldb::BreakpointSP GetSP() const;
|
||||
|
||||
lldb::BreakpointWP m_opaque_wp;
|
||||
|
|
|
@ -22,6 +22,8 @@ public:
|
|||
SBStructuredData(const lldb::SBStructuredData &rhs);
|
||||
|
||||
SBStructuredData(const lldb::EventSP &event_sp);
|
||||
|
||||
SBStructuredData(lldb_private::StructuredDataImpl *impl);
|
||||
|
||||
~SBStructuredData();
|
||||
|
||||
|
@ -41,7 +43,7 @@ public:
|
|||
/// Return the type of data in this data structure
|
||||
//------------------------------------------------------------------
|
||||
lldb::StructuredDataType GetType() const;
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the size (i.e. number of elements) in this data structure
|
||||
/// if it is an array or dictionary type. For other types, 0 will be
|
||||
|
@ -49,6 +51,12 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
size_t GetSize() const;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Fill keys with the keys in this object and return true if this data
|
||||
/// structure is a dictionary. Returns false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool GetKeys(lldb::SBStringList &keys) const;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the value corresponding to a key if this data structure
|
||||
/// is a dictionary type.
|
||||
|
|
|
@ -26,6 +26,8 @@ public:
|
|||
|
||||
SBSymbolContext(const lldb::SBSymbolContext &rhs);
|
||||
|
||||
SBSymbolContext(const lldb_private::SymbolContext *sc_ptr);
|
||||
|
||||
~SBSymbolContext();
|
||||
|
||||
bool IsValid() const;
|
||||
|
@ -69,8 +71,6 @@ protected:
|
|||
|
||||
lldb_private::SymbolContext *get() const;
|
||||
|
||||
SBSymbolContext(const lldb_private::SymbolContext *sc_ptr);
|
||||
|
||||
void SetSymbolContext(const lldb_private::SymbolContext *sc_ptr);
|
||||
|
||||
private:
|
||||
|
|
|
@ -662,6 +662,37 @@ public:
|
|||
lldb::SBBreakpoint BreakpointCreateByAddress(addr_t address);
|
||||
|
||||
lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Create a breakpoint using a scripted resolver.
|
||||
///
|
||||
/// @param[in] class_name
|
||||
/// This is the name of the class that implements a scripted resolver.
|
||||
///
|
||||
/// @param[in] extra_args
|
||||
/// This is an SBStructuredData object that will get passed to the
|
||||
/// constructor of the class in class_name. You can use this to
|
||||
/// reuse the same class, parametrizing with entries from this
|
||||
/// dictionary.
|
||||
///
|
||||
/// @param module_list
|
||||
/// If this is non-empty, this will be used as the module filter in the
|
||||
/// SearchFilter created for this breakpoint.
|
||||
///
|
||||
/// @param file_list
|
||||
/// If this is non-empty, this will be used as the comp unit filter in the
|
||||
/// SearchFilter created for this breakpoint.
|
||||
///
|
||||
/// @return
|
||||
/// An SBBreakpoint that will set locations based on the logic in the
|
||||
/// resolver's search callback.
|
||||
//------------------------------------------------------------------
|
||||
lldb::SBBreakpoint BreakpointCreateFromScript(
|
||||
const char *class_name,
|
||||
SBStructuredData &extra_args,
|
||||
const SBFileSpecList &module_list,
|
||||
const SBFileSpecList &file_list,
|
||||
bool request_hardware = false);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Read breakpoints from source_file and return the newly created
|
||||
|
|
|
@ -158,6 +158,7 @@ public:
|
|||
AddressResolver, // This is an instance of BreakpointResolverAddress
|
||||
NameResolver, // This is an instance of BreakpointResolverName
|
||||
FileRegexResolver,
|
||||
PythonResolver,
|
||||
ExceptionResolver,
|
||||
LastKnownResolverType = ExceptionResolver,
|
||||
UnknownResolver
|
||||
|
@ -204,14 +205,19 @@ protected:
|
|||
ModuleName,
|
||||
NameMaskArray,
|
||||
Offset,
|
||||
PythonClassName,
|
||||
RegexString,
|
||||
ScriptArgs,
|
||||
SectionName,
|
||||
SearchDepth,
|
||||
SkipPrologue,
|
||||
SymbolNameArray,
|
||||
LastOptionName
|
||||
};
|
||||
static const char
|
||||
*g_option_names[static_cast<uint32_t>(OptionNames::LastOptionName)];
|
||||
|
||||
virtual void NotifyBreakpointSet() {};
|
||||
|
||||
public:
|
||||
static const char *GetKey(OptionNames enum_value) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "lldb/Breakpoint/BreakpointOptions.h"
|
||||
#include "lldb/Core/Broadcaster.h"
|
||||
#include "lldb/Core/PluginInterface.h"
|
||||
#include "lldb/Core/SearchFilter.h"
|
||||
#include "lldb/Utility/Status.h"
|
||||
#include "lldb/Utility/StructuredData.h"
|
||||
|
||||
|
@ -234,6 +235,26 @@ public:
|
|||
return lldb::eStateStepping;
|
||||
}
|
||||
|
||||
virtual StructuredData::GenericSP
|
||||
CreateScriptedBreakpointResolver(const char *class_name,
|
||||
StructuredDataImpl *args_data,
|
||||
lldb::BreakpointSP &bkpt_sp) {
|
||||
return StructuredData::GenericSP();
|
||||
}
|
||||
|
||||
virtual bool
|
||||
ScriptedBreakpointResolverSearchCallback(StructuredData::GenericSP implementor_sp,
|
||||
SymbolContext *sym_ctx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual lldb::SearchDepth
|
||||
ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP implementor_sp)
|
||||
{
|
||||
return lldb::eSearchDepthModule;
|
||||
}
|
||||
|
||||
virtual StructuredData::ObjectSP
|
||||
LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) {
|
||||
return StructuredData::ObjectSP();
|
||||
|
|
|
@ -617,6 +617,15 @@ public:
|
|||
Args *additional_args = nullptr,
|
||||
Status *additional_args_error = nullptr);
|
||||
|
||||
lldb::BreakpointSP
|
||||
CreateScriptedBreakpoint(const llvm::StringRef class_name,
|
||||
const FileSpecList *containingModules,
|
||||
const FileSpecList *containingSourceFiles,
|
||||
bool internal,
|
||||
bool request_hardware,
|
||||
StructuredData::ObjectSP extra_args_sp,
|
||||
Status *creation_error = nullptr);
|
||||
|
||||
// This is the same as the func_name breakpoint except that you can specify a
|
||||
// vector of names. This is cheaper than a regular expression breakpoint in
|
||||
// the case where you just want to set a breakpoint on a set of names you
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
#define LLDB_OPT_SET_8 (1U << 7)
|
||||
#define LLDB_OPT_SET_9 (1U << 8)
|
||||
#define LLDB_OPT_SET_10 (1U << 9)
|
||||
#define LLDB_OPT_SET_11 (1U << 10)
|
||||
#define LLDB_OPT_SET_FROM_TO(A, B) \
|
||||
(((1U << (B)) - 1) ^ (((1U << (A)) - 1) >> 1))
|
||||
|
||||
|
|
|
@ -258,13 +258,14 @@ enum ExpressionResults {
|
|||
};
|
||||
|
||||
enum SearchDepth {
|
||||
eSearchDepthTarget = 0,
|
||||
eSearchDepthInvalid = 0,
|
||||
eSearchDepthTarget,
|
||||
eSearchDepthModule,
|
||||
eSearchDepthCompUnit,
|
||||
eSearchDepthFunction,
|
||||
eSearchDepthBlock,
|
||||
eSearchDepthAddress,
|
||||
kNumSearchDepthKinds = eSearchDepthAddress
|
||||
kLastSearchDepthKind = eSearchDepthAddress
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -330,6 +330,20 @@ def sort_stopped_threads(process,
|
|||
# Utility functions for setting breakpoints
|
||||
# ==================================================
|
||||
|
||||
def run_break_set_by_script(
|
||||
test,
|
||||
class_name,
|
||||
extra_options=None,
|
||||
num_expected_locations=1):
|
||||
"""Set a scripted breakpoint. Check that it got the right number of locations."""
|
||||
test.assertTrue(class_name is not None, "Must pass in a class name.")
|
||||
command = "breakpoint set -P " + class_name
|
||||
if extra_options is not None:
|
||||
command += " " + extra_options
|
||||
|
||||
break_results = run_break_set_command(test, command)
|
||||
check_breakpoint_result(test, break_results, num_locations=num_expected_locations)
|
||||
return get_bpno_from_match(break_results)
|
||||
|
||||
def run_break_set_by_file_and_line(
|
||||
test,
|
||||
|
@ -737,7 +751,7 @@ def get_crashed_threads(test, process):
|
|||
|
||||
# Helper functions for run_to_{source,name}_breakpoint:
|
||||
|
||||
def run_to_breakpoint_make_target(test, exe_name, in_cwd):
|
||||
def run_to_breakpoint_make_target(test, exe_name = "a.out", in_cwd = True):
|
||||
if in_cwd:
|
||||
exe = test.getBuildArtifact(exe_name)
|
||||
|
||||
|
@ -746,7 +760,7 @@ def run_to_breakpoint_make_target(test, exe_name, in_cwd):
|
|||
test.assertTrue(target, "Target: %s is not valid."%(exe_name))
|
||||
return target
|
||||
|
||||
def run_to_breakpoint_do_run(test, target, bkpt, launch_info):
|
||||
def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None):
|
||||
|
||||
# Launch the process, and do not stop at the entry point.
|
||||
if not launch_info:
|
||||
|
|
|
@ -147,3 +147,17 @@ SBTypeToSWIGWrapper (lldb::SBTypeSummaryOptions* summary_options_sb)
|
|||
{
|
||||
return SWIG_NewPointerObj((void *) summary_options_sb, SWIGTYPE_p_lldb__SBTypeSummaryOptions, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
PyObject*
|
||||
SBTypeToSWIGWrapper (lldb::SBStructuredData* structured_data_sb)
|
||||
{
|
||||
return SWIG_NewPointerObj((void *) structured_data_sb, SWIGTYPE_p_lldb__SBStructuredData, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
PyObject*
|
||||
SBTypeToSWIGWrapper (lldb::SBSymbolContext* sym_ctx_sb)
|
||||
{
|
||||
return SWIG_NewPointerObj((void *) sym_ctx_sb, SWIGTYPE_p_lldb__SBSymbolContext, 0);
|
||||
}
|
||||
|
|
|
@ -333,6 +333,101 @@ LLDBSWIGPythonCallThreadPlan
|
|||
return false;
|
||||
}
|
||||
|
||||
SWIGEXPORT void *
|
||||
LLDBSwigPythonCreateScriptedBreakpointResolver
|
||||
(
|
||||
const char *python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb_private::StructuredDataImpl *args_impl,
|
||||
lldb::BreakpointSP &breakpoint_sp
|
||||
)
|
||||
{
|
||||
using namespace lldb_private;
|
||||
|
||||
if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
PyErr_Cleaner py_err_cleaner(true);
|
||||
|
||||
auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name);
|
||||
auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name, dict);
|
||||
|
||||
if (!pfunc.IsAllocated())
|
||||
return nullptr;
|
||||
|
||||
lldb::SBBreakpoint *bkpt_value = new lldb::SBBreakpoint(breakpoint_sp);
|
||||
|
||||
PythonObject bkpt_arg(PyRefType::Owned, SBTypeToSWIGWrapper(bkpt_value));
|
||||
|
||||
lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl);
|
||||
PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value));
|
||||
|
||||
PythonObject result = pfunc(bkpt_arg, args_arg, dict);
|
||||
// FIXME: At this point we should check that the class we found supports all the methods
|
||||
// that we need.
|
||||
|
||||
if (result.IsAllocated())
|
||||
{
|
||||
// Check that __callback__ is defined:
|
||||
auto callback_func = result.ResolveName<PythonCallable>("__callback__");
|
||||
if (callback_func.IsAllocated())
|
||||
return result.release();
|
||||
else
|
||||
result.release();
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
SWIGEXPORT unsigned int
|
||||
LLDBSwigPythonCallBreakpointResolver
|
||||
(
|
||||
void *implementor,
|
||||
const char *method_name,
|
||||
lldb_private::SymbolContext *sym_ctx
|
||||
)
|
||||
{
|
||||
using namespace lldb_private;
|
||||
|
||||
PyErr_Cleaner py_err_cleaner(false);
|
||||
PythonObject self(PyRefType::Borrowed, static_cast<PyObject*>(implementor));
|
||||
auto pfunc = self.ResolveName<PythonCallable>(method_name);
|
||||
|
||||
if (!pfunc.IsAllocated())
|
||||
return 0;
|
||||
|
||||
PythonObject result;
|
||||
if (sym_ctx != nullptr) {
|
||||
lldb::SBSymbolContext sb_sym_ctx(sym_ctx);
|
||||
PythonObject sym_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_sym_ctx));
|
||||
result = pfunc(sym_ctx_arg);
|
||||
} else
|
||||
result = pfunc();
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The callback will return a bool, but we're need to also return ints
|
||||
// so we're squirrelling the bool through as an int... And if you return
|
||||
// nothing, we'll continue.
|
||||
if (strcmp(method_name, "__callback__") == 0) {
|
||||
if (result.get() == Py_False)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
PythonInteger int_result = result.AsType<PythonInteger>();
|
||||
if (!int_result.IsAllocated())
|
||||
return 0;
|
||||
|
||||
unsigned int ret_val = int_result.GetInteger();
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// wrapper that calls an optional instance member of an object taking no arguments
|
||||
static PyObject*
|
||||
LLDBSwigPython_CallOptionalMember
|
||||
|
|
|
@ -226,6 +226,10 @@ public:
|
|||
bool
|
||||
GetDescription(lldb::SBStream &description, bool include_locations);
|
||||
|
||||
// Can only be called from a ScriptedBreakpointResolver...
|
||||
SBError
|
||||
AddLocation(SBAddress &address);
|
||||
|
||||
bool
|
||||
operator == (const lldb::SBBreakpoint& rhs);
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace lldb {
|
|||
|
||||
size_t GetSize() const;
|
||||
|
||||
bool GetKeys(lldb::SBStringList &keys) const;
|
||||
|
||||
lldb::SBStructuredData GetValueForKey(const char *key) const;
|
||||
|
||||
lldb::SBStructuredData GetItemAtIndex(size_t idx) const;
|
||||
|
|
|
@ -731,6 +731,74 @@ public:
|
|||
|
||||
lldb::SBBreakpoint
|
||||
BreakpointCreateBySBAddress (SBAddress &sb_address);
|
||||
|
||||
%feature("docstring", "
|
||||
//------------------------------------------------------------------
|
||||
/// Create a breakpoint using a scripted resolver.
|
||||
///
|
||||
/// @param[in] class_name
|
||||
/// This is the name of the class that implements a scripted resolver.
|
||||
/// The class should have the following signature:
|
||||
/// class Resolver:
|
||||
/// def __init__(self, bkpt, extra_args):
|
||||
/// # bkpt - the breakpoint for which this is the resolver. When
|
||||
/// # the resolver finds an interesting address, call AddLocation
|
||||
/// # on this breakpoint to add it.
|
||||
/// #
|
||||
/// # extra_args - an SBStructuredData that can be used to
|
||||
/// # parametrize this instance. Same as the extra_args passed
|
||||
/// # to BreakpointCreateFromScript.
|
||||
///
|
||||
/// def __get_depth__ (self):
|
||||
/// # This is optional, but if defined, you should return the
|
||||
/// # depth at which you want the callback to be called. The
|
||||
/// # available options are:
|
||||
/// # lldb.eSearchDepthModule
|
||||
/// # lldb.eSearchDepthCompUnit
|
||||
/// # The default if you don't implement this method is
|
||||
/// # eSearchDepthModule.
|
||||
///
|
||||
/// def __callback__(self, sym_ctx):
|
||||
/// # sym_ctx - an SBSymbolContext that is the cursor in the
|
||||
/// # search through the program to resolve breakpoints.
|
||||
/// # The sym_ctx will be filled out to the depth requested in
|
||||
/// # __get_depth__.
|
||||
/// # Look in this sym_ctx for new breakpoint locations,
|
||||
/// # and if found use bkpt.AddLocation to add them.
|
||||
/// # Note, you will only get called for modules/compile_units that
|
||||
/// # pass the SearchFilter provided by the module_list & file_list
|
||||
/// # passed into BreakpointCreateFromScript.
|
||||
///
|
||||
/// def get_short_help(self):
|
||||
/// # Optional, but if implemented return a short string that will
|
||||
/// # be printed at the beginning of the break list output for the
|
||||
/// # breakpoint.
|
||||
///
|
||||
/// @param[in] extra_args
|
||||
/// This is an SBStructuredData object that will get passed to the
|
||||
/// constructor of the class in class_name. You can use this to
|
||||
/// reuse the same class, parametrizing it with entries from this
|
||||
/// dictionary.
|
||||
///
|
||||
/// @param module_list
|
||||
/// If this is non-empty, this will be used as the module filter in the
|
||||
/// SearchFilter created for this breakpoint.
|
||||
///
|
||||
/// @param file_list
|
||||
/// If this is non-empty, this will be used as the comp unit filter in the
|
||||
/// SearchFilter created for this breakpoint.
|
||||
///
|
||||
/// @return
|
||||
/// An SBBreakpoint that will set locations based on the logic in the
|
||||
/// resolver's search callback.
|
||||
//------------------------------------------------------------------
|
||||
") BreakpointCreateFromScript;
|
||||
lldb::SBBreakpoint BreakpointCreateFromScript(
|
||||
const char *class_name,
|
||||
SBStructuredData &extra_args,
|
||||
const SBFileSpecList &module_list,
|
||||
const SBFileSpecList &file_list,
|
||||
bool request_hardware = false);
|
||||
|
||||
uint32_t
|
||||
GetNumBreakpoints () const;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "lldb/Breakpoint/Breakpoint.h"
|
||||
#include "lldb/Breakpoint/BreakpointIDList.h"
|
||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolver.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverScripted.h"
|
||||
#include "lldb/Breakpoint/StoppointCallbackContext.h"
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
|
@ -487,6 +489,40 @@ bool SBBreakpoint::GetDescription(SBStream &s, bool include_locations) {
|
|||
return false;
|
||||
}
|
||||
|
||||
SBError
|
||||
SBBreakpoint::AddLocation(SBAddress &address) {
|
||||
BreakpointSP bkpt_sp = GetSP();
|
||||
SBError error;
|
||||
|
||||
if (!address.IsValid()) {
|
||||
error.SetErrorString("Can't add an invalid address.");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!bkpt_sp) {
|
||||
error.SetErrorString("No breakpoint to add a location to.");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!llvm::isa<BreakpointResolverScripted>(bkpt_sp->GetResolver().get())) {
|
||||
error.SetErrorString("Only a scripted resolver can add locations.");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (bkpt_sp->GetSearchFilter()->AddressPasses(address.ref()))
|
||||
bkpt_sp->AddLocation(address.ref());
|
||||
else
|
||||
{
|
||||
StreamString s;
|
||||
address.get()->Dump(&s, &bkpt_sp->GetTarget(),
|
||||
Address::DumpStyleModuleWithFileAddress);
|
||||
error.SetErrorStringWithFormat("Address: %s didn't pass the filter.",
|
||||
s.GetData());
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void SBBreakpoint
|
||||
::SetCallback(SBBreakpointHitCallback callback,
|
||||
void *baton) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "lldb/API/SBStructuredData.h"
|
||||
|
||||
#include "lldb/API/SBStream.h"
|
||||
#include "lldb/API/SBStringList.h"
|
||||
#include "lldb/Core/Event.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Target/StructuredDataPlugin.h"
|
||||
|
@ -31,6 +32,9 @@ SBStructuredData::SBStructuredData(const lldb::SBStructuredData &rhs)
|
|||
SBStructuredData::SBStructuredData(const lldb::EventSP &event_sp)
|
||||
: m_impl_up(new StructuredDataImpl(event_sp)) {}
|
||||
|
||||
SBStructuredData::SBStructuredData(lldb_private::StructuredDataImpl *impl)
|
||||
: m_impl_up(impl) {}
|
||||
|
||||
SBStructuredData::~SBStructuredData() {}
|
||||
|
||||
SBStructuredData &SBStructuredData::
|
||||
|
@ -76,6 +80,33 @@ size_t SBStructuredData::GetSize() const {
|
|||
return (m_impl_up ? m_impl_up->GetSize() : 0);
|
||||
}
|
||||
|
||||
bool SBStructuredData::GetKeys(lldb::SBStringList &keys) const {
|
||||
if (!m_impl_up)
|
||||
return false;
|
||||
|
||||
if (GetType() != eStructuredDataTypeDictionary)
|
||||
return false;
|
||||
|
||||
StructuredData::ObjectSP obj_sp = m_impl_up->GetObjectSP();
|
||||
if (!obj_sp)
|
||||
return false;
|
||||
|
||||
StructuredData::Dictionary *dict = obj_sp->GetAsDictionary();
|
||||
// We claimed we were a dictionary, so this can't be null.
|
||||
assert(dict);
|
||||
// The return kind of GetKeys is an Array:
|
||||
StructuredData::ObjectSP array_sp = dict->GetKeys();
|
||||
StructuredData::Array *key_arr = array_sp->GetAsArray();
|
||||
assert(key_arr);
|
||||
|
||||
key_arr->ForEach([&keys] (StructuredData::Object *object) -> bool {
|
||||
llvm::StringRef key = object->GetStringValue("");
|
||||
keys.AppendString(key.str().c_str());
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
lldb::SBStructuredData SBStructuredData::GetValueForKey(const char *key) const {
|
||||
if (!m_impl_up)
|
||||
return SBStructuredData();
|
||||
|
|
|
@ -1044,7 +1044,7 @@ SBTarget::BreakpointCreateForException(lldb::LanguageType language,
|
|||
}
|
||||
|
||||
if (log)
|
||||
log->Printf("SBTarget(%p)::BreakpointCreateByRegex (Language: %s, catch: "
|
||||
log->Printf("SBTarget(%p)::BreakpointCreateForException (Language: %s, catch: "
|
||||
"%s throw: %s) => SBBreakpoint(%p)",
|
||||
static_cast<void *>(target_sp.get()),
|
||||
Language::GetNameForLanguageType(language),
|
||||
|
@ -1054,6 +1054,42 @@ SBTarget::BreakpointCreateForException(lldb::LanguageType language,
|
|||
return sb_bp;
|
||||
}
|
||||
|
||||
lldb::SBBreakpoint
|
||||
SBTarget::BreakpointCreateFromScript(const char *class_name,
|
||||
SBStructuredData &extra_args,
|
||||
const SBFileSpecList &module_list,
|
||||
const SBFileSpecList &file_list,
|
||||
bool request_hardware)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
|
||||
|
||||
SBBreakpoint sb_bp;
|
||||
TargetSP target_sp(GetSP());
|
||||
if (target_sp) {
|
||||
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
|
||||
Status error;
|
||||
|
||||
StructuredData::ObjectSP obj_sp = extra_args.m_impl_up->GetObjectSP();
|
||||
sb_bp =
|
||||
target_sp->CreateScriptedBreakpoint(class_name,
|
||||
module_list.get(),
|
||||
file_list.get(),
|
||||
false, /* internal */
|
||||
request_hardware,
|
||||
obj_sp,
|
||||
&error);
|
||||
}
|
||||
if (log)
|
||||
log->Printf("SBTarget(%p)::BreakpointCreateFromScript (class name: %s) "
|
||||
" => SBBreakpoint(%p)",
|
||||
static_cast<void *>(target_sp.get()),
|
||||
class_name,
|
||||
static_cast<void *>(sb_bp.GetSP().get()));
|
||||
|
||||
return sb_bp;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SBTarget::GetNumBreakpoints() const {
|
||||
TargetSP target_sp(GetSP());
|
||||
if (target_sp) {
|
||||
|
|
|
@ -176,6 +176,18 @@ extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan(
|
|||
extern "C" bool LLDBSWIGPythonCallThreadPlan(void *implementor,
|
||||
const char *method_name,
|
||||
Event *event_sp, bool &got_error);
|
||||
|
||||
extern "C" void *LLDBSwigPythonCreateScriptedBreakpointResolver(
|
||||
const char *python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb_private::StructuredDataImpl *args,
|
||||
lldb::BreakpointSP &bkpt_sp);
|
||||
|
||||
extern "C" unsigned int LLDBSwigPythonCallBreakpointResolver(
|
||||
void *implementor,
|
||||
const char *method_name,
|
||||
lldb_private::SymbolContext *sym_ctx
|
||||
);
|
||||
|
||||
extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor,
|
||||
uint32_t max);
|
||||
|
@ -413,7 +425,8 @@ void SystemInitializerFull::InitializeSWIG() {
|
|||
LLDBSWIGPythonRunScriptKeywordThread,
|
||||
LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame,
|
||||
LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting,
|
||||
LLDBSwigPythonCreateScriptedThreadPlan, LLDBSWIGPythonCallThreadPlan);
|
||||
LLDBSwigPythonCreateScriptedThreadPlan, LLDBSWIGPythonCallThreadPlan,
|
||||
LLDBSwigPythonCreateScriptedBreakpointResolver, LLDBSwigPythonCallBreakpointResolver);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverName.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverScripted.h"
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Core/ModuleList.h"
|
||||
#include "lldb/Core/SearchFilter.h"
|
||||
|
@ -44,9 +45,10 @@ const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
|
|||
|
||||
const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
|
||||
BreakpointResolver::OptionNames::LastOptionName)] = {
|
||||
"AddressOffset", "Exact", "FileName", "Inlines", "Language",
|
||||
"LineNumber", "Column", "ModuleName", "NameMask", "Offset",
|
||||
"Regex", "SectionName", "SkipPrologue", "SymbolNames"};
|
||||
"AddressOffset", "Exact", "FileName", "Inlines", "Language",
|
||||
"LineNumber", "Column", "ModuleName", "NameMask", "Offset",
|
||||
"PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth",
|
||||
"SkipPrologue", "SymbolNames"};
|
||||
|
||||
const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
|
||||
if (type > LastKnownResolverType)
|
||||
|
@ -132,6 +134,10 @@ BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
|
|||
resolver = BreakpointResolverFileRegex::CreateFromStructuredData(
|
||||
nullptr, *subclass_options, error);
|
||||
break;
|
||||
case PythonResolver:
|
||||
resolver = BreakpointResolverScripted::CreateFromStructuredData(
|
||||
nullptr, *subclass_options, error);
|
||||
break;
|
||||
case ExceptionResolver:
|
||||
error.SetErrorString("Exception resolvers are hard.");
|
||||
break;
|
||||
|
@ -165,6 +171,7 @@ StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict(
|
|||
|
||||
void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) {
|
||||
m_breakpoint = bkpt;
|
||||
NotifyBreakpointSet();
|
||||
}
|
||||
|
||||
void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,
|
||||
|
|
|
@ -245,10 +245,10 @@ public:
|
|||
|
||||
// If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
|
||||
// update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
|
||||
#define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2)
|
||||
#define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10)
|
||||
#define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 11) & ~LLDB_OPT_SET_10)
|
||||
#define LLDB_OPT_SKIP_PROLOGUE (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
|
||||
#define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
|
||||
#define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 11) & ~LLDB_OPT_SET_2 & ~LLDB_OPT_SET_10)
|
||||
#define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_FROM_TO(1, 8) & ~LLDB_OPT_SET_2)
|
||||
#define LLDB_OPT_MOVE_TO_NEAREST_CODE (LLDB_OPT_SET_1 | LLDB_OPT_SET_9)
|
||||
#define LLDB_OPT_EXPR_LANGUAGE (LLDB_OPT_SET_FROM_TO(3, 8))
|
||||
|
||||
|
@ -301,6 +301,9 @@ static OptionDefinition g_breakpoint_set_options[] = {
|
|||
"are specified, uses the current \"default source file\". If you want to "
|
||||
"match against all source files, pass the \"--all-files\" option." },
|
||||
{ LLDB_OPT_SET_9, false, "all-files", 'A', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "All files are searched for source pattern matches." },
|
||||
{ LLDB_OPT_SET_11, true, "python-class", 'P', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "The name of the class that implement a scripted breakpoint." },
|
||||
{ LLDB_OPT_SET_11, false, "python-class-key", 'k', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The key for a key/value pair passed to the class that implements a scripted breakpoint. Can be specified more than once." },
|
||||
{ LLDB_OPT_SET_11, false, "python-class-value", 'v', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The value for the previous key in the pair passed to the class that implements a scripted breakpoint. Can be specified more than once." },
|
||||
{ LLDB_OPT_SET_10, true, "language-exception", 'E', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Set the breakpoint on exceptions thrown by the specified language (without "
|
||||
"options, on throw but not catch.)" },
|
||||
{ LLDB_OPT_SET_10, false, "on-throw", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Set the breakpoint on exception throW." },
|
||||
|
@ -336,7 +339,8 @@ public:
|
|||
eSetTypeFunctionName,
|
||||
eSetTypeFunctionRegexp,
|
||||
eSetTypeSourceRegexp,
|
||||
eSetTypeException
|
||||
eSetTypeException,
|
||||
eSetTypeScripted,
|
||||
} BreakpointSetType;
|
||||
|
||||
CommandObjectBreakpointSet(CommandInterpreter &interpreter)
|
||||
|
@ -454,7 +458,15 @@ public:
|
|||
case 'H':
|
||||
m_hardware = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'k': {
|
||||
if (m_current_key.empty())
|
||||
m_current_key.assign(option_arg);
|
||||
else
|
||||
error.SetErrorStringWithFormat("Key: %s missing value.",
|
||||
m_current_key.c_str());
|
||||
|
||||
} break;
|
||||
case 'K': {
|
||||
bool success;
|
||||
bool value;
|
||||
|
@ -535,6 +547,10 @@ public:
|
|||
case 'p':
|
||||
m_source_text_regexp.assign(option_arg);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
m_python_class.assign(option_arg);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
m_func_regexp.assign(option_arg);
|
||||
|
@ -549,6 +565,16 @@ public:
|
|||
m_func_name_type_mask |= eFunctionNameTypeSelector;
|
||||
break;
|
||||
|
||||
case 'v': {
|
||||
if (!m_current_key.empty()) {
|
||||
m_extra_args_sp->AddStringItem(m_current_key, option_arg);
|
||||
m_current_key.clear();
|
||||
}
|
||||
else
|
||||
error.SetErrorStringWithFormat("Value \"%s\" missing matching key.",
|
||||
option_arg.str().c_str());
|
||||
} break;
|
||||
|
||||
case 'w': {
|
||||
bool success;
|
||||
m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
|
||||
|
@ -593,6 +619,9 @@ public:
|
|||
m_exception_extra_args.Clear();
|
||||
m_move_to_nearest_code = eLazyBoolCalculate;
|
||||
m_source_regex_func_names.clear();
|
||||
m_python_class.clear();
|
||||
m_extra_args_sp.reset(new StructuredData::Dictionary());
|
||||
m_current_key.clear();
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
|
@ -623,6 +652,9 @@ public:
|
|||
Args m_exception_extra_args;
|
||||
LazyBool m_move_to_nearest_code;
|
||||
std::unordered_set<std::string> m_source_regex_func_names;
|
||||
std::string m_python_class;
|
||||
StructuredData::DictionarySP m_extra_args_sp;
|
||||
std::string m_current_key;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -649,7 +681,9 @@ protected:
|
|||
|
||||
BreakpointSetType break_type = eSetTypeInvalid;
|
||||
|
||||
if (m_options.m_line_num != 0)
|
||||
if (!m_options.m_python_class.empty())
|
||||
break_type = eSetTypeScripted;
|
||||
else if (m_options.m_line_num != 0)
|
||||
break_type = eSetTypeFileAndLine;
|
||||
else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
|
||||
break_type = eSetTypeAddress;
|
||||
|
@ -824,6 +858,25 @@ protected:
|
|||
return false;
|
||||
}
|
||||
} break;
|
||||
case eSetTypeScripted: {
|
||||
|
||||
Status error;
|
||||
bp_sp = target->CreateScriptedBreakpoint(m_options.m_python_class,
|
||||
&(m_options.m_modules),
|
||||
&(m_options.m_filenames),
|
||||
false,
|
||||
m_options.m_hardware,
|
||||
m_options.m_extra_args_sp,
|
||||
&error);
|
||||
if (error.Fail()) {
|
||||
result.AppendErrorWithFormat(
|
||||
"Error setting extra exception arguments: %s",
|
||||
error.AsCString());
|
||||
target->RemoveBreakpointByID(bp_sp->GetID());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -311,7 +311,7 @@ SearchFilter::DoCUIteration(const ModuleSP &module_sp,
|
|||
return Searcher::eCallbackReturnContinue;
|
||||
else if (shouldContinue == Searcher::eCallbackReturnStop)
|
||||
return shouldContinue;
|
||||
} else {
|
||||
} else if (searcher.GetDepth() == lldb::eSearchDepthFunction) {
|
||||
// FIXME Descend to block.
|
||||
}
|
||||
}
|
||||
|
@ -748,7 +748,15 @@ SearchFilterByModuleListAndCU::SerializeToStructuredData() {
|
|||
}
|
||||
|
||||
bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) {
|
||||
return true;
|
||||
SymbolContext sym_ctx;
|
||||
address.CalculateSymbolContext(&sym_ctx, eSymbolContextEverything);
|
||||
if (!sym_ctx.comp_unit) {
|
||||
if (m_cu_spec_list.GetSize() != 0)
|
||||
return false; // Has no comp_unit so can't pass the file check.
|
||||
}
|
||||
if (m_cu_spec_list.FindFileIndex(0, sym_ctx.comp_unit, false) == UINT32_MAX)
|
||||
return false; // Fails the file check
|
||||
return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp);
|
||||
}
|
||||
|
||||
bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) {
|
||||
|
|
|
@ -107,6 +107,10 @@ static ScriptInterpreterPython::SWIGPythonCreateScriptedThreadPlan
|
|||
g_swig_thread_plan_script = nullptr;
|
||||
static ScriptInterpreterPython::SWIGPythonCallThreadPlan
|
||||
g_swig_call_thread_plan = nullptr;
|
||||
static ScriptInterpreterPython::SWIGPythonCreateScriptedBreakpointResolver
|
||||
g_swig_bkpt_resolver_script = nullptr;
|
||||
static ScriptInterpreterPython::SWIGPythonCallBreakpointResolver
|
||||
g_swig_call_bkpt_resolver = nullptr;
|
||||
|
||||
static bool g_initialized = false;
|
||||
|
||||
|
@ -1868,6 +1872,84 @@ lldb::StateType ScriptInterpreterPython::ScriptedThreadPlanGetRunState(
|
|||
return lldb::eStateRunning;
|
||||
}
|
||||
|
||||
StructuredData::GenericSP
|
||||
ScriptInterpreterPython::CreateScriptedBreakpointResolver(
|
||||
const char *class_name,
|
||||
StructuredDataImpl *args_data,
|
||||
lldb::BreakpointSP &bkpt_sp) {
|
||||
|
||||
if (class_name == nullptr || class_name[0] == '\0')
|
||||
return StructuredData::GenericSP();
|
||||
|
||||
if (!bkpt_sp.get())
|
||||
return StructuredData::GenericSP();
|
||||
|
||||
Debugger &debugger = bkpt_sp->GetTarget().GetDebugger();
|
||||
ScriptInterpreter *script_interpreter =
|
||||
debugger.GetCommandInterpreter().GetScriptInterpreter();
|
||||
ScriptInterpreterPython *python_interpreter =
|
||||
static_cast<ScriptInterpreterPython *>(script_interpreter);
|
||||
|
||||
if (!script_interpreter)
|
||||
return StructuredData::GenericSP();
|
||||
|
||||
void *ret_val;
|
||||
|
||||
{
|
||||
Locker py_lock(this,
|
||||
Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
|
||||
|
||||
ret_val = g_swig_bkpt_resolver_script(
|
||||
class_name, python_interpreter->m_dictionary_name.c_str(),
|
||||
args_data, bkpt_sp);
|
||||
}
|
||||
|
||||
return StructuredData::GenericSP(new StructuredPythonObject(ret_val));
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::ScriptedBreakpointResolverSearchCallback(
|
||||
StructuredData::GenericSP implementor_sp,
|
||||
SymbolContext *sym_ctx) {
|
||||
bool should_continue = false;
|
||||
|
||||
if (implementor_sp) {
|
||||
Locker py_lock(this,
|
||||
Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
|
||||
should_continue
|
||||
= g_swig_call_bkpt_resolver(implementor_sp->GetValue(), "__callback__",
|
||||
sym_ctx);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
return should_continue;
|
||||
}
|
||||
|
||||
lldb::SearchDepth
|
||||
ScriptInterpreterPython::ScriptedBreakpointResolverSearchDepth(
|
||||
StructuredData::GenericSP implementor_sp) {
|
||||
int depth_as_int = lldb::eSearchDepthModule;
|
||||
if (implementor_sp) {
|
||||
Locker py_lock(this,
|
||||
Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
|
||||
depth_as_int
|
||||
= g_swig_call_bkpt_resolver(implementor_sp->GetValue(), "__get_depth__", nullptr);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
if (depth_as_int == lldb::eSearchDepthInvalid)
|
||||
return lldb::eSearchDepthModule;
|
||||
|
||||
if (depth_as_int <= lldb::kLastSearchDepthKind)
|
||||
return (lldb::SearchDepth) depth_as_int;
|
||||
else
|
||||
return lldb::eSearchDepthModule;
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP
|
||||
ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec,
|
||||
lldb_private::Status &error) {
|
||||
|
@ -3107,7 +3189,9 @@ void ScriptInterpreterPython::InitializeInterpreter(
|
|||
SWIGPythonScriptKeyword_Value swig_run_script_keyword_value,
|
||||
SWIGPython_GetDynamicSetting swig_plugin_get,
|
||||
SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
|
||||
SWIGPythonCallThreadPlan swig_call_thread_plan) {
|
||||
SWIGPythonCallThreadPlan swig_call_thread_plan,
|
||||
SWIGPythonCreateScriptedBreakpointResolver swig_bkpt_resolver_script,
|
||||
SWIGPythonCallBreakpointResolver swig_call_bkpt_resolver) {
|
||||
g_swig_init_callback = swig_init_callback;
|
||||
g_swig_breakpoint_callback = swig_breakpoint_callback;
|
||||
g_swig_watchpoint_callback = swig_watchpoint_callback;
|
||||
|
@ -3134,6 +3218,8 @@ void ScriptInterpreterPython::InitializeInterpreter(
|
|||
g_swig_plugin_get = swig_plugin_get;
|
||||
g_swig_thread_plan_script = swig_thread_plan_script;
|
||||
g_swig_call_thread_plan = swig_call_thread_plan;
|
||||
g_swig_bkpt_resolver_script = swig_bkpt_resolver_script;
|
||||
g_swig_call_bkpt_resolver = swig_call_bkpt_resolver;
|
||||
}
|
||||
|
||||
void ScriptInterpreterPython::InitializePrivate() {
|
||||
|
|
|
@ -81,6 +81,15 @@ public:
|
|||
const char *method_name,
|
||||
Event *event_sp, bool &got_error);
|
||||
|
||||
typedef void *(*SWIGPythonCreateScriptedBreakpointResolver)(
|
||||
const char *python_class_name, const char *session_dictionary_name,
|
||||
lldb_private::StructuredDataImpl *args_impl,
|
||||
lldb::BreakpointSP &bkpt_sp);
|
||||
|
||||
typedef unsigned int (*SWIGPythonCallBreakpointResolver)(void *implementor,
|
||||
const char *method_name,
|
||||
lldb_private::SymbolContext *sym_ctx);
|
||||
|
||||
typedef void *(*SWIGPythonCreateOSPlugin)(const char *python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::ProcessSP &process_sp);
|
||||
|
@ -208,6 +217,19 @@ public:
|
|||
lldb::StateType
|
||||
ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp,
|
||||
bool &script_error) override;
|
||||
|
||||
StructuredData::GenericSP
|
||||
CreateScriptedBreakpointResolver(const char *class_name,
|
||||
StructuredDataImpl *args_data,
|
||||
lldb::BreakpointSP &bkpt_sp) override;
|
||||
bool
|
||||
ScriptedBreakpointResolverSearchCallback(StructuredData::GenericSP
|
||||
implementor_sp,
|
||||
SymbolContext *sym_ctx) override;
|
||||
|
||||
lldb::SearchDepth
|
||||
ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP
|
||||
implementor_sp) override;
|
||||
|
||||
StructuredData::GenericSP
|
||||
OSPlugin_CreatePluginObject(const char *class_name,
|
||||
|
@ -411,7 +433,9 @@ public:
|
|||
SWIGPythonScriptKeyword_Value swig_run_script_keyword_value,
|
||||
SWIGPython_GetDynamicSetting swig_plugin_get,
|
||||
SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
|
||||
SWIGPythonCallThreadPlan swig_call_thread_plan);
|
||||
SWIGPythonCallThreadPlan swig_call_thread_plan,
|
||||
SWIGPythonCreateScriptedBreakpointResolver swig_bkpt_resolver_script,
|
||||
SWIGPythonCallBreakpointResolver swig_call_breakpoint_resolver);
|
||||
|
||||
const char *GetDictionaryName() { return m_dictionary_name.c_str(); }
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverName.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverScripted.h"
|
||||
#include "lldb/Breakpoint/Watchpoint.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/Event.h"
|
||||
|
@ -28,8 +29,10 @@
|
|||
#include "lldb/Core/ModuleSpec.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/Section.h"
|
||||
#include "lldb/Core/SearchFilter.h"
|
||||
#include "lldb/Core/SourceManager.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/Expression/REPL.h"
|
||||
#include "lldb/Expression/UserExpression.h"
|
||||
|
@ -579,6 +582,48 @@ Target::CreateExceptionBreakpoint(enum lldb::LanguageType language,
|
|||
return exc_bkpt_sp;
|
||||
}
|
||||
|
||||
lldb::BreakpointSP
|
||||
Target::CreateScriptedBreakpoint(const llvm::StringRef class_name,
|
||||
const FileSpecList *containingModules,
|
||||
const FileSpecList *containingSourceFiles,
|
||||
bool internal,
|
||||
bool request_hardware,
|
||||
StructuredData::ObjectSP extra_args_sp,
|
||||
Status *creation_error)
|
||||
{
|
||||
SearchFilterSP filter_sp;
|
||||
|
||||
lldb::SearchDepth depth = lldb::eSearchDepthTarget;
|
||||
bool has_files = containingSourceFiles && containingSourceFiles->GetSize() > 0;
|
||||
bool has_modules = containingModules && containingModules->GetSize() > 0;
|
||||
|
||||
if (has_files && has_modules) {
|
||||
filter_sp = GetSearchFilterForModuleAndCUList(
|
||||
containingModules, containingSourceFiles);
|
||||
} else if (has_files) {
|
||||
filter_sp = GetSearchFilterForModuleAndCUList(
|
||||
nullptr, containingSourceFiles);
|
||||
} else if (has_modules) {
|
||||
filter_sp = GetSearchFilterForModuleList(containingModules);
|
||||
} else {
|
||||
filter_sp.reset(new SearchFilterForUnconstrainedSearches(shared_from_this()));
|
||||
}
|
||||
|
||||
StructuredDataImpl *extra_args_impl = new StructuredDataImpl();
|
||||
if (extra_args_sp)
|
||||
extra_args_impl->SetObjectSP(extra_args_sp);
|
||||
|
||||
BreakpointResolverSP resolver_sp(new
|
||||
BreakpointResolverScripted(nullptr, class_name,
|
||||
depth,
|
||||
extra_args_impl,
|
||||
*GetDebugger().GetCommandInterpreter()
|
||||
.GetScriptInterpreter()));
|
||||
return CreateBreakpoint(filter_sp, resolver_sp, internal, false, true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
BreakpointSP Target::CreateBreakpoint(SearchFilterSP &filter_sp,
|
||||
BreakpointResolverSP &resolver_sp,
|
||||
bool internal, bool request_hardware,
|
||||
|
|
Loading…
Reference in New Issue