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.33k stars 1.31k forks source link

UC_HOOK_MEM_READ only triggered once (x86 64 emulated on mac M1) #1908

Open stevielavern opened 7 months ago

stevielavern commented 7 months ago

Hello,

Description

I'm facing a strange issue where my UC_HOOK_MEM_READ is only called the first time a memory read is encountered. All subsequent reads do not trigger the callback.

Setup

Unicorn has been compiled as per recommendations in the documentation. Unicorn python bindings were installed in a fresh python venv.

Test case

from unicorn import *
from unicorn.x86_const import *

# mov rax, [0x10000]
# mov [0x10000], rax
code = b"\x48\xa1\x00\x00\x01\x00\x00\x00\x00\x00\x48\xa3\x00\x00\x01\x00\x00\x00\x00\x00"*10

# callback for tracing memory access (READ ony)
def hook_mem_access(uc, access, address, size, value, user_data):
    if access == UC_MEM_READ:
        print(f">>> Memory is being READ at {address:#x}, data size = {size}")
    else:
        print(f">>> Memory is being WRITE at {address:#x}, data size = {size}")

def test_x86_64_mem_read():
    print("Emulate x86 64-bit code")
    try:

        mu = Uc(UC_ARCH_X86, UC_MODE_64)
        mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access)

        mu.mem_map(0x10000, 1024*8)
        mu.mem_write(0x10000, b"\xaa"*8)

        # write machine code to be emulated to memory
        mu.mem_map(0, 0x1000)
        mu.mem_write(0, code)

        # emulate machine code in infinite time
        mu.emu_start(0, len(code))

    except UcError as e:
        print("ERROR: %s" % e)

if __name__ == '__main__':
    test_x86_64_mem_read()

Test case output

Emulate x86 64-bit code
>>> Memory is being READ at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8
>>> Memory is being WRITE at 0x10000, data size = 8

As can be seen above, hook_mem_access is only called once for READ while it is expected to be called 10 times. Strangely, this does not affect writes.

TinyNiko commented 6 months ago

I meet the same problem on M2 pro. I test arm64 arch

wtdcode commented 6 months ago

Verified the read operations are inlined. Arm64 backend tends to inline read/write operations.

See: https://github.com/unicorn-engine/unicorn/wiki/FAQ#memory-hooks-are-skipped

1200003E0: F4 03 10 32                orr    w20, wzr, #0x10000
1200003E4: 60 06 7E A9                ldp    x0, x1, [x19, #-0x20]
1200003E8: 00 18 54 8A                and    x0, x0, x20, lsr #6
1200003EC: 21 00 00 8B                add    x1, x1, x0
1200003F0: 20 00 40 F9                ldr    x0, [x1]  # <--- Optimized as a single instruction, x1 = 0x100000
lwerdna commented 3 months ago

Same problem here, M2 :(

keroblabs commented 3 months ago

I'm emulating UC_ARCH_ARM/UC_CPU_ARM_CORTEX_M4 and on Mac M1 host, and I'm not seeing UC_MEM_READ events. Is there a way to overcome this limitation, e.g. recompile the lib with the TCG inlining disabled? I'm trying to emulate peripherals and things needs to take action on read events.

saicao commented 2 months ago

you may try this, not tested full functionalities , since I only need the address and value of reads. https://github.com/saicao/unicorn/commit/026f4c447e944cd855fd0d44fea52ac31bc3a372 @keroblabs

wtdcode commented 2 months ago

@saicao Would you like to submit a PR for that?


From: SAI @.> Sent: Friday, April 12, 2024 11:23:13 AM To: unicorn-engine/unicorn @.> Cc: lazymio @.>; Comment @.> Subject: Re: [unicorn-engine/unicorn] UC_HOOK_MEM_READ only triggered once (x86 64 emulated on mac M1) (Issue #1908)

you may try this, not tested full functionalities , since I only need the address and value of reads. @.***https://github.com/saicao/unicorn/commit/026f4c447e944cd855fd0d44fea52ac31bc3a372 @keroblabshttps://github.com/keroblabs

― Reply to this email directly, view it on GitHubhttps://github.com/unicorn-engine/unicorn/issues/1908#issuecomment-2050896270, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AHJULO4YKUHK5KBRAGYLUUTY45HSDAVCNFSM6AAAAAA7MLCXI6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANJQHA4TMMRXGA. You are receiving this because you commented.Message ID: @.***>

keroblabs commented 2 months ago

@saicao Awesome! I applied the patch locally, rebuilt the lib and now all read events are coming through.