diff options
author | Ed Schouten <ed@FreeBSD.org> | 2011-12-31 14:55:23 +0000 |
---|---|---|
committer | Ed Schouten <ed@FreeBSD.org> | 2011-12-31 14:55:23 +0000 |
commit | 219fb0488994a289f1087f7b3da18789e068da12 (patch) | |
tree | d59ced7e19afaab87432b7610faefff3080e8d2a /lib/asan/asan_globals.cc | |
parent | b0a04aaa595ba76468e521f12727a872d144d6d0 (diff) | |
download | src-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.cc | 171 |
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]); + } +} |