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