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