forked from OSchip/llvm-project
This is some groundwork for filtering the language Exception
breakpoints, for instance on the class of the thrown object. This change doesn't actually make that work, the part where we extract the thrown object type from the throw site isn't done yet. This provides a general programmatic "precondition" that you can add to breakpoints to give them the ability to do filtering on the LLDB side before we pass the stop on to the user-provided conditions & callbacks. llvm-svn: 235538
This commit is contained in:
parent
787dc438c9
commit
a72b31c79e
|
@ -155,6 +155,23 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class BreakpointPrecondition
|
||||
{
|
||||
public:
|
||||
virtual ~BreakpointPrecondition() {}
|
||||
|
||||
virtual bool
|
||||
EvaluatePrecondition(StoppointCallbackContext &context);
|
||||
|
||||
virtual Error
|
||||
ConfigurePrecondition(Args &options);
|
||||
|
||||
virtual void
|
||||
DescribePrecondition(Stream &stream, lldb::DescriptionLevel level);
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<BreakpointPrecondition> BreakpointPreconditionSP;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Destructor.
|
||||
///
|
||||
|
@ -665,6 +682,31 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Set a pre-condition filter that overrides all user provided filters/callbacks etc.
|
||||
///
|
||||
/// Used to define fancy breakpoints that can do dynamic hit detection without taking up the condition slot -
|
||||
/// which really belongs to the user anyway...
|
||||
///
|
||||
/// The Precondition should not continue the target, it should return true if the condition says to stop and
|
||||
/// false otherwise.
|
||||
///
|
||||
//------------------------------------------------------------------
|
||||
void
|
||||
SetPrecondition(BreakpointPreconditionSP precondition_sp)
|
||||
{
|
||||
m_precondition_sp = precondition_sp;
|
||||
}
|
||||
|
||||
bool
|
||||
EvaluatePrecondition (StoppointCallbackContext &context);
|
||||
|
||||
BreakpointPreconditionSP
|
||||
GetPrecondition()
|
||||
{
|
||||
return m_precondition_sp;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class Target;
|
||||
//------------------------------------------------------------------
|
||||
|
@ -737,13 +779,17 @@ private:
|
|||
// For Breakpoint only
|
||||
//------------------------------------------------------------------
|
||||
bool m_being_created;
|
||||
bool m_hardware; // If this breakpoint is required to use a hardware breakpoint
|
||||
Target &m_target; // The target that holds this breakpoint.
|
||||
bool m_hardware; // If this breakpoint is required to use a hardware breakpoint
|
||||
Target &m_target; // The target that holds this breakpoint.
|
||||
std::unordered_set<std::string> m_name_list; // If not empty, this is the name of this breakpoint (many breakpoints can share the same name.)
|
||||
lldb::SearchFilterSP m_filter_sp; // The filter that constrains the breakpoint's domain.
|
||||
lldb::BreakpointResolverSP m_resolver_sp; // The resolver that defines this breakpoint.
|
||||
BreakpointOptions m_options; // Settable breakpoint options
|
||||
BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint.
|
||||
lldb::SearchFilterSP m_filter_sp; // The filter that constrains the breakpoint's domain.
|
||||
lldb::BreakpointResolverSP m_resolver_sp; // The resolver that defines this breakpoint.
|
||||
BreakpointPreconditionSP m_precondition_sp; // The precondition is a breakpoint-level hit filter that can be used
|
||||
// to skip certain breakpoint hits. For instance, exception breakpoints
|
||||
// use this to limit the stop to certain exception classes, while leaving
|
||||
// the condition & callback free for user specification.
|
||||
BreakpointOptions m_options; // Settable breakpoint options
|
||||
BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint.
|
||||
std::string m_kind_description;
|
||||
bool m_resolve_indirect_symbols;
|
||||
uint32_t m_hit_count; // Number of times this breakpoint/watchpoint has been hit. This is kept
|
||||
|
|
|
@ -89,6 +89,9 @@ public:
|
|||
// callback.
|
||||
// Asynchronous callbacks get run as part of the "ShouldStop" logic in the thread plan. The logic there is:
|
||||
// a) If the breakpoint is thread specific and not for this thread, continue w/o running the callback.
|
||||
// NB. This is actually enforced underneath the breakpoint system, the Process plugin is expected to
|
||||
// call BreakpointSite::IsValidForThread, and set the thread's StopInfo to "no reason". That way,
|
||||
// thread displays won't show stops for breakpoints not for that thread...
|
||||
// b) If the ignore count says we shouldn't stop, then ditto.
|
||||
// c) If the condition says we shouldn't stop, then ditto.
|
||||
// d) Otherwise, the callback will get run, and if it returns true we will stop, and if false we won't.
|
||||
|
|
|
@ -80,11 +80,16 @@ public:
|
|||
|
||||
static lldb::BreakpointSP
|
||||
CreateExceptionBreakpoint (Target &target,
|
||||
lldb::LanguageType language,
|
||||
lldb::LanguageType language,
|
||||
bool catch_bp,
|
||||
bool throw_bp,
|
||||
bool is_internal = false);
|
||||
|
||||
|
||||
static Breakpoint::BreakpointPreconditionSP
|
||||
CreateExceptionPrecondition (lldb::LanguageType language,
|
||||
bool catch_bp,
|
||||
bool throw_bp);
|
||||
|
||||
static lldb::LanguageType
|
||||
GetLanguageTypeFromString (const char *string);
|
||||
|
||||
|
|
|
@ -289,6 +289,24 @@ public:
|
|||
protected:
|
||||
std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap;
|
||||
};
|
||||
|
||||
class ObjCExceptionPrecondition : public Breakpoint::BreakpointPrecondition
|
||||
{
|
||||
public:
|
||||
ObjCExceptionPrecondition();
|
||||
|
||||
virtual ~ObjCExceptionPrecondition() {}
|
||||
|
||||
bool EvaluatePrecondition(StoppointCallbackContext &context) override;
|
||||
void DescribePrecondition(Stream &stream, lldb::DescriptionLevel level) override;
|
||||
Error ConfigurePrecondition(Args &args) override;
|
||||
|
||||
protected:
|
||||
void AddClassName(const char *class_name);
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> m_class_names;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
|
||||
|
||||
|
|
|
@ -741,7 +741,12 @@ public:
|
|||
bool request_hardware);
|
||||
|
||||
lldb::BreakpointSP
|
||||
CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal);
|
||||
CreateExceptionBreakpoint (enum lldb::LanguageType language,
|
||||
bool catch_bp,
|
||||
bool throw_bp,
|
||||
bool internal,
|
||||
Args *additional_args = nullptr,
|
||||
Error *additional_args_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
|
||||
|
|
|
@ -521,6 +521,7 @@ namespace lldb {
|
|||
eArgTypeThreadID,
|
||||
eArgTypeThreadIndex,
|
||||
eArgTypeThreadName,
|
||||
eArgTypeTypeName,
|
||||
eArgTypeUnsignedInteger,
|
||||
eArgTypeUnixSignal,
|
||||
eArgTypeVarName,
|
||||
|
|
|
@ -949,6 +949,34 @@ Breakpoint::GetFilterDescription (Stream *s)
|
|||
m_filter_sp->GetDescription (s);
|
||||
}
|
||||
|
||||
bool
|
||||
Breakpoint::EvaluatePrecondition (StoppointCallbackContext &context)
|
||||
{
|
||||
if (!m_precondition_sp)
|
||||
return true;
|
||||
|
||||
return m_precondition_sp->EvaluatePrecondition(context);
|
||||
}
|
||||
|
||||
bool
|
||||
Breakpoint::BreakpointPrecondition::EvaluatePrecondition(StoppointCallbackContext &context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Breakpoint::BreakpointPrecondition::DescribePrecondition(Stream &stream, lldb::DescriptionLevel level)
|
||||
{
|
||||
}
|
||||
|
||||
Error
|
||||
Breakpoint::BreakpointPrecondition::ConfigurePrecondition(Args &options)
|
||||
{
|
||||
Error error;
|
||||
error.SetErrorString("Base breakpoint precondition has no options.");
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
Breakpoint::SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind)
|
||||
{
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
m_catch_bp (false),
|
||||
m_throw_bp (true),
|
||||
m_hardware (false),
|
||||
m_language (eLanguageTypeUnknown),
|
||||
m_exception_language (eLanguageTypeUnknown),
|
||||
m_skip_prologue (eLazyBoolCalculate),
|
||||
m_one_shot (false),
|
||||
m_all_files (false)
|
||||
|
@ -173,16 +173,16 @@ public:
|
|||
case eLanguageTypeC:
|
||||
case eLanguageTypeC99:
|
||||
case eLanguageTypeC11:
|
||||
m_language = eLanguageTypeC;
|
||||
m_exception_language = eLanguageTypeC;
|
||||
break;
|
||||
case eLanguageTypeC_plus_plus:
|
||||
case eLanguageTypeC_plus_plus_03:
|
||||
case eLanguageTypeC_plus_plus_11:
|
||||
case eLanguageTypeC_plus_plus_14:
|
||||
m_language = eLanguageTypeC_plus_plus;
|
||||
m_exception_language = eLanguageTypeC_plus_plus;
|
||||
break;
|
||||
case eLanguageTypeObjC:
|
||||
m_language = eLanguageTypeObjC;
|
||||
m_exception_language = eLanguageTypeObjC;
|
||||
break;
|
||||
case eLanguageTypeObjC_plus_plus:
|
||||
error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c");
|
||||
|
@ -268,6 +268,11 @@ public:
|
|||
m_one_shot = true;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
m_exception_extra_args.AppendArgument ("-O");
|
||||
m_exception_extra_args.AppendArgument (option_arg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
m_source_text_regexp.assign (option_arg);
|
||||
break;
|
||||
|
@ -349,12 +354,13 @@ public:
|
|||
m_catch_bp = false;
|
||||
m_throw_bp = true;
|
||||
m_hardware = false;
|
||||
m_language = eLanguageTypeUnknown;
|
||||
m_exception_language = eLanguageTypeUnknown;
|
||||
m_skip_prologue = eLazyBoolCalculate;
|
||||
m_one_shot = false;
|
||||
m_use_dummy = false;
|
||||
m_breakpoint_names.clear();
|
||||
m_all_files = false;
|
||||
m_exception_extra_args.Clear();
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
|
@ -388,11 +394,12 @@ public:
|
|||
bool m_catch_bp;
|
||||
bool m_throw_bp;
|
||||
bool m_hardware; // Request to use hardware breakpoints
|
||||
lldb::LanguageType m_language;
|
||||
lldb::LanguageType m_exception_language;
|
||||
LazyBool m_skip_prologue;
|
||||
bool m_one_shot;
|
||||
bool m_use_dummy;
|
||||
bool m_all_files;
|
||||
Args m_exception_extra_args;
|
||||
|
||||
};
|
||||
|
||||
|
@ -430,7 +437,7 @@ protected:
|
|||
break_type = eSetTypeFunctionRegexp;
|
||||
else if (!m_options.m_source_text_regexp.empty())
|
||||
break_type = eSetTypeSourceRegexp;
|
||||
else if (m_options.m_language != eLanguageTypeUnknown)
|
||||
else if (m_options.m_exception_language != eLanguageTypeUnknown)
|
||||
break_type = eSetTypeException;
|
||||
|
||||
Breakpoint *bp = NULL;
|
||||
|
@ -556,10 +563,21 @@ protected:
|
|||
break;
|
||||
case eSetTypeException:
|
||||
{
|
||||
bp = target->CreateExceptionBreakpoint (m_options.m_language,
|
||||
Error precond_error;
|
||||
bp = target->CreateExceptionBreakpoint (m_options.m_exception_language,
|
||||
m_options.m_catch_bp,
|
||||
m_options.m_throw_bp,
|
||||
internal).get();
|
||||
internal,
|
||||
&m_options.m_exception_extra_args,
|
||||
&precond_error).get();
|
||||
if (precond_error.Fail())
|
||||
{
|
||||
result.AppendErrorWithFormat("Error setting extra exception arguments: %s",
|
||||
precond_error.AsCString());
|
||||
target->RemoveBreakpointByID(bp->GetID());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -758,6 +776,10 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
|
|||
{ LLDB_OPT_SET_10, false, "on-catch", 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
|
||||
"Set the breakpoint on exception catcH." },
|
||||
|
||||
// Don't add this option till it actually does something useful...
|
||||
// { LLDB_OPT_SET_10, false, "exception-typename", 'O', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeTypeName,
|
||||
// "The breakpoint will only stop if an exception Object of this type is thrown. Can be repeated multiple times to stop for multiple object types" },
|
||||
|
||||
{ LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
|
||||
"sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used." },
|
||||
|
||||
|
|
|
@ -1193,6 +1193,7 @@ CommandObject::g_arguments_data[] =
|
|||
{ eArgTypeThreadID, "thread-id", CommandCompletions::eNoCompletion, { nullptr, false }, "Thread ID number." },
|
||||
{ eArgTypeThreadIndex, "thread-index", CommandCompletions::eNoCompletion, { nullptr, false }, "Index into the process' list of threads." },
|
||||
{ eArgTypeThreadName, "thread-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The thread's name." },
|
||||
{ eArgTypeTypeName, "type-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A type name." },
|
||||
{ eArgTypeUnsignedInteger, "unsigned-integer", CommandCompletions::eNoCompletion, { nullptr, false }, "An unsigned integer." },
|
||||
{ eArgTypeUnixSignal, "unix-signal", CommandCompletions::eNoCompletion, { nullptr, false }, "A valid Unix signal name or number (e.g. SIGKILL, KILL or 9)." },
|
||||
{ eArgTypeVarName, "variable-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a variable in your program." },
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lldb/Target/LanguageRuntime.h"
|
||||
#include "lldb/Target/ObjCLanguageRuntime.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/SearchFilter.h"
|
||||
|
@ -277,6 +278,23 @@ LanguageRuntime::~LanguageRuntime()
|
|||
{
|
||||
}
|
||||
|
||||
Breakpoint::BreakpointPreconditionSP
|
||||
LanguageRuntime::CreateExceptionPrecondition (lldb::LanguageType language,
|
||||
bool catch_bp,
|
||||
bool throw_bp)
|
||||
{
|
||||
switch (language)
|
||||
{
|
||||
case eLanguageTypeObjC:
|
||||
if (throw_bp)
|
||||
return Breakpoint::BreakpointPreconditionSP(new ObjCLanguageRuntime::ObjCExceptionPrecondition ());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Breakpoint::BreakpointPreconditionSP();
|
||||
}
|
||||
|
||||
BreakpointSP
|
||||
LanguageRuntime::CreateExceptionBreakpoint (Target &target,
|
||||
lldb::LanguageType language,
|
||||
|
@ -289,8 +307,15 @@ LanguageRuntime::CreateExceptionBreakpoint (Target &target,
|
|||
bool hardware = false;
|
||||
bool resolve_indirect_functions = false;
|
||||
BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions));
|
||||
if (is_internal)
|
||||
exc_breakpt_sp->SetBreakpointKind("exception");
|
||||
if (exc_breakpt_sp)
|
||||
{
|
||||
Breakpoint::BreakpointPreconditionSP precondition_sp = CreateExceptionPrecondition(language, catch_bp, throw_bp);
|
||||
if (precondition_sp)
|
||||
exc_breakpt_sp->SetPrecondition(precondition_sp);
|
||||
|
||||
if (is_internal)
|
||||
exc_breakpt_sp->SetBreakpointKind("exception");
|
||||
}
|
||||
|
||||
return exc_breakpt_sp;
|
||||
}
|
||||
|
|
|
@ -670,3 +670,36 @@ ObjCLanguageRuntime::GetTypeBitSize (const ClangASTType& clang_type,
|
|||
|
||||
return found;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Exception breakpoint Precondition class for ObjC:
|
||||
//------------------------------------------------------------------
|
||||
void
|
||||
ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(const char *class_name)
|
||||
{
|
||||
m_class_names.insert(class_name);
|
||||
}
|
||||
|
||||
ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(StoppointCallbackContext &context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ObjCLanguageRuntime::ObjCExceptionPrecondition::DescribePrecondition(Stream &stream, lldb::DescriptionLevel level)
|
||||
{
|
||||
}
|
||||
|
||||
Error
|
||||
ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(Args &args)
|
||||
{
|
||||
Error error;
|
||||
if (args.GetArgumentCount() > 0)
|
||||
error.SetErrorString("The ObjC Exception breakpoint doesn't support extra options.");
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -523,11 +523,23 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules,
|
|||
}
|
||||
|
||||
lldb::BreakpointSP
|
||||
Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal)
|
||||
Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal, Args *additional_args, Error *error)
|
||||
{
|
||||
return LanguageRuntime::CreateExceptionBreakpoint (*this, language, catch_bp, throw_bp, internal);
|
||||
BreakpointSP exc_bkpt_sp = LanguageRuntime::CreateExceptionBreakpoint (*this, language, catch_bp, throw_bp, internal);
|
||||
if (exc_bkpt_sp && additional_args)
|
||||
{
|
||||
Breakpoint::BreakpointPreconditionSP precondition_sp = exc_bkpt_sp->GetPrecondition();
|
||||
if (precondition_sp && additional_args)
|
||||
{
|
||||
if (error)
|
||||
*error = precondition_sp->ConfigurePrecondition(*additional_args);
|
||||
else
|
||||
precondition_sp->ConfigurePrecondition(*additional_args);
|
||||
}
|
||||
}
|
||||
return exc_bkpt_sp;
|
||||
}
|
||||
|
||||
|
||||
BreakpointSP
|
||||
Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware, bool resolve_indirect_symbols)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue