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