[lldb] Format Python files in scripts and utils (#66053)
Using: black --exclude "third_party/" ./lldb/
This commit is contained in:
parent
a1ef5a9437
commit
602e47c5f9
@ -10,12 +10,21 @@ from collections import defaultdict
|
||||
from use_lldb_suite import lldb_root
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Analyze LLDB project #include dependencies.')
|
||||
parser.add_argument('--show-counts', default=False, action='store_true',
|
||||
help='When true, show the number of dependencies from each subproject')
|
||||
parser.add_argument('--discover-cycles', default=False, action='store_true',
|
||||
help='When true, find and display all project dependency cycles. Note,'
|
||||
'this option is very slow')
|
||||
description="Analyze LLDB project #include dependencies."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--show-counts",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="When true, show the number of dependencies from each subproject",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--discover-cycles",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="When true, find and display all project dependency cycles. Note,"
|
||||
"this option is very slow",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -24,12 +33,14 @@ inc_dir = os.path.join(lldb_root, "include")
|
||||
|
||||
src_map = {}
|
||||
|
||||
include_regex = re.compile('#include \"((lldb|Plugins|clang)(.*/)+).*\"')
|
||||
include_regex = re.compile('#include "((lldb|Plugins|clang)(.*/)+).*"')
|
||||
|
||||
|
||||
def is_sublist(small, big):
|
||||
it = iter(big)
|
||||
return all(c in it for c in small)
|
||||
|
||||
|
||||
def normalize_host(str):
|
||||
if str.startswith("lldb/Host"):
|
||||
return "lldb/Host"
|
||||
@ -39,6 +50,7 @@ def normalize_host(str):
|
||||
return str.replace("lldb/../../source", "lldb")
|
||||
return str
|
||||
|
||||
|
||||
def scan_deps(this_dir, file):
|
||||
global src_map
|
||||
deps = {}
|
||||
@ -62,7 +74,8 @@ def scan_deps(this_dir, file):
|
||||
if this_dir not in src_map and len(deps) > 0:
|
||||
src_map[this_dir] = deps
|
||||
|
||||
for (base, dirs, files) in os.walk(inc_dir):
|
||||
|
||||
for base, dirs, files in os.walk(inc_dir):
|
||||
dir = os.path.basename(base)
|
||||
relative = os.path.relpath(base, inc_dir)
|
||||
inc_files = [x for x in files if os.path.splitext(x)[1] in [".h"]]
|
||||
@ -71,7 +84,7 @@ for (base, dirs, files) in os.walk(inc_dir):
|
||||
inc_path = os.path.join(base, inc)
|
||||
scan_deps(relative, inc_path)
|
||||
|
||||
for (base, dirs, files) in os.walk(src_dir):
|
||||
for base, dirs, files in os.walk(src_dir):
|
||||
dir = os.path.basename(base)
|
||||
relative = os.path.relpath(base, src_dir)
|
||||
src_files = [x for x in files if os.path.splitext(x)[1] in [".cpp", ".h", ".mm"]]
|
||||
@ -82,6 +95,7 @@ for (base, dirs, files) in os.walk(src_dir):
|
||||
scan_deps(norm_base_path, src_path)
|
||||
pass
|
||||
|
||||
|
||||
def is_existing_cycle(path, cycles):
|
||||
# If we have a cycle like # A -> B -> C (with an implicit -> A at the end)
|
||||
# then we don't just want to check for an occurrence of A -> B -> C in the
|
||||
@ -90,12 +104,13 @@ def is_existing_cycle(path, cycles):
|
||||
# at the end), then A -> B -> C is also a cycle. This is an important
|
||||
# optimization which reduces the search space by multiple orders of
|
||||
# magnitude.
|
||||
for i in range(0,len(path)):
|
||||
for i in range(0, len(path)):
|
||||
if any(is_sublist(x, path) for x in cycles):
|
||||
return True
|
||||
path = [path[-1]] + path[0:-1]
|
||||
return False
|
||||
|
||||
|
||||
def expand(path_queue, path_lengths, cycles, src_map):
|
||||
# We do a breadth first search, to make sure we visit all paths in order
|
||||
# of ascending length. This is an important optimization to make sure that
|
||||
@ -127,54 +142,57 @@ def expand(path_queue, path_lengths, cycles, src_map):
|
||||
path_queue.append(cur_path + [item])
|
||||
pass
|
||||
|
||||
|
||||
cycles = []
|
||||
|
||||
path_queue = [[x] for x in iter(src_map)]
|
||||
path_lens = [1] * len(path_queue)
|
||||
|
||||
items = list(src_map.items())
|
||||
items.sort(key = lambda A : A[0])
|
||||
items.sort(key=lambda A: A[0])
|
||||
|
||||
for (path, deps) in items:
|
||||
for path, deps in items:
|
||||
print(path + ":")
|
||||
sorted_deps = list(deps.items())
|
||||
if args.show_counts:
|
||||
sorted_deps.sort(key = lambda A: (A[1], A[0]))
|
||||
sorted_deps.sort(key=lambda A: (A[1], A[0]))
|
||||
for dep in sorted_deps:
|
||||
print("\t{} [{}]".format(dep[0], dep[1]))
|
||||
else:
|
||||
sorted_deps.sort(key = lambda A: A[0])
|
||||
sorted_deps.sort(key=lambda A: A[0])
|
||||
for dep in sorted_deps:
|
||||
print("\t{}".format(dep[0]))
|
||||
|
||||
|
||||
def iter_cycles(cycles):
|
||||
global src_map
|
||||
for cycle in cycles:
|
||||
cycle.append(cycle[0])
|
||||
zipper = list(zip(cycle[0:-1], cycle[1:]))
|
||||
result = [(x, src_map[x][y], y) for (x,y) in zipper]
|
||||
result = [(x, src_map[x][y], y) for (x, y) in zipper]
|
||||
total = 0
|
||||
smallest = result[0][1]
|
||||
for (first, value, last) in result:
|
||||
for first, value, last in result:
|
||||
total += value
|
||||
smallest = min(smallest, value)
|
||||
yield (total, smallest, result)
|
||||
|
||||
|
||||
if args.discover_cycles:
|
||||
print("Analyzing cycles...")
|
||||
|
||||
expand(path_queue, path_lens, cycles, src_map)
|
||||
|
||||
average = sum([len(x)+1 for x in cycles]) / len(cycles)
|
||||
average = sum([len(x) + 1 for x in cycles]) / len(cycles)
|
||||
|
||||
print("Found {} cycles. Average cycle length = {}.".format(len(cycles), average))
|
||||
counted = list(iter_cycles(cycles))
|
||||
if args.show_counts:
|
||||
counted.sort(key = lambda A: A[0])
|
||||
for (total, smallest, cycle) in counted:
|
||||
counted.sort(key=lambda A: A[0])
|
||||
for total, smallest, cycle in counted:
|
||||
sys.stdout.write("{} deps to break: ".format(total))
|
||||
sys.stdout.write(cycle[0][0])
|
||||
for (first, count, last) in cycle:
|
||||
for first, count, last in cycle:
|
||||
sys.stdout.write(" [{}->] {}".format(count, last))
|
||||
sys.stdout.write("\n")
|
||||
else:
|
||||
@ -186,8 +204,8 @@ if args.discover_cycles:
|
||||
islands = []
|
||||
outgoing_counts = defaultdict(int)
|
||||
incoming_counts = defaultdict(int)
|
||||
for (total, smallest, cycle) in counted:
|
||||
for (first, count, last) in cycle:
|
||||
for total, smallest, cycle in counted:
|
||||
for first, count, last in cycle:
|
||||
outgoing_counts[first] += count
|
||||
incoming_counts[last] += count
|
||||
for cycle in cycles:
|
||||
@ -201,8 +219,8 @@ if args.discover_cycles:
|
||||
sorted = []
|
||||
for node in island:
|
||||
sorted.append((node, incoming_counts[node], outgoing_counts[node]))
|
||||
sorted.sort(key = lambda x: x[1]+x[2])
|
||||
for (node, inc, outg) in sorted:
|
||||
sorted.sort(key=lambda x: x[1] + x[2])
|
||||
for node, inc, outg in sorted:
|
||||
print(" {} [{} in, {} out]".format(node, inc, outg))
|
||||
sys.stdout.flush()
|
||||
pass
|
||||
|
@ -20,45 +20,59 @@ def host_art_bt(debugger, command, result, internal_dict):
|
||||
thread = process.GetSelectedThread()
|
||||
while lldb_frame_index < thread.GetNumFrames():
|
||||
frame = thread.GetFrameAtIndex(lldb_frame_index)
|
||||
if frame.GetModule() and re.match(r'JIT\(.*?\)',
|
||||
frame.GetModule().GetFileSpec().GetFilename()):
|
||||
if frame.GetModule() and re.match(
|
||||
r"JIT\(.*?\)", frame.GetModule().GetFileSpec().GetFilename()
|
||||
):
|
||||
# Compiled Java frame
|
||||
|
||||
# Get function/filename/lineno from symbol context
|
||||
symbol = frame.GetSymbol()
|
||||
if not symbol:
|
||||
print('No symbol info for compiled Java frame: ', frame)
|
||||
print("No symbol info for compiled Java frame: ", frame)
|
||||
sys.exit(1)
|
||||
line_entry = frame.GetLineEntry()
|
||||
prettified_frames.append({
|
||||
'function': symbol.GetName(),
|
||||
'file': str(line_entry.GetFileSpec()) if line_entry else None,
|
||||
'line': line_entry.GetLine() if line_entry else -1
|
||||
})
|
||||
prettified_frames.append(
|
||||
{
|
||||
"function": symbol.GetName(),
|
||||
"file": str(line_entry.GetFileSpec()) if line_entry else None,
|
||||
"line": line_entry.GetLine() if line_entry else -1,
|
||||
}
|
||||
)
|
||||
|
||||
# Skip art frames
|
||||
while True:
|
||||
art_stack_visitor = frame.EvaluateExpression(
|
||||
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" +
|
||||
str(art_frame_index) +
|
||||
"""); visitor.WalkStack(true); visitor""")
|
||||
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor("""
|
||||
+ str(art_frame_index)
|
||||
+ """); visitor.WalkStack(true); visitor"""
|
||||
)
|
||||
art_method = frame.EvaluateExpression(
|
||||
art_stack_visitor.GetName() + """.GetMethod()""")
|
||||
art_stack_visitor.GetName() + """.GetMethod()"""
|
||||
)
|
||||
if art_method.GetValueAsUnsigned() != 0:
|
||||
art_method_name = frame.EvaluateExpression(
|
||||
"""art::PrettyMethod(""" + art_method.GetName() + """, true)""")
|
||||
"""art::PrettyMethod(""" + art_method.GetName() + """, true)"""
|
||||
)
|
||||
art_method_name_data = frame.EvaluateExpression(
|
||||
art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned()
|
||||
art_method_name.GetName() + """.c_str()"""
|
||||
).GetValueAsUnsigned()
|
||||
art_method_name_size = frame.EvaluateExpression(
|
||||
art_method_name.GetName() + """.length()""").GetValueAsUnsigned()
|
||||
art_method_name.GetName() + """.length()"""
|
||||
).GetValueAsUnsigned()
|
||||
error = lldb.SBError()
|
||||
art_method_name = process.ReadCStringFromMemory(
|
||||
art_method_name_data, art_method_name_size + 1, error)
|
||||
art_method_name_data, art_method_name_size + 1, error
|
||||
)
|
||||
if not error.Success:
|
||||
print('Failed to read method name')
|
||||
print("Failed to read method name")
|
||||
sys.exit(1)
|
||||
if art_method_name != symbol.GetName():
|
||||
print('Function names in native symbol and art runtime stack do not match: ', symbol.GetName(), ' != ', art_method_name)
|
||||
print(
|
||||
"Function names in native symbol and art runtime stack do not match: ",
|
||||
symbol.GetName(),
|
||||
" != ",
|
||||
art_method_name,
|
||||
)
|
||||
art_frame_index = art_frame_index + 1
|
||||
break
|
||||
art_frame_index = art_frame_index + 1
|
||||
@ -68,53 +82,69 @@ def host_art_bt(debugger, command, result, internal_dict):
|
||||
if lldb_frame_index < thread.GetNumFrames():
|
||||
frame = thread.GetFrameAtIndex(lldb_frame_index)
|
||||
if frame.GetModule() and re.match(
|
||||
r'JIT\(.*?\)', frame.GetModule().GetFileSpec().GetFilename()):
|
||||
r"JIT\(.*?\)", frame.GetModule().GetFileSpec().GetFilename()
|
||||
):
|
||||
# Another compile Java frame
|
||||
# Don't skip; leave it to the next iteration
|
||||
continue
|
||||
elif frame.GetSymbol() and (frame.GetSymbol().GetName() == 'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'):
|
||||
elif frame.GetSymbol() and (
|
||||
frame.GetSymbol().GetName() == "art_quick_invoke_stub"
|
||||
or frame.GetSymbol().GetName() == "art_quick_invoke_static_stub"
|
||||
):
|
||||
# art_quick_invoke_stub / art_quick_invoke_static_stub
|
||||
# Skip until we get past the next ArtMethod::Invoke()
|
||||
while True:
|
||||
lldb_frame_index = lldb_frame_index + 1
|
||||
if lldb_frame_index >= thread.GetNumFrames():
|
||||
print('ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub')
|
||||
print(
|
||||
"ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub"
|
||||
)
|
||||
sys.exit(1)
|
||||
frame = thread.GetFrameAtIndex(lldb_frame_index)
|
||||
if frame.GetSymbol() and frame.GetSymbol().GetName(
|
||||
) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)':
|
||||
if (
|
||||
frame.GetSymbol()
|
||||
and frame.GetSymbol().GetName()
|
||||
== "art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)"
|
||||
):
|
||||
lldb_frame_index = lldb_frame_index + 1
|
||||
break
|
||||
else:
|
||||
print('Invalid frame below compiled Java frame: ', frame)
|
||||
elif frame.GetSymbol() and frame.GetSymbol().GetName() == 'art_quick_generic_jni_trampoline':
|
||||
print("Invalid frame below compiled Java frame: ", frame)
|
||||
elif (
|
||||
frame.GetSymbol()
|
||||
and frame.GetSymbol().GetName() == "art_quick_generic_jni_trampoline"
|
||||
):
|
||||
# Interpreted JNI frame for x86_64
|
||||
|
||||
# Skip art frames
|
||||
while True:
|
||||
art_stack_visitor = frame.EvaluateExpression(
|
||||
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" +
|
||||
str(art_frame_index) +
|
||||
"""); visitor.WalkStack(true); visitor""")
|
||||
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor("""
|
||||
+ str(art_frame_index)
|
||||
+ """); visitor.WalkStack(true); visitor"""
|
||||
)
|
||||
art_method = frame.EvaluateExpression(
|
||||
art_stack_visitor.GetName() + """.GetMethod()""")
|
||||
art_stack_visitor.GetName() + """.GetMethod()"""
|
||||
)
|
||||
if art_method.GetValueAsUnsigned() != 0:
|
||||
# Get function/filename/lineno from ART runtime
|
||||
art_method_name = frame.EvaluateExpression(
|
||||
"""art::PrettyMethod(""" + art_method.GetName() + """, true)""")
|
||||
"""art::PrettyMethod(""" + art_method.GetName() + """, true)"""
|
||||
)
|
||||
art_method_name_data = frame.EvaluateExpression(
|
||||
art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned()
|
||||
art_method_name.GetName() + """.c_str()"""
|
||||
).GetValueAsUnsigned()
|
||||
art_method_name_size = frame.EvaluateExpression(
|
||||
art_method_name.GetName() + """.length()""").GetValueAsUnsigned()
|
||||
art_method_name.GetName() + """.length()"""
|
||||
).GetValueAsUnsigned()
|
||||
error = lldb.SBError()
|
||||
function = process.ReadCStringFromMemory(
|
||||
art_method_name_data, art_method_name_size + 1, error)
|
||||
art_method_name_data, art_method_name_size + 1, error
|
||||
)
|
||||
|
||||
prettified_frames.append({
|
||||
'function': function,
|
||||
'file': None,
|
||||
'line': -1
|
||||
})
|
||||
prettified_frames.append(
|
||||
{"function": function, "file": None, "line": -1}
|
||||
)
|
||||
|
||||
art_frame_index = art_frame_index + 1
|
||||
break
|
||||
@ -124,78 +154,98 @@ def host_art_bt(debugger, command, result, internal_dict):
|
||||
lldb_frame_index = lldb_frame_index + 1
|
||||
if lldb_frame_index < thread.GetNumFrames():
|
||||
frame = thread.GetFrameAtIndex(lldb_frame_index)
|
||||
if frame.GetSymbol() and (frame.GetSymbol().GetName() ==
|
||||
'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'):
|
||||
if frame.GetSymbol() and (
|
||||
frame.GetSymbol().GetName() == "art_quick_invoke_stub"
|
||||
or frame.GetSymbol().GetName() == "art_quick_invoke_static_stub"
|
||||
):
|
||||
# art_quick_invoke_stub / art_quick_invoke_static_stub
|
||||
# Skip until we get past the next ArtMethod::Invoke()
|
||||
while True:
|
||||
lldb_frame_index = lldb_frame_index + 1
|
||||
if lldb_frame_index >= thread.GetNumFrames():
|
||||
print('ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub')
|
||||
print(
|
||||
"ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub"
|
||||
)
|
||||
sys.exit(1)
|
||||
frame = thread.GetFrameAtIndex(lldb_frame_index)
|
||||
if frame.GetSymbol() and frame.GetSymbol().GetName(
|
||||
) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)':
|
||||
if (
|
||||
frame.GetSymbol()
|
||||
and frame.GetSymbol().GetName()
|
||||
== "art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)"
|
||||
):
|
||||
lldb_frame_index = lldb_frame_index + 1
|
||||
break
|
||||
else:
|
||||
print('Invalid frame below compiled Java frame: ', frame)
|
||||
elif frame.GetSymbol() and re.search(r'art::interpreter::', frame.GetSymbol().GetName()):
|
||||
print("Invalid frame below compiled Java frame: ", frame)
|
||||
elif frame.GetSymbol() and re.search(
|
||||
r"art::interpreter::", frame.GetSymbol().GetName()
|
||||
):
|
||||
# Interpreted Java frame
|
||||
|
||||
while True:
|
||||
lldb_frame_index = lldb_frame_index + 1
|
||||
if lldb_frame_index >= thread.GetNumFrames():
|
||||
print('art::interpreter::Execute not found in interpreter frame')
|
||||
print("art::interpreter::Execute not found in interpreter frame")
|
||||
sys.exit(1)
|
||||
frame = thread.GetFrameAtIndex(lldb_frame_index)
|
||||
if frame.GetSymbol() and frame.GetSymbol().GetName(
|
||||
) == 'art::interpreter::Execute(art::Thread*, art::MethodHelper&, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)':
|
||||
if (
|
||||
frame.GetSymbol()
|
||||
and frame.GetSymbol().GetName()
|
||||
== "art::interpreter::Execute(art::Thread*, art::MethodHelper&, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)"
|
||||
):
|
||||
break
|
||||
|
||||
# Skip art frames
|
||||
while True:
|
||||
art_stack_visitor = frame.EvaluateExpression(
|
||||
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" +
|
||||
str(art_frame_index) +
|
||||
"""); visitor.WalkStack(true); visitor""")
|
||||
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor("""
|
||||
+ str(art_frame_index)
|
||||
+ """); visitor.WalkStack(true); visitor"""
|
||||
)
|
||||
art_method = frame.EvaluateExpression(
|
||||
art_stack_visitor.GetName() + """.GetMethod()""")
|
||||
art_stack_visitor.GetName() + """.GetMethod()"""
|
||||
)
|
||||
if art_method.GetValueAsUnsigned() != 0:
|
||||
# Get function/filename/lineno from ART runtime
|
||||
art_method_name = frame.EvaluateExpression(
|
||||
"""art::PrettyMethod(""" + art_method.GetName() + """, true)""")
|
||||
"""art::PrettyMethod(""" + art_method.GetName() + """, true)"""
|
||||
)
|
||||
art_method_name_data = frame.EvaluateExpression(
|
||||
art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned()
|
||||
art_method_name.GetName() + """.c_str()"""
|
||||
).GetValueAsUnsigned()
|
||||
art_method_name_size = frame.EvaluateExpression(
|
||||
art_method_name.GetName() + """.length()""").GetValueAsUnsigned()
|
||||
art_method_name.GetName() + """.length()"""
|
||||
).GetValueAsUnsigned()
|
||||
error = lldb.SBError()
|
||||
function = process.ReadCStringFromMemory(
|
||||
art_method_name_data, art_method_name_size + 1, error)
|
||||
art_method_name_data, art_method_name_size + 1, error
|
||||
)
|
||||
|
||||
line = frame.EvaluateExpression(
|
||||
art_stack_visitor.GetName() +
|
||||
""".GetMethod()->GetLineNumFromDexPC(""" +
|
||||
art_stack_visitor.GetName() +
|
||||
""".GetDexPc(true))""").GetValueAsUnsigned()
|
||||
art_stack_visitor.GetName()
|
||||
+ """.GetMethod()->GetLineNumFromDexPC("""
|
||||
+ art_stack_visitor.GetName()
|
||||
+ """.GetDexPc(true))"""
|
||||
).GetValueAsUnsigned()
|
||||
|
||||
file_name = frame.EvaluateExpression(
|
||||
art_method.GetName() + """->GetDeclaringClassSourceFile()""")
|
||||
art_method.GetName() + """->GetDeclaringClassSourceFile()"""
|
||||
)
|
||||
file_name_data = file_name.GetValueAsUnsigned()
|
||||
file_name_size = frame.EvaluateExpression(
|
||||
"""(size_t)strlen(""" + file_name.GetName() + """)""").GetValueAsUnsigned()
|
||||
"""(size_t)strlen(""" + file_name.GetName() + """)"""
|
||||
).GetValueAsUnsigned()
|
||||
error = lldb.SBError()
|
||||
file_name = process.ReadCStringFromMemory(
|
||||
file_name_data, file_name_size + 1, error)
|
||||
file_name_data, file_name_size + 1, error
|
||||
)
|
||||
if not error.Success():
|
||||
print('Failed to read source file name')
|
||||
print("Failed to read source file name")
|
||||
sys.exit(1)
|
||||
|
||||
prettified_frames.append({
|
||||
'function': function,
|
||||
'file': file_name,
|
||||
'line': line
|
||||
})
|
||||
prettified_frames.append(
|
||||
{"function": function, "file": file_name, "line": line}
|
||||
)
|
||||
|
||||
art_frame_index = art_frame_index + 1
|
||||
break
|
||||
@ -205,11 +255,12 @@ def host_art_bt(debugger, command, result, internal_dict):
|
||||
while True:
|
||||
lldb_frame_index = lldb_frame_index + 1
|
||||
if lldb_frame_index >= thread.GetNumFrames():
|
||||
print('Can not get past interpreter native frames')
|
||||
print("Can not get past interpreter native frames")
|
||||
sys.exit(1)
|
||||
frame = thread.GetFrameAtIndex(lldb_frame_index)
|
||||
if frame.GetSymbol() and not re.search(
|
||||
r'art::interpreter::', frame.GetSymbol().GetName()):
|
||||
r"art::interpreter::", frame.GetSymbol().GetName()
|
||||
):
|
||||
break
|
||||
else:
|
||||
# Other frames. Add them as-is.
|
||||
@ -218,20 +269,32 @@ def host_art_bt(debugger, command, result, internal_dict):
|
||||
if frame.GetModule():
|
||||
module_name = frame.GetModule().GetFileSpec().GetFilename()
|
||||
if not module_name in [
|
||||
'libartd.so',
|
||||
'dalvikvm32',
|
||||
'dalvikvm64',
|
||||
'libc.so.6']:
|
||||
prettified_frames.append({
|
||||
'function': frame.GetSymbol().GetName() if frame.GetSymbol() else None,
|
||||
'file': str(frame.GetLineEntry().GetFileSpec()) if frame.GetLineEntry() else None,
|
||||
'line': frame.GetLineEntry().GetLine() if frame.GetLineEntry() else -1
|
||||
})
|
||||
"libartd.so",
|
||||
"dalvikvm32",
|
||||
"dalvikvm64",
|
||||
"libc.so.6",
|
||||
]:
|
||||
prettified_frames.append(
|
||||
{
|
||||
"function": frame.GetSymbol().GetName()
|
||||
if frame.GetSymbol()
|
||||
else None,
|
||||
"file": str(frame.GetLineEntry().GetFileSpec())
|
||||
if frame.GetLineEntry()
|
||||
else None,
|
||||
"line": frame.GetLineEntry().GetLine()
|
||||
if frame.GetLineEntry()
|
||||
else -1,
|
||||
}
|
||||
)
|
||||
|
||||
for prettified_frame in prettified_frames:
|
||||
print(prettified_frame['function'], prettified_frame['file'], prettified_frame['line'])
|
||||
print(
|
||||
prettified_frame["function"],
|
||||
prettified_frame["file"],
|
||||
prettified_frame["line"],
|
||||
)
|
||||
|
||||
|
||||
def __lldb_init_module(debugger, internal_dict):
|
||||
debugger.HandleCommand(
|
||||
'command script add -f host_art_bt.host_art_bt host_art_bt')
|
||||
debugger.HandleCommand("command script add -f host_art_bt.host_art_bt host_art_bt")
|
||||
|
@ -30,122 +30,112 @@ import sys
|
||||
def copy_one_file(dest_dir, source_dir, filename):
|
||||
source_path = os.path.join(source_dir, filename)
|
||||
dest_path = os.path.join(dest_dir, filename)
|
||||
print('Copying file %s ==> %s...' % (source_path, dest_path))
|
||||
print("Copying file %s ==> %s..." % (source_path, dest_path))
|
||||
shutil.copyfile(source_path, dest_path)
|
||||
|
||||
|
||||
def copy_named_files(
|
||||
dest_dir,
|
||||
source_dir,
|
||||
files,
|
||||
extensions,
|
||||
copy_debug_suffix_also):
|
||||
for (file, ext) in itertools.product(files, extensions):
|
||||
copy_one_file(dest_dir, source_dir, file + '.' + ext)
|
||||
def copy_named_files(dest_dir, source_dir, files, extensions, copy_debug_suffix_also):
|
||||
for file, ext in itertools.product(files, extensions):
|
||||
copy_one_file(dest_dir, source_dir, file + "." + ext)
|
||||
if copy_debug_suffix_also:
|
||||
copy_one_file(dest_dir, source_dir, file + '_d.' + ext)
|
||||
copy_one_file(dest_dir, source_dir, file + "_d." + ext)
|
||||
|
||||
|
||||
def copy_subdirectory(dest_dir, source_dir, subdir):
|
||||
dest_dir = os.path.join(dest_dir, subdir)
|
||||
source_dir = os.path.join(source_dir, subdir)
|
||||
print('Copying directory %s ==> %s...' % (source_dir, dest_dir))
|
||||
print("Copying directory %s ==> %s..." % (source_dir, dest_dir))
|
||||
shutil.copytree(source_dir, dest_dir)
|
||||
|
||||
|
||||
def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix):
|
||||
dest_dir = os.path.join(dest_dir, dest_subdir)
|
||||
|
||||
print('Copying distribution %s ==> %s' % (source_dir, dest_dir))
|
||||
print("Copying distribution %s ==> %s" % (source_dir, dest_dir))
|
||||
|
||||
os.mkdir(dest_dir)
|
||||
PCbuild_dir = os.path.join(source_dir, 'PCbuild')
|
||||
PCbuild_dir = os.path.join(source_dir, "PCbuild")
|
||||
if source_prefix:
|
||||
PCbuild_dir = os.path.join(PCbuild_dir, source_prefix)
|
||||
# First copy the files that go into the root of the new distribution. This
|
||||
# includes the Python executables, python27(_d).dll, and relevant PDB
|
||||
# files.
|
||||
print('Copying Python executables...')
|
||||
print("Copying Python executables...")
|
||||
copy_named_files(dest_dir, PCbuild_dir, ["w9xpopen"], ["exe", "pdb"], False)
|
||||
copy_named_files(dest_dir, PCbuild_dir, ["python_d", "pythonw_d"], ["exe"], False)
|
||||
copy_named_files(
|
||||
dest_dir, PCbuild_dir, ['w9xpopen'], [
|
||||
'exe', 'pdb'], False)
|
||||
copy_named_files(
|
||||
dest_dir, PCbuild_dir, [
|
||||
'python_d', 'pythonw_d'], ['exe'], False)
|
||||
copy_named_files(
|
||||
dest_dir, PCbuild_dir, [
|
||||
'python', 'pythonw'], [
|
||||
'exe', 'pdb'], False)
|
||||
copy_named_files(dest_dir, PCbuild_dir, ['python27'], ['dll', 'pdb'], True)
|
||||
dest_dir, PCbuild_dir, ["python", "pythonw"], ["exe", "pdb"], False
|
||||
)
|
||||
copy_named_files(dest_dir, PCbuild_dir, ["python27"], ["dll", "pdb"], True)
|
||||
|
||||
# Next copy everything in the Include directory.
|
||||
print('Copying Python include directory')
|
||||
copy_subdirectory(dest_dir, source_dir, 'Include')
|
||||
print("Copying Python include directory")
|
||||
copy_subdirectory(dest_dir, source_dir, "Include")
|
||||
|
||||
# Copy Lib folder (builtin Python modules)
|
||||
print('Copying Python Lib directory')
|
||||
copy_subdirectory(dest_dir, source_dir, 'Lib')
|
||||
print("Copying Python Lib directory")
|
||||
copy_subdirectory(dest_dir, source_dir, "Lib")
|
||||
|
||||
# Copy tools folder. These are probably not necessary, but we copy them anyway to
|
||||
# match an official distribution as closely as possible. Note that we don't just copy
|
||||
# the subdirectory recursively. The source distribution ships with many more tools
|
||||
# than what you get by installing python regularly. We only copy the tools that appear
|
||||
# in an installed distribution.
|
||||
tools_dest_dir = os.path.join(dest_dir, 'Tools')
|
||||
tools_source_dir = os.path.join(source_dir, 'Tools')
|
||||
tools_dest_dir = os.path.join(dest_dir, "Tools")
|
||||
tools_source_dir = os.path.join(source_dir, "Tools")
|
||||
os.mkdir(tools_dest_dir)
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, 'i18n')
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, 'pynche')
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, 'scripts')
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, 'versioncheck')
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, 'webchecker')
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, "i18n")
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, "pynche")
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, "scripts")
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, "versioncheck")
|
||||
copy_subdirectory(tools_dest_dir, tools_source_dir, "webchecker")
|
||||
|
||||
pyd_names = [
|
||||
'_ctypes',
|
||||
'_ctypes_test',
|
||||
'_elementtree',
|
||||
'_multiprocessing',
|
||||
'_socket',
|
||||
'_testcapi',
|
||||
'pyexpat',
|
||||
'select',
|
||||
'unicodedata',
|
||||
'winsound']
|
||||
"_ctypes",
|
||||
"_ctypes_test",
|
||||
"_elementtree",
|
||||
"_multiprocessing",
|
||||
"_socket",
|
||||
"_testcapi",
|
||||
"pyexpat",
|
||||
"select",
|
||||
"unicodedata",
|
||||
"winsound",
|
||||
]
|
||||
|
||||
# Copy builtin extension modules (pyd files)
|
||||
dlls_dir = os.path.join(dest_dir, 'DLLs')
|
||||
dlls_dir = os.path.join(dest_dir, "DLLs")
|
||||
os.mkdir(dlls_dir)
|
||||
print('Copying DLLs directory')
|
||||
copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ['pyd', 'pdb'], True)
|
||||
print("Copying DLLs directory")
|
||||
copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ["pyd", "pdb"], True)
|
||||
|
||||
# Copy libs folder (implibs for the pyd files)
|
||||
libs_dir = os.path.join(dest_dir, 'libs')
|
||||
libs_dir = os.path.join(dest_dir, "libs")
|
||||
os.mkdir(libs_dir)
|
||||
print('Copying libs directory')
|
||||
copy_named_files(libs_dir, PCbuild_dir, pyd_names, ['lib'], False)
|
||||
copy_named_files(libs_dir, PCbuild_dir, ['python27'], ['lib'], True)
|
||||
print("Copying libs directory")
|
||||
copy_named_files(libs_dir, PCbuild_dir, pyd_names, ["lib"], False)
|
||||
copy_named_files(libs_dir, PCbuild_dir, ["python27"], ["lib"], True)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Install a custom Python distribution')
|
||||
parser = argparse.ArgumentParser(description="Install a custom Python distribution")
|
||||
parser.add_argument(
|
||||
'--source',
|
||||
required=True,
|
||||
help='The root of the source tree where Python is built.')
|
||||
"--source", required=True, help="The root of the source tree where Python is built."
|
||||
)
|
||||
parser.add_argument(
|
||||
'--dest',
|
||||
required=True,
|
||||
help='The location to install the Python distributions.')
|
||||
"--dest", required=True, help="The location to install the Python distributions."
|
||||
)
|
||||
parser.add_argument(
|
||||
'--overwrite',
|
||||
"--overwrite",
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='If the destination directory already exists, destroys its contents first.')
|
||||
action="store_true",
|
||||
help="If the destination directory already exists, destroys its contents first.",
|
||||
)
|
||||
parser.add_argument(
|
||||
'--silent',
|
||||
"--silent",
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='If --overwite was specified, suppress confirmation before deleting a directory tree.')
|
||||
action="store_true",
|
||||
help="If --overwite was specified, suppress confirmation before deleting a directory tree.",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -153,23 +143,31 @@ args.source = os.path.normpath(args.source)
|
||||
args.dest = os.path.normpath(args.dest)
|
||||
|
||||
if not os.path.exists(args.source):
|
||||
print('The source directory %s does not exist. Exiting...')
|
||||
print("The source directory %s does not exist. Exiting...")
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.exists(args.dest):
|
||||
if not args.overwrite:
|
||||
print('The destination directory \'%s\' already exists and --overwrite was not specified. Exiting...' % args.dest)
|
||||
print(
|
||||
"The destination directory '%s' already exists and --overwrite was not specified. Exiting..."
|
||||
% args.dest
|
||||
)
|
||||
sys.exit(1)
|
||||
while not args.silent:
|
||||
print('Ok to recursively delete \'%s\' and all contents (Y/N)? Choosing Y will permanently delete the contents.' % args.dest)
|
||||
print(
|
||||
"Ok to recursively delete '%s' and all contents (Y/N)? Choosing Y will permanently delete the contents."
|
||||
% args.dest
|
||||
)
|
||||
result = str.upper(sys.stdin.read(1))
|
||||
if result == 'N':
|
||||
print('Unable to copy files to the destination. The destination already exists.')
|
||||
if result == "N":
|
||||
print(
|
||||
"Unable to copy files to the destination. The destination already exists."
|
||||
)
|
||||
sys.exit(1)
|
||||
elif result == 'Y':
|
||||
elif result == "Y":
|
||||
break
|
||||
shutil.rmtree(args.dest)
|
||||
|
||||
os.mkdir(args.dest)
|
||||
copy_distro(args.dest, 'x86', args.source, None)
|
||||
copy_distro(args.dest, 'x64', args.source, 'amd64')
|
||||
copy_distro(args.dest, "x86", args.source, None)
|
||||
copy_distro(args.dest, "x64", args.source, "amd64")
|
||||
|
@ -10,39 +10,39 @@ import subprocess
|
||||
|
||||
|
||||
def run_reproducer(path):
|
||||
proc = subprocess.Popen([LLDB, '--replay', path],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
proc = subprocess.Popen(
|
||||
[LLDB, "--replay", path], stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
reason = None
|
||||
try:
|
||||
outs, errs = proc.communicate(timeout=TIMEOUT)
|
||||
success = proc.returncode == 0
|
||||
result = 'PASSED' if success else 'FAILED'
|
||||
result = "PASSED" if success else "FAILED"
|
||||
if not success:
|
||||
outs = outs.decode()
|
||||
errs = errs.decode()
|
||||
# Do some pattern matching to find out the cause of the failure.
|
||||
if 'Encountered unexpected packet during replay' in errs:
|
||||
reason = 'Unexpected packet'
|
||||
elif 'Assertion failed' in errs:
|
||||
reason = 'Assertion failed'
|
||||
elif 'UNREACHABLE' in errs:
|
||||
reason = 'Unreachable executed'
|
||||
elif 'Segmentation fault' in errs:
|
||||
reason = 'Segmentation fault'
|
||||
elif 'Illegal instruction' in errs:
|
||||
reason = 'Illegal instruction'
|
||||
if "Encountered unexpected packet during replay" in errs:
|
||||
reason = "Unexpected packet"
|
||||
elif "Assertion failed" in errs:
|
||||
reason = "Assertion failed"
|
||||
elif "UNREACHABLE" in errs:
|
||||
reason = "Unreachable executed"
|
||||
elif "Segmentation fault" in errs:
|
||||
reason = "Segmentation fault"
|
||||
elif "Illegal instruction" in errs:
|
||||
reason = "Illegal instruction"
|
||||
else:
|
||||
reason = f'Exit code {proc.returncode}'
|
||||
reason = f"Exit code {proc.returncode}"
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
success = False
|
||||
outs, errs = proc.communicate()
|
||||
result = 'TIMEOUT'
|
||||
result = "TIMEOUT"
|
||||
|
||||
if not FAILURE_ONLY or not success:
|
||||
reason_str = f' ({reason})' if reason else ''
|
||||
print(f'{result}: {path}{reason_str}')
|
||||
reason_str = f" ({reason})" if reason else ""
|
||||
print(f"{result}: {path}{reason_str}")
|
||||
if VERBOSE:
|
||||
if outs:
|
||||
print(outs)
|
||||
@ -54,49 +54,51 @@ def find_reproducers(path):
|
||||
for root, dirs, files in os.walk(path):
|
||||
for dir in dirs:
|
||||
_, extension = os.path.splitext(dir)
|
||||
if dir.startswith('Test') and extension == '.py':
|
||||
if dir.startswith("Test") and extension == ".py":
|
||||
yield os.path.join(root, dir)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description='LLDB API Test Replay Driver. '
|
||||
'Replay one or more reproducers in parallel using the specified LLDB driver. '
|
||||
'The script will look for reproducers generated by the API lit test suite. '
|
||||
'To generate the reproducers, pass --param \'lldb-run-with-repro=capture\' to lit.'
|
||||
description="LLDB API Test Replay Driver. "
|
||||
"Replay one or more reproducers in parallel using the specified LLDB driver. "
|
||||
"The script will look for reproducers generated by the API lit test suite. "
|
||||
"To generate the reproducers, pass --param 'lldb-run-with-repro=capture' to lit."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-j',
|
||||
'--threads',
|
||||
"-j",
|
||||
"--threads",
|
||||
type=int,
|
||||
default=multiprocessing.cpu_count(),
|
||||
help='Number of threads. The number of CPU threads if not specified.')
|
||||
help="Number of threads. The number of CPU threads if not specified.",
|
||||
)
|
||||
parser.add_argument(
|
||||
'-t',
|
||||
'--timeout',
|
||||
"-t",
|
||||
"--timeout",
|
||||
type=int,
|
||||
default=60,
|
||||
help='Replay timeout in seconds. 60 seconds if not specified.')
|
||||
help="Replay timeout in seconds. 60 seconds if not specified.",
|
||||
)
|
||||
parser.add_argument(
|
||||
'-p',
|
||||
'--path',
|
||||
"-p",
|
||||
"--path",
|
||||
type=str,
|
||||
default=os.getcwd(),
|
||||
help=
|
||||
'Path to the directory containing the reproducers. The current working directory if not specified.'
|
||||
help="Path to the directory containing the reproducers. The current working directory if not specified.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--lldb",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Path to the LLDB command line driver",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", help="Print replay output.", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--failure-only", help="Only log failures.", action="store_true"
|
||||
)
|
||||
parser.add_argument('-l',
|
||||
'--lldb',
|
||||
type=str,
|
||||
required=True,
|
||||
help='Path to the LLDB command line driver')
|
||||
parser.add_argument('-v',
|
||||
'--verbose',
|
||||
help='Print replay output.',
|
||||
action='store_true')
|
||||
parser.add_argument('--failure-only',
|
||||
help='Only log failures.',
|
||||
action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
global LLDB
|
||||
@ -109,11 +111,11 @@ if __name__ == '__main__':
|
||||
FAILURE_ONLY = args.failure_only
|
||||
|
||||
print(
|
||||
f'Replaying reproducers in {args.path} with {args.threads} threads and a {args.timeout} seconds timeout'
|
||||
f"Replaying reproducers in {args.path} with {args.threads} threads and a {args.timeout} seconds timeout"
|
||||
)
|
||||
|
||||
try:
|
||||
pool = Pool(args.threads)
|
||||
pool.map(run_reproducer, find_reproducers(args.path))
|
||||
except KeyboardInterrupt:
|
||||
print('Interrupted')
|
||||
print("Interrupted")
|
||||
|
@ -7,7 +7,7 @@ def find_lldb_root():
|
||||
lldb_root = os.path.dirname(inspect.getfile(inspect.currentframe()))
|
||||
while True:
|
||||
parent = os.path.dirname(lldb_root)
|
||||
if parent == lldb_root: # dirname('/') == '/'
|
||||
if parent == lldb_root: # dirname('/') == '/'
|
||||
raise Exception("use_lldb_suite_root.py not found")
|
||||
lldb_root = parent
|
||||
|
||||
@ -15,8 +15,10 @@ def find_lldb_root():
|
||||
if os.path.isfile(test_path):
|
||||
return lldb_root
|
||||
|
||||
|
||||
lldb_root = find_lldb_root()
|
||||
import imp
|
||||
|
||||
fp, pathname, desc = imp.find_module("use_lldb_suite_root", [lldb_root])
|
||||
try:
|
||||
imp.load_module("use_lldb_suite_root", fp, pathname, desc)
|
||||
|
@ -10,58 +10,67 @@ import sys
|
||||
|
||||
def extract_exe_symbol_names(arch, exe_path, match_str):
|
||||
command = 'dsymutil --arch %s -s "%s" | grep "%s" | colrm 1 69' % (
|
||||
arch, exe_path, match_str)
|
||||
arch,
|
||||
exe_path,
|
||||
match_str,
|
||||
)
|
||||
(command_exit_status, command_output) = subprocess.getstatusoutput(command)
|
||||
if command_exit_status == 0:
|
||||
if command_output:
|
||||
return command_output[0:-1].split("'\n")
|
||||
else:
|
||||
print('error: command returned no output')
|
||||
print("error: command returned no output")
|
||||
else:
|
||||
print('error: command failed with exit status %i\n command: %s' % (command_exit_status, command))
|
||||
print(
|
||||
"error: command failed with exit status %i\n command: %s"
|
||||
% (command_exit_status, command)
|
||||
)
|
||||
return list()
|
||||
|
||||
|
||||
def verify_api(all_args):
|
||||
'''Verify the API in the specified library is valid given one or more binaries.'''
|
||||
"""Verify the API in the specified library is valid given one or more binaries."""
|
||||
usage = "usage: verify_api --library <path> [ --library <path> ...] executable1 [executable2 ...]"
|
||||
description = '''Verify the API in the specified library is valid given one or more binaries.
|
||||
description = """Verify the API in the specified library is valid given one or more binaries.
|
||||
|
||||
Example:
|
||||
|
||||
verify_api.py --library ~/Documents/src/lldb/build/Debug/LLDB.framework/LLDB --arch x86_64 /Applications/Xcode.app/Contents/PlugIns/DebuggerLLDB.ideplugin/Contents/MacOS/DebuggerLLDB --api-regex lldb
|
||||
'''
|
||||
"""
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='verify_api',
|
||||
usage=usage)
|
||||
description=description, prog="verify_api", usage=usage
|
||||
)
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help='display verbose debug info',
|
||||
default=False)
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
dest="verbose",
|
||||
help="display verbose debug info",
|
||||
default=False,
|
||||
)
|
||||
parser.add_option(
|
||||
'-a',
|
||||
'--arch',
|
||||
type='string',
|
||||
action='append',
|
||||
dest='archs',
|
||||
help='architecture to use when checking the api')
|
||||
"-a",
|
||||
"--arch",
|
||||
type="string",
|
||||
action="append",
|
||||
dest="archs",
|
||||
help="architecture to use when checking the api",
|
||||
)
|
||||
parser.add_option(
|
||||
'-r',
|
||||
'--api-regex',
|
||||
type='string',
|
||||
dest='api_regex_str',
|
||||
help='Exclude any undefined symbols that do not match this regular expression when searching for missing APIs.')
|
||||
"-r",
|
||||
"--api-regex",
|
||||
type="string",
|
||||
dest="api_regex_str",
|
||||
help="Exclude any undefined symbols that do not match this regular expression when searching for missing APIs.",
|
||||
)
|
||||
parser.add_option(
|
||||
'-l',
|
||||
'--library',
|
||||
type='string',
|
||||
action='append',
|
||||
dest='libraries',
|
||||
help='Specify one or more libraries that will contain all needed APIs for the executables.')
|
||||
"-l",
|
||||
"--library",
|
||||
type="string",
|
||||
action="append",
|
||||
dest="libraries",
|
||||
help="Specify one or more libraries that will contain all needed APIs for the executables.",
|
||||
)
|
||||
(options, args) = parser.parse_args(all_args)
|
||||
|
||||
api_external_symbols = list()
|
||||
@ -69,18 +78,19 @@ def verify_api(all_args):
|
||||
for arch in options.archs:
|
||||
for library in options.libraries:
|
||||
external_symbols = extract_exe_symbol_names(
|
||||
arch, library, "( SECT EXT)")
|
||||
arch, library, "( SECT EXT)"
|
||||
)
|
||||
if external_symbols:
|
||||
for external_symbol in external_symbols:
|
||||
api_external_symbols.append(external_symbol)
|
||||
else:
|
||||
sys.exit(1)
|
||||
else:
|
||||
print('error: must specify one or more architectures with the --arch option')
|
||||
print("error: must specify one or more architectures with the --arch option")
|
||||
sys.exit(4)
|
||||
if options.verbose:
|
||||
print("API symbols:")
|
||||
for (i, external_symbol) in enumerate(api_external_symbols):
|
||||
for i, external_symbol in enumerate(api_external_symbols):
|
||||
print("[%u] %s" % (i, external_symbol))
|
||||
|
||||
api_regex = None
|
||||
@ -92,24 +102,29 @@ def verify_api(all_args):
|
||||
print('Verifying (%s) "%s"...' % (arch, exe_path))
|
||||
exe_errors = 0
|
||||
undefined_symbols = extract_exe_symbol_names(
|
||||
arch, exe_path, "( UNDF EXT)")
|
||||
arch, exe_path, "( UNDF EXT)"
|
||||
)
|
||||
for undefined_symbol in undefined_symbols:
|
||||
if api_regex:
|
||||
match = api_regex.search(undefined_symbol)
|
||||
if not match:
|
||||
if options.verbose:
|
||||
print('ignoring symbol: %s' % (undefined_symbol))
|
||||
print("ignoring symbol: %s" % (undefined_symbol))
|
||||
continue
|
||||
if undefined_symbol in api_external_symbols:
|
||||
if options.verbose:
|
||||
print('verified symbol: %s' % (undefined_symbol))
|
||||
print("verified symbol: %s" % (undefined_symbol))
|
||||
else:
|
||||
print('missing symbol: %s' % (undefined_symbol))
|
||||
print("missing symbol: %s" % (undefined_symbol))
|
||||
exe_errors += 1
|
||||
if exe_errors:
|
||||
print('error: missing %u API symbols from %s' % (exe_errors, options.libraries))
|
||||
print(
|
||||
"error: missing %u API symbols from %s"
|
||||
% (exe_errors, options.libraries)
|
||||
)
|
||||
else:
|
||||
print('success')
|
||||
print("success")
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
verify_api(sys.argv[1:])
|
||||
|
@ -34,23 +34,27 @@ def main():
|
||||
# Compute an MD5 hash based on the input arguments and the current working
|
||||
# directory.
|
||||
h = hashlib.md5()
|
||||
h.update(' '.join(sys.argv[2:]).encode('utf-8'))
|
||||
h.update(os.getcwd().encode('utf-8'))
|
||||
h.update(" ".join(sys.argv[2:]).encode("utf-8"))
|
||||
h.update(os.getcwd().encode("utf-8"))
|
||||
input_hash = h.hexdigest()
|
||||
|
||||
# Use the hash to "uniquely" identify a reproducer path.
|
||||
reproducer_path = os.path.join(tempfile.gettempdir(), input_hash)
|
||||
|
||||
# Create a new lldb invocation with capture or replay enabled.
|
||||
lldb = os.path.join(os.path.dirname(sys.argv[0]), 'lldb')
|
||||
lldb = os.path.join(os.path.dirname(sys.argv[0]), "lldb")
|
||||
new_args = [lldb]
|
||||
if sys.argv[1] == "replay":
|
||||
new_args.extend(['--replay', reproducer_path])
|
||||
new_args.extend(["--replay", reproducer_path])
|
||||
elif sys.argv[1] == "capture":
|
||||
new_args.extend([
|
||||
'--capture', '--capture-path', reproducer_path,
|
||||
'--reproducer-generate-on-exit'
|
||||
])
|
||||
new_args.extend(
|
||||
[
|
||||
"--capture",
|
||||
"--capture-path",
|
||||
reproducer_path,
|
||||
"--reproducer-generate-on-exit",
|
||||
]
|
||||
)
|
||||
new_args.extend(sys.argv[2:])
|
||||
else:
|
||||
help()
|
||||
@ -60,10 +64,10 @@ def main():
|
||||
|
||||
# The driver always exists with a zero exit code during replay. Store the
|
||||
# exit code and return that for tests that expect a non-zero exit code.
|
||||
exit_code_path = os.path.join(reproducer_path, 'exit_code.txt')
|
||||
exit_code_path = os.path.join(reproducer_path, "exit_code.txt")
|
||||
if sys.argv[1] == "replay":
|
||||
replay_exit_code = exit_code
|
||||
with open(exit_code_path, 'r') as f:
|
||||
with open(exit_code_path, "r") as f:
|
||||
exit_code = int(f.read())
|
||||
if replay_exit_code != 0:
|
||||
print("error: replay failed with exit code {}".format(replay_exit_code))
|
||||
@ -72,11 +76,11 @@ def main():
|
||||
return 1 if (exit_code == 0) else 0
|
||||
shutil.rmtree(reproducer_path, True)
|
||||
elif sys.argv[1] == "capture":
|
||||
with open(exit_code_path, 'w') as f:
|
||||
f.write('%d' % exit_code)
|
||||
with open(exit_code_path, "w") as f:
|
||||
f.write("%d" % exit_code)
|
||||
|
||||
return exit_code
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
|
@ -14,7 +14,6 @@ import re
|
||||
|
||||
|
||||
class BreakWin(cui.ListWin):
|
||||
|
||||
def __init__(self, driver, x, y, w, h):
|
||||
super(BreakWin, self).__init__(x, y, w, h)
|
||||
self.driver = driver
|
||||
@ -26,7 +25,7 @@ class BreakWin(cui.ListWin):
|
||||
if lldb.SBBreakpoint.EventIsBreakpointEvent(event):
|
||||
self.update()
|
||||
if isinstance(event, int):
|
||||
if event == ord('d'):
|
||||
if event == ord("d"):
|
||||
self.deleteSelected()
|
||||
if event == curses.ascii.NL or event == curses.ascii.SP:
|
||||
self.toggleSelected()
|
||||
@ -72,14 +71,14 @@ class BreakWin(cui.ListWin):
|
||||
continue
|
||||
text = lldbutil.get_description(bp)
|
||||
# FIXME: Use an API for this, not parsing the description.
|
||||
match = re.search('SBBreakpoint: id = ([^,]+), (.*)', text)
|
||||
match = re.search("SBBreakpoint: id = ([^,]+), (.*)", text)
|
||||
try:
|
||||
id = match.group(1)
|
||||
desc = match.group(2).strip()
|
||||
if bp.IsEnabled():
|
||||
text = '%s: %s' % (id, desc)
|
||||
text = "%s: %s" % (id, desc)
|
||||
else:
|
||||
text = '%s: (disabled) %s' % (id, desc)
|
||||
text = "%s: (disabled) %s" % (id, desc)
|
||||
except ValueError as e:
|
||||
# bp unparsable
|
||||
pass
|
||||
@ -87,7 +86,8 @@ class BreakWin(cui.ListWin):
|
||||
if self.showDetails.setdefault(bp.id, False):
|
||||
for location in bp:
|
||||
desc = lldbutil.get_description(
|
||||
location, lldb.eDescriptionLevelFull)
|
||||
text += '\n ' + desc
|
||||
location, lldb.eDescriptionLevelFull
|
||||
)
|
||||
text += "\n " + desc
|
||||
self.addItem(text)
|
||||
self.setSelected(selected)
|
||||
|
@ -13,21 +13,20 @@ from itertools import islice
|
||||
|
||||
|
||||
class History(object):
|
||||
|
||||
def __init__(self):
|
||||
self.data = {}
|
||||
self.pos = 0
|
||||
self.tempEntry = ''
|
||||
self.tempEntry = ""
|
||||
|
||||
def previous(self, curr):
|
||||
if self.pos == len(self.data):
|
||||
self.tempEntry = curr
|
||||
|
||||
if self.pos < 0:
|
||||
return ''
|
||||
return ""
|
||||
if self.pos == 0:
|
||||
self.pos -= 1
|
||||
return ''
|
||||
return ""
|
||||
if self.pos > 0:
|
||||
self.pos -= 1
|
||||
return self.data[self.pos]
|
||||
@ -38,13 +37,13 @@ class History(object):
|
||||
|
||||
if self.pos < len(self.data):
|
||||
return self.data[self.pos]
|
||||
elif self.tempEntry != '':
|
||||
elif self.tempEntry != "":
|
||||
return self.tempEntry
|
||||
else:
|
||||
return ''
|
||||
return ""
|
||||
|
||||
def add(self, c):
|
||||
self.tempEntry = ''
|
||||
self.tempEntry = ""
|
||||
self.pos = len(self.data)
|
||||
if self.pos == 0 or self.data[self.pos - 1] != c:
|
||||
self.data[self.pos] = c
|
||||
@ -52,7 +51,6 @@ class History(object):
|
||||
|
||||
|
||||
class CommandWin(cui.TitledWin):
|
||||
|
||||
def __init__(self, driver, x, y, w, h):
|
||||
super(CommandWin, self).__init__(x, y, w, h, "Commands")
|
||||
self.command = ""
|
||||
@ -72,7 +70,8 @@ class CommandWin(cui.TitledWin):
|
||||
matches = lldb.SBStringList()
|
||||
commandinterpreter = self.getCommandInterpreter()
|
||||
commandinterpreter.HandleCompletion(
|
||||
self.data, self.el.index, 0, -1, matches)
|
||||
self.data, self.el.index, 0, -1, matches
|
||||
)
|
||||
if matches.GetSize() == 2:
|
||||
self.el.content += matches.GetStringAtIndex(0)
|
||||
self.el.index = len(self.el.content)
|
||||
@ -90,19 +89,17 @@ class CommandWin(cui.TitledWin):
|
||||
self.startline = self.win.getmaxyx()[0] - 2
|
||||
|
||||
self.el = cui.CursesEditLine(
|
||||
self.win,
|
||||
self.history,
|
||||
enterCallback,
|
||||
tabCompleteCallback)
|
||||
self.win, self.history, enterCallback, tabCompleteCallback
|
||||
)
|
||||
self.el.prompt = self.driver.getPrompt()
|
||||
self.el.showPrompt(self.startline, 0)
|
||||
|
||||
def handleCommand(self, cmd):
|
||||
# enter!
|
||||
# enter!
|
||||
self.win.scroll(1) # TODO: scroll more for longer commands
|
||||
if cmd == '':
|
||||
cmd = self.history.previous('')
|
||||
elif cmd in ('q', 'quit'):
|
||||
if cmd == "":
|
||||
cmd = self.history.previous("")
|
||||
elif cmd in ("q", "quit"):
|
||||
self.driver.terminate()
|
||||
return
|
||||
|
||||
@ -114,13 +111,13 @@ class CommandWin(cui.TitledWin):
|
||||
else:
|
||||
out = ret.GetError()
|
||||
attr = curses.color_pair(3) # red on black
|
||||
self.win.addstr(self.startline, 0, out + '\n', attr)
|
||||
self.win.addstr(self.startline, 0, out + "\n", attr)
|
||||
self.win.scroll(1)
|
||||
self.el.showPrompt(self.startline, 0)
|
||||
|
||||
def handleEvent(self, event):
|
||||
if isinstance(event, int):
|
||||
if event == curses.ascii.EOT and self.el.content == '':
|
||||
if event == curses.ascii.EOT and self.el.content == "":
|
||||
# When the command is empty, treat CTRL-D as EOF.
|
||||
self.driver.terminate()
|
||||
return
|
||||
|
@ -12,7 +12,6 @@ import threading
|
||||
|
||||
|
||||
class CursesWin(object):
|
||||
|
||||
def __init__(self, x, y, w, h):
|
||||
self.win = curses.newwin(h, w, y, x)
|
||||
self.focus = False
|
||||
@ -34,11 +33,10 @@ class CursesWin(object):
|
||||
|
||||
|
||||
class TextWin(CursesWin):
|
||||
|
||||
def __init__(self, x, y, w):
|
||||
super(TextWin, self).__init__(x, y, w, 1)
|
||||
self.win.bkgd(curses.color_pair(1))
|
||||
self.text = ''
|
||||
self.text = ""
|
||||
self.reverse = False
|
||||
|
||||
def canFocus(self):
|
||||
@ -48,8 +46,8 @@ class TextWin(CursesWin):
|
||||
w = self.win.getmaxyx()[1]
|
||||
text = self.text
|
||||
if len(text) > w:
|
||||
#trunc_length = len(text) - w
|
||||
text = text[-w + 1:]
|
||||
# trunc_length = len(text) - w
|
||||
text = text[-w + 1 :]
|
||||
if self.reverse:
|
||||
self.win.addstr(0, 0, text, curses.A_REVERSE)
|
||||
else:
|
||||
@ -64,7 +62,6 @@ class TextWin(CursesWin):
|
||||
|
||||
|
||||
class TitledWin(CursesWin):
|
||||
|
||||
def __init__(self, x, y, w, h, title):
|
||||
super(TitledWin, self).__init__(x, y + 1, w, h - 1)
|
||||
self.title = title
|
||||
@ -82,7 +79,6 @@ class TitledWin(CursesWin):
|
||||
|
||||
|
||||
class ListWin(CursesWin):
|
||||
|
||||
def __init__(self, x, y, w, h):
|
||||
super(ListWin, self).__init__(x, y, w, h)
|
||||
self.items = []
|
||||
@ -101,10 +97,10 @@ class ListWin(CursesWin):
|
||||
firstSelected = -1
|
||||
lastSelected = -1
|
||||
for i, item in enumerate(self.items):
|
||||
lines = self.items[i].split('\n')
|
||||
lines = lines if lines[len(lines) - 1] != '' else lines[:-1]
|
||||
lines = self.items[i].split("\n")
|
||||
lines = lines if lines[len(lines) - 1] != "" else lines[:-1]
|
||||
if len(lines) == 0:
|
||||
lines = ['']
|
||||
lines = [""]
|
||||
|
||||
if i == self.getSelected():
|
||||
firstSelected = len(allLines)
|
||||
@ -127,7 +123,7 @@ class ListWin(CursesWin):
|
||||
attr = curses.A_NORMAL
|
||||
if i >= firstSelected and i <= lastSelected:
|
||||
attr = curses.A_REVERSE
|
||||
line = '{0:{width}}'.format(line, width=w - 1)
|
||||
line = "{0:{width}}".format(line, width=w - 1)
|
||||
|
||||
# Ignore the error we get from drawing over the bottom-right char.
|
||||
try:
|
||||
@ -170,7 +166,6 @@ class ListWin(CursesWin):
|
||||
|
||||
|
||||
class InputHandler(threading.Thread):
|
||||
|
||||
def __init__(self, screen, queue):
|
||||
super(InputHandler, self).__init__()
|
||||
self.screen = screen
|
||||
@ -183,7 +178,7 @@ class InputHandler(threading.Thread):
|
||||
|
||||
|
||||
class CursesUI(object):
|
||||
""" Responsible for updating the console UI with curses. """
|
||||
"""Responsible for updating the console UI with curses."""
|
||||
|
||||
def __init__(self, screen, event_queue):
|
||||
self.screen = screen
|
||||
@ -220,7 +215,6 @@ class CursesUI(object):
|
||||
self.focusNext()
|
||||
|
||||
def eventLoop(self):
|
||||
|
||||
self.input_handler.start()
|
||||
self.wins[self.focus].setFocus(True)
|
||||
|
||||
@ -247,7 +241,7 @@ class CursesUI(object):
|
||||
|
||||
|
||||
class CursesEditLine(object):
|
||||
""" Embed an 'editline'-compatible prompt inside a CursesWin. """
|
||||
"""Embed an 'editline'-compatible prompt inside a CursesWin."""
|
||||
|
||||
def __init__(self, win, history, enterCallback, tabCompleteCallback):
|
||||
self.win = win
|
||||
@ -255,8 +249,8 @@ class CursesEditLine(object):
|
||||
self.enterCallback = enterCallback
|
||||
self.tabCompleteCallback = tabCompleteCallback
|
||||
|
||||
self.prompt = ''
|
||||
self.content = ''
|
||||
self.prompt = ""
|
||||
self.content = ""
|
||||
self.index = 0
|
||||
self.startx = -1
|
||||
self.starty = -1
|
||||
@ -269,16 +263,16 @@ class CursesEditLine(object):
|
||||
self.win.scroll(1)
|
||||
self.starty -= 1
|
||||
if self.starty < 0:
|
||||
raise RuntimeError('Input too long; aborting')
|
||||
raise RuntimeError("Input too long; aborting")
|
||||
(y, x) = (self.starty, self.startx)
|
||||
|
||||
self.win.move(y, x)
|
||||
self.win.clrtobot()
|
||||
self.win.addstr(y, x, prompt)
|
||||
remain = self.content
|
||||
self.win.addstr(remain[:w - len(prompt)])
|
||||
remain = remain[w - len(prompt):]
|
||||
while remain != '':
|
||||
self.win.addstr(remain[: w - len(prompt)])
|
||||
remain = remain[w - len(prompt) :]
|
||||
while remain != "":
|
||||
y += 1
|
||||
self.win.addstr(y, 0, remain[:w])
|
||||
remain = remain[w:]
|
||||
@ -287,7 +281,7 @@ class CursesEditLine(object):
|
||||
self.win.move(self.starty + length / w, length % w)
|
||||
|
||||
def showPrompt(self, y, x, prompt=None):
|
||||
self.content = ''
|
||||
self.content = ""
|
||||
self.index = 0
|
||||
self.startx = x
|
||||
self.starty = y
|
||||
@ -299,26 +293,27 @@ class CursesEditLine(object):
|
||||
key = event
|
||||
|
||||
if self.startx == -1:
|
||||
raise RuntimeError('Trying to handle input without prompt')
|
||||
raise RuntimeError("Trying to handle input without prompt")
|
||||
|
||||
if key == curses.ascii.NL:
|
||||
self.enterCallback(self.content)
|
||||
elif key == curses.ascii.TAB:
|
||||
self.tabCompleteCallback(self.content)
|
||||
elif curses.ascii.isprint(key):
|
||||
self.content = self.content[:self.index] + \
|
||||
chr(key) + self.content[self.index:]
|
||||
self.content = (
|
||||
self.content[: self.index] + chr(key) + self.content[self.index :]
|
||||
)
|
||||
self.index += 1
|
||||
elif key == curses.KEY_BACKSPACE or key == curses.ascii.BS:
|
||||
if self.index > 0:
|
||||
self.index -= 1
|
||||
self.content = self.content[
|
||||
:self.index] + self.content[self.index + 1:]
|
||||
self.content = (
|
||||
self.content[: self.index] + self.content[self.index + 1 :]
|
||||
)
|
||||
elif key == curses.KEY_DC or key == curses.ascii.DEL or key == curses.ascii.EOT:
|
||||
self.content = self.content[
|
||||
:self.index] + self.content[self.index + 1:]
|
||||
self.content = self.content[: self.index] + self.content[self.index + 1 :]
|
||||
elif key == curses.ascii.VT: # CTRL-K
|
||||
self.content = self.content[:self.index]
|
||||
self.content = self.content[: self.index]
|
||||
elif key == curses.KEY_LEFT or key == curses.ascii.STX: # left or CTRL-B
|
||||
if self.index > 0:
|
||||
self.index -= 1
|
||||
|
@ -14,7 +14,7 @@ from threading import Thread
|
||||
|
||||
|
||||
class DebuggerDriver(Thread):
|
||||
""" Drives the debugger and responds to events. """
|
||||
"""Drives the debugger and responds to events."""
|
||||
|
||||
def __init__(self, debugger, event_queue):
|
||||
Thread.__init__(self)
|
||||
@ -31,41 +31,45 @@ class DebuggerDriver(Thread):
|
||||
if not self.listener.IsValid():
|
||||
raise "Invalid listener"
|
||||
|
||||
self.listener.StartListeningForEventClass(self.debugger,
|
||||
lldb.SBTarget.GetBroadcasterClassName(),
|
||||
lldb.SBTarget.eBroadcastBitBreakpointChanged
|
||||
#| lldb.SBTarget.eBroadcastBitModuleLoaded
|
||||
#| lldb.SBTarget.eBroadcastBitModuleUnloaded
|
||||
| lldb.SBTarget.eBroadcastBitWatchpointChanged
|
||||
#| lldb.SBTarget.eBroadcastBitSymbolLoaded
|
||||
)
|
||||
self.listener.StartListeningForEventClass(
|
||||
self.debugger,
|
||||
lldb.SBTarget.GetBroadcasterClassName(),
|
||||
lldb.SBTarget.eBroadcastBitBreakpointChanged
|
||||
# | lldb.SBTarget.eBroadcastBitModuleLoaded
|
||||
# | lldb.SBTarget.eBroadcastBitModuleUnloaded
|
||||
| lldb.SBTarget.eBroadcastBitWatchpointChanged
|
||||
# | lldb.SBTarget.eBroadcastBitSymbolLoaded
|
||||
)
|
||||
|
||||
self.listener.StartListeningForEventClass(self.debugger,
|
||||
lldb.SBThread.GetBroadcasterClassName(),
|
||||
lldb.SBThread.eBroadcastBitStackChanged
|
||||
# lldb.SBThread.eBroadcastBitBreakpointChanged
|
||||
| lldb.SBThread.eBroadcastBitThreadSuspended
|
||||
| lldb.SBThread.eBroadcastBitThreadResumed
|
||||
| lldb.SBThread.eBroadcastBitSelectedFrameChanged
|
||||
| lldb.SBThread.eBroadcastBitThreadSelected
|
||||
)
|
||||
self.listener.StartListeningForEventClass(
|
||||
self.debugger,
|
||||
lldb.SBThread.GetBroadcasterClassName(),
|
||||
lldb.SBThread.eBroadcastBitStackChanged
|
||||
# lldb.SBThread.eBroadcastBitBreakpointChanged
|
||||
| lldb.SBThread.eBroadcastBitThreadSuspended
|
||||
| lldb.SBThread.eBroadcastBitThreadResumed
|
||||
| lldb.SBThread.eBroadcastBitSelectedFrameChanged
|
||||
| lldb.SBThread.eBroadcastBitThreadSelected,
|
||||
)
|
||||
|
||||
self.listener.StartListeningForEventClass(self.debugger,
|
||||
lldb.SBProcess.GetBroadcasterClassName(),
|
||||
lldb.SBProcess.eBroadcastBitStateChanged
|
||||
| lldb.SBProcess.eBroadcastBitInterrupt
|
||||
| lldb.SBProcess.eBroadcastBitSTDOUT
|
||||
| lldb.SBProcess.eBroadcastBitSTDERR
|
||||
| lldb.SBProcess.eBroadcastBitProfileData
|
||||
)
|
||||
self.listener.StartListeningForEventClass(self.debugger,
|
||||
lldb.SBCommandInterpreter.GetBroadcasterClass(),
|
||||
lldb.SBCommandInterpreter.eBroadcastBitThreadShouldExit
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitResetPrompt
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitQuitCommandReceived
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousOutputData
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousErrorData
|
||||
)
|
||||
self.listener.StartListeningForEventClass(
|
||||
self.debugger,
|
||||
lldb.SBProcess.GetBroadcasterClassName(),
|
||||
lldb.SBProcess.eBroadcastBitStateChanged
|
||||
| lldb.SBProcess.eBroadcastBitInterrupt
|
||||
| lldb.SBProcess.eBroadcastBitSTDOUT
|
||||
| lldb.SBProcess.eBroadcastBitSTDERR
|
||||
| lldb.SBProcess.eBroadcastBitProfileData,
|
||||
)
|
||||
self.listener.StartListeningForEventClass(
|
||||
self.debugger,
|
||||
lldb.SBCommandInterpreter.GetBroadcasterClass(),
|
||||
lldb.SBCommandInterpreter.eBroadcastBitThreadShouldExit
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitResetPrompt
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitQuitCommandReceived
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousOutputData
|
||||
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousErrorData,
|
||||
)
|
||||
|
||||
def createTarget(self, target_image, args=None):
|
||||
self.handleCommand("target create %s" % target_image)
|
||||
|
@ -12,9 +12,8 @@ import lldbutil
|
||||
|
||||
|
||||
class EventWin(cui.TitledWin):
|
||||
|
||||
def __init__(self, x, y, w, h):
|
||||
super(EventWin, self).__init__(x, y, w, h, 'LLDB Event Log')
|
||||
super(EventWin, self).__init__(x, y, w, h, "LLDB Event Log")
|
||||
self.win.scrollok(1)
|
||||
super(EventWin, self).draw()
|
||||
|
||||
|
@ -40,6 +40,7 @@ def which(program):
|
||||
return exe_file
|
||||
return None
|
||||
|
||||
|
||||
# ===================================================
|
||||
# Disassembly for an SBFunction or an SBSymbol object
|
||||
# ===================================================
|
||||
@ -56,6 +57,7 @@ def disassemble(target, function_or_symbol):
|
||||
print(i, file=buf)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
# ==========================================================
|
||||
# Integer (byte size 1, 2, 4, and 8) to bytearray conversion
|
||||
# ==========================================================
|
||||
@ -75,11 +77,11 @@ def int_to_bytearray(val, bytesize):
|
||||
# Little endian followed by a format character.
|
||||
template = "<%c"
|
||||
if bytesize == 2:
|
||||
fmt = template % 'h'
|
||||
fmt = template % "h"
|
||||
elif bytesize == 4:
|
||||
fmt = template % 'i'
|
||||
fmt = template % "i"
|
||||
elif bytesize == 4:
|
||||
fmt = template % 'q'
|
||||
fmt = template % "q"
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -101,11 +103,11 @@ def bytearray_to_int(bytes, bytesize):
|
||||
# Little endian followed by a format character.
|
||||
template = "<%c"
|
||||
if bytesize == 2:
|
||||
fmt = template % 'h'
|
||||
fmt = template % "h"
|
||||
elif bytesize == 4:
|
||||
fmt = template % 'i'
|
||||
fmt = template % "i"
|
||||
elif bytesize == 4:
|
||||
fmt = template % 'q'
|
||||
fmt = template % "q"
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -126,7 +128,7 @@ def get_description(obj, option=None):
|
||||
o lldb.eDescriptionLevelFull
|
||||
o lldb.eDescriptionLevelVerbose
|
||||
"""
|
||||
method = getattr(obj, 'GetDescription')
|
||||
method = getattr(obj, "GetDescription")
|
||||
if not method:
|
||||
return None
|
||||
tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint)
|
||||
@ -148,6 +150,7 @@ def get_description(obj, option=None):
|
||||
# Convert some enum value to its string counterpart
|
||||
# =================================================
|
||||
|
||||
|
||||
def state_type_to_str(enum):
|
||||
"""Returns the stateType string given an enum."""
|
||||
if enum == lldb.eStateInvalid:
|
||||
@ -280,60 +283,70 @@ def value_type_to_str(enum):
|
||||
# Get stopped threads due to each stop reason.
|
||||
# ==================================================
|
||||
|
||||
def sort_stopped_threads(process,
|
||||
breakpoint_threads=None,
|
||||
crashed_threads=None,
|
||||
watchpoint_threads=None,
|
||||
signal_threads=None,
|
||||
exiting_threads=None,
|
||||
other_threads=None):
|
||||
""" Fills array *_threads with threads stopped for the corresponding stop
|
||||
reason.
|
||||
|
||||
def sort_stopped_threads(
|
||||
process,
|
||||
breakpoint_threads=None,
|
||||
crashed_threads=None,
|
||||
watchpoint_threads=None,
|
||||
signal_threads=None,
|
||||
exiting_threads=None,
|
||||
other_threads=None,
|
||||
):
|
||||
"""Fills array *_threads with threads stopped for the corresponding stop
|
||||
reason.
|
||||
"""
|
||||
for lst in [breakpoint_threads,
|
||||
watchpoint_threads,
|
||||
signal_threads,
|
||||
exiting_threads,
|
||||
other_threads]:
|
||||
for lst in [
|
||||
breakpoint_threads,
|
||||
watchpoint_threads,
|
||||
signal_threads,
|
||||
exiting_threads,
|
||||
other_threads,
|
||||
]:
|
||||
if lst is not None:
|
||||
lst[:] = []
|
||||
|
||||
for thread in process:
|
||||
dispatched = False
|
||||
for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads),
|
||||
(lldb.eStopReasonException, crashed_threads),
|
||||
(lldb.eStopReasonWatchpoint, watchpoint_threads),
|
||||
(lldb.eStopReasonSignal, signal_threads),
|
||||
(lldb.eStopReasonThreadExiting, exiting_threads),
|
||||
(None, other_threads)]:
|
||||
for reason, list in [
|
||||
(lldb.eStopReasonBreakpoint, breakpoint_threads),
|
||||
(lldb.eStopReasonException, crashed_threads),
|
||||
(lldb.eStopReasonWatchpoint, watchpoint_threads),
|
||||
(lldb.eStopReasonSignal, signal_threads),
|
||||
(lldb.eStopReasonThreadExiting, exiting_threads),
|
||||
(None, other_threads),
|
||||
]:
|
||||
if not dispatched and list is not None:
|
||||
if thread.GetStopReason() == reason or reason is None:
|
||||
list.append(thread)
|
||||
dispatched = True
|
||||
|
||||
|
||||
# ==================================================
|
||||
# Utility functions for setting breakpoints
|
||||
# ==================================================
|
||||
|
||||
|
||||
def run_break_set_by_file_and_line(
|
||||
test,
|
||||
file_name,
|
||||
line_number,
|
||||
extra_options=None,
|
||||
num_expected_locations=1,
|
||||
loc_exact=False,
|
||||
module_name=None):
|
||||
test,
|
||||
file_name,
|
||||
line_number,
|
||||
extra_options=None,
|
||||
num_expected_locations=1,
|
||||
loc_exact=False,
|
||||
module_name=None,
|
||||
):
|
||||
"""Set a breakpoint by file and line, returning the breakpoint number.
|
||||
|
||||
If extra_options is not None, then we append it to the breakpoint set command.
|
||||
|
||||
If num_expected_locations is -1 we check that we got AT LEAST one location, otherwise we check that num_expected_locations equals the number of locations.
|
||||
|
||||
If loc_exact is true, we check that there is one location, and that location must be at the input file and line number."""
|
||||
If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.
|
||||
"""
|
||||
|
||||
if file_name is None:
|
||||
command = 'breakpoint set -l %d' % (line_number)
|
||||
command = "breakpoint set -l %d" % (line_number)
|
||||
else:
|
||||
command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number)
|
||||
|
||||
@ -352,26 +365,28 @@ def run_break_set_by_file_and_line(
|
||||
num_locations=num_expected_locations,
|
||||
file_name=file_name,
|
||||
line_number=line_number,
|
||||
module_name=module_name)
|
||||
module_name=module_name,
|
||||
)
|
||||
else:
|
||||
check_breakpoint_result(
|
||||
test,
|
||||
break_results,
|
||||
num_locations=num_expected_locations)
|
||||
test, break_results, num_locations=num_expected_locations
|
||||
)
|
||||
|
||||
return get_bpno_from_match(break_results)
|
||||
|
||||
|
||||
def run_break_set_by_symbol(
|
||||
test,
|
||||
symbol,
|
||||
extra_options=None,
|
||||
num_expected_locations=-1,
|
||||
sym_exact=False,
|
||||
module_name=None):
|
||||
test,
|
||||
symbol,
|
||||
extra_options=None,
|
||||
num_expected_locations=-1,
|
||||
sym_exact=False,
|
||||
module_name=None,
|
||||
):
|
||||
"""Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line.
|
||||
|
||||
If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match."""
|
||||
If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.
|
||||
"""
|
||||
command = 'breakpoint set -n "%s"' % (symbol)
|
||||
|
||||
if module_name:
|
||||
@ -388,22 +403,19 @@ def run_break_set_by_symbol(
|
||||
break_results,
|
||||
num_locations=num_expected_locations,
|
||||
symbol_name=symbol,
|
||||
module_name=module_name)
|
||||
module_name=module_name,
|
||||
)
|
||||
else:
|
||||
check_breakpoint_result(
|
||||
test,
|
||||
break_results,
|
||||
num_locations=num_expected_locations)
|
||||
test, break_results, num_locations=num_expected_locations
|
||||
)
|
||||
|
||||
return get_bpno_from_match(break_results)
|
||||
|
||||
|
||||
def run_break_set_by_selector(
|
||||
test,
|
||||
selector,
|
||||
extra_options=None,
|
||||
num_expected_locations=-1,
|
||||
module_name=None):
|
||||
test, selector, extra_options=None, num_expected_locations=-1, module_name=None
|
||||
):
|
||||
"""Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line."""
|
||||
|
||||
command = 'breakpoint set -S "%s"' % (selector)
|
||||
@ -423,21 +435,19 @@ def run_break_set_by_selector(
|
||||
num_locations=num_expected_locations,
|
||||
symbol_name=selector,
|
||||
symbol_match_exact=False,
|
||||
module_name=module_name)
|
||||
module_name=module_name,
|
||||
)
|
||||
else:
|
||||
check_breakpoint_result(
|
||||
test,
|
||||
break_results,
|
||||
num_locations=num_expected_locations)
|
||||
test, break_results, num_locations=num_expected_locations
|
||||
)
|
||||
|
||||
return get_bpno_from_match(break_results)
|
||||
|
||||
|
||||
def run_break_set_by_regexp(
|
||||
test,
|
||||
regexp,
|
||||
extra_options=None,
|
||||
num_expected_locations=-1):
|
||||
test, regexp, extra_options=None, num_expected_locations=-1
|
||||
):
|
||||
"""Set a breakpoint by regular expression match on symbol name. Common options are the same as run_break_set_by_file_and_line."""
|
||||
|
||||
command = 'breakpoint set -r "%s"' % (regexp)
|
||||
@ -446,19 +456,14 @@ def run_break_set_by_regexp(
|
||||
|
||||
break_results = run_break_set_command(test, command)
|
||||
|
||||
check_breakpoint_result(
|
||||
test,
|
||||
break_results,
|
||||
num_locations=num_expected_locations)
|
||||
check_breakpoint_result(test, break_results, num_locations=num_expected_locations)
|
||||
|
||||
return get_bpno_from_match(break_results)
|
||||
|
||||
|
||||
def run_break_set_by_source_regexp(
|
||||
test,
|
||||
regexp,
|
||||
extra_options=None,
|
||||
num_expected_locations=-1):
|
||||
test, regexp, extra_options=None, num_expected_locations=-1
|
||||
):
|
||||
"""Set a breakpoint by source regular expression. Common options are the same as run_break_set_by_file_and_line."""
|
||||
command = 'breakpoint set -p "%s"' % (regexp)
|
||||
if extra_options:
|
||||
@ -466,10 +471,7 @@ def run_break_set_by_source_regexp(
|
||||
|
||||
break_results = run_break_set_command(test, command)
|
||||
|
||||
check_breakpoint_result(
|
||||
test,
|
||||
break_results,
|
||||
num_locations=num_expected_locations)
|
||||
check_breakpoint_result(test, break_results, num_locations=num_expected_locations)
|
||||
|
||||
return get_bpno_from_match(break_results)
|
||||
|
||||
@ -496,120 +498,120 @@ def run_break_set_command(test, command):
|
||||
r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$",
|
||||
r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.",
|
||||
r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$",
|
||||
r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"]
|
||||
r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$",
|
||||
]
|
||||
match_object = test.match(command, patterns)
|
||||
break_results = match_object.groupdict()
|
||||
|
||||
# We always insert the breakpoint number, setting it to -1 if we couldn't find it
|
||||
# Also, make sure it gets stored as an integer.
|
||||
if not 'bpno' in break_results:
|
||||
break_results['bpno'] = -1
|
||||
if not "bpno" in break_results:
|
||||
break_results["bpno"] = -1
|
||||
else:
|
||||
break_results['bpno'] = int(break_results['bpno'])
|
||||
break_results["bpno"] = int(break_results["bpno"])
|
||||
|
||||
# We always insert the number of locations
|
||||
# If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1...
|
||||
# We also make sure it is an integer.
|
||||
|
||||
if not 'num_locations' in break_results:
|
||||
if not "num_locations" in break_results:
|
||||
num_locations = 1
|
||||
else:
|
||||
num_locations = break_results['num_locations']
|
||||
if num_locations == 'no':
|
||||
num_locations = break_results["num_locations"]
|
||||
if num_locations == "no":
|
||||
num_locations = 0
|
||||
else:
|
||||
num_locations = int(break_results['num_locations'])
|
||||
num_locations = int(break_results["num_locations"])
|
||||
|
||||
break_results['num_locations'] = num_locations
|
||||
break_results["num_locations"] = num_locations
|
||||
|
||||
if 'line_no' in break_results:
|
||||
break_results['line_no'] = int(break_results['line_no'])
|
||||
if "line_no" in break_results:
|
||||
break_results["line_no"] = int(break_results["line_no"])
|
||||
|
||||
return break_results
|
||||
|
||||
|
||||
def get_bpno_from_match(break_results):
|
||||
return int(break_results['bpno'])
|
||||
return int(break_results["bpno"])
|
||||
|
||||
|
||||
def check_breakpoint_result(
|
||||
test,
|
||||
break_results,
|
||||
file_name=None,
|
||||
line_number=-1,
|
||||
symbol_name=None,
|
||||
symbol_match_exact=True,
|
||||
module_name=None,
|
||||
offset=-1,
|
||||
num_locations=-1):
|
||||
|
||||
out_num_locations = break_results['num_locations']
|
||||
test,
|
||||
break_results,
|
||||
file_name=None,
|
||||
line_number=-1,
|
||||
symbol_name=None,
|
||||
symbol_match_exact=True,
|
||||
module_name=None,
|
||||
offset=-1,
|
||||
num_locations=-1,
|
||||
):
|
||||
out_num_locations = break_results["num_locations"]
|
||||
|
||||
if num_locations == -1:
|
||||
test.assertTrue(out_num_locations > 0,
|
||||
"Expecting one or more locations, got none.")
|
||||
test.assertTrue(
|
||||
out_num_locations > 0, "Expecting one or more locations, got none."
|
||||
)
|
||||
else:
|
||||
test.assertTrue(
|
||||
num_locations == out_num_locations,
|
||||
"Expecting %d locations, got %d." %
|
||||
(num_locations,
|
||||
out_num_locations))
|
||||
"Expecting %d locations, got %d." % (num_locations, out_num_locations),
|
||||
)
|
||||
|
||||
if file_name:
|
||||
out_file_name = ""
|
||||
if 'file' in break_results:
|
||||
out_file_name = break_results['file']
|
||||
if "file" in break_results:
|
||||
out_file_name = break_results["file"]
|
||||
test.assertTrue(
|
||||
file_name == out_file_name,
|
||||
"Breakpoint file name '%s' doesn't match resultant name '%s'." %
|
||||
(file_name,
|
||||
out_file_name))
|
||||
"Breakpoint file name '%s' doesn't match resultant name '%s'."
|
||||
% (file_name, out_file_name),
|
||||
)
|
||||
|
||||
if line_number != -1:
|
||||
out_file_line = -1
|
||||
if 'line_no' in break_results:
|
||||
out_line_number = break_results['line_no']
|
||||
if "line_no" in break_results:
|
||||
out_line_number = break_results["line_no"]
|
||||
|
||||
test.assertTrue(
|
||||
line_number == out_line_number,
|
||||
"Breakpoint line number %s doesn't match resultant line %s." %
|
||||
(line_number,
|
||||
out_line_number))
|
||||
"Breakpoint line number %s doesn't match resultant line %s."
|
||||
% (line_number, out_line_number),
|
||||
)
|
||||
|
||||
if symbol_name:
|
||||
out_symbol_name = ""
|
||||
# Look first for the inlined symbol name, otherwise use the symbol
|
||||
# name:
|
||||
if 'inline_symbol' in break_results and break_results['inline_symbol']:
|
||||
out_symbol_name = break_results['inline_symbol']
|
||||
elif 'symbol' in break_results:
|
||||
out_symbol_name = break_results['symbol']
|
||||
if "inline_symbol" in break_results and break_results["inline_symbol"]:
|
||||
out_symbol_name = break_results["inline_symbol"]
|
||||
elif "symbol" in break_results:
|
||||
out_symbol_name = break_results["symbol"]
|
||||
|
||||
if symbol_match_exact:
|
||||
test.assertTrue(
|
||||
symbol_name == out_symbol_name,
|
||||
"Symbol name '%s' doesn't match resultant symbol '%s'." %
|
||||
(symbol_name,
|
||||
out_symbol_name))
|
||||
"Symbol name '%s' doesn't match resultant symbol '%s'."
|
||||
% (symbol_name, out_symbol_name),
|
||||
)
|
||||
else:
|
||||
test.assertTrue(
|
||||
out_symbol_name.find(symbol_name) != -
|
||||
1,
|
||||
"Symbol name '%s' isn't in resultant symbol '%s'." %
|
||||
(symbol_name,
|
||||
out_symbol_name))
|
||||
out_symbol_name.find(symbol_name) != -1,
|
||||
"Symbol name '%s' isn't in resultant symbol '%s'."
|
||||
% (symbol_name, out_symbol_name),
|
||||
)
|
||||
|
||||
if module_name:
|
||||
out_nodule_name = None
|
||||
if 'module' in break_results:
|
||||
out_module_name = break_results['module']
|
||||
if "module" in break_results:
|
||||
out_module_name = break_results["module"]
|
||||
|
||||
test.assertTrue(
|
||||
module_name.find(out_module_name) != -
|
||||
1,
|
||||
"Symbol module name '%s' isn't in expected module name '%s'." %
|
||||
(out_module_name,
|
||||
module_name))
|
||||
module_name.find(out_module_name) != -1,
|
||||
"Symbol module name '%s' isn't in expected module name '%s'."
|
||||
% (out_module_name, module_name),
|
||||
)
|
||||
|
||||
|
||||
# ==================================================
|
||||
# Utility functions related to Threads and Processes
|
||||
@ -658,7 +660,7 @@ def get_stopped_thread(process, reason):
|
||||
|
||||
|
||||
def get_threads_stopped_at_breakpoint(process, bkpt):
|
||||
""" For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""
|
||||
"""For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""
|
||||
stopped_threads = []
|
||||
threads = []
|
||||
|
||||
@ -677,7 +679,7 @@ def get_threads_stopped_at_breakpoint(process, bkpt):
|
||||
|
||||
|
||||
def continue_to_breakpoint(process, bkpt):
|
||||
""" Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
|
||||
"""Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
|
||||
process.Continue()
|
||||
if process.GetState() != lldb.eStateStopped:
|
||||
return None
|
||||
@ -703,6 +705,7 @@ def get_function_names(thread):
|
||||
"""
|
||||
Returns a sequence of function names from the stack frames of this thread.
|
||||
"""
|
||||
|
||||
def GetFuncName(i):
|
||||
return thread.GetFrameAtIndex(i).GetFunctionName()
|
||||
|
||||
@ -713,6 +716,7 @@ def get_symbol_names(thread):
|
||||
"""
|
||||
Returns a sequence of symbols for this thread.
|
||||
"""
|
||||
|
||||
def GetSymbol(i):
|
||||
return thread.GetFrameAtIndex(i).GetSymbol().GetName()
|
||||
|
||||
@ -723,6 +727,7 @@ def get_pc_addresses(thread):
|
||||
"""
|
||||
Returns a sequence of pc addresses for this thread.
|
||||
"""
|
||||
|
||||
def GetPCAddress(i):
|
||||
return thread.GetFrameAtIndex(i).GetPCAddress()
|
||||
|
||||
@ -733,9 +738,9 @@ def get_filenames(thread):
|
||||
"""
|
||||
Returns a sequence of file names from the stack frames of this thread.
|
||||
"""
|
||||
|
||||
def GetFilename(i):
|
||||
return thread.GetFrameAtIndex(
|
||||
i).GetLineEntry().GetFileSpec().GetFilename()
|
||||
return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()
|
||||
|
||||
return [GetFilename(i) for i in range(thread.GetNumFrames())]
|
||||
|
||||
@ -744,6 +749,7 @@ def get_line_numbers(thread):
|
||||
"""
|
||||
Returns a sequence of line numbers from the stack frames of this thread.
|
||||
"""
|
||||
|
||||
def GetLineNumber(i):
|
||||
return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()
|
||||
|
||||
@ -754,9 +760,9 @@ def get_module_names(thread):
|
||||
"""
|
||||
Returns a sequence of module names from the stack frames of this thread.
|
||||
"""
|
||||
|
||||
def GetModuleName(i):
|
||||
return thread.GetFrameAtIndex(
|
||||
i).GetModule().GetFileSpec().GetFilename()
|
||||
return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()
|
||||
|
||||
return [GetModuleName(i) for i in range(thread.GetNumFrames())]
|
||||
|
||||
@ -765,6 +771,7 @@ def get_stack_frames(thread):
|
||||
"""
|
||||
Returns a sequence of stack frames for this thread.
|
||||
"""
|
||||
|
||||
def GetStackFrame(i):
|
||||
return thread.GetFrameAtIndex(i)
|
||||
|
||||
@ -790,8 +797,13 @@ def print_stacktrace(thread, string_buffer=False):
|
||||
desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason())
|
||||
else:
|
||||
desc = ""
|
||||
print("Stack trace for thread id={0:#x} name={1} queue={2} ".format(
|
||||
thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc, file=output)
|
||||
print(
|
||||
"Stack trace for thread id={0:#x} name={1} queue={2} ".format(
|
||||
thread.GetThreadID(), thread.GetName(), thread.GetQueueName()
|
||||
)
|
||||
+ desc,
|
||||
file=output,
|
||||
)
|
||||
|
||||
for i in range(depth):
|
||||
frame = thread.GetFrameAtIndex(i)
|
||||
@ -802,13 +814,31 @@ def print_stacktrace(thread, string_buffer=False):
|
||||
file_addr = addrs[i].GetFileAddress()
|
||||
start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress()
|
||||
symbol_offset = file_addr - start_addr
|
||||
print(" frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format(
|
||||
num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset), file=output)
|
||||
print(
|
||||
" frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format(
|
||||
num=i,
|
||||
addr=load_addr,
|
||||
mod=mods[i],
|
||||
symbol=symbols[i],
|
||||
offset=symbol_offset,
|
||||
),
|
||||
file=output,
|
||||
)
|
||||
else:
|
||||
print(" frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(
|
||||
num=i, addr=load_addr, mod=mods[i], func='%s [inlined]' %
|
||||
funcs[i] if frame.IsInlined() else funcs[i], file=files[i], line=lines[i], args=get_args_as_string(
|
||||
frame, showFuncName=False) if not frame.IsInlined() else '()'), file=output)
|
||||
print(
|
||||
" frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(
|
||||
num=i,
|
||||
addr=load_addr,
|
||||
mod=mods[i],
|
||||
func="%s [inlined]" % funcs[i] if frame.IsInlined() else funcs[i],
|
||||
file=files[i],
|
||||
line=lines[i],
|
||||
args=get_args_as_string(frame, showFuncName=False)
|
||||
if not frame.IsInlined()
|
||||
else "()",
|
||||
),
|
||||
file=output,
|
||||
)
|
||||
|
||||
if string_buffer:
|
||||
return output.getvalue()
|
||||
@ -827,6 +857,7 @@ def print_stacktraces(process, string_buffer=False):
|
||||
if string_buffer:
|
||||
return output.getvalue()
|
||||
|
||||
|
||||
# ===================================
|
||||
# Utility functions related to Frames
|
||||
# ===================================
|
||||
@ -859,9 +890,7 @@ def get_args_as_string(frame, showFuncName=True):
|
||||
vars = frame.GetVariables(True, False, False, True) # type of SBValueList
|
||||
args = [] # list of strings
|
||||
for var in vars:
|
||||
args.append("(%s)%s=%s" % (var.GetTypeName(),
|
||||
var.GetName(),
|
||||
var.GetValue()))
|
||||
args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), var.GetValue()))
|
||||
if frame.GetFunction():
|
||||
name = frame.GetFunction().GetName()
|
||||
elif frame.GetSymbol():
|
||||
@ -882,15 +911,20 @@ def print_registers(frame, string_buffer=False):
|
||||
print("Register sets for " + str(frame), file=output)
|
||||
|
||||
registerSet = frame.GetRegisters() # Return type of SBValueList.
|
||||
print("Frame registers (size of register set = %d):" % registerSet.GetSize(
|
||||
), file=output)
|
||||
print(
|
||||
"Frame registers (size of register set = %d):" % registerSet.GetSize(),
|
||||
file=output,
|
||||
)
|
||||
for value in registerSet:
|
||||
#print >> output, value
|
||||
print("%s (number of children = %d):" % (
|
||||
value.GetName(), value.GetNumChildren()), file=output)
|
||||
# print >> output, value
|
||||
print(
|
||||
"%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()),
|
||||
file=output,
|
||||
)
|
||||
for child in value:
|
||||
print("Name: %s, Value: %s" % (
|
||||
child.GetName(), child.GetValue()), file=output)
|
||||
print(
|
||||
"Name: %s, Value: %s" % (child.GetName(), child.GetValue()), file=output
|
||||
)
|
||||
|
||||
if string_buffer:
|
||||
return output.getvalue()
|
||||
@ -950,6 +984,7 @@ def get_ESRs(frame):
|
||||
"""
|
||||
return get_registers(frame, "exception state")
|
||||
|
||||
|
||||
# ======================================
|
||||
# Utility classes/functions for SBValues
|
||||
# ======================================
|
||||
@ -970,11 +1005,15 @@ class BasicFormatter(object):
|
||||
val = value.GetValue()
|
||||
if val is None and value.GetNumChildren() > 0:
|
||||
val = "%s (location)" % value.GetLocation()
|
||||
print("{indentation}({type}) {name} = {value}".format(
|
||||
indentation=' ' * indent,
|
||||
type=value.GetTypeName(),
|
||||
name=value.GetName(),
|
||||
value=val), file=output)
|
||||
print(
|
||||
"{indentation}({type}) {name} = {value}".format(
|
||||
indentation=" " * indent,
|
||||
type=value.GetTypeName(),
|
||||
name=value.GetName(),
|
||||
value=val,
|
||||
),
|
||||
file=output,
|
||||
)
|
||||
return output.getvalue()
|
||||
|
||||
|
||||
@ -996,8 +1035,7 @@ class ChildVisitingFormatter(BasicFormatter):
|
||||
|
||||
BasicFormatter.format(self, value, buffer=output)
|
||||
for child in value:
|
||||
BasicFormatter.format(
|
||||
self, child, buffer=output, indent=self.cindent)
|
||||
BasicFormatter.format(self, child, buffer=output, indent=self.cindent)
|
||||
|
||||
return output.getvalue()
|
||||
|
||||
@ -1025,14 +1063,12 @@ class RecursiveDecentFormatter(BasicFormatter):
|
||||
new_indent = self.lindent + self.cindent
|
||||
for child in value:
|
||||
if child.GetSummary() is not None:
|
||||
BasicFormatter.format(
|
||||
self, child, buffer=output, indent=new_indent)
|
||||
BasicFormatter.format(self, child, buffer=output, indent=new_indent)
|
||||
else:
|
||||
if child.GetNumChildren() > 0:
|
||||
rdf = RecursiveDecentFormatter(indent_level=new_indent)
|
||||
rdf.format(child, buffer=output)
|
||||
else:
|
||||
BasicFormatter.format(
|
||||
self, child, buffer=output, indent=new_indent)
|
||||
BasicFormatter.format(self, child, buffer=output, indent=new_indent)
|
||||
|
||||
return output.getvalue()
|
||||
|
@ -38,17 +38,11 @@ event_queue = None
|
||||
def handle_args(driver, argv):
|
||||
parser = OptionParser()
|
||||
parser.add_option(
|
||||
"-p",
|
||||
"--attach",
|
||||
dest="pid",
|
||||
help="Attach to specified Process ID",
|
||||
type="int")
|
||||
"-p", "--attach", dest="pid", help="Attach to specified Process ID", type="int"
|
||||
)
|
||||
parser.add_option(
|
||||
"-c",
|
||||
"--core",
|
||||
dest="core",
|
||||
help="Load specified core file",
|
||||
type="string")
|
||||
"-c", "--core", dest="core", help="Load specified core file", type="string"
|
||||
)
|
||||
|
||||
(options, args) = parser.parse_args(argv)
|
||||
|
||||
@ -60,9 +54,7 @@ def handle_args(driver, argv):
|
||||
print("Error: expecting integer PID, got '%s'" % options.pid)
|
||||
elif options.core is not None:
|
||||
if not os.path.exists(options.core):
|
||||
raise Exception(
|
||||
"Specified core file '%s' does not exist." %
|
||||
options.core)
|
||||
raise Exception("Specified core file '%s' does not exist." % options.core)
|
||||
driver.loadCore(options.core)
|
||||
elif len(args) == 2:
|
||||
if not os.path.isfile(args[1]):
|
||||
@ -80,7 +72,6 @@ def sigint_handler(signal, frame):
|
||||
|
||||
|
||||
class LLDBUI(cui.CursesUI):
|
||||
|
||||
def __init__(self, screen, event_queue, driver):
|
||||
super(LLDBUI, self).__init__(screen, event_queue)
|
||||
|
||||
@ -94,19 +85,21 @@ class LLDBUI(cui.CursesUI):
|
||||
self.status_win = statuswin.StatusWin(0, h - 1, w, 1)
|
||||
h -= 1
|
||||
self.command_win = commandwin.CommandWin(
|
||||
driver, 0, h - command_win_height, w, command_win_height)
|
||||
driver, 0, h - command_win_height, w, command_win_height
|
||||
)
|
||||
h -= command_win_height
|
||||
self.source_win = sourcewin.SourceWin(driver, 0, 0,
|
||||
w - break_win_width - 1, h)
|
||||
self.break_win = breakwin.BreakWin(driver, w - break_win_width, 0,
|
||||
break_win_width, h)
|
||||
self.source_win = sourcewin.SourceWin(driver, 0, 0, w - break_win_width - 1, h)
|
||||
self.break_win = breakwin.BreakWin(
|
||||
driver, w - break_win_width, 0, break_win_width, h
|
||||
)
|
||||
|
||||
self.wins = [self.status_win,
|
||||
# self.event_win,
|
||||
self.source_win,
|
||||
self.break_win,
|
||||
self.command_win,
|
||||
]
|
||||
self.wins = [
|
||||
self.status_win,
|
||||
# self.event_win,
|
||||
self.source_win,
|
||||
self.break_win,
|
||||
self.command_win,
|
||||
]
|
||||
|
||||
self.focus = len(self.wins) - 1 # index of command window;
|
||||
|
||||
@ -116,12 +109,14 @@ class LLDBUI(cui.CursesUI):
|
||||
if event == curses.KEY_F10:
|
||||
self.driver.terminate()
|
||||
if event == 20: # ctrl-T
|
||||
|
||||
def foo(cmd):
|
||||
ret = lldb.SBCommandReturnObject()
|
||||
self.driver.getCommandInterpreter().HandleCommand(cmd, ret)
|
||||
foo('target create a.out')
|
||||
foo('b main')
|
||||
foo('run')
|
||||
|
||||
foo("target create a.out")
|
||||
foo("b main")
|
||||
foo("run")
|
||||
super(LLDBUI, self).handleEvent(event)
|
||||
|
||||
|
||||
@ -145,6 +140,7 @@ def main(screen):
|
||||
handle_args(driver, sys.argv)
|
||||
view.eventLoop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
curses.wrapper(main)
|
||||
|
@ -25,7 +25,6 @@ event_queue = None
|
||||
|
||||
|
||||
class SandboxUI(cui.CursesUI):
|
||||
|
||||
def __init__(self, screen, event_queue):
|
||||
super(SandboxUI, self).__init__(screen, event_queue)
|
||||
|
||||
@ -34,10 +33,10 @@ class SandboxUI(cui.CursesUI):
|
||||
h2 = height / 2
|
||||
|
||||
self.wins = []
|
||||
#self.wins.append(cui.TitledWin(w2, h2, w2, h2, "Test Window 4"))
|
||||
# self.wins.append(cui.TitledWin(w2, h2, w2, h2, "Test Window 4"))
|
||||
list_win = cui.ListWin(w2, h2, w2, h2)
|
||||
for i in range(0, 40):
|
||||
list_win.addItem('Item %s' % i)
|
||||
list_win.addItem("Item %s" % i)
|
||||
self.wins.append(list_win)
|
||||
self.wins.append(cui.TitledWin(0, 0, w2, h2, "Test Window 1"))
|
||||
self.wins.append(cui.TitledWin(w2, 0, w2, h2, "Test Window 2"))
|
||||
@ -52,12 +51,12 @@ class SandboxUI(cui.CursesUI):
|
||||
# self.wins[0].win.scrollok(1)
|
||||
# self.el = cui.CursesEditLine(self.wins[0].win, None,
|
||||
# lambda c: callback('got', c), lambda c: callback('tab', c))
|
||||
#self.el.prompt = '>>> '
|
||||
#self.el.showPrompt(10, 0)
|
||||
# self.el.prompt = '>>> '
|
||||
# self.el.showPrompt(10, 0)
|
||||
|
||||
def handleEvent(self, event):
|
||||
if isinstance(event, int):
|
||||
if event == ord('q'):
|
||||
if event == ord("q"):
|
||||
sys.exit(0)
|
||||
# self.el.handleEvent(event)
|
||||
super(SandboxUI, self).handleEvent(event)
|
||||
@ -70,6 +69,7 @@ def main(screen):
|
||||
sandbox = SandboxUI(screen, event_queue)
|
||||
sandbox.eventLoop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
curses.wrapper(main)
|
||||
|
@ -15,7 +15,6 @@ import os
|
||||
|
||||
|
||||
class SourceWin(cui.TitledWin):
|
||||
|
||||
def __init__(self, driver, x, y, w, h):
|
||||
super(SourceWin, self).__init__(x, y, w, h, "Source")
|
||||
self.sourceman = driver.getSourceManager()
|
||||
@ -35,9 +34,10 @@ class SourceWin(cui.TitledWin):
|
||||
|
||||
try:
|
||||
from pygments.formatters import TerminalFormatter
|
||||
|
||||
self.formatter = TerminalFormatter()
|
||||
except ImportError:
|
||||
#self.win.addstr("\nWarning: no 'pygments' library found. Syntax highlighting is disabled.")
|
||||
# self.win.addstr("\nWarning: no 'pygments' library found. Syntax highlighting is disabled.")
|
||||
self.lexer = None
|
||||
self.formatter = None
|
||||
pass
|
||||
@ -55,8 +55,9 @@ class SourceWin(cui.TitledWin):
|
||||
if lldb.SBBreakpoint.EventIsBreakpointEvent(event):
|
||||
self.handleBPEvent(event)
|
||||
|
||||
if lldb.SBProcess.EventIsProcessEvent(event) and \
|
||||
not lldb.SBProcess.GetRestartedFromEvent(event):
|
||||
if lldb.SBProcess.EventIsProcessEvent(
|
||||
event
|
||||
) and not lldb.SBProcess.GetRestartedFromEvent(event):
|
||||
process = lldb.SBProcess.GetProcessFromEvent(event)
|
||||
if not process.IsValid():
|
||||
return
|
||||
@ -71,8 +72,8 @@ class SourceWin(cui.TitledWin):
|
||||
pid = process.GetProcessID()
|
||||
ec = process.GetExitStatus()
|
||||
self.win.addstr(
|
||||
"\nProcess %s [%d] has exited with exit-code %d" %
|
||||
(target, pid, ec))
|
||||
"\nProcess %s [%d] has exited with exit-code %d" % (target, pid, ec)
|
||||
)
|
||||
|
||||
def pageUp(self):
|
||||
if self.viewline > 0:
|
||||
@ -100,8 +101,8 @@ class SourceWin(cui.TitledWin):
|
||||
|
||||
if self.viewline < 0:
|
||||
raise Exception(
|
||||
"negative viewline: pc=%d viewline=%d" %
|
||||
(self.pc_line, self.viewline))
|
||||
"negative viewline: pc=%d viewline=%d" % (self.pc_line, self.viewline)
|
||||
)
|
||||
|
||||
def refreshSource(self, process=None):
|
||||
(self.height, self.width) = self.win.getmaxyx()
|
||||
@ -126,9 +127,14 @@ class SourceWin(cui.TitledWin):
|
||||
|
||||
if self.formatter is not None:
|
||||
from pygments.lexers import get_lexer_for_filename
|
||||
|
||||
self.lexer = get_lexer_for_filename(self.filename)
|
||||
|
||||
bps = [] if not self.filename in self.breakpoints else self.breakpoints[self.filename]
|
||||
bps = (
|
||||
[]
|
||||
if not self.filename in self.breakpoints
|
||||
else self.breakpoints[self.filename]
|
||||
)
|
||||
self.win.erase()
|
||||
if self.content:
|
||||
self.formatContent(self.content, self.pc_line, bps)
|
||||
@ -159,7 +165,7 @@ class SourceWin(cui.TitledWin):
|
||||
marker = self.markerBP
|
||||
line = "%s%3d %s" % (marker, line_num, self.highlight(content[i]))
|
||||
if len(line) >= self.width:
|
||||
line = line[0:self.width - 1] + "\n"
|
||||
line = line[0 : self.width - 1] + "\n"
|
||||
self.win.addstr(line, attr)
|
||||
source += line
|
||||
count = count + 1
|
||||
@ -168,6 +174,7 @@ class SourceWin(cui.TitledWin):
|
||||
def highlight(self, source):
|
||||
if self.lexer and self.formatter:
|
||||
from pygments import highlight
|
||||
|
||||
return highlight(source, self.lexer, self.formatter)
|
||||
else:
|
||||
return source
|
||||
@ -202,9 +209,8 @@ class SourceWin(cui.TitledWin):
|
||||
# hack! getting the LineEntry via SBBreakpointLocation.GetAddress.GetLineEntry does not work good for
|
||||
# inlined frames, so we get the description (which does take
|
||||
# into account inlined functions) and parse it.
|
||||
desc = lldbutil.get_description(
|
||||
location, lldb.eDescriptionLevelFull)
|
||||
match = re.search('at\ ([^:]+):([\d]+)', desc)
|
||||
desc = lldbutil.get_description(location, lldb.eDescriptionLevelFull)
|
||||
match = re.search("at\ ([^:]+):([\d]+)", desc)
|
||||
try:
|
||||
path = match.group(1)
|
||||
line = int(match.group(2).strip())
|
||||
@ -219,20 +225,26 @@ class SourceWin(cui.TitledWin):
|
||||
return locs
|
||||
|
||||
event_type = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event)
|
||||
if event_type == lldb.eBreakpointEventTypeEnabled \
|
||||
or event_type == lldb.eBreakpointEventTypeAdded \
|
||||
or event_type == lldb.eBreakpointEventTypeLocationsResolved \
|
||||
or event_type == lldb.eBreakpointEventTypeLocationsAdded:
|
||||
if (
|
||||
event_type == lldb.eBreakpointEventTypeEnabled
|
||||
or event_type == lldb.eBreakpointEventTypeAdded
|
||||
or event_type == lldb.eBreakpointEventTypeLocationsResolved
|
||||
or event_type == lldb.eBreakpointEventTypeLocationsAdded
|
||||
):
|
||||
self.addBPLocations(getLocations(event))
|
||||
elif event_type == lldb.eBreakpointEventTypeRemoved \
|
||||
or event_type == lldb.eBreakpointEventTypeLocationsRemoved \
|
||||
or event_type == lldb.eBreakpointEventTypeDisabled:
|
||||
elif (
|
||||
event_type == lldb.eBreakpointEventTypeRemoved
|
||||
or event_type == lldb.eBreakpointEventTypeLocationsRemoved
|
||||
or event_type == lldb.eBreakpointEventTypeDisabled
|
||||
):
|
||||
self.removeBPLocations(getLocations(event))
|
||||
elif event_type == lldb.eBreakpointEventTypeCommandChanged \
|
||||
or event_type == lldb.eBreakpointEventTypeConditionChanged \
|
||||
or event_type == lldb.eBreakpointEventTypeIgnoreChanged \
|
||||
or event_type == lldb.eBreakpointEventTypeThreadChanged \
|
||||
or event_type == lldb.eBreakpointEventTypeInvalidType:
|
||||
elif (
|
||||
event_type == lldb.eBreakpointEventTypeCommandChanged
|
||||
or event_type == lldb.eBreakpointEventTypeConditionChanged
|
||||
or event_type == lldb.eBreakpointEventTypeIgnoreChanged
|
||||
or event_type == lldb.eBreakpointEventTypeThreadChanged
|
||||
or event_type == lldb.eBreakpointEventTypeInvalidType
|
||||
):
|
||||
# no-op
|
||||
pass
|
||||
self.refreshSource()
|
||||
|
@ -13,19 +13,19 @@ import curses
|
||||
|
||||
|
||||
class StatusWin(cui.TextWin):
|
||||
|
||||
def __init__(self, x, y, w, h):
|
||||
super(StatusWin, self).__init__(x, y, w)
|
||||
|
||||
self.keys = [ # ('F1', 'Help', curses.KEY_F1),
|
||||
('F3', 'Cycle-focus', curses.KEY_F3),
|
||||
('F10', 'Quit', curses.KEY_F10)]
|
||||
("F3", "Cycle-focus", curses.KEY_F3),
|
||||
("F10", "Quit", curses.KEY_F10),
|
||||
]
|
||||
|
||||
def draw(self):
|
||||
self.win.addstr(0, 0, '')
|
||||
self.win.addstr(0, 0, "")
|
||||
for key in self.keys:
|
||||
self.win.addstr('{0}'.format(key[0]), curses.A_REVERSE)
|
||||
self.win.addstr(' {0} '.format(key[1]), curses.A_NORMAL)
|
||||
self.win.addstr("{0}".format(key[0]), curses.A_REVERSE)
|
||||
self.win.addstr(" {0} ".format(key[1]), curses.A_NORMAL)
|
||||
super(StatusWin, self).draw()
|
||||
|
||||
def handleEvent(self, event):
|
||||
|
Loading…
x
Reference in New Issue
Block a user