llvm-project/lldb/scripts/android/host_art_bt.py

240 lines
13 KiB
Python

# Usage:
# art/test/run-test --host --gdb [--64] [--interpreter] 004-JniTest
# 'b Java_Main_shortMethod'
# 'r'
# 'command script import host_art_bt.py'
# 'host_art_bt'
from __future__ import print_function
import sys
import re
import lldb
def host_art_bt(debugger, command, result, internal_dict):
prettified_frames = []
lldb_frame_index = 0
art_frame_index = 0
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
while lldb_frame_index < thread.GetNumFrames():
frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetModule() and re.match(r'JIT\(.*?\)',
frame.GetModule().GetFileSpec().GetFilename()):
# Compiled Java frame
# Get function/filename/lineno from symbol context
symbol = frame.GetSymbol()
if not symbol:
print('No symbol info for compiled Java frame: ', frame)
sys.exit(1)
line_entry = frame.GetLineEntry()
prettified_frames.append({
'function': symbol.GetName(),
'file': str(line_entry.GetFileSpec()) if line_entry else None,
'line': line_entry.GetLine() if line_entry else -1
})
# Skip art frames
while True:
art_stack_visitor = frame.EvaluateExpression(
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" +
str(art_frame_index) +
"""); visitor.WalkStack(true); visitor""")
art_method = frame.EvaluateExpression(
art_stack_visitor.GetName() + """.GetMethod()""")
if art_method.GetValueAsUnsigned() != 0:
art_method_name = frame.EvaluateExpression(
"""art::PrettyMethod(""" + art_method.GetName() + """, true)""")
art_method_name_data = frame.EvaluateExpression(
art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned()
art_method_name_size = frame.EvaluateExpression(
art_method_name.GetName() + """.length()""").GetValueAsUnsigned()
error = lldb.SBError()
art_method_name = process.ReadCStringFromMemory(
art_method_name_data, art_method_name_size + 1, error)
if not error.Success:
print('Failed to read method name')
sys.exit(1)
if art_method_name != symbol.GetName():
print('Function names in native symbol and art runtime stack do not match: ', symbol.GetName(), ' != ', art_method_name)
art_frame_index = art_frame_index + 1
break
art_frame_index = art_frame_index + 1
# Skip native frames
lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index < thread.GetNumFrames():
frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetModule() and re.match(
r'JIT\(.*?\)', frame.GetModule().GetFileSpec().GetFilename()):
# Another compile Java frame
# Don't skip; leave it to the next iteration
continue
elif frame.GetSymbol() and (frame.GetSymbol().GetName() == 'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'):
# art_quick_invoke_stub / art_quick_invoke_static_stub
# Skip until we get past the next ArtMethod::Invoke()
while True:
lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames():
print('ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub')
sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and frame.GetSymbol().GetName(
) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)':
lldb_frame_index = lldb_frame_index + 1
break
else:
print('Invalid frame below compiled Java frame: ', frame)
elif frame.GetSymbol() and frame.GetSymbol().GetName() == 'art_quick_generic_jni_trampoline':
# Interpreted JNI frame for x86_64
# Skip art frames
while True:
art_stack_visitor = frame.EvaluateExpression(
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" +
str(art_frame_index) +
"""); visitor.WalkStack(true); visitor""")
art_method = frame.EvaluateExpression(
art_stack_visitor.GetName() + """.GetMethod()""")
if art_method.GetValueAsUnsigned() != 0:
# Get function/filename/lineno from ART runtime
art_method_name = frame.EvaluateExpression(
"""art::PrettyMethod(""" + art_method.GetName() + """, true)""")
art_method_name_data = frame.EvaluateExpression(
art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned()
art_method_name_size = frame.EvaluateExpression(
art_method_name.GetName() + """.length()""").GetValueAsUnsigned()
error = lldb.SBError()
function = process.ReadCStringFromMemory(
art_method_name_data, art_method_name_size + 1, error)
prettified_frames.append({
'function': function,
'file': None,
'line': -1
})
art_frame_index = art_frame_index + 1
break
art_frame_index = art_frame_index + 1
# Skip native frames
lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index < thread.GetNumFrames():
frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and (frame.GetSymbol().GetName() ==
'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'):
# art_quick_invoke_stub / art_quick_invoke_static_stub
# Skip until we get past the next ArtMethod::Invoke()
while True:
lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames():
print('ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub')
sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and frame.GetSymbol().GetName(
) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)':
lldb_frame_index = lldb_frame_index + 1
break
else:
print('Invalid frame below compiled Java frame: ', frame)
elif frame.GetSymbol() and re.search(r'art::interpreter::', frame.GetSymbol().GetName()):
# Interpreted Java frame
while True:
lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames():
print('art::interpreter::Execute not found in interpreter frame')
sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and frame.GetSymbol().GetName(
) == 'art::interpreter::Execute(art::Thread*, art::MethodHelper&, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)':
break
# Skip art frames
while True:
art_stack_visitor = frame.EvaluateExpression(
"""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" +
str(art_frame_index) +
"""); visitor.WalkStack(true); visitor""")
art_method = frame.EvaluateExpression(
art_stack_visitor.GetName() + """.GetMethod()""")
if art_method.GetValueAsUnsigned() != 0:
# Get function/filename/lineno from ART runtime
art_method_name = frame.EvaluateExpression(
"""art::PrettyMethod(""" + art_method.GetName() + """, true)""")
art_method_name_data = frame.EvaluateExpression(
art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned()
art_method_name_size = frame.EvaluateExpression(
art_method_name.GetName() + """.length()""").GetValueAsUnsigned()
error = lldb.SBError()
function = process.ReadCStringFromMemory(
art_method_name_data, art_method_name_size + 1, error)
line = frame.EvaluateExpression(
art_stack_visitor.GetName() +
""".GetMethod()->GetLineNumFromDexPC(""" +
art_stack_visitor.GetName() +
""".GetDexPc(true))""").GetValueAsUnsigned()
file_name = frame.EvaluateExpression(
art_method.GetName() + """->GetDeclaringClassSourceFile()""")
file_name_data = file_name.GetValueAsUnsigned()
file_name_size = frame.EvaluateExpression(
"""(size_t)strlen(""" + file_name.GetName() + """)""").GetValueAsUnsigned()
error = lldb.SBError()
file_name = process.ReadCStringFromMemory(
file_name_data, file_name_size + 1, error)
if not error.Success():
print('Failed to read source file name')
sys.exit(1)
prettified_frames.append({
'function': function,
'file': file_name,
'line': line
})
art_frame_index = art_frame_index + 1
break
art_frame_index = art_frame_index + 1
# Skip native frames
while True:
lldb_frame_index = lldb_frame_index + 1
if lldb_frame_index >= thread.GetNumFrames():
print('Can not get past interpreter native frames')
sys.exit(1)
frame = thread.GetFrameAtIndex(lldb_frame_index)
if frame.GetSymbol() and not re.search(
r'art::interpreter::', frame.GetSymbol().GetName()):
break
else:
# Other frames. Add them as-is.
frame = thread.GetFrameAtIndex(lldb_frame_index)
lldb_frame_index = lldb_frame_index + 1
if frame.GetModule():
module_name = frame.GetModule().GetFileSpec().GetFilename()
if not module_name in [
'libartd.so',
'dalvikvm32',
'dalvikvm64',
'libc.so.6']:
prettified_frames.append({
'function': frame.GetSymbol().GetName() if frame.GetSymbol() else None,
'file': str(frame.GetLineEntry().GetFileSpec()) if frame.GetLineEntry() else None,
'line': frame.GetLineEntry().GetLine() if frame.GetLineEntry() else -1
})
for prettified_frame in prettified_frames:
print(prettified_frame['function'], prettified_frame['file'], prettified_frame['line'])
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand(
'command script add -f host_art_bt.host_art_bt host_art_bt')