Revamp flags to allow fine grained control over aliasing - #3008
Conversation
Rot127
left a comment
There was a problem hiding this comment.
I might have overlooked it because Github lags. But I don't see any tests with other combinations than real text.
Please add all the cases we discussed in the threads before here.
Especially the edge cases. And document them appropriately please.
|
@slate5 |
| } else { // the instruction is not an alias | ||
| if (!is_uncompressed) { | ||
| printInstruction(MI, MI->address, O); | ||
| } else if (printAliasInstr(McInstr, |
There was a problem hiding this comment.
Please just have a MI and an MIUncompressed pointer.
It is pretty confusing to follow, because on a first look it seems like MI = McInstr.
There was a problem hiding this comment.
Fair point, the original naming is terrible.
| if (isUncompressedRealSyntax(MI)) { | ||
| printInstruction(McInstr, McInstr->address, O); | ||
| } else { | ||
| // side-effectful check for alias instructions that prints to the SStream if true |
There was a problem hiding this comment.
What does "side-effectful" mean?
There was a problem hiding this comment.
Just a note to self that it prints to the SStream AND returns true, or returns false and doesn't print.
I find this kind of "already did the thing in the if's condition" highly confusing and counterintuitive, so that's why I commented it. For me the ideal is always that conditions are stateless.
There was a problem hiding this comment.
Yeah, the comment is good. Please be more descriptive though.
| } | ||
| } else // the instruction is not an alias | ||
| printInstruction(McInstr, MI->address, O); | ||
| } |
There was a problem hiding this comment.
Assertion else case is missing.
There was a problem hiding this comment.
It's kinda implicit, the then is itself a kind of "else". Because when printAliasInstr is true then nothing needs to be done, so the negated condition itself is kinda of "then" block.
But when printAliasInstr returns false, the negation makes the then execute as if it's the "else" case.
(If you're wondering why, unlike the duplicated block of code above, there is no setAlias(..., true | false), it's because there is no reason to repeat this, that's why the conditional can be simplified somewhat.)
I can abstract it into a macro, not sure if a function can work here.
There was a problem hiding this comment.
It is about defensive programming. Something changes in the function and suddenly there is an "else" case executed but not handled. That is why a simple CS_RETURN_IF_FAIL() is enough but necessary
| cs_arch archs[CS_ARCH_MAX]; | ||
| cs_opt_value opt; | ||
| cs_mode mode; | ||
| cs_opt_type type; |
There was a problem hiding this comment.
| cs_opt_type type; | |
| cs_opt_type opt_type; |
There was a problem hiding this comment.
If I haven't overlooked something, there are only the combination covered for:
CS_OPT_SYNTAX_REAL + default
CS_OPT_SYNTAX_REAL + CS_OPT_DETAIL_REAL
CS_OPT_SYNTAX_ALIAS + default
CS_OPT_SYNTAX_UNCOMPRESSED_REAL + default
So there are still the cases missing for:
CS_OPT_SYNTAX_REAL + CS_OPT_DETAIL_ALIAS
CS_OPT_SYNTAX_REAL + CS_OPT_DETAIL_UNCOMPRESSED_REAL
CS_OPT_SYNTAX_ALIAS + CS_OPT_DETAIL_REAL
CS_OPT_SYNTAX_ALIAS + CS_OPT_DETAIL_ALIAS
CS_OPT_SYNTAX_ALIAS + CS_OPT_DETAIL_UNCOMPRESSED_REAL
CS_OPT_SYNTAX_UNCOMPRESSED_REAL + CS_OPT_DETAIL_REAL
CS_OPT_SYNTAX_UNCOMPRESSED_REAL + CS_OPT_DETAIL_ALIAS
CS_OPT_SYNTAX_UNCOMPRESSED_REAL + CS_OPT_DETAIL_UNCOMPRESSED_REAL
I know it is annoying, but it is important that we have them checked at least twice. Ones with a normal instruction, once with a compressed.
I think it is better to add a new yaml file for those.
There was a problem hiding this comment.
Never hurts to add tests, I will do that.
| Note that `+noalias` "overpowers" `noaliascompressed` in the second case: despite `+noaliascompressed` being false, meaning aliases are wanted for compressed instructions, `+noalias` being true means ALL aliases are supressed, and this takes precedence. Other than that, case 1 and case 3 work as intuitively expected, and case 4 is redundant. | ||
|
|
||
| So a single-sentence description of this table is: if `+noalias` is given then no aliases will be printed for any instruction, but if not given then aliases will be printed for non-compressed instruction and alias printing for compressed instruction futher checks `+noaliascompressed` before proceeding. | ||
| - Added RISC-V syntax/detail options for selecting real, uncompressed-real, or alias-preferred printing/details: |
There was a problem hiding this comment.
I am sorry, I didn't mentioned it in the first comment.
I was thinking more about a table like this:
| Flag combination | normal insn | compressed instruction |
|---|---|---|
| CS_OPT_SYNTAX_REAL + default | asm: real insn text, details: real detail |
asm: compressed real text, detail: compressed real details |
| CS_OPT_SYNTAX_REAL + CS_OPT_DETAIL_REAL | asm: real insn text, details: real detail |
asm: compressed real text, detail: compressed real details |
| CS_OPT_SYNTAX_REAL + CS_OPT_DETAIL_ALIAS | asm: real insn text, details: alias detail |
asm: compressed real text, detail: compressed alias details |
| ... |
The reason I prefer a table over sentences with pictures is two fold:
- We must assume some new user starts using RISC-V and quickly wants to lookup what result a combination of flag will give them. They have only two kind of info:
what flags they use,what type the instruction is. Reading long sentences with many commas is very error prone for that case. - The state machine pictures are not exhaustive, because they seem to only show the asm text case. The detail flags are missing in there, right? That makes it more confusing in combination with the next.
There was a problem hiding this comment.
I see, but maybe it's wasteful to do every combination of two flags from the sets of flags ? they're completely orthogonal, no interaction whatsoever. It's never the case that a flag from one set affects the behaviour of another flag from a different set.
Maybe I thought about this so hard that it looks obvious though.
What makes this harder is that the *_ALIAS flag has like 5 different cases: full instruction prints as alias, compressed instruction prints as alias, full instruction prints as itself, compressed instruction prints as itself, compressed instruction uncompresses then prints as alias, compressed instruction uncompresses then prints as the equivalent normal instruction. Multiplying that by 6 (text alias flag with all 3 details flag, and details alias flag with all 3 text) would yield 30 cases (!). Most of that would be repetitive copy pasta, since varying text flags doesn't change details behaviour and varying the details flags doesn't change text behaviour.
How about just 2 seperate table for each sets of flags, each table having the 5 different cases for the alias (the other two are pretty tame and only discriminate between compressed and non-compressed like you sketched them).
There was a problem hiding this comment.
Give me a sec to post a table that I think is much better than the cartesian product of {all text flags} x {all details flag} x {all instruction cases}
Your checklist for this pull request
Detailed description
Implementing the extensive discussions here #2923 and here #2959.
Test plan
...
Closing issues
...