301 lines · python
1# Usage:2# art/test/run-test --host --gdb [--64] [--interpreter] 004-JniTest3# 'b Java_Main_shortMethod'4# 'r'5# 'command script import host_art_bt.py'6# 'host_art_bt'7 8import sys9import re10 11import lldb12 13 14def host_art_bt(debugger, command, result, internal_dict):15 prettified_frames = []16 lldb_frame_index = 017 art_frame_index = 018 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 frame27 28 # Get function/filename/lineno from symbol context29 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 frames43 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, error65 )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 + 177 break78 art_frame_index = art_frame_index + 179 80 # Skip native frames81 lldb_frame_index = lldb_frame_index + 182 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 frame88 # Don't skip; leave it to the next iteration89 continue90 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_stub95 # Skip until we get past the next ArtMethod::Invoke()96 while True:97 lldb_frame_index = lldb_frame_index + 198 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 + 1110 break111 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_64118 119 # Skip art frames120 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 runtime131 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, error143 )144 145 prettified_frames.append(146 {"function": function, "file": None, "line": -1}147 )148 149 art_frame_index = art_frame_index + 1150 break151 art_frame_index = art_frame_index + 1152 153 # Skip native frames154 lldb_frame_index = lldb_frame_index + 1155 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_stub162 # Skip until we get past the next ArtMethod::Invoke()163 while True:164 lldb_frame_index = lldb_frame_index + 1165 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 + 1177 break178 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 frame184 185 while True:186 lldb_frame_index = lldb_frame_index + 1187 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 break197 198 # Skip art frames199 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 runtime210 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, error222 )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, error241 )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 + 1251 break252 art_frame_index = art_frame_index + 1253 254 # Skip native frames255 while True:256 lldb_frame_index = lldb_frame_index + 1257 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 break265 else:266 # Other frames. Add them as-is.267 frame = thread.GetFrameAtIndex(lldb_frame_index)268 lldb_frame_index = lldb_frame_index + 1269 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