Skip to content

Commit 705a6ec

Browse files
committed
More comprehensive frame reporting
1 parent 7971f77 commit 705a6ec

File tree

1 file changed

+80
-14
lines changed

1 file changed

+80
-14
lines changed

src/Mono.Android/Android.Runtime/JavaProxyThrowable.cs

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
22
using System.Diagnostics;
33
using System.Diagnostics.CodeAnalysis;
4+
using System.Globalization;
45
using System.Reflection;
6+
using System.Text;
57

68
using StackTraceElement = Java.Lang.StackTraceElement;
79

@@ -37,6 +39,81 @@ public static JavaProxyThrowable Create (Exception innerException)
3739
return proxy;
3840
}
3941

42+
(int lineNumber, string? methodName, string? className) GetFrameInfo (StackFrame? managedFrame, MethodBase? managedMethod)
43+
{
44+
string? methodName = null;
45+
string? className = null;
46+
47+
if (managedFrame == null) {
48+
if (managedMethod != null) {
49+
methodName = managedMethod.Name;
50+
className = managedMethod.DeclaringType?.FullName;
51+
}
52+
53+
return (-1, methodName, className);
54+
}
55+
56+
int lineNumber = -1;
57+
lineNumber = managedFrame.GetFileLineNumber ();
58+
if (lineNumber == 0) {
59+
// -2 means it's a native frame
60+
lineNumber = managedFrame.HasNativeImage () ? -2 : -1;
61+
}
62+
63+
if (managedMethod != null) {
64+
// If we have no line number information and if it's a managed frame, add the
65+
// IL offset.
66+
if (lineNumber == -1 && managedFrame.HasILOffset ()) {
67+
methodName = $"{managedMethod.Name} + 0x{managedFrame.HasILOffset:x}";
68+
} else {
69+
methodName = managedMethod.Name;
70+
}
71+
72+
return (lineNumber, methodName, managedMethod.DeclaringType?.FullName);
73+
}
74+
75+
string frameString = managedFrame.ToString ();
76+
var sb = new StringBuilder ();
77+
78+
// We take the part of the returned string that stretches from the beginning to the first space character
79+
// and treat it as the method name.
80+
// https://github.com/dotnet/runtime/blob/18c3ad05c3fc127c3b7f37c49bc350bf7f8264a0/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs#L15-L55
81+
int pos = frameString.IndexOf (' ');
82+
string? fullName = null;
83+
if (pos > 1) {
84+
fullName = frameString.Substring (0, pos);
85+
}
86+
87+
if (!String.IsNullOrEmpty (fullName) && (pos = fullName.LastIndexOf ('.')) >= 1) {
88+
className = pos + 1 < fullName.Length ? fullName.Substring (pos + 1) : null;
89+
fullName = fullName.Substring (0, pos);
90+
}
91+
92+
if (!String.IsNullOrEmpty (fullName)) {
93+
sb.Append (fullName);
94+
} else if (managedFrame.HasNativeImage ()) {
95+
// We have no name, so we'll put the native IP
96+
nint nativeIP = managedFrame.GetNativeIP ();
97+
sb.Append (CultureInfo.InvariantCulture, $"Native 0x{nativeIP:x}");
98+
}
99+
100+
if (sb.Length > 0) {
101+
// We will also append information native offset information, if available and only if we
102+
// have recorded any previous information, since the offset without context is useless.
103+
int nativeOffset = managedFrame.GetNativeOffset ();
104+
if (nativeOffset != StackFrame.OFFSET_UNKNOWN) {
105+
sb.Append (" + ");
106+
sb.Append (CultureInfo.InvariantCulture, $"0x{nativeOffset:x}");
107+
}
108+
}
109+
110+
if (sb.Length > 0) {
111+
methodName = sb.ToString ();
112+
}
113+
114+
return (lineNumber, methodName, className);
115+
}
116+
40117
void TranslateStackTrace ()
41118
{
42119
// FIXME: https://github.com/xamarin/xamarin-android/issues/8724
@@ -61,7 +138,6 @@ void TranslateStackTrace ()
61138
// ..but ignore
62139
}
63140

64-
65141
StackFrame[] frames = trace.GetFrames ();
66142
int nElements = frames.Length + (javaTrace?.Length ?? 0);
67143
StackTraceElement[] elements = new StackTraceElement[nElements];
@@ -72,20 +148,10 @@ void TranslateStackTrace ()
72148
MethodBase? managedMethod = StackFrameGetMethod (managedFrame);
73149

74150
// https://developer.android.com/reference/java/lang/StackTraceElement?hl=en#StackTraceElement(java.lang.String,%20java.lang.String,%20java.lang.String,%20int)
75-
int lineNumber;
76-
if (managedFrame != null) {
77-
lineNumber = managedFrame.GetFileLineNumber ();
78-
if (lineNumber == 0) {
79-
// -2 means it's a native frame
80-
lineNumber = managedFrame.HasNativeImage () ? -2 : -1;
81-
}
82-
} else {
83-
lineNumber = -1;
84-
}
85-
151+
(int lineNumber, string? methodName, string? declaringClass) = GetFrameInfo (managedFrame, managedMethod);
86152
var throwableFrame = new StackTraceElement (
87-
declaringClass: managedMethod?.DeclaringType?.FullName ?? Unknown,
88-
methodName: managedMethod?.Name ?? Unknown,
153+
declaringClass: declaringClass ?? Unknown,
154+
methodName: methodName ?? Unknown,
89155
fileName: managedFrame?.GetFileName (),
90156
lineNumber: lineNumber
91157
);

0 commit comments

Comments
 (0)