@@ -56,6 +56,17 @@ extern llvm::cl::opt<bool> PrintForkingStatus;
5656extern llvm::cl::opt<bool > VerboseStateDeletion;
5757extern llvm::cl::opt<bool > DebugConstraints;
5858
59+ // clang-format off
60+ namespace {
61+ // This should be true by default, because otherwise overheads are way too high.
62+ // Drawback is that execution is not fully consistent by default.
63+ llvm::cl::opt<bool >
64+ StateSharedMemory (" state-shared-memory" ,
65+ llvm::cl::desc (" Allow unimportant memory regions (like video RAM) to be shared between states" ),
66+ llvm::cl::init(true ));
67+ }
68+ // clang-format on
69+
5970namespace s2e {
6071
6172using namespace klee ;
@@ -89,11 +100,29 @@ ExecutionStatePtr S2EExecutionState::clone() {
89100 // This means that we must clean owned-by-us flag in S2E TLB.
90101 assert (m_active);
91102
103+ s2e_kvm_flush_disk ();
104+
92105 m_tlb.clearTlbOwnership ();
93106#if defined(SE_ENABLE_PHYSRAM_TLB)
94107 m_tlb.clearRamTlb ();
95108#endif
96109
110+ saveSharedConcreteMemory ();
111+
112+ // We must not save the current tb, because this pointer will become
113+ // stale on state restore. If a signal occurs while restoring the state,
114+ // its handler will try to unlink a stale tb, which could cause a hang
115+ // or a crash.
116+ auto old_tb = env->current_tb ;
117+ env->current_tb = nullptr ;
118+ m_registers.saveConcreteState ();
119+ env->current_tb = old_tb;
120+
121+ cpu_disable_ticks ();
122+ s2e_kvm_save_device_state ();
123+ m_timersState = timers_state;
124+ cpu_enable_ticks ();
125+
97126 S2EExecutionState *ret = new S2EExecutionState (*this );
98127
99128 ret->m_stateID = g_s2e->fetchAndIncrementStateId ();
@@ -109,6 +138,78 @@ ExecutionStatePtr S2EExecutionState::clone() {
109138 return ret;
110139}
111140
141+ void S2EExecutionState::registerRam (uint64_t size, uint64_t hostAddress, bool isSharedConcrete, const char *name) {
142+ #ifdef CONFIG_SYMBEX_MP
143+ assert (m_stateID == 0 && " Ram registration must be done in the initial state" );
144+ assert ((size & ~TARGET_PAGE_MASK) == 0 );
145+ assert ((hostAddress & ~TARGET_PAGE_MASK) == 0 );
146+
147+ g_s2e->getDebugStream () << " Adding memory block (size = " << hexval (size) << " , hostAddr = " << hexval (hostAddress)
148+ << " , isSharedConcrete=" << isSharedConcrete << " , name=" << name << " )\n " ;
149+
150+ for (uint64_t addr = hostAddress; addr < hostAddress + size; addr += SE_RAM_OBJECT_SIZE) {
151+
152+ auto os = addExternalObject ((void *) addr, SE_RAM_OBJECT_SIZE, false , isSharedConcrete);
153+
154+ os->setMemoryPage (true );
155+
156+ if (!isSharedConcrete) {
157+ os->setSplittable (true );
158+ os->setNotifyOnConcretenessChange (true );
159+ }
160+
161+ #ifdef S2E_DEBUG_MEMOBJECT_NAME
162+ std::stringstream ss;
163+ ss << name << " _" << std::hex << (addr - hostAddress);
164+ mo->setName (ss.str ());
165+ #endif
166+
167+ if (isSharedConcrete && !StateSharedMemory) {
168+ m_saveOnContextSwitch.push_back (os->getKey ());
169+ }
170+ }
171+
172+ if (!isSharedConcrete) {
173+ // mprotecting does not actually free the RAM, it's still committed,
174+ // we need to explicitely unmap it.
175+ // mprotect((void*) hostAddress, size, PROT_NONE);
176+ if (munmap ((void *) hostAddress, size) < 0 ) {
177+ g_s2e->getWarningsStream (nullptr ) << " Could not unmap host RAM\n " ;
178+ exit (-1 );
179+ }
180+
181+ // Make sure that the memory space is reserved and won't be used anymore
182+ // so that there are no conflicts with klee memory objects.
183+ void *newhost = mmap ((void *) hostAddress, size, PROT_NONE, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0 , 0 );
184+ if (newhost == MAP_FAILED || newhost != (void *) hostAddress) {
185+ g_s2e->getWarningsStream (nullptr ) << " Could not map host RAM\n " ;
186+ exit (-1 );
187+ }
188+ }
189+
190+ m_asCache.registerPool (hostAddress, size);
191+ #endif
192+ }
193+
194+ void S2EExecutionState::saveSharedConcreteMemory () {
195+ for (auto &mo : m_saveOnContextSwitch) {
196+ auto os = addressSpace ().findObject (mo.address );
197+ auto wos = addressSpace ().getWriteable (os);
198+ uint8_t *store = wos->getConcreteBuffer ();
199+ assert (store);
200+ memcpy (store, (uint8_t *) mo.address , mo.size );
201+ }
202+ }
203+
204+ void S2EExecutionState::restoreSharedConcreteMemory () {
205+ for (auto &mo : m_saveOnContextSwitch) {
206+ auto os = addressSpace ().findObject (mo.address );
207+ const uint8_t *store = os->getConcreteBuffer ();
208+ assert (store);
209+ memcpy ((uint8_t *) mo.address , store, mo.size );
210+ }
211+ }
212+
112213/* **/
113214
114215void S2EExecutionState::enableForking () {
0 commit comments