diff --git a/src/core/util/CMakeLists.txt b/src/core/util/CMakeLists.txt index d3f4d81b..b03de716 100644 --- a/src/core/util/CMakeLists.txt +++ b/src/core/util/CMakeLists.txt @@ -37,8 +37,8 @@ find_package(Protobuf REQUIRED) include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) -# required by Synchronized*.cc: -find_package(Boost 1.42 COMPONENTS thread regex system REQUIRED) +# required by Synchronized*.cc, MemoryMap.* (needs icl, which came with 1.46): +find_package(Boost 1.46 COMPONENTS thread regex system REQUIRED) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) @@ -74,3 +74,7 @@ if (BUILD_LLVM_DISASSEMBLER) add_subdirectory(llvmdisassembler) endif (BUILD_LLVM_DISASSEMBLER) +### Tests +add_executable(memorymap-test testing/memorymap-test.cc) +target_link_libraries(memorymap-test fail-util) +add_test(NAME memorymap-test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testing COMMAND memorymap-test) diff --git a/src/core/util/MemoryMap.cc b/src/core/util/MemoryMap.cc index 1855bd3d..4429cf1b 100644 --- a/src/core/util/MemoryMap.cc +++ b/src/core/util/MemoryMap.cc @@ -37,9 +37,12 @@ bool MemoryMap::writeToFile(char const * const filename) return false; } - for (iterator it = begin(); it != end(); ++it) { - file << *it << "\t1\n"; +#ifndef __puma + for (address_set::iterator it = as.begin(); + it != as.end(); ++it) { + file << it->lower() << " " << (it->upper() - it->lower() + 1) << "\n"; } +#endif return true; } diff --git a/src/core/util/MemoryMap.hpp b/src/core/util/MemoryMap.hpp index dca92c94..923e8446 100644 --- a/src/core/util/MemoryMap.hpp +++ b/src/core/util/MemoryMap.hpp @@ -1,12 +1,13 @@ #ifndef __MEMORYMAP_HPP__ #define __MEMORYMAP_HPP__ -#ifdef BOOST_1_46_OR_NEWER +#ifndef __puma +#include +#include #include -using namespace boost::icl; #endif -#include +#include #include "sal/SALConfig.hpp" @@ -17,62 +18,78 @@ namespace fail { * An efficient container for memory maps with holes. */ class MemoryMap { +#ifndef __puma private: -#ifdef BOOST_1_46_OR_NEWER - typedef interval::type address_interval; - typedef interval_set::type address_set; + typedef boost::icl::discrete_interval::type address_interval; + typedef boost::icl::interval_set::type address_set; address_set as; + public: - MemoryMap() { } - void clear() { as.clear(); } - void add(address_t addr, int size) { as.add(address_interval(addr, addr+size-1)); } - void isMatching(address_t addr, int size) { return intersects(as, address_interval(addr, addr+size-1)); } + /** + * The (STL-style) iterator of this class used to iterate over all + * addresses in this map. + */ + typedef address_set::element_iterator iterator; +#else +public: + typedef int const* iterator; #endif - std::set as; + public: - MemoryMap() { } /** * Clears the map. */ - void clear() { as.clear(); } + void clear() + { +#ifndef __puma + as.clear(); +#endif + } + /** * Adds one or a sequence of addresses to the map. */ void add(address_t addr, int size = 1) { - for (int i = 0; i < size; ++i) { - as.insert(addr + i); - } +#ifndef __puma + as.add(boost::icl::construct(addr, addr + size - 1, boost::icl::interval_bounds::closed())); +#endif } + /** * Determines whether a given memory access at address \a addr with width * \a size hits the map. */ bool isMatching(address_t addr, int size = 1) { - for (int i = 0; i < size; ++i) { - if (as.find(addr + i) != as.end()) { - return true; - } - } - return false; +#ifndef __puma + return boost::icl::intersects(as, boost::icl::construct(addr, addr + size - 1, boost::icl::interval_bounds::closed())); +#endif } - /** - * The (STL-style) iterator of this class used to iterate over all - * addresses in this map. - */ - typedef std::set::iterator iterator; + /** * Returns an (STL-style) iterator to the beginning of the internal data * structure. */ - iterator begin() { return as.begin(); } + iterator begin() + { +#ifndef __puma + return boost::icl::elements_begin(as); +#endif + } + /** * Returns an (STL-style) iterator to the end of the interal data * structure. */ - iterator end() { return as.end(); } + iterator end() + { +#ifndef __puma + return boost::icl::elements_end(as); +#endif + } + /** * Loads a memory map from a file and merges it with the current state. * @@ -91,6 +108,14 @@ public: * to a long list of single-byte addresses. */ bool writeToFile(char const * const filename); + + // debugging + void dump(std::ostream& os) + { +#ifndef __puma + os << as << std::endl; +#endif + } }; } // end-of-namespace: fail diff --git a/src/core/util/testing/memorymap-test.cc b/src/core/util/testing/memorymap-test.cc new file mode 100644 index 00000000..ba8cc4ab --- /dev/null +++ b/src/core/util/testing/memorymap-test.cc @@ -0,0 +1,128 @@ +#include +#include +#include +#include "util/MemoryMap.hpp" + +using namespace fail; +using std::cerr; +using std::endl; + +#define LEN(arr) (sizeof(arr)/sizeof(*arr)) + +// start, size, start, size, ... +uint32_t inside[] = { 10, 5, 11, 1, 12, 1, 15, 1, 17, 1, 19, 1, 18, 2, 23, 2, 22, 1, 21, 1 }; +uint32_t outside[] = { 0, 10, 16, 1, 20, 1, 25, 10 }; + +void test_failed(std::string msg) +{ + cerr << "MemoryMap test failed (" << msg << ")!" << endl; +} + +// pass by value intentional +void test(MemoryMap mm) +{ + std::stringstream ss; + for (unsigned i = 0; i < LEN(inside); i += 2) { + uint32_t start = inside[i], size = inside[i+1]; + uint32_t end = start + size; + + if (!mm.isMatching(start, size)) { + ss << "1 " << start << " " << size; + test_failed(ss.str()); + ss.str(""); + } + + for (; start < end; ++start) { + if (!mm.isMatching(start)) { + ss << "2 " << start; + test_failed(ss.str()); + ss.str(""); + } + } + } + for (unsigned i = 0; i < LEN(outside); i += 2) { + uint32_t start = outside[i], size = outside[i+1]; + uint32_t end = start + size; + + if (mm.isMatching(start, size)) { + ss << "3 " << start << " " << size; + test_failed(ss.str()); + ss.str(""); + } + + for (; start < end; ++start) { + if (mm.isMatching(start)) { + ss << "4 " << start; + test_failed(ss.str()); + ss.str(""); + } + } + } + for (MemoryMap::iterator it = mm.begin(); it != mm.end(); ++it) { + cerr << *it << " "; + bool found = false; + for (unsigned i = 0; i < LEN(inside); i += 2) { + uint32_t start = inside[i], size = inside[i+1]; + uint32_t end = start + size; + if (*it >= start && *it < end) { + found = true; + break; + } + } + if (!found) { + ss << "5 " << *it; + test_failed(ss.str()); + ss.str(""); + } + found = false; + for (unsigned i = 0; i < LEN(outside); i += 2) { + uint32_t start = outside[i], size = outside[i+1]; + uint32_t end = start + size; + if (*it >= start && *it < end) { + found = true; + break; + } + } + if (found) { + ss << "6 " << *it; + test_failed(ss.str()); + ss.str(""); + } + } + cerr << "Test finished" << endl; +} + +int main() +{ + MemoryMap mm; + char const *filename_tmp = "tmp.memorymap"; + char const *filename_test1 = "test1.memorymap"; + char const *filename_test2 = "test2.memorymap"; + + for (unsigned i = 0; i < LEN(inside); i += 2) { + mm.add(inside[i], inside[i+1]); + } + mm.dump(cerr); + + test(mm); + + mm.writeToFile(filename_tmp); + mm.clear(); + mm.readFromFile(filename_tmp); + + mm.dump(cerr); + + test(mm); + + // intentionally omitting mm.clear() here + mm.readFromFile(filename_test1); + test(mm); + + mm.clear(); + mm.readFromFile(filename_test1); + test(mm); + + mm.clear(); + mm.readFromFile(filename_test2); + test(mm); +} diff --git a/src/core/util/testing/test1.memorymap b/src/core/util/testing/test1.memorymap new file mode 100644 index 00000000..0f60137f --- /dev/null +++ b/src/core/util/testing/test1.memorymap @@ -0,0 +1,13 @@ +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +17 1 +18 1 +19 1 +21 1 +22 1 +23 1 +24 1 diff --git a/src/core/util/testing/test2.memorymap b/src/core/util/testing/test2.memorymap new file mode 100644 index 00000000..d54841d9 --- /dev/null +++ b/src/core/util/testing/test2.memorymap @@ -0,0 +1,3 @@ +10 6 +17 3 +21 4