mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-28 16:20:01 +02:00
* Added breakpad support for Linux.
This commit is contained in:
58
thirdparty/breakpad/common/mac/Breakpad.xcconfig
vendored
Normal file
58
thirdparty/breakpad/common/mac/Breakpad.xcconfig
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
ARCHS = $(ARCHS_STANDARD_32_64_BIT)
|
||||
SDKROOT = macosx10.5
|
||||
SDKROOT[arch=i386] = macosx10.4
|
||||
SDKROOT[arch=ppc] = macosx10.4
|
||||
|
||||
GCC_VERSION = 4.2
|
||||
GCC_VERSION[sdk=macosx10.4][arch=*] = 4.0
|
||||
|
||||
GCC_C_LANGUAGE_STANDARD = c99
|
||||
|
||||
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
|
||||
// TODO(nealsid): Get the code so we can turn on the 64_TO_32 warning.
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES
|
||||
GCC_WARN_MISSING_PARENTHESES = YES
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
|
||||
GCC_WARN_SIGN_COMPARE = YES
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES
|
||||
GCC_WARN_UNUSED_VARIABLE = YES
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES
|
||||
|
||||
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
|
||||
DEBUG_INFORMATION_FORMAT[sdk=macosx10.4][arch=*] = stabs
|
||||
|
||||
ALWAYS_SEARCH_USER_PATHS = NO
|
32
thirdparty/breakpad/common/mac/BreakpadDebug.xcconfig
vendored
Normal file
32
thirdparty/breakpad/common/mac/BreakpadDebug.xcconfig
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "Breakpad.xcconfig"
|
||||
|
||||
GCC_OPTIMIZATION_LEVEL = 0
|
33
thirdparty/breakpad/common/mac/BreakpadRelease.xcconfig
vendored
Normal file
33
thirdparty/breakpad/common/mac/BreakpadRelease.xcconfig
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "Breakpad.xcconfig"
|
||||
|
||||
GCC_OPTIMIZATION_LEVEL = s
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES
|
241
thirdparty/breakpad/common/mac/GTMDefines.h
vendored
Normal file
241
thirdparty/breakpad/common/mac/GTMDefines.h
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
//
|
||||
// GTMDefines.h
|
||||
//
|
||||
// Copyright 2008 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy
|
||||
// of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
//
|
||||
|
||||
// ============================================================================
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs
|
||||
#ifndef MAC_OS_X_VERSION_10_5
|
||||
#define MAC_OS_X_VERSION_10_5 1050
|
||||
#endif
|
||||
#ifndef MAC_OS_X_VERSION_10_6
|
||||
#define MAC_OS_X_VERSION_10_6 1060
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CPP symbols that can be overridden in a prefix to control how the toolbox
|
||||
// is compiled.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and
|
||||
// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens
|
||||
// when a validation fails. If you implement your own validators, you may want
|
||||
// to control their internals using the same macros for consistency.
|
||||
#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT
|
||||
#define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0
|
||||
#endif
|
||||
|
||||
// Give ourselves a consistent way to do inlines. Apple's macros even use
|
||||
// a few different actual definitions, so we're based off of the foundation
|
||||
// one.
|
||||
#if !defined(GTM_INLINE)
|
||||
#if defined (__GNUC__) && (__GNUC__ == 4)
|
||||
#define GTM_INLINE static __inline__ __attribute__((always_inline))
|
||||
#else
|
||||
#define GTM_INLINE static __inline__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Give ourselves a consistent way of doing externs that links up nicely
|
||||
// when mixing objc and objc++
|
||||
#if !defined (GTM_EXTERN)
|
||||
#if defined __cplusplus
|
||||
#define GTM_EXTERN extern "C"
|
||||
#else
|
||||
#define GTM_EXTERN extern
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Give ourselves a consistent way of exporting things if we have visibility
|
||||
// set to hidden.
|
||||
#if !defined (GTM_EXPORT)
|
||||
#define GTM_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
// _GTMDevLog & _GTMDevAssert
|
||||
//
|
||||
// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for
|
||||
// developer level errors. This implementation simply macros to NSLog/NSAssert.
|
||||
// It is not intended to be a general logging/reporting system.
|
||||
//
|
||||
// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert
|
||||
// for a little more background on the usage of these macros.
|
||||
//
|
||||
// _GTMDevLog log some error/problem in debug builds
|
||||
// _GTMDevAssert assert if conditon isn't met w/in a method/function
|
||||
// in all builds.
|
||||
//
|
||||
// To replace this system, just provide different macro definitions in your
|
||||
// prefix header. Remember, any implementation you provide *must* be thread
|
||||
// safe since this could be called by anything in what ever situtation it has
|
||||
// been placed in.
|
||||
//
|
||||
|
||||
// We only define the simple macros if nothing else has defined this.
|
||||
#ifndef _GTMDevLog
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _GTMDevLog(...) NSLog(__VA_ARGS__)
|
||||
#else
|
||||
#define _GTMDevLog(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif // _GTMDevLog
|
||||
|
||||
// Declared here so that it can easily be used for logging tracking if
|
||||
// necessary. See GTMUnitTestDevLog.h for details.
|
||||
@class NSString;
|
||||
GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||
|
||||
#ifndef _GTMDevAssert
|
||||
// we directly invoke the NSAssert handler so we can pass on the varargs
|
||||
// (NSAssert doesn't have a macro we can use that takes varargs)
|
||||
#if !defined(NS_BLOCK_ASSERTIONS)
|
||||
#define _GTMDevAssert(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
[[NSAssertionHandler currentHandler] \
|
||||
handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \
|
||||
file:[NSString stringWithUTF8String:__FILE__] \
|
||||
lineNumber:__LINE__ \
|
||||
description:__VA_ARGS__]; \
|
||||
} \
|
||||
} while(0)
|
||||
#else // !defined(NS_BLOCK_ASSERTIONS)
|
||||
#define _GTMDevAssert(condition, ...) do { } while (0)
|
||||
#endif // !defined(NS_BLOCK_ASSERTIONS)
|
||||
|
||||
#endif // _GTMDevAssert
|
||||
|
||||
// _GTMCompileAssert
|
||||
// _GTMCompileAssert is an assert that is meant to fire at compile time if you
|
||||
// want to check things at compile instead of runtime. For example if you
|
||||
// want to check that a wchar is 4 bytes instead of 2 you would use
|
||||
// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X)
|
||||
// Note that the second "arg" is not in quotes, and must be a valid processor
|
||||
// symbol in it's own right (no spaces, punctuation etc).
|
||||
|
||||
// Wrapping this in an #ifndef allows external groups to define their own
|
||||
// compile time assert scheme.
|
||||
#ifndef _GTMCompileAssert
|
||||
// We got this technique from here:
|
||||
// http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html
|
||||
|
||||
#define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg
|
||||
#define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg)
|
||||
#define _GTMCompileAssert(test, msg) \
|
||||
typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
|
||||
#endif // _GTMCompileAssert
|
||||
|
||||
// Macro to allow fast enumeration when building for 10.5 or later, and
|
||||
// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration
|
||||
// does keys, so pick the right thing, nothing is done on the FastEnumeration
|
||||
// side to be sure you're getting what you wanted.
|
||||
#ifndef GTM_FOREACH_OBJECT
|
||||
#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
#define GTM_FOREACH_OBJECT(element, collection) \
|
||||
for (element in collection)
|
||||
#define GTM_FOREACH_KEY(element, collection) \
|
||||
for (element in collection)
|
||||
#else
|
||||
#define GTM_FOREACH_OBJECT(element, collection) \
|
||||
for (NSEnumerator * _ ## element ## _enum = [collection objectEnumerator]; \
|
||||
(element = [_ ## element ## _enum nextObject]) != nil; )
|
||||
#define GTM_FOREACH_KEY(element, collection) \
|
||||
for (NSEnumerator * _ ## element ## _enum = [collection keyEnumerator]; \
|
||||
(element = [_ ## element ## _enum nextObject]) != nil; )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CPP symbols defined based on the project settings so the GTM code has
|
||||
// simple things to test against w/o scattering the knowledge of project
|
||||
// setting through all the code.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Provide a single constant CPP symbol that all of GTM uses for ifdefing
|
||||
// iPhone code.
|
||||
#if TARGET_OS_IPHONE // iPhone SDK
|
||||
// For iPhone specific stuff
|
||||
#define GTM_IPHONE_SDK 1
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
#define GTM_IPHONE_SIMULATOR 1
|
||||
#else
|
||||
#define GTM_IPHONE_DEVICE 1
|
||||
#endif // TARGET_IPHONE_SIMULATOR
|
||||
#else
|
||||
// For MacOS specific stuff
|
||||
#define GTM_MACOS_SDK 1
|
||||
#endif
|
||||
|
||||
// Provide a symbol to include/exclude extra code for GC support. (This mainly
|
||||
// just controls the inclusion of finalize methods).
|
||||
#ifndef GTM_SUPPORT_GC
|
||||
#if GTM_IPHONE_SDK
|
||||
// iPhone never needs GC
|
||||
#define GTM_SUPPORT_GC 0
|
||||
#else
|
||||
// We can't find a symbol to tell if GC is supported/required, so best we
|
||||
// do on Mac targets is include it if we're on 10.5 or later.
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
||||
#define GTM_SUPPORT_GC 0
|
||||
#else
|
||||
#define GTM_SUPPORT_GC 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// To simplify support for 64bit (and Leopard in general), we provide the type
|
||||
// defines for non Leopard SDKs
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
||||
// NSInteger/NSUInteger and Max/Mins
|
||||
#ifndef NSINTEGER_DEFINED
|
||||
#if __LP64__ || NS_BUILD_32_LIKE_64
|
||||
typedef long NSInteger;
|
||||
typedef unsigned long NSUInteger;
|
||||
#else
|
||||
typedef int NSInteger;
|
||||
typedef unsigned int NSUInteger;
|
||||
#endif
|
||||
#define NSIntegerMax LONG_MAX
|
||||
#define NSIntegerMin LONG_MIN
|
||||
#define NSUIntegerMax ULONG_MAX
|
||||
#define NSINTEGER_DEFINED 1
|
||||
#endif // NSINTEGER_DEFINED
|
||||
// CGFloat
|
||||
#ifndef CGFLOAT_DEFINED
|
||||
#if defined(__LP64__) && __LP64__
|
||||
// This really is an untested path (64bit on Tiger?)
|
||||
typedef double CGFloat;
|
||||
#define CGFLOAT_MIN DBL_MIN
|
||||
#define CGFLOAT_MAX DBL_MAX
|
||||
#define CGFLOAT_IS_DOUBLE 1
|
||||
#else /* !defined(__LP64__) || !__LP64__ */
|
||||
typedef float CGFloat;
|
||||
#define CGFLOAT_MIN FLT_MIN
|
||||
#define CGFLOAT_MAX FLT_MAX
|
||||
#define CGFLOAT_IS_DOUBLE 0
|
||||
#endif /* !defined(__LP64__) || !__LP64__ */
|
||||
#define CGFLOAT_DEFINED 1
|
||||
#endif // CGFLOAT_DEFINED
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
72
thirdparty/breakpad/common/mac/GTMGarbageCollection.h
vendored
Normal file
72
thirdparty/breakpad/common/mac/GTMGarbageCollection.h
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// GTMGarbageCollection.h
|
||||
//
|
||||
// Copyright 2007-2008 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy
|
||||
// of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "GTMDefines.h"
|
||||
|
||||
// This allows us to easily move our code from GC to non GC.
|
||||
// They are no-ops unless we are require Leopard or above.
|
||||
// See
|
||||
// http://developer.apple.com/documentation/Cocoa/Conceptual/GarbageCollection/index.html
|
||||
// and
|
||||
// http://developer.apple.com/documentation/Cocoa/Conceptual/GarbageCollection/Articles/gcCoreFoundation.html#//apple_ref/doc/uid/TP40006687-SW1
|
||||
// for details.
|
||||
|
||||
#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) && !GTM_IPHONE_SDK
|
||||
// General use would be to call this through GTMCFAutorelease
|
||||
// but there may be a reason the you want to make something collectable
|
||||
// but not autoreleased, especially in pure GC code where you don't
|
||||
// want to bother with the nop autorelease. Done as a define instead of an
|
||||
// inline so that tools like Clang's scan-build don't report code as leaking.
|
||||
#define GTMNSMakeCollectable(cf) ((id)NSMakeCollectable(cf))
|
||||
|
||||
// GTMNSMakeUncollectable is for global maps, etc. that we don't
|
||||
// want released ever. You should still retain these in non-gc code.
|
||||
GTM_INLINE void GTMNSMakeUncollectable(id object) {
|
||||
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:object];
|
||||
}
|
||||
|
||||
// Hopefully no code really needs this, but GTMIsGarbageCollectionEnabled is
|
||||
// a common way to check at runtime if GC is on.
|
||||
// There are some places where GC doesn't work w/ things w/in Apple's
|
||||
// frameworks, so this is here so GTM unittests and detect it, and not run
|
||||
// individual tests to work around bugs in Apple's frameworks.
|
||||
GTM_INLINE BOOL GTMIsGarbageCollectionEnabled(void) {
|
||||
return ([NSGarbageCollector defaultCollector] != nil);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define GTMNSMakeCollectable(cf) ((id)(cf))
|
||||
|
||||
GTM_INLINE void GTMNSMakeUncollectable(id object) {
|
||||
}
|
||||
|
||||
GTM_INLINE BOOL GTMIsGarbageCollectionEnabled(void) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// GTMCFAutorelease makes a CF object collectable in GC mode, or adds it
|
||||
// to the autorelease pool in non-GC mode. Either way it is taken care
|
||||
// of. Done as a define instead of an inline so that tools like Clang's
|
||||
// scan-build don't report code as leaking.
|
||||
#define GTMCFAutorelease(cf) ([GTMNSMakeCollectable(cf) autorelease])
|
||||
|
458
thirdparty/breakpad/common/mac/GTMLogger.h
vendored
Normal file
458
thirdparty/breakpad/common/mac/GTMLogger.h
vendored
Normal file
@@ -0,0 +1,458 @@
|
||||
//
|
||||
// GTMLogger.h
|
||||
//
|
||||
// Copyright 2007-2008 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy
|
||||
// of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
//
|
||||
|
||||
// Key Abstractions
|
||||
// ----------------
|
||||
//
|
||||
// This file declares multiple classes and protocols that are used by the
|
||||
// GTMLogger logging system. The 4 main abstractions used in this file are the
|
||||
// following:
|
||||
//
|
||||
// * logger (GTMLogger) - The main logging class that users interact with. It
|
||||
// has methods for logging at different levels and uses a log writer, a log
|
||||
// formatter, and a log filter to get the job done.
|
||||
//
|
||||
// * log writer (GTMLogWriter) - Writes a given string to some log file, where
|
||||
// a "log file" can be a physical file on disk, a POST over HTTP to some URL,
|
||||
// or even some in-memory structure (e.g., a ring buffer).
|
||||
//
|
||||
// * log formatter (GTMLogFormatter) - Given a format string and arguments as
|
||||
// a va_list, returns a single formatted NSString. A "formatted string" could
|
||||
// be a string with the date prepended, a string with values in a CSV format,
|
||||
// or even a string of XML.
|
||||
//
|
||||
// * log filter (GTMLogFilter) - Given a formatted log message as an NSString
|
||||
// and the level at which the message is to be logged, this class will decide
|
||||
// whether the given message should be logged or not. This is a flexible way
|
||||
// to filter out messages logged at a certain level, messages that contain
|
||||
// certain text, or filter nothing out at all. This gives the caller the
|
||||
// flexibility to dynamically enable debug logging in Release builds.
|
||||
//
|
||||
// This file also declares some classes to handle the common log writer, log
|
||||
// formatter, and log filter cases. Callers can also create their own writers,
|
||||
// formatters, and filters and they can even build them on top of the ones
|
||||
// declared here. Keep in mind that your custom writer/formatter/filter may be
|
||||
// called from multiple threads, so it must be thread-safe.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "GTMDefines.h"
|
||||
|
||||
// Predeclaration of used protocols that are declared later in this file.
|
||||
@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter;
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
|
||||
#define CHECK_FORMAT_NSSTRING(a, b) __attribute__((format(__NSString__, a, b)))
|
||||
#else
|
||||
#define CHECK_FORMAT_NSSTRING(a, b)
|
||||
#endif
|
||||
|
||||
// GTMLogger
|
||||
//
|
||||
// GTMLogger is the primary user-facing class for an object-oriented logging
|
||||
// system. It is built on the concept of log formatters (GTMLogFormatter), log
|
||||
// writers (GTMLogWriter), and log filters (GTMLogFilter). When a message is
|
||||
// sent to a GTMLogger to log a message, the message is formatted using the log
|
||||
// formatter, then the log filter is consulted to see if the message should be
|
||||
// logged, and if so, the message is sent to the log writer to be written out.
|
||||
//
|
||||
// GTMLogger is intended to be a flexible and thread-safe logging solution. Its
|
||||
// flexibility comes from the fact that GTMLogger instances can be customized
|
||||
// with user defined formatters, filters, and writers. And these writers,
|
||||
// filters, and formatters can be combined, stacked, and customized in arbitrary
|
||||
// ways to suit the needs at hand. For example, multiple writers can be used at
|
||||
// the same time, and a GTMLogger instance can even be used as another
|
||||
// GTMLogger's writer. This allows for arbitrarily deep logging trees.
|
||||
//
|
||||
// A standard GTMLogger uses a writer that sends messages to standard out, a
|
||||
// formatter that smacks a timestamp and a few other bits of interesting
|
||||
// information on the message, and a filter that filters out debug messages from
|
||||
// release builds. Using the standard log settings, a log message will look like
|
||||
// the following:
|
||||
//
|
||||
// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] foo=<Foo: 0x123>
|
||||
//
|
||||
// The output contains the date and time of the log message, the name of the
|
||||
// process followed by its process ID/thread ID, the log level at which the
|
||||
// message was logged (in the previous example the level was 1:
|
||||
// kGTMLoggerLevelDebug), and finally, the user-specified log message itself (in
|
||||
// this case, the log message was @"foo=%@", foo).
|
||||
//
|
||||
// Multiple instances of GTMLogger can be created, each configured their own
|
||||
// way. Though GTMLogger is not a singleton (in the GoF sense), it does provide
|
||||
// access to a shared (i.e., globally accessible) GTMLogger instance. This makes
|
||||
// it convenient for all code in a process to use the same GTMLogger instance.
|
||||
// The shared GTMLogger instance can also be configured in an arbitrary, and
|
||||
// these configuration changes will affect all code that logs through the shared
|
||||
// instance.
|
||||
|
||||
//
|
||||
// Log Levels
|
||||
// ----------
|
||||
// GTMLogger has 3 different log levels: Debug, Info, and Error. GTMLogger
|
||||
// doesn't take any special action based on the log level; it simply forwards
|
||||
// this information on to formatters, filters, and writers, each of which may
|
||||
// optionally take action based on the level. Since log level filtering is
|
||||
// performed at runtime, log messages are typically not filtered out at compile
|
||||
// time. The exception to this rule is that calls to the GTMLoggerDebug() macro
|
||||
// *ARE* filtered out of non-DEBUG builds. This is to be backwards compatible
|
||||
// with behavior that many developers are currently used to. Note that this
|
||||
// means that GTMLoggerDebug(@"hi") will be compiled out of Release builds, but
|
||||
// [[GTMLogger sharedLogger] logDebug:@"hi"] will NOT be compiled out.
|
||||
//
|
||||
// Standard loggers are created with the GTMLogLevelFilter log filter, which
|
||||
// filters out certain log messages based on log level, and some other settings.
|
||||
//
|
||||
// In addition to the -logDebug:, -logInfo:, and -logError: methods defined on
|
||||
// GTMLogger itself, there are also C macros that make usage of the shared
|
||||
// GTMLogger instance very convenient. These macros are:
|
||||
//
|
||||
// GTMLoggerDebug(...)
|
||||
// GTMLoggerInfo(...)
|
||||
// GTMLoggerError(...)
|
||||
//
|
||||
// Again, a notable feature of these macros is that GTMLogDebug() calls *will be
|
||||
// compiled out of non-DEBUG builds*.
|
||||
//
|
||||
// Standard Loggers
|
||||
// ----------------
|
||||
// GTMLogger has the concept of "standard loggers". A standard logger is simply
|
||||
// a logger that is pre-configured with some standard/common writer, formatter,
|
||||
// and filter combination. Standard loggers are created using the creation
|
||||
// methods beginning with "standard". The alternative to a standard logger is a
|
||||
// regular logger, which will send messages to stdout, with no special
|
||||
// formatting, and no filtering.
|
||||
//
|
||||
// How do I use GTMLogger?
|
||||
// ----------------------
|
||||
// The typical way you will want to use GTMLogger is to simply use the
|
||||
// GTMLogger*() macros for logging from code. That way we can easily make
|
||||
// changes to the GTMLogger class and simply update the macros accordingly. Only
|
||||
// your application startup code (perhaps, somewhere in main()) should use the
|
||||
// GTMLogger class directly in order to configure the shared logger, which all
|
||||
// of the code using the macros will be using. Again, this is just the typical
|
||||
// situation.
|
||||
//
|
||||
// To be complete, there are cases where you may want to use GTMLogger directly,
|
||||
// or even create separate GTMLogger instances for some reason. That's fine,
|
||||
// too.
|
||||
//
|
||||
// Examples
|
||||
// --------
|
||||
// The following show some common GTMLogger use cases.
|
||||
//
|
||||
// 1. You want to log something as simply as possible. Also, this call will only
|
||||
// appear in debug builds. In non-DEBUG builds it will be completely removed.
|
||||
//
|
||||
// GTMLoggerDebug(@"foo = %@", foo);
|
||||
//
|
||||
// 2. The previous example is similar to the following. The major difference is
|
||||
// that the previous call (example 1) will be compiled out of Release builds
|
||||
// but this statement will not be compiled out.
|
||||
//
|
||||
// [[GTMLogger sharedLogger] logDebug:@"foo = %@", foo];
|
||||
//
|
||||
// 3. Send all logging output from the shared logger to a file. We do this by
|
||||
// creating an NSFileHandle for writing associated with a file, and setting
|
||||
// that file handle as the logger's writer.
|
||||
//
|
||||
// NSFileHandle *f = [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log"
|
||||
// create:YES];
|
||||
// [[GTMLogger sharedLogger] setWriter:f];
|
||||
// GTMLoggerError(@"hi"); // This will be sent to /tmp/f.log
|
||||
//
|
||||
// 4. Create a new GTMLogger that will log to a file. This example differs from
|
||||
// the previous one because here we create a new GTMLogger that is different
|
||||
// from the shared logger.
|
||||
//
|
||||
// GTMLogger *logger = [GTMLogger standardLoggerWithPath:@"/tmp/temp.log"];
|
||||
// [logger logInfo:@"hi temp log file"];
|
||||
//
|
||||
// 5. Create a logger that writes to stdout and does NOT do any formatting to
|
||||
// the log message. This might be useful, for example, when writing a help
|
||||
// screen for a command-line tool to standard output.
|
||||
//
|
||||
// GTMLogger *logger = [GTMLogger logger];
|
||||
// [logger logInfo:@"%@ version 0.1 usage", progName];
|
||||
//
|
||||
// 6. Send log output to stdout AND to a log file. The trick here is that
|
||||
// NSArrays function as composite log writers, which means when an array is
|
||||
// set as the log writer, it forwards all logging messages to all of its
|
||||
// contained GTMLogWriters.
|
||||
//
|
||||
// // Create array of GTMLogWriters
|
||||
// NSArray *writers = [NSArray arrayWithObjects:
|
||||
// [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log" create:YES],
|
||||
// [NSFileHandle fileHandleWithStandardOutput], nil];
|
||||
//
|
||||
// GTMLogger *logger = [GTMLogger standardLogger];
|
||||
// [logger setWriter:writers];
|
||||
// [logger logInfo:@"hi"]; // Output goes to stdout and /tmp/f.log
|
||||
//
|
||||
// For futher details on log writers, formatters, and filters, see the
|
||||
// documentation below.
|
||||
//
|
||||
// NOTE: GTMLogger is application level logging. By default it does nothing
|
||||
// with _GTMDevLog/_GTMDevAssert (see GTMDefines.h). An application can choose
|
||||
// to bridge _GTMDevLog/_GTMDevAssert to GTMLogger by providing macro
|
||||
// definitions in its prefix header (see GTMDefines.h for how one would do
|
||||
// that).
|
||||
//
|
||||
@interface GTMLogger : NSObject {
|
||||
@private
|
||||
id<GTMLogWriter> writer_;
|
||||
id<GTMLogFormatter> formatter_;
|
||||
id<GTMLogFilter> filter_;
|
||||
}
|
||||
|
||||
//
|
||||
// Accessors for the shared logger instance
|
||||
//
|
||||
|
||||
// Returns a shared/global standard GTMLogger instance. Callers should typically
|
||||
// use this method to get a GTMLogger instance, unless they explicitly want
|
||||
// their own instance to configure for their own needs. This is the only method
|
||||
// that returns a shared instance; all the rest return new GTMLogger instances.
|
||||
+ (id)sharedLogger;
|
||||
|
||||
// Sets the shared logger instance to |logger|. Future calls to +sharedLogger
|
||||
// will return |logger| instead.
|
||||
+ (void)setSharedLogger:(GTMLogger *)logger;
|
||||
|
||||
//
|
||||
// Creation methods
|
||||
//
|
||||
|
||||
// Returns a new autoreleased GTMLogger instance that will log to stdout, using
|
||||
// the GTMLogStandardFormatter, and the GTMLogLevelFilter filter.
|
||||
+ (id)standardLogger;
|
||||
|
||||
// Same as +standardLogger, but logs to stderr.
|
||||
+ (id)standardLoggerWithStderr;
|
||||
|
||||
// Returns a new standard GTMLogger instance with a log writer that will
|
||||
// write to the file at |path|, and will use the GTMLogStandardFormatter and
|
||||
// GTMLogLevelFilter classes. If |path| does not exist, it will be created.
|
||||
+ (id)standardLoggerWithPath:(NSString *)path;
|
||||
|
||||
// Returns an autoreleased GTMLogger instance that will use the specified
|
||||
// |writer|, |formatter|, and |filter|.
|
||||
+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
|
||||
formatter:(id<GTMLogFormatter>)formatter
|
||||
filter:(id<GTMLogFilter>)filter;
|
||||
|
||||
// Returns an autoreleased GTMLogger instance that logs to stdout, with the
|
||||
// basic formatter, and no filter. The returned logger differs from the logger
|
||||
// returned by +standardLogger because this one does not do any filtering and
|
||||
// does not do any special log formatting; this is the difference between a
|
||||
// "regular" logger and a "standard" logger.
|
||||
+ (id)logger;
|
||||
|
||||
// Designated initializer. This method returns a GTMLogger initialized with the
|
||||
// specified |writer|, |formatter|, and |filter|. See the setter methods below
|
||||
// for what values will be used if nil is passed for a parameter.
|
||||
- (id)initWithWriter:(id<GTMLogWriter>)writer
|
||||
formatter:(id<GTMLogFormatter>)formatter
|
||||
filter:(id<GTMLogFilter>)filter;
|
||||
|
||||
//
|
||||
// Logging methods
|
||||
//
|
||||
|
||||
// Logs a message at the debug level (kGTMLoggerLevelDebug).
|
||||
- (void)logDebug:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
// Logs a message at the info level (kGTMLoggerLevelInfo).
|
||||
- (void)logInfo:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
// Logs a message at the error level (kGTMLoggerLevelError).
|
||||
- (void)logError:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
// Logs a message at the assert level (kGTMLoggerLevelAssert).
|
||||
- (void)logAssert:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
|
||||
|
||||
//
|
||||
// Accessors
|
||||
//
|
||||
|
||||
// Accessor methods for the log writer. If the log writer is set to nil,
|
||||
// [NSFileHandle fileHandleWithStandardOutput] is used.
|
||||
- (id<GTMLogWriter>)writer;
|
||||
- (void)setWriter:(id<GTMLogWriter>)writer;
|
||||
|
||||
// Accessor methods for the log formatter. If the log formatter is set to nil,
|
||||
// GTMLogBasicFormatter is used. This formatter will format log messages in a
|
||||
// plain printf style.
|
||||
- (id<GTMLogFormatter>)formatter;
|
||||
- (void)setFormatter:(id<GTMLogFormatter>)formatter;
|
||||
|
||||
// Accessor methods for the log filter. If the log filter is set to nil,
|
||||
// GTMLogNoFilter is used, which allows all log messages through.
|
||||
- (id<GTMLogFilter>)filter;
|
||||
- (void)setFilter:(id<GTMLogFilter>)filter;
|
||||
|
||||
@end // GTMLogger
|
||||
|
||||
|
||||
// Helper functions that are used by the convenience GTMLogger*() macros that
|
||||
// enable the logging of function names.
|
||||
@interface GTMLogger (GTMLoggerMacroHelpers)
|
||||
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
@end // GTMLoggerMacroHelpers
|
||||
|
||||
|
||||
// Convenience macros that log to the shared GTMLogger instance. These macros
|
||||
// are how users should typically log to GTMLogger. Notice that GTMLoggerDebug()
|
||||
// calls will be compiled out of non-Debug builds.
|
||||
#define GTMLoggerDebug(...) \
|
||||
[[GTMLogger sharedLogger] logFuncDebug:__func__ msg:__VA_ARGS__]
|
||||
#define GTMLoggerInfo(...) \
|
||||
[[GTMLogger sharedLogger] logFuncInfo:__func__ msg:__VA_ARGS__]
|
||||
#define GTMLoggerError(...) \
|
||||
[[GTMLogger sharedLogger] logFuncError:__func__ msg:__VA_ARGS__]
|
||||
#define GTMLoggerAssert(...) \
|
||||
[[GTMLogger sharedLogger] logFuncAssert:__func__ msg:__VA_ARGS__]
|
||||
|
||||
// If we're not in a debug build, remove the GTMLoggerDebug statements. This
|
||||
// makes calls to GTMLoggerDebug "compile out" of Release builds
|
||||
#ifndef DEBUG
|
||||
#undef GTMLoggerDebug
|
||||
#define GTMLoggerDebug(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
// Log levels.
|
||||
typedef enum {
|
||||
kGTMLoggerLevelUnknown,
|
||||
kGTMLoggerLevelDebug,
|
||||
kGTMLoggerLevelInfo,
|
||||
kGTMLoggerLevelError,
|
||||
kGTMLoggerLevelAssert,
|
||||
} GTMLoggerLevel;
|
||||
|
||||
|
||||
//
|
||||
// Log Writers
|
||||
//
|
||||
|
||||
// Protocol to be implemented by a GTMLogWriter instance.
|
||||
@protocol GTMLogWriter <NSObject>
|
||||
// Writes the given log message to where the log writer is configured to write.
|
||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level;
|
||||
@end // GTMLogWriter
|
||||
|
||||
|
||||
// Simple category on NSFileHandle that makes NSFileHandles valid log writers.
|
||||
// This is convenient because something like, say, +fileHandleWithStandardError
|
||||
// now becomes a valid log writer. Log messages are written to the file handle
|
||||
// with a newline appended.
|
||||
@interface NSFileHandle (GTMFileHandleLogWriter) <GTMLogWriter>
|
||||
// Opens the file at |path| in append mode, and creates the file with |mode|
|
||||
// if it didn't previously exist.
|
||||
+ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode;
|
||||
@end // NSFileHandle
|
||||
|
||||
|
||||
// This category makes NSArray a GTMLogWriter that can be composed of other
|
||||
// GTMLogWriters. This is the classic Composite GoF design pattern. When the
|
||||
// GTMLogWriter -logMessage:level: message is sent to the array, the array
|
||||
// forwards the message to all of its elements that implement the GTMLogWriter
|
||||
// protocol.
|
||||
//
|
||||
// This is useful in situations where you would like to send log output to
|
||||
// multiple log writers at the same time. Simply create an NSArray of the log
|
||||
// writers you wish to use, then set the array as the "writer" for your
|
||||
// GTMLogger instance.
|
||||
@interface NSArray (GTMArrayCompositeLogWriter) <GTMLogWriter>
|
||||
@end // GTMArrayCompositeLogWriter
|
||||
|
||||
|
||||
// This category adapts the GTMLogger interface so that it can be used as a log
|
||||
// writer; it's an "adapter" in the GoF Adapter pattern sense.
|
||||
//
|
||||
// This is useful when you want to configure a logger to log to a specific
|
||||
// writer with a specific formatter and/or filter. But you want to also compose
|
||||
// that with a different log writer that may have its own formatter and/or
|
||||
// filter.
|
||||
@interface GTMLogger (GTMLoggerLogWriter) <GTMLogWriter>
|
||||
@end // GTMLoggerLogWriter
|
||||
|
||||
|
||||
//
|
||||
// Log Formatters
|
||||
//
|
||||
|
||||
// Protocol to be implemented by a GTMLogFormatter instance.
|
||||
@protocol GTMLogFormatter <NSObject>
|
||||
// Returns a formatted string using the format specified in |fmt| and the va
|
||||
// args specified in |args|.
|
||||
- (NSString *)stringForFunc:(NSString *)func
|
||||
withFormat:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level;
|
||||
@end // GTMLogFormatter
|
||||
|
||||
|
||||
// A basic log formatter that formats a string the same way that NSLog (or
|
||||
// printf) would. It does not do anything fancy, nor does it add any data of its
|
||||
// own.
|
||||
@interface GTMLogBasicFormatter : NSObject <GTMLogFormatter>
|
||||
@end // GTMLogBasicFormatter
|
||||
|
||||
|
||||
// A log formatter that formats the log string like the basic formatter, but
|
||||
// also prepends a timestamp and some basic process info to the message, as
|
||||
// shown in the following sample output.
|
||||
// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] log mesage here
|
||||
@interface GTMLogStandardFormatter : GTMLogBasicFormatter {
|
||||
@private
|
||||
NSDateFormatter *dateFormatter_; // yyyy-MM-dd HH:mm:ss.SSS
|
||||
NSString *pname_;
|
||||
pid_t pid_;
|
||||
}
|
||||
@end // GTMLogStandardFormatter
|
||||
|
||||
|
||||
//
|
||||
// Log Filters
|
||||
//
|
||||
|
||||
// Protocol to be imlemented by a GTMLogFilter instance.
|
||||
@protocol GTMLogFilter <NSObject>
|
||||
// Returns YES if |msg| at |level| should be filtered out; NO otherwise.
|
||||
- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level;
|
||||
@end // GTMLogFilter
|
||||
|
||||
|
||||
// A log filter that filters messages at the kGTMLoggerLevelDebug level out of
|
||||
// non-debug builds. Messages at the kGTMLoggerLevelInfo level are also filtered
|
||||
// out of non-debug builds unless GTMVerboseLogging is set in the environment or
|
||||
// the processes's defaults. Messages at the kGTMLoggerLevelError level are
|
||||
// never filtered.
|
||||
@interface GTMLogLevelFilter : NSObject <GTMLogFilter>
|
||||
@end // GTMLogLevelFilter
|
||||
|
||||
|
||||
// A simple log filter that does NOT filter anything out;
|
||||
// -filterAllowsMessage:level will always return YES. This can be a convenient
|
||||
// way to enable debug-level logging in release builds (if you so desire).
|
||||
@interface GTMLogNoFilter : NSObject <GTMLogFilter>
|
||||
@end // GTMLogNoFilter
|
445
thirdparty/breakpad/common/mac/GTMLogger.m
vendored
Normal file
445
thirdparty/breakpad/common/mac/GTMLogger.m
vendored
Normal file
@@ -0,0 +1,445 @@
|
||||
//
|
||||
// GTMLogger.m
|
||||
//
|
||||
// Copyright 2007-2008 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy
|
||||
// of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
//
|
||||
|
||||
#import "GTMLogger.h"
|
||||
#import "GTMGarbageCollection.h"
|
||||
#import <fcntl.h>
|
||||
#import <unistd.h>
|
||||
#import <stdlib.h>
|
||||
#import <pthread.h>
|
||||
|
||||
|
||||
// Define a trivial assertion macro to avoid dependencies
|
||||
#ifdef DEBUG
|
||||
#define GTMLOGGER_ASSERT(expr) assert(expr)
|
||||
#else
|
||||
#define GTMLOGGER_ASSERT(expr)
|
||||
#endif
|
||||
|
||||
|
||||
@interface GTMLogger (PrivateMethods)
|
||||
|
||||
- (void)logInternalFunc:(const char *)func
|
||||
format:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// Reference to the shared GTMLogger instance. This is not a singleton, it's
|
||||
// just an easy reference to one shared instance.
|
||||
static GTMLogger *gSharedLogger = nil;
|
||||
|
||||
|
||||
@implementation GTMLogger
|
||||
|
||||
// Returns a pointer to the shared logger instance. If none exists, a standard
|
||||
// logger is created and returned.
|
||||
+ (id)sharedLogger {
|
||||
@synchronized(self) {
|
||||
if (gSharedLogger == nil) {
|
||||
gSharedLogger = [[self standardLogger] retain];
|
||||
}
|
||||
GTMLOGGER_ASSERT(gSharedLogger != nil);
|
||||
}
|
||||
return [[gSharedLogger retain] autorelease];
|
||||
}
|
||||
|
||||
+ (void)setSharedLogger:(GTMLogger *)logger {
|
||||
@synchronized(self) {
|
||||
[gSharedLogger autorelease];
|
||||
gSharedLogger = [logger retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)standardLogger {
|
||||
id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
|
||||
id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init] autorelease];
|
||||
id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
|
||||
return [self loggerWithWriter:writer formatter:fr filter:filter];
|
||||
}
|
||||
|
||||
+ (id)standardLoggerWithStderr {
|
||||
id me = [self standardLogger];
|
||||
[me setWriter:[NSFileHandle fileHandleWithStandardError]];
|
||||
return me;
|
||||
}
|
||||
|
||||
+ (id)standardLoggerWithPath:(NSString *)path {
|
||||
NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
|
||||
if (fh == nil) return nil;
|
||||
id me = [self standardLogger];
|
||||
[me setWriter:fh];
|
||||
return me;
|
||||
}
|
||||
|
||||
+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
|
||||
formatter:(id<GTMLogFormatter>)formatter
|
||||
filter:(id<GTMLogFilter>)filter {
|
||||
return [[[self alloc] initWithWriter:writer
|
||||
formatter:formatter
|
||||
filter:filter] autorelease];
|
||||
}
|
||||
|
||||
+ (id)logger {
|
||||
return [[[self alloc] init] autorelease];
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
return [self initWithWriter:nil formatter:nil filter:nil];
|
||||
}
|
||||
|
||||
- (id)initWithWriter:(id<GTMLogWriter>)writer
|
||||
formatter:(id<GTMLogFormatter>)formatter
|
||||
filter:(id<GTMLogFilter>)filter {
|
||||
if ((self = [super init])) {
|
||||
[self setWriter:writer];
|
||||
[self setFormatter:formatter];
|
||||
[self setFilter:filter];
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
[writer_ release];
|
||||
[formatter_ release];
|
||||
[filter_ release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id<GTMLogWriter>)writer {
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
return [[writer_ retain] autorelease];
|
||||
}
|
||||
|
||||
- (void)setWriter:(id<GTMLogWriter>)writer {
|
||||
@synchronized(self) {
|
||||
[writer_ autorelease];
|
||||
if (writer == nil)
|
||||
writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
|
||||
else
|
||||
writer_ = [writer retain];
|
||||
}
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
}
|
||||
|
||||
- (id<GTMLogFormatter>)formatter {
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
return [[formatter_ retain] autorelease];
|
||||
}
|
||||
|
||||
- (void)setFormatter:(id<GTMLogFormatter>)formatter {
|
||||
@synchronized(self) {
|
||||
[formatter_ autorelease];
|
||||
if (formatter == nil)
|
||||
formatter_ = [[GTMLogBasicFormatter alloc] init];
|
||||
else
|
||||
formatter_ = [formatter retain];
|
||||
}
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
}
|
||||
|
||||
- (id<GTMLogFilter>)filter {
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
return [[filter_ retain] autorelease];
|
||||
}
|
||||
|
||||
- (void)setFilter:(id<GTMLogFilter>)filter {
|
||||
@synchronized(self) {
|
||||
[filter_ autorelease];
|
||||
if (filter == nil)
|
||||
filter_ = [[GTMLogNoFilter alloc] init];
|
||||
else
|
||||
filter_ = [filter retain];
|
||||
}
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
}
|
||||
|
||||
- (void)logDebug:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
- (void)logInfo:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
- (void)logError:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
- (void)logAssert:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@end // GTMLogger
|
||||
|
||||
|
||||
@implementation GTMLogger (GTMLoggerMacroHelpers)
|
||||
|
||||
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
[self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert];
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@end // GTMLoggerMacroHelpers
|
||||
|
||||
|
||||
@implementation GTMLogger (PrivateMethods)
|
||||
|
||||
- (void)logInternalFunc:(const char *)func
|
||||
format:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level {
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
|
||||
NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
|
||||
NSString *msg = [formatter_ stringForFunc:fname
|
||||
withFormat:fmt
|
||||
valist:args
|
||||
level:level];
|
||||
if (msg && [filter_ filterAllowsMessage:msg level:level])
|
||||
[writer_ logMessage:msg level:level];
|
||||
}
|
||||
|
||||
@end // PrivateMethods
|
||||
|
||||
|
||||
@implementation NSFileHandle (GTMFileHandleLogWriter)
|
||||
|
||||
+ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode {
|
||||
int fd = -1;
|
||||
if (path) {
|
||||
int flags = O_WRONLY | O_APPEND | O_CREAT;
|
||||
fd = open([path fileSystemRepresentation], flags, mode);
|
||||
}
|
||||
if (fd == -1) return nil;
|
||||
return [[[self alloc] initWithFileDescriptor:fd
|
||||
closeOnDealloc:YES] autorelease];
|
||||
}
|
||||
|
||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||
@synchronized(self) {
|
||||
NSString *line = [NSString stringWithFormat:@"%@\n", msg];
|
||||
[self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
}
|
||||
|
||||
@end // GTMFileHandleLogWriter
|
||||
|
||||
|
||||
@implementation NSArray (GTMArrayCompositeLogWriter)
|
||||
|
||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||
@synchronized(self) {
|
||||
id<GTMLogWriter> child = nil;
|
||||
GTM_FOREACH_OBJECT(child, self) {
|
||||
if ([child conformsToProtocol:@protocol(GTMLogWriter)])
|
||||
[child logMessage:msg level:level];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end // GTMArrayCompositeLogWriter
|
||||
|
||||
|
||||
@implementation GTMLogger (GTMLoggerLogWriter)
|
||||
|
||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||
switch (level) {
|
||||
case kGTMLoggerLevelDebug:
|
||||
[self logDebug:@"%@", msg];
|
||||
break;
|
||||
case kGTMLoggerLevelInfo:
|
||||
[self logInfo:@"%@", msg];
|
||||
break;
|
||||
case kGTMLoggerLevelError:
|
||||
[self logError:@"%@", msg];
|
||||
break;
|
||||
case kGTMLoggerLevelAssert:
|
||||
[self logAssert:@"%@", msg];
|
||||
break;
|
||||
default:
|
||||
// Ignore the message.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end // GTMLoggerLogWriter
|
||||
|
||||
|
||||
@implementation GTMLogBasicFormatter
|
||||
|
||||
- (NSString *)stringForFunc:(NSString *)func
|
||||
withFormat:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level {
|
||||
// Performance note: since we always have to create a new NSString from the
|
||||
// returned CFStringRef, we may want to do a quick check here to see if |fmt|
|
||||
// contains a '%', and if not, simply return 'fmt'.
|
||||
CFStringRef cfmsg = NULL;
|
||||
cfmsg = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault,
|
||||
NULL, // format options
|
||||
(CFStringRef)fmt,
|
||||
args);
|
||||
return GTMCFAutorelease(cfmsg);
|
||||
}
|
||||
|
||||
@end // GTMLogBasicFormatter
|
||||
|
||||
|
||||
@implementation GTMLogStandardFormatter
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
dateFormatter_ = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4];
|
||||
[dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
|
||||
pname_ = [[[NSProcessInfo processInfo] processName] copy];
|
||||
pid_ = [[NSProcessInfo processInfo] processIdentifier];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[dateFormatter_ release];
|
||||
[pname_ release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)stringForFunc:(NSString *)func
|
||||
withFormat:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level {
|
||||
GTMLOGGER_ASSERT(dateFormatter_ != nil);
|
||||
NSString *tstamp = nil;
|
||||
@synchronized (dateFormatter_) {
|
||||
tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
|
||||
tstamp, pname_, pid_, pthread_self(),
|
||||
level, (func ? func : @"(no func)"),
|
||||
[super stringForFunc:func withFormat:fmt valist:args level:level]];
|
||||
}
|
||||
|
||||
@end // GTMLogStandardFormatter
|
||||
|
||||
|
||||
@implementation GTMLogLevelFilter
|
||||
|
||||
// Check the environment and the user preferences for the GTMVerboseLogging key
|
||||
// to see if verbose logging has been enabled. The environment variable will
|
||||
// override the defaults setting, so check the environment first.
|
||||
// COV_NF_START
|
||||
static BOOL IsVerboseLoggingEnabled(void) {
|
||||
static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
|
||||
static char *env = NULL;
|
||||
if (env == NULL)
|
||||
env = getenv([kVerboseLoggingKey UTF8String]);
|
||||
|
||||
if (env && env[0]) {
|
||||
return (strtol(env, NULL, 10) != 0);
|
||||
}
|
||||
|
||||
return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey];
|
||||
}
|
||||
// COV_NF_END
|
||||
|
||||
// In DEBUG builds, log everything. If we're not in a debug build we'll assume
|
||||
// that we're in a Release build.
|
||||
- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||
#if DEBUG
|
||||
return YES;
|
||||
#endif
|
||||
|
||||
BOOL allow = YES;
|
||||
|
||||
switch (level) {
|
||||
case kGTMLoggerLevelDebug:
|
||||
allow = NO;
|
||||
break;
|
||||
case kGTMLoggerLevelInfo:
|
||||
allow = (IsVerboseLoggingEnabled() == YES);
|
||||
break;
|
||||
case kGTMLoggerLevelError:
|
||||
allow = YES;
|
||||
break;
|
||||
case kGTMLoggerLevelAssert:
|
||||
allow = YES;
|
||||
break;
|
||||
default:
|
||||
allow = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
return allow;
|
||||
}
|
||||
|
||||
@end // GTMLogLevelFilter
|
||||
|
||||
|
||||
@implementation GTMLogNoFilter
|
||||
|
||||
- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||
return YES; // Allow everything through
|
||||
}
|
||||
|
||||
@end // GTMLogNoFilter
|
61
thirdparty/breakpad/common/mac/HTTPMultipartUpload.h
vendored
Normal file
61
thirdparty/breakpad/common/mac/HTTPMultipartUpload.h
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// HTTPMultipartUpload: A multipart/form-data HTTP uploader.
|
||||
// Each parameter pair is sent as a boundary
|
||||
// Each file is sent with a name field in addition to the filename and data
|
||||
// The data will be sent synchronously.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface HTTPMultipartUpload : NSObject {
|
||||
@protected
|
||||
NSURL *url_; // The destination URL (STRONG)
|
||||
NSDictionary *parameters_; // The key/value pairs for sending data (STRONG)
|
||||
NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG)
|
||||
NSString *boundary_; // The boundary string (STRONG)
|
||||
NSHTTPURLResponse *response_; // The response from the send (STRONG)
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL *)url;
|
||||
|
||||
- (NSURL *)URL;
|
||||
|
||||
- (void)setParameters:(NSDictionary *)parameters;
|
||||
- (NSDictionary *)parameters;
|
||||
|
||||
- (void)addFileAtPath:(NSString *)path name:(NSString *)name;
|
||||
- (void)addFileContents:(NSData *)data name:(NSString *)name;
|
||||
- (NSDictionary *)files;
|
||||
|
||||
// Set the data and return the response
|
||||
- (NSData *)send:(NSError **)error;
|
||||
- (NSHTTPURLResponse *)response;
|
||||
|
||||
@end
|
205
thirdparty/breakpad/common/mac/HTTPMultipartUpload.m
vendored
Normal file
205
thirdparty/breakpad/common/mac/HTTPMultipartUpload.m
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import "HTTPMultipartUpload.h"
|
||||
#import "GTMDefines.h"
|
||||
|
||||
@interface HTTPMultipartUpload(PrivateMethods)
|
||||
- (NSString *)multipartBoundary;
|
||||
- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value;
|
||||
- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name;
|
||||
- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name;
|
||||
@end
|
||||
|
||||
@implementation HTTPMultipartUpload
|
||||
//=============================================================================
|
||||
#pragma mark -
|
||||
#pragma mark || Private ||
|
||||
//=============================================================================
|
||||
- (NSString *)multipartBoundary {
|
||||
// The boundary has 27 '-' characters followed by 16 hex digits
|
||||
return [NSString stringWithFormat:@"---------------------------%08X%08X",
|
||||
rand(), rand()];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
|
||||
NSString *escaped =
|
||||
[key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *fmt =
|
||||
@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
|
||||
NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
|
||||
|
||||
return [form dataUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name {
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSString *escaped =
|
||||
[name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
|
||||
"filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
|
||||
NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped];
|
||||
NSString *post = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
|
||||
|
||||
[data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[data appendData:contents];
|
||||
[data appendData:[post dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name {
|
||||
NSData *contents = [NSData dataWithContentsOfFile:file];
|
||||
|
||||
return [self formDataForFileContents:contents name:name];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
#pragma mark -
|
||||
#pragma mark || Public ||
|
||||
//=============================================================================
|
||||
- (id)initWithURL:(NSURL *)url {
|
||||
if ((self = [super init])) {
|
||||
url_ = [url copy];
|
||||
boundary_ = [[self multipartBoundary] retain];
|
||||
files_ = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (void)dealloc {
|
||||
[url_ release];
|
||||
[parameters_ release];
|
||||
[files_ release];
|
||||
[boundary_ release];
|
||||
[response_ release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSURL *)URL {
|
||||
return url_;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (void)setParameters:(NSDictionary *)parameters {
|
||||
if (parameters != parameters_) {
|
||||
[parameters_ release];
|
||||
parameters_ = [parameters copy];
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSDictionary *)parameters {
|
||||
return parameters_;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (void)addFileAtPath:(NSString *)path name:(NSString *)name {
|
||||
[files_ setObject:path forKey:name];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (void)addFileContents:(NSData *)data name:(NSString *)name {
|
||||
[files_ setObject:data forKey:name];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSDictionary *)files {
|
||||
return files_;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSData *)send:(NSError **)error {
|
||||
NSMutableURLRequest *req =
|
||||
[[NSMutableURLRequest alloc]
|
||||
initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval:10.0 ];
|
||||
|
||||
NSMutableData *postBody = [NSMutableData data];
|
||||
|
||||
[req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",
|
||||
boundary_] forHTTPHeaderField:@"Content-type"];
|
||||
|
||||
// Add any parameters to the message
|
||||
NSArray *parameterKeys = [parameters_ allKeys];
|
||||
NSString *key;
|
||||
|
||||
NSInteger count = [parameterKeys count];
|
||||
for (NSInteger i = 0; i < count; ++i) {
|
||||
key = [parameterKeys objectAtIndex:i];
|
||||
[postBody appendData:[self formDataForKey:key
|
||||
value:[parameters_ objectForKey:key]]];
|
||||
}
|
||||
|
||||
// Add any files to the message
|
||||
NSArray *fileNames = [files_ allKeys];
|
||||
count = [fileNames count];
|
||||
for (NSInteger i = 0; i < count; ++i) {
|
||||
NSString *name = [fileNames objectAtIndex:i];
|
||||
id fileOrData = [files_ objectForKey:name];
|
||||
NSData *fileData;
|
||||
|
||||
// The object can be either the path to a file (NSString) or the contents
|
||||
// of the file (NSData).
|
||||
if ([fileOrData isKindOfClass:[NSData class]])
|
||||
fileData = [self formDataForFileContents:fileOrData name:name];
|
||||
else
|
||||
fileData = [self formDataForFile:fileOrData name:name];
|
||||
|
||||
[postBody appendData:fileData];
|
||||
}
|
||||
|
||||
[req setHTTPBody:postBody];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
|
||||
[response_ release];
|
||||
response_ = nil;
|
||||
|
||||
NSData *data = [NSURLConnection sendSynchronousRequest:req
|
||||
returningResponse:&response_
|
||||
error:error];
|
||||
|
||||
[response_ retain];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
- (NSHTTPURLResponse *)response {
|
||||
return response_;
|
||||
}
|
||||
|
||||
@end
|
301
thirdparty/breakpad/common/mac/MachIPC.h
vendored
Normal file
301
thirdparty/breakpad/common/mac/MachIPC.h
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// MachIPC.h
|
||||
//
|
||||
// Some helpful wrappers for using Mach IPC calls
|
||||
|
||||
#ifndef MACH_IPC_H__
|
||||
#define MACH_IPC_H__
|
||||
|
||||
#import <mach/mach.h>
|
||||
#import <mach/message.h>
|
||||
#import <servers/bootstrap.h>
|
||||
#import <sys/types.h>
|
||||
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
||||
//==============================================================================
|
||||
// DISCUSSION:
|
||||
//
|
||||
// The three main classes of interest are
|
||||
//
|
||||
// MachMessage: a wrapper for a mach message of the following form
|
||||
// mach_msg_header_t
|
||||
// mach_msg_body_t
|
||||
// optional descriptors
|
||||
// optional extra message data
|
||||
//
|
||||
// MachReceiveMessage and MachSendMessage subclass MachMessage
|
||||
// and are used instead of MachMessage which is an abstract base class
|
||||
//
|
||||
// ReceivePort:
|
||||
// Represents a mach port for which we have receive rights
|
||||
//
|
||||
// MachPortSender:
|
||||
// Represents a mach port for which we have send rights
|
||||
//
|
||||
// Here's an example to receive a message on a server port:
|
||||
//
|
||||
// // This creates our named server port
|
||||
// ReceivePort receivePort("com.Google.MyService");
|
||||
//
|
||||
// MachReceiveMessage message;
|
||||
// kern_return_t result = receivePort.WaitForMessage(&message, 0);
|
||||
//
|
||||
// if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
|
||||
// mach_port_t task = message.GetTranslatedPort(0);
|
||||
// mach_port_t thread = message.GetTranslatedPort(1);
|
||||
//
|
||||
// char *messageString = message.GetData();
|
||||
//
|
||||
// printf("message string = %s\n", messageString);
|
||||
// }
|
||||
//
|
||||
// Here is an example of using these classes to send a message to this port:
|
||||
//
|
||||
// // send to already named port
|
||||
// MachPortSender sender("com.Google.MyService");
|
||||
// MachSendMessage message(57); // our message ID is 57
|
||||
//
|
||||
// // add some ports to be translated for us
|
||||
// message.AddDescriptor(mach_task_self()); // our task
|
||||
// message.AddDescriptor(mach_thread_self()); // this thread
|
||||
//
|
||||
// char messageString[] = "Hello server!\n";
|
||||
// message.SetData(messageString, strlen(messageString)+1);
|
||||
//
|
||||
// kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms
|
||||
//
|
||||
|
||||
namespace google_breakpad {
|
||||
#define PRINT_MACH_RESULT(result_, message_) \
|
||||
printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
|
||||
|
||||
//==============================================================================
|
||||
// A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
|
||||
// with convenient constructors and accessors
|
||||
class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
|
||||
public:
|
||||
// General-purpose constructor
|
||||
MachMsgPortDescriptor(mach_port_t in_name,
|
||||
mach_msg_type_name_t in_disposition) {
|
||||
name = in_name;
|
||||
pad1 = 0;
|
||||
pad2 = 0;
|
||||
disposition = in_disposition;
|
||||
type = MACH_MSG_PORT_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// For passing send rights to a port
|
||||
MachMsgPortDescriptor(mach_port_t in_name) {
|
||||
name = in_name;
|
||||
pad1 = 0;
|
||||
pad2 = 0;
|
||||
disposition = MACH_MSG_TYPE_COPY_SEND;
|
||||
type = MACH_MSG_PORT_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
|
||||
name = desc.name;
|
||||
pad1 = desc.pad1;
|
||||
pad2 = desc.pad2;
|
||||
disposition = desc.disposition;
|
||||
type = desc.type;
|
||||
}
|
||||
|
||||
mach_port_t GetMachPort() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
mach_msg_type_name_t GetDisposition() const {
|
||||
return disposition;
|
||||
}
|
||||
|
||||
// For convenience
|
||||
operator mach_port_t() const {
|
||||
return GetMachPort();
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// MachMessage: a wrapper for a mach message
|
||||
// (mach_msg_header_t, mach_msg_body_t, extra data)
|
||||
//
|
||||
// This considerably simplifies the construction of a message for sending
|
||||
// and the getting at relevant data and descriptors for the receiver.
|
||||
//
|
||||
// Currently the combined size of the descriptors plus data must be
|
||||
// less than 1024. But as a benefit no memory allocation is necessary.
|
||||
//
|
||||
// TODO: could consider adding malloc() support for very large messages
|
||||
//
|
||||
// A MachMessage object is used by ReceivePort::WaitForMessage
|
||||
// and MachPortSender::SendMessage
|
||||
//
|
||||
class MachMessage {
|
||||
public:
|
||||
|
||||
// The receiver of the message can retrieve the raw data this way
|
||||
u_int8_t *GetData() {
|
||||
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
|
||||
}
|
||||
|
||||
u_int32_t GetDataLength() {
|
||||
return EndianU32_LtoN(GetDataPacket()->data_length);
|
||||
}
|
||||
|
||||
// The message ID may be used as a code identifying the type of message
|
||||
void SetMessageID(int32_t message_id) {
|
||||
GetDataPacket()->id = EndianU32_NtoL(message_id);
|
||||
}
|
||||
|
||||
int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
|
||||
|
||||
// Adds a descriptor (typically a mach port) to be translated
|
||||
// returns true if successful, otherwise not enough space
|
||||
bool AddDescriptor(const MachMsgPortDescriptor &desc);
|
||||
|
||||
int GetDescriptorCount() const { return body.msgh_descriptor_count; }
|
||||
MachMsgPortDescriptor *GetDescriptor(int n);
|
||||
|
||||
// Convenience method which gets the mach port described by the descriptor
|
||||
mach_port_t GetTranslatedPort(int n);
|
||||
|
||||
// A simple message is one with no descriptors
|
||||
bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
|
||||
|
||||
// Sets raw data for the message (returns false if not enough space)
|
||||
bool SetData(void *data, int32_t data_length);
|
||||
|
||||
protected:
|
||||
// Consider this an abstract base class - must create an actual instance
|
||||
// of MachReceiveMessage or MachSendMessage
|
||||
|
||||
MachMessage() {
|
||||
memset(this, 0, sizeof(MachMessage));
|
||||
}
|
||||
|
||||
friend class ReceivePort;
|
||||
friend class MachPortSender;
|
||||
|
||||
// Represents raw data in our message
|
||||
struct MessageDataPacket {
|
||||
int32_t id; // little-endian
|
||||
int32_t data_length; // little-endian
|
||||
u_int8_t data[1]; // actual size limited by sizeof(MachMessage)
|
||||
};
|
||||
|
||||
MessageDataPacket* GetDataPacket();
|
||||
|
||||
void SetDescriptorCount(int n);
|
||||
void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
|
||||
|
||||
// Returns total message size setting msgh_size in the header to this value
|
||||
mach_msg_size_t CalculateSize();
|
||||
|
||||
mach_msg_header_t head;
|
||||
mach_msg_body_t body;
|
||||
u_int8_t padding[1024]; // descriptors and data may be embedded here
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// MachReceiveMessage and MachSendMessage are useful to separate the idea
|
||||
// of a mach message being sent and being received, and adds increased type
|
||||
// safety:
|
||||
// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
|
||||
// MachPortSender::SendMessage() only accepts a MachSendMessage
|
||||
|
||||
//==============================================================================
|
||||
class MachReceiveMessage : public MachMessage {
|
||||
public:
|
||||
MachReceiveMessage() : MachMessage() {};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class MachSendMessage : public MachMessage {
|
||||
public:
|
||||
MachSendMessage(int32_t message_id);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Represents a mach port for which we have receive rights
|
||||
class ReceivePort {
|
||||
public:
|
||||
// Creates a new mach port for receiving messages and registers a name for it
|
||||
explicit ReceivePort(const char *receive_port_name);
|
||||
|
||||
// Given an already existing mach port, use it. We take ownership of the
|
||||
// port and deallocate it in our destructor.
|
||||
explicit ReceivePort(mach_port_t receive_port);
|
||||
|
||||
// Create a new mach port for receiving messages
|
||||
ReceivePort();
|
||||
|
||||
~ReceivePort();
|
||||
|
||||
// Waits on the mach port until message received or timeout
|
||||
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
|
||||
mach_msg_timeout_t timeout);
|
||||
|
||||
// The underlying mach port that we wrap
|
||||
mach_port_t GetPort() const { return port_; }
|
||||
|
||||
private:
|
||||
ReceivePort(const ReceivePort&); // disable copy c-tor
|
||||
|
||||
mach_port_t port_;
|
||||
kern_return_t init_result_;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Represents a mach port for which we have send rights
|
||||
class MachPortSender {
|
||||
public:
|
||||
// get a port with send rights corresponding to a named registered service
|
||||
explicit MachPortSender(const char *receive_port_name);
|
||||
|
||||
|
||||
// Given an already existing mach port, use it.
|
||||
explicit MachPortSender(mach_port_t send_port);
|
||||
|
||||
kern_return_t SendMessage(MachSendMessage &message,
|
||||
mach_msg_timeout_t timeout);
|
||||
|
||||
private:
|
||||
MachPortSender(const MachPortSender&); // disable copy c-tor
|
||||
|
||||
mach_port_t send_port_;
|
||||
kern_return_t init_result_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // MACH_IPC_H__
|
304
thirdparty/breakpad/common/mac/MachIPC.mm
vendored
Normal file
304
thirdparty/breakpad/common/mac/MachIPC.mm
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// MachIPC.mm
|
||||
// Wrapper for mach IPC calls
|
||||
|
||||
#import <stdio.h>
|
||||
#import "MachIPC.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
//==============================================================================
|
||||
MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
|
||||
head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
|
||||
|
||||
// head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
|
||||
head.msgh_local_port = MACH_PORT_NULL;
|
||||
head.msgh_reserved = 0;
|
||||
head.msgh_id = 0;
|
||||
|
||||
SetDescriptorCount(0); // start out with no descriptors
|
||||
|
||||
SetMessageID(message_id);
|
||||
SetData(NULL, 0); // client may add data later
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// returns true if successful
|
||||
bool MachMessage::SetData(void *data,
|
||||
int32_t data_length) {
|
||||
// first check to make sure we have enough space
|
||||
size_t size = CalculateSize();
|
||||
size_t new_size = size + data_length;
|
||||
|
||||
if (new_size > sizeof(MachMessage)) {
|
||||
return false; // not enough space
|
||||
}
|
||||
|
||||
GetDataPacket()->data_length = EndianU32_NtoL(data_length);
|
||||
if (data) memcpy(GetDataPacket()->data, data, data_length);
|
||||
|
||||
CalculateSize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// calculates and returns the total size of the message
|
||||
// Currently, the entire message MUST fit inside of the MachMessage
|
||||
// messsage size <= sizeof(MachMessage)
|
||||
mach_msg_size_t MachMessage::CalculateSize() {
|
||||
size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
|
||||
|
||||
// add space for MessageDataPacket
|
||||
int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
|
||||
size += 2*sizeof(int32_t) + alignedDataLength;
|
||||
|
||||
// add space for descriptors
|
||||
size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
|
||||
|
||||
head.msgh_size = static_cast<mach_msg_size_t>(size);
|
||||
|
||||
return head.msgh_size;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
|
||||
size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
|
||||
MessageDataPacket *packet =
|
||||
reinterpret_cast<MessageDataPacket*>(padding + desc_size);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MachMessage::SetDescriptor(int n,
|
||||
const MachMsgPortDescriptor &desc) {
|
||||
MachMsgPortDescriptor *desc_array =
|
||||
reinterpret_cast<MachMsgPortDescriptor*>(padding);
|
||||
desc_array[n] = desc;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// returns true if successful otherwise there was not enough space
|
||||
bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
|
||||
// first check to make sure we have enough space
|
||||
int size = CalculateSize();
|
||||
size_t new_size = size + sizeof(MachMsgPortDescriptor);
|
||||
|
||||
if (new_size > sizeof(MachMessage)) {
|
||||
return false; // not enough space
|
||||
}
|
||||
|
||||
// unfortunately, we need to move the data to allow space for the
|
||||
// new descriptor
|
||||
u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
|
||||
bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
|
||||
|
||||
SetDescriptor(GetDescriptorCount(), desc);
|
||||
SetDescriptorCount(GetDescriptorCount() + 1);
|
||||
|
||||
CalculateSize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MachMessage::SetDescriptorCount(int n) {
|
||||
body.msgh_descriptor_count = n;
|
||||
|
||||
if (n > 0) {
|
||||
head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
|
||||
} else {
|
||||
head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
|
||||
if (n < GetDescriptorCount()) {
|
||||
MachMsgPortDescriptor *desc =
|
||||
reinterpret_cast<MachMsgPortDescriptor*>(padding);
|
||||
return desc + n;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
mach_port_t MachMessage::GetTranslatedPort(int n) {
|
||||
if (n < GetDescriptorCount()) {
|
||||
return GetDescriptor(n)->GetMachPort();
|
||||
}
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
//==============================================================================
|
||||
// create a new mach port for receiving messages and register a name for it
|
||||
ReceivePort::ReceivePort(const char *receive_port_name) {
|
||||
mach_port_t current_task = mach_task_self();
|
||||
|
||||
init_result_ = mach_port_allocate(current_task,
|
||||
MACH_PORT_RIGHT_RECEIVE,
|
||||
&port_);
|
||||
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return;
|
||||
|
||||
init_result_ = mach_port_insert_right(current_task,
|
||||
port_,
|
||||
port_,
|
||||
MACH_MSG_TYPE_MAKE_SEND);
|
||||
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return;
|
||||
|
||||
mach_port_t task_bootstrap_port = 0;
|
||||
init_result_ = task_get_bootstrap_port(current_task, &task_bootstrap_port);
|
||||
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return;
|
||||
|
||||
init_result_ = bootstrap_register(bootstrap_port,
|
||||
const_cast<char*>(receive_port_name),
|
||||
port_);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// create a new mach port for receiving messages
|
||||
ReceivePort::ReceivePort() {
|
||||
mach_port_t current_task = mach_task_self();
|
||||
|
||||
init_result_ = mach_port_allocate(current_task,
|
||||
MACH_PORT_RIGHT_RECEIVE,
|
||||
&port_);
|
||||
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return;
|
||||
|
||||
init_result_ = mach_port_insert_right(current_task,
|
||||
port_,
|
||||
port_,
|
||||
MACH_MSG_TYPE_MAKE_SEND);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Given an already existing mach port, use it. We take ownership of the
|
||||
// port and deallocate it in our destructor.
|
||||
ReceivePort::ReceivePort(mach_port_t receive_port)
|
||||
: port_(receive_port),
|
||||
init_result_(KERN_SUCCESS) {
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ReceivePort::~ReceivePort() {
|
||||
if (init_result_ == KERN_SUCCESS)
|
||||
mach_port_deallocate(mach_task_self(), port_);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
|
||||
mach_msg_timeout_t timeout) {
|
||||
if (!out_message) {
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
// return any error condition encountered in constructor
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return init_result_;
|
||||
|
||||
out_message->head.msgh_bits = 0;
|
||||
out_message->head.msgh_local_port = port_;
|
||||
out_message->head.msgh_remote_port = MACH_PORT_NULL;
|
||||
out_message->head.msgh_reserved = 0;
|
||||
out_message->head.msgh_id = 0;
|
||||
|
||||
mach_msg_option_t options = MACH_RCV_MSG;
|
||||
if (timeout != MACH_MSG_TIMEOUT_NONE)
|
||||
options |= MACH_RCV_TIMEOUT;
|
||||
kern_return_t result = mach_msg(&out_message->head,
|
||||
options,
|
||||
0,
|
||||
sizeof(MachMessage),
|
||||
port_,
|
||||
timeout, // timeout in ms
|
||||
MACH_PORT_NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
//==============================================================================
|
||||
// get a port with send rights corresponding to a named registered service
|
||||
MachPortSender::MachPortSender(const char *receive_port_name) {
|
||||
mach_port_t task_bootstrap_port = 0;
|
||||
init_result_ = task_get_bootstrap_port(mach_task_self(),
|
||||
&task_bootstrap_port);
|
||||
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return;
|
||||
|
||||
init_result_ = bootstrap_look_up(task_bootstrap_port,
|
||||
const_cast<char*>(receive_port_name),
|
||||
&send_port_);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
MachPortSender::MachPortSender(mach_port_t send_port)
|
||||
: send_port_(send_port),
|
||||
init_result_(KERN_SUCCESS) {
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
|
||||
mach_msg_timeout_t timeout) {
|
||||
if (message.head.msgh_size == 0) {
|
||||
return KERN_INVALID_VALUE; // just for safety -- never should occur
|
||||
};
|
||||
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return init_result_;
|
||||
|
||||
message.head.msgh_remote_port = send_port_;
|
||||
|
||||
kern_return_t result = mach_msg(&message.head,
|
||||
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
|
||||
message.head.msgh_size,
|
||||
0,
|
||||
MACH_PORT_NULL,
|
||||
timeout, // timeout in ms
|
||||
MACH_PORT_NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
195
thirdparty/breakpad/common/mac/SimpleStringDictionary.h
vendored
Normal file
195
thirdparty/breakpad/common/mac/SimpleStringDictionary.h
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// SimpleStringDictionary.h
|
||||
//
|
||||
|
||||
#ifndef SimpleStringDictionary_H__
|
||||
#define SimpleStringDictionary_H__
|
||||
|
||||
#import <string>
|
||||
#import <vector>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
//==============================================================================
|
||||
// SimpleStringDictionary (and associated class KeyValueEntry) implement a very
|
||||
// basic dictionary container class. It has the property of not making any
|
||||
// memory allocations when getting and setting values. But it is not very
|
||||
// efficient, with calls to get and set values operating in linear time.
|
||||
// It has the additional limitation of having a fairly small fixed capacity of
|
||||
// SimpleStringDictionary::MAX_NUM_ENTRIES entries. An assert() will fire if
|
||||
// the client attempts to set more than this number of key/value pairs.
|
||||
// Ordinarilly a C++ programmer would use something like the std::map template
|
||||
// class, or on the Macintosh would often choose CFDictionary or NSDictionary.
|
||||
// But these dictionary classes may call malloc() during get and set operations.
|
||||
// Google Breakpad requires that no memory allocations be made in code running
|
||||
// in its exception handling thread, so it uses SimpleStringDictionary as the
|
||||
// underlying implementation for the GoogleBreakpad.framework APIs:
|
||||
// GoogleBreakpadSetKeyValue(), GoogleBreakpadKeyValue(), and
|
||||
// GoogleBreakpadRemoveKeyValue()
|
||||
//
|
||||
|
||||
//==============================================================================
|
||||
// KeyValueEntry
|
||||
//
|
||||
// A helper class used by SimpleStringDictionary representing a single
|
||||
// storage cell for a key/value pair. Each key and value string are
|
||||
// limited to MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). This class
|
||||
// performs no memory allocations. It has methods for setting and getting
|
||||
// key and value strings.
|
||||
//
|
||||
class KeyValueEntry {
|
||||
public:
|
||||
KeyValueEntry() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
KeyValueEntry(const char *key, const char *value) {
|
||||
SetKeyValue(key, value);
|
||||
}
|
||||
|
||||
void SetKeyValue(const char *key, const char *value) {
|
||||
if (!key) {
|
||||
key = "";
|
||||
}
|
||||
if (!value) {
|
||||
value = "";
|
||||
}
|
||||
|
||||
strlcpy(key_, key, sizeof(key_));
|
||||
strlcpy(value_, value, sizeof(value_));
|
||||
}
|
||||
|
||||
void SetValue(const char *value) {
|
||||
if (!value) {
|
||||
value = "";
|
||||
}
|
||||
strlcpy(value_, value, sizeof(value_));
|
||||
};
|
||||
|
||||
// Removes the key/value
|
||||
void Clear() {
|
||||
memset(key_, 0, sizeof(key_));
|
||||
memset(value_, 0, sizeof(value_));
|
||||
}
|
||||
|
||||
bool IsActive() const { return key_[0] != '\0'; }
|
||||
const char *GetKey() const { return key_; }
|
||||
const char *GetValue() const { return value_; }
|
||||
|
||||
// Don't change this without considering the fixed size
|
||||
// of MachMessage (in MachIPC.h)
|
||||
// (see also struct KeyValueMessageData in Inspector.h)
|
||||
enum {MAX_STRING_STORAGE_SIZE = 256};
|
||||
|
||||
private:
|
||||
char key_[MAX_STRING_STORAGE_SIZE];
|
||||
char value_[MAX_STRING_STORAGE_SIZE];
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// This class is not an efficient dictionary, but for the purposes of breakpad
|
||||
// will be just fine. We're just dealing with ten or so distinct
|
||||
// key/value pairs. The idea is to avoid any malloc() or free() calls
|
||||
// in certain important methods to be called when a process is in a
|
||||
// crashed state. Each key and value string are limited to
|
||||
// KeyValueEntry::MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). Strings passed
|
||||
// in exceeding this length will be truncated.
|
||||
//
|
||||
class SimpleStringDictionary {
|
||||
public:
|
||||
SimpleStringDictionary() {}; // entries will all be cleared
|
||||
|
||||
// Returns the number of active key/value pairs. The upper limit for this
|
||||
// is MAX_NUM_ENTRIES.
|
||||
int GetCount() const;
|
||||
|
||||
// Given |key|, returns its corresponding |value|.
|
||||
// If |key| is NULL, an assert will fire or NULL will be returned. If |key|
|
||||
// is not found or is an empty string, NULL is returned.
|
||||
const char *GetValueForKey(const char *key);
|
||||
|
||||
// Stores a string |value| represented by |key|. If |key| is NULL or an empty
|
||||
// string, this will assert (or do nothing). If |value| is NULL then
|
||||
// the |key| will be removed. An empty string is OK for |value|.
|
||||
void SetKeyValue(const char *key, const char *value);
|
||||
|
||||
// Given |key|, removes any associated value. It will assert (or do nothing)
|
||||
// if NULL is passed in. It will do nothing if |key| is not found.
|
||||
void RemoveKey(const char *key);
|
||||
|
||||
// This is the maximum number of key/value pairs which may be set in the
|
||||
// dictionary. An assert may fire if more values than this are set.
|
||||
// Don't change this without also changing comment in GoogleBreakpad.h
|
||||
enum {MAX_NUM_ENTRIES = 64};
|
||||
|
||||
private:
|
||||
friend class SimpleStringDictionaryIterator;
|
||||
|
||||
const KeyValueEntry *GetEntry(int i) const;
|
||||
|
||||
KeyValueEntry entries_[MAX_NUM_ENTRIES];
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class SimpleStringDictionaryIterator {
|
||||
public:
|
||||
SimpleStringDictionaryIterator(const SimpleStringDictionary &dict)
|
||||
: dict_(dict), i_(0) {
|
||||
}
|
||||
|
||||
// Initializes iterator to the beginning (may later call Next() )
|
||||
void Start() {
|
||||
i_ = 0;
|
||||
}
|
||||
|
||||
// like the nextObject method of NSEnumerator (in Cocoa)
|
||||
// returns NULL when there are no more entries
|
||||
//
|
||||
const KeyValueEntry* Next() {
|
||||
for (; i_ < SimpleStringDictionary::MAX_NUM_ENTRIES; ++i_) {
|
||||
const KeyValueEntry *entry = dict_.GetEntry(i_);
|
||||
if (entry->IsActive()) {
|
||||
i_++; // move to next entry for next time
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // reached end of array
|
||||
}
|
||||
|
||||
private:
|
||||
const SimpleStringDictionary& dict_;
|
||||
int i_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // SimpleStringDictionary_H__
|
133
thirdparty/breakpad/common/mac/SimpleStringDictionary.mm
vendored
Normal file
133
thirdparty/breakpad/common/mac/SimpleStringDictionary.mm
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// SimpleStringDictionary.mm
|
||||
// Simple string dictionary that does not allocate memory
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#import "SimpleStringDictionary.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
//==============================================================================
|
||||
const KeyValueEntry *SimpleStringDictionary::GetEntry(int i) const {
|
||||
return (i >= 0 && i < MAX_NUM_ENTRIES) ? &entries_[i] : NULL;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int SimpleStringDictionary::GetCount() const {
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
if (entries_[i].IsActive() ) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char *SimpleStringDictionary::GetValueForKey(const char *key) {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
KeyValueEntry &entry = entries_[i];
|
||||
if (entry.IsActive() && !strcmp(entry.GetKey(), key)) {
|
||||
return entry.GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void SimpleStringDictionary::SetKeyValue(const char *key,
|
||||
const char *value) {
|
||||
if (!value) {
|
||||
RemoveKey(key);
|
||||
return;
|
||||
}
|
||||
|
||||
// key must not be NULL
|
||||
assert(key);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
// key must not be empty string
|
||||
assert(key[0] != '\0');
|
||||
if (key[0] == '\0')
|
||||
return;
|
||||
|
||||
int free_index = -1;
|
||||
|
||||
// check if key already exists
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
KeyValueEntry &entry = entries_[i];
|
||||
|
||||
if (entry.IsActive()) {
|
||||
if (!strcmp(entry.GetKey(), key)) {
|
||||
entry.SetValue(value);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Make a note of an empty slot
|
||||
if (free_index == -1) {
|
||||
free_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we've run out of space
|
||||
assert(free_index != -1);
|
||||
|
||||
// Put new key into an empty slot (if found)
|
||||
if (free_index != -1) {
|
||||
entries_[free_index].SetKeyValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void SimpleStringDictionary::RemoveKey(const char *key) {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
if (!strcmp(entries_[i].GetKey(), key)) {
|
||||
entries_[i].Clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
48
thirdparty/breakpad/common/mac/byteswap.h
vendored
Normal file
48
thirdparty/breakpad/common/mac/byteswap.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jim@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// byteswap.h: Overloaded functions for conveniently byteswapping values.
|
||||
|
||||
#ifndef COMMON_MAC_BYTESWAP_H_
|
||||
#define COMMON_MAC_BYTESWAP_H_
|
||||
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
static inline uint16_t ByteSwap(uint16_t v) { return OSSwapInt16(v); }
|
||||
static inline uint32_t ByteSwap(uint32_t v) { return OSSwapInt32(v); }
|
||||
static inline uint64_t ByteSwap(uint64_t v) { return OSSwapInt64(v); }
|
||||
static inline int16_t ByteSwap(int16_t v) { return OSSwapInt16(v); }
|
||||
static inline int32_t ByteSwap(int32_t v) { return OSSwapInt32(v); }
|
||||
static inline int64_t ByteSwap(int64_t v) { return OSSwapInt64(v); }
|
||||
|
||||
#endif // COMMON_MAC_BYTESWAP_H_
|
172
thirdparty/breakpad/common/mac/dump_syms.h
vendored
Normal file
172
thirdparty/breakpad/common/mac/dump_syms.h
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dump_syms.h: Declaration of google_breakpad::DumpSymbols, a class for
|
||||
// reading debugging information from Mach-O files and writing it out as a
|
||||
// Breakpad symbol file.
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/byte_cursor.h"
|
||||
#include "common/mac/macho_reader.h"
|
||||
#include "common/module.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class DumpSymbols {
|
||||
public:
|
||||
DumpSymbols()
|
||||
: input_pathname_(),
|
||||
object_filename_(),
|
||||
contents_(),
|
||||
selected_object_file_(),
|
||||
selected_object_name_() { }
|
||||
~DumpSymbols() {
|
||||
[input_pathname_ release];
|
||||
[object_filename_ release];
|
||||
[contents_ release];
|
||||
}
|
||||
|
||||
// Prepare to read debugging information from |filename|. |filename| may be
|
||||
// the name of a universal binary, a Mach-O file, or a dSYM bundle
|
||||
// containing either of the above. On success, return true; if there is a
|
||||
// problem reading |filename|, report it and return false.
|
||||
//
|
||||
// (This class uses NSString for filenames and related values,
|
||||
// because the Mac Foundation framework seems to support
|
||||
// filename-related operations more fully on NSString values.)
|
||||
bool Read(NSString *filename);
|
||||
|
||||
// If this dumper's file includes an object file for |cpu_type| and
|
||||
// |cpu_subtype|, then select that object file for dumping, and return
|
||||
// true. Otherwise, return false, and leave this dumper's selected
|
||||
// architecture unchanged.
|
||||
//
|
||||
// By default, if this dumper's file contains only one object file, then
|
||||
// the dumper will dump those symbols; and if it contains more than one
|
||||
// object file, then the dumper will dump the object file whose
|
||||
// architecture matches that of this dumper program.
|
||||
bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
|
||||
|
||||
// If this dumper's file includes an object file for |arch_name|, then select
|
||||
// that object file for dumping, and return true. Otherwise, return false,
|
||||
// and leave this dumper's selected architecture unchanged.
|
||||
//
|
||||
// By default, if this dumper's file contains only one object file, then
|
||||
// the dumper will dump those symbols; and if it contains more than one
|
||||
// object file, then the dumper will dump the object file whose
|
||||
// architecture matches that of this dumper program.
|
||||
bool SetArchitecture(const std::string &arch_name);
|
||||
|
||||
// Return a pointer to an array of 'struct fat_arch' structures,
|
||||
// describing the object files contained in this dumper's file. Set
|
||||
// *|count| to the number of elements in the array. The returned array is
|
||||
// owned by this DumpSymbols instance.
|
||||
//
|
||||
// If there are no available architectures, this function
|
||||
// may return NULL.
|
||||
const struct fat_arch *AvailableArchitectures(size_t *count) {
|
||||
*count = object_files_.size();
|
||||
if (object_files_.size() > 0)
|
||||
return &object_files_[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read the selected object file's debugging information, and write it
|
||||
// out to |stream|. Return true on success; if an error occurs, report it
|
||||
// and return false.
|
||||
bool WriteSymbolFile(std::ostream &stream);
|
||||
|
||||
private:
|
||||
// Used internally.
|
||||
class DumperLineToModule;
|
||||
class LoadCommandDumper;
|
||||
|
||||
// Return an identifier string for the file this DumpSymbols is dumping.
|
||||
std::string Identifier();
|
||||
|
||||
// Read debugging information from |dwarf_sections|, which was taken from
|
||||
// |macho_reader|, and add it to |module|. On success, return true;
|
||||
// on failure, report the problem and return false.
|
||||
bool ReadDwarf(google_breakpad::Module *module,
|
||||
const mach_o::Reader &macho_reader,
|
||||
const mach_o::SectionMap &dwarf_sections) const;
|
||||
|
||||
// Read DWARF CFI or .eh_frame data from |section|, belonging to
|
||||
// |macho_reader|, and record it in |module|. If |eh_frame| is true,
|
||||
// then the data is .eh_frame-format data; otherwise, it is standard DWARF
|
||||
// .debug_frame data. On success, return true; on failure, report
|
||||
// the problem and return false.
|
||||
bool ReadCFI(google_breakpad::Module *module,
|
||||
const mach_o::Reader &macho_reader,
|
||||
const mach_o::Section §ion,
|
||||
bool eh_frame) const;
|
||||
|
||||
// The name of the file or bundle whose symbols this will dump.
|
||||
// This is the path given to Read, for use in error messages.
|
||||
NSString *input_pathname_;
|
||||
|
||||
// The name of the file this DumpSymbols will actually read debugging
|
||||
// information from. Normally, this is the same as input_pathname_, but if
|
||||
// filename refers to a dSYM bundle, then this is the resource file
|
||||
// within that bundle.
|
||||
NSString *object_filename_;
|
||||
|
||||
// The complete contents of object_filename_, mapped into memory.
|
||||
NSData *contents_;
|
||||
|
||||
// A vector of fat_arch structures describing the object files
|
||||
// object_filename_ contains. If object_filename_ refers to a fat binary,
|
||||
// this may have more than one element; if it refers to a Mach-O file, this
|
||||
// has exactly one element.
|
||||
vector<struct fat_arch> object_files_;
|
||||
|
||||
// The object file in object_files_ selected to dump, or NULL if
|
||||
// SetArchitecture hasn't been called yet.
|
||||
const struct fat_arch *selected_object_file_;
|
||||
|
||||
// A string that identifies the selected object file, for use in error
|
||||
// messages. This is usually object_filename_, but if that refers to a
|
||||
// fat binary, it includes an indication of the particular architecture
|
||||
// within that binary.
|
||||
string selected_object_name_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
496
thirdparty/breakpad/common/mac/dump_syms.mm
vendored
Normal file
496
thirdparty/breakpad/common/mac/dump_syms.mm
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dump_syms.mm: Create a symbol file for use with minidumps
|
||||
|
||||
#include "common/mac/dump_syms.h"
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <mach-o/arch.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
#include "common/mac/file_id.h"
|
||||
#include "common/mac/macho_reader.h"
|
||||
#include "common/module.h"
|
||||
#include "common/stabs_reader.h"
|
||||
#include "common/stabs_to_module.h"
|
||||
|
||||
#ifndef CPU_TYPE_ARM
|
||||
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
|
||||
#endif // CPU_TYPE_ARM
|
||||
|
||||
using dwarf2reader::ByteReader;
|
||||
using google_breakpad::DwarfCUToModule;
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::FileID;
|
||||
using google_breakpad::mach_o::FatReader;
|
||||
using google_breakpad::mach_o::Section;
|
||||
using google_breakpad::mach_o::Segment;
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::StabsReader;
|
||||
using google_breakpad::StabsToModule;
|
||||
using std::make_pair;
|
||||
using std::pair;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
bool DumpSymbols::Read(NSString *filename) {
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
|
||||
fprintf(stderr, "Object file does not exist: %s\n",
|
||||
[filename fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
|
||||
input_pathname_ = [filename retain];
|
||||
|
||||
// Does this filename refer to a dSYM bundle?
|
||||
NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_];
|
||||
|
||||
if (bundle) {
|
||||
// Filenames referring to bundles usually have names of the form
|
||||
// "<basename>.dSYM"; however, if the user has specified a wrapper
|
||||
// suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings),
|
||||
// then the name may have the form "<basename>.<extension>.dSYM". In
|
||||
// either case, the resource name for the file containing the DWARF
|
||||
// info within the bundle is <basename>.
|
||||
//
|
||||
// Since there's no way to tell how much to strip off, remove one
|
||||
// extension at a time, and use the first one that
|
||||
// pathForResource:ofType:inDirectory likes.
|
||||
NSString *base_name = [input_pathname_ lastPathComponent];
|
||||
NSString *dwarf_resource;
|
||||
|
||||
do {
|
||||
NSString *new_base_name = [base_name stringByDeletingPathExtension];
|
||||
|
||||
// If stringByDeletingPathExtension returned the name unchanged, then
|
||||
// there's nothing more for us to strip off --- lose.
|
||||
if ([new_base_name isEqualToString:base_name]) {
|
||||
fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
|
||||
[input_pathname_ fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Take the shortened result as our new base_name.
|
||||
base_name = new_base_name;
|
||||
|
||||
// Try to find a DWARF resource in the bundle under the new base_name.
|
||||
dwarf_resource = [bundle pathForResource:base_name
|
||||
ofType:nil inDirectory:@"DWARF"];
|
||||
} while (!dwarf_resource);
|
||||
|
||||
object_filename_ = [dwarf_resource retain];
|
||||
} else {
|
||||
object_filename_ = [input_pathname_ retain];
|
||||
}
|
||||
|
||||
// Read the file's contents into memory.
|
||||
//
|
||||
// The documentation for dataWithContentsOfMappedFile says:
|
||||
//
|
||||
// Because of file mapping restrictions, this method should only be
|
||||
// used if the file is guaranteed to exist for the duration of the
|
||||
// data object’s existence. It is generally safer to use the
|
||||
// dataWithContentsOfFile: method.
|
||||
//
|
||||
// I gather this means that OS X doesn't have (or at least, that method
|
||||
// doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the
|
||||
// process appears to get its own copy of the data, and changes to the
|
||||
// file don't affect memory and vice versa).
|
||||
NSError *error;
|
||||
contents_ = [NSData dataWithContentsOfFile:object_filename_
|
||||
options:0
|
||||
error:&error];
|
||||
if (!contents_) {
|
||||
fprintf(stderr, "Error reading object file: %s: %s\n",
|
||||
[object_filename_ fileSystemRepresentation],
|
||||
[[error localizedDescription] UTF8String]);
|
||||
return false;
|
||||
}
|
||||
[contents_ retain];
|
||||
|
||||
// Get the list of object files present in the file.
|
||||
FatReader::Reporter fat_reporter([object_filename_
|
||||
fileSystemRepresentation]);
|
||||
FatReader fat_reader(&fat_reporter);
|
||||
if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]),
|
||||
[contents_ length])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get our own copy of fat_reader's object file list.
|
||||
size_t object_files_count;
|
||||
const struct fat_arch *object_files =
|
||||
fat_reader.object_files(&object_files_count);
|
||||
if (object_files_count == 0) {
|
||||
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
object_files_.resize(object_files_count);
|
||||
memcpy(&object_files_[0], object_files,
|
||||
sizeof(struct fat_arch) * object_files_count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype) {
|
||||
// Find the best match for the architecture the user requested.
|
||||
const struct fat_arch *best_match
|
||||
= NXFindBestFatArch(cpu_type, cpu_subtype, &object_files_[0],
|
||||
static_cast<uint32_t>(object_files_.size()));
|
||||
if (!best_match) return false;
|
||||
|
||||
// Record the selected object file.
|
||||
selected_object_file_ = best_match;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
|
||||
bool arch_set = false;
|
||||
const NXArchInfo *arch_info = NXGetArchInfoFromName(arch_name.c_str());
|
||||
if (arch_info) {
|
||||
arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
|
||||
}
|
||||
return arch_set;
|
||||
}
|
||||
|
||||
string DumpSymbols::Identifier() {
|
||||
FileID file_id([object_filename_ fileSystemRepresentation]);
|
||||
unsigned char identifier_bytes[16];
|
||||
cpu_type_t cpu_type = selected_object_file_->cputype;
|
||||
if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) {
|
||||
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
return "";
|
||||
}
|
||||
|
||||
char identifier_string[40];
|
||||
FileID::ConvertIdentifierToString(identifier_bytes, identifier_string,
|
||||
sizeof(identifier_string));
|
||||
|
||||
string compacted(identifier_string);
|
||||
for(size_t i = compacted.find('-'); i != string::npos;
|
||||
i = compacted.find('-', i))
|
||||
compacted.erase(i, 1);
|
||||
|
||||
return compacted;
|
||||
}
|
||||
|
||||
// A line-to-module loader that accepts line number info parsed by
|
||||
// dwarf2reader::LineInfo and populates a Module and a line vector
|
||||
// with the results.
|
||||
class DumpSymbols::DumperLineToModule:
|
||||
public DwarfCUToModule::LineToModuleFunctor {
|
||||
public:
|
||||
// Create a line-to-module converter using BYTE_READER.
|
||||
DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
|
||||
: byte_reader_(byte_reader) { }
|
||||
void operator()(const char *program, uint64 length,
|
||||
Module *module, vector<Module::Line> *lines) {
|
||||
DwarfLineToModule handler(module, lines);
|
||||
dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
|
||||
parser.Start();
|
||||
}
|
||||
private:
|
||||
dwarf2reader::ByteReader *byte_reader_; // WEAK
|
||||
};
|
||||
|
||||
bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
||||
const mach_o::Reader &macho_reader,
|
||||
const mach_o::SectionMap &dwarf_sections) const {
|
||||
// Build a byte reader of the appropriate endianness.
|
||||
ByteReader byte_reader(macho_reader.big_endian()
|
||||
? dwarf2reader::ENDIANNESS_BIG
|
||||
: dwarf2reader::ENDIANNESS_LITTLE);
|
||||
|
||||
// Construct a context for this file.
|
||||
DwarfCUToModule::FileContext file_context(selected_object_name_,
|
||||
module);
|
||||
|
||||
// Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
|
||||
for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
|
||||
it != dwarf_sections.end(); it++) {
|
||||
file_context.section_map[it->first] =
|
||||
make_pair(reinterpret_cast<const char *>(it->second.contents.start),
|
||||
it->second.contents.Size());
|
||||
}
|
||||
|
||||
// Find the __debug_info section.
|
||||
std::pair<const char *, uint64> debug_info_section
|
||||
= file_context.section_map["__debug_info"];
|
||||
// There had better be a __debug_info section!
|
||||
if (!debug_info_section.first) {
|
||||
fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
|
||||
selected_object_name_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a line-to-module loader for the root handler to use.
|
||||
DumperLineToModule line_to_module(&byte_reader);
|
||||
|
||||
// Walk the __debug_info section, one compilation unit at a time.
|
||||
uint64 debug_info_length = debug_info_section.second;
|
||||
for (uint64 offset = 0; offset < debug_info_length;) {
|
||||
// Make a handler for the root DIE that populates MODULE with the
|
||||
// debug info.
|
||||
DwarfCUToModule::WarningReporter reporter(selected_object_name_,
|
||||
offset);
|
||||
DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
|
||||
// Make a Dwarf2Handler that drives our DIEHandler.
|
||||
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
|
||||
// Make a DWARF parser for the compilation unit at OFFSET.
|
||||
dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map,
|
||||
offset,
|
||||
&byte_reader,
|
||||
&die_dispatcher);
|
||||
// Process the entire compilation unit; get the offset of the next.
|
||||
offset += dwarf_reader.Start();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
|
||||
const mach_o::Reader &macho_reader,
|
||||
const mach_o::Section §ion,
|
||||
bool eh_frame) const {
|
||||
// Find the appropriate set of register names for this file's
|
||||
// architecture.
|
||||
vector<string> register_names;
|
||||
switch (macho_reader.cpu_type()) {
|
||||
case CPU_TYPE_X86:
|
||||
register_names = DwarfCFIToModule::RegisterNames::I386();
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
register_names = DwarfCFIToModule::RegisterNames::X86_64();
|
||||
break;
|
||||
case CPU_TYPE_ARM:
|
||||
register_names = DwarfCFIToModule::RegisterNames::ARM();
|
||||
break;
|
||||
default: {
|
||||
const NXArchInfo *arch =
|
||||
NXGetArchInfoFromCpuType(macho_reader.cpu_type(),
|
||||
macho_reader.cpu_subtype());
|
||||
fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
|
||||
selected_object_name_.c_str());
|
||||
if (arch)
|
||||
fprintf(stderr, "architecture '%s'", arch->name);
|
||||
else
|
||||
fprintf(stderr, "architecture %d,%d",
|
||||
macho_reader.cpu_type(), macho_reader.cpu_subtype());
|
||||
fprintf(stderr, " to Breakpad symbol file: no register name table\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the call frame information and its size.
|
||||
const char *cfi = reinterpret_cast<const char *>(section.contents.start);
|
||||
size_t cfi_size = section.contents.Size();
|
||||
|
||||
// Plug together the parser, handler, and their entourages.
|
||||
DwarfCFIToModule::Reporter module_reporter(selected_object_name_,
|
||||
section.section_name);
|
||||
DwarfCFIToModule handler(module, register_names, &module_reporter);
|
||||
dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ?
|
||||
dwarf2reader::ENDIANNESS_BIG :
|
||||
dwarf2reader::ENDIANNESS_LITTLE);
|
||||
byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4);
|
||||
// At the moment, according to folks at Apple and some cursory
|
||||
// investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
|
||||
// this is the only base address the CFI parser will need.
|
||||
byte_reader.SetCFIDataBase(section.address, cfi);
|
||||
|
||||
dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
|
||||
section.section_name);
|
||||
dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
|
||||
&byte_reader, &handler, &dwarf_reporter,
|
||||
eh_frame);
|
||||
parser.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
// A LoadCommandHandler that loads whatever debugging data it finds into a
|
||||
// Module.
|
||||
class DumpSymbols::LoadCommandDumper:
|
||||
public mach_o::Reader::LoadCommandHandler {
|
||||
public:
|
||||
// Create a load command dumper handling load commands from READER's
|
||||
// file, and adding data to MODULE.
|
||||
LoadCommandDumper(const DumpSymbols &dumper,
|
||||
google_breakpad::Module *module,
|
||||
const mach_o::Reader &reader)
|
||||
: dumper_(dumper), module_(module), reader_(reader) { }
|
||||
|
||||
bool SegmentCommand(const mach_o::Segment &segment);
|
||||
bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
|
||||
|
||||
private:
|
||||
const DumpSymbols &dumper_;
|
||||
google_breakpad::Module *module_; // WEAK
|
||||
const mach_o::Reader &reader_;
|
||||
};
|
||||
|
||||
bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
|
||||
mach_o::SectionMap section_map;
|
||||
if (!reader_.MapSegmentSections(segment, §ion_map))
|
||||
return false;
|
||||
|
||||
if (segment.name == "__TEXT") {
|
||||
module_->SetLoadAddress(segment.vmaddr);
|
||||
mach_o::SectionMap::const_iterator eh_frame =
|
||||
section_map.find("__eh_frame");
|
||||
if (eh_frame != section_map.end()) {
|
||||
// If there is a problem reading this, don't treat it as a fatal error.
|
||||
dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (segment.name == "__DWARF") {
|
||||
if (!dumper_.ReadDwarf(module_, reader_, section_map))
|
||||
return false;
|
||||
mach_o::SectionMap::const_iterator debug_frame
|
||||
= section_map.find("__debug_frame");
|
||||
if (debug_frame != section_map.end()) {
|
||||
// If there is a problem reading this, don't treat it as a fatal error.
|
||||
dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
|
||||
const ByteBuffer &strings) {
|
||||
StabsToModule stabs_to_module(module_);
|
||||
// Mac OS X STABS are never "unitized", and the size of the 'value' field
|
||||
// matches the address size of the executable.
|
||||
StabsReader stabs_reader(entries.start, entries.Size(),
|
||||
strings.start, strings.Size(),
|
||||
reader_.big_endian(),
|
||||
reader_.bits_64() ? 8 : 4,
|
||||
true,
|
||||
&stabs_to_module);
|
||||
if (!stabs_reader.Process())
|
||||
return false;
|
||||
stabs_to_module.Finalize();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||
// Select an object file, if SetArchitecture hasn't been called to set one
|
||||
// explicitly.
|
||||
if (!selected_object_file_) {
|
||||
// If there's only one architecture, that's the one.
|
||||
if (object_files_.size() == 1)
|
||||
selected_object_file_ = &object_files_[0];
|
||||
else {
|
||||
// Look for an object file whose architecture matches our own.
|
||||
const NXArchInfo *local_arch = NXGetLocalArchInfo();
|
||||
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
|
||||
fprintf(stderr, "%s: object file contains more than one"
|
||||
" architecture, none of which match the current"
|
||||
" architecture; specify an architecture explicitly"
|
||||
" with '-a ARCH' to resolve the ambiguity\n",
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(selected_object_file_);
|
||||
|
||||
// Find the name of the selected file's architecture, to appear in
|
||||
// the MODULE record and in error messages.
|
||||
const NXArchInfo *selected_arch_info
|
||||
= NXGetArchInfoFromCpuType(selected_object_file_->cputype,
|
||||
selected_object_file_->cpusubtype);
|
||||
|
||||
const char *selected_arch_name = selected_arch_info->name;
|
||||
if (strcmp(selected_arch_name, "i386") == 0)
|
||||
selected_arch_name = "x86";
|
||||
|
||||
// Produce a name to use in error messages that includes the
|
||||
// filename, and the architecture, if there is more than one.
|
||||
selected_object_name_ = [object_filename_ UTF8String];
|
||||
if (object_files_.size() > 1) {
|
||||
selected_object_name_ += ", architecture ";
|
||||
selected_object_name_ + selected_arch_name;
|
||||
}
|
||||
|
||||
// Compute a module name, to appear in the MODULE record.
|
||||
NSString *module_name = [object_filename_ lastPathComponent];
|
||||
|
||||
// Choose an identifier string, to appear in the MODULE record.
|
||||
string identifier = Identifier();
|
||||
if (identifier.empty())
|
||||
return false;
|
||||
identifier += "0";
|
||||
|
||||
// Create a module to hold the debugging information.
|
||||
Module module([module_name UTF8String], "mac", selected_arch_name,
|
||||
identifier);
|
||||
|
||||
// Parse the selected object file.
|
||||
mach_o::Reader::Reporter reporter(selected_object_name_);
|
||||
mach_o::Reader reader(&reporter);
|
||||
if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
|
||||
+ selected_object_file_->offset,
|
||||
selected_object_file_->size,
|
||||
selected_object_file_->cputype,
|
||||
selected_object_file_->cpusubtype))
|
||||
return false;
|
||||
|
||||
// Walk its load commands, and deal with whatever is there.
|
||||
LoadCommandDumper load_command_dumper(*this, &module, reader);
|
||||
if (!reader.WalkLoadCommands(&load_command_dumper))
|
||||
return false;
|
||||
|
||||
return module.Write(stream);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
101
thirdparty/breakpad/common/mac/file_id.cc
vendored
Normal file
101
thirdparty/breakpad/common/mac/file_id.cc
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// file_id.cc: Return a unique identifier for a file
|
||||
//
|
||||
// See file_id.h for documentation
|
||||
//
|
||||
// Author: Dan Waylonis
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/mac/file_id.h"
|
||||
#include "common/mac/macho_id.h"
|
||||
|
||||
using MacFileUtilities::MachoID;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
FileID::FileID(const char *path) {
|
||||
strlcpy(path_, path, sizeof(path_));
|
||||
}
|
||||
|
||||
bool FileID::FileIdentifier(unsigned char identifier[16]) {
|
||||
int fd = open(path_, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return false;
|
||||
|
||||
MD5Context md5;
|
||||
MD5Init(&md5);
|
||||
|
||||
// Read 4k x 2 bytes at a time. This is faster than just 4k bytes, but
|
||||
// doesn't seem to be an unreasonable size for the stack.
|
||||
unsigned char buffer[4096 * 2];
|
||||
size_t buffer_size = sizeof(buffer);
|
||||
while ((buffer_size = read(fd, buffer, buffer_size) > 0)) {
|
||||
MD5Update(&md5, buffer, buffer_size);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
MD5Final(identifier, &md5);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileID::MachoIdentifier(int cpu_type, unsigned char identifier[16]) {
|
||||
MachoID macho(path_);
|
||||
|
||||
if (macho.UUIDCommand(cpu_type, identifier))
|
||||
return true;
|
||||
|
||||
return macho.MD5(cpu_type, identifier);
|
||||
}
|
||||
|
||||
// static
|
||||
void FileID::ConvertIdentifierToString(const unsigned char identifier[16],
|
||||
char *buffer, int buffer_length) {
|
||||
int buffer_idx = 0;
|
||||
for (int idx = 0; (buffer_idx < buffer_length) && (idx < 16); ++idx) {
|
||||
int hi = (identifier[idx] >> 4) & 0x0F;
|
||||
int lo = (identifier[idx]) & 0x0F;
|
||||
|
||||
if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
|
||||
buffer[buffer_idx++] = '-';
|
||||
|
||||
buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
|
||||
buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
|
||||
}
|
||||
|
||||
// NULL terminate
|
||||
buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
78
thirdparty/breakpad/common/mac/file_id.h
vendored
Normal file
78
thirdparty/breakpad/common/mac/file_id.h
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// file_id.h: Return a unique identifier for a file
|
||||
//
|
||||
// Author: Dan Waylonis
|
||||
|
||||
#ifndef COMMON_MAC_FILE_ID_H__
|
||||
#define COMMON_MAC_FILE_ID_H__
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class FileID {
|
||||
public:
|
||||
FileID(const char *path);
|
||||
~FileID() {};
|
||||
|
||||
// Load the identifier for the file path specified in the constructor into
|
||||
// |identifier|. Return false if the identifier could not be created for the
|
||||
// file.
|
||||
// The current implementation will return the MD5 hash of the file's bytes.
|
||||
bool FileIdentifier(unsigned char identifier[16]);
|
||||
|
||||
// Treat the file as a mach-o file that will contain one or more archicture.
|
||||
// Accepted values for |cpu_type| (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC)
|
||||
// are listed in /usr/include/mach/machine.h.
|
||||
// If |cpu_type| is 0, then the native cpu type is used.
|
||||
// Returns false if opening the file failed or if the |cpu_type| is not
|
||||
// present in the file.
|
||||
// Return the unique identifier in |identifier|.
|
||||
// The current implementation will look for the (in order of priority):
|
||||
// LC_UUID, LC_ID_DYLIB, or MD5 hash of the given |cpu_type|.
|
||||
bool MachoIdentifier(int cpu_type, unsigned char identifier[16]);
|
||||
|
||||
// Convert the |identifier| data to a NULL terminated string. The string will
|
||||
// be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
|
||||
// The |buffer| should be at least 37 bytes long to receive all of the data
|
||||
// and termination. Shorter buffers will contain truncated data.
|
||||
static void ConvertIdentifierToString(const unsigned char identifier[16],
|
||||
char *buffer, int buffer_length);
|
||||
|
||||
private:
|
||||
// Storage for the path specified
|
||||
char path_[PATH_MAX];
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_MAC_FILE_ID_H__
|
||||
|
349
thirdparty/breakpad/common/mac/macho_id.cc
vendored
Normal file
349
thirdparty/breakpad/common/mac/macho_id.cc
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// macho_id.cc: Functions to gather identifying information from a macho file
|
||||
//
|
||||
// See macho_id.h for documentation
|
||||
//
|
||||
// Author: Dan Waylonis
|
||||
|
||||
extern "C" { // necessary for Leopard
|
||||
#include <fcntl.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/swap.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include "common/mac/macho_id.h"
|
||||
#include "common/mac/macho_walker.h"
|
||||
#include "common/mac/macho_utilities.h"
|
||||
|
||||
namespace MacFileUtilities {
|
||||
|
||||
MachoID::MachoID(const char *path)
|
||||
: file_(0),
|
||||
crc_(0),
|
||||
md5_context_(),
|
||||
update_function_(NULL) {
|
||||
strlcpy(path_, path, sizeof(path_));
|
||||
file_ = open(path, O_RDONLY);
|
||||
}
|
||||
|
||||
MachoID::~MachoID() {
|
||||
if (file_ != -1)
|
||||
close(file_);
|
||||
}
|
||||
|
||||
// The CRC info is from http://en.wikipedia.org/wiki/Adler-32
|
||||
// With optimizations from http://www.zlib.net/
|
||||
|
||||
// The largest prime smaller than 65536
|
||||
#define MOD_ADLER 65521
|
||||
// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1
|
||||
#define MAX_BLOCK 5552
|
||||
|
||||
void MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
|
||||
// Unrolled loops for summing
|
||||
#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;}
|
||||
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
|
||||
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
|
||||
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
|
||||
#define DO16(buf) DO8(buf,0); DO8(buf,8);
|
||||
// Split up the crc
|
||||
uint32_t sum1 = crc_ & 0xFFFF;
|
||||
uint32_t sum2 = (crc_ >> 16) & 0xFFFF;
|
||||
|
||||
// Do large blocks
|
||||
while (size >= MAX_BLOCK) {
|
||||
size -= MAX_BLOCK;
|
||||
int block_count = MAX_BLOCK / 16;
|
||||
do {
|
||||
DO16(bytes);
|
||||
bytes += 16;
|
||||
} while (--block_count);
|
||||
sum1 %= MOD_ADLER;
|
||||
sum2 %= MOD_ADLER;
|
||||
}
|
||||
|
||||
// Do remaining bytes
|
||||
if (size) {
|
||||
while (size >= 16) {
|
||||
size -= 16;
|
||||
DO16(bytes);
|
||||
bytes += 16;
|
||||
}
|
||||
while (size--) {
|
||||
sum1 += *bytes++;
|
||||
sum2 += sum1;
|
||||
}
|
||||
sum1 %= MOD_ADLER;
|
||||
sum2 %= MOD_ADLER;
|
||||
crc_ = (sum2 << 16) | sum1;
|
||||
}
|
||||
}
|
||||
|
||||
void MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
|
||||
MD5Update(&md5_context_, bytes, size);
|
||||
}
|
||||
|
||||
void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
|
||||
if (!update_function_ || !size)
|
||||
return;
|
||||
|
||||
// Read up to 4k bytes at a time
|
||||
unsigned char buffer[4096];
|
||||
size_t buffer_size;
|
||||
off_t file_offset = offset;
|
||||
while (size > 0) {
|
||||
if (size > sizeof(buffer)) {
|
||||
buffer_size = sizeof(buffer);
|
||||
size -= buffer_size;
|
||||
} else {
|
||||
buffer_size = size;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (!walker->ReadBytes(buffer, buffer_size, file_offset))
|
||||
return;
|
||||
|
||||
(this->*update_function_)(buffer, buffer_size);
|
||||
file_offset += buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
|
||||
struct breakpad_uuid_command uuid_cmd;
|
||||
MachoWalker walker(path_, UUIDWalkerCB, &uuid_cmd);
|
||||
|
||||
uuid_cmd.cmd = 0;
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
return false;
|
||||
|
||||
// If we found the command, we'll have initialized the uuid_command
|
||||
// structure
|
||||
if (uuid_cmd.cmd == LC_UUID) {
|
||||
memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
|
||||
struct dylib_command dylib_cmd;
|
||||
MachoWalker walker(path_, IDWalkerCB, &dylib_cmd);
|
||||
|
||||
dylib_cmd.cmd = 0;
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
return false;
|
||||
|
||||
// If we found the command, we'll have initialized the dylib_command
|
||||
// structure
|
||||
if (dylib_cmd.cmd == LC_ID_DYLIB) {
|
||||
// Take the hashed filename, version, and compatability version bytes
|
||||
// to form the first 12 bytes, pad the rest with zeros
|
||||
|
||||
// create a crude hash of the filename to generate the first 4 bytes
|
||||
identifier[0] = 0;
|
||||
identifier[1] = 0;
|
||||
identifier[2] = 0;
|
||||
identifier[3] = 0;
|
||||
|
||||
for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) {
|
||||
identifier[j%4] += path_[i];
|
||||
}
|
||||
|
||||
identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF;
|
||||
identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF;
|
||||
identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF;
|
||||
identifier[7] = dylib_cmd.dylib.current_version & 0xFF;
|
||||
identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF;
|
||||
identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF;
|
||||
identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF;
|
||||
identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF;
|
||||
identifier[12] = (cpu_type >> 24) & 0xFF;
|
||||
identifier[13] = (cpu_type >> 16) & 0xFF;
|
||||
identifier[14] = (cpu_type >> 8) & 0xFF;
|
||||
identifier[15] = cpu_type & 0xFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t MachoID::Adler32(int cpu_type) {
|
||||
MachoWalker walker(path_, WalkerCB, this);
|
||||
update_function_ = &MachoID::UpdateCRC;
|
||||
crc_ = 0;
|
||||
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
return 0;
|
||||
|
||||
return crc_;
|
||||
}
|
||||
|
||||
bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) {
|
||||
MachoWalker walker(path_, WalkerCB, this);
|
||||
update_function_ = &MachoID::UpdateMD5;
|
||||
|
||||
MD5Init(&md5_context_);
|
||||
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
return false;
|
||||
|
||||
MD5Final(identifier, &md5_context_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context) {
|
||||
MachoID *macho_id = (MachoID *)context;
|
||||
|
||||
if (cmd->cmd == LC_SEGMENT) {
|
||||
struct segment_command seg;
|
||||
|
||||
if (!walker->ReadBytes(&seg, sizeof(seg), offset))
|
||||
return false;
|
||||
|
||||
if (swap)
|
||||
swap_segment_command(&seg, NXHostByteOrder());
|
||||
|
||||
struct mach_header_64 header;
|
||||
off_t header_offset;
|
||||
|
||||
if (!walker->CurrentHeader(&header, &header_offset))
|
||||
return false;
|
||||
|
||||
// Process segments that have sections:
|
||||
// (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
|
||||
offset += sizeof(struct segment_command);
|
||||
struct section sec;
|
||||
for (unsigned long i = 0; i < seg.nsects; ++i) {
|
||||
if (!walker->ReadBytes(&sec, sizeof(sec), offset))
|
||||
return false;
|
||||
|
||||
if (swap)
|
||||
swap_section(&sec, 1, NXHostByteOrder());
|
||||
|
||||
// sections of type S_ZEROFILL are "virtual" and contain no data
|
||||
// in the file itself
|
||||
if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0)
|
||||
macho_id->Update(walker, header_offset + sec.offset, sec.size);
|
||||
|
||||
offset += sizeof(struct section);
|
||||
}
|
||||
} else if (cmd->cmd == LC_SEGMENT_64) {
|
||||
struct segment_command_64 seg64;
|
||||
|
||||
if (!walker->ReadBytes(&seg64, sizeof(seg64), offset))
|
||||
return false;
|
||||
|
||||
if (swap)
|
||||
breakpad_swap_segment_command_64(&seg64, NXHostByteOrder());
|
||||
|
||||
struct mach_header_64 header;
|
||||
off_t header_offset;
|
||||
|
||||
if (!walker->CurrentHeader(&header, &header_offset))
|
||||
return false;
|
||||
|
||||
// Process segments that have sections:
|
||||
// (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
|
||||
offset += sizeof(struct segment_command_64);
|
||||
struct section_64 sec64;
|
||||
for (unsigned long i = 0; i < seg64.nsects; ++i) {
|
||||
if (!walker->ReadBytes(&sec64, sizeof(sec64), offset))
|
||||
return false;
|
||||
|
||||
if (swap)
|
||||
breakpad_swap_section_64(&sec64, 1, NXHostByteOrder());
|
||||
|
||||
// sections of type S_ZEROFILL are "virtual" and contain no data
|
||||
// in the file itself
|
||||
if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0)
|
||||
macho_id->Update(walker,
|
||||
header_offset + sec64.offset,
|
||||
(size_t)sec64.size);
|
||||
|
||||
offset += sizeof(struct section_64);
|
||||
}
|
||||
}
|
||||
|
||||
// Continue processing
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context) {
|
||||
if (cmd->cmd == LC_UUID) {
|
||||
struct breakpad_uuid_command *uuid_cmd =
|
||||
(struct breakpad_uuid_command *)context;
|
||||
|
||||
if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
|
||||
offset))
|
||||
return false;
|
||||
|
||||
if (swap)
|
||||
breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Continue processing
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context) {
|
||||
if (cmd->cmd == LC_ID_DYLIB) {
|
||||
struct dylib_command *dylib_cmd = (struct dylib_command *)context;
|
||||
|
||||
if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset))
|
||||
return false;
|
||||
|
||||
if (swap)
|
||||
swap_dylib_command(dylib_cmd, NXHostByteOrder());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Continue processing
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace MacFileUtilities
|
113
thirdparty/breakpad/common/mac/macho_id.h
vendored
Normal file
113
thirdparty/breakpad/common/mac/macho_id.h
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// macho_id.h: Functions to gather identifying information from a macho file
|
||||
//
|
||||
// Author: Dan Waylonis
|
||||
|
||||
#ifndef COMMON_MAC_MACHO_ID_H__
|
||||
#define COMMON_MAC_MACHO_ID_H__
|
||||
|
||||
#include <limits.h>
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
#include "common/md5.h"
|
||||
|
||||
namespace MacFileUtilities {
|
||||
|
||||
class MachoWalker;
|
||||
|
||||
class MachoID {
|
||||
public:
|
||||
MachoID(const char *path);
|
||||
~MachoID();
|
||||
|
||||
// For the given |cpu_type|, return a UUID from the LC_UUID command.
|
||||
// Return false if there isn't a LC_UUID command.
|
||||
bool UUIDCommand(int cpu_type, unsigned char identifier[16]);
|
||||
|
||||
// For the given |cpu_type|, return a UUID from the LC_ID_DYLIB command.
|
||||
// Return false if there isn't a LC_ID_DYLIB command.
|
||||
bool IDCommand(int cpu_type, unsigned char identifier[16]);
|
||||
|
||||
// For the given |cpu_type|, return the Adler32 CRC for the mach-o data
|
||||
// segment(s).
|
||||
// Return 0 on error (e.g., if the file is not a mach-o file)
|
||||
uint32_t Adler32(int cpu_type);
|
||||
|
||||
// For the given |cpu_type|, return the MD5 for the mach-o data segment(s).
|
||||
// Return true on success, false otherwise
|
||||
bool MD5(int cpu_type, unsigned char identifier[16]);
|
||||
|
||||
private:
|
||||
// Signature of class member function to be called with data read from file
|
||||
typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size);
|
||||
|
||||
// Update the CRC value by examining |size| |bytes| and applying the algorithm
|
||||
// to each byte.
|
||||
void UpdateCRC(unsigned char *bytes, size_t size);
|
||||
|
||||
// Update the MD5 value by examining |size| |bytes| and applying the algorithm
|
||||
// to each byte.
|
||||
void UpdateMD5(unsigned char *bytes, size_t size);
|
||||
|
||||
// Bottleneck for update routines
|
||||
void Update(MachoWalker *walker, off_t offset, size_t size);
|
||||
|
||||
// The callback from the MachoWalker for CRC and MD5
|
||||
static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context);
|
||||
|
||||
// The callback from the MachoWalker for LC_UUID
|
||||
static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context);
|
||||
|
||||
// The callback from the MachoWalker for LC_ID_DYLIB
|
||||
static bool IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context);
|
||||
|
||||
// File path
|
||||
char path_[PATH_MAX];
|
||||
|
||||
// File descriptor
|
||||
int file_;
|
||||
|
||||
// The current crc value
|
||||
uint32_t crc_;
|
||||
|
||||
// The MD5 context
|
||||
MD5Context md5_context_;
|
||||
|
||||
// The current update to call from the Update callback
|
||||
UpdateFunction update_function_;
|
||||
};
|
||||
|
||||
} // namespace MacFileUtilities
|
||||
|
||||
#endif // COMMON_MAC_MACHO_ID_H__
|
524
thirdparty/breakpad/common/mac/macho_reader.cc
vendored
Normal file
524
thirdparty/breakpad/common/mac/macho_reader.cc
vendored
Normal file
@@ -0,0 +1,524 @@
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and
|
||||
// google_breakpad::Mach_O::Reader. See macho_reader.h for details.
|
||||
|
||||
#include "common/mac/macho_reader.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace mach_o {
|
||||
|
||||
// If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its
|
||||
// arguments, so you can't place expressions that do necessary work in
|
||||
// the argument of an assert. Nor can you assign the result of the
|
||||
// expression to a variable and assert that the variable's value is
|
||||
// true: you'll get unused variable warnings when NDEBUG is #defined.
|
||||
//
|
||||
// ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that
|
||||
// the result is true if NDEBUG is not #defined.
|
||||
#if defined(NDEBUG)
|
||||
#define ASSERT_ALWAYS_EVAL(x) (x)
|
||||
#else
|
||||
#define ASSERT_ALWAYS_EVAL(x) assert(x)
|
||||
#endif
|
||||
|
||||
void FatReader::Reporter::BadHeader() {
|
||||
fprintf(stderr, "%s: file is neither a fat binary file"
|
||||
" nor a Mach-O object file\n", filename_.c_str());
|
||||
}
|
||||
|
||||
void FatReader::Reporter::TooShort() {
|
||||
fprintf(stderr, "%s: file too short for the data it claims to contain\n",
|
||||
filename_.c_str());
|
||||
}
|
||||
|
||||
void FatReader::Reporter::MisplacedObjectFile() {
|
||||
fprintf(stderr, "%s: file too short for the object files it claims"
|
||||
" to contain\n", filename_.c_str());
|
||||
}
|
||||
|
||||
bool FatReader::Read(const uint8_t *buffer, size_t size) {
|
||||
buffer_.start = buffer;
|
||||
buffer_.end = buffer + size;
|
||||
ByteCursor cursor(&buffer_);
|
||||
|
||||
// Fat binaries always use big-endian, so read the magic number in
|
||||
// that endianness. To recognize Mach-O magic numbers, which can use
|
||||
// either endianness, check for both the proper and reversed forms
|
||||
// of the magic numbers.
|
||||
cursor.set_big_endian(true);
|
||||
if (cursor >> magic_) {
|
||||
if (magic_ == FAT_MAGIC) {
|
||||
// How many object files does this fat binary contain?
|
||||
uint32_t object_files_count;
|
||||
if (!(cursor >> object_files_count)) { // nfat_arch
|
||||
reporter_->TooShort();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the list of object files.
|
||||
object_files_.resize(object_files_count);
|
||||
for (size_t i = 0; i < object_files_count; i++) {
|
||||
struct fat_arch *objfile = &object_files_[i];
|
||||
|
||||
// Read this object file entry, byte-swapping as appropriate.
|
||||
cursor >> objfile->cputype
|
||||
>> objfile->cpusubtype
|
||||
>> objfile->offset
|
||||
>> objfile->size
|
||||
>> objfile->align;
|
||||
if (!cursor) {
|
||||
reporter_->TooShort();
|
||||
return false;
|
||||
}
|
||||
// Does the file actually have the bytes this entry refers to?
|
||||
size_t fat_size = buffer_.Size();
|
||||
if (objfile->offset > fat_size ||
|
||||
objfile->size > fat_size - objfile->offset) {
|
||||
reporter_->MisplacedObjectFile();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 ||
|
||||
magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) {
|
||||
// If this is a little-endian Mach-O file, fix the cursor's endianness.
|
||||
if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64)
|
||||
cursor.set_big_endian(false);
|
||||
// Record the entire file as a single entry in the object file list.
|
||||
object_files_.resize(1);
|
||||
|
||||
// Get the cpu type and subtype from the Mach-O header.
|
||||
if (!(cursor >> object_files_[0].cputype
|
||||
>> object_files_[0].cpusubtype)) {
|
||||
reporter_->TooShort();
|
||||
return false;
|
||||
}
|
||||
|
||||
object_files_[0].offset = 0;
|
||||
object_files_[0].size = static_cast<uint32_t>(buffer_.Size());
|
||||
// This alignment is correct for 32 and 64-bit x86 and ppc.
|
||||
// See get_align in the lipo source for other architectures:
|
||||
// http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
|
||||
object_files_[0].align = 12; // 2^12 == 4096
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
reporter_->BadHeader();
|
||||
return false;
|
||||
}
|
||||
|
||||
void Reader::Reporter::BadHeader() {
|
||||
fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype) {
|
||||
fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected"
|
||||
" type %d, subtype %d\n",
|
||||
filename_.c_str(), cpu_type, cpu_subtype,
|
||||
expected_cpu_type, expected_cpu_subtype);
|
||||
}
|
||||
|
||||
void Reader::Reporter::HeaderTruncated() {
|
||||
fprintf(stderr, "%s: file does not contain a complete Mach-O header\n",
|
||||
filename_.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::LoadCommandRegionTruncated() {
|
||||
fprintf(stderr, "%s: file too short to hold load command region"
|
||||
" given in Mach-O header\n", filename_.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i,
|
||||
LoadCommandType type) {
|
||||
fprintf(stderr, "%s: file's header claims there are %ld"
|
||||
" load commands, but load command #%ld",
|
||||
filename_.c_str(), claimed, i);
|
||||
if (type) fprintf(stderr, ", of type %d,", type);
|
||||
fprintf(stderr, " extends beyond the end of the load command region\n");
|
||||
}
|
||||
|
||||
void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
|
||||
fprintf(stderr, "%s: the contents of load command #%ld, of type %d,"
|
||||
" extend beyond the size given in the load command's header\n",
|
||||
filename_.c_str(), i, type);
|
||||
}
|
||||
|
||||
void Reader::Reporter::SectionsMissing(const string &name) {
|
||||
fprintf(stderr, "%s: the load command for segment '%s'"
|
||||
" is too short to hold the section headers it claims to have\n",
|
||||
filename_.c_str(), name.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::MisplacedSegmentData(const string &name) {
|
||||
fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond"
|
||||
" the end of the file\n", filename_.c_str(), name.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::MisplacedSectionData(const string §ion,
|
||||
const string &segment) {
|
||||
fprintf(stderr, "%s: the section '%s' in segment '%s'"
|
||||
" claims its contents lie outside the segment's contents\n",
|
||||
filename_.c_str(), section.c_str(), segment.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::MisplacedSymbolTable() {
|
||||
fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol"
|
||||
" table's contents are located beyond the end of the file\n",
|
||||
filename_.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) {
|
||||
fprintf(stderr, "%s: CPU type %d is not supported\n",
|
||||
filename_.c_str(), cpu_type);
|
||||
}
|
||||
|
||||
bool Reader::Read(const uint8_t *buffer,
|
||||
size_t size,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype) {
|
||||
assert(!buffer_.start);
|
||||
buffer_.start = buffer;
|
||||
buffer_.end = buffer + size;
|
||||
ByteCursor cursor(&buffer_, true);
|
||||
uint32_t magic;
|
||||
if (!(cursor >> magic)) {
|
||||
reporter_->HeaderTruncated();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_cpu_type != CPU_TYPE_ANY) {
|
||||
uint32_t expected_magic;
|
||||
// validate that magic matches the expected cpu type
|
||||
switch (expected_cpu_type) {
|
||||
case CPU_TYPE_I386:
|
||||
expected_magic = MH_CIGAM;
|
||||
break;
|
||||
case CPU_TYPE_POWERPC:
|
||||
expected_magic = MH_MAGIC;
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
expected_magic = MH_CIGAM_64;
|
||||
break;
|
||||
case CPU_TYPE_POWERPC64:
|
||||
expected_magic = MH_MAGIC_64;
|
||||
break;
|
||||
default:
|
||||
reporter_->UnsupportedCPUType(expected_cpu_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_magic != magic) {
|
||||
reporter_->BadHeader();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Since the byte cursor is in big-endian mode, a reversed magic number
|
||||
// always indicates a little-endian file, regardless of our own endianness.
|
||||
switch (magic) {
|
||||
case MH_MAGIC: big_endian_ = true; bits_64_ = false; break;
|
||||
case MH_CIGAM: big_endian_ = false; bits_64_ = false; break;
|
||||
case MH_MAGIC_64: big_endian_ = true; bits_64_ = true; break;
|
||||
case MH_CIGAM_64: big_endian_ = false; bits_64_ = true; break;
|
||||
default:
|
||||
reporter_->BadHeader();
|
||||
return false;
|
||||
}
|
||||
cursor.set_big_endian(big_endian_);
|
||||
uint32_t commands_size, reserved;
|
||||
cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_
|
||||
>> commands_size >> flags_;
|
||||
if (bits_64_)
|
||||
cursor >> reserved;
|
||||
if (!cursor) {
|
||||
reporter_->HeaderTruncated();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_cpu_type != CPU_TYPE_ANY &&
|
||||
(expected_cpu_type != cpu_type_ ||
|
||||
expected_cpu_subtype != cpu_subtype_)) {
|
||||
reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_,
|
||||
expected_cpu_type, expected_cpu_subtype);
|
||||
return false;
|
||||
}
|
||||
|
||||
cursor
|
||||
.PointTo(&load_commands_.start, commands_size)
|
||||
.PointTo(&load_commands_.end, 0);
|
||||
if (!cursor) {
|
||||
reporter_->LoadCommandRegionTruncated();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
|
||||
ByteCursor list_cursor(&load_commands_, big_endian_);
|
||||
|
||||
for (size_t index = 0; index < load_command_count_; ++index) {
|
||||
// command refers to this load command alone, so that cursor will
|
||||
// refuse to read past the load command's end. But since we haven't
|
||||
// read the size yet, let command initially refer to the entire
|
||||
// remainder of the load command series.
|
||||
ByteBuffer command(list_cursor.here(), list_cursor.Available());
|
||||
ByteCursor cursor(&command, big_endian_);
|
||||
|
||||
// Read the command type and size --- fields common to all commands.
|
||||
uint32_t type, size;
|
||||
if (!(cursor >> type)) {
|
||||
reporter_->LoadCommandsOverrun(load_command_count_, index, 0);
|
||||
return false;
|
||||
}
|
||||
if (!(cursor >> size) || size > command.Size()) {
|
||||
reporter_->LoadCommandsOverrun(load_command_count_, index, type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now that we've read the length, restrict command's range to this
|
||||
// load command only.
|
||||
command.end = command.start + size;
|
||||
|
||||
switch (type) {
|
||||
case LC_SEGMENT:
|
||||
case LC_SEGMENT_64: {
|
||||
Segment segment;
|
||||
segment.bits_64 = (type == LC_SEGMENT_64);
|
||||
size_t word_size = segment.bits_64 ? 8 : 4;
|
||||
cursor.CString(&segment.name, 16);
|
||||
size_t file_offset, file_size;
|
||||
cursor
|
||||
.Read(word_size, false, &segment.vmaddr)
|
||||
.Read(word_size, false, &segment.vmsize)
|
||||
.Read(word_size, false, &file_offset)
|
||||
.Read(word_size, false, &file_size);
|
||||
cursor >> segment.maxprot
|
||||
>> segment.initprot
|
||||
>> segment.nsects
|
||||
>> segment.flags;
|
||||
if (!cursor) {
|
||||
reporter_->LoadCommandTooShort(index, type);
|
||||
return false;
|
||||
}
|
||||
if (file_offset > buffer_.Size() ||
|
||||
file_size > buffer_.Size() - file_offset) {
|
||||
reporter_->MisplacedSegmentData(segment.name);
|
||||
return false;
|
||||
}
|
||||
// Mach-O files in .dSYM bundles have the contents of the loaded
|
||||
// segments removed, and their file offsets and file sizes zeroed
|
||||
// out. To help us handle this special case properly, give such
|
||||
// segments' contents NULL starting and ending pointers.
|
||||
if (file_offset == 0 && file_size == 0) {
|
||||
segment.contents.start = segment.contents.end = NULL;
|
||||
} else {
|
||||
segment.contents.start = buffer_.start + file_offset;
|
||||
segment.contents.end = segment.contents.start + file_size;
|
||||
}
|
||||
// The section list occupies the remainder of this load command's space.
|
||||
segment.section_list.start = cursor.here();
|
||||
segment.section_list.end = command.end;
|
||||
|
||||
if (!handler->SegmentCommand(segment))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case LC_SYMTAB: {
|
||||
uint32_t symoff, nsyms, stroff, strsize;
|
||||
cursor >> symoff >> nsyms >> stroff >> strsize;
|
||||
if (!cursor) {
|
||||
reporter_->LoadCommandTooShort(index, type);
|
||||
return false;
|
||||
}
|
||||
// How big are the entries in the symbol table?
|
||||
// sizeof(struct nlist_64) : sizeof(struct nlist),
|
||||
// but be paranoid about alignment vs. target architecture.
|
||||
size_t symbol_size = bits_64_ ? 16 : 12;
|
||||
// How big is the entire symbol array?
|
||||
size_t symbols_size = nsyms * symbol_size;
|
||||
if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff ||
|
||||
stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) {
|
||||
reporter_->MisplacedSymbolTable();
|
||||
return false;
|
||||
}
|
||||
ByteBuffer entries(buffer_.start + symoff, symbols_size);
|
||||
ByteBuffer names(buffer_.start + stroff, strsize);
|
||||
if (!handler->SymtabCommand(entries, names))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (!handler->UnknownCommand(type, command))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_cursor.set_here(command.end);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// A load command handler that looks for a segment of a given name.
|
||||
class Reader::SegmentFinder : public LoadCommandHandler {
|
||||
public:
|
||||
// Create a load command handler that looks for a segment named NAME,
|
||||
// and sets SEGMENT to describe it if found.
|
||||
SegmentFinder(const string &name, Segment *segment)
|
||||
: name_(name), segment_(segment), found_() { }
|
||||
|
||||
// Return true if the traversal found the segment, false otherwise.
|
||||
bool found() const { return found_; }
|
||||
|
||||
bool SegmentCommand(const Segment &segment) {
|
||||
if (segment.name == name_) {
|
||||
*segment_ = segment;
|
||||
found_ = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// The name of the segment our creator is looking for.
|
||||
const string &name_;
|
||||
|
||||
// Where we should store the segment if found. (WEAK)
|
||||
Segment *segment_;
|
||||
|
||||
// True if we found the segment.
|
||||
bool found_;
|
||||
};
|
||||
|
||||
bool Reader::FindSegment(const string &name, Segment *segment) const {
|
||||
SegmentFinder finder(name, segment);
|
||||
WalkLoadCommands(&finder);
|
||||
return finder.found();
|
||||
}
|
||||
|
||||
bool Reader::WalkSegmentSections(const Segment &segment,
|
||||
SectionHandler *handler) const {
|
||||
size_t word_size = segment.bits_64 ? 8 : 4;
|
||||
ByteCursor cursor(&segment.section_list, big_endian_);
|
||||
|
||||
for (size_t i = 0; i < segment.nsects; i++) {
|
||||
Section section;
|
||||
section.bits_64 = segment.bits_64;
|
||||
uint64_t size;
|
||||
uint32_t offset, dummy32;
|
||||
cursor
|
||||
.CString(§ion.section_name, 16)
|
||||
.CString(§ion.segment_name, 16)
|
||||
.Read(word_size, false, §ion.address)
|
||||
.Read(word_size, false, &size)
|
||||
>> offset
|
||||
>> section.align
|
||||
>> dummy32
|
||||
>> dummy32
|
||||
>> section.flags
|
||||
>> dummy32
|
||||
>> dummy32;
|
||||
if (section.bits_64)
|
||||
cursor >> dummy32;
|
||||
if (!cursor) {
|
||||
reporter_->SectionsMissing(segment.name);
|
||||
return false;
|
||||
}
|
||||
if ((section.flags & SECTION_TYPE) == S_ZEROFILL) {
|
||||
// Zero-fill sections have a size, but no contents.
|
||||
section.contents.start = section.contents.end = NULL;
|
||||
} else if (segment.contents.start == NULL &&
|
||||
segment.contents.end == NULL) {
|
||||
// Mach-O files in .dSYM bundles have the contents of the loaded
|
||||
// segments removed, and their file offsets and file sizes zeroed
|
||||
// out. However, the sections within those segments still have
|
||||
// non-zero sizes. There's no reason to call MisplacedSectionData in
|
||||
// this case; the caller may just need the section's load
|
||||
// address. But do set the contents' limits to NULL, for safety.
|
||||
section.contents.start = section.contents.end = NULL;
|
||||
} else {
|
||||
if (offset < size_t(segment.contents.start - buffer_.start) ||
|
||||
offset > size_t(segment.contents.end - buffer_.start) ||
|
||||
size > size_t(segment.contents.end - buffer_.start - offset)) {
|
||||
reporter_->MisplacedSectionData(section.section_name,
|
||||
section.segment_name);
|
||||
return false;
|
||||
}
|
||||
section.contents.start = buffer_.start + offset;
|
||||
section.contents.end = section.contents.start + size;
|
||||
}
|
||||
if (!handler->HandleSection(section))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// A SectionHandler that builds a SectionMap for the sections within a
|
||||
// given segment.
|
||||
class Reader::SectionMapper: public SectionHandler {
|
||||
public:
|
||||
// Create a SectionHandler that populates MAP with an entry for
|
||||
// each section it is given.
|
||||
SectionMapper(SectionMap *map) : map_(map) { }
|
||||
bool HandleSection(const Section §ion) {
|
||||
(*map_)[section.section_name] = section;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
// The map under construction. (WEAK)
|
||||
SectionMap *map_;
|
||||
};
|
||||
|
||||
bool Reader::MapSegmentSections(const Segment &segment,
|
||||
SectionMap *section_map) const {
|
||||
section_map->clear();
|
||||
SectionMapper mapper(section_map);
|
||||
return WalkSegmentSections(segment, &mapper);
|
||||
}
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace google_breakpad
|
459
thirdparty/breakpad/common/mac/macho_reader.h
vendored
Normal file
459
thirdparty/breakpad/common/mac/macho_reader.h
vendored
Normal file
@@ -0,0 +1,459 @@
|
||||
// -*- mode: C++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// macho_reader.h: A class for parsing Mach-O files.
|
||||
|
||||
#ifndef BREAKPAD_COMMON_MAC_MACHO_READER_H_
|
||||
#define BREAKPAD_COMMON_MAC_MACHO_READER_H_
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/byte_cursor.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace mach_o {
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
// The Mac headers don't specify particular types for these groups of
|
||||
// constants, but defining them here provides some documentation
|
||||
// value. We also give them the same width as the fields in which
|
||||
// they appear, which makes them a bit easier to use with ByteCursors.
|
||||
typedef uint32_t Magic;
|
||||
typedef uint32_t FileType;
|
||||
typedef uint32_t FileFlags;
|
||||
typedef uint32_t LoadCommandType;
|
||||
typedef uint32_t SegmentFlags;
|
||||
typedef uint32_t SectionFlags;
|
||||
|
||||
// A parser for fat binary files, used to store universal binaries.
|
||||
// When applied to a (non-fat) Mach-O file, this behaves as if the
|
||||
// file were a fat file containing a single object file.
|
||||
class FatReader {
|
||||
public:
|
||||
|
||||
// A class for reporting errors found while parsing fat binary files. The
|
||||
// default definitions of these methods print messages to stderr.
|
||||
class Reporter {
|
||||
public:
|
||||
// Create a reporter that attributes problems to |filename|.
|
||||
explicit Reporter(const string &filename) : filename_(filename) { }
|
||||
|
||||
virtual ~Reporter() { }
|
||||
|
||||
// The data does not begin with a fat binary or Mach-O magic number.
|
||||
// This is a fatal error.
|
||||
virtual void BadHeader();
|
||||
|
||||
// The Mach-O fat binary file ends abruptly, without enough space
|
||||
// to contain an object file it claims is present.
|
||||
virtual void MisplacedObjectFile();
|
||||
|
||||
// The file ends abruptly: either it is not large enough to hold a
|
||||
// complete header, or the header implies that contents are present
|
||||
// beyond the actual end of the file.
|
||||
virtual void TooShort();
|
||||
|
||||
private:
|
||||
// The filename to which the reader should attribute problems.
|
||||
string filename_;
|
||||
};
|
||||
|
||||
// Create a fat binary file reader that uses |reporter| to report problems.
|
||||
explicit FatReader(Reporter *reporter) : reporter_(reporter) { }
|
||||
|
||||
// Read the |size| bytes at |buffer| as a fat binary file. On success,
|
||||
// return true; on failure, report the problem to reporter_ and return
|
||||
// false.
|
||||
//
|
||||
// If the data is a plain Mach-O file, rather than a fat binary file,
|
||||
// then the reader behaves as if it had found a fat binary file whose
|
||||
// single object file is the Mach-O file.
|
||||
bool Read(const uint8_t *buffer, size_t size);
|
||||
|
||||
// Return an array of 'struct fat_arch' structures describing the
|
||||
// object files present in this fat binary file. Set |size| to the
|
||||
// number of elements in the array.
|
||||
//
|
||||
// Assuming Read returned true, the entries are validated: it is
|
||||
// safe to assume that the offsets and sizes in each 'struct
|
||||
// fat_arch' refer to subranges of the bytes passed to Read.
|
||||
//
|
||||
// If there are no object files in this fat binary, then this
|
||||
// function can return NULL.
|
||||
//
|
||||
// The array is owned by this FatReader instance; it will be freed when
|
||||
// this FatReader is destroyed.
|
||||
//
|
||||
// This function returns a C-style array instead of a vector to make it
|
||||
// possible to use the result with OS X functions like NXFindBestFatArch,
|
||||
// so that the symbol dumper will behave consistently with other OS X
|
||||
// utilities that work with fat binaries.
|
||||
const struct fat_arch *object_files(size_t *count) const {
|
||||
*count = object_files_.size();
|
||||
if (object_files_.size() > 0)
|
||||
return &object_files_[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
// We use this to report problems parsing the file's contents. (WEAK)
|
||||
Reporter *reporter_;
|
||||
|
||||
// The contents of the fat binary or Mach-O file we're parsing. We do not
|
||||
// own the storage it refers to.
|
||||
ByteBuffer buffer_;
|
||||
|
||||
// The magic number of this binary, in host byte order.
|
||||
Magic magic_;
|
||||
|
||||
// The list of object files in this binary.
|
||||
// object_files_.size() == fat_header.nfat_arch
|
||||
vector<struct fat_arch> object_files_;
|
||||
};
|
||||
|
||||
// A segment in a Mach-O file. All these fields have been byte-swapped as
|
||||
// appropriate for use by the executing architecture.
|
||||
struct Segment {
|
||||
// The ByteBuffers below point into the bytes passed to the Reader that
|
||||
// created this Segment.
|
||||
|
||||
ByteBuffer section_list; // This segment's section list.
|
||||
ByteBuffer contents; // This segment's contents.
|
||||
|
||||
// This segment's name.
|
||||
string name;
|
||||
|
||||
// The address at which this segment should be loaded in memory. If
|
||||
// bits_64 is false, only the bottom 32 bits of this value are valid.
|
||||
uint64_t vmaddr;
|
||||
|
||||
// The size of this segment when loaded into memory. This may be larger
|
||||
// than contents.Size(), in which case the extra area will be
|
||||
// initialized with zeros. If bits_64 is false, only the bottom 32 bits
|
||||
// of this value are valid.
|
||||
uint64_t vmsize;
|
||||
|
||||
// The maximum and initial VM protection of this segment's contents.
|
||||
uint32_t maxprot;
|
||||
uint32_t initprot;
|
||||
|
||||
// The number of sections in section_list.
|
||||
uint32_t nsects;
|
||||
|
||||
// Flags describing this segment, from SegmentFlags.
|
||||
uint32_t flags;
|
||||
|
||||
// True if this is a 64-bit section; false if it is a 32-bit section.
|
||||
bool bits_64;
|
||||
};
|
||||
|
||||
// A section in a Mach-O file. All these fields have been byte-swapped as
|
||||
// appropriate for use by the executing architecture.
|
||||
struct Section {
|
||||
// This section's contents. This points into the bytes passed to the
|
||||
// Reader that created this Section.
|
||||
ByteBuffer contents;
|
||||
|
||||
// This section's name.
|
||||
string section_name; // section[_64].sectname
|
||||
// The name of the segment this section belongs to.
|
||||
string segment_name; // section[_64].segname
|
||||
|
||||
// The address at which this section's contents should be loaded in
|
||||
// memory. If bits_64 is false, only the bottom 32 bits of this value
|
||||
// are valid.
|
||||
uint64_t address;
|
||||
|
||||
// The contents of this section should be loaded into memory at an
|
||||
// address which is a multiple of (two raised to this power).
|
||||
uint32_t align;
|
||||
|
||||
// Flags from SectionFlags describing the section's contents.
|
||||
uint32_t flags;
|
||||
|
||||
// We don't support reading relocations yet.
|
||||
|
||||
// True if this is a 64-bit section; false if it is a 32-bit section.
|
||||
bool bits_64;
|
||||
};
|
||||
|
||||
// A map from section names to Sections.
|
||||
typedef map<string, Section> SectionMap;
|
||||
|
||||
// A reader for a Mach-O file.
|
||||
//
|
||||
// This does not handle fat binaries; see FatReader above. FatReader
|
||||
// provides a friendly interface for parsing data that could be either a
|
||||
// fat binary or a Mach-O file.
|
||||
class Reader {
|
||||
public:
|
||||
|
||||
// A class for reporting errors found while parsing Mach-O files. The
|
||||
// default definitions of these member functions print messages to
|
||||
// stderr.
|
||||
class Reporter {
|
||||
public:
|
||||
// Create a reporter that attributes problems to |filename|.
|
||||
explicit Reporter(const string &filename) : filename_(filename) { }
|
||||
virtual ~Reporter() { }
|
||||
|
||||
// Reporter functions for fatal errors return void; the reader will
|
||||
// definitely return an error to its caller after calling them
|
||||
|
||||
// The data does not begin with a Mach-O magic number, or the magic
|
||||
// number does not match the expected value for the cpu architecture.
|
||||
// This is a fatal error.
|
||||
virtual void BadHeader();
|
||||
|
||||
// The data contained in a Mach-O fat binary (|cpu_type|, |cpu_subtype|)
|
||||
// does not match the expected CPU architecture
|
||||
// (|expected_cpu_type|, |expected_cpu_subtype|).
|
||||
virtual void CPUTypeMismatch(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype);
|
||||
|
||||
// The file ends abruptly: either it is not large enough to hold a
|
||||
// complete header, or the header implies that contents are present
|
||||
// beyond the actual end of the file.
|
||||
virtual void HeaderTruncated();
|
||||
|
||||
// The file's load command region, as given in the Mach-O header, is
|
||||
// too large for the file.
|
||||
virtual void LoadCommandRegionTruncated();
|
||||
|
||||
// The file's Mach-O header claims the file contains |claimed| load
|
||||
// commands, but the I'th load command, of type |type|, extends beyond
|
||||
// the end of the load command region, as given by the Mach-O header.
|
||||
// If |type| is zero, the command's type was unreadable.
|
||||
virtual void LoadCommandsOverrun(size_t claimed, size_t i,
|
||||
LoadCommandType type);
|
||||
|
||||
// The contents of the |i|'th load command, of type |type|, extend beyond
|
||||
// the size given in the load command's header.
|
||||
virtual void LoadCommandTooShort(size_t i, LoadCommandType type);
|
||||
|
||||
// The LC_SEGMENT or LC_SEGMENT_64 load command for the segment named
|
||||
// |name| is too short to hold the sections that its header says it does.
|
||||
// (This more specific than LoadCommandTooShort.)
|
||||
virtual void SectionsMissing(const string &name);
|
||||
|
||||
// The segment named |name| claims that its contents lie beyond the end
|
||||
// of the file.
|
||||
virtual void MisplacedSegmentData(const string &name);
|
||||
|
||||
// The section named |section| in the segment named |segment| claims that
|
||||
// its contents do not lie entirely within the segment.
|
||||
virtual void MisplacedSectionData(const string §ion,
|
||||
const string &segment);
|
||||
|
||||
// The LC_SYMTAB command claims that symbol table contents are located
|
||||
// beyond the end of the file.
|
||||
virtual void MisplacedSymbolTable();
|
||||
|
||||
// An attempt was made to read a Mach-O file of the unsupported
|
||||
// CPU architecture |cpu_type|.
|
||||
virtual void UnsupportedCPUType(cpu_type_t cpu_type);
|
||||
|
||||
private:
|
||||
string filename_;
|
||||
};
|
||||
|
||||
// A handler for sections parsed from a segment. The WalkSegmentSections
|
||||
// member function accepts an instance of this class, and applies it to
|
||||
// each section defined in a given segment.
|
||||
class SectionHandler {
|
||||
public:
|
||||
virtual ~SectionHandler() { }
|
||||
|
||||
// Called to report that the segment's section list contains |section|.
|
||||
// This should return true if the iteration should continue, or false
|
||||
// if it should stop.
|
||||
virtual bool HandleSection(const Section §ion) = 0;
|
||||
};
|
||||
|
||||
// A handler for the load commands in a Mach-O file.
|
||||
class LoadCommandHandler {
|
||||
public:
|
||||
LoadCommandHandler() { }
|
||||
virtual ~LoadCommandHandler() { }
|
||||
|
||||
// When called from WalkLoadCommands, the following handler functions
|
||||
// should return true if they wish to continue iterating over the load
|
||||
// command list, or false if they wish to stop iterating.
|
||||
//
|
||||
// When called from LoadCommandIterator::Handle or Reader::Handle,
|
||||
// these functions' return values are simply passed through to Handle's
|
||||
// caller.
|
||||
//
|
||||
// The definitions provided by this base class simply return true; the
|
||||
// default is to silently ignore sections whose member functions the
|
||||
// subclass doesn't override.
|
||||
|
||||
// COMMAND is load command we don't recognize. We provide only the
|
||||
// command type and a ByteBuffer enclosing the command's data (If we
|
||||
// cannot parse the command type or its size, we call
|
||||
// reporter_->IncompleteLoadCommand instead.)
|
||||
virtual bool UnknownCommand(LoadCommandType type,
|
||||
const ByteBuffer &contents) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The load command is LC_SEGMENT or LC_SEGMENT_64, defining a segment
|
||||
// with the properties given in |segment|.
|
||||
virtual bool SegmentCommand(const Segment &segment) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The load command is LC_SYMTAB. |entries| holds the array of nlist
|
||||
// entries, and |names| holds the strings the entries refer to.
|
||||
virtual bool SymtabCommand(const ByteBuffer &entries,
|
||||
const ByteBuffer &names) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add handler functions for more load commands here as needed.
|
||||
};
|
||||
|
||||
// Create a Mach-O file reader that reports problems to |reporter|.
|
||||
explicit Reader(Reporter *reporter)
|
||||
: reporter_(reporter) { }
|
||||
|
||||
// Read the given data as a Mach-O file. The reader retains pointers
|
||||
// into the data passed, so the data should live as long as the reader
|
||||
// does. On success, return true; on failure, return false.
|
||||
//
|
||||
// At most one of these functions should be invoked once on each Reader
|
||||
// instance.
|
||||
bool Read(const uint8_t *buffer,
|
||||
size_t size,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype);
|
||||
bool Read(const ByteBuffer &buffer,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype) {
|
||||
return Read(buffer.start,
|
||||
buffer.Size(),
|
||||
expected_cpu_type,
|
||||
expected_cpu_subtype);
|
||||
}
|
||||
|
||||
// Return this file's characteristics, as found in the Mach-O header.
|
||||
cpu_type_t cpu_type() const { return cpu_type_; }
|
||||
cpu_subtype_t cpu_subtype() const { return cpu_subtype_; }
|
||||
FileType file_type() const { return file_type_; }
|
||||
FileFlags flags() const { return flags_; }
|
||||
|
||||
// Return true if this is a 64-bit Mach-O file, false if it is a 32-bit
|
||||
// Mach-O file.
|
||||
bool bits_64() const { return bits_64_; }
|
||||
|
||||
// Return true if this is a big-endian Mach-O file, false if it is
|
||||
// little-endian.
|
||||
bool big_endian() const { return big_endian_; }
|
||||
|
||||
// Apply |handler| to each load command in this Mach-O file, stopping when
|
||||
// a handler function returns false. If we encounter a malformed load
|
||||
// command, report it via reporter_ and return false. Return true if all
|
||||
// load commands were parseable and all handlers returned true.
|
||||
bool WalkLoadCommands(LoadCommandHandler *handler) const;
|
||||
|
||||
// Set |segment| to describe the segment named |name|, if present. If
|
||||
// found, |segment|'s byte buffers refer to a subregion of the bytes
|
||||
// passed to Read. If we find the section, return true; otherwise,
|
||||
// return false.
|
||||
bool FindSegment(const string &name, Segment *segment) const;
|
||||
|
||||
// Apply |handler| to each section defined in |segment|. If |handler| returns
|
||||
// false, stop iterating and return false. If all calls to |handler| return
|
||||
// true and we reach the end of the section list, return true.
|
||||
bool WalkSegmentSections(const Segment &segment, SectionHandler *handler)
|
||||
const;
|
||||
|
||||
// Clear |section_map| and then populate it with a map of the sections
|
||||
// in |segment|, from section names to Section structures.
|
||||
// Each Section's contents refer to bytes in |segment|'s contents.
|
||||
// On success, return true; if a problem occurs, report it and return false.
|
||||
bool MapSegmentSections(const Segment &segment, SectionMap *section_map)
|
||||
const;
|
||||
|
||||
private:
|
||||
// Used internally.
|
||||
class SegmentFinder;
|
||||
class SectionMapper;
|
||||
|
||||
// We use this to report problems parsing the file's contents. (WEAK)
|
||||
Reporter *reporter_;
|
||||
|
||||
// The contents of the Mach-O file we're parsing. We do not own the
|
||||
// storage it refers to.
|
||||
ByteBuffer buffer_;
|
||||
|
||||
// True if this file is big-endian.
|
||||
bool big_endian_;
|
||||
|
||||
// True if this file is a 64-bit Mach-O file.
|
||||
bool bits_64_;
|
||||
|
||||
// This file's cpu type and subtype.
|
||||
cpu_type_t cpu_type_; // mach_header[_64].cputype
|
||||
cpu_subtype_t cpu_subtype_; // mach_header[_64].cpusubtype
|
||||
|
||||
// This file's type.
|
||||
FileType file_type_; // mach_header[_64].filetype
|
||||
|
||||
// The region of buffer_ occupied by load commands.
|
||||
ByteBuffer load_commands_;
|
||||
|
||||
// The number of load commands in load_commands_.
|
||||
uint32_t load_command_count_; // mach_header[_64].ncmds
|
||||
|
||||
// This file's header flags.
|
||||
FileFlags flags_;
|
||||
};
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // BREAKPAD_COMMON_MAC_MACHO_READER_H_
|
1898
thirdparty/breakpad/common/mac/macho_reader_unittest.cc
vendored
Normal file
1898
thirdparty/breakpad/common/mac/macho_reader_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
90
thirdparty/breakpad/common/mac/macho_utilities.cc
vendored
Normal file
90
thirdparty/breakpad/common/mac/macho_utilities.cc
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// macho_utilties.cc: Utilities for dealing with mach-o files
|
||||
//
|
||||
// Author: Dave Camp
|
||||
|
||||
#include "common/mac/byteswap.h"
|
||||
#include "common/mac/macho_utilities.h"
|
||||
|
||||
void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc,
|
||||
enum NXByteOrder target_byte_order)
|
||||
{
|
||||
uc->cmd = ByteSwap(uc->cmd);
|
||||
uc->cmdsize = ByteSwap(uc->cmdsize);
|
||||
}
|
||||
|
||||
void breakpad_swap_segment_command_64(struct segment_command_64 *sg,
|
||||
enum NXByteOrder target_byte_order)
|
||||
{
|
||||
sg->cmd = ByteSwap(sg->cmd);
|
||||
sg->cmdsize = ByteSwap(sg->cmdsize);
|
||||
|
||||
sg->vmaddr = ByteSwap(sg->vmaddr);
|
||||
sg->vmsize = ByteSwap(sg->vmsize);
|
||||
sg->fileoff = ByteSwap(sg->fileoff);
|
||||
sg->filesize = ByteSwap(sg->filesize);
|
||||
|
||||
sg->maxprot = ByteSwap(sg->maxprot);
|
||||
sg->initprot = ByteSwap(sg->initprot);
|
||||
sg->nsects = ByteSwap(sg->nsects);
|
||||
sg->flags = ByteSwap(sg->flags);
|
||||
}
|
||||
|
||||
void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
|
||||
enum NXByteOrder target_byte_order)
|
||||
{
|
||||
mh->magic = ByteSwap(mh->magic);
|
||||
mh->cputype = ByteSwap(mh->cputype);
|
||||
mh->cpusubtype = ByteSwap(mh->cpusubtype);
|
||||
mh->filetype = ByteSwap(mh->filetype);
|
||||
mh->ncmds = ByteSwap(mh->ncmds);
|
||||
mh->sizeofcmds = ByteSwap(mh->sizeofcmds);
|
||||
mh->flags = ByteSwap(mh->flags);
|
||||
mh->reserved = ByteSwap(mh->reserved);
|
||||
}
|
||||
|
||||
void breakpad_swap_section_64(struct section_64 *s,
|
||||
uint32_t nsects,
|
||||
enum NXByteOrder target_byte_order)
|
||||
{
|
||||
for (uint32_t i = 0; i < nsects; i++) {
|
||||
s[i].addr = ByteSwap(s[i].addr);
|
||||
s[i].size = ByteSwap(s[i].size);
|
||||
|
||||
s[i].offset = ByteSwap(s[i].offset);
|
||||
s[i].align = ByteSwap(s[i].align);
|
||||
s[i].reloff = ByteSwap(s[i].reloff);
|
||||
s[i].nreloc = ByteSwap(s[i].nreloc);
|
||||
s[i].flags = ByteSwap(s[i].flags);
|
||||
s[i].reserved1 = ByteSwap(s[i].reserved1);
|
||||
s[i].reserved2 = ByteSwap(s[i].reserved2);
|
||||
}
|
||||
}
|
92
thirdparty/breakpad/common/mac/macho_utilities.h
vendored
Normal file
92
thirdparty/breakpad/common/mac/macho_utilities.h
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// macho_utilities.h: Utilities for dealing with mach-o files
|
||||
//
|
||||
// Author: Dave Camp
|
||||
|
||||
#ifndef COMMON_MAC_MACHO_UTILITIES_H__
|
||||
#define COMMON_MAC_MACHO_UTILITIES_H__
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach/thread_status.h>
|
||||
|
||||
/* Some #defines and structs that aren't defined in older SDKs */
|
||||
#ifndef CPU_ARCH_ABI64
|
||||
# define CPU_ARCH_ABI64 0x01000000
|
||||
#endif
|
||||
|
||||
#ifndef CPU_TYPE_X86
|
||||
# define CPU_TYPE_X86 CPU_TYPE_I386
|
||||
#endif
|
||||
|
||||
#ifndef CPU_TYPE_POWERPC64
|
||||
# define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
|
||||
#endif
|
||||
|
||||
#ifndef LC_UUID
|
||||
# define LC_UUID 0x1b /* the uuid */
|
||||
#endif
|
||||
|
||||
#if TARGET_CPU_X86
|
||||
# define BREAKPAD_MACHINE_THREAD_STATE i386_THREAD_STATE
|
||||
#elif TARGET_CPU_X86_64
|
||||
# define BREAKPAD_MACHINE_THREAD_STATE x86_THREAD_STATE64
|
||||
#else
|
||||
# define BREAKPAD_MACHINE_THREAD_STATE MACHINE_THREAD_STATE
|
||||
#endif
|
||||
|
||||
// The uuid_command struct/swap routines were added during the 10.4 series.
|
||||
// Their presence isn't guaranteed.
|
||||
struct breakpad_uuid_command {
|
||||
uint32_t cmd; /* LC_UUID */
|
||||
uint32_t cmdsize; /* sizeof(struct uuid_command) */
|
||||
uint8_t uuid[16]; /* the 128-bit uuid */
|
||||
};
|
||||
|
||||
void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
// Older SDKs defines thread_state_data_t as an int[] instead
|
||||
// of the natural_t[] it should be.
|
||||
typedef natural_t breakpad_thread_state_data_t[THREAD_STATE_MAX];
|
||||
|
||||
// The 64-bit swap routines were added during the 10.4 series, their
|
||||
// presence isn't guaranteed.
|
||||
void breakpad_swap_segment_command_64(struct segment_command_64 *sg,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
void breakpad_swap_section_64(struct section_64 *s,
|
||||
uint32_t nsects,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
#endif
|
239
thirdparty/breakpad/common/mac/macho_walker.cc
vendored
Normal file
239
thirdparty/breakpad/common/mac/macho_walker.cc
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// macho_walker.cc: Iterate over the load commands in a mach-o file
|
||||
//
|
||||
// See macho_walker.h for documentation
|
||||
//
|
||||
// Author: Dan Waylonis
|
||||
|
||||
extern "C" { // necessary for Leopard
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <mach-o/arch.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/swap.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include "common/mac/byteswap.h"
|
||||
#include "common/mac/macho_walker.h"
|
||||
#include "common/mac/macho_utilities.h"
|
||||
|
||||
namespace MacFileUtilities {
|
||||
|
||||
MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
|
||||
void *context)
|
||||
: file_(0),
|
||||
callback_(callback),
|
||||
callback_context_(context),
|
||||
current_header_(NULL),
|
||||
current_header_size_(0),
|
||||
current_header_offset_(0) {
|
||||
file_ = open(path, O_RDONLY);
|
||||
}
|
||||
|
||||
MachoWalker::~MachoWalker() {
|
||||
if (file_ != -1)
|
||||
close(file_);
|
||||
}
|
||||
|
||||
int MachoWalker::ValidateCPUType(int cpu_type) {
|
||||
// If the user didn't specify, use the local architecture.
|
||||
if (cpu_type == 0) {
|
||||
const NXArchInfo *arch = NXGetLocalArchInfo();
|
||||
assert(arch);
|
||||
cpu_type = arch->cputype;
|
||||
}
|
||||
|
||||
return cpu_type;
|
||||
}
|
||||
|
||||
bool MachoWalker::WalkHeader(int cpu_type) {
|
||||
int valid_cpu_type = ValidateCPUType(cpu_type);
|
||||
off_t offset;
|
||||
if (FindHeader(valid_cpu_type, offset)) {
|
||||
if (cpu_type & CPU_ARCH_ABI64)
|
||||
return WalkHeader64AtOffset(offset);
|
||||
|
||||
return WalkHeaderAtOffset(offset);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
|
||||
return pread(file_, buffer, size, offset) == (ssize_t)size;
|
||||
}
|
||||
|
||||
bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
|
||||
if (current_header_) {
|
||||
memcpy(header, current_header_, sizeof(mach_header_64));
|
||||
*offset = current_header_offset_;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
|
||||
int valid_cpu_type = ValidateCPUType(cpu_type);
|
||||
// Read the magic bytes that's common amongst all mach-o files
|
||||
uint32_t magic;
|
||||
if (!ReadBytes(&magic, sizeof(magic), 0))
|
||||
return false;
|
||||
|
||||
offset = sizeof(magic);
|
||||
|
||||
// Figure out what type of file we've got
|
||||
bool is_fat = false;
|
||||
if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
|
||||
is_fat = true;
|
||||
}
|
||||
else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
|
||||
magic != MH_CIGAM_64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_fat) {
|
||||
// If we don't have a fat header, check if the cpu type matches the single
|
||||
// header
|
||||
cpu_type_t header_cpu_type;
|
||||
if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
|
||||
return false;
|
||||
|
||||
if (magic == MH_CIGAM || magic == MH_CIGAM_64)
|
||||
header_cpu_type = ByteSwap(header_cpu_type);
|
||||
|
||||
if (valid_cpu_type != header_cpu_type)
|
||||
return false;
|
||||
|
||||
offset = 0;
|
||||
return true;
|
||||
} else {
|
||||
// Read the fat header and find an appropriate architecture
|
||||
offset = 0;
|
||||
struct fat_header fat;
|
||||
if (!ReadBytes(&fat, sizeof(fat), offset))
|
||||
return false;
|
||||
|
||||
if (NXHostByteOrder() != NX_BigEndian)
|
||||
swap_fat_header(&fat, NXHostByteOrder());
|
||||
|
||||
offset += sizeof(fat);
|
||||
|
||||
// Search each architecture for the desired one
|
||||
struct fat_arch arch;
|
||||
for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
|
||||
if (!ReadBytes(&arch, sizeof(arch), offset))
|
||||
return false;
|
||||
|
||||
if (NXHostByteOrder() != NX_BigEndian)
|
||||
swap_fat_arch(&arch, 1, NXHostByteOrder());
|
||||
|
||||
if (arch.cputype == valid_cpu_type) {
|
||||
offset = arch.offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
offset += sizeof(arch);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
|
||||
struct mach_header header;
|
||||
if (!ReadBytes(&header, sizeof(header), offset))
|
||||
return false;
|
||||
|
||||
bool swap = (header.magic == MH_CIGAM);
|
||||
if (swap)
|
||||
swap_mach_header(&header, NXHostByteOrder());
|
||||
|
||||
// Copy the data into the mach_header_64 structure. Since the 32-bit and
|
||||
// 64-bit only differ in the last field (reserved), this is safe to do.
|
||||
struct mach_header_64 header64;
|
||||
memcpy((void *)&header64, (const void *)&header, sizeof(header));
|
||||
header64.reserved = 0;
|
||||
|
||||
current_header_ = &header64;
|
||||
current_header_size_ = sizeof(header); // 32-bit, not 64-bit
|
||||
current_header_offset_ = offset;
|
||||
offset += current_header_size_;
|
||||
bool result = WalkHeaderCore(offset, header.ncmds, swap);
|
||||
current_header_ = NULL;
|
||||
current_header_size_ = 0;
|
||||
current_header_offset_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
|
||||
struct mach_header_64 header;
|
||||
if (!ReadBytes(&header, sizeof(header), offset))
|
||||
return false;
|
||||
|
||||
bool swap = (header.magic == MH_CIGAM_64);
|
||||
if (swap)
|
||||
breakpad_swap_mach_header_64(&header, NXHostByteOrder());
|
||||
|
||||
current_header_ = &header;
|
||||
current_header_size_ = sizeof(header);
|
||||
current_header_offset_ = offset;
|
||||
offset += current_header_size_;
|
||||
bool result = WalkHeaderCore(offset, header.ncmds, swap);
|
||||
current_header_ = NULL;
|
||||
current_header_size_ = 0;
|
||||
current_header_offset_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
|
||||
bool swap) {
|
||||
for (uint32_t i = 0; i < number_of_commands; ++i) {
|
||||
struct load_command cmd;
|
||||
if (!ReadBytes(&cmd, sizeof(cmd), offset))
|
||||
return false;
|
||||
|
||||
if (swap)
|
||||
swap_load_command(&cmd, NXHostByteOrder());
|
||||
|
||||
// Call the user callback
|
||||
if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
|
||||
break;
|
||||
|
||||
offset += cmd.cmdsize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace MacFileUtilities
|
110
thirdparty/breakpad/common/mac/macho_walker.h
vendored
Normal file
110
thirdparty/breakpad/common/mac/macho_walker.h
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// macho_walker.h: Iterate over the load commands in a mach-o file
|
||||
//
|
||||
// Author: Dan Waylonis
|
||||
|
||||
#ifndef COMMON_MAC_MACHO_WALKER_H__
|
||||
#define COMMON_MAC_MACHO_WALKER_H__
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace MacFileUtilities {
|
||||
|
||||
class MachoWalker {
|
||||
public:
|
||||
// A callback function executed when a new load command is read. If no
|
||||
// further processing of load commands is desired, return false. Otherwise,
|
||||
// return true.
|
||||
// |cmd| is the current command, and |offset| is the location relative to the
|
||||
// beginning of the file (not header) where the command was read. If |swap|
|
||||
// is set, then any command data (other than the returned load_command) should
|
||||
// be swapped when read
|
||||
typedef bool (*LoadCommandCallback)(MachoWalker *walker, load_command *cmd,
|
||||
off_t offset, bool swap, void *context);
|
||||
|
||||
MachoWalker(const char *path, LoadCommandCallback callback, void *context);
|
||||
MachoWalker(int file_descriptor, LoadCommandCallback callback, void *context);
|
||||
~MachoWalker();
|
||||
|
||||
// Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the
|
||||
// native cpu type is used. Otherwise, accepted values are listed in
|
||||
// /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC).
|
||||
// Returns false if opening the file failed or if the |cpu_type| is not
|
||||
// present in the file.
|
||||
bool WalkHeader(int cpu_type);
|
||||
|
||||
// Locate (if any) the header offset for |cpu_type| and return in |offset|.
|
||||
// Return true if found, false otherwise.
|
||||
bool FindHeader(int cpu_type, off_t &offset);
|
||||
|
||||
// Read |size| bytes from the opened file at |offset| into |buffer|
|
||||
bool ReadBytes(void *buffer, size_t size, off_t offset);
|
||||
|
||||
// Return the current header and header offset
|
||||
bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
|
||||
|
||||
private:
|
||||
// Validate the |cpu_type|
|
||||
int ValidateCPUType(int cpu_type);
|
||||
|
||||
// Process an individual header starting at |offset| from the start of the
|
||||
// file. Return true if successful, false otherwise.
|
||||
bool WalkHeaderAtOffset(off_t offset);
|
||||
bool WalkHeader64AtOffset(off_t offset);
|
||||
|
||||
// Bottleneck for walking the load commands
|
||||
bool WalkHeaderCore(off_t offset, uint32_t number_of_commands, bool swap);
|
||||
|
||||
// File descriptor to the opened file
|
||||
int file_;
|
||||
|
||||
// User specified callback & context
|
||||
LoadCommandCallback callback_;
|
||||
void *callback_context_;
|
||||
|
||||
// Current header, size, and offset. The mach_header_64 is used for both
|
||||
// 32-bit and 64-bit headers because they only differ in their last field
|
||||
// (reserved). By adding the |current_header_size_| and the
|
||||
// |current_header_offset_|, you can determine the offset in the file just
|
||||
// after the header.
|
||||
struct mach_header_64 *current_header_;
|
||||
unsigned long current_header_size_;
|
||||
off_t current_header_offset_;
|
||||
|
||||
private:
|
||||
MachoWalker(const MachoWalker &);
|
||||
MachoWalker &operator=(const MachoWalker &);
|
||||
};
|
||||
|
||||
} // namespace MacFileUtilities
|
||||
|
||||
#endif // COMMON_MAC_MACHO_WALKER_H__
|
56
thirdparty/breakpad/common/mac/scoped_task_suspend-inl.h
vendored
Normal file
56
thirdparty/breakpad/common/mac/scoped_task_suspend-inl.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Inline implementation of ScopedTaskSuspend, which suspends a Mach
|
||||
// task for the duration of its scope.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_
|
||||
#define GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class ScopedTaskSuspend {
|
||||
public:
|
||||
explicit ScopedTaskSuspend(mach_port_t target) : target_(target) {
|
||||
task_suspend(target_);
|
||||
}
|
||||
|
||||
~ScopedTaskSuspend() {
|
||||
task_resume(target_);
|
||||
}
|
||||
|
||||
private:
|
||||
mach_port_t target_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_
|
84
thirdparty/breakpad/common/mac/string_utilities.cc
vendored
Normal file
84
thirdparty/breakpad/common/mac/string_utilities.cc
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "processor/scoped_ptr.h"
|
||||
#include "common/mac/string_utilities.h"
|
||||
|
||||
namespace MacStringUtils {
|
||||
|
||||
using google_breakpad::scoped_array;
|
||||
|
||||
std::string ConvertToString(CFStringRef str) {
|
||||
CFIndex length = CFStringGetLength(str);
|
||||
std::string result;
|
||||
|
||||
if (!length)
|
||||
return result;
|
||||
|
||||
CFIndex maxUTF8Length =
|
||||
CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
|
||||
scoped_array<UInt8> buffer(new UInt8[maxUTF8Length + 1]);
|
||||
CFIndex actualUTF8Length;
|
||||
CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, 0,
|
||||
false, buffer.get(), maxUTF8Length, &actualUTF8Length);
|
||||
buffer[actualUTF8Length] = 0;
|
||||
result.assign((const char *)buffer.get());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int IntegerValueAtIndex(string &str, unsigned int idx) {
|
||||
string digits("0123456789"), temp;
|
||||
size_t start = 0;
|
||||
size_t end;
|
||||
size_t found = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
for (; found <= idx; ++found) {
|
||||
end = str.find_first_not_of(digits, start);
|
||||
|
||||
if (end == string::npos)
|
||||
end = str.size();
|
||||
|
||||
temp = str.substr(start, end - start);
|
||||
|
||||
if (found == idx) {
|
||||
result = atoi(temp.c_str());
|
||||
}
|
||||
|
||||
start = str.find_first_of(digits, end + 1);
|
||||
|
||||
if (start == string::npos)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace MacStringUtils
|
52
thirdparty/breakpad/common/mac/string_utilities.h
vendored
Normal file
52
thirdparty/breakpad/common/mac/string_utilities.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// string_utilities.h: Utilities for strings for Mac platform
|
||||
|
||||
#ifndef COMMON_MAC_STRING_UTILITIES_H__
|
||||
#define COMMON_MAC_STRING_UTILITIES_H__
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace MacStringUtils {
|
||||
|
||||
using std::string;
|
||||
|
||||
// Convert a CoreFoundation string into a std::string
|
||||
string ConvertToString(CFStringRef str);
|
||||
|
||||
// Return the idx'th decimal integer in str, separated by non-decimal-digits
|
||||
// E.g., str = 10.4.8, idx = 1 -> 4
|
||||
unsigned int IntegerValueAtIndex(string &str, unsigned int idx);
|
||||
|
||||
} // namespace MacStringUtils
|
||||
|
||||
#endif // COMMON_MAC_STRING_UTILITIES_H__
|
1004
thirdparty/breakpad/common/mac/testing/GTMSenTestCase.h
vendored
Normal file
1004
thirdparty/breakpad/common/mac/testing/GTMSenTestCase.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
366
thirdparty/breakpad/common/mac/testing/GTMSenTestCase.m
vendored
Normal file
366
thirdparty/breakpad/common/mac/testing/GTMSenTestCase.m
vendored
Normal file
@@ -0,0 +1,366 @@
|
||||
//
|
||||
// GTMSenTestCase.m
|
||||
//
|
||||
// Copyright 2007-2008 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy
|
||||
// of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
//
|
||||
|
||||
#import "GTMSenTestCase.h"
|
||||
#import <unistd.h>
|
||||
|
||||
#if !GTM_IPHONE_SDK
|
||||
#import "GTMGarbageCollection.h"
|
||||
#endif // !GTM_IPHONE_SDK
|
||||
|
||||
#if GTM_IPHONE_SDK
|
||||
#import <stdarg.h>
|
||||
|
||||
@interface NSException (GTMSenTestPrivateAdditions)
|
||||
+ (NSException *)failureInFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
reason:(NSString *)reason;
|
||||
@end
|
||||
|
||||
@implementation NSException (GTMSenTestPrivateAdditions)
|
||||
+ (NSException *)failureInFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
reason:(NSString *)reason {
|
||||
NSDictionary *userInfo =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInteger:lineNumber], SenTestLineNumberKey,
|
||||
filename, SenTestFilenameKey,
|
||||
nil];
|
||||
|
||||
return [self exceptionWithName:SenTestFailureException
|
||||
reason:reason
|
||||
userInfo:userInfo];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSException (GTMSenTestAdditions)
|
||||
|
||||
+ (NSException *)failureInFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
withDescription:(NSString *)formatString, ... {
|
||||
|
||||
NSString *testDescription = @"";
|
||||
if (formatString) {
|
||||
va_list vl;
|
||||
va_start(vl, formatString);
|
||||
testDescription =
|
||||
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
NSString *reason = testDescription;
|
||||
|
||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||
}
|
||||
|
||||
+ (NSException *)failureInCondition:(NSString *)condition
|
||||
isTrue:(BOOL)isTrue
|
||||
inFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
withDescription:(NSString *)formatString, ... {
|
||||
|
||||
NSString *testDescription = @"";
|
||||
if (formatString) {
|
||||
va_list vl;
|
||||
va_start(vl, formatString);
|
||||
testDescription =
|
||||
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@",
|
||||
condition, isTrue ? "TRUE" : "FALSE", testDescription];
|
||||
|
||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||
}
|
||||
|
||||
+ (NSException *)failureInEqualityBetweenObject:(id)left
|
||||
andObject:(id)right
|
||||
inFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
withDescription:(NSString *)formatString, ... {
|
||||
|
||||
NSString *testDescription = @"";
|
||||
if (formatString) {
|
||||
va_list vl;
|
||||
va_start(vl, formatString);
|
||||
testDescription =
|
||||
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
NSString *reason =
|
||||
[NSString stringWithFormat:@"'%@' should be equal to '%@'. %@",
|
||||
[left description], [right description], testDescription];
|
||||
|
||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||
}
|
||||
|
||||
+ (NSException *)failureInEqualityBetweenValue:(NSValue *)left
|
||||
andValue:(NSValue *)right
|
||||
withAccuracy:(NSValue *)accuracy
|
||||
inFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
withDescription:(NSString *)formatString, ... {
|
||||
|
||||
NSString *testDescription = @"";
|
||||
if (formatString) {
|
||||
va_list vl;
|
||||
va_start(vl, formatString);
|
||||
testDescription =
|
||||
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
NSString *reason;
|
||||
if (accuracy) {
|
||||
reason =
|
||||
[NSString stringWithFormat:@"'%@' should be equal to '%@'. %@",
|
||||
left, right, testDescription];
|
||||
} else {
|
||||
reason =
|
||||
[NSString stringWithFormat:@"'%@' should be equal to '%@' +/-'%@'. %@",
|
||||
left, right, accuracy, testDescription];
|
||||
}
|
||||
|
||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||
}
|
||||
|
||||
+ (NSException *)failureInRaise:(NSString *)expression
|
||||
inFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
withDescription:(NSString *)formatString, ... {
|
||||
|
||||
NSString *testDescription = @"";
|
||||
if (formatString) {
|
||||
va_list vl;
|
||||
va_start(vl, formatString);
|
||||
testDescription =
|
||||
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
NSString *reason = [NSString stringWithFormat:@"'%@' should raise. %@",
|
||||
expression, testDescription];
|
||||
|
||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||
}
|
||||
|
||||
+ (NSException *)failureInRaise:(NSString *)expression
|
||||
exception:(NSException *)exception
|
||||
inFile:(NSString *)filename
|
||||
atLine:(int)lineNumber
|
||||
withDescription:(NSString *)formatString, ... {
|
||||
|
||||
NSString *testDescription = @"";
|
||||
if (formatString) {
|
||||
va_list vl;
|
||||
va_start(vl, formatString);
|
||||
testDescription =
|
||||
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
NSString *reason;
|
||||
if ([[exception name] isEqualToString:SenTestFailureException]) {
|
||||
// it's our exception, assume it has the right description on it.
|
||||
reason = [exception reason];
|
||||
} else {
|
||||
// not one of our exception, use the exceptions reason and our description
|
||||
reason = [NSString stringWithFormat:@"'%@' raised '%@'. %@",
|
||||
expression, [exception reason], testDescription];
|
||||
}
|
||||
|
||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NSString *STComposeString(NSString *formatString, ...) {
|
||||
NSString *reason = @"";
|
||||
if (formatString) {
|
||||
va_list vl;
|
||||
va_start(vl, formatString);
|
||||
reason =
|
||||
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
|
||||
va_end(vl);
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
NSString *const SenTestFailureException = @"SenTestFailureException";
|
||||
NSString *const SenTestFilenameKey = @"SenTestFilenameKey";
|
||||
NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||
|
||||
@interface SenTestCase (SenTestCasePrivate)
|
||||
// our method of logging errors
|
||||
+ (void)printException:(NSException *)exception fromTestName:(NSString *)name;
|
||||
@end
|
||||
|
||||
@implementation SenTestCase
|
||||
- (void)failWithException:(NSException*)exception {
|
||||
[exception raise];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
}
|
||||
|
||||
- (void)performTest:(SEL)sel {
|
||||
currentSelector_ = sel;
|
||||
@try {
|
||||
[self invokeTest];
|
||||
} @catch (NSException *exception) {
|
||||
[[self class] printException:exception
|
||||
fromTestName:NSStringFromSelector(sel)];
|
||||
[exception raise];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)printException:(NSException *)exception fromTestName:(NSString *)name {
|
||||
NSDictionary *userInfo = [exception userInfo];
|
||||
NSString *filename = [userInfo objectForKey:SenTestFilenameKey];
|
||||
NSNumber *lineNumber = [userInfo objectForKey:SenTestLineNumberKey];
|
||||
NSString *className = NSStringFromClass([self class]);
|
||||
if ([filename length] == 0) {
|
||||
filename = @"Unknown.m";
|
||||
}
|
||||
fprintf(stderr, "%s:%ld: error: -[%s %s] : %s\n",
|
||||
[filename UTF8String],
|
||||
(long)[lineNumber integerValue],
|
||||
[className UTF8String],
|
||||
[name UTF8String],
|
||||
[[exception reason] UTF8String]);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
- (void)invokeTest {
|
||||
NSException *e = nil;
|
||||
@try {
|
||||
// Wrap things in autorelease pools because they may
|
||||
// have an STMacro in their dealloc which may get called
|
||||
// when the pool is cleaned up
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
// We don't log exceptions here, instead we let the person that called
|
||||
// this log the exception. This ensures they are only logged once but the
|
||||
// outer layers get the exceptions to report counts, etc.
|
||||
@try {
|
||||
[self setUp];
|
||||
@try {
|
||||
[self performSelector:currentSelector_];
|
||||
} @catch (NSException *exception) {
|
||||
e = [exception retain];
|
||||
}
|
||||
[self tearDown];
|
||||
} @catch (NSException *exception) {
|
||||
e = [exception retain];
|
||||
}
|
||||
[pool release];
|
||||
} @catch (NSException *exception) {
|
||||
e = [exception retain];
|
||||
}
|
||||
if (e) {
|
||||
[e autorelease];
|
||||
[e raise];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
// This matches the description OCUnit would return to you
|
||||
return [NSString stringWithFormat:@"-[%@ %@]", [self class],
|
||||
NSStringFromSelector(currentSelector_)];
|
||||
}
|
||||
@end
|
||||
|
||||
#endif // GTM_IPHONE_SDK
|
||||
|
||||
@implementation GTMTestCase : SenTestCase
|
||||
- (void)invokeTest {
|
||||
Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog");
|
||||
if (devLogClass) {
|
||||
[devLogClass performSelector:@selector(enableTracking)];
|
||||
[devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
|
||||
|
||||
}
|
||||
[super invokeTest];
|
||||
if (devLogClass) {
|
||||
[devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
|
||||
[devLogClass performSelector:@selector(disableTracking)];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
// Leak detection
|
||||
#if !GTM_IPHONE_DEVICE
|
||||
// Don't want to get leaks on the iPhone Device as the device doesn't
|
||||
// have 'leaks'. The simulator does though.
|
||||
|
||||
// COV_NF_START
|
||||
// We don't have leak checking on by default, so this won't be hit.
|
||||
static void _GTMRunLeaks(void) {
|
||||
// This is an atexit handler. It runs leaks for us to check if we are
|
||||
// leaking anything in our tests.
|
||||
const char* cExclusionsEnv = getenv("GTM_LEAKS_SYMBOLS_TO_IGNORE");
|
||||
NSMutableString *exclusions = [NSMutableString string];
|
||||
if (cExclusionsEnv) {
|
||||
NSString *exclusionsEnv = [NSString stringWithUTF8String:cExclusionsEnv];
|
||||
NSArray *exclusionsArray = [exclusionsEnv componentsSeparatedByString:@","];
|
||||
NSString *exclusion;
|
||||
NSCharacterSet *wcSet = [NSCharacterSet whitespaceCharacterSet];
|
||||
GTM_FOREACH_OBJECT(exclusion, exclusionsArray) {
|
||||
exclusion = [exclusion stringByTrimmingCharactersInSet:wcSet];
|
||||
[exclusions appendFormat:@"-exclude \"%@\" ", exclusion];
|
||||
}
|
||||
}
|
||||
NSString *string
|
||||
= [NSString stringWithFormat:@"/usr/bin/leaks %@%d"
|
||||
@"| /usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'",
|
||||
exclusions, getpid()];
|
||||
int ret = system([string UTF8String]);
|
||||
if (ret) {
|
||||
fprintf(stderr, "%s:%d: Error: Unable to run leaks. 'system' returned: %d",
|
||||
__FILE__, __LINE__, ret);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
// COV_NF_END
|
||||
|
||||
static __attribute__((constructor)) void _GTMInstallLeaks(void) {
|
||||
BOOL checkLeaks = YES;
|
||||
#if !GTM_IPHONE_SDK
|
||||
checkLeaks = GTMIsGarbageCollectionEnabled() ? NO : YES;
|
||||
#endif // !GTM_IPHONE_SDK
|
||||
if (checkLeaks) {
|
||||
checkLeaks = getenv("GTM_ENABLE_LEAKS") ? YES : NO;
|
||||
if (checkLeaks) {
|
||||
// COV_NF_START
|
||||
// We don't have leak checking on by default, so this won't be hit.
|
||||
fprintf(stderr, "Leak Checking Enabled\n");
|
||||
fflush(stderr);
|
||||
int ret = atexit(&_GTMRunLeaks);
|
||||
_GTMDevAssert(ret == 0,
|
||||
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
|
||||
errno);
|
||||
// COV_NF_END
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !GTM_IPHONE_DEVICE
|
Reference in New Issue
Block a user