unicorn-engine / unicorn

Unicorn CPU emulator framework (ARM, AArch64, M68K, Mips, Sparc, PowerPC, RiscV, S390x, TriCore, X86)
http://www.unicorn-engine.org
GNU General Public License v2.0
7.63k stars 1.35k forks source link

Question on saving and restoring memory snapshots #2043

Closed ivlzme closed 2 weeks ago

ivlzme commented 2 weeks ago

I'm attempting to use Unicorn (v2.1.1) for some full system emulation. My assumption is that calling uc_context_save() saves both the CPU state and the memory mappings into the uc_context object. Then, the emulation can be restored to the same CPU and memory state by calling uc_context_restore() with the saved uc_context. Is this assumption correct?

I also noticed Unicorn was erroring out specifically in uc_mem_protect() when I'm trying to save a snapshot. I found this comment in uc.c:

UNICORN_EXPORT
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
                      uint32_t perms)
{
    // ... removed for brevity

    // snapshot and protection can't be mixed
    if (uc->snapshot_level > 0) {
        restore_jit_state(uc);
        return UC_ERR_ARG;
    }

Can you explain why snapshots and memory protections cannot coexist?

Thanks in advance!

wtdcode commented 2 weeks ago

https://github.com/unicorn-engine/unicorn/pull/1820#issuecomment-1557115623

See this comment and the full conversation if you are interested. Personally, implementing uc_mem_protect for the snapshots is possible but I expect lots of corner cases here.

What do you think? @PhilippTakacs Is there any issue if we just overwrite the permission of parent memory regions when restoring snapshots?

ivlzme commented 2 weeks ago

Thank you for linking the previous conversation, that helped provide a lot of context. I now understand the reasoning behind using an incremental snapshot with snapshot_level and why memory protections cannot coexist.

For my use-case, I have a program that takes a long time to emulate until the function I am interested in is reached. I had hoped to use the memory snapshot feature to create some sort of save file that can be written to disk and can be restored on a future emulation, but that is not how the current snapshot feature was designed.

wtdcode commented 2 weeks ago

For my use-case, I have a program that takes a long time to emulate until the function I am interested in is reached. I had hoped to use the memory snapshot feature to create some sort of save file that can be written to disk and can be restored on a future emulation, but that is not how the current snapshot feature was designed.

That is https://github.com/unicorn-engine/unicorn/pull/1963#discussion_r1802608473 then. You should save memory like what qiling does (reading content through mapping).

PhilippTakacs commented 2 weeks ago

Is there any issue if we just overwrite the permission of parent memory regions when restoring snapshots?

The main reason for not allowing change of protection was, splitting regions is not possible with snapshots. For complete regions this could be implemented. It just need to store the old permissions somewhere. On restore the permission of the parent and all subregions could be changed back. It would be very similar to the implementation of unmap with snapshots.

I haven't implemented this because it's complex, has many corner cases to consider and needs some time to change and restore. Also with the tlb callbacks changing permissions is possible, even for more complex situation (i.e. have a region executable on one address and writable on another at the same time).

ivlzme commented 2 weeks ago

Thank you for the clarification