/*--------------------------------------------------------------------*/ /*--- 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, see . The GNU General Public License is contained in the file COPYING. */ /* Contributed by Julian Seward */ #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 ---*/ /*--------------------------------------------------------------------*/