RangeLookup.h

Go to the documentation of this file.
00001 /*
00002  * See the dyninst/COPYRIGHT file for copyright information.
00003  * 
00004  * We provide the Paradyn Tools (below described as "Paradyn")
00005  * on an AS IS basis, and do not warrant its validity or performance.
00006  * We reserve the right to update, modify, or discontinue this
00007  * software at any time.  We shall have no obligation to supply such
00008  * updates or modifications or any other form of support to you.
00009  * 
00010  * By your use of Paradyn, you understand and agree that we (or any
00011  * other person or entity with proprietary rights in Paradyn) are
00012  * under no obligation to provide either maintenance services,
00013  * update services, notices of latent defects, or correction of
00014  * defects for Paradyn.
00015  * 
00016  * This library is free software; you can redistribute it and/or
00017  * modify it under the terms of the GNU Lesser General Public
00018  * License as published by the Free Software Foundation; either
00019  * version 2.1 of the License, or (at your option) any later version.
00020  * 
00021  * This library is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00024  * Lesser General Public License for more details.
00025  * 
00026  * You should have received a copy of the GNU Lesser General Public
00027  * License along with this library; if not, write to the Free Software
00028  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00029  */
00030 
00031 #if ! defined( RANGE_LOOKUP_H )
00032 #define RANGE_LOOKUP_H
00033 
00034 #include <map>
00035 #include <vector>
00036 #include <list>
00037 #include <assert.h>
00038 #include "dyntypes.h"
00039 #include "util.h"
00040 
00041 namespace Dyninst
00042 {
00043 namespace SymtabAPI
00044 {
00045 
00046 /* The Windows C++ compiler is broken and won't instantiate this function when it's in RangeLookup proper. */
00047 
00048 class SYMTAB_EXPORT RangeLookupImpl 
00049 {
00050     public:
00051         typedef std::pair< Offset, Offset > AddressRange;
00052 
00053         /* Explicit comparison functors seems slightly less confusing than using
00054            operator <() via an implicit Less<> template argument to the maps. */
00055 
00056         struct AddressRangeLess {
00057             bool operator()(const AddressRange &lhs, const AddressRange &rhs) const
00058             {
00059                 if ( lhs.first < rhs.first ) 
00060                 { 
00061                     return true; 
00062                 }
00063                 else if ( lhs.first == rhs.first ) 
00064                 {
00065                     if ( lhs.second < rhs.second ) 
00066                     {
00067                         return true;
00068                     }
00069                     else
00070                     {
00071                         return false; 
00072                     }
00073                 }
00074 
00075                 return false; 
00076             } /* end AddressRangeLess() */
00077         };
00078 
00079 }; /* end class RangeLookupImpl */
00080 
00081 template< class Value, class ValueLess > 
00082 class SYMTAB_EXPORT RangeLookup 
00083 {
00084     protected:
00085         typedef RangeLookupImpl::AddressRange AddressRange;
00086         typedef RangeLookupImpl::AddressRangeLess AddressRangeLess;
00087 
00088         typedef std::multimap< Value, AddressRange, ValueLess > AddressRangeByValue;
00089         typedef std::multimap< AddressRange, Value, AddressRangeLess > ValueByAddressRange;
00090 
00091     public:     
00092         typedef typename ValueByAddressRange::const_iterator const_iterator;
00093 
00094         RangeLookup();
00095 
00096         /* Values are copied: a RangeLookup considers itself the primary repository. */
00097         bool addValue( Value v, Offset lowInclusiveAddr, Offset highExclusiveAddr );
00098         bool addAddressRange( Offset lowInclusiveAddr, Offset highExclusiveAddr, Value v );
00099 
00100         /* Likewise, copies of the values are returned. */
00101         bool getValues( Offset addressInRange, std::vector< Value *> & values );
00102         bool getAddressRanges( Value v, std::vector< AddressRange > & ranges );
00103 
00104         const_iterator begin() const;
00105         const_iterator end() const;
00106 
00107         ~RangeLookup();
00108 
00109         // /* DEBUG */ void dump( FILE * stream );
00110         // /* DEBUG */ static void testInsertionSpeed();
00111 
00112     protected:
00113         ValueByAddressRange valuesByAddressRangeMap;
00114         AddressRangeByValue addressRangesByValueMap;
00115 }; /* end class RangeLookup */
00116 
00117 template< class Value, class ValueRange > RangeLookup< Value, ValueRange >::RangeLookup() :
00118     valuesByAddressRangeMap(),
00119     addressRangesByValueMap() {}
00120 
00121 /* Private refactoring function: erase()s value from map. */
00122 template< class M >
00123 bool removeByValue( M & map, const typename M::value_type & value ) 
00124 {
00125     std::pair< typename M::iterator, typename M::iterator > range = map.equal_range( value.first ); 
00126 #if 0
00127 #if ! defined( os_windows )
00128     std::pair< typename M::iterator, typename M::iterator > range = map.equal_range( value.first ); 
00129 #else
00130     std::pair< M::iterator, M::iterator > range = map.equal_range( value.first );   
00131 #endif
00132 #endif
00133 
00134     for ( ; range.first != range.second && range.first != map.end(); ++range.first ) 
00135     {
00136         typename M::value_type &cmp = *range.first;
00137         if (cmp == value ) 
00138         {
00139             map.erase( range.first );
00140             return true;
00141         }
00142     }
00143 
00144     return false;
00145     
00146 } /* end removeByValue() */
00147 
00148 /* We maintain the invariant that low and high address sort orders are the same.  (If we
00149    didn't, we could only find one of the two endpoints of the range of ranges we should
00150    check.  If we find one endpoint and iterate over the other sort order until we found
00151    the other, a range contained by another range would change the sort order and cause
00152    ranges containing the search target to be skippped.)  So we check, whenever we insert
00153    a new range, if it contains or is contained by any other range.
00154 
00155    Since we insert elements one at a time, we can assume that no range already present
00156    contains another range.  Furthermore, if no range contains another range, then any
00157    range (B) between the inserted range (I) and a range which might contain it (A)
00158    must also contain I.  (Where ranges are ordered by their low address.)
00159 
00160    (Proof by contradiction: suppose there exists a B not containing I.  Because B is between
00161    I and A, B's low address is lower than I's.  Therefore, because B does not contain I, its
00162    high address must be lower than I's.  Because I is contained by A, its high address is
00163    lower than A's.  By transitivity, B's high address is lower than A's.  Since B's low
00164    address is higher than A's (because B is between A and I), B is contained by A.  Contradiction.)
00165 
00166    Therefore, we only need to check ranges lower than I until one of them does not contain it.
00167    If we split each containing range in the middle of I, we can insert I and maintain our
00168    no-overlap invariant.
00169 
00170    Similar logic applies in reverse direction: if I contains a range, it contains every
00171    range between it and I.
00172 
00173    Furthermore, the same range can't be both contained and contained-by: if it's contained-by,
00174    its container contains whatever it does.
00175 
00176    We want to split ranges so that their low and high addresses sort in the same order.  (Strictly
00177    speaking, the above conditions ought to be "not a range which will cause the low and high address
00178    sort order to be different, but it ends up not mattering, AFAICT.)
00179 
00180    If we're inserting a contained range, we split the containing ranges on the contained range's right edge.
00181 
00182    If we're inserted a containing range, we split it and the other ranges on the least upper address in
00183    each group of contained ranges.
00184  */
00185 
00186 template <class Value, class ValueRange> 
00187 bool RangeLookup< Value, ValueRange >::addValue(Value v, 
00188         Offset lowInclusiveAddr, 
00189         Offset highExclusiveAddr) 
00190 {
00191     /* Verify the input. */
00192     if ( lowInclusiveAddr >= highExclusiveAddr ) 
00193     { 
00194         return false; 
00195     }
00196 
00197     /* If we've already got this range, it's safe to insert it. */
00198 
00199     typedef typename ValueByAddressRange::iterator RangeIterator;
00200     std::pair< RangeIterator, RangeIterator > rangeOfRanges;
00201 
00202     rangeOfRanges = valuesByAddressRangeMap.equal_range(AddressRange(lowInclusiveAddr, 
00203                 highExclusiveAddr));
00204 
00205     if (   (rangeOfRanges.first != rangeOfRanges.second) 
00206             || (valuesByAddressRangeMap.size() == 0) ) 
00207     {
00208         // insert() is amortized constant time if the new value is inserted 
00209         // immediately before the hint. 
00210 
00211         valuesByAddressRangeMap.insert( rangeOfRanges.second, 
00212                 std::make_pair(AddressRange(lowInclusiveAddr, 
00213                         highExclusiveAddr), v));
00214 
00215         addressRangesByValueMap.insert( std::make_pair( v, AddressRange(lowInclusiveAddr, 
00216                         highExclusiveAddr)));
00217         return true;
00218     }
00219 
00220     /* Otherwise, we need to look for containing ranges. */
00221 
00222     typedef std::pair< AddressRange, Value > Range;
00223     typedef std::list< Range > RangeList;
00224     RangeIterator downIterator = rangeOfRanges.second;
00225 
00226     if (rangeOfRanges.second != valuesByAddressRangeMap.begin()) 
00227     {
00228         --downIterator; 
00229     }
00230 
00231     RangeList containingRangeList;
00232     for (; ( (downIterator->first.first <= lowInclusiveAddr)
00233                 && (highExclusiveAddr < downIterator->first.second) )
00234             ; --downIterator ) 
00235     {
00236 
00237         // /* DEBUG */ fprintf( stderr, "%s[%d]: found containing range [0x%lx, 0x%lx) while inserting [0x%lx, 0x%lx) (%s, %d)\n", __FILE__, __LINE__, downIterator->first.first, downIterator->first.second, lowInclusiveAddr, highExclusiveAddr, lineSourceInternal, lineNo );
00238 
00239         containingRangeList.push_back( * downIterator );
00240 
00241         if ( downIterator == valuesByAddressRangeMap.begin() ) 
00242             break; 
00243     }
00244 
00245     /* We also need to look for contained ranges. */    
00246     RangeIterator upIterator = rangeOfRanges.second;    
00247     RangeList containedRangeList;
00248 
00249     for (; (upIterator != valuesByAddressRangeMap.end()) 
00250             && ((lowInclusiveAddr <= upIterator->first.first)
00251                 && (upIterator->first.second < highExclusiveAddr) )
00252             ; ++upIterator ) 
00253     {
00254 
00255         // /* DEBUG */ fprintf( stderr, "%s[%d]: found contained range [0x%lx, 0x%lx) while inserting [0x%lx, 0x%lx) (%s, %d)\n", __FILE__, __LINE__, upIterator->first.first, upIterator->first.second, lowInclusiveAddr, highExclusiveAddr, lineSourceInternal, lineNo );
00256 
00257         containedRangeList.push_back( * upIterator );
00258     } /* end iteration looking for contained ranges */
00259 
00260     if (containingRangeList.size() == 0 && containedRangeList.size() == 0 ) 
00261     {
00262         /* insert() is amortized constant time if the new value is inserted immediately before the hint. */
00263         valuesByAddressRangeMap.insert(rangeOfRanges.second, 
00264                 std::make_pair(AddressRange(lowInclusiveAddr, 
00265                         highExclusiveAddr), v));
00266         addressRangesByValueMap.insert( std::make_pair(v,AddressRange(lowInclusiveAddr, 
00267                         highExclusiveAddr)));
00268         return true;
00269     }
00270 
00271     /* TODO: combine lists; if wasContaining, splitaddrlist is just highExclusiveAddr */
00272 
00273     if (containingRangeList.size() != 0) 
00274     {
00275         Offset splitAddress = highExclusiveAddr;
00276 
00277         /* Remove the old (containing) ranges, split them, insert the new ones. */
00278         typename RangeList::const_iterator containingIterator = containingRangeList.begin();
00279 
00280         for ( ; containingIterator != containingRangeList.end(); ++containingIterator ) 
00281         {
00282             AddressRange ar = containingIterator->first;
00283             Value lnt = containingIterator->second;
00284 
00285             // /* DEBUG */ fprintf( stderr, "%s[%d]: removing range [0x%lx, 0x%lx) (%s, %u)...\n", __FILE__, __LINE__, ar.first, ar.second, lnt.first, lnt.second );
00286 
00287             assert( removeByValue( valuesByAddressRangeMap, * containingIterator ) );
00288             assert( removeByValue( addressRangesByValueMap, std::make_pair( lnt, ar ) ) );
00289 
00290             // /* DEBUG */ fprintf( stderr, "%s[%d]: ... done removing range [0x%lx, 0%lx) (%s, %u)\n", __FILE__, __LINE__, ar.first, ar.second, lnt.first, lnt.second );
00291             // /* DEBUG */ fprintf( stderr, "%s[%d]: inserting range [0x%lx, 0x%lx) (%s, %u)\n", __FILE__, __LINE__, ar.first, splitAddress, lnt.first, lnt.second );
00292 
00293             valuesByAddressRangeMap.insert(std::make_pair(AddressRange(ar.first, 
00294                             splitAddress), lnt));
00295             addressRangesByValueMap.insert( std::make_pair(lnt,AddressRange(ar.first, 
00296                             splitAddress)));
00297 
00298             // /* DEBUG */ fprintf( stderr, "%s[%d]: inserting range [0x%lx, 0x%lx) (%s, %u)\n", __FILE__, __LINE__, splitAddress, ar.second, lnt.first, lnt.second );
00299 
00300             valuesByAddressRangeMap.insert(std::make_pair(AddressRange(splitAddress, 
00301                             ar.second ), lnt ) );
00302             addressRangesByValueMap.insert(std::make_pair(lnt, AddressRange(splitAddress, 
00303                             ar.second ) ) );
00304         } /* end removes/split/insert iteration */
00305 
00306         // /* DEBUG */ fprintf( stderr, "%s[%d]: inserting new range [0x%lx, 0x%lx) (%s, %u)\n\n", __FILE__, __LINE__, lowInclusiveAddr, highExclusiveAddr, lineSourceInternal, lineNo );
00307 
00308         /* Insert the new range. */
00309         valuesByAddressRangeMap.insert(std::make_pair(AddressRange(lowInclusiveAddr, 
00310                         highExclusiveAddr ), v ) );
00311         addressRangesByValueMap.insert(std::make_pair(v, AddressRange(lowInclusiveAddr, 
00312                         highExclusiveAddr ) ) );
00313         return true;
00314     } /* end if the range to be inserted is contained by other ranges. */
00315 
00316     if (containedRangeList.size() != 0 ) 
00317     {
00318         /* We'll split the ranges at these points. */
00319         typedef std::list< Offset > AddressList;
00320         AddressList splitAddressList;
00321 
00322         /* Overlapping ranges overlap until a discontuity, so we only need to
00323            know about one of them. */
00324 
00325         typename RangeList::const_iterator containedIterator = containedRangeList.begin();
00326         Offset splitAddress = containedIterator->first.second;
00327         ++containedIterator;
00328 
00329         for ( ; containedIterator != containedRangeList.end(); ++containedIterator ) 
00330         {
00331             /* Is there a discontinuity? */
00332 
00333             if (containedIterator->first.first >= splitAddress) 
00334             {
00335                 // /* DEBUG */ fprintf( stderr, "%s[%d]: will split at 0x%lx\n", __FILE__, __LINE__, splitAddress );
00336 
00337                 /* If there is, our current splitAddress should be a split, */
00338                 splitAddressList.push_back( splitAddress );             
00339 
00340                 /* and the high end of the next contained range will be our next split point. */
00341                 splitAddress = containedIterator->first.second;             
00342             }
00343             else 
00344             {
00345                 splitAddress = containedIterator->first.second; 
00346             }
00347         } /* end split point determination iteration */
00348 
00349         // /* DEBUG */ fprintf( stderr, "%s[%d]: will split at 0x%lx\n", __FILE__, __LINE__, splitAddress );
00350 
00351         splitAddressList.push_back( splitAddress );
00352 
00353         /* Split the range to be inserted. */
00354 
00355         Offset lowAddress = lowInclusiveAddr;
00356         AddressList::const_iterator splitAddressIterator = splitAddressList.begin();
00357         Offset highAddress = 0;
00358 
00359         for ( ; splitAddressIterator != splitAddressList.end(); ++ splitAddressIterator ) 
00360         {
00361             highAddress = * splitAddressIterator;
00362 
00363             // /* DEBUG */ fprintf( stderr, "%s[%d]: inserting range [0x%lx, 0x%lx) (%s, %u)\n", __FILE__, __LINE__, lowAddress, highAddress, lnt.first, lnt.second );
00364 
00365             valuesByAddressRangeMap.insert(std::make_pair(AddressRange(lowAddress, highAddress ), v ) );
00366             addressRangesByValueMap.insert(std::make_pair(v, AddressRange(lowAddress, highAddress ) ) );
00367 
00368             lowAddress = highAddress;
00369         } /* end iteration to split range to be inserted. */
00370 
00371         // /* DEBUG */ fprintf( stderr, "%s[%d]: inserting range [0x%lx, 0x%lx) (%s, %u)\n", __FILE__, __LINE__, highAddress, highExclusiveAddr, lnt.first, lnt.second );
00372 
00373         valuesByAddressRangeMap.insert(std::make_pair(AddressRange( highAddress, highExclusiveAddr ), v ) );
00374         addressRangesByValueMap.insert(std::make_pair(v, AddressRange( highAddress, highExclusiveAddr ) ) );    
00375 
00376         /* We done did it. */
00377         return true;
00378     } /* end if the range to be inserted contains other ranges. */
00379 
00380     /* Something Terrible happened. */
00381     return false;
00382 } /* end addValue() */
00383 
00384 template< class Value, class ValueRange > 
00385 bool RangeLookup< Value, ValueRange >::addAddressRange( Offset lowInclusiveAddr, 
00386         Offset highExclusiveAddr, 
00387         Value v ) 
00388 {
00389     return addValue( v, lowInclusiveAddr, highExclusiveAddr );
00390 } /* end addAddressRange() */
00391 
00392 
00393 /*  We maintain the invariant that the ranges sort in the same order on
00394     their low and high addresses.  In this case, we only need to search from
00395     the range whose low address is the least too large down to the range
00396     whose high address is the first too small to find all ranges which
00397     contain the desired address.    
00398  */    
00399 template< class Value, class ValueRange > 
00400 bool RangeLookup< Value, ValueRange >::getValues( Offset addressInRange, 
00401         std::vector< Value *> & values ) 
00402 {
00403     /* We can't find an address if we have no ranges. */
00404     if ( valuesByAddressRangeMap.size() == 0 ) 
00405         return false;
00406 
00407     /* Because the sort order of the low and high addresses is the same, we know every range
00408        which could contain addressInRange must be below the range whose low address is one
00409        larger, and above the range whose high address is the same.  We use addressInRange + 1
00410        to make sure we find one past the end of a span of ranges with the same low address,
00411        so we decrement the iterator to point it at the first range which could contain
00412        addressInRange.  If equal_range() returns end(), then decrementing the iterator
00413        ensures we start checking with a real range. */
00414 
00415     typedef typename ValueByAddressRange::const_iterator RangeIterator;
00416     std::pair< RangeIterator, RangeIterator > lowRange 
00417         = valuesByAddressRangeMap.equal_range( AddressRange( addressInRange + 1, 0 ) );
00418 
00419     if (lowRange.second == valuesByAddressRangeMap.begin())
00420         return false; //Searched for an address lower than any in the map.
00421 
00422     assert( lowRange.first == lowRange.second );
00423     RangeIterator hHighEnd = --(lowRange.second);
00424 
00425     /* Some implementations get stuck on valuesByAddressRangeMap.begin(), apparently. */
00426 
00427     for ( ; hHighEnd->first.second > addressInRange && hHighEnd != valuesByAddressRangeMap.end();
00428             --hHighEnd ) 
00429     {
00430         if (   (hHighEnd->first.first <= addressInRange)
00431                 && (addressInRange < hHighEnd->first.second) ) 
00432         {
00433             values.push_back( const_cast<Value *> (& hHighEnd->second) );
00434         }
00435 
00436         if (hHighEnd == valuesByAddressRangeMap.begin() ) 
00437             break; 
00438     } /* end iteration over possible range matches. */
00439 
00440     if ( values.size() == 0 ) 
00441         return false; 
00442 
00443     return true;
00444 } /* end getLinesFromAddress() */
00445 
00446 template< class Value, class ValueRange > 
00447 bool RangeLookup< Value, ValueRange >::getAddressRanges(Value v, 
00448         std::vector<AddressRange> &ranges) 
00449 {
00450     /* Look for the specified lineSource:lineNo. */
00451     typedef typename AddressRangeByValue::const_iterator IteratorType;
00452     std::pair< IteratorType, IteratorType > range = addressRangesByValueMap.equal_range( v );
00453 
00454     /* If equal_range() doesn't find anything, range.first and range.second will be equal. */
00455 
00456     if ( range.first == range.second ) 
00457     {
00458         return false;
00459     }
00460 
00461     /* Otherwise, copy out the found ranges. */
00462     for ( IteratorType i = range.first; i != range.second; ++i ) 
00463     {
00464         //    ranges.push_back( AddressRange(i->second));
00465         ranges.push_back(i->second);
00466     } /* end iteration over located address ranges. */
00467 
00468     return true;
00469 } /* end getAddressRangesFromLine() */
00470 
00471 template< class Value, class ValueRange > 
00472 typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::begin() const 
00473 {
00474     return valuesByAddressRangeMap.begin();
00475 } /* end begin() */
00476 
00477 template< class Value, class ValueRange > 
00478 typename RangeLookup< Value, ValueRange >::const_iterator RangeLookup< Value, ValueRange >::end() const 
00479 {
00480     return valuesByAddressRangeMap.end();
00481 } /* end begin() */
00482 
00483 template< class Value, class ValueRange > 
00484 RangeLookup< Value, ValueRange >::~RangeLookup() 
00485 {
00486 } /* end RangeLookup destructor */
00487 
00488 
00489 } //  namespace SymtabAPI
00490 } // namespace Dyninst
00491 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 12 Jul 2013 for SymtabAPI by  doxygen 1.6.1