/* Memory access checker.
   Copyright 1993 Tristan Gingold
		  Written September 1993 by Tristan Gingold

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License 
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address marc@david.saclay.cea.fr,
   or (US/French mail) as Tristan Gingold 
   			  8 rue Parmentier
   			  F91120 PALAISEAU
   			  FRANCE
*/

#define _MALLOC_INTERNAL
#define NEED_MM
#include "malloc.h"

#include "machine.h"
#include "errlist.h"
#include "message.h"
#include "dmstrings.h"

#ifdef CHKR_USE_BITMAP

typedef unsigned char uchar;
/* typedef unsigned int uint; */

extern char etext, end;
int is_text_writable;

/* Differents type of bitmap.
   SegFinish : end of table
   SegVoid :   Can't be accessed (e.g. NULL pointers)
   SegText:    Text segment.
   SegROnly :  Can't be written (e.g. text segment)
   SegNormal : Normal segment (e.g. data segment)
   SegStack :  Reverse bitmap (e.g. stack segment)
   SegRW :     Can be read and write but no bitmap (e.g. data segment)
   SegWOlny:   Cab be only written.
 */
typedef enum { SegFinish, SegVoid, SegText, SegNormal, SegStack,
               SegRW, SegROnly, SegWOnly } MapType;

/* Anything you want to know about a bitmap */
typedef struct
{
  __ptr_t base;		/* base of the segment */
  uint length;		/* length of the segment */  
  uchar *bmbase;	/* base of the bitmap */
  MapType type;		/* type of the segment */
  const char *name;		/* name of the segment */
  void (*efunc)(const __ptr_t ptr);	/* function to call in case of error */
#ifdef CHKR_PROFILE
  uint addressed;
#endif
} MapInfo;

/* This is the structure filled when you wonder informations about an address
 * See SetBitMem
 */
struct BitMem
{
  uint seg_offset;	/* Offset in the segment */
  uint bm_offset;	/* Offset in the bitmap */
  uint bit_offset;	/* Offset in the byte */
  uint length;		/* How many bytes to the end */
  MapInfo *info;	/* description of the bitmap */
};

/* Here are the offset */
#define NULLBM  0
#define TEXTBM  1
#define DATABM  2
#define HEAPBM  3
#define STACKBM 4 

MapInfo Fmapinfo[6];	/* for faster access */
MapInfo *mapinfo[6];

MapInfo null_mapinfo = { (__ptr_t)0, 0, (uchar*)0, SegFinish, M_ERROR };

static int bytes_per_state = 1;	/* Number of bytes regrouped by a state */
__ptr_t known_stack_limit;	/* current %esp known */
__ptr_t stack_bitmapped;	/* limit of the bitmap */

static void chkr_access_error(const __ptr_t ptr, int arq, struct BitMem *bm, char val, int size);
static void adjust_bm(void);
#ifdef CHKR_STACKBITMAP
void adjust_stackbitmap(__ptr_t ptr);
static void chkr_access_error_stack(const __ptr_t ptr);
#endif /* CHKR_STACKBITMAP */
static void chkr_access_error_heap (const __ptr_t ptr);

/* Optimization: what is the condition to call adjust_bm */
#ifdef CHKR_STACKBITMAP
#define ADJUST_BM_COND (stack_bitmapped > known_stack_limit)
#else  /* !CHKR_STACKBITMAP */
#define ADJUST_BM_COND (0)	/* never */
#endif /* CHKR_STACKBITMAP */

#ifdef CHKR_PROFILE
uint adjust_bm_called = 0;
#endif

int __chkr_maccess = 0;	/* set to 1 when compiled with checker */

/* Get information about addr in bitmem: which bitmap, which offset... */
static void
SetBitMem(const __ptr_t addr, struct BitMem *bitmem)
{
 register MapInfo *tmpinfo = Fmapinfo;
 
 if (ADJUST_BM_COND)	/* Only if useful */
   adjust_bm();
   
 while(tmpinfo->type != SegFinish)
   {
     if (tmpinfo->type != SegStack)
       {
         if (!(addr >= tmpinfo->base && addr < (tmpinfo->base + tmpinfo->length)))
           {
             tmpinfo++;
             continue;
           }
         bitmem->seg_offset = addr - tmpinfo->base;
         bitmem->length = tmpinfo->length - bitmem->seg_offset;
       }
     else
       {
         if (!(addr < tmpinfo->base && addr >= (tmpinfo->base - tmpinfo->length)))
           {
             tmpinfo++;
             continue;
           }
         bitmem->seg_offset = tmpinfo->base - addr;
         bitmem->length = bitmem->seg_offset;
       }
     bitmem->bit_offset = bitmem->seg_offset & bm_round;
     bitmem->bm_offset = bitmem->seg_offset >> bm_log_size;
     bitmem->info = tmpinfo;
#ifdef CHKR_PROFILE
     tmpinfo->addressed++;
#endif      
     return;
   }
 bitmem->info = &null_mapinfo;
 return;
}

/* Adjust all bitmaps (Useful for the stack) */
static void
adjust_bm(void)
{
#ifdef CHKR_STACKBITMAP
 if (1)	/* WAS: stack_bitmapped > known_stack_limit */
   {
     /* set correctly the stack bitmap */
     int bit_off;
     unsigned char *bm_offset2;
     unsigned char *bm_offset1;
     adjust_bm_called++;
     adjust_stackbitmap(known_stack_limit);  
     bit_off = ((int)stack_bitmapped) & bm_round;
     bm_offset2 = chkr_stack_bitmap + 1 +
   			((STACK_LIMIT - (int)stack_bitmapped) >> bm_log_size);
     bm_offset1 = chkr_stack_bitmap + 1 +
   			((STACK_LIMIT - (int)known_stack_limit) >> bm_log_size);  
     if(bit_off != 0)
       {
         *bm_offset2 &=  (bit_off == 1) ? 0xfc :
     		   ((bit_off == 2) ? 0xf0 : 0xc0);
         *bm_offset2 |=  ((bit_off == 1) ? 0x01:
     		   ((bit_off == 2) ? 0x05 : 0x15)) * CHKR_WO;
         bm_offset2++;
       }
#if 0   
     while (bm_offset2 < bm_offset1)
       {
         *bm_offset2 = 0x55 * CHKR_WO;
         bm_offset2++;
       }
#endif
     if (bm_offset2 < bm_offset1)
       memset(bm_offset2, 0x55 * CHKR_WO, (int)bm_offset1 - (int)bm_offset2 + 1);
     
     /* stack bitmap is set */
     stack_bitmapped = known_stack_limit;
   }
#endif       			
}   						
   
#ifdef CHKR_DEBUG
/* Disp the bitmap from addr ptr. len is the number of line.
 * Use this function, only when debugging Checker.
 */
void
chkr_disp_right(const __ptr_t ptr, int len)
{
 struct BitMem bitmem;
 int bm_offset;
 uchar *base;
 int val;
 int i,j;
 int delta;
 uint addr = (int)ptr & (~bm_round); /* round ptr */
 static char *name_right[]={ "--", M_2_RO_RIGHT, M_2_WO_RIGHT, M_2_RW_RIGHT };
 
 /* Search info about the bitmap */
 SetBitMem((__ptr_t)addr, &bitmem);
 base = bitmem.info->bmbase;
 bm_offset = bitmem.bm_offset;
 
 if (base == (uchar*)0)
   {
     chkr_printf(M_NO_BM_4ADDRESS);
     return;
   }
 if (bitmem.info->type != SegStack && bitmem.info->type != SegNormal)
   {
     chkr_printf(M_NO_BM_4ADDRESS);
     return;
   }
 if ( (bitmem.info->type != SegStack && bitmem.bit_offset !=0)
      || (bitmem.info->type == SegStack && bitmem.bit_offset !=3) )
   chkr_printf(M_BO_NOT_ALIGNED);
   
 /* delta is the correction */
 delta = (bitmem.info->type != SegStack) ? bitmem.bit_offset : 3 - bitmem.bit_offset;
 addr -= delta * bytes_per_state;
 
 /* print the header */
 chkr_printf("          ");
 for(i=0; i<16; i++)
   chkr_printf("%02x ",((addr & 0x0f)+i*bytes_per_state) & 
   			      (0x0f * bytes_per_state));
 chkr_printf("\n");
 
 for(i=0; i<len; i++)
   {
     /* address of the line */
     chkr_printf("%08x: ", addr + i*16*bytes_per_state);
     /* bitmap */
     /* val = ((unsigned int*)base)[bm_offset]; */
     if (bitmem.info->type != SegStack)
       {
         val = base[bm_offset] + (base[bm_offset+1]<<8)+ (base[bm_offset+2]<<16)
               + (base[bm_offset+3]<<24);
         bm_offset += 4;
         for(j = 0; j < 16; j++)
           {
             if ((addr + i*16*bytes_per_state +j) >= (uint)ptr)
               chkr_printf("%s ", name_right[val & 3]);
             else
               chkr_printf("?? ");
             val >>= 2;
           }
       }
     else
       {
         val = (base[bm_offset]<<24) + (base[bm_offset-1]<<16)+ 
               (base[bm_offset-2]<<8) + (base[bm_offset-3]);
         bm_offset -= 4;
         for(j = 0; j < 16; j++)
           {
             if ((addr + i*16*bytes_per_state +j) >= (uint)ptr)
               chkr_printf("%s ", name_right[(val>>30) & 3]);
             else
               chkr_printf("?? ");
             val <<= 2;
           }
       }
     chkr_printf("\n");
   }
}
#endif /* CHKR_DEBUG */

/* Set the right of a zone of length len, starting at ptr */
void
chkr_set_right(const __ptr_t ptr, int len, int right)
{
 struct BitMem bitmem;
 uchar *base;	/* Bitmap base */
 uchar val = 0;		/* Val to set in the bitmap */
 uchar mask = 0;	/* Mask corresponding to the val */
 static uchar tab_beg_offset[4] = { 0x00, 0x54, 0x50, 0x40 }; 
 static uchar tab_end_offset[4] = { 0x00, 0x01, 0x05, 0x15 };  
 static uchar tab_beg_off1[4] = { 0x01, 0x05, 0x15, 0x55 };
 static uchar tab_end_off1[4] = { 0x00, 0x40, 0x50, 0x54};
  
 /* Search info about ptr */
 SetBitMem(ptr, &bitmem);
 base = bitmem.info->bmbase;
 if (base == (uchar*)0)
   {
     chkr_printf(M_ERR_SET_RIGHT);
     return;
   }
 /* Be sure about right. Right is 2 bits length */
 right &= 3;   
 if (len > bitmem.length || len == 0)
   {
     chkr_printf(M_BAD_LEN_IN_SR);
     return;
   }
 if (bitmem.info->type == SegNormal)
   {
     if (bitmem.bit_offset > 0)
       { 
         /* len must be divided */
         if ((len / bytes_per_state + bitmem.bit_offset) < (bm_round + 1))
           {
             val = (tab_beg_offset[bitmem.bit_offset] - 
       	       tab_beg_offset[bitmem.bit_offset + len/bytes_per_state]) * right;
             mask = (tab_beg_offset[bitmem.bit_offset] - 
       	       tab_beg_offset[bitmem.bit_offset + len/bytes_per_state]) * CHKR_RW;
             len = 0;	/* finish */
           }
         else
           {
             val = tab_beg_offset[bitmem.bit_offset] * right;
             mask = tab_beg_offset[bitmem.bit_offset] * CHKR_RW;
             len -= (bm_round + 1) - bitmem.bit_offset * bytes_per_state;
           }
         mask = ~mask;
         base[bitmem.bm_offset] &= mask;
         base[bitmem.bm_offset] |= val;
         /* If finish, then return */
         if (len <= 0)
           return;
         /* next byte to set */
         bitmem.bm_offset++;
       }
     /* Now, we set bytes of bitmap. So len is decrease by bm_round + 1 */
     if (len > bm_round)
       {
         val = 0x55 * right;
         while(len > bm_round)
           {
             base[bitmem.bm_offset++] = val;
             len -= bm_round + 1;
           }
         if (len <= 0)
           return;
       }
     /* Now, the end. Set the last byte of bitmap */
     val = tab_end_offset[len] * right;
     mask = tab_end_offset[len] * CHKR_RW;
     mask = ~mask;
     base[bitmem.bm_offset] &= mask;
     base[bitmem.bm_offset] |= val;
     return;
   } 
 else if (bitmem.info->type == SegStack)
   {
     if (bitmem.bit_offset < 3)
       { 
         if (bitmem.bit_offset >= len / bytes_per_state)
           {
             val = (tab_beg_off1[bitmem.bit_offset] - 
                tab_beg_off1[bitmem.bit_offset - len/bytes_per_state]) * right;
             mask = (tab_beg_off1[bitmem.bit_offset] - 
                tab_beg_off1[bitmem.bit_offset - len/bytes_per_state]) * CHKR_RW;
             len = 0;
           }
         else
           {
             val = tab_beg_off1[bitmem.bit_offset] * right;
             mask = tab_beg_off1[bitmem.bit_offset] * CHKR_RW;
             len -= (1 + bitmem.bit_offset) * bytes_per_state;
           }
         mask = ~mask;
         base[bitmem.bm_offset] &= mask;
         base[bitmem.bm_offset] |= val;
         /* If finish, then return */
         if (len <= 0)
           return;
         /* next byte to set */
         bitmem.bm_offset--;
       }
     /* Now, we set bytes of bitmap. So len is decrease by bm_round + 1 */
     if (len > bm_round)
       {
         val = 0x55 * right;
         while(len > bm_round)
           {
             base[bitmem.bm_offset--] = val;
             len -= bm_round + 1;
           }
         if (len <= 0)
           return;
      }
     /* Now, the end. Set the last byte of bitmap */
     val = tab_end_off1[len] * right;
     mask = tab_end_off1[len] * CHKR_RW;
     mask = ~mask;
     base[bitmem.bm_offset] &= mask;
     base[bitmem.bm_offset] |= val;
     return; 
   }
 else
   return;
}

/* Check the right of a zone of length len, starting at ptr */
/*				rights in bitmap
 *                   +-----------+-------------+-------------+-------------+
 *  r                |  CHKR_UN  |   CHKR_RO   |   CHKR_WO   |   CHKR_RW   |
 *  i    +-----------+-----------+-------------+-------------+-------------+
 *  g    |  CHKR_UN  |              not accepted                           |
 *  h    +-----------+-----------+-------------+-------------+-------------+
 *  t    |  CHKR_RO  |   error   |     OK      |    error    |     OK      |
 *       +-----------+-----------+-------------+-------------+-------------+
 *  t    |  CHKR_WO  |   error   |    error    | -> CHKR_RW  |     OK      |
 *  e    +-----------+-----------+-------------+-------------+-------------+
 *  s    |  CHKR_TW  |   error   |    error    |     OK      |     OK      |
 *  t    +-----------+-----------+-------------+-------------+-------------+
 *  e    |  CHKR_RW  |   error   |    error    |    error    |     OK      | 
 *  d    +-----------+-----------+-------------+-------------+-------------+
 */
void
chkr_check_addr(const __ptr_t ptr, int len, int right1)
{
 struct BitMem bitmem;
 uchar *base;		/* Bitmap base */
 uchar val = 0;		/* Val to set in the bitmap */
 uchar mask = 0;
 int size = len;	/* save */
 int right;			/* Good Value of right1 */
 static uchar tab_beg_offset[4] = { 0x00, 0x54, 0x50, 0x40 }; 
 static uchar tab_end_offset[4] = { 0x00, 0x01, 0x05, 0x15 };  
 static uchar tab_beg_off1[4] = { 0x01, 0x05, 0x15, 0x55 };
 static uchar tab_end_off1[4] = { 0x00, 0x40, 0x50, 0x54};

 /* Be sure about right. Right is 2 bits length */
 right = right1 &  3;  
 
 /* check for stupidities. Could be removed */
 if (right == 0)
   {
     chkr_errno = E_IE_BRIGHT;	/* bad check, must never happen */
     chkr_perror();
     chkr_abort();
   }
 if (len == 0)
   return;		/* can be used by syscall */
   
 /* Search info about ptr */
 SetBitMem(ptr, &bitmem);
 base = bitmem.info->bmbase;

 switch (bitmem.info->type)
 {
   case SegNormal:
     if (bitmem.bit_offset > 0)
       { 
         /* len must be divided */
         if ((len / bytes_per_state + bitmem.bit_offset) < (bm_round + 1))
           {
             val = (tab_beg_offset[bitmem.bit_offset] - 
       	       tab_beg_offset[bitmem.bit_offset + len/bytes_per_state]) * right;
             mask = (tab_beg_offset[bitmem.bit_offset] - 
       	       tab_beg_offset[bitmem.bit_offset + len/bytes_per_state]) * CHKR_RW;
             len = 0;	/* finish */
           }
         else
           {
             val = tab_beg_offset[bitmem.bit_offset] * right;
             mask = tab_beg_offset[bitmem.bit_offset] * CHKR_RW;
             len -= (bm_round + 1) - bitmem.bit_offset * bytes_per_state;
           }
         if ((base[bitmem.bm_offset] & val) != val)
           {
             chkr_access_error(ptr, right, &bitmem, val, size);
             return;	/* check fails */
           }
         if (right1 == CHKR_WO)
           base[bitmem.bm_offset] |= mask;	/* CHKR_WO -> CHKR_RW */
         /* If finish, then return */
         if (len <= 0)
           return;
         /* next byte to set */
         bitmem.bm_offset++;
       }
     /* Now, we set bytes of bitmap. So len is decrease by bm_round + 1 */
     if (len > bm_round)
       {
         val = 0x55 * right;
         mask = 0x55 * CHKR_RW;
         while(len > bm_round)
           {
             if ((base[bitmem.bm_offset] & val) != val)
               {
                  chkr_access_error(ptr, right, &bitmem, val, size);
                  return;	/* check fails */
               }
             if (right1 == CHKR_WO)
               base[bitmem.bm_offset] |= mask;
             bitmem.bm_offset++;
             len -= bm_round + 1;
           }
         if (len <= 0)
           return;
       }
     /* Now, the end. Set the last byte of bitmap */
     val = tab_end_offset[len] * right;
     mask = tab_end_offset[len] * CHKR_RW;
     if ((base[bitmem.bm_offset] & val) != val)
       {
         chkr_access_error(ptr, right, &bitmem, val, size);
         return;	/* check fails */
       }
     if (right1 == CHKR_WO)
       base[bitmem.bm_offset] |= mask;
     return;
     
   case SegStack:
     if (bitmem.bit_offset < 3)
       { 
         /* means bitmem.bit_offset - len / bytes_per_state > 0 */
         if (bitmem.bit_offset >= len / bytes_per_state)
           {
             val = (tab_beg_off1[bitmem.bit_offset] - 
                tab_beg_off1[bitmem.bit_offset - len/bytes_per_state]) * right;
             mask = (tab_beg_off1[bitmem.bit_offset] - 
                tab_beg_off1[bitmem.bit_offset - len/bytes_per_state]) * CHKR_RW;
             len = 0;
           }
         else
           {
             val = tab_beg_off1[bitmem.bit_offset] * right;
             mask = tab_beg_off1[bitmem.bit_offset] * CHKR_RW;
             len -= (1 + bitmem.bit_offset) * bytes_per_state;
           }
         if ((base[bitmem.bm_offset] & val) != val)
           {
             chkr_access_error(ptr, right, &bitmem, val, size);
             return;	/* check fails */
           }
         if (right1 == CHKR_WO)
           base[bitmem.bm_offset] |= mask;	/* CHKR_WO -> CHKR_RW */
         /* If finish, then return */
         if (len <= 0)
           return;
         /* next byte to set */
         bitmem.bm_offset--;
       }
     /* Now, we set bytes of bitmap. So len is decrease by bm_round + 1 */
     if (len > bm_round)
       {
         val = 0x55 * right;
         mask = 0x55 * CHKR_RW;
         while(len > bm_round)
           {
             if ((base[bitmem.bm_offset] & val) != val)
               {
                 chkr_access_error(ptr, right, &bitmem, val, size);
                 return;	/* check fails */
               }
             if (right1 == CHKR_WO)
               base[bitmem.bm_offset] |= mask;
             bitmem.bm_offset--;
             len -= bm_round + 1;     
           }
         if (len <= 0)
           return;
       }
     /* Now, the end. Set the last byte of bitmap */
     val = tab_end_off1[len] * right;
     mask = tab_end_off1[len] * CHKR_RW;
     if ((base[bitmem.bm_offset] & val) != val)
       {
         chkr_access_error(ptr, right, &bitmem, val, size);
         return;	/* check fails */
       }
     if (right1 == CHKR_WO)
       base[bitmem.bm_offset] |= mask;
     return; 
     
   case SegFinish:
   case SegVoid:
     chkr_access_error(ptr, right, &bitmem, 0, size);
     return;
     
   case SegText:
     if (!is_text_writable)
       if (right != CHKR_RO)
         chkr_access_error(ptr, right, &bitmem, 0, size);
     return;
     
   case SegRW:
     return;
   
   case SegROnly:
   case SegWOnly:
     chkr_abort();	/* Not implemented */
 }
}

/* Check for a string.
 * Is this implementation poor ?
 */
void
chkr_check_str(const __ptr_t ptr, int right)
{
   chkr_check_addr(ptr, strlen(ptr), right);
}

/* copy a part of bitmap 
 * This is used by realloc.
 */
void
chkr_copy_bm(__ptr_t dest, __ptr_t src, uint len)
{
 struct BitMem bmsrc, bmdest;
 static uchar tab_offset[] = { 0x00, 0x03, 0x0f, 0x3f };
 uint bm_len;
  
 SetBitMem(src, &bmsrc);
 if(bmsrc.info->type != SegNormal || bmsrc.length < len)
   {
     chkr_printf(M_SRC_IN_CP_BM);
     return;
   }
 SetBitMem(dest, &bmdest);
 if(bmdest.info->type != SegNormal || bmdest.length < len)
   {
     chkr_printf(M_DEST_IN_CP_BM);
     return;
   }  
 if(bmsrc.bit_offset != 0 || bmdest.bit_offset != 0)
   {
     chkr_printf(M_ALIGN_IN_CP_BM);
     return;
   }
 bm_len = len / (bm_round + 1);
 memcpy(&(bmdest.info->bmbase[bmdest.bm_offset]),
         &(bmsrc.info->bmbase[bmsrc.bm_offset]),
         bm_len);
 if ((len & bm_round) == 0)
   return;
 bmdest.info->bmbase[bmdest.bm_offset + bm_len] &= ~(tab_offset[len & bm_round]);
 bmdest.info->bmbase[bmdest.bm_offset + bm_len] |= 
     tab_offset[len & bm_round] & bmsrc.info->bmbase[bmsrc.bm_offset + bm_len];
} 

#ifdef CHKR_PROFILE
void
display_profile()
{
 register MapInfo *tmpinfo = Fmapinfo;
 unsigned int total = 0;
 
 chkr_header(M_PROF_INFO_HERE);
 while(tmpinfo->type != SegFinish)
   {
     chkr_printf(M_HANDLED_N_TIME, tmpinfo->name, 
   		tmpinfo->addressed, (tmpinfo->addressed > 1) ? "s" : "");
     total += tmpinfo->addressed;
     tmpinfo++;
   }
 chkr_printf(M_HANDLED_MEM, total);
 chkr_printf(M_BM_CALLED, adjust_bm_called);
}
#endif

/* initialize the informations for the bitmaps */
static void
init_mapinfos(void)
{
 int i=0;

#ifdef CHKR_STACKBITMAP
 mapinfo[STACKBM] = &Fmapinfo[i++];
#endif
#ifdef CHKR_HEAPBITMAP
 mapinfo[HEAPBM] =  &Fmapinfo[i++];
#endif
#ifdef CHKR_DATABITMAP
 mapinfo[DATABM] =  &Fmapinfo[i++];
#endif
 mapinfo[TEXTBM] =  &Fmapinfo[i++];
 mapinfo[NULLBM] =  &Fmapinfo[i++];
  
 Fmapinfo[i].type = SegFinish;
  
 /* NULL zone */
 mapinfo[NULLBM]->name = M_NULL_ZONE;
 mapinfo[NULLBM]->base = (__ptr_t)0x0;
 mapinfo[NULLBM]->length = null_pointer_zone;
 mapinfo[NULLBM]->bmbase = (uchar*)0;
 mapinfo[NULLBM]->type = SegVoid;
  
 /* text segment */
 mapinfo[TEXTBM]->name = M_TEXT_SEGMENT;
 mapinfo[TEXTBM]->base = (__ptr_t)null_pointer_zone;
 mapinfo[TEXTBM]->length = (int)&etext - null_pointer_zone;
 mapinfo[TEXTBM]->bmbase = (uchar*)0;
 mapinfo[TEXTBM]->type = SegText;
 
#ifdef CHKR_DATABITMAP
 /* data segment */  
 mapinfo[DATABM]->name = M_DATA_SEGMENT;
 mapinfo[DATABM]->base = &etext;
 mapinfo[DATABM]->length = (int)&end - (int)&etext;
 mapinfo[DATABM]->bmbase = (uchar*)0;
 mapinfo[DATABM]->type = SegRW; /*SegNormal;*/
#endif  
#ifdef CHKR_HEAPBITMAP
 /* heap 'segment' */
 mapinfo[HEAPBM]->name = M_HEAP_SEGMENT;
 mapinfo[HEAPBM]->base = (__ptr_t)0x0;
 mapinfo[HEAPBM]->length = 0;
 mapinfo[HEAPBM]->bmbase = (uchar*)0;
 mapinfo[HEAPBM]->type = SegNormal;  
 mapinfo[HEAPBM]->efunc = chkr_access_error_heap;
#endif
#ifdef CHKR_STACKBITMAP
 mapinfo[STACKBM]->name = M_STACK_SEGMENT;
 mapinfo[STACKBM]->base = (__ptr_t)STACK_LIMIT;
 mapinfo[STACKBM]->length = 0;
 mapinfo[STACKBM]->bmbase = (uchar*)0;
 mapinfo[STACKBM]->type = SegStack;
 mapinfo[STACKBM]->efunc = chkr_access_error_stack;
#endif
}


/* Disp the history of a block
 */   
static void
disp_block_history(__ptr_t *ptr)
{
  if (symtab_available == 0)
    chkr_printf(M_CANT_USE_SYMTAB);
  else
    {
      for(; *ptr; ptr++)
        chkr_show_addr((__ptr_t)ptr);
    }
}

#ifdef CHKR_STACKBITMAP
/* Code that handle access error on the stack
 */
static void
chkr_access_error_stack(const __ptr_t ptr)
{
 chkr_printf(M_KNOW_STACK_LIM, known_stack_limit);
 chkr_printf(M_STACK_BITMAPED, stack_bitmapped);
 chkr_disp_right(ptr, 2);
}
#endif
 
/* Code that handle access error on the heap.
 * Display all informations.
 */
static void
chkr_access_error_heap (const __ptr_t ptr)
{
  struct malloc_header *block;
  __ptr_t *ptr_on_block;
  int block_size;

  if (_lastblock == NULL_HEADER)
    return;
  if(ptr < (__ptr_t)_firstblock || ptr > ((__ptr_t)_lastblock + _lastblock->size))
    return;	/* not inside the heap */
   
  block = find_header(ptr);

  /* Don't forget that ptr can point to anywhere */
  if (block->state == MDFREE)
    {
      chkr_printf(M_INSIDE_FBLOCK);
      return;	/* pointer on free block */
    }
  
  /* compute the size of the block */
  if (block->state == MDAGED)
    block_size = block->size - be_red_zone - af_red_zone - block->s_diff;
  else
    block_size = block->info.busy.real_size;
    
  /* display size of the block and its beginning */
  chkr_printf(M_BLOCK_ID, block_size, (uint)block + HEADER_SIZE + be_red_zone);
  
  if (ptr < ((__ptr_t)block + be_red_zone + HEADER_SIZE))
    chkr_printf(M_BEFORE_BLOCK,
		(int)((int)block + be_red_zone + HEADER_SIZE - (int)ptr));
  else if (ptr < ((__ptr_t)block + be_red_zone + HEADER_SIZE + block_size))
    chkr_printf(M_INSIDE_BLOCK,
		(int)(ptr) - (int)((int)block + be_red_zone + HEADER_SIZE));
  else
    chkr_printf(M_AFTER_BLOCK,
    		(int)(ptr) -
    		(int)((__ptr_t)block + be_red_zone + HEADER_SIZE + block_size));
#if CHKR_SAVESTACK
  ptr_on_block = (__ptr_t*)((int)block + block->size + HEADER_SIZE - af_red_zone);
  chkr_load_symtab();
  chkr_printf(M_BLOCK_ALLO_FRM);
  disp_block_history(ptr_on_block);
  if (block->state == MDAGED)
    {
      chkr_printf(M_N_FREE_CALLED, get_age(block));
      ptr_on_block = (__ptr_t*)((int)block + HEADER_SIZE);
      disp_block_history(ptr_on_block);
    }
  chkr_unload_symtab();
#endif /* CHKR_SAVESTACK */  			
}

static char *right_name[]={
	M_IE_RIGHT_NAME,
	M_RO_RIGHT_NAME,
	M_WO_RIGHT_NAME,
	M_RW_RIGHT_NAME};

/* This function is called by chkr_check_addr, when an error has been 
 * discovered. It calls chkr_access_error_*
 */
static void
chkr_access_error(const __ptr_t ptr, int arq, struct BitMem *bm, char val, int size)
{
#ifdef CHKR_SAVESTACK
 int must_remove = 0;
#endif /* CHKR_SAVESTACK */ 
 int i;
 
 /* without inserted code */
 if (__chkr_maccess == 0)
   return;
   
 /* Check for disabled ip (--disable= option) */
 for (i = 0; i < disable_cur; i++)
   if ((int)chkr_frames_ip >= (*disable)[i].first
       && (int)chkr_frames_ip <= (*disable)[i].last)
     return;
 
 chkr_header(M_MEM_ACCESS_ERR);
 chkr_printf(M_ACC_ERR_WHERE, right_name[arq], size, ptr, bm->info->name);
 if (bm->info == mapinfo[NULLBM]) 
   {
     chkr_printf(M_USE_NULL_PTR);
     chkr_printf(M_PROD_SEG_FAULT);
     /* Can produce a segmentation fault. So, remove th temp file */
#ifdef CHKR_SAVESTACK     
     must_remove = 1;
#endif /* CHKR_SAVESTACK */
   }
 else if (bm->info == mapinfo[TEXTBM])
   {
     chkr_printf(M_CANT_MODIFY_IT);
     chkr_printf(M_PROD_SEG_FAULT);
#ifdef CHKR_SAVESTACK     
     must_remove = 1;
#endif /* CHKR_SAVESTACK */
   }
 else if (bm->info->efunc)
   (bm->info->efunc)(ptr);
 chkr_errno = E_MEMACCERR;
#ifdef CHKR_SAVESTACK
 chkr_frames_to_forget = 5;
 chkr_show_frames();
 if (must_remove)
   chkr_remove_symtabfile();
#endif  /* CHKR_SAVESTACK */
}
#endif /* CHKR_USE_BITMAP */

#ifdef CHECKER_USE_MMAP
#include "macc-mmap.h"
#else
#include "macc-brk.h"
#endif /* CHECKER_USE_MMAP */
