Skip to content

Pipeline definition

ReOxide can reconfigure the decompilation pipeline by using the default.yaml file in the parent directory of the plugins directory, e.g. /home/user/.local/share/Reoxide. If this file does not exist, reoxided copies it here on startup. This file has the same pipeline that Ghidra uses to decompile code:

yaml
- action: start
  group: base
- action: constbase
  group: base
- action: normalizesetup
  group: normalanalysis
- action: defaultparams
  group: base
- action: extrapopsetup
  group: base
- action: prototypetypes
  group: protorecovery
- action: funclink
  group: protorecovery
- action: funclink_outonly
  group: noproto
- action_group: fullloop
  actions:
  - action_group: mainloop
    actions:
    - action: unreachable
      group: base
      ...

The structure of this pipeline mirrors the definition of the universal action described in the overview of the Ghidra decompilation pipeline. Four different types of entries describe the pipeline:

  • action: A Ghidra Action
  • rule: A Ghidra Rule
  • action_group: A grouping of Action objects
  • pool: A grouping of Rule objects

When adding an action or rule entry to the yaml file, you need to specify a name and a group. The following example shows the first action entry, the action with the name start:

yaml
- action: start
  group: base

The ReOxide manager will search all loaded plugins for this name on startup and then construct the action from this plugin. All plugins currently share a global namespace and the libcore.so plugin defines the start action. We also see that the action definition specifies base as its target group. This causes the execution of the action apply function when Ghidra selects the base group during construction of a default action. If you want to make sure that an action executes during the decompile default action, the default groups documentation lists all groups enabled by this action. The definition of rules follows the same pattern, except only pool entries allow listing rules.

Action and rule containers

The action_group entry structures the control-flow of the actions inside the group. Because Ghidra currently initializes all action groups with the Action::rule_repeatapply flag, the action group restarts if any of the rules apply. Examine the following excerpt from the default pipeline:

yaml
...
- action_group: fullloop
  actions:
  - action_group: mainloop
    actions:
    - action: unreachable
      group: base
    - action: varnodeprops
      group: base
    - action: heritage
      group: base
    - action: paramdouble
      group: protorecovery
    ...

Ghidra defines fullloop as outermost action group, making it the primary loop of the pipeline. Since we can treat an action_group the same as a normal action, we can use the mainloop as an action inside the fullloop group. The mainloop group then consists of actual action objects. This means, for every change an action makes inside mainloop, the mainloop restarts. Conversely, if mainloop applied any changes, the outer fullloop will also restart after the mainloop execution finished.

In a similar manner, pool objects group rule objects. We can treat pool objects the same as an action, but the pool itself can only hold rule objects. The following excerpt shows one of the default pipeline pools:

yaml
...
    - action: infertypes
      group: typerecovery
    - action_group: stackstall
      actions:
      - pool: oppool1
        rules:
        - rule: earlyremoval
          group: deadcode
        - rule: termorder
          group: analysis
        - rule: selectcse
          group: analysis
        - rule: collect_terms
          group: analysis
        - rule: pullsub_multi
          group: analysis
        - rule: pullsub_indirect
          group: analysis
        - rule: push_multi
          group: nodejoin
        ...

The oppool1 pool works the same way as the action_group. The contained rules apply to P-Code opcodes and the pool tries to apply these rules repeatedly until they do not trigger any further changes. In comparison to the action object, pool and action_group do not have a group attribute. This means they do not have a default group and Ghidra cannot disable entire action groups or pools. Instead, if the specified default action does not include, for example, the deadcode group, the earlyremoval rule in the excerpt will not run. Conversely, the looping structure of action groups and pools still stays the same, even if they no longer contain any actions or groups.