forked from DerekSelander/LLDB
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbreakifonfunc.py
101 lines (81 loc) · 3.35 KB
/
breakifonfunc.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
99
100
101
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import lldb
import re
import optparse
import ds
import shlex
class GlobalOptions(object):
symbols = {}
@staticmethod
def addSymbols(symbols, options, breakpoint):
key = str(breakpoint.GetID())
GlobalOptions.symbols[key] = (symbols, options)
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand(
'command script add -f breakifonfunc.breakifonfunc biof')
def breakifonfunc(debugger, command, exe_ctx, result, internal_dict):
'''
usage: biof [ModuleName] regex1 ||| [ModuleName2] regex2
Regex breakpoint that stops only if the second regex breakpoint is in the stack trace
For example, to only stop if code in the Test module resulted the setTintColor: being called
biof setTintColor: ||| . Test
'''
command_args = shlex.split(command, posix=False)
parser = generateOptionParser()
try:
(options, args) = parser.parse_args(command_args)
except e:
result.SetError(e)
return
# if len(args) >= 2:
# result.SetError(parser.usage)
# return
target = exe_ctx.target
# if len(command.split('|||')) != 2:
# result.SetError(parser.usage)
t = " ".join(args).split('|||')
clean_command = t[0].strip().split()
if len(clean_command) == 2:
breakpoint = target.BreakpointCreateByRegex(clean_command[0], clean_command[1])
else:
breakpoint = target.BreakpointCreateByRegex(clean_command[0], None)
moduleName = t[1].strip().split()[1]
module = target.module[moduleName]
if not module:
result.SetError('Invalid module {}'.format(moduleName))
return
searchQuery = t[1].strip().split()[0]
s = [i for i in module.symbols if re.search(searchQuery, i.name)]
GlobalOptions.addSymbols(s, options, breakpoint)
breakpoint.SetScriptCallbackFunction("breakifonfunc.breakpointHandler")
if not breakpoint.IsValid() or breakpoint.num_locations == 0:
result.AppendWarning("Breakpoint isn't valid or hasn't found any hits: " + clean_command[0])
else:
result.AppendMessage("\"{}\" produced {} hits\nOnly will stop if the following stack frame symbols contain:\n{}` \"{}\" produced {} hits".format(
clean_command[0], breakpoint.num_locations, module.file.basename, searchQuery, len(s)) )
def breakpointHandler(frame, bp_loc, dict):
if len(GlobalOptions.symbols) == 0:
print("womp something internal called reload LLDB init which removed the global symbols")
return True
key = str(bp_loc.GetBreakpoint().GetID())
searchSymbols = GlobalOptions.symbols[key][0]
options = GlobalOptions.symbols[key][1]
function_name = frame.GetFunctionName()
thread = frame.thread
if options.direct_call:
frame = thread.frame[1]
print(frame)
symbol = frame.symbol
return any([symbol in searchSymbols])
s = [i.symbol for i in thread.frames]
return any(x in s for x in searchSymbols)
def generateOptionParser():
usage = breakifonfunc.__doc__
parser = optparse.OptionParser(usage=usage, prog="biof")
parser.add_option("-d", "--direct",
action="store_true",
default=False,
dest="direct_call",
help="Only stop if the second regex directly calls the breakpoint")
return parser