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

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library 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
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  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
*/

#ifndef	_MALLOC_INTERNAL
#define _MALLOC_INTERNAL
#include "malloc.h"
#endif

#ifdef CHECKER
#include "errlist.h"
#endif

#ifdef CHKR_USE_BITMAP
#include "machine.h"

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)
 */
typedef enum { SegFinish, SegVoid, SegText, SegROnly, SegNormal, SegStack} 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 */
  char *name;		/* name of the segment */
  void (*efunc)(__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
{
/*  uchar *base;	*/	/* Bitmap base */
  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 */
  MapType type;		/* type of bitmap */
  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, "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(__ptr_t ptr, int arq, struct BitMem *bm, char val);
void chkr_show_frames(void);
static void adjust_bm();
#ifdef CHKR_SAVESTACK
void chkr_remove_symtabfile();
#endif /* CHKR_SAVESTACK */
#ifdef CHKR_STACKBITMAP
void adjust_stackbitmap(__ptr_t ptr);
static void chkr_access_error_stack(__ptr_t ptr);
#endif /* CHKR_STACKBITMAP */
static void chkr_access_error_heap (__ptr_t ptr);

static void SetBitMem(__ptr_t addr, struct BitMem *bitmem)
{
 register MapInfo *tmpinfo = Fmapinfo;
 
 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->base = tmpinfo->bmbase; */
   bitmem->bm_offset = bitmem->seg_offset >> bm_log_size;
   bitmem->type = tmpinfo->type;
   bitmem->info = tmpinfo;
#ifdef CHKR_PROFILE
   tmpinfo->addressed++;
#endif      
   return;
 }
 bitmem->type = SegFinish;
 bitmem->info = &null_mapinfo;
/* bitmem->base = (uchar*)0; */
 return;
}

static void adjust_bm()
{
#ifdef CHKR_STACKBITMAP
 if (stack_bitmapped > known_stack_limit)
 {
 /* set correctly the stack bitmap */
   int bit_off;
   unsigned char *bm_offset2;
   unsigned char *bm_offset1;
   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(__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[]={ "--", " R", " W", "RW" };
 
 /* 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("No bitmap for this address.\n");
   return;
 }
 if ( (bitmem.info->type != SegStack && bitmem.bit_offset !=0) ||
      (bitmem.info->type == SegStack && bitmem.bit_offset !=3) )
   chkr_printf("Hmmm, bit_offset is not lined up !! Ignore.\n");
   
 /* 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(__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("Error while chkr_set_right\n");
   return;
 }
 /* Be sure about right. Right is 2 bits length */
 right &= 3;   
 if (len > bitmem.length || len == 0)
 {
   chkr_printf("len > bitmem.length or len == 0\n");
   return;
 }
 if (bitmem.info->type != SegStack)
 {
   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.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; 
 }
}

/* Check the right of a zone of length len, starting at ptr */
/*				rights in bitmap
 *                    +------------+-------------+-------------+-------------+
 *                    | CHKR_UN    |   CHKR_RO   |   CHKR_WO   |   CHKR_RW   |
 *       +------------+------------+-------------+-------------+-------------+
 * right |  CHKR_UN   |               not accepted                           |
 *       +------------+------------+-------------+-------------+-------------+
 *  t    |  CHKR_RO   |   error    |     OK      |    error    |     OK      |
 *  e    +------------+------------+-------------+-------------+-------------+
 *  s    |  CHKR_WO   |   error    |    error    | -> CHKR_RW  |     OK      |
 *  t    +------------+------------+-------------+-------------+-------------+
 *  e    |  CHKR_TW   |   error    |    error    |     OK      |     OK      |
 *  d    +------------+------------+-------------+-------------+-------------+
 *       |  CHKR_RW   |   error    |    error    |    error    |     OK      | 
 *       +------------+------------+-------------+-------------+-------------+
 */
void chkr_check_addr(__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 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 || len == 0)
 {
   chkr_errno = E_IE_BRIGHT;	/* bad check, must never happen */
   chkr_perror();
   chkr_abort();
 }
 /* Search info about ptr */
 SetBitMem(ptr, &bitmem);
 base = bitmem.info->bmbase;
 if (bitmem.info->type == SegFinish || bitmem.info->type == SegVoid)
 {
   chkr_access_error(ptr, right, &bitmem, 0);
   return;
 }
 /* Inside the text segment ? */
 if (bitmem.info->type == SegText)
 {
   if (!is_text_writable)
     if (right != CHKR_RO)
       chkr_access_error(ptr, right, &bitmem, 0);
   return;
 }
 if (bitmem.info->type != SegStack)
 {
   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);
       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);
         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);
     return;	/* check fails */
   }
   if (right1 == CHKR_WO)
     base[bitmem.bm_offset] |= mask;
   return;
 } 
 else
 {
   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);
       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);
         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);
     return;	/* check fails */
   }
   if (right1 == CHKR_WO)
     base[bitmem.bm_offset] |= mask;
   return; 
 }
}

/* Check for a string.
   Is this implementation poor ? */
void chkr_check_str(__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.type != SegNormal || bmsrc.length < len)
  {
    chkr_printf("Error with src in chkr_copy_bm\n");
    return;
  }
  SetBitMem(dest, &bmdest);
  if(bmdest.type != SegNormal || bmdest.length < len)
  {
    chkr_printf("Error with dest in chkr_copy_bm\n");
    return;
  }  
  if(bmsrc.bit_offset != 0 || bmdest.bit_offset != 0)
  {
    chkr_printf("Bad alignment in chkr_copy_bm\n");
    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("Here are profile informations:\n");
 while(tmpinfo->type != SegFinish)
 {
   chkr_printf("The %s was handled (addressed) %d time%s.\n", tmpinfo->name, 
   		tmpinfo->addressed, (tmpinfo->addressed > 1) ? "s" : "");
   total += tmpinfo->addressed;
   tmpinfo++;
 }
 chkr_printf("Your program handles %u times the memory.\n", total);
}
#endif

static void init_mapinfos()
{
  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 = "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 = "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 = "data segment";
  mapinfo[DATABM]->base = &etext;
  mapinfo[DATABM]->length = (int)&end - (int)&etext;
  mapinfo[DATABM]->bmbase = (uchar*)0;
  mapinfo[DATABM]->type = SegNormal;
#endif  
#ifdef CHKR_HEAPBITMAP
  /* heap 'segment' */
  mapinfo[HEAPBM]->name = "heap";
  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 = "stack";
  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
}
/**************************************************************************/
   
static __ptr_t *ptr_on_block;

static void disp_block_history(int status)
{
  if (status == 0)
    chkr_printf("Can't access to the symbol table.\n");
  else
  {
    chkr_printf("The block was allocated from:\n");
    for(; *ptr_on_block; ptr_on_block++)
      chkr_show_addr((__ptr_t)ptr_on_block);
  }
}

#ifdef CHKR_STACKBITMAP
static void chkr_access_error_stack(__ptr_t ptr)
{
 chkr_printf("known stack limit= 0x%p\n", known_stack_limit);
 chkr_printf("stack bitmaped 0x%p\n", stack_bitmapped);
 chkr_disp_right(ptr, 2);
}
#endif
 
/* Display all information */
static void chkr_access_error_heap (__ptr_t ptr)
{
  size_t block;
  __ptr_t real_ptr;	/* begin of the block */
  int type,i;
  struct list *next;

  if(ptr < (__ptr_t)_heapbase || ptr > ADDRESS(_heaplimit))
   return;	/* not inside the heap */
   
  block = BLOCK (ptr);

  /* Don't forget that ptr can point to anywhere */
  if(_heapinfo[block].status.state!=MDHEAD &&
     _heapinfo[block].status.state!=MDCORP && 
     _heapinfo[block].status.state!=MDTAIL )
  {
    chkr_printf("inside a free block.\n");
    return;	/* pointer on free block */
  }
    
  /* Search the begin of the block */
  while(_heapinfo[block].status.state!=MDHEAD)
    block--;
 
  type=_heapinfo[block].busy.type;
  
  if(type==0)
  {
    real_ptr = ADDRESS(block);	/* found the begin of the block */
    if (real_ptr == (__ptr_t)_heapinfo) 
    {
     chkr_printf("inside the heapinfo structure\n");
      return;	/* point on the _heapinfo[] structure */
    }
  }
  else
  {
   real_ptr = (__ptr_t)((unsigned int)ptr & (0xffffffff << type));
   /* Get the address of the first free fragment in this block.  */
   next = (struct list *) ((char *) ADDRESS (block) +
			   (_heapinfo[block].busy.info.frag.first << type));
		
   /* Test if this fragment is free */
   for( i=_heapinfo[block].busy.info.frag.nfree; i > 0; i--)
   {
     if(next==real_ptr)
     {
       chkr_printf("inside a free fragment\n");
       return;	/* free block */
     }
     next=next->next;
   }
  }
  if (((struct hdr_red_zone*)real_ptr)->magic != RED_ZONE_MAGIC)
  {
    chkr_printf("access error: bad magic number at block %u.\n",block);
    return;
  }
  if (ptr < (real_ptr + be_red_zone + sizeof(struct hdr_red_zone)))
    chkr_printf("%d bytes before the begin of the block\n",
		(int)(real_ptr + be_red_zone + sizeof(struct hdr_red_zone)) -
		(int)(ptr));
  else if (ptr < (real_ptr + be_red_zone + sizeof(struct hdr_red_zone) +
  			((struct hdr_red_zone*)real_ptr)->real_size) )
    chkr_printf("%d bytes after the begin of the block\n",
		(int)(ptr) -
		(int)(real_ptr + be_red_zone + sizeof(struct hdr_red_zone)));
  else
    chkr_printf("%d bytes after the end of the block\n",
    		(int)(ptr) -
    		(int)(real_ptr + be_red_zone + sizeof(struct hdr_red_zone) +
  			((struct hdr_red_zone*)real_ptr)->real_size));
#if CHKR_SAVESTACK
  ptr_on_block = (__ptr_t*)((int)real_ptr + be_red_zone + 
       	sizeof(struct hdr_red_zone) + 
       	((struct hdr_red_zone*)real_ptr)->real_size);
  chkr_use_symtab(disp_block_history);
#endif /* CHKR_SAVESTACK */  			
}

static char *right_name[]={
	"*internal error*",
	"Reading",
	"Writing",
	"modifying"};
	
static void chkr_access_error(__ptr_t ptr, int arq, struct BitMem *bm, char val)
{
#ifdef CHKR_SAVESTACK
 int must_remove = 0;
#endif /* CHKR_SAVESTACK */ 
 
 chkr_header("Memory access error\n");
 chkr_printf("When %s at address 0x%p, inside the %s.\n", right_name[arq], ptr, bm->info->name);
 if (bm->info == mapinfo[NULLBM]) 
 {
   chkr_printf("You probably use a NULL pointer.\n");
   chkr_printf("THIS SHOULD PRODUCE A SEGMENTATION FAULT.\n");
#ifdef CHKR_SAVESTACK     
   must_remove = 1;
#endif /* CHKR_SAVESTACK */
 }
 else if (bm->info == mapinfo[TEXTBM])
 {
   chkr_printf("You may not modify it.\n");
   chkr_printf("THIS WILL PRODUCE A SEGMENTATION FAULT.\n");
#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_show_frames();
 if (must_remove)
   chkr_remove_symtabfile();
#endif  /* CHKR_SAVESTACK */
}
#endif /* CHKR_USE_BITMAP */

/* with Checker, the memory map is like this:
 +---------------------------------------------------------------------------+
 | code | data | bss |  data  | heap |  heap  | stack  | >>>>   <<<< | stack |
 |      |      |     | bitmap |      | bitmap | bitmap | >>>>   <<<< |       |
 +---------------------------------------------------------------------------+
 0    &etext       &end                              sbrk(0)        %esp    
*/

#include <limits.h>
#include <stddef.h>
#include "malloc.h"
#include "chkrlib.h"

static __ptr_t safe_sbrk(int incr);

#ifdef CHKR_HEAPBITMAP
__ptr_t chkr_heap_begin;
static __ptr_t heap_end;
static __ptr_t real_heap_end;
unsigned char *chkr_heap_bitmap;
static int heap_bitmap_size;
#endif /* CHKR_HEAPBITMAP */

#ifdef CHKR_DATABITMAP
unsigned char *chkr_data_bitmap;
static int data_bitmap_size;
#endif /* CHKR_DATABITMAP */

#ifdef CHKR_STACKBITMAP
unsigned char *chkr_stack_bitmap;
static int stack_bitmap_size;
#endif /* CHKR_STACKBITMAP */

int bm_round;			/* number of bytes per byte of bitmap -1 */
int bm_log_size;
static int initialized;

#ifdef CHKR_USE_BITMAP
void init_morecore()
{
 void *result;
 
 if (initialized)
   return;	/* because, init_morecore can be called by __chkr_init_chkr */
 
 /* initialisation */
 if (bytes_per_state == 0)	/* Can't be used */
 {
    chkr_errno = E_BADBYTEPS;	/* error: bad bytes per state */
    chkr_perror();
    bytes_per_state = 1;	/* default value */
 }
 while (bytes_per_state != 1)
 {
   bm_log_size++;
   bytes_per_state >>= 1;
 }
 bytes_per_state = 1 << bm_log_size;
 bm_log_size += 2;
 bm_round = (1 << bm_log_size) -1;
 init_mapinfos();
#ifdef CHKR_DATABITMAP
 result = sbrk(0);
 data_bitmap_size = (result - (__ptr_t)&etext + bm_round) >> bm_log_size;
 chkr_data_bitmap = sbrk((data_bitmap_size + 0x10) & (~0x0f)); /* alignment */
 if (chkr_data_bitmap == (__ptr_t)-1)
   chkr_data_bitmap = NULL;	/* Won't be checked */
 memset(chkr_data_bitmap, 0xff, data_bitmap_size);
 mapinfo[DATABM]->length = data_bitmap_size << bm_log_size;
 mapinfo[DATABM]->bmbase = chkr_data_bitmap;
#endif /* CHKR_DATABITMAP */
#ifdef CHKR_HEAPBITMAP
 chkr_heap_begin = heap_end = sbrk(0); /* Can sbrk(0) return -1 ??? */
 chkr_heap_bitmap = heap_end;
 heap_bitmap_size = 0;
 mapinfo[HEAPBM]->base = chkr_heap_begin;
 mapinfo[HEAPBM]->length = heap_bitmap_size << bm_log_size;
 mapinfo[HEAPBM]->bmbase = chkr_heap_bitmap;
#endif /* CHKR_HEAPBITMAP */
#ifdef CHKR_STACKBITMAP
 known_stack_limit = stack_bitmapped = &result;
 stack_bitmap_size = (STACK_LIMIT - (int)(&result) + bm_round) >> bm_log_size;
 chkr_stack_bitmap = sbrk(stack_bitmap_size + 1);
 if (chkr_stack_bitmap == (__ptr_t)-1)
   chkr_stack_bitmap = NULL;
 /* Rights are set to read/write */
 memset(chkr_stack_bitmap, 0xff, stack_bitmap_size);
 mapinfo[STACKBM]->base = (uchar*)STACK_LIMIT;
 mapinfo[STACKBM]->length = stack_bitmap_size << bm_log_size;
 mapinfo[STACKBM]->bmbase = chkr_stack_bitmap;
#endif
 real_heap_end = sbrk(0);
 initialized = 1;	/* don't forget this !!! */
}
#endif /* CHKR_USE_BITMAP */

/* sbrk() return the old break address. ie brk(0) == brk(100) */
/* Note that morecore has to take a signed argument so
   that negative values can return memory to the system. */
void *
__default_morecore(int size)
{
 void *result;
#ifdef CHKR_HEAPBITMAP 
 int size1;
#endif /* CHKR_HEAPBITMAP */

#ifdef CHKR_USE_BITMAP
 if(!initialized)
   init_morecore();
#endif /* CHKR_USE_BITMAP */

#if !defined(CHKR_HEAPBITMAP)
 /* really stupid morecore */
 result = sbrk(size);
 if (result == (void *) -1)
   return NULL;
 return result;
#else
 if (size == 0)
 {
   safe_sbrk(0);
   return heap_end;	/* morecore(0) cheats the caller... */
 }
 if (size > 0)
 {
   /* We must grow the bitmap */
   size1 = (size + bm_round) >> bm_log_size;
   
   result = safe_sbrk(size + size1);
   if (result == NULL)
     return NULL;
#ifdef CHKR_STACKBITMAP
   /* Move the stack bitmap */
   memmove(chkr_stack_bitmap + size + size1, chkr_stack_bitmap, stack_bitmap_size);
   chkr_stack_bitmap += size + size1;
   mapinfo[STACKBM]->bmbase = chkr_stack_bitmap;
#endif        
   /* Move the bitmap */
   memmove(chkr_heap_bitmap + size, chkr_heap_bitmap, heap_bitmap_size);
   /* initialize the new bitmap */
   chkr_heap_bitmap += size;   
   mapinfo[HEAPBM]->bmbase = chkr_heap_bitmap;
   memset(chkr_heap_bitmap + heap_bitmap_size, 0, size1);
   /* Adjust the bitmap info */
   heap_bitmap_size += size1;
   mapinfo[HEAPBM]->length = heap_bitmap_size << bm_log_size;
   /* Clean the new area */
   memset(heap_end, 0, size);
   heap_end += size;
   real_heap_end += size + size1;
   return heap_end - (size /*+ size1*/);	/* return the old address */
 }
 else
 { 
   /* We must reduce the bitmap */
   size1 = (abs(size) + bm_round) >> bm_log_size;
   /* Move the heap bitmap */
   memmove(chkr_heap_bitmap + size, chkr_heap_bitmap, heap_bitmap_size - size1);
   chkr_heap_bitmap += size;   
   mapinfo[HEAPBM]->bmbase = chkr_heap_bitmap;
#ifdef CHKR_STACKBITMAP
   /* Move the stack bitmap */
   memmove(chkr_stack_bitmap + size - size1, chkr_stack_bitmap, stack_bitmap_size);
   chkr_stack_bitmap += size - size1;
   mapinfo[STACKBM]->bmbase = chkr_stack_bitmap;
#endif   
   /* return memory to the system */
   result = safe_sbrk(size - size1);
   if (result == NULL)	/* Is it possible ?? */
     return NULL;
   /* Adjust the bitmap info */
   heap_bitmap_size -= size1;
   mapinfo[HEAPBM]->length = heap_bitmap_size << bm_log_size;
   heap_end += size;
   real_heap_end += size - size1;
   return heap_end - (size /*- size1*/);	/* return the old address */
 }
#endif
}

#ifdef CHKR_STACKBITMAP
void adjust_stackbitmap(__ptr_t ptr)
{
 int diff;
 int size;
 void *result;

 size = (STACK_LIMIT - (int)ptr + bm_round) >> bm_log_size;
 if (size <= stack_bitmap_size)
  return;	/* we never reduce it */
 diff = size - stack_bitmap_size;
 result = sbrk(diff);
 real_heap_end += diff;
 stack_bitmap_size +=diff;
 mapinfo[STACKBM]->length = stack_bitmap_size << bm_log_size;
 /* no access right */
 memset(result, 0, diff);
}
#endif

#ifdef CHKR_HEAPBITMAP
static __ptr_t safe_sbrk(int incr)
{
 __ptr_t result;
 result = sbrk(incr);
 if (result == (void*)-1)	/* Is it possible ?? */
   return NULL;
#ifndef CHKR_IS_SAFE
 if (result != real_heap_end)
 {
   chkr_errno = E_CALLBRK;	/* brk(2) has been called */
   chkr_perror();	/* We can't continue. */
   chkr_abort();
 }
#endif
 return result;
}
#endif /* CHKR_HEAPBITMAP */