Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2019 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#include "Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h"
16
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
17
#include "Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h"
18
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
19
 
20
#include <dlfcn.h>
21
#include <stdlib.h>
22
 
23
#if CLS_SIGNAL_SUPPORTED
24
static const int FIRCLSFatalSignals[FIRCLSSignalCount] = {SIGABRT, SIGBUS, SIGFPE, SIGILL,
25
                                                          SIGSEGV, SIGSYS, SIGTRAP};
26
 
27
#if CLS_USE_SIGALTSTACK
28
static void FIRCLSSignalInstallAltStack(FIRCLSSignalReadContext *roContext);
29
#endif
30
static void FIRCLSSignalInstallHandlers(FIRCLSSignalReadContext *roContext);
31
static void FIRCLSSignalHandler(int signal, siginfo_t *info, void *uapVoid);
32
 
33
void FIRCLSSignalInitialize(FIRCLSSignalReadContext *roContext) {
34
  if (!FIRCLSUnlinkIfExists(roContext->path)) {
35
    FIRCLSSDKLog("Unable to reset the signal log file %s\n", strerror(errno));
36
  }
37
 
38
#if CLS_USE_SIGALTSTACK
39
  FIRCLSSignalInstallAltStack(roContext);
40
#endif
41
  FIRCLSSignalInstallHandlers(roContext);
42
#if TARGET_IPHONE_SIMULATOR
43
  // prevent the OpenGL stack (by way of OpenGLES.framework/libLLVMContainer.dylib) from installing
44
  // signal handlers that do not chain back
45
  // TODO: I don't believe this is necessary as of recent iOS releases
46
  bool *ptr = dlsym(RTLD_DEFAULT, "_ZN4llvm23DisablePrettyStackTraceE");
47
  if (ptr) {
48
    *ptr = true;
49
  }
50
#endif
51
}
52
 
53
void FIRCLSSignalEnumerateHandledSignals(void (^block)(int idx, int signal)) {
54
  for (int i = 0; i < FIRCLSSignalCount; ++i) {
55
    block(i, FIRCLSFatalSignals[i]);
56
  }
57
}
58
 
59
#if CLS_USE_SIGALTSTACK
60
 
61
static void FIRCLSSignalInstallAltStack(FIRCLSSignalReadContext *roContext) {
62
  stack_t signalStack;
63
  stack_t originalStack;
64
 
65
  signalStack.ss_sp = _firclsContext.readonly->signalStack;
66
  signalStack.ss_size = CLS_SIGNAL_HANDLER_STACK_SIZE;
67
  signalStack.ss_flags = 0;
68
 
69
  if (sigaltstack(&signalStack, &originalStack) != 0) {
70
    FIRCLSSDKLog("Unable to setup stack %s\n", strerror(errno));
71
 
72
    return;
73
  }
74
 
75
  roContext->originalStack.ss_sp = NULL;
76
  roContext->originalStack = originalStack;
77
}
78
 
79
#endif
80
 
81
static void FIRCLSSignalInstallHandlers(FIRCLSSignalReadContext *roContext) {
82
  FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) {
83
    struct sigaction action;
84
    struct sigaction previousAction;
85
 
86
    action.sa_sigaction = FIRCLSSignalHandler;
87
    // SA_RESETHAND seems like it would be great, but it doesn't appear to
88
    // work correctly.  After taking a signal, causing another identical signal in
89
    // the handler will *not* cause the default handler to be invokved (which should
90
    // terminate the process).  I've found some evidence that others have seen this
91
    // behavior on MAC OS X.
92
    action.sa_flags = SA_SIGINFO | SA_ONSTACK;
93
 
94
    sigemptyset(&action.sa_mask);
95
 
96
    previousAction.sa_sigaction = NULL;
97
    if (sigaction(signal, &action, &previousAction) != 0) {
98
      FIRCLSSDKLog("Unable to install handler for %d (%s)\n", signal, strerror(errno));
99
    }
100
 
101
    // store the last action, so it can be recalled
102
    roContext->originalActions[idx].sa_sigaction = NULL;
103
 
104
    if (previousAction.sa_sigaction) {
105
      roContext->originalActions[idx] = previousAction;
106
    }
107
  });
108
}
109
 
110
void FIRCLSSignalCheckHandlers(void) {
111
  if (_firclsContext.readonly->debuggerAttached) {
112
    return;
113
  }
114
 
115
  FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) {
116
    struct sigaction previousAction;
117
    Dl_info info;
118
    void *ptr;
119
 
120
    if (sigaction(signal, 0, &previousAction) != 0) {
121
      fprintf(stderr, "Unable to read signal handler\n");
122
      return;
123
    }
124
 
125
    ptr = previousAction.__sigaction_u.__sa_handler;
126
    const char *signalName = NULL;
127
    const char *codeName = NULL;
128
 
129
    FIRCLSSignalNameLookup(signal, 0, &signalName, &codeName);
130
 
131
    if (ptr == FIRCLSSignalHandler) {
132
      return;
133
    }
134
 
135
    const char *name = NULL;
136
    if (dladdr(ptr, &info) != 0) {
137
      name = info.dli_sname;
138
    }
139
 
140
    fprintf(stderr,
141
            "[Crashlytics] The signal %s has a non-Crashlytics handler (%s).  This will interfere "
142
            "with reporting.\n",
143
            signalName, name);
144
  });
145
}
146
 
147
void FIRCLSSignalSafeRemoveHandlers(bool includingAbort) {
148
  FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) {
149
    struct sigaction sa;
150
 
151
    if (!includingAbort && (signal == SIGABRT)) {
152
      return;
153
    }
154
 
155
    sa.sa_handler = SIG_DFL;
156
    sigemptyset(&sa.sa_mask);
157
 
158
    if (sigaction(signal, &sa, NULL) != 0) {
159
          FIRCLSSDKLog("Unable to set default handler for %d (%s)\n", signal, strerror(errno));
160
        }
161
  });
162
}
163
 
164
bool FIRCLSSignalSafeInstallPreexistingHandlers(FIRCLSSignalReadContext *roContext,
165
                                                const int signal,
166
                                                siginfo_t *info,
167
                                                void *uapVoid) {
168
  __block bool success = true;
169
 
170
  FIRCLSSignalSafeRemoveHandlers(true);
171
 
172
#if CLS_USE_SIGALTSTACK
173
 
174
  // re-install the original stack, if needed
175
  if (roContext->originalStack.ss_sp) {
176
    if (sigaltstack(&roContext->originalStack, 0) != 0) {
177
      FIRCLSSDKLog("Unable to setup stack %s\n", strerror(errno));
178
 
179
      return false;
180
    }
181
  }
182
 
183
#endif
184
 
185
  // re-install the original handlers, if any
186
  FIRCLSSignalEnumerateHandledSignals(^(int idx, int currentSignal) {
187
      if (roContext->originalActions[idx].sa_sigaction == NULL) {
188
        return;
189
      }
190
 
191
      if (sigaction(currentSignal, &roContext->originalActions[idx], 0) != 0) {
192
        FIRCLSSDKLog("Unable to install handler for %d (%s)\n", currentSignal, strerror(errno));
193
        success = false;
194
      }
195
 
196
      // invoke original handler for current signal
197
      if (signal < 0) {
198
        return;
199
      }
200
      if (signal == currentSignal) {
201
        roContext->originalActions[idx].sa_sigaction(signal, info, uapVoid);
202
      }
203
    });
204
 
205
  return success;
206
}
207
 
208
void FIRCLSSignalNameLookup(int number, int code, const char **name, const char **codeName) {
209
  if (!name || !codeName) {
210
    return;
211
  }
212
 
213
  *codeName = NULL;
214
 
215
  switch (number) {
216
    case SIGABRT:
217
      *name = "SIGABRT";
218
      *codeName = "ABORT";
219
      break;
220
    case SIGBUS:
221
      *name = "SIGBUS";
222
      break;
223
    case SIGFPE:
224
      *name = "SIGFPE";
225
      break;
226
    case SIGILL:
227
      *name = "SIGILL";
228
      break;
229
    case SIGSEGV:
230
      *name = "SIGSEGV";
231
      break;
232
    case SIGSYS:
233
      *name = "SIGSYS";
234
      break;
235
    case SIGTRAP:
236
      *name = "SIGTRAP";
237
      break;
238
    default:
239
      *name = "UNKNOWN";
240
      break;
241
  }
242
}
243
 
244
static void FIRCLSSignalRecordSignal(int savedErrno, siginfo_t *info, void *uapVoid) {
245
  if (!_firclsContext.readonly) {
246
    return;
247
  }
248
 
249
  if (FIRCLSContextMarkAndCheckIfCrashed()) {
250
    FIRCLSSDKLog("Error: aborting signal handler because crash has already occurred");
251
    exit(1);
252
    return;
253
  }
254
 
255
  FIRCLSFile file;
256
 
257
  if (!FIRCLSFileInitWithPath(&file, _firclsContext.readonly->signal.path, false)) {
258
    FIRCLSSDKLog("Unable to open signal file\n");
259
    return;
260
  }
261
 
262
  FIRCLSFileWriteSectionStart(&file, "signal");
263
 
264
  FIRCLSFileWriteHashStart(&file);
265
 
266
  if (FIRCLSIsValidPointer(info)) {
267
    FIRCLSFileWriteHashEntryUint64(&file, "number", info->si_signo);
268
    FIRCLSFileWriteHashEntryUint64(&file, "code", info->si_code);
269
    FIRCLSFileWriteHashEntryUint64(&file, "address", (uint64_t)info->si_addr);
270
 
271
    const char *name = NULL;
272
    const char *codeName = NULL;
273
 
274
    FIRCLSSignalNameLookup(info->si_signo, info->si_code, &name, &codeName);
275
 
276
    FIRCLSFileWriteHashEntryString(&file, "name", name);
277
    FIRCLSFileWriteHashEntryString(&file, "code_name", codeName);
278
  }
279
 
280
  FIRCLSFileWriteHashEntryUint64(&file, "errno", savedErrno);
281
  FIRCLSFileWriteHashEntryUint64(&file, "time", time(NULL));
282
 
283
  FIRCLSFileWriteHashEnd(&file);
284
 
285
  FIRCLSFileWriteSectionEnd(&file);
286
 
287
  FIRCLSHandler(&file, mach_thread_self(), uapVoid);
288
 
289
  FIRCLSFileClose(&file);
290
}
291
 
292
static void FIRCLSSignalHandler(int signal, siginfo_t *info, void *uapVoid) {
293
  int savedErrno;
294
  sigset_t set;
295
 
296
  // save errno, both because it is interesting, and so we can restore it afterwards
297
  savedErrno = errno;
298
  errno = 0;
299
 
300
  FIRCLSSDKLog("Signal: %d\n", signal);
301
 
302
  // it is important to do this before unmasking signals, otherwise we can get
303
  // called in a loop
304
  FIRCLSSignalSafeRemoveHandlers(true);
305
 
306
  sigfillset(&set);
307
  if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) {
308
    FIRCLSSDKLog("Unable to unmask signals - we risk infinite recursion here\n");
309
  }
310
 
311
  // check info and uapVoid, and set them to appropriate values if invalid.  This can happen
312
  // if we have been called without the SA_SIGINFO flag set
313
  if (!FIRCLSIsValidPointer(info)) {
314
    info = NULL;
315
  }
316
 
317
  if (!FIRCLSIsValidPointer(uapVoid)) {
318
    uapVoid = NULL;
319
  }
320
 
321
  FIRCLSSignalRecordSignal(savedErrno, info, uapVoid);
322
 
323
  // re-install original handlers
324
  if (_firclsContext.readonly) {
325
    FIRCLSSignalSafeInstallPreexistingHandlers(&_firclsContext.readonly->signal, signal, info,
326
                                                   uapVoid);
327
  }
328
 
329
  // restore errno
330
  errno = savedErrno;
331
}
332
#endif