blob: f73497303bec07974ce40b7c5aa8a5e542b1771f [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/mac/exception_processor.h"
#import <Foundation/Foundation.h>
#include <objc/objc-exception.h>
#include "base/debug/stack_trace.h"
#include "base/strings/sys_string_conversions.h"
#include "components/crash/core/common/crash_key.h"
namespace {
objc_exception_preprocessor g_next_preprocessor = nullptr;
bool g_first_exception_seen = false;
id ObjcExceptionPreprocessor(id exception) {
static crash_reporter::CrashKeyString<256> firstexception("firstexception");
static crash_reporter::CrashKeyString<256> lastexception("lastexception");
static crash_reporter::CrashKeyString<1024> firstexception_bt(
"firstexception_bt");
static crash_reporter::CrashKeyString<1024> lastexception_bt(
"lastexception_bt");
auto* key = g_first_exception_seen ? &lastexception : &firstexception;
auto* bt_key =
g_first_exception_seen ? &lastexception_bt : &firstexception_bt;
NSString* value = [NSString
stringWithFormat:@"%@ reason %@", [exception name], [exception reason]];
key->Set(base::SysNSStringToUTF8(value));
// This exception preprocessor runs prior to the one in libobjc, which sets
// the -[NSException callStackReturnAddresses].
crash_reporter::SetCrashKeyStringToStackTrace(bt_key,
base::debug::StackTrace());
g_first_exception_seen = true;
// Forward to the next preprocessor.
if (g_next_preprocessor) {
return g_next_preprocessor(exception);
}
return exception;
}
} // namespace
void InstallObjcExceptionPreprocessor() {
if (g_next_preprocessor) {
return;
}
g_next_preprocessor =
objc_setExceptionPreprocessor(&ObjcExceptionPreprocessor);
}
void ResetObjcExceptionStateForTesting() {
g_first_exception_seen = false;
}