summaryrefslogtreecommitdiffstats
path: root/third_party/tcmalloc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/tcmalloc')
-rw-r--r--third_party/tcmalloc/chromium/src/linux_shadow_stacks.cc128
-rw-r--r--third_party/tcmalloc/chromium/src/linux_shadow_stacks.h20
-rw-r--r--third_party/tcmalloc/chromium/src/stacktrace_x86-inl.h45
3 files changed, 193 insertions, 0 deletions
diff --git a/third_party/tcmalloc/chromium/src/linux_shadow_stacks.cc b/third_party/tcmalloc/chromium/src/linux_shadow_stacks.cc
new file mode 100644
index 0000000..a060b54
--- /dev/null
+++ b/third_party/tcmalloc/chromium/src/linux_shadow_stacks.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2006-2010 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 "linux_shadow_stacks.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static const int kMaxShadowIndex = 2048;
+static const char kOverflowMessage[] = "Shadow stack overflow\n";
+
+// Thread-local vars.
+__thread
+int shadow_index = -1;
+__thread
+void *shadow_ip_stack[kMaxShadowIndex];
+__thread
+void *shadow_sp_stack[kMaxShadowIndex];
+
+enum Status {UNINITIALIZED = -1, DISABLED, ENABLED};
+Status status = UNINITIALIZED;
+
+void init() {
+ if (!getenv("KEEP_SHADOW_STACKS")) {
+ status = DISABLED;
+ return;
+ }
+ status = ENABLED;
+}
+
+void __cyg_profile_func_enter(void *this_fn, void *call_site) {
+ if (status == DISABLED) return;
+ if (status == UNINITIALIZED) {
+ init();
+ if (status == DISABLED) return;
+ }
+ shadow_index++;
+ if (shadow_index > kMaxShadowIndex) {
+ // Avoid memory allocation when reporting an error.
+ write(2, kOverflowMessage, sizeof(kOverflowMessage));
+ int a = 0;
+ a = a / a;
+ }
+ // Update the shadow IP stack
+ shadow_ip_stack[shadow_index] = this_fn;
+ // Update the shadow SP stack. The code for obtaining the frame address was
+ // borrowed from Google Perftools, http://code.google.com/p/google-perftools/
+ //
+ // Copyright (c) 2005, 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.
+ void **sp;
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
+ // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8.
+ // It's always correct on llvm, and the techniques below aren't (in
+ // particular, llvm-gcc will make a copy of this_fn, so it's not in sp[2]),
+ // so we also prefer __builtin_frame_address when running under llvm.
+ sp = reinterpret_cast<void**>(__builtin_frame_address(0));
+#elif defined(__i386__)
+ // Stack frame format:
+ // sp[0] pointer to previous frame
+ // sp[1] caller address
+ // sp[2] first argument
+ // ...
+ // NOTE: This will break under llvm, since result is a copy and not in sp[2]
+ sp = (void **)&this_fn - 2;
+#elif defined(__x86_64__)
+ unsigned long rbp;
+ // Move the value of the register %rbp into the local variable rbp.
+ // We need 'volatile' to prevent this instruction from getting moved
+ // around during optimization to before function prologue is done.
+ // An alternative way to achieve this
+ // would be (before this __asm__ instruction) to call Noop() defined as
+ // static void Noop() __attribute__ ((noinline)); // prevent inlining
+ // static void Noop() { asm(""); } // prevent optimizing-away
+ __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
+ // Arguments are passed in registers on x86-64, so we can't just
+ // offset from &result
+ sp = (void **) rbp;
+#else
+# error Cannot obtain SP (possibly compiling on a non x86 architecture)
+#endif
+ shadow_sp_stack[shadow_index] = (void*)sp;
+ return;
+}
+
+void __cyg_profile_func_exit(void *this_fn, void *call_site) {
+ if (status == DISABLED) return;
+ shadow_index--;
+}
+
+void *get_shadow_ip_stack(int *index /*OUT*/) {
+ *index = shadow_index;
+ return shadow_ip_stack;
+}
+
+void *get_shadow_sp_stack(int *index /*OUT*/) {
+ *index = shadow_index;
+ return shadow_sp_stack;
+}
diff --git a/third_party/tcmalloc/chromium/src/linux_shadow_stacks.h b/third_party/tcmalloc/chromium/src/linux_shadow_stacks.h
new file mode 100644
index 0000000..e519d29
--- /dev/null
+++ b/third_party/tcmalloc/chromium/src/linux_shadow_stacks.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2006-2010 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 THIRD_PARTY_TCMALLOC_CHROMIUM_SRC_LINUX_SHADOW_STACKS_H__
+#define THIRD_PARTY_TCMALLOC_CHROMIUM_SRC_LINUX_SHADOW_STACKS_H__
+
+#define NO_INSTRUMENT __attribute__((no_instrument_function))
+
+extern "C" {
+void init() NO_INSTRUMENT;
+void __cyg_profile_func_enter(void *this_fn, void *call_site) NO_INSTRUMENT;
+void __cyg_profile_func_exit(void *this_fn, void *call_site) NO_INSTRUMENT;
+void *get_shadow_ip_stack(int *index /*OUT*/) NO_INSTRUMENT;
+void *get_shadow_sp_stack(int *index /*OUT*/) NO_INSTRUMENT;
+}
+
+#undef NO_INSTRUMENT
+
+#endif // THIRD_PARTY_TCMALLOC_CHROMIUM_SRC_LINUX_SHADOW_STACKS_H__
diff --git a/third_party/tcmalloc/chromium/src/stacktrace_x86-inl.h b/third_party/tcmalloc/chromium/src/stacktrace_x86-inl.h
index a140ab6..0f8c4de 100644
--- a/third_party/tcmalloc/chromium/src/stacktrace_x86-inl.h
+++ b/third_party/tcmalloc/chromium/src/stacktrace_x86-inl.h
@@ -65,6 +65,9 @@ typedef ucontext ucontext_t;
#endif
#include "google/stacktrace.h"
+#if defined(KEEP_SHADOW_STACKS)
+#include "linux_shadow_stacks.h"
+#endif // KEEP_SHADOW_STACKS
#if defined(__linux__) && defined(__i386__) && defined(__ELF__) && defined(HAVE_MMAP)
// Count "push %reg" instructions in VDSO __kernel_vsyscall(),
@@ -316,6 +319,21 @@ int GET_STACK_TRACE_OR_FRAMES {
#endif
int n = 0;
+#if defined(KEEP_SHADOW_STACKS)
+ void **shadow_ip_stack;
+ void **shadow_sp_stack;
+ int stack_size;
+ shadow_ip_stack = (void**) get_shadow_ip_stack(&stack_size);
+ shadow_sp_stack = (void**) get_shadow_sp_stack(&stack_size);
+ int shadow_index = stack_size - 1;
+ for (int i = stack_size - 1; i >= 0; i--) {
+ if (sp == shadow_sp_stack[i]) {
+ shadow_index = i;
+ break;
+ }
+ }
+ void **prev_sp = NULL;
+#endif // KEEP_SHADOW_STACKS
while (sp && n < max_depth) {
if (*(sp+1) == reinterpret_cast<void *>(0)) {
// In 64-bit code, we often see a frame that
@@ -328,8 +346,17 @@ int GET_STACK_TRACE_OR_FRAMES {
void **next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp);
if (skip_count > 0) {
skip_count--;
+#if defined(KEEP_SHADOW_STACKS)
+ shadow_index--;
+#endif // KEEP_SHADOW_STACKS
} else {
result[n] = *(sp+1);
+#if defined(KEEP_SHADOW_STACKS)
+ if ((shadow_index > 0) && (sp == shadow_sp_stack[shadow_index])) {
+ shadow_index--;
+ }
+#endif // KEEP_SHADOW_STACKS
+
#if IS_STACK_FRAMES
if (next_sp > sp) {
sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
@@ -340,7 +367,25 @@ int GET_STACK_TRACE_OR_FRAMES {
#endif
n++;
}
+#if defined(KEEP_SHADOW_STACKS)
+ prev_sp = sp;
+#endif // KEEP_SHADOW_STACKS
sp = next_sp;
}
+
+#if defined(KEEP_SHADOW_STACKS)
+ if (shadow_index >= 0) {
+ for (int i = shadow_index; i >= 0; i--) {
+ if (shadow_sp_stack[i] > prev_sp) {
+ result[n] = shadow_ip_stack[i];
+ if (n + 1 < max_depth) {
+ n++;
+ continue;
+ }
+ }
+ break;
+ }
+ }
+#endif // KEEP_SHADOW_STACKS
return n;
}