/*--------------------------------------------------------------------*/
/*--- A mapping where the keys exactly cover the address space. ---*/
/*--- m_rangemap.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2014-2017 Mozilla Foundation
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 program 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; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
/* Contributed by Julian Seward <jseward@acm.org> */
#include "pub_core_basics.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcprint.h"
#include "pub_core_xarray.h"
#include "pub_core_rangemap.h" /* self */
/* See pub_tool_rangemap.h for details of what this is all about. */
#define UWORD_MIN ((UWord)0)
#define UWORD_MAX (~(UWord)0)
typedef
struct { UWord key_min; UWord key_max; UWord val; }
Range;
struct _RangeMap {
Alloc_Fn_t alloc_fn; /* alloc fn (nofail) */
const HChar* cc; /* cost centre for alloc */
Free_Fn_t free_fn; /* free fn */
XArray* ranges;
};
/* fwds */
static void preen (/*MOD*/RangeMap* rm);
static Word find ( const RangeMap* rm, UWord key );
static void split_at ( /*MOD*/RangeMap* rm, UWord key );
static void show ( const RangeMap* rm );
RangeMap* VG_(newRangeMap) ( Alloc_Fn_t alloc_fn,
const HChar* cc,
Free_Fn_t free_fn,
UWord initialVal )
{
/* check user-supplied info .. */
vg_assert(alloc_fn);
vg_assert(free_fn);
RangeMap* rm = alloc_fn(cc, sizeof(RangeMap));
rm->alloc_fn = alloc_fn;
rm->cc = cc;
rm->free_fn = free_fn;
rm->ranges = VG_(newXA)( alloc_fn, cc, free_fn, sizeof(Range) );
/* Add the initial range */
Range r;
r.key_min = UWORD_MIN;
r.key_max = UWORD_MAX;
r.val = initialVal;
Word i = VG_(addToXA)(rm->ranges, &r);
vg_assert(i == 0);
vg_assert(VG_(sizeXA)(rm->ranges) == 1);
/* */
return rm;
}
void VG_(deleteRangeMap) ( RangeMap* rm )
{
vg_assert(rm);
vg_assert(rm->free_fn);
vg_assert(rm->ranges);
VG_(deleteXA)(rm->ranges);
rm->free_fn(rm);
}
void VG_(bindRangeMap) ( RangeMap* rm,
UWord key_min, UWord key_max, UWord val )
{
vg_assert(key_min <= key_max);
split_at(rm, key_min);
if (key_max < UWORD_MAX)
split_at(rm, key_max + 1);
Word iMin, iMax, i;
iMin = find(rm, key_min);
iMax = find(rm, key_max);
for (i = iMin; i <= iMax; i++) {
Range* rng = VG_(indexXA)(rm->ranges, i);
rng->val = val;
}
preen(rm);
}
void VG_(lookupRangeMap) ( /*OUT*/UWord* key_min, /*OUT*/UWord* key_max,
/*OUT*/UWord* val, const RangeMap* rm, UWord key )
{
Word i = find(rm, key);
Range* rng = (Range*)VG_(indexXA)(rm->ranges, i);
*key_min = rng->key_min;
*key_max = rng->key_max;
*val = rng->val;
}
UInt VG_(sizeRangeMap) ( const RangeMap* rm )
{
vg_assert(rm && rm->ranges);
Word size = VG_(sizeXA)(rm->ranges);
vg_assert(size >= 0);
return size;
}
void VG_(indexRangeMap) ( /*OUT*/UWord* key_min, /*OUT*/UWord* key_max,
/*OUT*/UWord* val, const RangeMap* rm, Word ix )
{
vg_assert(rm && rm->ranges);
Range* rng = (Range*)VG_(indexXA)(rm->ranges, ix);
*key_min = rng->key_min;
*key_max = rng->key_max;
*val = rng->val;
}
/* Helper functions, not externally visible. */
static void preen (/*MOD*/RangeMap* rm)
{
Word i;
XArray* ranges = rm->ranges;
for (i = 0; i < VG_(sizeXA)(ranges) - 1; i++) {
Range* rng0 = VG_(indexXA)(ranges, i+0);
Range* rng1 = VG_(indexXA)(ranges, i+1);
if (rng0->val != rng1->val)
continue;
rng0->key_max = rng1->key_max;
VG_(removeIndexXA)(ranges, i+1);
/* Back up one, so as not to miss an opportunity to merge with
the entry after this one. */
i--;
}
}
static Word find ( const RangeMap* rm, UWord key )
{
XArray* ranges = rm->ranges;
Word lo = 0;
Word hi = VG_(sizeXA)(ranges);
while (True) {
/* The unsearched space is lo .. hi inclusive */
if (lo > hi) {
/* Not found. This can't happen. */
VG_(core_panic)("RangeMap::find: not found");
/*NOTREACHED*/
return -1;
}
Word mid = (lo + hi) / 2;
Range* mid_rng = (Range*)VG_(indexXA)(ranges, mid);
UWord key_mid_min = mid_rng->key_min;
UWord key_mid_max = mid_rng->key_max;
if (key < key_mid_min) { hi = mid-1; continue; }
if (key > key_mid_max) { lo = mid+1; continue; }
return mid;
}
}
static void split_at ( /*MOD*/RangeMap* rm, UWord key )
{
XArray* ranges = rm->ranges;
Word i = find(rm, key);
Range rng_i0 = *(Range*)VG_(indexXA)( ranges, i+0 );
if (rng_i0.key_min == key)
return;
VG_(insertIndexXA)( ranges, i+1, &rng_i0 );
/* The insert could have relocated the payload, hence the
re-indexing of i+0 here. */
Range* rng_i0p = (Range*)VG_(indexXA)( ranges, i+0 );
Range* rng_i1p = (Range*)VG_(indexXA)( ranges, i+1 );
rng_i0p->key_max = key-1;
rng_i1p->key_min = key;
}
__attribute__((unused))
static void show ( const RangeMap* rm )
{
Word i;
VG_(printf)("<< %ld entries:\n", VG_(sizeXA)(rm->ranges) );
for (i = 0; i < VG_(sizeXA)(rm->ranges); i++) {
Range* rng = (Range*)VG_(indexXA)(rm->ranges, i);
VG_(printf)(" %016llx %016llx --> 0x%llx\n",
(ULong)rng->key_min, (ULong)rng->key_max, (ULong)rng->val);
}
VG_(printf)(">>\n");
}
/*--------------------------------------------------------------------*/
/*--- end m_rangemap.c ---*/
/*--------------------------------------------------------------------*/