aboutsummaryrefslogtreecommitdiff
path: root/lib/asan/asan_globals.cc
diff options
context:
space:
mode:
authorEd Schouten <ed@FreeBSD.org>2011-12-31 14:55:23 +0000
committerEd Schouten <ed@FreeBSD.org>2011-12-31 14:55:23 +0000
commit219fb0488994a289f1087f7b3da18789e068da12 (patch)
treed59ced7e19afaab87432b7610faefff3080e8d2a /lib/asan/asan_globals.cc
parentb0a04aaa595ba76468e521f12727a872d144d6d0 (diff)
downloadsrc-vendor/compiler-rt/compiler-rt-r147390.tar.gz
src-vendor/compiler-rt/compiler-rt-r147390.zip
Import compiler-rt r147390.vendor/compiler-rt/compiler-rt-r147390
Diffstat (limited to 'lib/asan/asan_globals.cc')
-rw-r--r--lib/asan/asan_globals.cc171
1 files changed, 171 insertions, 0 deletions
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
new file mode 100644
index 000000000000..f53bf38db4c2
--- /dev/null
+++ b/lib/asan/asan_globals.cc
@@ -0,0 +1,171 @@
+//===-- asan_globals.cc -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Handle globals.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_lock.h"
+#include "asan_mapping.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+
+#include <ctype.h>
+
+namespace __asan {
+
+typedef __asan_global Global;
+
+struct ListOfGlobals {
+ const Global *g;
+ ListOfGlobals *next;
+};
+
+static AsanLock mu_for_globals(LINKER_INITIALIZED);
+static ListOfGlobals *list_of_globals;
+static LowLevelAllocator allocator_for_globals(LINKER_INITIALIZED);
+
+void PoisonRedZones(const Global &g) {
+ size_t shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
+ CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
+ // full right redzone
+ size_t g_aligned_size = kGlobalAndStackRedzone *
+ ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
+ PoisonShadow(g.beg + g_aligned_size,
+ kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
+ if ((g.size % kGlobalAndStackRedzone) != 0) {
+ // partial right redzone
+ uint64_t g_aligned_down_size = kGlobalAndStackRedzone *
+ (g.size / kGlobalAndStackRedzone);
+ CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
+ PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
+ g.size % kGlobalAndStackRedzone,
+ kGlobalAndStackRedzone,
+ kAsanGlobalRedzoneMagic);
+ }
+}
+
+static size_t GetAlignedSize(size_t size) {
+ return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
+ * kGlobalAndStackRedzone;
+}
+
+ // Check if the global is a zero-terminated ASCII string. If so, print it.
+void PrintIfASCII(const Global &g) {
+ for (size_t p = g.beg; p < g.beg + g.size - 1; p++) {
+ if (!isascii(*(char*)p)) return;
+ }
+ if (*(char*)(g.beg + g.size - 1) != 0) return;
+ Printf(" '%s' is ascii string '%s'\n", g.name, g.beg);
+}
+
+bool DescribeAddrIfMyRedZone(const Global &g, uintptr_t addr) {
+ if (addr < g.beg - kGlobalAndStackRedzone) return false;
+ if (addr >= g.beg + g.size_with_redzone) return false;
+ Printf("%p is located ", addr);
+ if (addr < g.beg) {
+ Printf("%d bytes to the left", g.beg - addr);
+ } else if (addr >= g.beg + g.size) {
+ Printf("%d bytes to the right", addr - (g.beg + g.size));
+ } else {
+ Printf("%d bytes inside", addr - g.beg); // Can it happen?
+ }
+ Printf(" of global variable '%s' (0x%lx) of size %ld\n",
+ g.name, g.beg, g.size);
+ PrintIfASCII(g);
+ return true;
+}
+
+
+bool DescribeAddrIfGlobal(uintptr_t addr) {
+ if (!FLAG_report_globals) return false;
+ ScopedLock lock(&mu_for_globals);
+ bool res = false;
+ for (ListOfGlobals *l = list_of_globals; l; l = l->next) {
+ const Global &g = *l->g;
+ if (FLAG_report_globals >= 2)
+ Printf("Search Global: beg=%p size=%ld name=%s\n",
+ g.beg, g.size, g.name);
+ res |= DescribeAddrIfMyRedZone(g, addr);
+ }
+ return res;
+}
+
+// Register a global variable.
+// This function may be called more than once for every global
+// so we store the globals in a map.
+static void RegisterGlobal(const Global *g) {
+ CHECK(asan_inited);
+ CHECK(FLAG_report_globals);
+ CHECK(AddrIsInMem(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ PoisonRedZones(*g);
+ ListOfGlobals *l =
+ (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
+ l->g = g;
+ l->next = list_of_globals;
+ list_of_globals = l;
+ if (FLAG_report_globals >= 2)
+ Report("Added Global: beg=%p size=%ld name=%s\n",
+ g->beg, g->size, g->name);
+}
+
+static void UnregisterGlobal(const Global *g) {
+ CHECK(asan_inited);
+ CHECK(FLAG_report_globals);
+ CHECK(AddrIsInMem(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->beg));
+ CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+ PoisonShadow(g->beg, g->size_with_redzone, 0);
+ // We unpoison the shadow memory for the global but we do not remove it from
+ // the list because that would require O(n^2) time with the current list
+ // implementation. It might not be worth doing anyway.
+}
+
+} // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+// Register one global with a default redzone.
+void __asan_register_global(uintptr_t addr, size_t size,
+ const char *name) {
+ if (!FLAG_report_globals) return;
+ ScopedLock lock(&mu_for_globals);
+ Global *g = (Global *)allocator_for_globals.Allocate(sizeof(Global));
+ g->beg = addr;
+ g->size = size;
+ g->size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone;
+ g->name = name;
+ RegisterGlobal(g);
+}
+
+// Register an array of globals.
+void __asan_register_globals(__asan_global *globals, size_t n) {
+ if (!FLAG_report_globals) return;
+ ScopedLock lock(&mu_for_globals);
+ for (size_t i = 0; i < n; i++) {
+ RegisterGlobal(&globals[i]);
+ }
+}
+
+// Unregister an array of globals.
+// We must do it when a shared objects gets dlclosed.
+void __asan_unregister_globals(__asan_global *globals, size_t n) {
+ if (!FLAG_report_globals) return;
+ ScopedLock lock(&mu_for_globals);
+ for (size_t i = 0; i < n; i++) {
+ UnregisterGlobal(&globals[i]);
+ }
+}