Add r2ghidra.inline to combine inline functions

This commit is contained in:
pancake committed 2026-10-27 23:10:51 +01:00
1 parent af847a9396
commit d6a283c5cf
4 files changed
+172

No files matched your search

+14
View File
@@ -64,6 +64,19 @@ Usage: pdg # Native Ghidra decompiler plugin
| pdgx # Dump the XML of the current decompiled function
```
With radare2 ABI 163 or newer, `pdg` inlines analyzed callees whose `inline`
attribute is set when `r2ghidra.inline` is enabled (the default):
```
afia+ inline @ child
pdg @ caller
```
Disable inlining with `e r2ghidra.inline=false`, or clear the mark with
`afia- inline @ child`. The callee's machine code must be
available in radare2's IO maps, including for external functions. This uses
Ghidra's native inliner for argument passing and control flow.
`pdgx` includes the native p-code operation's `is_dead` boolean on its
`<seqnum>` element, after the existing `space`, `offset` and `uniq` identity
attributes. The value comes from `PcodeOp::isDead()` for that exact operation;
@@ -155,6 +168,7 @@ The following config vars (for the `e` command) can be used to adjust r2ghidra's
r2ghidra.cmt.indent: Comment indent
r2ghidra.deadcode: Include unused code and removed p-code metadata
r2ghidra.indent: Indent increment
r2ghidra.inline: Inline functions marked with the inline attribute
r2ghidra.lang: Custom Sleigh ID to override auto-detection (e.g. x86:LE:32:default)
r2ghidra.linelen: Max line length
r2ghidra.maximplref: Maximum number of references to an expression before showing an explicit variable.
+7
View File
@@ -810,6 +810,13 @@ FunctionSymbol *R2Scope::registerFunction(RAnalFunction *fcn) const {
if (fcn->is_noreturn) {
markNoReturn (funcsym, noreturnHasNoArgs (core, fcn, fcn_name));
}
#if R2_ABIVERSION >= 163
if (funcsym && r_config_get_b (core->config, "r2ghidra.inline") && r_anal_function_is_inline (fcn)) {
if (Funcdata *fd = funcsym->getFunction ()) {
fd->getFuncProto ().setInline (true);
}
}
#endif
return funcsym;
}
+1
View File
@@ -86,6 +86,7 @@ CV cfg_var_casts ("casts", "false", "Show type casts where needed"
CV cfg_var_ccode ("ccode", "false", "Emit clean C identifiers (bare import names, no fcn./sub. prefixes)");
CV cfg_var_deadcode ("deadcode", "false", "Include unused code and removed p-code metadata");
CV cfg_var_fixups ("fixups", "false", "Apply pcode fixups");
CV cfg_var_inline ("inline", "true", "Inline functions marked with the inline attribute");
CV cfg_var_varargs ("varargs", "false", "Recover printf-family varargs from literal format strings");
CV cfg_var_vaformats ("varargs.formats", "", "Extra printf-style formatters for vararg recovery (bare names, comma separated)");
CV cfg_var_roprop ("roprop", "0", "Propagate read-only constants (0,1,2,3,4)");
+150
View File
@@ -0,0 +1,150 @@
# Requires radare2 ABI 163 or newer.
NAME=inline defaults to enabled and respects the config toggle and callee mark
FILE=malloc://256
ARGS=-a x86 -b64
CMDS=<<EOF
wx e83b00000083c002c3
wx b807000000c3 @ 0x40
af child @ 0x40
af caller @ 0
e r2ghidra.inline
pdg @ 0~child(~?
afia+ inline @ 0x40
pdg @ 0~child(~?
pdg @ 0~return 9
e r2ghidra.inline=false
pdg @ 0~child(~?
e r2ghidra.inline=true
pdg @ 0~child(~?
afia- inline @ 0x40
pdg @ 0~child(~?
EOF
EXPECT=<<EOF
true
1
0
return 9;
1
0
1
EOF
RUN
NAME=inline external function loaded in another IO map
FILE=malloc://256
ARGS=-a x86 -b64
CMDS=<<EOF
o malloc://256 0x1000
ompg +x
wx b807000000c3 @ 0x1000
wx e8fb0f000083c002c3 @ 0
af sym.imp.external_child @ 0x1000
af caller @ 0
afia+ inline @ 0x1000
pdg @ 0~external_child(~?
pdg @ 0~return 9
EOF
EXPECT=<<EOF
0
return 9;
EOF
RUN
NAME=inline callee receives a register argument
FILE=malloc://256
ARGS=-a x86 -b64
CMDS=<<EOF
wx bf07000000e83600000083c002c3
wx 8d4703c3 @ 0x40
af child @ 0x40
af caller @ 0
td int child(int x);
afia+ inline @ 0x40
pdg @ 0~child(~?
pdg @ 0~return 0xc
EOF
EXPECT=<<EOF
0
return 0xc;
EOF
RUN
NAME=inline callee receives a stack argument
FILE=malloc://256
ARGS=-a x86 -b32
CMDS=<<EOF
wx 6a07e83900000083c404c3
wx 8b44240483c003c3 @ 0x40
af child @ 0x40
af caller @ 0
td int child(int x);
afia+ inline @ 0x40
pdg @ 0~child(~?
pdg @ 0~return 10
EOF
EXPECT=<<EOF
0
return 10;
EOF
RUN
NAME=inline nested callees are expanded at repeated call sites
FILE=malloc://256
ARGS=-a x86 -b64
CMDS=<<EOF
wx e83b00000089c3e83400000001d8c3
wx e83b00000083c003c3 @ 0x40
wx b807000000c3 @ 0x80
af leaf @ 0x80
af child @ 0x40
af caller @ 0
afia+ inline @ 0x40
afia+ inline @ 0x80
pdg @ 0~child(,leaf(~?
pdg @ 0~return 0x14
EOF
EXPECT=<<EOF
0
return 0x14;
EOF
RUN
NAME=inline callee keeps both early returns and the caller continuation
FILE=malloc://256
ARGS=-a x86 -b64
CMDS=<<EOF
wx e83b00000083c002c3
wx 85ff7406b807000000c3b809000000c3 @ 0x40
af child @ 0x40
af caller @ 0
afia+ inline @ 0x40
pdg @ 0~child(~?
pdg @ 0~iVar1 = 9,iVar1 = 7,return iVar1 + 2
EOF
EXPECT=<<EOF
0
iVar1 = 9;
iVar1 = 7;
return iVar1 + 2;
EOF
RUN
NAME=inline recursion keeps the recursive call
FILE=malloc://256
ARGS=-a x86 -b64
CMDS=<<EOF
wx e83b00000083c002c3
wx e8fbffffff83c001c3 @ 0x40
af child @ 0x40
af caller @ 0
afia+ inline @ 0x40
pdg @ 0~Could not inline here~?
pdg @ 0~child(~?
pdg @ 0~return iVar1 + 3
EOF
EXPECT=<<EOF
1
1
return iVar1 + 3;
EOF
RUN