Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
stevielavern opened this issue Nov 15, 2023 · 7 comments
Open

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

stevielavern opened this issue Nov 15, 2023 · 7 comments

Comments

@stevielavern
Copy link
Contributor

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 commit d4b9248
  • Host: Mac M1 running macOS 14 (Sonoma)
  • Emulated code: x86 64

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
Copy link

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

@wtdcode
Copy link
Member

wtdcode commented Dec 25, 2023

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
Copy link

lwerdna commented Mar 12, 2024

Same problem here, M2 :(

@keroblabs
Copy link

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 added a commit to saicao/unicorn that referenced this issue Apr 12, 2024
@saicao
Copy link

saicao commented Apr 12, 2024

you may try this, not tested full functionalities , since I only need the address and value of reads.
saicao@026f4c4
@keroblabs

@wtdcode
Copy link
Member

wtdcode commented Apr 12, 2024 via email

@keroblabs
Copy link

keroblabs commented Apr 12, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants