1*061da546Spatrick# Usage: 2*061da546Spatrick# art/test/run-test --host --gdb [--64] [--interpreter] 004-JniTest 3*061da546Spatrick# 'b Java_Main_shortMethod' 4*061da546Spatrick# 'r' 5*061da546Spatrick# 'command script import host_art_bt.py' 6*061da546Spatrick# 'host_art_bt' 7*061da546Spatrick 8*061da546Spatrickfrom __future__ import print_function 9*061da546Spatrick 10*061da546Spatrickimport sys 11*061da546Spatrickimport re 12*061da546Spatrick 13*061da546Spatrickimport lldb 14*061da546Spatrick 15*061da546Spatrick 16*061da546Spatrickdef host_art_bt(debugger, command, result, internal_dict): 17*061da546Spatrick prettified_frames = [] 18*061da546Spatrick lldb_frame_index = 0 19*061da546Spatrick art_frame_index = 0 20*061da546Spatrick target = debugger.GetSelectedTarget() 21*061da546Spatrick process = target.GetProcess() 22*061da546Spatrick thread = process.GetSelectedThread() 23*061da546Spatrick while lldb_frame_index < thread.GetNumFrames(): 24*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 25*061da546Spatrick if frame.GetModule() and re.match(r'JIT\(.*?\)', 26*061da546Spatrick frame.GetModule().GetFileSpec().GetFilename()): 27*061da546Spatrick # Compiled Java frame 28*061da546Spatrick 29*061da546Spatrick # Get function/filename/lineno from symbol context 30*061da546Spatrick symbol = frame.GetSymbol() 31*061da546Spatrick if not symbol: 32*061da546Spatrick print('No symbol info for compiled Java frame: ', frame) 33*061da546Spatrick sys.exit(1) 34*061da546Spatrick line_entry = frame.GetLineEntry() 35*061da546Spatrick prettified_frames.append({ 36*061da546Spatrick 'function': symbol.GetName(), 37*061da546Spatrick 'file': str(line_entry.GetFileSpec()) if line_entry else None, 38*061da546Spatrick 'line': line_entry.GetLine() if line_entry else -1 39*061da546Spatrick }) 40*061da546Spatrick 41*061da546Spatrick # Skip art frames 42*061da546Spatrick while True: 43*061da546Spatrick art_stack_visitor = frame.EvaluateExpression( 44*061da546Spatrick """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(""" + 45*061da546Spatrick str(art_frame_index) + 46*061da546Spatrick """); visitor.WalkStack(true); visitor""") 47*061da546Spatrick art_method = frame.EvaluateExpression( 48*061da546Spatrick art_stack_visitor.GetName() + """.GetMethod()""") 49*061da546Spatrick if art_method.GetValueAsUnsigned() != 0: 50*061da546Spatrick art_method_name = frame.EvaluateExpression( 51*061da546Spatrick """art::PrettyMethod(""" + art_method.GetName() + """, true)""") 52*061da546Spatrick art_method_name_data = frame.EvaluateExpression( 53*061da546Spatrick art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned() 54*061da546Spatrick art_method_name_size = frame.EvaluateExpression( 55*061da546Spatrick art_method_name.GetName() + """.length()""").GetValueAsUnsigned() 56*061da546Spatrick error = lldb.SBError() 57*061da546Spatrick art_method_name = process.ReadCStringFromMemory( 58*061da546Spatrick art_method_name_data, art_method_name_size + 1, error) 59*061da546Spatrick if not error.Success: 60*061da546Spatrick print('Failed to read method name') 61*061da546Spatrick sys.exit(1) 62*061da546Spatrick if art_method_name != symbol.GetName(): 63*061da546Spatrick print('Function names in native symbol and art runtime stack do not match: ', symbol.GetName(), ' != ', art_method_name) 64*061da546Spatrick art_frame_index = art_frame_index + 1 65*061da546Spatrick break 66*061da546Spatrick art_frame_index = art_frame_index + 1 67*061da546Spatrick 68*061da546Spatrick # Skip native frames 69*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 70*061da546Spatrick if lldb_frame_index < thread.GetNumFrames(): 71*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 72*061da546Spatrick if frame.GetModule() and re.match( 73*061da546Spatrick r'JIT\(.*?\)', frame.GetModule().GetFileSpec().GetFilename()): 74*061da546Spatrick # Another compile Java frame 75*061da546Spatrick # Don't skip; leave it to the next iteration 76*061da546Spatrick continue 77*061da546Spatrick elif frame.GetSymbol() and (frame.GetSymbol().GetName() == 'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'): 78*061da546Spatrick # art_quick_invoke_stub / art_quick_invoke_static_stub 79*061da546Spatrick # Skip until we get past the next ArtMethod::Invoke() 80*061da546Spatrick while True: 81*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 82*061da546Spatrick if lldb_frame_index >= thread.GetNumFrames(): 83*061da546Spatrick print('ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub') 84*061da546Spatrick sys.exit(1) 85*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 86*061da546Spatrick if frame.GetSymbol() and frame.GetSymbol().GetName( 87*061da546Spatrick ) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)': 88*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 89*061da546Spatrick break 90*061da546Spatrick else: 91*061da546Spatrick print('Invalid frame below compiled Java frame: ', frame) 92*061da546Spatrick elif frame.GetSymbol() and frame.GetSymbol().GetName() == 'art_quick_generic_jni_trampoline': 93*061da546Spatrick # Interpreted JNI frame for x86_64 94*061da546Spatrick 95*061da546Spatrick # Skip art frames 96*061da546Spatrick while True: 97*061da546Spatrick art_stack_visitor = frame.EvaluateExpression( 98*061da546Spatrick """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(""" + 99*061da546Spatrick str(art_frame_index) + 100*061da546Spatrick """); visitor.WalkStack(true); visitor""") 101*061da546Spatrick art_method = frame.EvaluateExpression( 102*061da546Spatrick art_stack_visitor.GetName() + """.GetMethod()""") 103*061da546Spatrick if art_method.GetValueAsUnsigned() != 0: 104*061da546Spatrick # Get function/filename/lineno from ART runtime 105*061da546Spatrick art_method_name = frame.EvaluateExpression( 106*061da546Spatrick """art::PrettyMethod(""" + art_method.GetName() + """, true)""") 107*061da546Spatrick art_method_name_data = frame.EvaluateExpression( 108*061da546Spatrick art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned() 109*061da546Spatrick art_method_name_size = frame.EvaluateExpression( 110*061da546Spatrick art_method_name.GetName() + """.length()""").GetValueAsUnsigned() 111*061da546Spatrick error = lldb.SBError() 112*061da546Spatrick function = process.ReadCStringFromMemory( 113*061da546Spatrick art_method_name_data, art_method_name_size + 1, error) 114*061da546Spatrick 115*061da546Spatrick prettified_frames.append({ 116*061da546Spatrick 'function': function, 117*061da546Spatrick 'file': None, 118*061da546Spatrick 'line': -1 119*061da546Spatrick }) 120*061da546Spatrick 121*061da546Spatrick art_frame_index = art_frame_index + 1 122*061da546Spatrick break 123*061da546Spatrick art_frame_index = art_frame_index + 1 124*061da546Spatrick 125*061da546Spatrick # Skip native frames 126*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 127*061da546Spatrick if lldb_frame_index < thread.GetNumFrames(): 128*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 129*061da546Spatrick if frame.GetSymbol() and (frame.GetSymbol().GetName() == 130*061da546Spatrick 'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'): 131*061da546Spatrick # art_quick_invoke_stub / art_quick_invoke_static_stub 132*061da546Spatrick # Skip until we get past the next ArtMethod::Invoke() 133*061da546Spatrick while True: 134*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 135*061da546Spatrick if lldb_frame_index >= thread.GetNumFrames(): 136*061da546Spatrick print('ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub') 137*061da546Spatrick sys.exit(1) 138*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 139*061da546Spatrick if frame.GetSymbol() and frame.GetSymbol().GetName( 140*061da546Spatrick ) == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)': 141*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 142*061da546Spatrick break 143*061da546Spatrick else: 144*061da546Spatrick print('Invalid frame below compiled Java frame: ', frame) 145*061da546Spatrick elif frame.GetSymbol() and re.search(r'art::interpreter::', frame.GetSymbol().GetName()): 146*061da546Spatrick # Interpreted Java frame 147*061da546Spatrick 148*061da546Spatrick while True: 149*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 150*061da546Spatrick if lldb_frame_index >= thread.GetNumFrames(): 151*061da546Spatrick print('art::interpreter::Execute not found in interpreter frame') 152*061da546Spatrick sys.exit(1) 153*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 154*061da546Spatrick if frame.GetSymbol() and frame.GetSymbol().GetName( 155*061da546Spatrick ) == 'art::interpreter::Execute(art::Thread*, art::MethodHelper&, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)': 156*061da546Spatrick break 157*061da546Spatrick 158*061da546Spatrick # Skip art frames 159*061da546Spatrick while True: 160*061da546Spatrick art_stack_visitor = frame.EvaluateExpression( 161*061da546Spatrick """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(""" + 162*061da546Spatrick str(art_frame_index) + 163*061da546Spatrick """); visitor.WalkStack(true); visitor""") 164*061da546Spatrick art_method = frame.EvaluateExpression( 165*061da546Spatrick art_stack_visitor.GetName() + """.GetMethod()""") 166*061da546Spatrick if art_method.GetValueAsUnsigned() != 0: 167*061da546Spatrick # Get function/filename/lineno from ART runtime 168*061da546Spatrick art_method_name = frame.EvaluateExpression( 169*061da546Spatrick """art::PrettyMethod(""" + art_method.GetName() + """, true)""") 170*061da546Spatrick art_method_name_data = frame.EvaluateExpression( 171*061da546Spatrick art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned() 172*061da546Spatrick art_method_name_size = frame.EvaluateExpression( 173*061da546Spatrick art_method_name.GetName() + """.length()""").GetValueAsUnsigned() 174*061da546Spatrick error = lldb.SBError() 175*061da546Spatrick function = process.ReadCStringFromMemory( 176*061da546Spatrick art_method_name_data, art_method_name_size + 1, error) 177*061da546Spatrick 178*061da546Spatrick line = frame.EvaluateExpression( 179*061da546Spatrick art_stack_visitor.GetName() + 180*061da546Spatrick """.GetMethod()->GetLineNumFromDexPC(""" + 181*061da546Spatrick art_stack_visitor.GetName() + 182*061da546Spatrick """.GetDexPc(true))""").GetValueAsUnsigned() 183*061da546Spatrick 184*061da546Spatrick file_name = frame.EvaluateExpression( 185*061da546Spatrick art_method.GetName() + """->GetDeclaringClassSourceFile()""") 186*061da546Spatrick file_name_data = file_name.GetValueAsUnsigned() 187*061da546Spatrick file_name_size = frame.EvaluateExpression( 188*061da546Spatrick """(size_t)strlen(""" + file_name.GetName() + """)""").GetValueAsUnsigned() 189*061da546Spatrick error = lldb.SBError() 190*061da546Spatrick file_name = process.ReadCStringFromMemory( 191*061da546Spatrick file_name_data, file_name_size + 1, error) 192*061da546Spatrick if not error.Success(): 193*061da546Spatrick print('Failed to read source file name') 194*061da546Spatrick sys.exit(1) 195*061da546Spatrick 196*061da546Spatrick prettified_frames.append({ 197*061da546Spatrick 'function': function, 198*061da546Spatrick 'file': file_name, 199*061da546Spatrick 'line': line 200*061da546Spatrick }) 201*061da546Spatrick 202*061da546Spatrick art_frame_index = art_frame_index + 1 203*061da546Spatrick break 204*061da546Spatrick art_frame_index = art_frame_index + 1 205*061da546Spatrick 206*061da546Spatrick # Skip native frames 207*061da546Spatrick while True: 208*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 209*061da546Spatrick if lldb_frame_index >= thread.GetNumFrames(): 210*061da546Spatrick print('Can not get past interpreter native frames') 211*061da546Spatrick sys.exit(1) 212*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 213*061da546Spatrick if frame.GetSymbol() and not re.search( 214*061da546Spatrick r'art::interpreter::', frame.GetSymbol().GetName()): 215*061da546Spatrick break 216*061da546Spatrick else: 217*061da546Spatrick # Other frames. Add them as-is. 218*061da546Spatrick frame = thread.GetFrameAtIndex(lldb_frame_index) 219*061da546Spatrick lldb_frame_index = lldb_frame_index + 1 220*061da546Spatrick if frame.GetModule(): 221*061da546Spatrick module_name = frame.GetModule().GetFileSpec().GetFilename() 222*061da546Spatrick if not module_name in [ 223*061da546Spatrick 'libartd.so', 224*061da546Spatrick 'dalvikvm32', 225*061da546Spatrick 'dalvikvm64', 226*061da546Spatrick 'libc.so.6']: 227*061da546Spatrick prettified_frames.append({ 228*061da546Spatrick 'function': frame.GetSymbol().GetName() if frame.GetSymbol() else None, 229*061da546Spatrick 'file': str(frame.GetLineEntry().GetFileSpec()) if frame.GetLineEntry() else None, 230*061da546Spatrick 'line': frame.GetLineEntry().GetLine() if frame.GetLineEntry() else -1 231*061da546Spatrick }) 232*061da546Spatrick 233*061da546Spatrick for prettified_frame in prettified_frames: 234*061da546Spatrick print(prettified_frame['function'], prettified_frame['file'], prettified_frame['line']) 235*061da546Spatrick 236*061da546Spatrick 237*061da546Spatrickdef __lldb_init_module(debugger, internal_dict): 238*061da546Spatrick debugger.HandleCommand( 239*061da546Spatrick 'command script add -f host_art_bt.host_art_bt host_art_bt') 240