diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java index df33fd3a90..f2a1501ad0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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 { FlowType flowType, boolean checkForSideEffects, HashSet setRegisters, HashSet 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 - - // 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())); + // conditional jumps/call terminators can't be thunks, + // unless not checkingForSideEffects and just trying to get possible thunk address. + + 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 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; + } } } + } + + // 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); - // if not checking for sideEffect registers set, or there are no side-effects - if (!checkForSideEffects || setRegisters.size() == 0) { - flowingAddr = getFlowingAddress(program, instr); + // check that the setRegisters are all hidden, meaning don't care. + for (Iterator 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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java index 6545f6f0df..a9f0313745 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditThunkFunctionAction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -72,22 +72,30 @@ class EditThunkFunctionAction extends ProgramContextAction { if (func == null) { return; } + Address funcEntry = func.getEntryPoint(); - Function refFunc = func.getThunkedFunction(false); + 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 diff --git a/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml b/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml index f17b4813ab..4a9b96fc78 100644 --- a/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml +++ b/Ghidra/Processors/PowerPC/data/patterns/PPC_BE_patterns.xml @@ -36,4 +36,31 @@ + + + 0xf8410028 + 001111.. ...00010 0xff 0xff + 0xe9 ........ ........ ........ + 0x7d 0x.9 0x03 0xa6 + 0xe8 010..... ........ ........ + 0x28220000 + 0x4c 1..00010 0x04 0x20 + 010010.. ........ ........ ......00 + + + + + + + 0xf8410028 + 0xe9 ........ ........ ........ + 0x7d 0x.9 0x03 0xa6 + 0xe8 010..... ........ ........ + 0x28220000 + 0x4c 1..00010 0x04 0x20 + 010010.. ........ ........ ......00 + + + + diff --git a/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml b/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml index cdfb496d21..e334a96bac 100644 --- a/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml +++ b/Ghidra/Processors/PowerPC/data/patterns/PPC_LE_patterns.xml @@ -35,5 +35,32 @@ 0x21 0x00 0x80 0x4e + + + + 0x280041f8 + 0xff 0xff ...00010 001111.. + ........ ........ ........ 0xe9 + 0xa6 0x03 0x.9 0x7d + ........ ........ 010..... 0xe8 + 0x00002228 + 0x20 0x04 1..00010 0x4c + ......00 ........ ........ 010010.. + + + + + + + 0x280041f8 + ........ ........ ........ 0xe9 + 0xa6 0x03 0x.9 0x7d + ........ ........ 010..... 0xe8 + 0x00002228 + 0x20 0x04 1..00010 0x4c + ......00 ........ ........ 010010.. + + +