-
Notifications
You must be signed in to change notification settings - Fork 10
/
Setup.cs
178 lines (142 loc) · 4.87 KB
/
Setup.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Foundation;
using ObjCRuntime;
namespace MonoTouch.Fabric.Crashlytics
{
public class Setup
{
private enum Signal
{
SIGBUS = 10,
SIGSEGV
}
private static string Library = "";
[DllImport("libc")]
private static extern int sigaction(Setup.Signal sig, IntPtr act, IntPtr oact);
[DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")]
private static extern void void_objc_msgSend(IntPtr receiver, IntPtr selector);
public static void EnableCrashReporting(Action crashReportingDelegate, string library)
{
Library = library;
IntPtr sigbus = Marshal.AllocHGlobal(512);
IntPtr sigsev = Marshal.AllocHGlobal(512);
//store handlers
Setup.sigaction(Setup.Signal.SIGBUS, IntPtr.Zero, sigbus);
Setup.sigaction(Setup.Signal.SIGSEGV, IntPtr.Zero, sigsev);
//setup crash reporting
crashReportingDelegate();
//restore handlers
Setup.sigaction(Setup.Signal.SIGBUS, sigbus, IntPtr.Zero);
Setup.sigaction(Setup.Signal.SIGSEGV, sigsev, IntPtr.Zero);
Marshal.FreeHGlobal(sigbus);
Marshal.FreeHGlobal(sigsev);
}
public static void ThrowExceptionAsNative(Exception exception)
{
Setup.ConvertToNativeExceptionAndRaise(exception);
}
public static void ThrowExceptionAsNative(object exception)
{
Setup.ConvertToNativeExceptionAndRaise(exception);
}
public static void CaptureManagedInfo(object exception)
{
Crashlytics.SharedInstance.SetObjectValue(new NSString(Constants.Version), "monotouch version");
Exception ex = exception as Exception;
if (ex != null)
{
if (!string.IsNullOrWhiteSpace(ex.StackTrace))
Crashlytics.SharedInstance.SetObjectValue(new NSString(ex.StackTrace), "unhandled exception stack trace");
Crashlytics.SharedInstance.SetObjectValue(new NSString(ex.Message), "unhandled exception message");
Crashlytics.SharedInstance.SetObjectValue(new NSString(ex.GetType().FullName), "unhandled exception");
}
}
public static void CaptureStackFrames(object exception)
{
var frames = new List<CLSStackFrame>();
Exception ex = exception as Exception;
Action<StackTrace> frameWalker = (st) =>
{
for (int i = 0; i < st.FrameCount; i++)
{
StackFrame sf = st.GetFrame(i);
string filename = sf.GetFileName();
System.Reflection.MethodBase method = sf.GetMethod();
string methodName = "";
if (method != null)
{
var tokens = method.ToString().Split(new char[]{ ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (tokens.Count() > 1)
methodName = tokens.Skip(1).Aggregate((a, b) => a + " " + b);
else
methodName = method.ToString();
}
frames.Add(new CLSStackFrame()
{
FileName = filename ?? (method != null ? method.DeclaringType.Name + ".cs" : "uknown"),
LineNumber = (uint)sf.GetFileLineNumber(),
Library = Library,
Symbol = method != null ? method.DeclaringType.FullName + "." + methodName : "wrapper_managed_to_native"
});
}
};
if (ex != null)
{
//get traces from excetion dispath info - their are not included in StackTrace on mono
StackTrace[] traces = null;
var fi = typeof(Exception).GetField("captured_traces", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if (fi != null)
traces = fi.GetValue(ex) as StackTrace[];
if (traces != null)
foreach (var st in traces)
frameWalker(st);
frameWalker(new StackTrace(ex, true));
Crashlytics.SharedInstance.RecordCustomExceptionName(ex.GetType().Name, ex.Message, frames.Cast<NSObject>().ToArray());
}
}
private static void ConvertToNativeExceptionAndRaise(object e)
{
string name = "Managed Exception";
string reason = e.ToString();
Exception ex = e as Exception;
if (ex != null)
{
string file = "Unknown file";
string line = "???";
try
{
if (!string.IsNullOrEmpty(reason))
{
string buf = reason;
buf = buf.Replace(ex.Message, "");
buf = buf.Replace(ex.GetType().FullName, "");
var pos = buf.IndexOf(" in ");
var pos2 = buf.IndexOf(".cs", pos);
file = buf.Substring(pos + 4, pos2 + 3 - (pos + 4));
file = Path.GetFileName(file);
int i = pos2 + 4;
string line2 = "";
char tmp = reason[i];
while ("0123456789".Contains(buf[i].ToString()) && i < buf.Length)
line2 += buf[i++];
line = line2;
}
}
catch
{
}
name = string.Format("{0}: {1} - {2} line {3}", ex.GetType().FullName, ex.Message, file, line);
}
name = name.Replace("%", "%%");
reason = reason.Replace("%", "%%");
NSException nsex = new NSException(name, reason, null);
Selector selector = new Selector("raise");
void_objc_msgSend(nsex.Handle, selector.Handle);
}
}
}