1169695Skan/* Mudflap: narrow-pointer bounds-checking by tree rewriting. 2169695Skan Copyright (C) 2002, 2003 Free Software Foundation, Inc. 3169695Skan Contributed by Frank Ch. Eigler <fche@redhat.com> 4169695Skan and Graydon Hoare <graydon@redhat.com> 5169695Skan 6169695SkanThis file is part of GCC. 7169695Skan 8169695SkanGCC is free software; you can redistribute it and/or modify it under 9169695Skanthe terms of the GNU General Public License as published by the Free 10169695SkanSoftware Foundation; either version 2, or (at your option) any later 11169695Skanversion. 12169695Skan 13169695SkanIn addition to the permissions in the GNU General Public License, the 14169695SkanFree Software Foundation gives you unlimited permission to link the 15169695Skancompiled version of this file into combinations with other programs, 16169695Skanand to distribute those combinations without any restriction coming 17169695Skanfrom the use of this file. (The General Public License restrictions 18169695Skando apply in other respects; for example, they cover modification of 19169695Skanthe file, and distribution when not linked into a combine 20169695Skanexecutable.) 21169695Skan 22169695SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 23169695SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 24169695SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25169695Skanfor more details. 26169695Skan 27169695SkanYou should have received a copy of the GNU General Public License 28169695Skanalong with GCC; see the file COPYING. If not, write to the Free 29169695SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 30169695Skan02110-1301, USA. */ 31169695Skan 32169695Skan 33169695Skan#include "config.h" 34169695Skan 35169695Skan#include <stdio.h> 36169695Skan 37169695Skan#include "mf-runtime.h" 38169695Skan#include "mf-impl.h" 39169695Skan 40169695Skan#ifdef _MUDFLAP 41169695Skan#error "Do not compile this file with -fmudflap!" 42169695Skan#endif 43169695Skan 44169695Skan 45169695Skanextern char _end[]; 46169695Skanextern char ENTRY_POINT[]; 47169695Skan 48169695Skan 49169695Skan/* Run some quick validation of the given region. 50169695Skan Return -1 / 0 / 1 if the access known-invalid, possibly-valid, or known-valid. 51169695Skan*/ 52169695Skanint 53169695Skan__mf_heuristic_check (uintptr_t ptr, uintptr_t ptr_high) 54169695Skan{ 55169695Skan VERBOSE_TRACE ("mf: heuristic check\n"); 56169695Skan 57169695Skan /* XXX: Disable the stack bounding check for libmudflapth. We do 58169695Skan actually have enough information to track stack bounds (see 59169695Skan __mf_pthread_info in mf-hooks.c), so with a bit of future work, 60169695Skan this heuristic can be turned on. */ 61169695Skan#ifndef LIBMUDFLAPTH 62169695Skan 63169695Skan /* The first heuristic is to check stack bounds. This is a 64169695Skan transient condition and quick to check. */ 65169695Skan if (__mf_opts.heur_stack_bound) 66169695Skan { 67169695Skan uintptr_t stack_top_guess = (uintptr_t)__builtin_frame_address(0); 68169695Skan#if defined(__i386__) && defined (__linux__) 69169695Skan uintptr_t stack_segment_base = 0xC0000000; /* XXX: Bad assumption. */ 70169695Skan#else 71169695Skan /* Cause tests to fail. */ 72169695Skan uintptr_t stack_segment_base = 0; 73169695Skan#endif 74169695Skan 75169695Skan VERBOSE_TRACE ("mf: stack estimated as %p-%p\n", 76169695Skan (void *) stack_top_guess, (void *) stack_segment_base); 77169695Skan 78169695Skan if (ptr_high <= stack_segment_base && 79169695Skan ptr >= stack_top_guess && 80169695Skan ptr_high >= ptr) 81169695Skan { 82169695Skan return 1; 83169695Skan } 84169695Skan } 85169695Skan#endif 86169695Skan 87169695Skan 88169695Skan /* The second heuristic is to scan the range of memory regions 89169695Skan listed in /proc/self/maps, a special file provided by the Linux 90169695Skan kernel. Its results may be cached, and in fact, a GUESS object 91169695Skan may as well be recorded for interesting matching sections. */ 92169695Skan if (__mf_opts.heur_proc_map) 93169695Skan { 94169695Skan /* Keep a record of seen records from /proc/self/map. */ 95169695Skan enum { max_entries = 500 }; 96169695Skan struct proc_self_map_entry 97169695Skan { 98169695Skan uintptr_t low; 99169695Skan uintptr_t high; 100169695Skan }; 101169695Skan static struct proc_self_map_entry entry [max_entries]; 102169695Skan static unsigned entry_used [max_entries]; 103169695Skan 104169695Skan /* Look for a known proc_self_map entry that may cover this 105169695Skan region. If one exists, then this heuristic has already run, 106169695Skan and should not be run again. The check should be allowed to 107169695Skan fail. */ 108169695Skan unsigned i; 109169695Skan unsigned deja_vu = 0; 110169695Skan for (i=0; i<max_entries; i++) 111169695Skan { 112169695Skan if (entry_used[i] && 113169695Skan (entry[i].low <= ptr) && 114169695Skan (entry[i].high >= ptr_high)) 115169695Skan deja_vu = 1; 116169695Skan } 117169695Skan 118169695Skan if (! deja_vu) 119169695Skan { 120169695Skan /* Time to run the heuristic. Rescan /proc/self/maps; update the 121169695Skan entry[] array; XXX: remove expired entries, add new ones. 122169695Skan XXX: Consider entries that have grown (e.g., stack). */ 123169695Skan char buf[512]; 124169695Skan char flags[4]; 125169695Skan void *low, *high; 126169695Skan FILE *fp; 127169695Skan 128169695Skan fp = fopen ("/proc/self/maps", "r"); 129169695Skan if (fp) 130169695Skan { 131169695Skan while (fgets (buf, sizeof(buf), fp)) 132169695Skan { 133169695Skan if (sscanf (buf, "%p-%p %4c", &low, &high, flags) == 3) 134169695Skan { 135169695Skan if ((uintptr_t) low <= ptr && 136169695Skan (uintptr_t) high >= ptr_high) 137169695Skan { 138169695Skan for (i=0; i<max_entries; i++) 139169695Skan { 140169695Skan if (! entry_used[i]) 141169695Skan { 142169695Skan entry[i].low = (uintptr_t) low; 143169695Skan entry[i].high = (uintptr_t) high; 144169695Skan entry_used[i] = 1; 145169695Skan break; 146169695Skan } 147169695Skan } 148169695Skan 149169695Skan VERBOSE_TRACE ("mf: registering region #%d " 150169695Skan "%p-%p given %s", 151169695Skan i, (void *) low, (void *) high, buf); 152169695Skan 153169695Skan __mfu_register ((void *) low, (size_t) (high-low), 154169695Skan __MF_TYPE_GUESS, 155169695Skan "/proc/self/maps segment"); 156169695Skan 157169695Skan return 0; /* undecided (tending to cachable) */ 158169695Skan } 159169695Skan } 160169695Skan } 161169695Skan fclose (fp); 162169695Skan } 163169695Skan } 164169695Skan } 165169695Skan 166169695Skan 167169695Skan /* The third heuristic is to approve all accesses between _start (or its 168169695Skan equivalent for the given target) and _end, which should include all 169169695Skan text and initialized data. */ 170169695Skan if (__mf_opts.heur_start_end) 171169695Skan if (ptr >= (uintptr_t) & ENTRY_POINT && ptr_high <= (uintptr_t) & _end) 172169695Skan return 1; /* uncacheable */ 173169695Skan 174169695Skan return 0; /* unknown */ 175169695Skan} 176