diff options
Diffstat (limited to 'security/sandbox/chromium/base/debug')
-rw-r--r-- | security/sandbox/chromium/base/debug/alias.cc | 23 | ||||
-rw-r--r-- | security/sandbox/chromium/base/debug/alias.h | 21 | ||||
-rw-r--r-- | security/sandbox/chromium/base/debug/debugger.h | 44 | ||||
-rw-r--r-- | security/sandbox/chromium/base/debug/leak_annotations.h | 46 | ||||
-rw-r--r-- | security/sandbox/chromium/base/debug/profiler.cc | 221 | ||||
-rw-r--r-- | security/sandbox/chromium/base/debug/profiler.h | 91 |
6 files changed, 446 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/debug/alias.cc b/security/sandbox/chromium/base/debug/alias.cc new file mode 100644 index 000000000..6b0caaa6d --- /dev/null +++ b/security/sandbox/chromium/base/debug/alias.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/debug/alias.h" +#include "build/build_config.h" + +namespace base { +namespace debug { + +#if defined(COMPILER_MSVC) +#pragma optimize("", off) +#endif + +void Alias(const void* var) { +} + +#if defined(COMPILER_MSVC) +#pragma optimize("", on) +#endif + +} // namespace debug +} // namespace base diff --git a/security/sandbox/chromium/base/debug/alias.h b/security/sandbox/chromium/base/debug/alias.h new file mode 100644 index 000000000..3b2ab64f3 --- /dev/null +++ b/security/sandbox/chromium/base/debug/alias.h @@ -0,0 +1,21 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEBUG_ALIAS_H_ +#define BASE_DEBUG_ALIAS_H_ + +#include "base/base_export.h" + +namespace base { +namespace debug { + +// Make the optimizer think that var is aliased. This is to prevent it from +// optimizing out variables that that would not otherwise be live at the point +// of a potential crash. +void BASE_EXPORT Alias(const void* var); + +} // namespace debug +} // namespace base + +#endif // BASE_DEBUG_ALIAS_H_ diff --git a/security/sandbox/chromium/base/debug/debugger.h b/security/sandbox/chromium/base/debug/debugger.h new file mode 100644 index 000000000..8680e281e --- /dev/null +++ b/security/sandbox/chromium/base/debug/debugger.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a cross platform interface for helper functions related to +// debuggers. You should use this to test if you're running under a debugger, +// and if you would like to yield (breakpoint) into the debugger. + +#ifndef BASE_DEBUG_DEBUGGER_H_ +#define BASE_DEBUG_DEBUGGER_H_ + +#include "base/base_export.h" + +namespace base { +namespace debug { + +// Waits wait_seconds seconds for a debugger to attach to the current process. +// When silent is false, an exception is thrown when a debugger is detected. +BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent); + +// Returns true if the given process is being run under a debugger. +// +// On OS X, the underlying mechanism doesn't work when the sandbox is enabled. +// To get around this, this function caches its value. +// +// WARNING: Because of this, on OS X, a call MUST be made to this function +// BEFORE the sandbox is enabled. +BASE_EXPORT bool BeingDebugged(); + +// Break into the debugger, assumes a debugger is present. +BASE_EXPORT void BreakDebugger(); + +// Used in test code, this controls whether showing dialogs and breaking into +// the debugger is suppressed for debug errors, even in debug mode (normally +// release mode doesn't do this stuff -- this is controlled separately). +// Normally UI is not suppressed. This is normally used when running automated +// tests where we want a crash rather than a dialog or a debugger. +BASE_EXPORT void SetSuppressDebugUI(bool suppress); +BASE_EXPORT bool IsDebugUISuppressed(); + +} // namespace debug +} // namespace base + +#endif // BASE_DEBUG_DEBUGGER_H_ diff --git a/security/sandbox/chromium/base/debug/leak_annotations.h b/security/sandbox/chromium/base/debug/leak_annotations.h new file mode 100644 index 000000000..dc502461d --- /dev/null +++ b/security/sandbox/chromium/base/debug/leak_annotations.h @@ -0,0 +1,46 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_ +#define BASE_DEBUG_LEAK_ANNOTATIONS_H_ + +#include "base/macros.h" +#include "build/build_config.h" + +// This file defines macros which can be used to annotate intentional memory +// leaks. Support for annotations is implemented in LeakSanitizer. Annotated +// objects will be treated as a source of live pointers, i.e. any heap objects +// reachable by following pointers from an annotated object will not be +// reported as leaks. +// +// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope +// will be annotated as leaks. +// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will +// be annotated as a leak. + +#if defined(LEAK_SANITIZER) && !defined(OS_NACL) + +#include <sanitizer/lsan_interface.h> + +class ScopedLeakSanitizerDisabler { + public: + ScopedLeakSanitizerDisabler() { __lsan_disable(); } + ~ScopedLeakSanitizerDisabler() { __lsan_enable(); } + private: + DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler); +}; + +#define ANNOTATE_SCOPED_MEMORY_LEAK \ + ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast<void>(0) + +#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X); + +#else + +#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0) +#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0) + +#endif + +#endif // BASE_DEBUG_LEAK_ANNOTATIONS_H_ diff --git a/security/sandbox/chromium/base/debug/profiler.cc b/security/sandbox/chromium/base/debug/profiler.cc new file mode 100644 index 000000000..75e9aac0c --- /dev/null +++ b/security/sandbox/chromium/base/debug/profiler.cc @@ -0,0 +1,221 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/debug/profiler.h" + +#include <string> + +#include "base/debug/debugging_flags.h" +#include "base/process/process_handle.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include "base/win/pe_image.h" +#endif // defined(OS_WIN) + +// TODO(peria): Enable profiling on Windows. +#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN) +#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h" +#endif + +namespace base { +namespace debug { + +// TODO(peria): Enable profiling on Windows. +#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN) + +static int profile_count = 0; + +void StartProfiling(const std::string& name) { + ++profile_count; + std::string full_name(name); + std::string pid = IntToString(GetCurrentProcId()); + std::string count = IntToString(profile_count); + ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid); + ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count); + ProfilerStart(full_name.c_str()); +} + +void StopProfiling() { + ProfilerFlush(); + ProfilerStop(); +} + +void FlushProfiling() { + ProfilerFlush(); +} + +bool BeingProfiled() { + return ProfilingIsEnabledForAllThreads(); +} + +void RestartProfilingAfterFork() { + ProfilerRegisterThread(); +} + +#else + +void StartProfiling(const std::string& name) { +} + +void StopProfiling() { +} + +void FlushProfiling() { +} + +bool BeingProfiled() { + return false; +} + +void RestartProfilingAfterFork() { +} + +#endif + +#if !defined(OS_WIN) + +bool IsBinaryInstrumented() { + return false; +} + +ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { + return NULL; +} + +DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { + return NULL; +} + +AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { + return NULL; +} + +MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { + return NULL; +} + +#else // defined(OS_WIN) + +// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx +extern "C" IMAGE_DOS_HEADER __ImageBase; + +bool IsBinaryInstrumented() { + enum InstrumentationCheckState { + UNINITIALIZED, + INSTRUMENTED_IMAGE, + NON_INSTRUMENTED_IMAGE, + }; + + static InstrumentationCheckState state = UNINITIALIZED; + + if (state == UNINITIALIZED) { + HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); + base::win::PEImage image(this_module); + + // Check to be sure our image is structured as we'd expect. + DCHECK(image.VerifyMagic()); + + // Syzygy-instrumented binaries contain a PE image section named ".thunks", + // and all Syzygy-modified binaries contain the ".syzygy" image section. + // This is a very fast check, as it only looks at the image header. + if ((image.GetImageSectionHeaderByName(".thunks") != NULL) && + (image.GetImageSectionHeaderByName(".syzygy") != NULL)) { + state = INSTRUMENTED_IMAGE; + } else { + state = NON_INSTRUMENTED_IMAGE; + } + } + DCHECK(state != UNINITIALIZED); + + return state == INSTRUMENTED_IMAGE; +} + +namespace { + +struct FunctionSearchContext { + const char* name; + FARPROC function; +}; + +// Callback function to PEImage::EnumImportChunks. +bool FindResolutionFunctionInImports( + const base::win::PEImage &image, const char* module_name, + PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table, + PVOID cookie) { + FunctionSearchContext* context = + reinterpret_cast<FunctionSearchContext*>(cookie); + + DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context); + DCHECK_EQ(static_cast<FARPROC>(NULL), context->function); + + // Our import address table contains pointers to the functions we import + // at this point. Let's retrieve the first such function and use it to + // find the module this import was resolved to by the loader. + const wchar_t* function_in_module = + reinterpret_cast<const wchar_t*>(import_address_table->u1.Function); + + // Retrieve the module by a function in the module. + const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; + HMODULE module = NULL; + if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) { + // This can happen if someone IAT patches us to a thunk. + return true; + } + + // See whether this module exports the function we're looking for. + FARPROC exported_func = ::GetProcAddress(module, context->name); + if (exported_func != NULL) { + // We found it, return the function and terminate the enumeration. + context->function = exported_func; + return false; + } + + // Keep going. + return true; +} + +template <typename FunctionType> +FunctionType FindFunctionInImports(const char* function_name) { + if (!IsBinaryInstrumented()) + return NULL; + + HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); + base::win::PEImage image(this_module); + + FunctionSearchContext ctx = { function_name, NULL }; + image.EnumImportChunks(FindResolutionFunctionInImports, &ctx); + + return reinterpret_cast<FunctionType>(ctx.function); +} + +} // namespace + +ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { + return FindFunctionInImports<ReturnAddressLocationResolver>( + "ResolveReturnAddressLocation"); +} + +DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { + return FindFunctionInImports<DynamicFunctionEntryHook>( + "OnDynamicFunctionEntry"); +} + +AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { + return FindFunctionInImports<AddDynamicSymbol>( + "AddDynamicSymbol"); +} + +MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { + return FindFunctionInImports<MoveDynamicSymbol>( + "MoveDynamicSymbol"); +} + +#endif // defined(OS_WIN) + +} // namespace debug +} // namespace base diff --git a/security/sandbox/chromium/base/debug/profiler.h b/security/sandbox/chromium/base/debug/profiler.h new file mode 100644 index 000000000..7cce7b08f --- /dev/null +++ b/security/sandbox/chromium/base/debug/profiler.h @@ -0,0 +1,91 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEBUG_PROFILER_H_ +#define BASE_DEBUG_PROFILER_H_ + +#include <stddef.h> + +#include <string> + +#include "base/base_export.h" + +// The Profiler functions allow usage of the underlying sampling based +// profiler. If the application has not been built with the necessary +// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions +// are noops. +namespace base { +namespace debug { + +// Start profiling with the supplied name. +// {pid} will be replaced by the process' pid and {count} will be replaced +// by the count of the profile run (starts at 1 with each process). +BASE_EXPORT void StartProfiling(const std::string& name); + +// Stop profiling and write out data. +BASE_EXPORT void StopProfiling(); + +// Force data to be written to file. +BASE_EXPORT void FlushProfiling(); + +// Returns true if process is being profiled. +BASE_EXPORT bool BeingProfiled(); + +// Reset profiling after a fork, which disables timers. +BASE_EXPORT void RestartProfilingAfterFork(); + +// Returns true iff this executable is instrumented with the Syzygy profiler. +BASE_EXPORT bool IsBinaryInstrumented(); + +// There's a class of profilers that use "return address swizzling" to get a +// hook on function exits. This class of profilers uses some form of entry hook, +// like e.g. binary instrumentation, or a compiler flag, that calls a hook each +// time a function is invoked. The hook then switches the return address on the +// stack for the address of an exit hook function, and pushes the original +// return address to a shadow stack of some type. When in due course the CPU +// executes a return to the exit hook, the exit hook will do whatever work it +// does on function exit, then arrange to return to the original return address. +// This class of profiler does not play well with programs that look at the +// return address, as does e.g. V8. V8 uses the return address to certain +// runtime functions to find the JIT code that called it, and from there finds +// the V8 data structures associated to the JS function involved. +// A return address resolution function is used to fix this. It allows such +// programs to resolve a location on stack where a return address originally +// resided, to the shadow stack location where the profiler stashed it. +typedef uintptr_t (*ReturnAddressLocationResolver)( + uintptr_t return_addr_location); + +// This type declaration must match V8's FunctionEntryHook. +typedef void (*DynamicFunctionEntryHook)(uintptr_t function, + uintptr_t return_addr_location); + +// The functions below here are to support profiling V8-generated code. +// V8 has provisions for generating a call to an entry hook for newly generated +// JIT code, and it can push symbol information on code generation and advise +// when the garbage collector moves code. The functions declarations below here +// make glue between V8's facilities and a profiler. + +// This type declaration must match V8's FunctionEntryHook. +typedef void (*DynamicFunctionEntryHook)(uintptr_t function, + uintptr_t return_addr_location); + +typedef void (*AddDynamicSymbol)(const void* address, + size_t length, + const char* name, + size_t name_len); +typedef void (*MoveDynamicSymbol)(const void* address, const void* new_address); + + +// If this binary is instrumented and the instrumentation supplies a function +// for each of those purposes, find and return the function in question. +// Otherwise returns NULL. +BASE_EXPORT ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc(); +BASE_EXPORT DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc(); +BASE_EXPORT AddDynamicSymbol GetProfilerAddDynamicSymbolFunc(); +BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc(); + +} // namespace debug +} // namespace base + +#endif // BASE_DEBUG_PROFILER_H_ |