xref: /llvm-project/lldb/scripts/android/host_art_bt.py (revision 602e47c5f9fd2e14c7bfb6111e6558fa0d27c87f)
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