-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Weird bug in ARM emulation(investigating but need some help about code behaviour) #287
Comments
Can you please put together a sample code exposing this issue, and send in Thanks. |
I'm sorry that I can't provide the codes which trigger this bug for some reasons, and I don't know how to properly construct a minimal test case. So I asked for help, try to find and fix it locally. Of course I will send a pull request once I identify and fix it, if I can't fix it by myself, I will also share my discover with you here. |
if you can narrow down the input to just some bytes triggering the issue, i think you can show it without disclosing anything. |
@aquynh Once I know the range of bytes trigger this issue, I will share it. Now some new discovery, I found the point probably should be responsible for this issue or somehow relate. I attach to the thread continue occupy the CPU(one core full load), and the stack trace is like this: (gdb) bt I run the same debug session in a linux build and the backtrace is also similar, gdb complain stack corrupt. (gdb) thread 2 And both point that static_code_gen_buffer() as the top of the stack. |
you can find out which instruction triggers the crash by hooking every instructions, and print out its bytes before the instruction is executed. this is possible by having a callback like this: https://github.com/unicorn-engine/unicorn/blob/master/samples/sample_x86.c#L41. then you have to register the callback before emulation, with UC_HOOK_CODE hook, like this https://github.com/unicorn-engine/unicorn/blob/master/samples/sample_x86.c#L205 |
@aquynh Not crash, my first post has detail description of this issue. |
hmm... gdb can help me better... I think I don't need to modify the code~ |
Finally solved... a bug hidden very deep. It's a bug introduced by Unicorn modification to TCG(that's why it's not in qemu, which will surely be encountered and fixed already), in the tcg_liveness_analysis. ... Since liveness analysis is backward, first in Point A, NF as output operand, is sentenced to death and got the corresponding In-Memory bit clear, previous op will not sync result to it if it's used as output operand again, without In-Memory state refresh, that is, Point C will failed to remember NF(in the generated host code, discard), and then in label $0x5, condition check will be wrong if the subtraction is skipped. In Qemu, the brcond in Point B comes to rescue, but Unicorn prevent it altogether. IIUC, we should prevent only dead_temps refresh for brcond, and keep refresh TCG globals In-Memory states for brcond op. At least after the change I described above, my codes work properly, the bug is gone. I will learn to send a pull request ASAP. Any comments are welcome. |
This bug is really deep and very subtle, in the process of tracing it, it teach me many things about TCG... hooray for the solution... |
looks interesting, but with your fix, does everything else (especially those under tests/unit/ & tests/regress/) still works as before? here is what you should do to make a pull request. (i suppose you are using commandline on Mac or Linux)
you can repeat all the steps above for each pull request, but with different branch name each time |
Can I do the unit test in Windows? the default build configure of windows does not contain unit test code built, is it possible to build the unit test in Windows? |
yes you can try on Windows, but everything is much easier on Unix. |
It's not as fluid as it should be. I try to build the unit test(tests/unit) in a Ubuntu box, the linker still complained symbol not found(all are symbols from cmocka, IIUC. I encountered the same problem in Windows with mingw, so I gave up there and move to a Ubuntu box) . I've built cmocka-1.0.1 and install it already, and I even read the Makefile, know it include the root of unicorn directory as a library search directory, so I manually copy libcmocka.so(and the sym links) to here, and it still doesn't work. anything wrong? |
The patch is ready for test, but since test can not be built successfully, I'm not sure enough whether it will break them or not. |
On Dec 21, 2015 3:45 PM, "JCYang" notifications@github.com wrote:
Ok, just send a pull request so we can review and test it. Thanks. |
the tcg_liveness_analysis(). Refer to unicorn-engine#287 for further info.
I did have a problem with the ZF flag not being cleared when it should, perhaps it's related to this? |
@farmdve Maybe, any code result in brcond in the middle of a TB may introduce a scenario trigger this bug, I haven't look into x86 translator, though IIRC no condition-per-instruction code there. I've added a test case for this bug yesterday which contain detail explanation, which can help you better understand this bug. |
Some words about the initial weird behavior I found: |
But I don't think global hook can be used as a workaround, because global hook, first will slow down the emulation greatly, second, global hook has the highest priority in Unicorn, it will effectively disable all other hooks, force the user to write all hook logic in one place can be annoying, and sometimes even possible, is awful. |
merged the pull request to fix this issue, thanks! |
the tcg_liveness_analysis(). Refer to unicorn-engine#287 for further info.
how to get the tcg code like that? it is costly to type these codes b hands. @JCYang |
can you propose a fix, with pull req?
|
I emulated some ARMv7(thumb and ARM mixed) code and tried to exam the memory status at some point.
In order to emulate a known imported function, I hooked the entry of the lazy link PLT block(uc_hook_add + UC_HOOK_CODE) of the function and patched it to BX LR(I write r0 in my emulation codes), and it worked.
But a bug found, emulator seems to halt at a certain point later, yet the CPU usage indicate it is still live and running. In order to investigate what's wrong, I tried adding global instruction hook which simply print the instruction ran, in the callback of my patched hook. And weird thing happen, this very bug got "fixed", the engine continue to run to the "until" instruction I specified.
Some code snippet might better tell the story:
def GlobalHook(uc_emu, address, code_size, usr_data):
pass # even place holder helps!!!
def EmulateFunc(uc_emu, address, code_size, usr_data):
r0 = uc_emu.reg_read(UC_ARM_REG_R0)
# some calculation here
uc_emu.reg_write(UC_ARM_REG_R0, result)
uc_emu.hook_add(UC_HOOK_CODE, GlobalHook) # without this hook, the engine will halt at a certain point later
I've tried to read and modify Unicorn to help diagnose this bug, so I know it halt at a certain point.
And I guess, the hook callback codes make a different to the internal states of the engine, but I'm not familiar with Unicorn codebase, and the code generation engine it used, when I try to look for gen_helper_uc_tracecode from the source, only one invoke location and the definition is nowhere.
I'm continue investigating this bug and would like to fix it, but I really need some help from you, thank you.
The text was updated successfully, but these errors were encountered: