[lldb] Format Python files in scripts and utils (#66053)

Using:
black --exclude "third_party/" ./lldb/
This commit is contained in:
David Spickett 2023-09-14 08:54:02 +01:00 committed by GitHub
parent a1ef5a9437
commit 602e47c5f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 751 additions and 610 deletions

View File

@ -10,12 +10,21 @@ from collections import defaultdict
from use_lldb_suite import lldb_root from use_lldb_suite import lldb_root
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Analyze LLDB project #include dependencies.') 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(
parser.add_argument('--discover-cycles', default=False, action='store_true', "--show-counts",
help='When true, find and display all project dependency cycles. Note,' default=False,
'this option is very slow') 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() args = parser.parse_args()
@ -24,12 +33,14 @@ inc_dir = os.path.join(lldb_root, "include")
src_map = {} src_map = {}
include_regex = re.compile('#include \"((lldb|Plugins|clang)(.*/)+).*\"') include_regex = re.compile('#include "((lldb|Plugins|clang)(.*/)+).*"')
def is_sublist(small, big): def is_sublist(small, big):
it = iter(big) it = iter(big)
return all(c in it for c in small) return all(c in it for c in small)
def normalize_host(str): def normalize_host(str):
if str.startswith("lldb/Host"): if str.startswith("lldb/Host"):
return "lldb/Host" return "lldb/Host"
@ -39,6 +50,7 @@ def normalize_host(str):
return str.replace("lldb/../../source", "lldb") return str.replace("lldb/../../source", "lldb")
return str return str
def scan_deps(this_dir, file): def scan_deps(this_dir, file):
global src_map global src_map
deps = {} deps = {}
@ -62,7 +74,8 @@ def scan_deps(this_dir, file):
if this_dir not in src_map and len(deps) > 0: if this_dir not in src_map and len(deps) > 0:
src_map[this_dir] = deps 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) dir = os.path.basename(base)
relative = os.path.relpath(base, inc_dir) relative = os.path.relpath(base, inc_dir)
inc_files = [x for x in files if os.path.splitext(x)[1] in [".h"]] 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) inc_path = os.path.join(base, inc)
scan_deps(relative, inc_path) 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) dir = os.path.basename(base)
relative = os.path.relpath(base, src_dir) relative = os.path.relpath(base, src_dir)
src_files = [x for x in files if os.path.splitext(x)[1] in [".cpp", ".h", ".mm"]] 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) scan_deps(norm_base_path, src_path)
pass pass
def is_existing_cycle(path, cycles): def is_existing_cycle(path, cycles):
# If we have a cycle like # A -> B -> C (with an implicit -> A at the end) # 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 # 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 # 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 # optimization which reduces the search space by multiple orders of
# magnitude. # 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): if any(is_sublist(x, path) for x in cycles):
return True return True
path = [path[-1]] + path[0:-1] path = [path[-1]] + path[0:-1]
return False return False
def expand(path_queue, path_lengths, cycles, src_map): def expand(path_queue, path_lengths, cycles, src_map):
# We do a breadth first search, to make sure we visit all paths in order # 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 # 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]) path_queue.append(cur_path + [item])
pass pass
cycles = [] cycles = []
path_queue = [[x] for x in iter(src_map)] path_queue = [[x] for x in iter(src_map)]
path_lens = [1] * len(path_queue) path_lens = [1] * len(path_queue)
items = list(src_map.items()) 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 + ":") print(path + ":")
sorted_deps = list(deps.items()) sorted_deps = list(deps.items())
if args.show_counts: 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: for dep in sorted_deps:
print("\t{} [{}]".format(dep[0], dep[1])) print("\t{} [{}]".format(dep[0], dep[1]))
else: else:
sorted_deps.sort(key = lambda A: A[0]) sorted_deps.sort(key=lambda A: A[0])
for dep in sorted_deps: for dep in sorted_deps:
print("\t{}".format(dep[0])) print("\t{}".format(dep[0]))
def iter_cycles(cycles): def iter_cycles(cycles):
global src_map global src_map
for cycle in cycles: for cycle in cycles:
cycle.append(cycle[0]) cycle.append(cycle[0])
zipper = list(zip(cycle[0:-1], cycle[1:])) 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 total = 0
smallest = result[0][1] smallest = result[0][1]
for (first, value, last) in result: for first, value, last in result:
total += value total += value
smallest = min(smallest, value) smallest = min(smallest, value)
yield (total, smallest, result) yield (total, smallest, result)
if args.discover_cycles: if args.discover_cycles:
print("Analyzing cycles...") print("Analyzing cycles...")
expand(path_queue, path_lens, cycles, src_map) 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)) print("Found {} cycles. Average cycle length = {}.".format(len(cycles), average))
counted = list(iter_cycles(cycles)) counted = list(iter_cycles(cycles))
if args.show_counts: if args.show_counts:
counted.sort(key = lambda A: A[0]) counted.sort(key=lambda A: A[0])
for (total, smallest, cycle) in counted: for total, smallest, cycle in counted:
sys.stdout.write("{} deps to break: ".format(total)) sys.stdout.write("{} deps to break: ".format(total))
sys.stdout.write(cycle[0][0]) 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(" [{}->] {}".format(count, last))
sys.stdout.write("\n") sys.stdout.write("\n")
else: else:
@ -186,8 +204,8 @@ if args.discover_cycles:
islands = [] islands = []
outgoing_counts = defaultdict(int) outgoing_counts = defaultdict(int)
incoming_counts = defaultdict(int) incoming_counts = defaultdict(int)
for (total, smallest, cycle) in counted: for total, smallest, cycle in counted:
for (first, count, last) in cycle: for first, count, last in cycle:
outgoing_counts[first] += count outgoing_counts[first] += count
incoming_counts[last] += count incoming_counts[last] += count
for cycle in cycles: for cycle in cycles:
@ -201,8 +219,8 @@ if args.discover_cycles:
sorted = [] sorted = []
for node in island: for node in island:
sorted.append((node, incoming_counts[node], outgoing_counts[node])) sorted.append((node, incoming_counts[node], outgoing_counts[node]))
sorted.sort(key = lambda x: x[1]+x[2]) sorted.sort(key=lambda x: x[1] + x[2])
for (node, inc, outg) in sorted: for node, inc, outg in sorted:
print(" {} [{} in, {} out]".format(node, inc, outg)) print(" {} [{} in, {} out]".format(node, inc, outg))
sys.stdout.flush() sys.stdout.flush()
pass pass

View File

@ -20,45 +20,59 @@ def host_art_bt(debugger, command, result, internal_dict):
thread = process.GetSelectedThread() thread = process.GetSelectedThread()
while lldb_frame_index < thread.GetNumFrames(): while lldb_frame_index < thread.GetNumFrames():
frame = thread.GetFrameAtIndex(lldb_frame_index) frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetModule() and re.match(r'JIT\(.*?\)', if frame.GetModule() and re.match(
frame.GetModule().GetFileSpec().GetFilename()): r"JIT\(.*?\)", frame.GetModule().GetFileSpec().GetFilename()
):
# Compiled Java frame # Compiled Java frame
# Get function/filename/lineno from symbol context # Get function/filename/lineno from symbol context
symbol = frame.GetSymbol() symbol = frame.GetSymbol()
if not symbol: if not symbol:
print('No symbol info for compiled Java frame: ', frame) print("No symbol info for compiled Java frame: ", frame)
sys.exit(1) sys.exit(1)
line_entry = frame.GetLineEntry() line_entry = frame.GetLineEntry()
prettified_frames.append({ prettified_frames.append(
'function': symbol.GetName(), {
'file': str(line_entry.GetFileSpec()) if line_entry else None, "function": symbol.GetName(),
'line': line_entry.GetLine() if line_entry else -1 "file": str(line_entry.GetFileSpec()) if line_entry else None,
}) "line": line_entry.GetLine() if line_entry else -1,
}
)
# Skip art frames # Skip art frames
while True: while True:
art_stack_visitor = frame.EvaluateExpression( 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(""" + """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) + + str(art_frame_index)
"""); visitor.WalkStack(true); visitor""") + """); visitor.WalkStack(true); visitor"""
)
art_method = frame.EvaluateExpression( art_method = frame.EvaluateExpression(
art_stack_visitor.GetName() + """.GetMethod()""") art_stack_visitor.GetName() + """.GetMethod()"""
)
if art_method.GetValueAsUnsigned() != 0: if art_method.GetValueAsUnsigned() != 0:
art_method_name = frame.EvaluateExpression( 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_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_size = frame.EvaluateExpression(
art_method_name.GetName() + """.length()""").GetValueAsUnsigned() art_method_name.GetName() + """.length()"""
).GetValueAsUnsigned()
error = lldb.SBError() error = lldb.SBError()
art_method_name = process.ReadCStringFromMemory( 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: if not error.Success:
print('Failed to read method name') print("Failed to read method name")
sys.exit(1) sys.exit(1)
if art_method_name != symbol.GetName(): 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 art_frame_index = art_frame_index + 1
break break
art_frame_index = art_frame_index + 1 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(): if lldb_frame_index < thread.GetNumFrames():
frame = thread.GetFrameAtIndex(lldb_frame_index) frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetModule() and re.match( if frame.GetModule() and re.match(
r'JIT\(.*?\)', frame.GetModule().GetFileSpec().GetFilename()): r"JIT\(.*?\)", frame.GetModule().GetFileSpec().GetFilename()
):
# Another compile Java frame # Another compile Java frame
# Don't skip; leave it to the next iteration # Don't skip; leave it to the next iteration
continue 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 # art_quick_invoke_stub / art_quick_invoke_static_stub
# Skip until we get past the next ArtMethod::Invoke() # Skip until we get past the next ArtMethod::Invoke()
while True: while True:
lldb_frame_index = lldb_frame_index + 1 lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames(): 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) sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index) frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and frame.GetSymbol().GetName( if (
) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)': 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 lldb_frame_index = lldb_frame_index + 1
break break
else: else:
print('Invalid frame below compiled Java frame: ', frame) print("Invalid frame below compiled Java frame: ", frame)
elif frame.GetSymbol() and frame.GetSymbol().GetName() == 'art_quick_generic_jni_trampoline': elif (
frame.GetSymbol()
and frame.GetSymbol().GetName() == "art_quick_generic_jni_trampoline"
):
# Interpreted JNI frame for x86_64 # Interpreted JNI frame for x86_64
# Skip art frames # Skip art frames
while True: while True:
art_stack_visitor = frame.EvaluateExpression( 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(""" + """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) + + str(art_frame_index)
"""); visitor.WalkStack(true); visitor""") + """); visitor.WalkStack(true); visitor"""
)
art_method = frame.EvaluateExpression( art_method = frame.EvaluateExpression(
art_stack_visitor.GetName() + """.GetMethod()""") art_stack_visitor.GetName() + """.GetMethod()"""
)
if art_method.GetValueAsUnsigned() != 0: if art_method.GetValueAsUnsigned() != 0:
# Get function/filename/lineno from ART runtime # Get function/filename/lineno from ART runtime
art_method_name = frame.EvaluateExpression( 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_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_size = frame.EvaluateExpression(
art_method_name.GetName() + """.length()""").GetValueAsUnsigned() art_method_name.GetName() + """.length()"""
).GetValueAsUnsigned()
error = lldb.SBError() error = lldb.SBError()
function = process.ReadCStringFromMemory( 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({ prettified_frames.append(
'function': function, {"function": function, "file": None, "line": -1}
'file': None, )
'line': -1
})
art_frame_index = art_frame_index + 1 art_frame_index = art_frame_index + 1
break break
@ -124,78 +154,98 @@ def host_art_bt(debugger, command, result, internal_dict):
lldb_frame_index = lldb_frame_index + 1 lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index < thread.GetNumFrames(): if lldb_frame_index < thread.GetNumFrames():
frame = thread.GetFrameAtIndex(lldb_frame_index) frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and (frame.GetSymbol().GetName() == if frame.GetSymbol() and (
'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'): 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 # art_quick_invoke_stub / art_quick_invoke_static_stub
# Skip until we get past the next ArtMethod::Invoke() # Skip until we get past the next ArtMethod::Invoke()
while True: while True:
lldb_frame_index = lldb_frame_index + 1 lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames(): 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) sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index) frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and frame.GetSymbol().GetName( if (
) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)': 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 lldb_frame_index = lldb_frame_index + 1
break break
else: else:
print('Invalid frame below compiled Java frame: ', frame) print("Invalid frame below compiled Java frame: ", frame)
elif frame.GetSymbol() and re.search(r'art::interpreter::', frame.GetSymbol().GetName()): elif frame.GetSymbol() and re.search(
r"art::interpreter::", frame.GetSymbol().GetName()
):
# Interpreted Java frame # Interpreted Java frame
while True: while True:
lldb_frame_index = lldb_frame_index + 1 lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames(): 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) sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index) frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and frame.GetSymbol().GetName( if (
) == 'art::interpreter::Execute(art::Thread*, art::MethodHelper&, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)': frame.GetSymbol()
and frame.GetSymbol().GetName()
== "art::interpreter::Execute(art::Thread*, art::MethodHelper&, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)"
):
break break
# Skip art frames # Skip art frames
while True: while True:
art_stack_visitor = frame.EvaluateExpression( 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(""" + """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) + + str(art_frame_index)
"""); visitor.WalkStack(true); visitor""") + """); visitor.WalkStack(true); visitor"""
)
art_method = frame.EvaluateExpression( art_method = frame.EvaluateExpression(
art_stack_visitor.GetName() + """.GetMethod()""") art_stack_visitor.GetName() + """.GetMethod()"""
)
if art_method.GetValueAsUnsigned() != 0: if art_method.GetValueAsUnsigned() != 0:
# Get function/filename/lineno from ART runtime # Get function/filename/lineno from ART runtime
art_method_name = frame.EvaluateExpression( 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_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_size = frame.EvaluateExpression(
art_method_name.GetName() + """.length()""").GetValueAsUnsigned() art_method_name.GetName() + """.length()"""
).GetValueAsUnsigned()
error = lldb.SBError() error = lldb.SBError()
function = process.ReadCStringFromMemory( 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( line = frame.EvaluateExpression(
art_stack_visitor.GetName() + art_stack_visitor.GetName()
""".GetMethod()->GetLineNumFromDexPC(""" + + """.GetMethod()->GetLineNumFromDexPC("""
art_stack_visitor.GetName() + + art_stack_visitor.GetName()
""".GetDexPc(true))""").GetValueAsUnsigned() + """.GetDexPc(true))"""
).GetValueAsUnsigned()
file_name = frame.EvaluateExpression( file_name = frame.EvaluateExpression(
art_method.GetName() + """->GetDeclaringClassSourceFile()""") art_method.GetName() + """->GetDeclaringClassSourceFile()"""
)
file_name_data = file_name.GetValueAsUnsigned() file_name_data = file_name.GetValueAsUnsigned()
file_name_size = frame.EvaluateExpression( file_name_size = frame.EvaluateExpression(
"""(size_t)strlen(""" + file_name.GetName() + """)""").GetValueAsUnsigned() """(size_t)strlen(""" + file_name.GetName() + """)"""
).GetValueAsUnsigned()
error = lldb.SBError() error = lldb.SBError()
file_name = process.ReadCStringFromMemory( file_name = process.ReadCStringFromMemory(
file_name_data, file_name_size + 1, error) file_name_data, file_name_size + 1, error
)
if not error.Success(): if not error.Success():
print('Failed to read source file name') print("Failed to read source file name")
sys.exit(1) sys.exit(1)
prettified_frames.append({ prettified_frames.append(
'function': function, {"function": function, "file": file_name, "line": line}
'file': file_name, )
'line': line
})
art_frame_index = art_frame_index + 1 art_frame_index = art_frame_index + 1
break break
@ -205,11 +255,12 @@ def host_art_bt(debugger, command, result, internal_dict):
while True: while True:
lldb_frame_index = lldb_frame_index + 1 lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames(): 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) sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index) frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and not re.search( if frame.GetSymbol() and not re.search(
r'art::interpreter::', frame.GetSymbol().GetName()): r"art::interpreter::", frame.GetSymbol().GetName()
):
break break
else: else:
# Other frames. Add them as-is. # Other frames. Add them as-is.
@ -218,20 +269,32 @@ def host_art_bt(debugger, command, result, internal_dict):
if frame.GetModule(): if frame.GetModule():
module_name = frame.GetModule().GetFileSpec().GetFilename() module_name = frame.GetModule().GetFileSpec().GetFilename()
if not module_name in [ if not module_name in [
'libartd.so', "libartd.so",
'dalvikvm32', "dalvikvm32",
'dalvikvm64', "dalvikvm64",
'libc.so.6']: "libc.so.6",
prettified_frames.append({ ]:
'function': frame.GetSymbol().GetName() if frame.GetSymbol() else None, prettified_frames.append(
'file': str(frame.GetLineEntry().GetFileSpec()) if frame.GetLineEntry() else None, {
'line': frame.GetLineEntry().GetLine() if frame.GetLineEntry() else -1 "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: 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): def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand( debugger.HandleCommand("command script add -f host_art_bt.host_art_bt host_art_bt")
'command script add -f host_art_bt.host_art_bt host_art_bt')

View File

@ -30,122 +30,112 @@ import sys
def copy_one_file(dest_dir, source_dir, filename): def copy_one_file(dest_dir, source_dir, filename):
source_path = os.path.join(source_dir, filename) source_path = os.path.join(source_dir, filename)
dest_path = os.path.join(dest_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) shutil.copyfile(source_path, dest_path)
def copy_named_files( def copy_named_files(dest_dir, source_dir, files, extensions, copy_debug_suffix_also):
dest_dir, for file, ext in itertools.product(files, extensions):
source_dir, copy_one_file(dest_dir, source_dir, file + "." + ext)
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: 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): def copy_subdirectory(dest_dir, source_dir, subdir):
dest_dir = os.path.join(dest_dir, subdir) dest_dir = os.path.join(dest_dir, subdir)
source_dir = os.path.join(source_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) shutil.copytree(source_dir, dest_dir)
def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix): def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix):
dest_dir = os.path.join(dest_dir, dest_subdir) 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) os.mkdir(dest_dir)
PCbuild_dir = os.path.join(source_dir, 'PCbuild') PCbuild_dir = os.path.join(source_dir, "PCbuild")
if source_prefix: if source_prefix:
PCbuild_dir = os.path.join(PCbuild_dir, 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 # First copy the files that go into the root of the new distribution. This
# includes the Python executables, python27(_d).dll, and relevant PDB # includes the Python executables, python27(_d).dll, and relevant PDB
# files. # 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( copy_named_files(
dest_dir, PCbuild_dir, ['w9xpopen'], [ dest_dir, PCbuild_dir, ["python", "pythonw"], ["exe", "pdb"], False
'exe', 'pdb'], False) )
copy_named_files( copy_named_files(dest_dir, PCbuild_dir, ["python27"], ["dll", "pdb"], True)
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)
# Next copy everything in the Include directory. # Next copy everything in the Include directory.
print('Copying Python include directory') print("Copying Python include directory")
copy_subdirectory(dest_dir, source_dir, 'Include') copy_subdirectory(dest_dir, source_dir, "Include")
# Copy Lib folder (builtin Python modules) # Copy Lib folder (builtin Python modules)
print('Copying Python Lib directory') print("Copying Python Lib directory")
copy_subdirectory(dest_dir, source_dir, 'Lib') copy_subdirectory(dest_dir, source_dir, "Lib")
# Copy tools folder. These are probably not necessary, but we copy them anyway to # 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 # 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 # 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 # than what you get by installing python regularly. We only copy the tools that appear
# in an installed distribution. # in an installed distribution.
tools_dest_dir = os.path.join(dest_dir, 'Tools') tools_dest_dir = os.path.join(dest_dir, "Tools")
tools_source_dir = os.path.join(source_dir, 'Tools') tools_source_dir = os.path.join(source_dir, "Tools")
os.mkdir(tools_dest_dir) os.mkdir(tools_dest_dir)
copy_subdirectory(tools_dest_dir, tools_source_dir, 'i18n') 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, "pynche")
copy_subdirectory(tools_dest_dir, tools_source_dir, 'scripts') 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, "versioncheck")
copy_subdirectory(tools_dest_dir, tools_source_dir, 'webchecker') copy_subdirectory(tools_dest_dir, tools_source_dir, "webchecker")
pyd_names = [ pyd_names = [
'_ctypes', "_ctypes",
'_ctypes_test', "_ctypes_test",
'_elementtree', "_elementtree",
'_multiprocessing', "_multiprocessing",
'_socket', "_socket",
'_testcapi', "_testcapi",
'pyexpat', "pyexpat",
'select', "select",
'unicodedata', "unicodedata",
'winsound'] "winsound",
]
# Copy builtin extension modules (pyd files) # 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) os.mkdir(dlls_dir)
print('Copying DLLs directory') print("Copying DLLs directory")
copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ['pyd', 'pdb'], True) copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ["pyd", "pdb"], True)
# Copy libs folder (implibs for the pyd files) # 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) os.mkdir(libs_dir)
print('Copying libs directory') print("Copying libs directory")
copy_named_files(libs_dir, PCbuild_dir, pyd_names, ['lib'], False) copy_named_files(libs_dir, PCbuild_dir, pyd_names, ["lib"], False)
copy_named_files(libs_dir, PCbuild_dir, ['python27'], ['lib'], True) copy_named_files(libs_dir, PCbuild_dir, ["python27"], ["lib"], True)
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(description="Install a custom Python distribution")
description='Install a custom Python distribution')
parser.add_argument( parser.add_argument(
'--source', "--source", required=True, help="The root of the source tree where Python is built."
required=True, )
help='The root of the source tree where Python is built.')
parser.add_argument( parser.add_argument(
'--dest', "--dest", required=True, help="The location to install the Python distributions."
required=True, )
help='The location to install the Python distributions.')
parser.add_argument( parser.add_argument(
'--overwrite', "--overwrite",
default=False, default=False,
action='store_true', action="store_true",
help='If the destination directory already exists, destroys its contents first.') help="If the destination directory already exists, destroys its contents first.",
)
parser.add_argument( parser.add_argument(
'--silent', "--silent",
default=False, default=False,
action='store_true', action="store_true",
help='If --overwite was specified, suppress confirmation before deleting a directory tree.') help="If --overwite was specified, suppress confirmation before deleting a directory tree.",
)
args = parser.parse_args() args = parser.parse_args()
@ -153,23 +143,31 @@ args.source = os.path.normpath(args.source)
args.dest = os.path.normpath(args.dest) args.dest = os.path.normpath(args.dest)
if not os.path.exists(args.source): 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) sys.exit(1)
if os.path.exists(args.dest): if os.path.exists(args.dest):
if not args.overwrite: 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) sys.exit(1)
while not args.silent: 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)) result = str.upper(sys.stdin.read(1))
if result == 'N': if result == "N":
print('Unable to copy files to the destination. The destination already exists.') print(
"Unable to copy files to the destination. The destination already exists."
)
sys.exit(1) sys.exit(1)
elif result == 'Y': elif result == "Y":
break break
shutil.rmtree(args.dest) shutil.rmtree(args.dest)
os.mkdir(args.dest) os.mkdir(args.dest)
copy_distro(args.dest, 'x86', args.source, None) copy_distro(args.dest, "x86", args.source, None)
copy_distro(args.dest, 'x64', args.source, 'amd64') copy_distro(args.dest, "x64", args.source, "amd64")

View File

@ -10,39 +10,39 @@ import subprocess
def run_reproducer(path): def run_reproducer(path):
proc = subprocess.Popen([LLDB, '--replay', path], proc = subprocess.Popen(
stdout=subprocess.PIPE, [LLDB, "--replay", path], stdout=subprocess.PIPE, stderr=subprocess.PIPE
stderr=subprocess.PIPE) )
reason = None reason = None
try: try:
outs, errs = proc.communicate(timeout=TIMEOUT) outs, errs = proc.communicate(timeout=TIMEOUT)
success = proc.returncode == 0 success = proc.returncode == 0
result = 'PASSED' if success else 'FAILED' result = "PASSED" if success else "FAILED"
if not success: if not success:
outs = outs.decode() outs = outs.decode()
errs = errs.decode() errs = errs.decode()
# Do some pattern matching to find out the cause of the failure. # Do some pattern matching to find out the cause of the failure.
if 'Encountered unexpected packet during replay' in errs: if "Encountered unexpected packet during replay" in errs:
reason = 'Unexpected packet' reason = "Unexpected packet"
elif 'Assertion failed' in errs: elif "Assertion failed" in errs:
reason = 'Assertion failed' reason = "Assertion failed"
elif 'UNREACHABLE' in errs: elif "UNREACHABLE" in errs:
reason = 'Unreachable executed' reason = "Unreachable executed"
elif 'Segmentation fault' in errs: elif "Segmentation fault" in errs:
reason = 'Segmentation fault' reason = "Segmentation fault"
elif 'Illegal instruction' in errs: elif "Illegal instruction" in errs:
reason = 'Illegal instruction' reason = "Illegal instruction"
else: else:
reason = f'Exit code {proc.returncode}' reason = f"Exit code {proc.returncode}"
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
proc.kill() proc.kill()
success = False success = False
outs, errs = proc.communicate() outs, errs = proc.communicate()
result = 'TIMEOUT' result = "TIMEOUT"
if not FAILURE_ONLY or not success: if not FAILURE_ONLY or not success:
reason_str = f' ({reason})' if reason else '' reason_str = f" ({reason})" if reason else ""
print(f'{result}: {path}{reason_str}') print(f"{result}: {path}{reason_str}")
if VERBOSE: if VERBOSE:
if outs: if outs:
print(outs) print(outs)
@ -54,49 +54,51 @@ def find_reproducers(path):
for root, dirs, files in os.walk(path): for root, dirs, files in os.walk(path):
for dir in dirs: for dir in dirs:
_, extension = os.path.splitext(dir) _, 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) yield os.path.join(root, dir)
if __name__ == '__main__': if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='LLDB API Test Replay Driver. ' description="LLDB API Test Replay Driver. "
'Replay one or more reproducers in parallel using the specified LLDB 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. ' "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.' "To generate the reproducers, pass --param 'lldb-run-with-repro=capture' to lit."
) )
parser.add_argument( parser.add_argument(
'-j', "-j",
'--threads', "--threads",
type=int, type=int,
default=multiprocessing.cpu_count(), 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( parser.add_argument(
'-t', "-t",
'--timeout', "--timeout",
type=int, type=int,
default=60, 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( parser.add_argument(
'-p', "-p",
'--path', "--path",
type=str, type=str,
default=os.getcwd(), default=os.getcwd(),
help= help="Path to the directory containing the reproducers. The current working directory if not specified.",
'Path to the directory containing the reproducers. The current working directory if not specified.'
) )
parser.add_argument('-l', parser.add_argument(
'--lldb', "-l",
"--lldb",
type=str, type=str,
required=True, required=True,
help='Path to the LLDB command line driver') help="Path to the LLDB command line driver",
parser.add_argument('-v', )
'--verbose', parser.add_argument(
help='Print replay output.', "-v", "--verbose", help="Print replay output.", action="store_true"
action='store_true') )
parser.add_argument('--failure-only', parser.add_argument(
help='Only log failures.', "--failure-only", help="Only log failures.", action="store_true"
action='store_true') )
args = parser.parse_args() args = parser.parse_args()
global LLDB global LLDB
@ -109,11 +111,11 @@ if __name__ == '__main__':
FAILURE_ONLY = args.failure_only FAILURE_ONLY = args.failure_only
print( 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: try:
pool = Pool(args.threads) pool = Pool(args.threads)
pool.map(run_reproducer, find_reproducers(args.path)) pool.map(run_reproducer, find_reproducers(args.path))
except KeyboardInterrupt: except KeyboardInterrupt:
print('Interrupted') print("Interrupted")

View File

@ -15,8 +15,10 @@ def find_lldb_root():
if os.path.isfile(test_path): if os.path.isfile(test_path):
return lldb_root return lldb_root
lldb_root = find_lldb_root() lldb_root = find_lldb_root()
import imp import imp
fp, pathname, desc = imp.find_module("use_lldb_suite_root", [lldb_root]) fp, pathname, desc = imp.find_module("use_lldb_suite_root", [lldb_root])
try: try:
imp.load_module("use_lldb_suite_root", fp, pathname, desc) imp.load_module("use_lldb_suite_root", fp, pathname, desc)

View File

@ -10,58 +10,67 @@ import sys
def extract_exe_symbol_names(arch, exe_path, match_str): def extract_exe_symbol_names(arch, exe_path, match_str):
command = 'dsymutil --arch %s -s "%s" | grep "%s" | colrm 1 69' % ( 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) (command_exit_status, command_output) = subprocess.getstatusoutput(command)
if command_exit_status == 0: if command_exit_status == 0:
if command_output: if command_output:
return command_output[0:-1].split("'\n") return command_output[0:-1].split("'\n")
else: else:
print('error: command returned no output') print("error: command returned no output")
else: 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() return list()
def verify_api(all_args): 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 ...]" 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: 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 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( parser = optparse.OptionParser(
description=description, description=description, prog="verify_api", usage=usage
prog='verify_api', )
usage=usage)
parser.add_option( parser.add_option(
'-v', "-v",
'--verbose', "--verbose",
action='store_true', action="store_true",
dest='verbose', dest="verbose",
help='display verbose debug info', help="display verbose debug info",
default=False) default=False,
)
parser.add_option( parser.add_option(
'-a', "-a",
'--arch', "--arch",
type='string', type="string",
action='append', action="append",
dest='archs', dest="archs",
help='architecture to use when checking the api') help="architecture to use when checking the api",
)
parser.add_option( parser.add_option(
'-r', "-r",
'--api-regex', "--api-regex",
type='string', type="string",
dest='api_regex_str', dest="api_regex_str",
help='Exclude any undefined symbols that do not match this regular expression when searching for missing APIs.') help="Exclude any undefined symbols that do not match this regular expression when searching for missing APIs.",
)
parser.add_option( parser.add_option(
'-l', "-l",
'--library', "--library",
type='string', type="string",
action='append', action="append",
dest='libraries', dest="libraries",
help='Specify one or more libraries that will contain all needed APIs for the executables.') help="Specify one or more libraries that will contain all needed APIs for the executables.",
)
(options, args) = parser.parse_args(all_args) (options, args) = parser.parse_args(all_args)
api_external_symbols = list() api_external_symbols = list()
@ -69,18 +78,19 @@ def verify_api(all_args):
for arch in options.archs: for arch in options.archs:
for library in options.libraries: for library in options.libraries:
external_symbols = extract_exe_symbol_names( external_symbols = extract_exe_symbol_names(
arch, library, "( SECT EXT)") arch, library, "( SECT EXT)"
)
if external_symbols: if external_symbols:
for external_symbol in external_symbols: for external_symbol in external_symbols:
api_external_symbols.append(external_symbol) api_external_symbols.append(external_symbol)
else: else:
sys.exit(1) sys.exit(1)
else: 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) sys.exit(4)
if options.verbose: if options.verbose:
print("API symbols:") 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)) print("[%u] %s" % (i, external_symbol))
api_regex = None api_regex = None
@ -92,24 +102,29 @@ def verify_api(all_args):
print('Verifying (%s) "%s"...' % (arch, exe_path)) print('Verifying (%s) "%s"...' % (arch, exe_path))
exe_errors = 0 exe_errors = 0
undefined_symbols = extract_exe_symbol_names( undefined_symbols = extract_exe_symbol_names(
arch, exe_path, "( UNDF EXT)") arch, exe_path, "( UNDF EXT)"
)
for undefined_symbol in undefined_symbols: for undefined_symbol in undefined_symbols:
if api_regex: if api_regex:
match = api_regex.search(undefined_symbol) match = api_regex.search(undefined_symbol)
if not match: if not match:
if options.verbose: if options.verbose:
print('ignoring symbol: %s' % (undefined_symbol)) print("ignoring symbol: %s" % (undefined_symbol))
continue continue
if undefined_symbol in api_external_symbols: if undefined_symbol in api_external_symbols:
if options.verbose: if options.verbose:
print('verified symbol: %s' % (undefined_symbol)) print("verified symbol: %s" % (undefined_symbol))
else: else:
print('missing symbol: %s' % (undefined_symbol)) print("missing symbol: %s" % (undefined_symbol))
exe_errors += 1 exe_errors += 1
if exe_errors: 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: else:
print('success') print("success")
if __name__ == '__main__':
if __name__ == "__main__":
verify_api(sys.argv[1:]) verify_api(sys.argv[1:])

View File

@ -34,23 +34,27 @@ def main():
# Compute an MD5 hash based on the input arguments and the current working # Compute an MD5 hash based on the input arguments and the current working
# directory. # directory.
h = hashlib.md5() h = hashlib.md5()
h.update(' '.join(sys.argv[2:]).encode('utf-8')) h.update(" ".join(sys.argv[2:]).encode("utf-8"))
h.update(os.getcwd().encode('utf-8')) h.update(os.getcwd().encode("utf-8"))
input_hash = h.hexdigest() input_hash = h.hexdigest()
# Use the hash to "uniquely" identify a reproducer path. # Use the hash to "uniquely" identify a reproducer path.
reproducer_path = os.path.join(tempfile.gettempdir(), input_hash) reproducer_path = os.path.join(tempfile.gettempdir(), input_hash)
# Create a new lldb invocation with capture or replay enabled. # 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] new_args = [lldb]
if sys.argv[1] == "replay": if sys.argv[1] == "replay":
new_args.extend(['--replay', reproducer_path]) new_args.extend(["--replay", reproducer_path])
elif sys.argv[1] == "capture": elif sys.argv[1] == "capture":
new_args.extend([ new_args.extend(
'--capture', '--capture-path', reproducer_path, [
'--reproducer-generate-on-exit' "--capture",
]) "--capture-path",
reproducer_path,
"--reproducer-generate-on-exit",
]
)
new_args.extend(sys.argv[2:]) new_args.extend(sys.argv[2:])
else: else:
help() help()
@ -60,10 +64,10 @@ def main():
# The driver always exists with a zero exit code during replay. Store the # 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 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": if sys.argv[1] == "replay":
replay_exit_code = exit_code 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()) exit_code = int(f.read())
if replay_exit_code != 0: if replay_exit_code != 0:
print("error: replay failed with exit code {}".format(replay_exit_code)) 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 return 1 if (exit_code == 0) else 0
shutil.rmtree(reproducer_path, True) shutil.rmtree(reproducer_path, True)
elif sys.argv[1] == "capture": elif sys.argv[1] == "capture":
with open(exit_code_path, 'w') as f: with open(exit_code_path, "w") as f:
f.write('%d' % exit_code) f.write("%d" % exit_code)
return exit_code return exit_code
if __name__ == '__main__': if __name__ == "__main__":
exit(main()) exit(main())

View File

@ -14,7 +14,6 @@ import re
class BreakWin(cui.ListWin): class BreakWin(cui.ListWin):
def __init__(self, driver, x, y, w, h): def __init__(self, driver, x, y, w, h):
super(BreakWin, self).__init__(x, y, w, h) super(BreakWin, self).__init__(x, y, w, h)
self.driver = driver self.driver = driver
@ -26,7 +25,7 @@ class BreakWin(cui.ListWin):
if lldb.SBBreakpoint.EventIsBreakpointEvent(event): if lldb.SBBreakpoint.EventIsBreakpointEvent(event):
self.update() self.update()
if isinstance(event, int): if isinstance(event, int):
if event == ord('d'): if event == ord("d"):
self.deleteSelected() self.deleteSelected()
if event == curses.ascii.NL or event == curses.ascii.SP: if event == curses.ascii.NL or event == curses.ascii.SP:
self.toggleSelected() self.toggleSelected()
@ -72,14 +71,14 @@ class BreakWin(cui.ListWin):
continue continue
text = lldbutil.get_description(bp) text = lldbutil.get_description(bp)
# FIXME: Use an API for this, not parsing the description. # FIXME: Use an API for this, not parsing the description.
match = re.search('SBBreakpoint: id = ([^,]+), (.*)', text) match = re.search("SBBreakpoint: id = ([^,]+), (.*)", text)
try: try:
id = match.group(1) id = match.group(1)
desc = match.group(2).strip() desc = match.group(2).strip()
if bp.IsEnabled(): if bp.IsEnabled():
text = '%s: %s' % (id, desc) text = "%s: %s" % (id, desc)
else: else:
text = '%s: (disabled) %s' % (id, desc) text = "%s: (disabled) %s" % (id, desc)
except ValueError as e: except ValueError as e:
# bp unparsable # bp unparsable
pass pass
@ -87,7 +86,8 @@ class BreakWin(cui.ListWin):
if self.showDetails.setdefault(bp.id, False): if self.showDetails.setdefault(bp.id, False):
for location in bp: for location in bp:
desc = lldbutil.get_description( desc = lldbutil.get_description(
location, lldb.eDescriptionLevelFull) location, lldb.eDescriptionLevelFull
text += '\n ' + desc )
text += "\n " + desc
self.addItem(text) self.addItem(text)
self.setSelected(selected) self.setSelected(selected)

View File

@ -13,21 +13,20 @@ from itertools import islice
class History(object): class History(object):
def __init__(self): def __init__(self):
self.data = {} self.data = {}
self.pos = 0 self.pos = 0
self.tempEntry = '' self.tempEntry = ""
def previous(self, curr): def previous(self, curr):
if self.pos == len(self.data): if self.pos == len(self.data):
self.tempEntry = curr self.tempEntry = curr
if self.pos < 0: if self.pos < 0:
return '' return ""
if self.pos == 0: if self.pos == 0:
self.pos -= 1 self.pos -= 1
return '' return ""
if self.pos > 0: if self.pos > 0:
self.pos -= 1 self.pos -= 1
return self.data[self.pos] return self.data[self.pos]
@ -38,13 +37,13 @@ class History(object):
if self.pos < len(self.data): if self.pos < len(self.data):
return self.data[self.pos] return self.data[self.pos]
elif self.tempEntry != '': elif self.tempEntry != "":
return self.tempEntry return self.tempEntry
else: else:
return '' return ""
def add(self, c): def add(self, c):
self.tempEntry = '' self.tempEntry = ""
self.pos = len(self.data) self.pos = len(self.data)
if self.pos == 0 or self.data[self.pos - 1] != c: if self.pos == 0 or self.data[self.pos - 1] != c:
self.data[self.pos] = c self.data[self.pos] = c
@ -52,7 +51,6 @@ class History(object):
class CommandWin(cui.TitledWin): class CommandWin(cui.TitledWin):
def __init__(self, driver, x, y, w, h): def __init__(self, driver, x, y, w, h):
super(CommandWin, self).__init__(x, y, w, h, "Commands") super(CommandWin, self).__init__(x, y, w, h, "Commands")
self.command = "" self.command = ""
@ -72,7 +70,8 @@ class CommandWin(cui.TitledWin):
matches = lldb.SBStringList() matches = lldb.SBStringList()
commandinterpreter = self.getCommandInterpreter() commandinterpreter = self.getCommandInterpreter()
commandinterpreter.HandleCompletion( commandinterpreter.HandleCompletion(
self.data, self.el.index, 0, -1, matches) self.data, self.el.index, 0, -1, matches
)
if matches.GetSize() == 2: if matches.GetSize() == 2:
self.el.content += matches.GetStringAtIndex(0) self.el.content += matches.GetStringAtIndex(0)
self.el.index = len(self.el.content) self.el.index = len(self.el.content)
@ -90,19 +89,17 @@ class CommandWin(cui.TitledWin):
self.startline = self.win.getmaxyx()[0] - 2 self.startline = self.win.getmaxyx()[0] - 2
self.el = cui.CursesEditLine( self.el = cui.CursesEditLine(
self.win, self.win, self.history, enterCallback, tabCompleteCallback
self.history, )
enterCallback,
tabCompleteCallback)
self.el.prompt = self.driver.getPrompt() self.el.prompt = self.driver.getPrompt()
self.el.showPrompt(self.startline, 0) self.el.showPrompt(self.startline, 0)
def handleCommand(self, cmd): def handleCommand(self, cmd):
# enter! # enter!
self.win.scroll(1) # TODO: scroll more for longer commands self.win.scroll(1) # TODO: scroll more for longer commands
if cmd == '': if cmd == "":
cmd = self.history.previous('') cmd = self.history.previous("")
elif cmd in ('q', 'quit'): elif cmd in ("q", "quit"):
self.driver.terminate() self.driver.terminate()
return return
@ -114,13 +111,13 @@ class CommandWin(cui.TitledWin):
else: else:
out = ret.GetError() out = ret.GetError()
attr = curses.color_pair(3) # red on black 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.win.scroll(1)
self.el.showPrompt(self.startline, 0) self.el.showPrompt(self.startline, 0)
def handleEvent(self, event): def handleEvent(self, event):
if isinstance(event, int): 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. # When the command is empty, treat CTRL-D as EOF.
self.driver.terminate() self.driver.terminate()
return return

View File

@ -12,7 +12,6 @@ import threading
class CursesWin(object): class CursesWin(object):
def __init__(self, x, y, w, h): def __init__(self, x, y, w, h):
self.win = curses.newwin(h, w, y, x) self.win = curses.newwin(h, w, y, x)
self.focus = False self.focus = False
@ -34,11 +33,10 @@ class CursesWin(object):
class TextWin(CursesWin): class TextWin(CursesWin):
def __init__(self, x, y, w): def __init__(self, x, y, w):
super(TextWin, self).__init__(x, y, w, 1) super(TextWin, self).__init__(x, y, w, 1)
self.win.bkgd(curses.color_pair(1)) self.win.bkgd(curses.color_pair(1))
self.text = '' self.text = ""
self.reverse = False self.reverse = False
def canFocus(self): def canFocus(self):
@ -48,8 +46,8 @@ class TextWin(CursesWin):
w = self.win.getmaxyx()[1] w = self.win.getmaxyx()[1]
text = self.text text = self.text
if len(text) > w: if len(text) > w:
#trunc_length = len(text) - w # trunc_length = len(text) - w
text = text[-w + 1:] text = text[-w + 1 :]
if self.reverse: if self.reverse:
self.win.addstr(0, 0, text, curses.A_REVERSE) self.win.addstr(0, 0, text, curses.A_REVERSE)
else: else:
@ -64,7 +62,6 @@ class TextWin(CursesWin):
class TitledWin(CursesWin): class TitledWin(CursesWin):
def __init__(self, x, y, w, h, title): def __init__(self, x, y, w, h, title):
super(TitledWin, self).__init__(x, y + 1, w, h - 1) super(TitledWin, self).__init__(x, y + 1, w, h - 1)
self.title = title self.title = title
@ -82,7 +79,6 @@ class TitledWin(CursesWin):
class ListWin(CursesWin): class ListWin(CursesWin):
def __init__(self, x, y, w, h): def __init__(self, x, y, w, h):
super(ListWin, self).__init__(x, y, w, h) super(ListWin, self).__init__(x, y, w, h)
self.items = [] self.items = []
@ -101,10 +97,10 @@ class ListWin(CursesWin):
firstSelected = -1 firstSelected = -1
lastSelected = -1 lastSelected = -1
for i, item in enumerate(self.items): for i, item in enumerate(self.items):
lines = self.items[i].split('\n') lines = self.items[i].split("\n")
lines = lines if lines[len(lines) - 1] != '' else lines[:-1] lines = lines if lines[len(lines) - 1] != "" else lines[:-1]
if len(lines) == 0: if len(lines) == 0:
lines = [''] lines = [""]
if i == self.getSelected(): if i == self.getSelected():
firstSelected = len(allLines) firstSelected = len(allLines)
@ -127,7 +123,7 @@ class ListWin(CursesWin):
attr = curses.A_NORMAL attr = curses.A_NORMAL
if i >= firstSelected and i <= lastSelected: if i >= firstSelected and i <= lastSelected:
attr = curses.A_REVERSE 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. # Ignore the error we get from drawing over the bottom-right char.
try: try:
@ -170,7 +166,6 @@ class ListWin(CursesWin):
class InputHandler(threading.Thread): class InputHandler(threading.Thread):
def __init__(self, screen, queue): def __init__(self, screen, queue):
super(InputHandler, self).__init__() super(InputHandler, self).__init__()
self.screen = screen self.screen = screen
@ -183,7 +178,7 @@ class InputHandler(threading.Thread):
class CursesUI(object): 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): def __init__(self, screen, event_queue):
self.screen = screen self.screen = screen
@ -220,7 +215,6 @@ class CursesUI(object):
self.focusNext() self.focusNext()
def eventLoop(self): def eventLoop(self):
self.input_handler.start() self.input_handler.start()
self.wins[self.focus].setFocus(True) self.wins[self.focus].setFocus(True)
@ -247,7 +241,7 @@ class CursesUI(object):
class CursesEditLine(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): def __init__(self, win, history, enterCallback, tabCompleteCallback):
self.win = win self.win = win
@ -255,8 +249,8 @@ class CursesEditLine(object):
self.enterCallback = enterCallback self.enterCallback = enterCallback
self.tabCompleteCallback = tabCompleteCallback self.tabCompleteCallback = tabCompleteCallback
self.prompt = '' self.prompt = ""
self.content = '' self.content = ""
self.index = 0 self.index = 0
self.startx = -1 self.startx = -1
self.starty = -1 self.starty = -1
@ -269,16 +263,16 @@ class CursesEditLine(object):
self.win.scroll(1) self.win.scroll(1)
self.starty -= 1 self.starty -= 1
if self.starty < 0: if self.starty < 0:
raise RuntimeError('Input too long; aborting') raise RuntimeError("Input too long; aborting")
(y, x) = (self.starty, self.startx) (y, x) = (self.starty, self.startx)
self.win.move(y, x) self.win.move(y, x)
self.win.clrtobot() self.win.clrtobot()
self.win.addstr(y, x, prompt) self.win.addstr(y, x, prompt)
remain = self.content remain = self.content
self.win.addstr(remain[:w - len(prompt)]) self.win.addstr(remain[: w - len(prompt)])
remain = remain[w - len(prompt):] remain = remain[w - len(prompt) :]
while remain != '': while remain != "":
y += 1 y += 1
self.win.addstr(y, 0, remain[:w]) self.win.addstr(y, 0, remain[:w])
remain = remain[w:] remain = remain[w:]
@ -287,7 +281,7 @@ class CursesEditLine(object):
self.win.move(self.starty + length / w, length % w) self.win.move(self.starty + length / w, length % w)
def showPrompt(self, y, x, prompt=None): def showPrompt(self, y, x, prompt=None):
self.content = '' self.content = ""
self.index = 0 self.index = 0
self.startx = x self.startx = x
self.starty = y self.starty = y
@ -299,26 +293,27 @@ class CursesEditLine(object):
key = event key = event
if self.startx == -1: 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: if key == curses.ascii.NL:
self.enterCallback(self.content) self.enterCallback(self.content)
elif key == curses.ascii.TAB: elif key == curses.ascii.TAB:
self.tabCompleteCallback(self.content) self.tabCompleteCallback(self.content)
elif curses.ascii.isprint(key): elif curses.ascii.isprint(key):
self.content = self.content[:self.index] + \ self.content = (
chr(key) + self.content[self.index:] self.content[: self.index] + chr(key) + self.content[self.index :]
)
self.index += 1 self.index += 1
elif key == curses.KEY_BACKSPACE or key == curses.ascii.BS: elif key == curses.KEY_BACKSPACE or key == curses.ascii.BS:
if self.index > 0: if self.index > 0:
self.index -= 1 self.index -= 1
self.content = self.content[ self.content = (
:self.index] + self.content[self.index + 1:] self.content[: self.index] + self.content[self.index + 1 :]
)
elif key == curses.KEY_DC or key == curses.ascii.DEL or key == curses.ascii.EOT: elif key == curses.KEY_DC or key == curses.ascii.DEL or key == curses.ascii.EOT:
self.content = self.content[ self.content = self.content[: self.index] + self.content[self.index + 1 :]
:self.index] + self.content[self.index + 1:]
elif key == curses.ascii.VT: # CTRL-K 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 elif key == curses.KEY_LEFT or key == curses.ascii.STX: # left or CTRL-B
if self.index > 0: if self.index > 0:
self.index -= 1 self.index -= 1

View File

@ -14,7 +14,7 @@ from threading import Thread
class DebuggerDriver(Thread): class DebuggerDriver(Thread):
""" Drives the debugger and responds to events. """ """Drives the debugger and responds to events."""
def __init__(self, debugger, event_queue): def __init__(self, debugger, event_queue):
Thread.__init__(self) Thread.__init__(self)
@ -31,40 +31,44 @@ class DebuggerDriver(Thread):
if not self.listener.IsValid(): if not self.listener.IsValid():
raise "Invalid listener" raise "Invalid listener"
self.listener.StartListeningForEventClass(self.debugger, self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBTarget.GetBroadcasterClassName(), lldb.SBTarget.GetBroadcasterClassName(),
lldb.SBTarget.eBroadcastBitBreakpointChanged lldb.SBTarget.eBroadcastBitBreakpointChanged
#| lldb.SBTarget.eBroadcastBitModuleLoaded # | lldb.SBTarget.eBroadcastBitModuleLoaded
#| lldb.SBTarget.eBroadcastBitModuleUnloaded # | lldb.SBTarget.eBroadcastBitModuleUnloaded
| lldb.SBTarget.eBroadcastBitWatchpointChanged | lldb.SBTarget.eBroadcastBitWatchpointChanged
#| lldb.SBTarget.eBroadcastBitSymbolLoaded # | lldb.SBTarget.eBroadcastBitSymbolLoaded
) )
self.listener.StartListeningForEventClass(self.debugger, self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBThread.GetBroadcasterClassName(), lldb.SBThread.GetBroadcasterClassName(),
lldb.SBThread.eBroadcastBitStackChanged lldb.SBThread.eBroadcastBitStackChanged
# lldb.SBThread.eBroadcastBitBreakpointChanged # lldb.SBThread.eBroadcastBitBreakpointChanged
| lldb.SBThread.eBroadcastBitThreadSuspended | lldb.SBThread.eBroadcastBitThreadSuspended
| lldb.SBThread.eBroadcastBitThreadResumed | lldb.SBThread.eBroadcastBitThreadResumed
| lldb.SBThread.eBroadcastBitSelectedFrameChanged | lldb.SBThread.eBroadcastBitSelectedFrameChanged
| lldb.SBThread.eBroadcastBitThreadSelected | lldb.SBThread.eBroadcastBitThreadSelected,
) )
self.listener.StartListeningForEventClass(self.debugger, self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBProcess.GetBroadcasterClassName(), lldb.SBProcess.GetBroadcasterClassName(),
lldb.SBProcess.eBroadcastBitStateChanged lldb.SBProcess.eBroadcastBitStateChanged
| lldb.SBProcess.eBroadcastBitInterrupt | lldb.SBProcess.eBroadcastBitInterrupt
| lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDOUT
| lldb.SBProcess.eBroadcastBitSTDERR | lldb.SBProcess.eBroadcastBitSTDERR
| lldb.SBProcess.eBroadcastBitProfileData | lldb.SBProcess.eBroadcastBitProfileData,
) )
self.listener.StartListeningForEventClass(self.debugger, self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBCommandInterpreter.GetBroadcasterClass(), lldb.SBCommandInterpreter.GetBroadcasterClass(),
lldb.SBCommandInterpreter.eBroadcastBitThreadShouldExit lldb.SBCommandInterpreter.eBroadcastBitThreadShouldExit
| lldb.SBCommandInterpreter.eBroadcastBitResetPrompt | lldb.SBCommandInterpreter.eBroadcastBitResetPrompt
| lldb.SBCommandInterpreter.eBroadcastBitQuitCommandReceived | lldb.SBCommandInterpreter.eBroadcastBitQuitCommandReceived
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousOutputData | lldb.SBCommandInterpreter.eBroadcastBitAsynchronousOutputData
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousErrorData | lldb.SBCommandInterpreter.eBroadcastBitAsynchronousErrorData,
) )
def createTarget(self, target_image, args=None): def createTarget(self, target_image, args=None):

View File

@ -12,9 +12,8 @@ import lldbutil
class EventWin(cui.TitledWin): class EventWin(cui.TitledWin):
def __init__(self, x, y, w, h): 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) self.win.scrollok(1)
super(EventWin, self).draw() super(EventWin, self).draw()

View File

@ -40,6 +40,7 @@ def which(program):
return exe_file return exe_file
return None return None
# =================================================== # ===================================================
# Disassembly for an SBFunction or an SBSymbol object # Disassembly for an SBFunction or an SBSymbol object
# =================================================== # ===================================================
@ -56,6 +57,7 @@ def disassemble(target, function_or_symbol):
print(i, file=buf) print(i, file=buf)
return buf.getvalue() return buf.getvalue()
# ========================================================== # ==========================================================
# Integer (byte size 1, 2, 4, and 8) to bytearray conversion # 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. # Little endian followed by a format character.
template = "<%c" template = "<%c"
if bytesize == 2: if bytesize == 2:
fmt = template % 'h' fmt = template % "h"
elif bytesize == 4: elif bytesize == 4:
fmt = template % 'i' fmt = template % "i"
elif bytesize == 4: elif bytesize == 4:
fmt = template % 'q' fmt = template % "q"
else: else:
return None return None
@ -101,11 +103,11 @@ def bytearray_to_int(bytes, bytesize):
# Little endian followed by a format character. # Little endian followed by a format character.
template = "<%c" template = "<%c"
if bytesize == 2: if bytesize == 2:
fmt = template % 'h' fmt = template % "h"
elif bytesize == 4: elif bytesize == 4:
fmt = template % 'i' fmt = template % "i"
elif bytesize == 4: elif bytesize == 4:
fmt = template % 'q' fmt = template % "q"
else: else:
return None return None
@ -126,7 +128,7 @@ def get_description(obj, option=None):
o lldb.eDescriptionLevelFull o lldb.eDescriptionLevelFull
o lldb.eDescriptionLevelVerbose o lldb.eDescriptionLevelVerbose
""" """
method = getattr(obj, 'GetDescription') method = getattr(obj, "GetDescription")
if not method: if not method:
return None return None
tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) 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 # Convert some enum value to its string counterpart
# ================================================= # =================================================
def state_type_to_str(enum): def state_type_to_str(enum):
"""Returns the stateType string given an enum.""" """Returns the stateType string given an enum."""
if enum == lldb.eStateInvalid: if enum == lldb.eStateInvalid:
@ -280,37 +283,45 @@ def value_type_to_str(enum):
# Get stopped threads due to each stop reason. # Get stopped threads due to each stop reason.
# ================================================== # ==================================================
def sort_stopped_threads(process,
def sort_stopped_threads(
process,
breakpoint_threads=None, breakpoint_threads=None,
crashed_threads=None, crashed_threads=None,
watchpoint_threads=None, watchpoint_threads=None,
signal_threads=None, signal_threads=None,
exiting_threads=None, exiting_threads=None,
other_threads=None): other_threads=None,
""" Fills array *_threads with threads stopped for the corresponding stop ):
"""Fills array *_threads with threads stopped for the corresponding stop
reason. reason.
""" """
for lst in [breakpoint_threads, for lst in [
breakpoint_threads,
watchpoint_threads, watchpoint_threads,
signal_threads, signal_threads,
exiting_threads, exiting_threads,
other_threads]: other_threads,
]:
if lst is not None: if lst is not None:
lst[:] = [] lst[:] = []
for thread in process: for thread in process:
dispatched = False dispatched = False
for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads), for reason, list in [
(lldb.eStopReasonBreakpoint, breakpoint_threads),
(lldb.eStopReasonException, crashed_threads), (lldb.eStopReasonException, crashed_threads),
(lldb.eStopReasonWatchpoint, watchpoint_threads), (lldb.eStopReasonWatchpoint, watchpoint_threads),
(lldb.eStopReasonSignal, signal_threads), (lldb.eStopReasonSignal, signal_threads),
(lldb.eStopReasonThreadExiting, exiting_threads), (lldb.eStopReasonThreadExiting, exiting_threads),
(None, other_threads)]: (None, other_threads),
]:
if not dispatched and list is not None: if not dispatched and list is not None:
if thread.GetStopReason() == reason or reason is None: if thread.GetStopReason() == reason or reason is None:
list.append(thread) list.append(thread)
dispatched = True dispatched = True
# ================================================== # ==================================================
# Utility functions for setting breakpoints # Utility functions for setting breakpoints
# ================================================== # ==================================================
@ -323,17 +334,19 @@ def run_break_set_by_file_and_line(
extra_options=None, extra_options=None,
num_expected_locations=1, num_expected_locations=1,
loc_exact=False, loc_exact=False,
module_name=None): module_name=None,
):
"""Set a breakpoint by file and line, returning the breakpoint number. """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 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 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: if file_name is None:
command = 'breakpoint set -l %d' % (line_number) command = "breakpoint set -l %d" % (line_number)
else: else:
command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number)
@ -352,12 +365,12 @@ def run_break_set_by_file_and_line(
num_locations=num_expected_locations, num_locations=num_expected_locations,
file_name=file_name, file_name=file_name,
line_number=line_number, line_number=line_number,
module_name=module_name) module_name=module_name,
)
else: else:
check_breakpoint_result( check_breakpoint_result(
test, test, break_results, num_locations=num_expected_locations
break_results, )
num_locations=num_expected_locations)
return get_bpno_from_match(break_results) return get_bpno_from_match(break_results)
@ -368,10 +381,12 @@ def run_break_set_by_symbol(
extra_options=None, extra_options=None,
num_expected_locations=-1, num_expected_locations=-1,
sym_exact=False, sym_exact=False,
module_name=None): module_name=None,
):
"""Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line. """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) command = 'breakpoint set -n "%s"' % (symbol)
if module_name: if module_name:
@ -388,22 +403,19 @@ def run_break_set_by_symbol(
break_results, break_results,
num_locations=num_expected_locations, num_locations=num_expected_locations,
symbol_name=symbol, symbol_name=symbol,
module_name=module_name) module_name=module_name,
)
else: else:
check_breakpoint_result( check_breakpoint_result(
test, test, break_results, num_locations=num_expected_locations
break_results, )
num_locations=num_expected_locations)
return get_bpno_from_match(break_results) return get_bpno_from_match(break_results)
def run_break_set_by_selector( def run_break_set_by_selector(
test, test, selector, extra_options=None, num_expected_locations=-1, module_name=None
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.""" """Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line."""
command = 'breakpoint set -S "%s"' % (selector) command = 'breakpoint set -S "%s"' % (selector)
@ -423,21 +435,19 @@ def run_break_set_by_selector(
num_locations=num_expected_locations, num_locations=num_expected_locations,
symbol_name=selector, symbol_name=selector,
symbol_match_exact=False, symbol_match_exact=False,
module_name=module_name) module_name=module_name,
)
else: else:
check_breakpoint_result( check_breakpoint_result(
test, test, break_results, num_locations=num_expected_locations
break_results, )
num_locations=num_expected_locations)
return get_bpno_from_match(break_results) return get_bpno_from_match(break_results)
def run_break_set_by_regexp( def run_break_set_by_regexp(
test, test, regexp, extra_options=None, num_expected_locations=-1
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.""" """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) command = 'breakpoint set -r "%s"' % (regexp)
@ -446,19 +456,14 @@ def run_break_set_by_regexp(
break_results = run_break_set_command(test, command) break_results = run_break_set_command(test, command)
check_breakpoint_result( 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) return get_bpno_from_match(break_results)
def run_break_set_by_source_regexp( def run_break_set_by_source_regexp(
test, test, regexp, extra_options=None, num_expected_locations=-1
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.""" """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) command = 'breakpoint set -p "%s"' % (regexp)
if extra_options: if extra_options:
@ -466,10 +471,7 @@ def run_break_set_by_source_regexp(
break_results = run_break_set_command(test, command) break_results = run_break_set_command(test, command)
check_breakpoint_result( 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) return get_bpno_from_match(break_results)
@ -496,40 +498,41 @@ 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>[0-9]+) locations\.$",
r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", 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>[+\-]{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) match_object = test.match(command, patterns)
break_results = match_object.groupdict() break_results = match_object.groupdict()
# We always insert the breakpoint number, setting it to -1 if we couldn't find it # 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. # Also, make sure it gets stored as an integer.
if not 'bpno' in break_results: if not "bpno" in break_results:
break_results['bpno'] = -1 break_results["bpno"] = -1
else: else:
break_results['bpno'] = int(break_results['bpno']) break_results["bpno"] = int(break_results["bpno"])
# We always insert the number of locations # 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... # 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. # 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 num_locations = 1
else: else:
num_locations = break_results['num_locations'] num_locations = break_results["num_locations"]
if num_locations == 'no': if num_locations == "no":
num_locations = 0 num_locations = 0
else: 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: if "line_no" in break_results:
break_results['line_no'] = int(break_results['line_no']) break_results["line_no"] = int(break_results["line_no"])
return break_results return break_results
def get_bpno_from_match(break_results): def get_bpno_from_match(break_results):
return int(break_results['bpno']) return int(break_results["bpno"])
def check_breakpoint_result( def check_breakpoint_result(
@ -541,75 +544,74 @@ def check_breakpoint_result(
symbol_match_exact=True, symbol_match_exact=True,
module_name=None, module_name=None,
offset=-1, offset=-1,
num_locations=-1): num_locations=-1,
):
out_num_locations = break_results['num_locations'] out_num_locations = break_results["num_locations"]
if num_locations == -1: if num_locations == -1:
test.assertTrue(out_num_locations > 0, test.assertTrue(
"Expecting one or more locations, got none.") out_num_locations > 0, "Expecting one or more locations, got none."
)
else: else:
test.assertTrue( test.assertTrue(
num_locations == out_num_locations, num_locations == out_num_locations,
"Expecting %d locations, got %d." % "Expecting %d locations, got %d." % (num_locations, out_num_locations),
(num_locations, )
out_num_locations))
if file_name: if file_name:
out_file_name = "" out_file_name = ""
if 'file' in break_results: if "file" in break_results:
out_file_name = break_results['file'] out_file_name = break_results["file"]
test.assertTrue( test.assertTrue(
file_name == out_file_name, file_name == out_file_name,
"Breakpoint file name '%s' doesn't match resultant name '%s'." % "Breakpoint file name '%s' doesn't match resultant name '%s'."
(file_name, % (file_name, out_file_name),
out_file_name)) )
if line_number != -1: if line_number != -1:
out_file_line = -1 out_file_line = -1
if 'line_no' in break_results: if "line_no" in break_results:
out_line_number = break_results['line_no'] out_line_number = break_results["line_no"]
test.assertTrue( test.assertTrue(
line_number == out_line_number, line_number == out_line_number,
"Breakpoint line number %s doesn't match resultant line %s." % "Breakpoint line number %s doesn't match resultant line %s."
(line_number, % (line_number, out_line_number),
out_line_number)) )
if symbol_name: if symbol_name:
out_symbol_name = "" out_symbol_name = ""
# Look first for the inlined symbol name, otherwise use the symbol # Look first for the inlined symbol name, otherwise use the symbol
# name: # name:
if 'inline_symbol' in break_results and break_results['inline_symbol']: if "inline_symbol" in break_results and break_results["inline_symbol"]:
out_symbol_name = break_results['inline_symbol'] out_symbol_name = break_results["inline_symbol"]
elif 'symbol' in break_results: elif "symbol" in break_results:
out_symbol_name = break_results['symbol'] out_symbol_name = break_results["symbol"]
if symbol_match_exact: if symbol_match_exact:
test.assertTrue( test.assertTrue(
symbol_name == out_symbol_name, symbol_name == out_symbol_name,
"Symbol name '%s' doesn't match resultant symbol '%s'." % "Symbol name '%s' doesn't match resultant symbol '%s'."
(symbol_name, % (symbol_name, out_symbol_name),
out_symbol_name)) )
else: else:
test.assertTrue( test.assertTrue(
out_symbol_name.find(symbol_name) != - out_symbol_name.find(symbol_name) != -1,
1, "Symbol name '%s' isn't in resultant symbol '%s'."
"Symbol name '%s' isn't in resultant symbol '%s'." % % (symbol_name, out_symbol_name),
(symbol_name, )
out_symbol_name))
if module_name: if module_name:
out_nodule_name = None out_nodule_name = None
if 'module' in break_results: if "module" in break_results:
out_module_name = break_results['module'] out_module_name = break_results["module"]
test.assertTrue( test.assertTrue(
module_name.find(out_module_name) != - module_name.find(out_module_name) != -1,
1, "Symbol module name '%s' isn't in expected module name '%s'."
"Symbol module name '%s' isn't in expected module name '%s'." % % (out_module_name, module_name),
(out_module_name, )
module_name))
# ================================================== # ==================================================
# Utility functions related to Threads and Processes # 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): 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 = [] stopped_threads = []
threads = [] threads = []
@ -677,7 +679,7 @@ def get_threads_stopped_at_breakpoint(process, bkpt):
def continue_to_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() process.Continue()
if process.GetState() != lldb.eStateStopped: if process.GetState() != lldb.eStateStopped:
return None return None
@ -703,6 +705,7 @@ def get_function_names(thread):
""" """
Returns a sequence of function names from the stack frames of this thread. Returns a sequence of function names from the stack frames of this thread.
""" """
def GetFuncName(i): def GetFuncName(i):
return thread.GetFrameAtIndex(i).GetFunctionName() return thread.GetFrameAtIndex(i).GetFunctionName()
@ -713,6 +716,7 @@ def get_symbol_names(thread):
""" """
Returns a sequence of symbols for this thread. Returns a sequence of symbols for this thread.
""" """
def GetSymbol(i): def GetSymbol(i):
return thread.GetFrameAtIndex(i).GetSymbol().GetName() return thread.GetFrameAtIndex(i).GetSymbol().GetName()
@ -723,6 +727,7 @@ def get_pc_addresses(thread):
""" """
Returns a sequence of pc addresses for this thread. Returns a sequence of pc addresses for this thread.
""" """
def GetPCAddress(i): def GetPCAddress(i):
return thread.GetFrameAtIndex(i).GetPCAddress() 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. Returns a sequence of file names from the stack frames of this thread.
""" """
def GetFilename(i): def GetFilename(i):
return thread.GetFrameAtIndex( return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()
i).GetLineEntry().GetFileSpec().GetFilename()
return [GetFilename(i) for i in range(thread.GetNumFrames())] 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. Returns a sequence of line numbers from the stack frames of this thread.
""" """
def GetLineNumber(i): def GetLineNumber(i):
return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() 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. Returns a sequence of module names from the stack frames of this thread.
""" """
def GetModuleName(i): def GetModuleName(i):
return thread.GetFrameAtIndex( return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()
i).GetModule().GetFileSpec().GetFilename()
return [GetModuleName(i) for i in range(thread.GetNumFrames())] 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. Returns a sequence of stack frames for this thread.
""" """
def GetStackFrame(i): def GetStackFrame(i):
return thread.GetFrameAtIndex(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()) desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason())
else: else:
desc = "" desc = ""
print("Stack trace for thread id={0:#x} name={1} queue={2} ".format( print(
thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc, file=output) "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): for i in range(depth):
frame = thread.GetFrameAtIndex(i) frame = thread.GetFrameAtIndex(i)
@ -802,13 +814,31 @@ def print_stacktrace(thread, string_buffer=False):
file_addr = addrs[i].GetFileAddress() file_addr = addrs[i].GetFileAddress()
start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress() start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress()
symbol_offset = file_addr - start_addr symbol_offset = file_addr - start_addr
print(" frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format( print(
num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset), file=output) " 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: else:
print(" frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format( print(
num=i, addr=load_addr, mod=mods[i], func='%s [inlined]' % " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(
funcs[i] if frame.IsInlined() else funcs[i], file=files[i], line=lines[i], args=get_args_as_string( num=i,
frame, showFuncName=False) if not frame.IsInlined() else '()'), file=output) 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: if string_buffer:
return output.getvalue() return output.getvalue()
@ -827,6 +857,7 @@ def print_stacktraces(process, string_buffer=False):
if string_buffer: if string_buffer:
return output.getvalue() return output.getvalue()
# =================================== # ===================================
# Utility functions related to Frames # 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 vars = frame.GetVariables(True, False, False, True) # type of SBValueList
args = [] # list of strings args = [] # list of strings
for var in vars: for var in vars:
args.append("(%s)%s=%s" % (var.GetTypeName(), args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), var.GetValue()))
var.GetName(),
var.GetValue()))
if frame.GetFunction(): if frame.GetFunction():
name = frame.GetFunction().GetName() name = frame.GetFunction().GetName()
elif frame.GetSymbol(): elif frame.GetSymbol():
@ -882,15 +911,20 @@ def print_registers(frame, string_buffer=False):
print("Register sets for " + str(frame), file=output) print("Register sets for " + str(frame), file=output)
registerSet = frame.GetRegisters() # Return type of SBValueList. registerSet = frame.GetRegisters() # Return type of SBValueList.
print("Frame registers (size of register set = %d):" % registerSet.GetSize( print(
), file=output) "Frame registers (size of register set = %d):" % registerSet.GetSize(),
file=output,
)
for value in registerSet: for value in registerSet:
#print >> output, value # print >> output, value
print("%s (number of children = %d):" % ( print(
value.GetName(), value.GetNumChildren()), file=output) "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()),
file=output,
)
for child in value: for child in value:
print("Name: %s, Value: %s" % ( print(
child.GetName(), child.GetValue()), file=output) "Name: %s, Value: %s" % (child.GetName(), child.GetValue()), file=output
)
if string_buffer: if string_buffer:
return output.getvalue() return output.getvalue()
@ -950,6 +984,7 @@ def get_ESRs(frame):
""" """
return get_registers(frame, "exception state") return get_registers(frame, "exception state")
# ====================================== # ======================================
# Utility classes/functions for SBValues # Utility classes/functions for SBValues
# ====================================== # ======================================
@ -970,11 +1005,15 @@ class BasicFormatter(object):
val = value.GetValue() val = value.GetValue()
if val is None and value.GetNumChildren() > 0: if val is None and value.GetNumChildren() > 0:
val = "%s (location)" % value.GetLocation() val = "%s (location)" % value.GetLocation()
print("{indentation}({type}) {name} = {value}".format( print(
indentation=' ' * indent, "{indentation}({type}) {name} = {value}".format(
indentation=" " * indent,
type=value.GetTypeName(), type=value.GetTypeName(),
name=value.GetName(), name=value.GetName(),
value=val), file=output) value=val,
),
file=output,
)
return output.getvalue() return output.getvalue()
@ -996,8 +1035,7 @@ class ChildVisitingFormatter(BasicFormatter):
BasicFormatter.format(self, value, buffer=output) BasicFormatter.format(self, value, buffer=output)
for child in value: for child in value:
BasicFormatter.format( BasicFormatter.format(self, child, buffer=output, indent=self.cindent)
self, child, buffer=output, indent=self.cindent)
return output.getvalue() return output.getvalue()
@ -1025,14 +1063,12 @@ class RecursiveDecentFormatter(BasicFormatter):
new_indent = self.lindent + self.cindent new_indent = self.lindent + self.cindent
for child in value: for child in value:
if child.GetSummary() is not None: if child.GetSummary() is not None:
BasicFormatter.format( BasicFormatter.format(self, child, buffer=output, indent=new_indent)
self, child, buffer=output, indent=new_indent)
else: else:
if child.GetNumChildren() > 0: if child.GetNumChildren() > 0:
rdf = RecursiveDecentFormatter(indent_level=new_indent) rdf = RecursiveDecentFormatter(indent_level=new_indent)
rdf.format(child, buffer=output) rdf.format(child, buffer=output)
else: else:
BasicFormatter.format( BasicFormatter.format(self, child, buffer=output, indent=new_indent)
self, child, buffer=output, indent=new_indent)
return output.getvalue() return output.getvalue()

View File

@ -38,17 +38,11 @@ event_queue = None
def handle_args(driver, argv): def handle_args(driver, argv):
parser = OptionParser() parser = OptionParser()
parser.add_option( parser.add_option(
"-p", "-p", "--attach", dest="pid", help="Attach to specified Process ID", type="int"
"--attach", )
dest="pid",
help="Attach to specified Process ID",
type="int")
parser.add_option( parser.add_option(
"-c", "-c", "--core", dest="core", help="Load specified core file", type="string"
"--core", )
dest="core",
help="Load specified core file",
type="string")
(options, args) = parser.parse_args(argv) (options, args) = parser.parse_args(argv)
@ -60,9 +54,7 @@ def handle_args(driver, argv):
print("Error: expecting integer PID, got '%s'" % options.pid) print("Error: expecting integer PID, got '%s'" % options.pid)
elif options.core is not None: elif options.core is not None:
if not os.path.exists(options.core): if not os.path.exists(options.core):
raise Exception( raise Exception("Specified core file '%s' does not exist." % options.core)
"Specified core file '%s' does not exist." %
options.core)
driver.loadCore(options.core) driver.loadCore(options.core)
elif len(args) == 2: elif len(args) == 2:
if not os.path.isfile(args[1]): if not os.path.isfile(args[1]):
@ -80,7 +72,6 @@ def sigint_handler(signal, frame):
class LLDBUI(cui.CursesUI): class LLDBUI(cui.CursesUI):
def __init__(self, screen, event_queue, driver): def __init__(self, screen, event_queue, driver):
super(LLDBUI, self).__init__(screen, event_queue) super(LLDBUI, self).__init__(screen, event_queue)
@ -94,14 +85,16 @@ class LLDBUI(cui.CursesUI):
self.status_win = statuswin.StatusWin(0, h - 1, w, 1) self.status_win = statuswin.StatusWin(0, h - 1, w, 1)
h -= 1 h -= 1
self.command_win = commandwin.CommandWin( 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 h -= command_win_height
self.source_win = sourcewin.SourceWin(driver, 0, 0, self.source_win = sourcewin.SourceWin(driver, 0, 0, w - break_win_width - 1, h)
w - break_win_width - 1, h) self.break_win = breakwin.BreakWin(
self.break_win = breakwin.BreakWin(driver, w - break_win_width, 0, driver, w - break_win_width, 0, break_win_width, h
break_win_width, h) )
self.wins = [self.status_win, self.wins = [
self.status_win,
# self.event_win, # self.event_win,
self.source_win, self.source_win,
self.break_win, self.break_win,
@ -116,12 +109,14 @@ class LLDBUI(cui.CursesUI):
if event == curses.KEY_F10: if event == curses.KEY_F10:
self.driver.terminate() self.driver.terminate()
if event == 20: # ctrl-T if event == 20: # ctrl-T
def foo(cmd): def foo(cmd):
ret = lldb.SBCommandReturnObject() ret = lldb.SBCommandReturnObject()
self.driver.getCommandInterpreter().HandleCommand(cmd, ret) self.driver.getCommandInterpreter().HandleCommand(cmd, ret)
foo('target create a.out')
foo('b main') foo("target create a.out")
foo('run') foo("b main")
foo("run")
super(LLDBUI, self).handleEvent(event) super(LLDBUI, self).handleEvent(event)
@ -145,6 +140,7 @@ def main(screen):
handle_args(driver, sys.argv) handle_args(driver, sys.argv)
view.eventLoop() view.eventLoop()
if __name__ == "__main__": if __name__ == "__main__":
try: try:
curses.wrapper(main) curses.wrapper(main)

View File

@ -25,7 +25,6 @@ event_queue = None
class SandboxUI(cui.CursesUI): class SandboxUI(cui.CursesUI):
def __init__(self, screen, event_queue): def __init__(self, screen, event_queue):
super(SandboxUI, self).__init__(screen, event_queue) super(SandboxUI, self).__init__(screen, event_queue)
@ -34,10 +33,10 @@ class SandboxUI(cui.CursesUI):
h2 = height / 2 h2 = height / 2
self.wins = [] 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) list_win = cui.ListWin(w2, h2, w2, h2)
for i in range(0, 40): 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(list_win)
self.wins.append(cui.TitledWin(0, 0, w2, h2, "Test Window 1")) self.wins.append(cui.TitledWin(0, 0, w2, h2, "Test Window 1"))
self.wins.append(cui.TitledWin(w2, 0, w2, h2, "Test Window 2")) 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.wins[0].win.scrollok(1)
# self.el = cui.CursesEditLine(self.wins[0].win, None, # self.el = cui.CursesEditLine(self.wins[0].win, None,
# lambda c: callback('got', c), lambda c: callback('tab', c)) # lambda c: callback('got', c), lambda c: callback('tab', c))
#self.el.prompt = '>>> ' # self.el.prompt = '>>> '
#self.el.showPrompt(10, 0) # self.el.showPrompt(10, 0)
def handleEvent(self, event): def handleEvent(self, event):
if isinstance(event, int): if isinstance(event, int):
if event == ord('q'): if event == ord("q"):
sys.exit(0) sys.exit(0)
# self.el.handleEvent(event) # self.el.handleEvent(event)
super(SandboxUI, self).handleEvent(event) super(SandboxUI, self).handleEvent(event)
@ -70,6 +69,7 @@ def main(screen):
sandbox = SandboxUI(screen, event_queue) sandbox = SandboxUI(screen, event_queue)
sandbox.eventLoop() sandbox.eventLoop()
if __name__ == "__main__": if __name__ == "__main__":
try: try:
curses.wrapper(main) curses.wrapper(main)

View File

@ -15,7 +15,6 @@ import os
class SourceWin(cui.TitledWin): class SourceWin(cui.TitledWin):
def __init__(self, driver, x, y, w, h): def __init__(self, driver, x, y, w, h):
super(SourceWin, self).__init__(x, y, w, h, "Source") super(SourceWin, self).__init__(x, y, w, h, "Source")
self.sourceman = driver.getSourceManager() self.sourceman = driver.getSourceManager()
@ -35,9 +34,10 @@ class SourceWin(cui.TitledWin):
try: try:
from pygments.formatters import TerminalFormatter from pygments.formatters import TerminalFormatter
self.formatter = TerminalFormatter() self.formatter = TerminalFormatter()
except ImportError: 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.lexer = None
self.formatter = None self.formatter = None
pass pass
@ -55,8 +55,9 @@ class SourceWin(cui.TitledWin):
if lldb.SBBreakpoint.EventIsBreakpointEvent(event): if lldb.SBBreakpoint.EventIsBreakpointEvent(event):
self.handleBPEvent(event) self.handleBPEvent(event)
if lldb.SBProcess.EventIsProcessEvent(event) and \ if lldb.SBProcess.EventIsProcessEvent(
not lldb.SBProcess.GetRestartedFromEvent(event): event
) and not lldb.SBProcess.GetRestartedFromEvent(event):
process = lldb.SBProcess.GetProcessFromEvent(event) process = lldb.SBProcess.GetProcessFromEvent(event)
if not process.IsValid(): if not process.IsValid():
return return
@ -71,8 +72,8 @@ class SourceWin(cui.TitledWin):
pid = process.GetProcessID() pid = process.GetProcessID()
ec = process.GetExitStatus() ec = process.GetExitStatus()
self.win.addstr( self.win.addstr(
"\nProcess %s [%d] has exited with exit-code %d" % "\nProcess %s [%d] has exited with exit-code %d" % (target, pid, ec)
(target, pid, ec)) )
def pageUp(self): def pageUp(self):
if self.viewline > 0: if self.viewline > 0:
@ -100,8 +101,8 @@ class SourceWin(cui.TitledWin):
if self.viewline < 0: if self.viewline < 0:
raise Exception( raise Exception(
"negative viewline: pc=%d viewline=%d" % "negative viewline: pc=%d viewline=%d" % (self.pc_line, self.viewline)
(self.pc_line, self.viewline)) )
def refreshSource(self, process=None): def refreshSource(self, process=None):
(self.height, self.width) = self.win.getmaxyx() (self.height, self.width) = self.win.getmaxyx()
@ -126,9 +127,14 @@ class SourceWin(cui.TitledWin):
if self.formatter is not None: if self.formatter is not None:
from pygments.lexers import get_lexer_for_filename from pygments.lexers import get_lexer_for_filename
self.lexer = get_lexer_for_filename(self.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() self.win.erase()
if self.content: if self.content:
self.formatContent(self.content, self.pc_line, bps) self.formatContent(self.content, self.pc_line, bps)
@ -159,7 +165,7 @@ class SourceWin(cui.TitledWin):
marker = self.markerBP marker = self.markerBP
line = "%s%3d %s" % (marker, line_num, self.highlight(content[i])) line = "%s%3d %s" % (marker, line_num, self.highlight(content[i]))
if len(line) >= self.width: if len(line) >= self.width:
line = line[0:self.width - 1] + "\n" line = line[0 : self.width - 1] + "\n"
self.win.addstr(line, attr) self.win.addstr(line, attr)
source += line source += line
count = count + 1 count = count + 1
@ -168,6 +174,7 @@ class SourceWin(cui.TitledWin):
def highlight(self, source): def highlight(self, source):
if self.lexer and self.formatter: if self.lexer and self.formatter:
from pygments import highlight from pygments import highlight
return highlight(source, self.lexer, self.formatter) return highlight(source, self.lexer, self.formatter)
else: else:
return source return source
@ -202,9 +209,8 @@ class SourceWin(cui.TitledWin):
# hack! getting the LineEntry via SBBreakpointLocation.GetAddress.GetLineEntry does not work good for # hack! getting the LineEntry via SBBreakpointLocation.GetAddress.GetLineEntry does not work good for
# inlined frames, so we get the description (which does take # inlined frames, so we get the description (which does take
# into account inlined functions) and parse it. # into account inlined functions) and parse it.
desc = lldbutil.get_description( desc = lldbutil.get_description(location, lldb.eDescriptionLevelFull)
location, lldb.eDescriptionLevelFull) match = re.search("at\ ([^:]+):([\d]+)", desc)
match = re.search('at\ ([^:]+):([\d]+)', desc)
try: try:
path = match.group(1) path = match.group(1)
line = int(match.group(2).strip()) line = int(match.group(2).strip())
@ -219,20 +225,26 @@ class SourceWin(cui.TitledWin):
return locs return locs
event_type = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event) event_type = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event)
if event_type == lldb.eBreakpointEventTypeEnabled \ if (
or event_type == lldb.eBreakpointEventTypeAdded \ event_type == lldb.eBreakpointEventTypeEnabled
or event_type == lldb.eBreakpointEventTypeLocationsResolved \ or event_type == lldb.eBreakpointEventTypeAdded
or event_type == lldb.eBreakpointEventTypeLocationsAdded: or event_type == lldb.eBreakpointEventTypeLocationsResolved
or event_type == lldb.eBreakpointEventTypeLocationsAdded
):
self.addBPLocations(getLocations(event)) self.addBPLocations(getLocations(event))
elif event_type == lldb.eBreakpointEventTypeRemoved \ elif (
or event_type == lldb.eBreakpointEventTypeLocationsRemoved \ event_type == lldb.eBreakpointEventTypeRemoved
or event_type == lldb.eBreakpointEventTypeDisabled: or event_type == lldb.eBreakpointEventTypeLocationsRemoved
or event_type == lldb.eBreakpointEventTypeDisabled
):
self.removeBPLocations(getLocations(event)) self.removeBPLocations(getLocations(event))
elif event_type == lldb.eBreakpointEventTypeCommandChanged \ elif (
or event_type == lldb.eBreakpointEventTypeConditionChanged \ event_type == lldb.eBreakpointEventTypeCommandChanged
or event_type == lldb.eBreakpointEventTypeIgnoreChanged \ or event_type == lldb.eBreakpointEventTypeConditionChanged
or event_type == lldb.eBreakpointEventTypeThreadChanged \ or event_type == lldb.eBreakpointEventTypeIgnoreChanged
or event_type == lldb.eBreakpointEventTypeInvalidType: or event_type == lldb.eBreakpointEventTypeThreadChanged
or event_type == lldb.eBreakpointEventTypeInvalidType
):
# no-op # no-op
pass pass
self.refreshSource() self.refreshSource()

View File

@ -13,19 +13,19 @@ import curses
class StatusWin(cui.TextWin): class StatusWin(cui.TextWin):
def __init__(self, x, y, w, h): def __init__(self, x, y, w, h):
super(StatusWin, self).__init__(x, y, w) super(StatusWin, self).__init__(x, y, w)
self.keys = [ # ('F1', 'Help', curses.KEY_F1), self.keys = [ # ('F1', 'Help', curses.KEY_F1),
('F3', 'Cycle-focus', curses.KEY_F3), ("F3", "Cycle-focus", curses.KEY_F3),
('F10', 'Quit', curses.KEY_F10)] ("F10", "Quit", curses.KEY_F10),
]
def draw(self): def draw(self):
self.win.addstr(0, 0, '') self.win.addstr(0, 0, "")
for key in self.keys: for key in self.keys:
self.win.addstr('{0}'.format(key[0]), curses.A_REVERSE) 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[1]), curses.A_NORMAL)
super(StatusWin, self).draw() super(StatusWin, self).draw()
def handleEvent(self, event): def handleEvent(self, event):