-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcriteria.py
98 lines (86 loc) · 3.54 KB
/
criteria.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
try:
import __builtin__
except ImportError:
import builtins
__builtin__ = builtins
import re
from itertools import islice
# These functions are for adding breakpoint criteria. They are useful for
# constraining when a breakpoint stops, for example only stopping when called
# by this function or from that library.
#
# These helper functions make use of a subtle behavior of breakpoint commands.
# A breakpoint function that returns False tells lldb to continue running the
# process. Think of False as "No, don't stop".
#
# These functions were inspired by:
# https://sourceware.org/gdb/current/onlinedocs/gdb/Convenience-Funs.html
def break_criteria(predicate):
def decorator(*args):
def breakpoint_command(frame, location, _):
return predicate(frame, *args)
return breakpoint_command
setattr(__builtin__, predicate.__name__, decorator)
return decorator
# breakpoint command add -F 'caller_is("theCaller")'
# breakpoint command add -F 'not caller_is("theCaller")'
@break_criteria
def caller_is(frame, symbol):
return frame.parent.name == symbol
# breakpoint command add -F 'any_caller_is("someCaller")'
# breakpoint command add -F 'not any_caller_is("someCaller")'
@break_criteria
def any_caller_is(frame, symbol):
callers = islice(frame.thread, 1, None) # skip current frame
return any(f.name == symbol for f in callers)
# breakpoint command add -F 'caller_contains("theCaller")'
# breakpoint command add -F 'not caller_contains("theCaller")'
@break_criteria
def caller_contains(frame, substring):
return substring in frame.parent.name
# breakpoint command add -F 'any_caller_contains("someCaller")'
# breakpoint command add -F 'not any_caller_contains("someCaller")'
@break_criteria
def any_caller_contains(frame, substring):
callers = islice(frame.thread, 1, None) # skip current frame
return any(substring in f.name for f in callers)
_CACHED_REGEX = {}
def _get_regex(pattern):
global _CACHED_REGEX
regex = _CACHED_REGEX.get(pattern)
if not regex:
regex = re.compile(pattern)
_CACHED_REGEX[pattern] = regex
return regex
# breakpoint command add -F 'caller_matches("thisCaller|thatCaller")'
# breakpoint command add -F 'not caller_matches("thisCaller|thatCaller")'
@break_criteria
def caller_matches(frame, pattern):
regex = _get_regex(pattern)
return regex.search(frame.parent.name) is not None
# breakpoint command add -F 'any_caller_matches("oneCaller|anotherCaller")'
# breakpoint command add -F 'not any_caller_matches("oneCaller|anotherCaller")'
@break_criteria
def any_caller_matches(frame, pattern):
regex = _get_regex(pattern)
callers = islice(frame.thread, 1, None) # skip current frame
return any(regex.search(f.name) for f in callers)
# breakpoint command add -F 'caller_from("FrameworkKit")'
# breakpoint command add -F 'not caller_from("libThat")'
@break_criteria
def caller_from(frame, module):
return frame.parent.module.file.basename == module
# breakpoint command add -F 'any_caller_from("FrameworkKit")'
# breakpoint command add -F 'not any_caller_from("libThat")'
@break_criteria
def any_caller_from(frame, module):
callers = islice(frame.thread, 1, None) # skip current frame
return any(f.module.file.basename == module for f in callers)
# breakpoint command add -F 'not called_on(1)'
# breakpoint command add -F 'called_on("namedThread")'
@break_criteria
def called_on(frame, thread_id):
if isinstance(thread_id, int):
return thread_id == frame.thread.idx
else:
return thread_id in (frame.thread.name, frame.thread.queue)