11using System ;
22using System . Diagnostics ;
33using System . Diagnostics . CodeAnalysis ;
4+ using System . Globalization ;
45using System . Reflection ;
6+ using System . Text ;
57
68using 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