240 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			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')
 |