Open lwerdna opened 7 years ago
As described in Vector35/binaryninja-api#1123, while disassembling a PPC binary for the Broadway (750CL) I found multiple PPC instructions not supported by Binary Ninja, which aren't present in the table above:
and probably more which I just haven't seen yet (or are hidden behind these non-supported instructions).
For the future (for other unsupported ASM instructions), would it be possible to make Binary Ninja detect an unsupported instruction, display it as "??" but still continue disassembling the function? PPC asm instructions always have 4 bytes so it should be possible to ignore an unknown instruction and continue anyways ...
Sorry for bringing this up again, but is there any time frame when these missing instructions (#1123) can be added to Binary Ninja? I tried implementing them myself with an architecture plugin, but the examples I found are more about creating a new architecture, not adding instructions to an existing one so I was unable to get that to work.
Also, I noticed that for floating-point related instructions like lfs or stfs (and others), Binary Ninja doesn't display the corresponding memory address (like data_80123456), even though it can determine that just fine if the instruction were lwz (load integer) instead of lfs (load float); so one cannot assign variable names to these float variables. I'm not sure though if that is related to PPC lifting completion or if that would better fit into a new bug report.
Bringing this up again, still not fixed in 1.2. It's now over a year that I first reported the issue of lots of PPC instructions missing, and I am kinda annoyed that this is still not fixed. Am I the only one who uses Binary Ninja with PPC binaries? This issue must come up for other people as well, with the amount of instructions missing. And I don't even know if these are all the ones missing because Binary Ninja just stops disassembling a function when it encounters an unknown instruction...
Any update on when Binary NInja will support ALL PPC instructions? I don't need them to be fully lifted to the Intermediate Languages (that's whole another story, my binary shows 144107 "unimplemented instructions" in the new tag type view), but Binary Ninja should recognize the byte code and display the ASM code line and continue disassembling the function instead of just stopping ...
I'm very sorry for the delay on responding to this--it's totally understandable that you'd be frustrated.
There are definitely other users using Binary Ninja on PowerPC, but because there's a wide variety of different compilers and specific hardware revisions, it's entirely possible that the set of instructions you're missing are not as common across other people's environments. From the instructions you're describing my guess is you're doing Gamecube/Wii reversing while, for example, lots of other users might be analyzing networking equipment which also runs on powerpc and is less likely to use some of the same instructions.
As for just continuing disassembly, we don't want to just treat all four-byte patterns as valid instructions and keep scanning for bytes because that would produce a tremendous amount of garbage functions and not actually improve the results.
The good news is that there's three ways to fix/work around the problem. The first is to simply replace byte patterns that are commonly stopping execution with a NOP (at the least that would let you see how many total instructions are missing). The better fix though is to create an architecture extension that adds support for the specific instructions you're running into. The good news is there are several example architecture extensions: https://github.com/Vector35/binaryninja-api/blob/dev/python/examples/arch_hook.py https://github.com/Vector35/binaryninja-api/tree/dev/examples/x86_extension
Performance is much worse with python versus a native plugin, but it might be worth it depending on the size of the binaries.
Finally, you can even see how we're implementing our PPC support (https://github.com/Vector35/ppc-capstone) and submit PRs to that, though it's potentially a lot more involved than the other two.
I wish I could tell you we had an immediate fix planned for all PPC, but we don't have it currently scheduled at this time. I'll bring it up during our next team meeting to see if anyone has some time to put into it.
Hi Leseratte10, thanks for your feedback and sorry that you've been blocked on this issue.
This architecture was written to demonstrate how an existing disassembler could quickly bootstrap a creating an architecture. Obviously a huge drawback is that we adopt whatever shortcomings the disassembler has and Capstone unfortunately only makes available "ppc64" which won't decode those instructions.
We're tempted to make one-off exceptions for the 5 cases you provided (fcmpo, lq, psq_st, xxpermr, ps_muls0) but as soon as we start with psq_st for example, we know psq_stx, psq_stu, psq_stux will be an issue.
Your suggestion to return "???" is also tempting, but we rely on the disassembler failing to decode certain instructions to help Binary Ninja in the phase where it's searching about the binary and discerning between code and data.
The right thing to do is dump Capstone and make a disassembler that lets you choose which PPC variant you're working on, 750 in your case. According to binutils/libopcodes, different variants can have different ideas of which instructions are missing, and in some cases how a fixed instruction word should be decoded:
fcmpo:
(ppc) FC010040: fcmpo cr0,f1,f0
(ppc64) FC010040: fcmpo cr0,f1,f0
(ppc_403) FC010040: fcmpo cr0,f1,f0
(ppc_403gc) FC010040: fcmpo cr0,f1,f0
(ppc_405) FC010040: fcmpo cr0,f1,f0
(ppc_505) FC010040: fcmpo cr0,f1,f0
(ppc_601) FC010040: fcmpo cr0,f1,f0
(ppc_602) FC010040: fcmpo cr0,f1,f0
(ppc_603) FC010040: fcmpo cr0,f1,f0
(ppc_ec603e) FC010040: fcmpo cr0,f1,f0
(ppc_604) FC010040: fcmpo cr0,f1,f0
(ppc_620) FC010040: fcmpo cr0,f1,f0
(ppc_630) FC010040: fcmpo cr0,f1,f0
(ppc_750) FC010040: fcmpo cr0,f1,f0
(ppc_860) FC010040: fcmpo cr0,f1,f0
(ppc_a35) FC010040: fcmpo 0,f1,f0
(ppc_rs64ii) FC010040: fcmpo 0,f1,f0
(ppc_rs64iii) FC010040: fcmpo 0,f1,f0
(ppc_7400) FC010040: fcmpo cr0,f1,f0
(ppc_e500) FC010040:
(ppc_e500mc) FC010040: fcmpo cr0,f1,f0
(ppc_e500mc64) FC010040: fcmpo cr0,f1,f0
(ppc_e5500) FC010040: fcmpo cr0,f1,f0
(ppc_e6500) FC010040: fcmpo cr0,f1,f0
(ppc_titan) FC010040: fcmpo cr0,f1,f0
(ppc_vle) FC010040:
lq:
(ppc) E3E10038: psq_l f31,56(r1),0,0
(ppc64) E3E10038: psq_l f31,56(r1),0,0
(ppc_403) E3E10038:
(ppc_403gc) E3E10038:
(ppc_405) E3E10038:
(ppc_505) E3E10038: psq_l f31,56(r1),0,0
(ppc_601) E3E10038:
(ppc_602) E3E10038: psq_l f31,56(r1),0,0
(ppc_603) E3E10038: psq_l f31,56(r1),0,0
(ppc_ec603e) E3E10038: psq_l f31,56(r1),0,0
(ppc_604) E3E10038: psq_l f31,56(r1),0,0
(ppc_620) E3E10038: psq_l f31,56(r1),0,0
(ppc_630) E3E10038: psq_l f31,56(r1),0,0
(ppc_750) E3E10038: psq_l f31,56(r1),0,0
(ppc_860) E3E10038: psq_l f31,56(r1),0,0
(ppc_a35) E3E10038: lfq f31,56(r1)
(ppc_rs64ii) E3E10038: lfq f31,56(r1)
(ppc_rs64iii) E3E10038: lfq f31,56(r1)
(ppc_7400) E3E10038: psq_l f31,56(r1),0,0
(ppc_e500) E3E10038:
(ppc_e500mc) E3E10038:
(ppc_e500mc64) E3E10038:
(ppc_e5500) E3E10038:
(ppc_e6500) E3E10038:
(ppc_titan) E3E10038:
(ppc_vle) E3E10038:
psq_st:
(ppc) F3E10028: psq_st f31,40(r1),0,0
(ppc64) F3E10028: psq_st f31,40(r1),0,0
(ppc_403) F3E10028:
(ppc_403gc) F3E10028:
(ppc_405) F3E10028:
(ppc_505) F3E10028: psq_st f31,40(r1),0,0
(ppc_601) F3E10028:
(ppc_602) F3E10028: psq_st f31,40(r1),0,0
(ppc_603) F3E10028: psq_st f31,40(r1),0,0
(ppc_ec603e) F3E10028: psq_st f31,40(r1),0,0
(ppc_604) F3E10028: psq_st f31,40(r1),0,0
(ppc_620) F3E10028: psq_st f31,40(r1),0,0
(ppc_630) F3E10028: psq_st f31,40(r1),0,0
(ppc_750) F3E10028: psq_st f31,40(r1),0,0
(ppc_860) F3E10028: psq_st f31,40(r1),0,0
(ppc_a35) F3E10028: stfq f31,40(r1)
(ppc_rs64ii) F3E10028: stfq f31,40(r1)
(ppc_rs64iii) F3E10028: stfq f31,40(r1)
(ppc_7400) F3E10028: psq_st f31,40(r1),0,0
(ppc_e500) F3E10028:
(ppc_e500mc) F3E10028:
(ppc_e500mc64) F3E10028:
(ppc_e5500) F3E10028:
(ppc_e6500) F3E10028:
(ppc_titan) F3E10028:
(ppc_vle) F3E10028:
xxpermr:
(ppc) F02501D0: xxpermr vs1,vs5,vs0
(ppc64) F02501D0: xxpermr vs1,vs5,vs0
(ppc_403) F02501D0:
(ppc_403gc) F02501D0:
(ppc_405) F02501D0:
(ppc_505) F02501D0: xxpermr vs1,vs5,vs0
(ppc_601) F02501D0:
(ppc_602) F02501D0: xxpermr vs1,vs5,vs0
(ppc_603) F02501D0: xxpermr vs1,vs5,vs0
(ppc_ec603e) F02501D0: xxpermr vs1,vs5,vs0
(ppc_604) F02501D0: xxpermr vs1,vs5,vs0
(ppc_620) F02501D0: xxpermr vs1,vs5,vs0
(ppc_630) F02501D0: xxpermr vs1,vs5,vs0
(ppc_750) F02501D0: xxpermr vs1,vs5,vs0
(ppc_860) F02501D0: xxpermr vs1,vs5,vs0
(ppc_a35) F02501D0: stfq f1,464(r5)
(ppc_rs64ii) F02501D0: stfq f1,464(r5)
(ppc_rs64iii) F02501D0: stfq f1,464(r5)
(ppc_7400) F02501D0: xxpermr vs1,vs5,vs0
(ppc_e500) F02501D0:
(ppc_e500mc) F02501D0:
(ppc_e500mc64) F02501D0:
(ppc_e5500) F02501D0:
(ppc_e6500) F02501D0:
(ppc_titan) F02501D0:
(ppc_vle) F02501D0:
ps_muls0:
(ppc) 10230018: ps_muls0 f1,f3,f0
(ppc64) 10230018: ps_muls0 f1,f3,f0
(ppc_403) 10230018:
(ppc_403gc) 10230018:
(ppc_405) 10230018: machhwu r1,r3,r0
(ppc_505) 10230018: ps_muls0 f1,f3,f0
(ppc_601) 10230018:
(ppc_602) 10230018: ps_muls0 f1,f3,f0
(ppc_603) 10230018: ps_muls0 f1,f3,f0
(ppc_ec603e) 10230018: ps_muls0 f1,f3,f0
(ppc_604) 10230018: ps_muls0 f1,f3,f0
(ppc_620) 10230018: ps_muls0 f1,f3,f0
(ppc_630) 10230018: ps_muls0 f1,f3,f0
(ppc_750) 10230018: ps_muls0 f1,f3,f0
(ppc_860) 10230018: ps_muls0 f1,f3,f0
(ppc_a35) 10230018:
(ppc_rs64ii) 10230018:
(ppc_rs64iii) 10230018:
(ppc_7400) 10230018: ps_muls0 f1,f3,f0
(ppc_e500) 10230018:
(ppc_e500mc) 10230018:
(ppc_e500mc64) 10230018:
(ppc_e5500) 10230018:
(ppc_e6500) 10230018:
(ppc_titan) 10230018: machhwu r1,r3,r0
(ppc_vle) 10230018:
We're making a disassembler now that will take as input the variant you're working on, and then you can select that variant in the architecture list.
I'll try to get those 5 exceptions you listed on the dev channel just so you're not stuck until our better version comes out. But lq
I can't reproduce, can you verify the E3E10038 encoding?
Hm, apparently the disassembler I used last year to get from e3e10038 to the opcode was wrong, looks like this is indeed psq_l f31,56(r1),0,0
like you found out.
I am looking forward to the release of a proper disassembler that allows me to directly select the 750(CL) so it supports all of its instructions. I don't know if there'd be more exceptions other than the five I already mentioned, as there might be some more unsupported instructions that currently hide behind the already known unsupported ones.
So did I understand that correctly, when you have that new disassembler finished that allows me to directly select the PPC variant I'm using that that will support all the instructions that processor supports?
So did I understand that correctly, when you have that new disassembler finished that allows me to directly select the PPC variant I'm using that that will support all the instructions that processor supports?
Yes. Well that's the goal. So far attempts to analyze the instruction space and automatically find points of agreement and disagreement among the variants have been promising. It's a neat problem, find me on slack if you have ideas to share.
@Leseratte10, if your Binja is set up to update from the dev channel (Binary Ninja -> Preferences -> Update Channel -> Internal development builds), would you mind giving 1.2.1937 or newer a try?
Downloaded 1.2.1937, opened my BNDB, clicked "reanalyze current function", but instructions like fe310058 still only result in "??". Do I need to enable that new feature somewhere and tell Binary Ninja I'm using a 750CL?
You didn't miss any steps, the instructions you reported earlier should work. But I'm having trouble decoding FE310058 in particular. None of the libopcodes variants will decode it, and in the 750CL doc, it says all the new instructions specific to that core have opcode 4 (0b000100) while this has opcode 63 (0b111111) on the most significant side.
Sorry for the confusion, I made a typo. I meant f3e10058.
f02501d0 (xxpermr) and fc010040 (fcmpo) and 10230018 (ps_muls0) are now displayed correctly. f3e10058/f04501d8/f03e8028 (psq_st) or e3e10038 (lq) aren't recognized.
No problem! Would you mind sharing the reference disassembler you're using? I was sad to find recently libopcodes output sometimes disagrees the spec.
f3e10058/f04501d8/f03e8028 (psq_st)
f04501d8 and f03e8028 disassemble to psq_st for me but f3e10058 is xscmpgtdp according to libopcodes:
(ppc) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc64) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_403) F3E10058:
(ppc_403gc) F3E10058:
(ppc_405) F3E10058:
(ppc_505) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_601) F3E10058:
(ppc_602) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_603) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_ec603e) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_604) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_620) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_630) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_750) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_860) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_a35) F3E10058: stfq f31,88(r1)
(ppc_rs64ii) F3E10058: stfq f31,88(r1)
(ppc_rs64iii) F3E10058: stfq f31,88(r1)
(ppc_7400) F3E10058: xscmpgtdp vs31,vs1,vs0
(ppc_e500) F3E10058:
(ppc_e500mc) F3E10058:
(ppc_e500mc64) F3E10058:
(ppc_e5500) F3E10058:
(ppc_e6500) F3E10058:
(ppc_titan) F3E10058:
(ppc_vle) F3E10058:
e3e10038 (lq)
e3e10038 is psq_l according to libopcodes:
(ppc) E3E10038: psq_l f31,56(r1),0,0
(ppc64) E3E10038: psq_l f31,56(r1),0,0
(ppc_403) E3E10038:
(ppc_403gc) E3E10038:
(ppc_405) E3E10038:
(ppc_505) E3E10038: psq_l f31,56(r1),0,0
(ppc_601) E3E10038:
(ppc_602) E3E10038: psq_l f31,56(r1),0,0
(ppc_603) E3E10038: psq_l f31,56(r1),0,0
(ppc_ec603e) E3E10038: psq_l f31,56(r1),0,0
(ppc_604) E3E10038: psq_l f31,56(r1),0,0
(ppc_620) E3E10038: psq_l f31,56(r1),0,0
(ppc_630) E3E10038: psq_l f31,56(r1),0,0
(ppc_750) E3E10038: psq_l f31,56(r1),0,0
(ppc_860) E3E10038: psq_l f31,56(r1),0,0
(ppc_a35) E3E10038: lfq f31,56(r1)
(ppc_rs64ii) E3E10038: lfq f31,56(r1)
(ppc_rs64iii) E3E10038: lfq f31,56(r1)
(ppc_7400) E3E10038: psq_l f31,56(r1),0,0
(ppc_e500) E3E10038:
(ppc_e500mc) E3E10038:
(ppc_e500mc64) E3E10038:
(ppc_e5500) E3E10038:
(ppc_e6500) E3E10038:
(ppc_titan) E3E10038:
(ppc_vle) E3E10038:
I used powerpc-eabi-objdump v2.32 from devkitPPC, set to the CPU type "powerpc:750". That returns "psq_st f31,88(r1),0,0" for the op code f3 e1 00 58, and "lq r30,48(r1)" for op code e3 e1 00 38.
https://onlinedisassembler.com/odaweb/ returns the same instructions when set to "powerpc:750" and big-endian.
Maybe that is just an alias / simplification? Like "nop" is an alias for "or r0, r0, r0"?
I would have thought powerpc-eabi-objdump linked against libbfd and libopcodes.
The lq
instruction isn't in my 750CL pdf, but it is in the PowerISA v2.0.7 pdf and by hand decoding you're right: E3E10038 should be lq
.
But no psq_* instructions appear in the PowerISA pdf. The 750CL doc has psq_stx
and psq_stux
(and they should decode in Binja) but it does not have psq_st
and I'm pretty confident it's not a synonym or alias because the ones with x at the end have opcode 4 while f3e10058 has opcode 60.
But then a search turns up psq_st
and psq_stu
in the Gekko manual:
I'll stick those encodings into what Binja calls PPC, but doing this right will take some thought. Before seeing psq_st
missing from the PowerISA spec, I'd mistakenly believed it contained the union of all instructions from each variant, sort of a super lookup table. And all variants would just select or subset some portion from this super lookup table.
Hmmm, maybe libopcodes had good reason not to decode e3e10038 to lq
:
Note the bit:
If RTp is odd or RTp=RA, the instruction form is invalid."
Instruction word e3e10038 splits to opcode==111000, RTp==11111, RA==00001, DQ==000000000011 so RTp is odd. If we change it to even, RTp==11110 then the word becomes e3c10038 and:
(ppc) E3C10038: lq r30,48(r1)
(ppc64) E3C10038: lq r30,48(r1)
(ppc_403) E3C10038:
(ppc_403gc) E3C10038:
(ppc_405) E3C10038:
(ppc_505) E3C10038: lq r30,48(r1)
(ppc_601) E3C10038:
(ppc_602) E3C10038: lq r30,48(r1)
(ppc_603) E3C10038: lq r30,48(r1)
(ppc_ec603e) E3C10038: lq r30,48(r1)
(ppc_604) E3C10038: lq r30,48(r1)
(ppc_620) E3C10038: lq r30,48(r1)
(ppc_630) E3C10038: lq r30,48(r1)
(ppc_750) E3C10038: lq r30,48(r1)
(ppc_860) E3C10038: lq r30,48(r1)
(ppc_a35) E3C10038: lfq f30,56(r1)
(ppc_rs64ii) E3C10038: lfq f30,56(r1)
(ppc_rs64iii) E3C10038: lfq f30,56(r1)
(ppc_7400) E3C10038: lq r30,48(r1)
(ppc_e500) E3C10038:
(ppc_e500mc) E3C10038:
(ppc_e500mc64) E3C10038:
(ppc_e5500) E3C10038: lq r30,48(r1)
(ppc_e6500) E3C10038: lq r30,48(r1)
(ppc_titan) E3C10038:
(ppc_vle) E3C10038:
Since there's no reason an invalid instruction would be randomly in the stream of valid instructions, or no reason for the compiler to have emitted this, I'm forced to think this parity rule on RTp is only a PowerISA rule and doesn't exist on the Gecko.
Current collection of PPC complexities:
I think @Leseratte10 is getting confused, and also I'd like to jump in with my two cents Sorry this is so long, I was searching around for answers, found this, and went on a tangent
To be honest, I don't really care what these instructions disassemble into, I'd just like them all to disassemble into something so Binary NInja can finally disassemble all the functions and doesn't stop at the first unknown instruction ...
Are there any plans to add the missing PowerPC instructions, specifically floating-point support? I've bought Binary Ninja specifically for PowerPC, but can't really use it with any code heavy on floats. Am I just using it wrong or have the wrong settings?
Looking at the FAQ, I was assuming that BN supports lifting for the PowerPC instruction set.
I'm very interested in this thread! Was there ever any resolution, any instructions added or any way to disassemble instructions with opcodes like opcode 60?
Since we originally filed this issue we've open-sourced our architectures so it's possible to extend out the architecture for any given situation but we don't have specific architectures or instructions scheduled for a refresh at this time.
https://github.com/Vector35/arch-ppc
You'll notice however that we are still maintaining them and adding instructions that can serve as a model for any changes you want made:
https://github.com/Vector35/arch-ppc/commit/e9e8f72e9600703d472c6f6fa6743c0159390f9b
If you're interested in using your own modified architecture module, simply make any modifications, build your local copy as described in the readme, and then disable the built-in arch in Settings / Core Plugins / architectures:
The open source PPC architecture plugin -- like all architecture plugins -- has moved:
https://github.com/Vector35/binaryninja-api/tree/dev/arch/powerpc
The following is the list of instructions which we currently disassemble and lift (Fully or Partially). If you have any instructions which differ from this table, there is likely a bug or a documentation failure, please let us know.