110612SMarco.Elver@ARM.com/* 210612SMarco.Elver@ARM.com * Copyright (c) 2014 ARM Limited 310612SMarco.Elver@ARM.com * All rights reserved 410612SMarco.Elver@ARM.com * 510612SMarco.Elver@ARM.com * The license below extends only to copyright in the software and shall 610612SMarco.Elver@ARM.com * not be construed as granting a license to any other intellectual 710612SMarco.Elver@ARM.com * property including but not limited to intellectual property relating 810612SMarco.Elver@ARM.com * to a hardware implementation of the functionality of the software 910612SMarco.Elver@ARM.com * licensed hereunder. You may use the software subject to the license 1010612SMarco.Elver@ARM.com * terms below provided that you ensure that this notice is replicated 1110612SMarco.Elver@ARM.com * unmodified and in its entirety in all distributions of the software, 1210612SMarco.Elver@ARM.com * modified or unmodified, in source code or in binary form. 1310612SMarco.Elver@ARM.com * 1410612SMarco.Elver@ARM.com * Redistribution and use in source and binary forms, with or without 1510612SMarco.Elver@ARM.com * modification, are permitted provided that the following conditions are 1610612SMarco.Elver@ARM.com * met: redistributions of source code must retain the above copyright 1710612SMarco.Elver@ARM.com * notice, this list of conditions and the following disclaimer; 1810612SMarco.Elver@ARM.com * redistributions in binary form must reproduce the above copyright 1910612SMarco.Elver@ARM.com * notice, this list of conditions and the following disclaimer in the 2010612SMarco.Elver@ARM.com * documentation and/or other materials provided with the distribution; 2110612SMarco.Elver@ARM.com * neither the name of the copyright holders nor the names of its 2210612SMarco.Elver@ARM.com * contributors may be used to endorse or promote products derived from 2310612SMarco.Elver@ARM.com * this software without specific prior written permission. 2410612SMarco.Elver@ARM.com * 2510612SMarco.Elver@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610612SMarco.Elver@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710612SMarco.Elver@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810612SMarco.Elver@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910612SMarco.Elver@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010612SMarco.Elver@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110612SMarco.Elver@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210612SMarco.Elver@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310612SMarco.Elver@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410612SMarco.Elver@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510612SMarco.Elver@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610612SMarco.Elver@ARM.com * 3710612SMarco.Elver@ARM.com * Authors: Rune Holm 3810612SMarco.Elver@ARM.com * Marco Elver 3910612SMarco.Elver@ARM.com */ 4010612SMarco.Elver@ARM.com 4111793Sbrandon.potter@amd.com#include "mem/mem_checker.hh" 4211793Sbrandon.potter@amd.com 4310612SMarco.Elver@ARM.com#include <cassert> 4410612SMarco.Elver@ARM.com 4510612SMarco.Elver@ARM.comvoid 4610612SMarco.Elver@ARM.comMemChecker::WriteCluster::startWrite(MemChecker::Serial serial, Tick _start, 4710612SMarco.Elver@ARM.com uint8_t data) 4810612SMarco.Elver@ARM.com{ 4910612SMarco.Elver@ARM.com assert(!isComplete()); 5010612SMarco.Elver@ARM.com 5110612SMarco.Elver@ARM.com if (start == TICK_FUTURE) { 5210612SMarco.Elver@ARM.com // Initialize a fresh write cluster 5310612SMarco.Elver@ARM.com start = _start; 5410612SMarco.Elver@ARM.com } 5510612SMarco.Elver@ARM.com chatty_assert(start <= _start, "WriteClusters must filled in order!"); 5610612SMarco.Elver@ARM.com 5710612SMarco.Elver@ARM.com ++numIncomplete; 5810612SMarco.Elver@ARM.com 5910612SMarco.Elver@ARM.com if (complete != TICK_FUTURE) { 6010612SMarco.Elver@ARM.com // Reopen a closed write cluster 6110612SMarco.Elver@ARM.com assert(_start < complete); // should open a new write cluster, instead; 6210612SMarco.Elver@ARM.com // also somewhat fishy wrt causality / ordering of calls vs time 6310612SMarco.Elver@ARM.com // progression TODO: Check me! 6410612SMarco.Elver@ARM.com complete = TICK_FUTURE; 6510612SMarco.Elver@ARM.com } 6610612SMarco.Elver@ARM.com 6710612SMarco.Elver@ARM.com // Create new transaction, and denote completion time to be in the future. 6810612SMarco.Elver@ARM.com writes.insert(std::make_pair(serial, 6910612SMarco.Elver@ARM.com MemChecker::Transaction(serial, _start, TICK_FUTURE, data))); 7010612SMarco.Elver@ARM.com} 7110612SMarco.Elver@ARM.com 7210612SMarco.Elver@ARM.comvoid 7310612SMarco.Elver@ARM.comMemChecker::WriteCluster::completeWrite(MemChecker::Serial serial, Tick _complete) 7410612SMarco.Elver@ARM.com{ 7510612SMarco.Elver@ARM.com auto it = writes.find(serial); 7610612SMarco.Elver@ARM.com 7710612SMarco.Elver@ARM.com if (it == writes.end()) { 7810612SMarco.Elver@ARM.com warn("Could not locate write transaction: serial = %d, complete = %d\n", 7910612SMarco.Elver@ARM.com serial, _complete); 8010612SMarco.Elver@ARM.com return; 8110612SMarco.Elver@ARM.com } 8210612SMarco.Elver@ARM.com 8310612SMarco.Elver@ARM.com // Record completion time of the write 8410612SMarco.Elver@ARM.com assert(it->second.complete == TICK_FUTURE); 8510612SMarco.Elver@ARM.com it->second.complete = _complete; 8610612SMarco.Elver@ARM.com 8710612SMarco.Elver@ARM.com // Update max completion time for the cluster 8810612SMarco.Elver@ARM.com if (completeMax < _complete) { 8910612SMarco.Elver@ARM.com completeMax = _complete; 9010612SMarco.Elver@ARM.com } 9110612SMarco.Elver@ARM.com 9210612SMarco.Elver@ARM.com if (--numIncomplete == 0) { 9310612SMarco.Elver@ARM.com // All writes have completed, this cluster is now complete and will be 9410612SMarco.Elver@ARM.com // assigned the max of completion tick values among all writes. 9510612SMarco.Elver@ARM.com // 9610612SMarco.Elver@ARM.com // Note that we cannot simply keep updating complete, because that would 9710612SMarco.Elver@ARM.com // count the cluster as closed already. Instead, we keep TICK_FUTURE 9810612SMarco.Elver@ARM.com // until all writes have completed. 9910612SMarco.Elver@ARM.com complete = completeMax; 10010612SMarco.Elver@ARM.com } 10110612SMarco.Elver@ARM.com} 10210612SMarco.Elver@ARM.com 10310612SMarco.Elver@ARM.comvoid 10410612SMarco.Elver@ARM.comMemChecker::WriteCluster::abortWrite(MemChecker::Serial serial) 10510612SMarco.Elver@ARM.com{ 10610612SMarco.Elver@ARM.com if (!writes.erase(serial)) { 10710612SMarco.Elver@ARM.com warn("Could not locate write transaction: serial = %d\n", serial); 10810612SMarco.Elver@ARM.com return; 10910612SMarco.Elver@ARM.com } 11010612SMarco.Elver@ARM.com 11110612SMarco.Elver@ARM.com if (--numIncomplete == 0 && !writes.empty()) { 11210612SMarco.Elver@ARM.com // This write cluster is now complete, and we can assign the current 11310612SMarco.Elver@ARM.com // completeMax value. 11410612SMarco.Elver@ARM.com complete = completeMax; 11510612SMarco.Elver@ARM.com } 11610612SMarco.Elver@ARM.com 11710612SMarco.Elver@ARM.com // Note: this WriteCluster is in pristine state if this was the only 11810612SMarco.Elver@ARM.com // write present; the cluster will get reused through 11910612SMarco.Elver@ARM.com // getIncompleteWriteCluster(). 12010612SMarco.Elver@ARM.com} 12110612SMarco.Elver@ARM.com 12210612SMarco.Elver@ARM.comvoid 12310612SMarco.Elver@ARM.comMemChecker::ByteTracker::startRead(MemChecker::Serial serial, Tick start) 12410612SMarco.Elver@ARM.com{ 12510612SMarco.Elver@ARM.com outstandingReads.insert(std::make_pair(serial, 12610612SMarco.Elver@ARM.com MemChecker::Transaction(serial, start, TICK_FUTURE))); 12710612SMarco.Elver@ARM.com} 12810612SMarco.Elver@ARM.com 12910612SMarco.Elver@ARM.combool 13010612SMarco.Elver@ARM.comMemChecker::ByteTracker::inExpectedData(Tick start, Tick complete, uint8_t data) 13110612SMarco.Elver@ARM.com{ 13210612SMarco.Elver@ARM.com _lastExpectedData.clear(); 13310612SMarco.Elver@ARM.com 13410612SMarco.Elver@ARM.com bool wc_overlap = true; 13510612SMarco.Elver@ARM.com 13610612SMarco.Elver@ARM.com // Find the last value read from the location 13710612SMarco.Elver@ARM.com const Transaction& last_obs = 13810612SMarco.Elver@ARM.com *lastCompletedTransaction(&readObservations, start); 13910612SMarco.Elver@ARM.com bool last_obs_valid = (last_obs.complete != TICK_INITIAL); 14010612SMarco.Elver@ARM.com 14110612SMarco.Elver@ARM.com // Scan backwards through the write clusters to find the closest younger 14210612SMarco.Elver@ARM.com // preceding & overlapping writes. 14310612SMarco.Elver@ARM.com for (auto cluster = writeClusters.rbegin(); 14410612SMarco.Elver@ARM.com cluster != writeClusters.rend() && wc_overlap; ++cluster) { 14510612SMarco.Elver@ARM.com for (const auto& addr_write : cluster->writes) { 14610612SMarco.Elver@ARM.com const Transaction& write = addr_write.second; 14710612SMarco.Elver@ARM.com 14810612SMarco.Elver@ARM.com if (write.complete < last_obs.start) { 14910612SMarco.Elver@ARM.com // If this write transaction completed before the last 15010612SMarco.Elver@ARM.com // observation, we ignore it as the last_observation has the 15110612SMarco.Elver@ARM.com // correct value 15210612SMarco.Elver@ARM.com continue; 15310612SMarco.Elver@ARM.com } 15410612SMarco.Elver@ARM.com 15510612SMarco.Elver@ARM.com if (write.data == data) { 15610612SMarco.Elver@ARM.com // Found a match, end search. 15710612SMarco.Elver@ARM.com return true; 15810612SMarco.Elver@ARM.com } 15910612SMarco.Elver@ARM.com 16010612SMarco.Elver@ARM.com // Record possible, but non-matching data for debugging 16110612SMarco.Elver@ARM.com _lastExpectedData.push_back(write.data); 16210612SMarco.Elver@ARM.com 16310612SMarco.Elver@ARM.com if (write.complete > start) { 16410612SMarco.Elver@ARM.com // This write overlapped with the transaction we want to check 16510612SMarco.Elver@ARM.com // -> continue checking the overlapping write cluster 16610612SMarco.Elver@ARM.com continue; 16710612SMarco.Elver@ARM.com } 16810612SMarco.Elver@ARM.com 16910612SMarco.Elver@ARM.com // This write cluster has writes that have completed before the 17010612SMarco.Elver@ARM.com // checked transaction. There is no need to check an earlier 17110612SMarco.Elver@ARM.com // write-cluster -> set the exit condition for the outer loop 17210612SMarco.Elver@ARM.com wc_overlap = false; 17310612SMarco.Elver@ARM.com 17410612SMarco.Elver@ARM.com if (last_obs.complete < write.start) { 17510612SMarco.Elver@ARM.com // We found a write which started after the last observed read, 17610612SMarco.Elver@ARM.com // therefore we can not longer consider the value seen by the 17710612SMarco.Elver@ARM.com // last observation as a valid expected value. 17810612SMarco.Elver@ARM.com // 17910612SMarco.Elver@ARM.com // Once all writes have been iterated through, we can check if 18010612SMarco.Elver@ARM.com // the last observation is still valid to compare against. 18110612SMarco.Elver@ARM.com last_obs_valid = false; 18210612SMarco.Elver@ARM.com } 18310612SMarco.Elver@ARM.com } 18410612SMarco.Elver@ARM.com } 18510612SMarco.Elver@ARM.com 18610612SMarco.Elver@ARM.com // We have not found any matching write, so far; check other sources of 18710612SMarco.Elver@ARM.com // confirmation 18810612SMarco.Elver@ARM.com if (last_obs_valid) { 18910612SMarco.Elver@ARM.com // The last observation is not outdated according to the writes we have 19010612SMarco.Elver@ARM.com // seen so far. 19110612SMarco.Elver@ARM.com assert(last_obs.complete <= start); 19210612SMarco.Elver@ARM.com if (last_obs.data == data) { 19310612SMarco.Elver@ARM.com // Matched data from last observation -> all good 19410612SMarco.Elver@ARM.com return true; 19510612SMarco.Elver@ARM.com } 19610612SMarco.Elver@ARM.com // Record non-matching, but possible value 19710612SMarco.Elver@ARM.com _lastExpectedData.push_back(last_obs.data); 19810703Sstephan.diestelhorst@arm.com } else { 19910703Sstephan.diestelhorst@arm.com // We have not seen any valid observation, and the only writes 20010703Sstephan.diestelhorst@arm.com // observed are overlapping, so anything (in particular the 20110703Sstephan.diestelhorst@arm.com // initialisation value) goes 20210703Sstephan.diestelhorst@arm.com // NOTE: We can overlap with multiple write clusters, here 20310703Sstephan.diestelhorst@arm.com if (!writeClusters.empty() && wc_overlap) { 20410703Sstephan.diestelhorst@arm.com // ensure that all write clusters really overlap this read 20510703Sstephan.diestelhorst@arm.com assert(writeClusters.begin()->start < complete && 20610703Sstephan.diestelhorst@arm.com writeClusters.rbegin()->complete > start); 20710703Sstephan.diestelhorst@arm.com return true; 20810703Sstephan.diestelhorst@arm.com } 20910612SMarco.Elver@ARM.com } 21010612SMarco.Elver@ARM.com 21110612SMarco.Elver@ARM.com if (_lastExpectedData.empty()) { 21210612SMarco.Elver@ARM.com assert(last_obs.complete == TICK_INITIAL); 21310612SMarco.Elver@ARM.com // We have not found any possible (non-matching data). Can happen in 21410612SMarco.Elver@ARM.com // initial system state 21510612SMarco.Elver@ARM.com DPRINTF(MemChecker, "no last observation nor write! start = %d, "\ 21610612SMarco.Elver@ARM.com "complete = %d, data = %#x\n", start, complete, data); 21710612SMarco.Elver@ARM.com return true; 21810612SMarco.Elver@ARM.com } 21910612SMarco.Elver@ARM.com return false; 22010612SMarco.Elver@ARM.com} 22110612SMarco.Elver@ARM.com 22210612SMarco.Elver@ARM.combool 22310612SMarco.Elver@ARM.comMemChecker::ByteTracker::completeRead(MemChecker::Serial serial, 22410612SMarco.Elver@ARM.com Tick complete, uint8_t data) 22510612SMarco.Elver@ARM.com{ 22610612SMarco.Elver@ARM.com auto it = outstandingReads.find(serial); 22710612SMarco.Elver@ARM.com 22810612SMarco.Elver@ARM.com if (it == outstandingReads.end()) { 22910612SMarco.Elver@ARM.com // Can happen if concurrent with reset_address_range 23010612SMarco.Elver@ARM.com warn("Could not locate read transaction: serial = %d, complete = %d\n", 23110612SMarco.Elver@ARM.com serial, complete); 23210612SMarco.Elver@ARM.com return true; 23310612SMarco.Elver@ARM.com } 23410612SMarco.Elver@ARM.com 23510612SMarco.Elver@ARM.com Tick start = it->second.start; 23610612SMarco.Elver@ARM.com outstandingReads.erase(it); 23710612SMarco.Elver@ARM.com 23810612SMarco.Elver@ARM.com // Verify data 23910612SMarco.Elver@ARM.com const bool result = inExpectedData(start, complete, data); 24010612SMarco.Elver@ARM.com 24110612SMarco.Elver@ARM.com readObservations.emplace_back(serial, start, complete, data); 24210612SMarco.Elver@ARM.com pruneTransactions(); 24310612SMarco.Elver@ARM.com 24410612SMarco.Elver@ARM.com return result; 24510612SMarco.Elver@ARM.com} 24610612SMarco.Elver@ARM.com 24710612SMarco.Elver@ARM.comMemChecker::WriteCluster* 24810612SMarco.Elver@ARM.comMemChecker::ByteTracker::getIncompleteWriteCluster() 24910612SMarco.Elver@ARM.com{ 25010612SMarco.Elver@ARM.com if (writeClusters.empty() || writeClusters.back().isComplete()) { 25110612SMarco.Elver@ARM.com writeClusters.emplace_back(); 25210612SMarco.Elver@ARM.com } 25310612SMarco.Elver@ARM.com 25410612SMarco.Elver@ARM.com return &writeClusters.back(); 25510612SMarco.Elver@ARM.com} 25610612SMarco.Elver@ARM.com 25710612SMarco.Elver@ARM.comvoid 25810612SMarco.Elver@ARM.comMemChecker::ByteTracker::startWrite(MemChecker::Serial serial, Tick start, 25910612SMarco.Elver@ARM.com uint8_t data) 26010612SMarco.Elver@ARM.com{ 26110612SMarco.Elver@ARM.com getIncompleteWriteCluster()->startWrite(serial, start, data); 26210612SMarco.Elver@ARM.com} 26310612SMarco.Elver@ARM.com 26410612SMarco.Elver@ARM.comvoid 26510612SMarco.Elver@ARM.comMemChecker::ByteTracker::completeWrite(MemChecker::Serial serial, Tick complete) 26610612SMarco.Elver@ARM.com{ 26710612SMarco.Elver@ARM.com getIncompleteWriteCluster()->completeWrite(serial, complete); 26810612SMarco.Elver@ARM.com pruneTransactions(); 26910612SMarco.Elver@ARM.com} 27010612SMarco.Elver@ARM.com 27110612SMarco.Elver@ARM.comvoid 27210612SMarco.Elver@ARM.comMemChecker::ByteTracker::abortWrite(MemChecker::Serial serial) 27310612SMarco.Elver@ARM.com{ 27410612SMarco.Elver@ARM.com getIncompleteWriteCluster()->abortWrite(serial); 27510612SMarco.Elver@ARM.com} 27610612SMarco.Elver@ARM.com 27710612SMarco.Elver@ARM.comvoid 27810612SMarco.Elver@ARM.comMemChecker::ByteTracker::pruneTransactions() 27910612SMarco.Elver@ARM.com{ 28010612SMarco.Elver@ARM.com // Obtain tick of first outstanding read. If there are no outstanding 28110612SMarco.Elver@ARM.com // reads, we use curTick(), i.e. we will remove all readObservation except 28210612SMarco.Elver@ARM.com // the most recent one. 28310612SMarco.Elver@ARM.com const Tick before = outstandingReads.empty() ? curTick() : 28410612SMarco.Elver@ARM.com outstandingReads.begin()->second.start; 28510612SMarco.Elver@ARM.com 28610612SMarco.Elver@ARM.com // Pruning of readObservations 28710612SMarco.Elver@ARM.com readObservations.erase(readObservations.begin(), 28810612SMarco.Elver@ARM.com lastCompletedTransaction(&readObservations, before)); 28910612SMarco.Elver@ARM.com 29010612SMarco.Elver@ARM.com // Pruning of writeClusters 29110612SMarco.Elver@ARM.com if (!writeClusters.empty()) { 29210612SMarco.Elver@ARM.com writeClusters.erase(writeClusters.begin(), 29310612SMarco.Elver@ARM.com lastCompletedTransaction(&writeClusters, before)); 29410612SMarco.Elver@ARM.com } 29510612SMarco.Elver@ARM.com} 29610612SMarco.Elver@ARM.com 29710612SMarco.Elver@ARM.combool 29810612SMarco.Elver@ARM.comMemChecker::completeRead(MemChecker::Serial serial, Tick complete, 29910612SMarco.Elver@ARM.com Addr addr, size_t size, uint8_t *data) 30010612SMarco.Elver@ARM.com{ 30110612SMarco.Elver@ARM.com bool result = true; 30210612SMarco.Elver@ARM.com 30310612SMarco.Elver@ARM.com DPRINTF(MemChecker, 30410612SMarco.Elver@ARM.com "completing read: serial = %d, complete = %d, " 30510612SMarco.Elver@ARM.com "addr = %#llx, size = %d\n", serial, complete, addr, size); 30610612SMarco.Elver@ARM.com 30710612SMarco.Elver@ARM.com for (size_t i = 0; i < size; ++i) { 30810612SMarco.Elver@ARM.com ByteTracker *tracker = getByteTracker(addr + i); 30910612SMarco.Elver@ARM.com 31010612SMarco.Elver@ARM.com if (!tracker->completeRead(serial, complete, data[i])) { 31110612SMarco.Elver@ARM.com // Generate error message, and aggregate all failures for the bytes 31210612SMarco.Elver@ARM.com // considered in this transaction in one message. 31310612SMarco.Elver@ARM.com if (result) { 31410612SMarco.Elver@ARM.com result = false; 31510612SMarco.Elver@ARM.com errorMessage = ""; 31610612SMarco.Elver@ARM.com } else { 31710612SMarco.Elver@ARM.com errorMessage += "\n"; 31810612SMarco.Elver@ARM.com } 31910612SMarco.Elver@ARM.com 32010612SMarco.Elver@ARM.com errorMessage += csprintf(" Read transaction for address %#llx " 32110612SMarco.Elver@ARM.com "failed: received %#x, expected ", 32210612SMarco.Elver@ARM.com (unsigned long long)(addr + i), data[i]); 32310612SMarco.Elver@ARM.com 32410612SMarco.Elver@ARM.com for (size_t j = 0; j < tracker->lastExpectedData().size(); ++j) { 32510612SMarco.Elver@ARM.com errorMessage += 32610612SMarco.Elver@ARM.com csprintf("%#x%s", 32710612SMarco.Elver@ARM.com tracker->lastExpectedData()[j], 32810612SMarco.Elver@ARM.com (j == tracker->lastExpectedData().size() - 1) 32910612SMarco.Elver@ARM.com ? "" : "|"); 33010612SMarco.Elver@ARM.com } 33110612SMarco.Elver@ARM.com } 33210612SMarco.Elver@ARM.com } 33310612SMarco.Elver@ARM.com 33410612SMarco.Elver@ARM.com if (!result) { 33510612SMarco.Elver@ARM.com DPRINTF(MemChecker, "read of %#llx @ cycle %d failed:\n%s\n", addr, 33610612SMarco.Elver@ARM.com complete, errorMessage); 33710612SMarco.Elver@ARM.com } 33810612SMarco.Elver@ARM.com 33910612SMarco.Elver@ARM.com return result; 34010612SMarco.Elver@ARM.com} 34110612SMarco.Elver@ARM.com 34210612SMarco.Elver@ARM.comvoid 34310612SMarco.Elver@ARM.comMemChecker::reset(Addr addr, size_t size) 34410612SMarco.Elver@ARM.com{ 34510612SMarco.Elver@ARM.com for (size_t i = 0; i < size; ++i) { 34610612SMarco.Elver@ARM.com byte_trackers.erase(addr + i); 34710612SMarco.Elver@ARM.com } 34810612SMarco.Elver@ARM.com} 34910612SMarco.Elver@ARM.com 35010612SMarco.Elver@ARM.comMemChecker* 35110612SMarco.Elver@ARM.comMemCheckerParams::create() 35210612SMarco.Elver@ARM.com{ 35310612SMarco.Elver@ARM.com return new MemChecker(this); 35410612SMarco.Elver@ARM.com} 355