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