Merge remote-tracking branch 'origin/GP-5411_emteere_PPCpltThunk' into patch

This commit is contained in:
Ryan Kurtz 2025-03-05 10:18:52 -05:00
commit 57784ead36
4 changed files with 127 additions and 33 deletions

View file

@ -15,6 +15,8 @@
*/
package ghidra.app.cmd.function;
import static ghidra.program.model.symbol.RefType.*;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@ -732,36 +734,66 @@ public class CreateThunkFunctionCmd extends BackgroundCommand<Program> {
FlowType flowType, boolean checkForSideEffects, HashSet<Varnode> setRegisters,
HashSet<Varnode> usedRegisters) {
// conditional jumps can't be thunks.
// any other flow, not good
Address flowingAddr = null;
if ((flowType.isJump() || flowType.equals(RefType.COMPUTED_CALL_TERMINATOR) ||
flowType.equals(RefType.CALL_TERMINATOR)) && !flowType.isConditional()) {
// program counter should be assumed to be used
// conditional jumps/call terminators can't be thunks,
// unless not checkingForSideEffects and just trying to get possible thunk address.
// assume PC is used when considering registers that have been set
Register PC = program.getLanguage().getProgramCounter();
if (PC != null) {
usedRegisters.add(new Varnode(PC.getAddress(), PC.getMinimumByteSize()));
boolean isJump = flowType.isJump();
boolean isCall = flowType.isCall();
boolean isConditional = flowType.isConditional();
// only jump/call are allowed
if (!(isJump || isCall)) {
return null;
}
// no conditional jumps allowed
if (isJump && isConditional) {
return null;
}
if (isCall) {
// Any conditional call considered as having side-effects
if (isConditional && checkForSideEffects) {
return null;
}
setRegisters.removeAll(usedRegisters);
// check that the setRegisters are all hidden, meaning don't care.
for (Iterator<Varnode> iterator = setRegisters.iterator(); iterator.hasNext();) {
Varnode rvnode = iterator.next();
Register reg = program.getRegister(rvnode);
// the register pcode access could have fallen in the middle of a valid register
// thus no register will exist at the varnode
if (reg != null && reg.isHidden()) {
iterator.remove();
// CALL_TERMINATOR, COMPUTED_CALL_TERMINATOR
else if (!flowType.isTerminal()) {
if (flowType == COMPUTED_CALL ||
flowType == UNCONDITIONAL_CALL) {
// consider any simple call having side-effects
if (checkForSideEffects) {
return null;
}
}
}
}
// if not checking for sideEffect registers set, or there are no side-effects
if (!checkForSideEffects || setRegisters.size() == 0) {
flowingAddr = getFlowingAddress(program, instr);
// program counter should be assumed to be used
// assume PC is used when considering registers that have been set
Register PC = program.getLanguage().getProgramCounter();
if (PC != null) {
usedRegisters.add(new Varnode(PC.getAddress(), PC.getMinimumByteSize()));
}
setRegisters.removeAll(usedRegisters);
// check that the setRegisters are all hidden, meaning don't care.
for (Iterator<Varnode> iterator = setRegisters.iterator(); iterator.hasNext();) {
Varnode rvnode = iterator.next();
Register reg = program.getRegister(rvnode);
// the register pcode access could have fallen in the middle of a valid register
// thus no register will exist at the varnode
if (reg != null && reg.isHidden()) {
iterator.remove();
}
}
Address flowingAddr = null;
// if not checking for sideEffect registers set, or there are no side-effects
if (!checkForSideEffects || setRegisters.size() == 0) {
flowingAddr = getFlowingAddress(program, instr);
}
return flowingAddr;
}

View file

@ -72,22 +72,30 @@ class EditThunkFunctionAction extends ProgramContextAction {
if (func == null) {
return;
}
Address funcEntry = func.getEntryPoint();
Function refFunc = func.getThunkedFunction(false);
if (refFunc == null) {
// if not already thunked, fill in a possible value from functions instructions
Address thunkAddr = CreateThunkFunctionCmd.getThunkedAddr(program, funcEntry, false);
if (thunkAddr != null) {
refFunc = functionMgr.getFunctionAt(thunkAddr);
}
}
Symbol refSymbol = (refFunc == null ? null : refFunc.getSymbol());
// Prompt for function referenced by thunk
ThunkReferenceAddressDialog dialog = new ThunkReferenceAddressDialog(funcPlugin.getTool());
dialog.showDialog(program, func.getEntryPoint(),
refFunc != null ? refFunc.getSymbol() : null);
dialog.showDialog(program, funcEntry, refSymbol);
Symbol referencedSymbol = dialog.getSymbol();
Address referencedFunctionAddr = dialog.getAddress();
CreateThunkFunctionCmd cmd;
if (referencedSymbol != null) {
cmd = new CreateThunkFunctionCmd(func.getEntryPoint(), null, referencedSymbol);
cmd = new CreateThunkFunctionCmd(funcEntry, null, referencedSymbol);
}
else if (referencedFunctionAddr != null) {
cmd = new CreateThunkFunctionCmd(func.getEntryPoint(), null, referencedFunctionAddr);
cmd = new CreateThunkFunctionCmd(funcEntry, null, referencedFunctionAddr);
}
else {
return; // cancelled

View file

@ -36,4 +36,31 @@
<possiblefuncstart validcode="function" label="__get_pc_thunk_lr" /> <!-- must be a function here -->
</pattern>
<pattern> <!-- .plt entry thunk -->
<data>
0xf8410028 <!-- std r2,0x28(r1) -->
001111.. ...00010 0xff 0xff <!-- subis rX,r2,0x1 -->
0xe9 ........ ........ ........ <!-- ld rX,#(x) -->
0x7d 0x.9 0x03 0xa6 <!-- mtctr rX -->
0xe8 010..... ........ ........ <!-- ld r2,#(x) -->
0x28220000 <!-- cmpldi r2,0 -->
0x4c 1..00010 0x04 0x20 <!-- bnectr+ -->
010010.. ........ ........ ......00 <!-- b X@plt -->
</data>
<funcstart after="defined" thunk="true"/> <!-- must be something define before this -->
</pattern>
<pattern> <!-- .plt entry thunk -->
<data>
0xf8410028 <!-- std r2,0x28(r1) -->
0xe9 ........ ........ ........ <!-- ld rX,#(x) -->
0x7d 0x.9 0x03 0xa6 <!-- mtctr rX -->
0xe8 010..... ........ ........ <!-- ld r2,#(x) -->
0x28220000 <!-- cmpldi r2,0 -->
0x4c 1..00010 0x04 0x20 <!-- bnectr+ -->
010010.. ........ ........ ......00 <!-- b X@plt -->
</data>
<funcstart after="defined" thunk="true"/> <!-- must be something define before this -->
</pattern>
</patternlist>

View file

@ -36,4 +36,31 @@
<possiblefuncstart validcode="function" label="__get_pc_thunk_lr" /> <!-- must be a function here -->
</pattern>
<pattern> <!-- .plt entry thunk -->
<data>
0x280041f8 <!-- std r2,0x28(r1) -->
0xff 0xff ...00010 001111.. <!-- subis rX,r2,0x1 -->
........ ........ ........ 0xe9 <!-- ld rX,#(x) -->
0xa6 0x03 0x.9 0x7d <!-- mtctr rX -->
........ ........ 010..... 0xe8 <!-- ld r2,#(x) -->
0x00002228 <!-- cmpldi r2,0 -->
0x20 0x04 1..00010 0x4c <!-- bnectr+ -->
......00 ........ ........ 010010.. <!-- b X@plt -->
</data>
<funcstart after="defined" thunk="true"/> <!-- must be something define before this -->
</pattern>
<pattern> <!-- .plt entry thunk -->
<data>
0x280041f8 <!-- std r2,0x28(r1) -->
........ ........ ........ 0xe9 <!-- ld rX,#(x) -->
0xa6 0x03 0x.9 0x7d <!-- mtctr rX -->
........ ........ 010..... 0xe8 <!-- ld r2,#(x) -->
0x00002228 <!-- cmpldi r2,0 -->
0x20 0x04 1..00010 0x4c <!-- bnectr+ -->
......00 ........ ........ 010010.. <!-- b X@plt -->
</data>
<funcstart after="defined" thunk="true"/> <!-- must be something define before this -->
</pattern>
</patternlist>