Skip to content

Revamp flags to allow fine grained control over aliasing - #3008

Open
moste00 wants to merge 3 commits into
capstone-engine:nextfrom
moste00:feature/riscv_operands_details
Open

Revamp flags to allow fine grained control over aliasing#3008
moste00 wants to merge 3 commits into
capstone-engine:nextfrom
moste00:feature/riscv_operands_details

Conversation

@moste00

@moste00 moste00 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Your checklist for this pull request

  • I've documented or updated the documentation of every API function and struct this PR changes.
  • I've added tests that prove my fix is effective or that my feature works (if possible)

Detailed description

Implementing the extensive discussions here #2923 and here #2959.

Test plan

...

Closing issues

...

@Rot127 Rot127 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread bindings/python/capstone/__init__.py
Comment thread docs/cs_v6_release_guide.md
Comment thread arch/RISCV/RISCVInstPrinter.c Outdated
@Rot127

Rot127 commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

@slate5
Please take a look as well.

} else { // the instruction is not an alias
if (!is_uncompressed) {
printInstruction(MI, MI->address, O);
} else if (printAliasInstr(McInstr,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "side-effectful" mean?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Rot127 Rot127 Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the comment is good. Please be more descriptive though.

}
} else // the instruction is not an alias
printInstruction(McInstr, MI->address, O);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertion else case is missing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Rot127 Rot127 Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread arch/RISCV/RISCVInstPrinter.c
Comment thread cstool/cstool.c
cs_arch archs[CS_ARCH_MAX];
cs_opt_value opt;
cs_mode mode;
cs_opt_type type;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cs_opt_type type;
cs_opt_type opt_type;

Comment thread tests/details/riscv.yaml

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. 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.
  2. 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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}

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants