"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/Rose/BinaryAnalysis/Concolic/Architecture.C" between
rose-0.11.49.0.tar.gz and rose-0.11.50.0.tar.gz

About: ROSE is a compiler infrastructure to build source-to-source program transformation and analysis tools for large-scale C, C++, UPC, Fortran, OpenMP, Java, Python and PHP applications.

Architecture.C  (rose-0.11.49.0):Architecture.C  (rose-0.11.50.0)
#include <featureTests.h> #include <featureTests.h>
#ifdef ROSE_ENABLE_CONCOLIC_TESTING #ifdef ROSE_ENABLE_CONCOLIC_TESTING
#include <sage3basic.h> #include <sage3basic.h>
#include <Rose/BinaryAnalysis/Concolic/Architecture.h> #include <Rose/BinaryAnalysis/Concolic/Architecture.h>
#include <Rose/BinaryAnalysis/Concolic/Database.h> #include <Rose/BinaryAnalysis/Concolic/Database.h>
#include <Rose/BinaryAnalysis/Concolic/ExecutionEvent.h> #include <Rose/BinaryAnalysis/Concolic/ExecutionEvent.h>
#include <Rose/BinaryAnalysis/Concolic/InputVariables.h> #include <Rose/BinaryAnalysis/Concolic/InputVariables.h>
#include <Rose/BinaryAnalysis/Concolic/SharedMemory.h>
#include <Rose/BinaryAnalysis/Concolic/SystemCall.h> #include <Rose/BinaryAnalysis/Concolic/SystemCall.h>
#include <Rose/BinaryAnalysis/Concolic/TestCase.h> #include <Rose/BinaryAnalysis/Concolic/TestCase.h>
using namespace Sawyer::Message::Common; using namespace Sawyer::Message::Common;
namespace BS = Rose::BinaryAnalysis::InstructionSemantics2::BaseSemantics;
namespace P2 = Rose::BinaryAnalysis::Partitioner2;
namespace Rose { namespace Rose {
namespace BinaryAnalysis { namespace BinaryAnalysis {
namespace Concolic { namespace Concolic {
Architecture::Architecture(const Database::Ptr &db, TestCaseId testCaseId) Architecture::Architecture(const Database::Ptr &db, TestCaseId testCaseId, const
: db_(db), testCaseId_(testCaseId) { P2::Partitioner &partitioner)
: db_(db), testCaseId_(testCaseId), partitioner_(partitioner) {
ASSERT_not_null(db); ASSERT_not_null(db);
testCase_ = db->object(testCaseId, Update::NO); testCase_ = db->object(testCaseId, Update::NO);
ASSERT_not_null(testCase_); ASSERT_not_null(testCase_);
} }
Architecture::~Architecture() {} Architecture::~Architecture() {}
Database::Ptr Database::Ptr
Architecture::database() const { Architecture::database() const {
ASSERT_not_null(db_); ASSERT_not_null(db_);
skipping to change at line 45 skipping to change at line 48
ASSERT_require(testCaseId_); ASSERT_require(testCaseId_);
return testCaseId_; return testCaseId_;
} }
TestCase::Ptr TestCase::Ptr
Architecture::testCase() const { Architecture::testCase() const {
ASSERT_not_null(testCase_); ASSERT_not_null(testCase_);
return testCase_; return testCase_;
} }
const P2::Partitioner&
Architecture::partitioner() const {
return partitioner_;
}
ExecutionLocation
Architecture::currentLocation() const {
return currentLocation_;
}
void
Architecture::currentLocation(const ExecutionLocation &loc) {
currentLocation_ = loc;
}
const Architecture::SystemCallMap& const Architecture::SystemCallMap&
Architecture::systemCalls() const { Architecture::systemCalls() const {
return systemCalls_; return systemCalls_;
} }
Architecture::SystemCallMap& Architecture::SystemCallMap&
Architecture::systemCalls() { Architecture::systemCalls() {
return systemCalls_; return systemCalls_;
} }
void void
Architecture::saveEvents(const std::vector<ExecutionEvent::Ptr> &events) { Architecture::systemCalls(size_t syscallId, const SyscallCallback::Ptr &callback
) {
ASSERT_not_null(callback);
SyscallCallbacks &callbacks = systemCalls_.insertMaybeDefault(syscallId);
callbacks.append(callback);
}
const Architecture::SharedMemoryMap&
Architecture::sharedMemory() const {
return sharedMemory_;
}
Architecture::SharedMemoryMap&
Architecture::sharedMemory() {
return sharedMemory_;
}
void
Architecture::sharedMemory(const AddressInterval &where, const SharedMemoryCallb
ack::Ptr &callback) {
ASSERT_not_null(callback);
AddressInterval remaining = where;
while (!remaining.isEmpty()) {
SharedMemoryCallbacks callbacks;
auto iter = sharedMemory_.findFirstOverlap(remaining);
AddressInterval whereToInsert;
if (iter == sharedMemory_.nodes().end()) {
whereToInsert = remaining;
} else if (remaining.least() < iter->key().least()) {
whereToInsert = AddressInterval::hull(remaining.least(), iter->key()
.least() - 1);
} else {
whereToInsert = remaining & iter->key();
callbacks = sharedMemory_.get(whereToInsert.least());
}
callbacks.append(callback);
sharedMemory_.insert(whereToInsert, callbacks);
if (whereToInsert == remaining)
break;
remaining = AddressInterval::hull(whereToInsert.greatest() + 1, remainin
g.greatest());
}
}
void
Architecture::saveEvents(const std::vector<ExecutionEvent::Ptr> &events, When wh
en) {
for (const ExecutionEvent::Ptr &event: events) { for (const ExecutionEvent::Ptr &event: events) {
ASSERT_not_null(event); ASSERT_not_null(event);
event->testCase(testCase_); event->testCase(testCase_);
event->location(nextLocation()); event->location(nextEventLocation(when));
database()->save(event); database()->save(event);
} }
} }
size_t size_t
Architecture::playAllEvents() { Architecture::playAllEvents(const P2::Partitioner &partitioner) {
size_t retval = 0; size_t retval = 0;
std::vector<ExecutionEventId> eventIds = db_->executionEvents(testCaseId_); std::vector<ExecutionEventId> eventIds = db_->executionEvents(testCaseId_);
for (ExecutionEventId eventId: eventIds) { for (ExecutionEventId eventId: eventIds) {
ExecutionEvent::Ptr event = db_->object(eventId, Update::NO); ExecutionEvent::Ptr event = db_->object(eventId, Update::NO);
ASSERT_not_null(event); ASSERT_not_null(event);
runToEvent(event); runToEvent(event, partitioner);
bool handled = playEvent(event); bool handled = playEvent(event);
ASSERT_always_require(handled); ASSERT_always_require(handled);
++retval; ++retval;
} }
return retval; return retval;
} }
std::vector<ExecutionEvent::Ptr>
Architecture::getRelatedEvents(const ExecutionEvent::Ptr &parent) const {
ASSERT_not_null(parent);
TestCaseId testCaseId = database()->id(parent->testCase());
std::vector<ExecutionEventId> eventIds = database()->executionEvents(testCas
eId, parent->location().primary());
std::vector<ExecutionEvent::Ptr> events;
// Process from last event toward first event because it results in fewer da
tabase reads.
std::reverse(eventIds.begin(), eventIds.end());
for (ExecutionEventId eventId: eventIds) {
ExecutionEvent::Ptr event = database()->object(eventId);
if (parent->location() < event->location()) {
events.push_back(event);
} else {
break;
}
}
// We processed the events backward, but need to return them forward.
std::reverse(events.begin(), events.end());
return events;
}
bool bool
Architecture::playEvent(const ExecutionEvent::Ptr &event) { Architecture::playEvent(const ExecutionEvent::Ptr &event) {
ASSERT_not_null(event); ASSERT_not_null(event);
SAWYER_MESG(mlog[DEBUG]) <<"processing " <<event->printableName(database()) Sawyer::Message::Stream debug(mlog[DEBUG]);
<<" at " <<event->location().primary <<":" <<event-
>location().secondary SAWYER_MESG(debug) <<"processing " <<event->printableName(database())
<<" ip=" <<StringUtility::addrToString(event->instr <<" ip=" <<StringUtility::addrToString(event->instruction
uctionPointer()) <<"\n"; Pointer()) <<"\n";
switch (event->actionType()) { switch (event->actionType()) {
case ExecutionEvent::Action::NONE: case ExecutionEvent::Action::NONE:
SAWYER_MESG(mlog[DEBUG]) <<" no action necessary\n"; SAWYER_MESG(debug) <<" no action necessary\n";
return true; return true;
case ExecutionEvent::Action::MAP_MEMORY: { case ExecutionEvent::Action::MAP_MEMORY: {
AddressInterval where = event->memoryLocation(); AddressInterval where = event->memoryLocation();
ASSERT_forbid(where.isEmpty()); ASSERT_forbid(where.isEmpty());
SAWYER_MESG(mlog[DEBUG]) <<" map " <<where.size() <<" bytes at " << StringUtility::addrToString(where) <<", prot="; SAWYER_MESG(debug) <<" map " <<where.size() <<" bytes at " <<String Utility::addrToString(where) <<", prot=";
unsigned prot = 0; unsigned prot = 0;
for (char letter: event->bytes()) { for (char letter: event->bytes()) {
SAWYER_MESG(mlog[DEBUG]) <<letter; SAWYER_MESG(debug) <<letter;
switch (letter) { switch (letter) {
case 'r': case 'r':
prot |= MemoryMap::READABLE; prot |= MemoryMap::READABLE;
break; break;
case 'w': case 'w':
prot |= MemoryMap::WRITABLE; prot |= MemoryMap::WRITABLE;
break; break;
case 'x': case 'x':
prot |= MemoryMap::EXECUTABLE; prot |= MemoryMap::EXECUTABLE;
break; break;
skipping to change at line 126 skipping to change at line 211
case ExecutionEvent::Action::UNMAP_MEMORY: { case ExecutionEvent::Action::UNMAP_MEMORY: {
AddressInterval where = event->memoryLocation(); AddressInterval where = event->memoryLocation();
ASSERT_forbid(where.isEmpty()); ASSERT_forbid(where.isEmpty());
unmapMemory(where); unmapMemory(where);
return true; return true;
} }
case ExecutionEvent::Action::WRITE_MEMORY: { case ExecutionEvent::Action::WRITE_MEMORY: {
AddressInterval where = event->memoryLocation(); AddressInterval where = event->memoryLocation();
SAWYER_MESG(mlog[DEBUG]) <<" write memory " <<StringUtility::plural SAWYER_MESG(debug) <<" write memory " <<StringUtility::plural(where
(where.size(), "bytes") .size(), "bytes")
<<" at " <<StringUtility::addrToString(wher <<" at " <<StringUtility::addrToString(where) <<"
e) <<"\n"; \n";
ASSERT_forbid(where.isEmpty()); ASSERT_forbid(where.isEmpty());
ASSERT_require(where.size() == event->bytes().size()); ASSERT_require(where.size() == event->bytes().size());
size_t nWritten = writeMemory(where.least(), event->bytes()); size_t nWritten = writeMemory(where.least(), event->bytes());
if (nWritten != where.size()) if (nWritten != where.size())
mlog[ERROR] <<"WRITE_MEMORY event failed to write to memory\n"; mlog[ERROR] <<"WRITE_MEMORY event failed to write to memory\n";
return true; return true;
} }
case ExecutionEvent::Action::HASH_MEMORY: { case ExecutionEvent::Action::HASH_MEMORY: {
AddressInterval where = event->memoryLocation(); AddressInterval where = event->memoryLocation();
SAWYER_MESG(mlog[DEBUG]) <<" hash memory " <<StringUtility::plural( SAWYER_MESG(debug) <<" hash memory " <<StringUtility::plural(where.
where.size(), "bytes") size(), "bytes")
<<" at " <<StringUtility::addrToString(wher <<" at " <<StringUtility::addrToString(where) <<"
e) <<"\n"; \n";
ASSERT_forbid(where.isEmpty()); ASSERT_forbid(where.isEmpty());
std::vector<uint8_t> buf = readMemory(where.least(), where.size()); std::vector<uint8_t> buf = readMemory(where.least(), where.size());
if (buf.size() != where.size()) { if (buf.size() != where.size()) {
mlog[ERROR] <<"memory hash comparison failed at " <<StringUtilit y::addrToString(where) <<": read error\n"; mlog[ERROR] <<"memory hash comparison failed at " <<StringUtilit y::addrToString(where) <<": read error\n";
} else { } else {
Combinatorics::HasherSha256Builtin hasher; Combinatorics::HasherSha256Builtin hasher;
hasher.insert(buf); hasher.insert(buf);
Combinatorics::Hasher::Digest currentDigest = hasher.digest(); Combinatorics::Hasher::Digest currentDigest = hasher.digest();
const Combinatorics::Hasher::Digest &savedDigest = event->bytes( ); const Combinatorics::Hasher::Digest &savedDigest = event->bytes( );
ASSERT_require(currentDigest.size() == savedDigest.size()); ASSERT_require(currentDigest.size() == savedDigest.size());
if (!std::equal(currentDigest.begin(), currentDigest.end(), save dDigest.begin())) if (!std::equal(currentDigest.begin(), currentDigest.end(), save dDigest.begin()))
mlog[ERROR] <<"memory hash comparison failed at " <<StringUt ility::addrToString(where) <<": hash differs\n"; mlog[ERROR] <<"memory hash comparison failed at " <<StringUt ility::addrToString(where) <<": hash differs\n";
} }
return true; return true;
} }
case ExecutionEvent::Action::WRITE_REGISTER: { case ExecutionEvent::Action::WRITE_REGISTER: {
const RegisterDescriptor reg = RegisterDescriptor::fromRaw(event->sc alar()); const RegisterDescriptor reg = RegisterDescriptor::fromRaw(event->sc alar());
const uint64_t value = event->words()[0]; if (SymbolicExpr::Ptr symbolicValue = event->symbolic()) {
SAWYER_MESG(mlog[DEBUG]) <<" write register " <<reg <<" = " <<Strin if (debug) {
gUtility::toHex2(value, reg.nBits()) <<"\n"; debug <<" write register " <<reg <<" = " <<*symbolicValue <
writeRegister(reg, value); <"\n";
for (auto varVal: variableValues_)
debug <<" where " <<*varVal.first <<" = " <<*varVal.s
econd <<"\n";
}
SymbolicExpr::Ptr substValue = symbolicValue->substituteMultiple
(variableValues_);
SAWYER_MESG(debug) <<" substitution result: " <<*substValue <
<"\n";
ASSERT_require(substValue->isIntegerConstant());
ASSERT_require(substValue->nBits() == reg.nBits());
ASSERT_require(substValue->nBits() <= 64);
writeRegister(reg, *substValue->toUnsigned());
} else {
const uint64_t concreteValue = event->words()[0];
SAWYER_MESG(debug) <<" write register "
<<reg <<" = " <<StringUtility::toHex2(concret
eValue, reg.nBits()) <<"\n";
writeRegister(reg, concreteValue);
}
return true;
}
case ExecutionEvent::Action::OS_SYSCALL: {
// This is only the start of a system call. Additional following eve
nts for the same instruction will describe the
// effects of the system call.
const uint64_t functionNumber = event->scalar();
SyscallCallbacks callbacks = systemCalls().getOrDefault(functionNumb
er);
SyscallContext ctx(sharedFromThis(), event, getRelatedEvents(event))
;
return callbacks.apply(false, ctx);
}
case ExecutionEvent::Action::OS_SHM_READ: {
// This is only the start of a shared memory read. Additional follow
ing events for the same instruction will
// describe the effects of the read.
SymbolicExpr::Ptr variable = event->inputVariable();
ASSERT_not_null(variable);
SymbolicExpr::Ptr value = event->bytesAsSymbolic();
ASSERT_not_null(value);
variableValues_.insert(std::make_pair(variable, value));
SAWYER_MESG(debug) <<" shared memory read " <<*variable <<" = " <<*
value <<"\n";
// Invoke the shared memory read callbacks in playback mode so they
can initialize their states.
SharedMemoryCallbacks callbacks = sharedMemory().getOrDefault(event-
>memoryLocation().least());
if (!callbacks.isEmpty()) {
SharedMemoryContext ctx(sharedFromThis(), event);
callbacks.apply(false, ctx);
}
return true; return true;
} }
default: default:
// Not handled here, so may need to be handled by a subclass. // Not handled here, so may need to be handled by a subclass.
return false; return false;
} }
} }
const SymbolicExpr::ExprExprHashMap&
Architecture::variableValues() const {
return variableValues_;
}
SymbolicExpr::ExprExprHashMap&
Architecture::variableValues() {
return variableValues_;
}
void void
Architecture::runToEvent(const ExecutionEvent::Ptr &event) { Architecture::runToEvent(const ExecutionEvent::Ptr &event, const P2::Partitioner &partitioner) {
ASSERT_not_null(event); ASSERT_not_null(event);
while (curLocation_.primary < event->location().primary)
executeInstruction(); if (event->location().when() == When::PRE) {
ASSERT_require(curLocation_.primary == event->location().primary); while (currentLocation().primary() < event->location().primary()) {
executeInstruction(partitioner);
nextInstructionLocation();
}
} else {
ASSERT_require(event->location().when() == When::POST);
while (currentLocation().primary() <= event->location().primary()) {
executeInstruction(partitioner);
nextInstructionLocation();
}
}
} }
uint64_t uint64_t
Architecture::readMemoryUnsigned(rose_addr_t va, size_t nBytes) { Architecture::readMemoryUnsigned(rose_addr_t va, size_t nBytes) {
ASSERT_require(nBytes >= 1 && nBytes <= 8); ASSERT_require(nBytes >= 1 && nBytes <= 8);
std::vector<uint8_t> bytes = readMemory(va, nBytes); std::vector<uint8_t> bytes = readMemory(va, nBytes);
ASSERT_require(bytes.size() == nBytes); ASSERT_require(bytes.size() == nBytes);
uint64_t retval = 0; uint64_t retval = 0;
switch (memoryByteOrder()) { switch (memoryByteOrder()) {
case ByteOrder::ORDER_LSB: case ByteOrder::ORDER_LSB:
skipping to change at line 212 skipping to change at line 360
while (retval.size() < maxBytes) { while (retval.size() < maxBytes) {
auto byte = readMemory(va++, 1); auto byte = readMemory(va++, 1);
if (byte.empty() || byte[0] == 0) if (byte.empty() || byte[0] == 0)
break; break;
retval += (char)byte[0]; retval += (char)byte[0];
} }
return retval; return retval;
} }
const ExecutionLocation& const ExecutionLocation&
Architecture::incrementPathLength() { Architecture::nextInstructionLocation() {
++curLocation_.primary; currentLocation_ = currentLocation_.nextPrimary();
curLocation_.secondary = 0; return currentLocation_;
return curLocation_;
} }
const ExecutionLocation& const ExecutionLocation&
Architecture::nextLocation() { Architecture::nextEventLocation(When when) {
++curLocation_.secondary; currentLocation_ = currentLocation_.nextSecondary(when);
return curLocation_; return currentLocation_;
} }
void void
Architecture::restoreInputVariables(InputVariables &inputVariables, const Partit ioner2::Partitioner&, Architecture::restoreInputVariables(InputVariables &inputVariables, const Partit ioner2::Partitioner&,
const InstructionSemantics2::BaseSemantics:: RiscOperatorsPtr&, const SmtSolver::Ptr&) { const InstructionSemantics2::BaseSemantics:: RiscOperatorsPtr&, const SmtSolver::Ptr&) {
for (ExecutionEventId eventId: database()->executionEvents(testCaseId())) { for (ExecutionEventId eventId: database()->executionEvents(testCaseId())) {
ExecutionEvent::Ptr event = database()->object(eventId, Update::NO); ExecutionEvent::Ptr event = database()->object(eventId, Update::NO);
if (event->inputVariable()) if (event->inputVariable())
inputVariables.insertEvent(event); inputVariables.insertEvent(event);
} }
} }
std::pair<ExecutionEvent::Ptr, SymbolicExpr::Ptr>
Architecture::sharedMemoryRead(const SharedMemoryCallbacks&, const P2::Partition
er&, const BS::RiscOperators::Ptr&,
rose_addr_t /*memoryVa*/, size_t /*nBytes*/) {
return {ExecutionEvent::Ptr(), SymbolicExpr::Ptr()};
}
} // namespace } // namespace
} // namespace } // namespace
} // namespace } // namespace
#endif #endif
 End of changes. 22 change blocks. 
37 lines changed or deleted 209 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)