From 54359a7fef90d7d957a72a3db6166ea6734ddaeb Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Thu, 30 Oct 2025 23:25:00 +0000 Subject: [PATCH] GP-6078 Implement support for segment() ops in SymbolicPropagator --- .../function/NewFunctionStackAnalysisCmd.java | 3 + .../core/function/AnalyzeStackRefsAction.java | 7 +- .../core/function/StackVariableAnalyzer.java | 30 +-- .../ghidra/app/util/xml/FunctionsXmlMgr.java | 2 +- .../program/util/SymbolicPropogator.java | 34 ++- .../AbstractListingMergeManagerTest.java | 4 +- .../listing/SymbolMergeManager3Test.java | 8 +- .../FunctionStackAnalysisCmdTest.java | 239 ++++++++++++++++++ .../analysis/DecompilerSwitchAnalyzer.java | 2 +- 9 files changed, 285 insertions(+), 44 deletions(-) create mode 100644 Ghidra/Features/Base/src/test/java/ghidra/app/cmd/function/FunctionStackAnalysisCmdTest.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java index 48923d0106..dc8e7dc79f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java @@ -583,6 +583,9 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand { if (local_offset == offset) { return opIndex; } + if ((local_offset & 0xffff) == offset) { + return opIndex; + } } } return -1; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java index eceefb4643..0b528814d8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AnalyzeStackRefsAction.java @@ -104,13 +104,8 @@ class AnalyzeStackRefsAction extends ListingContextAction { doParameterAnalysis = options.getBoolean("Create Param Variables", doParameterAnalysis); BackgroundCommand cmd = null; - if (doNewStackAnalysis) { - cmd = new NewFunctionStackAnalysisCmd(funcSet, doParameterAnalysis, doLocalAnalysis, + cmd = new NewFunctionStackAnalysisCmd(funcSet, doParameterAnalysis, doLocalAnalysis, true); - } - else { - cmd = new FunctionStackAnalysisCmd(funcSet, doParameterAnalysis, doLocalAnalysis, true); - } funcPlugin.execute(program, cmd); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java index 120fc422a6..9f2d61bba8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java @@ -17,14 +17,12 @@ package ghidra.app.plugin.core.function; import java.util.*; -import ghidra.app.cmd.function.FunctionStackAnalysisCmd; import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd; import ghidra.app.services.*; import ghidra.app.util.importer.MessageLog; import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.options.Options; import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; import ghidra.util.Msg; @@ -41,7 +39,6 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { protected static final int MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE = 2; protected int maxThreadCount = MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE; - private boolean doNewStackAnalysis = true; private boolean doCreateLocalStackVars = true; private boolean doCreateStackParams = false; @@ -80,14 +77,8 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { final TaskMonitor monitor) throws CancelledException { BackgroundCommand cmd; - if (doNewStackAnalysis) { - cmd = new NewFunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars, + cmd = new NewFunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars, false); - } - else { - cmd = new FunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars, - false); - } cmd.applyTo(program, monitor); return EMPTY_ADDRESS_SET; @@ -120,23 +111,8 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { } } -// private boolean useOldStackAnalysisByDefault(Program program) { -// Language language = program.getLanguage(); -// if (language.getProcessor().equals(Processor.findOrPossiblyCreateProcessor("x86"))) { -// if (language.getLanguageDescription().getSize() == 16) { -// // Prefer using old stack analysis for x86 16-bit with segmented addresses -// return true; -// } -// } -// return false; -// } - @Override public void registerOptions(Options options, Program program) { - options.registerOption(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS, - true, null, - "Use General Stack Reference Propogator (This works best on most processors)"); - options.registerOption("Create Local Variables", doCreateLocalStackVars, null, "Create Function Local stack variables and references"); @@ -149,10 +125,6 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { @Override public void optionsChanged(Options options, Program program) { - doNewStackAnalysis = - options.getBoolean(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS, - true); - doCreateLocalStackVars = options.getBoolean("Create Local Variables", doCreateLocalStackVars); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java index c1dc17aebb..5c23c666d4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java @@ -228,7 +228,7 @@ class FunctionsXmlMgr { parser.end(element); FunctionPurgeAnalysisCmd purgeAnalysisCmd = new FunctionPurgeAnalysisCmd(functions); purgeAnalysisCmd.applyTo(program, monitor); - FunctionStackAnalysisCmd stackAnalysisCmd = new FunctionStackAnalysisCmd(functions, true); + NewFunctionStackAnalysisCmd stackAnalysisCmd = new NewFunctionStackAnalysisCmd(functions, true); stackAnalysisCmd.applyTo(program, monitor); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index 951a251f3a..f73db0bd27 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -886,6 +886,15 @@ public class SymbolicPropogator { } vContext.copy(out, in[0], mustClearAll, evaluator); break; + + case PcodeOp.SEGMENTOP: + // treat like a copy for now, and extend the size as if segment had been applied + Varnode vval = context.getValue(in[2], evaluator); + if (context.isSymbolicSpace(vval.getSpace())) { + vval = vContext.createVarnode(vval.getOffset(), vval.getSpace(), out.getSize()); + } + vContext.putValue(out, vval, mustClearAll); + break; case PcodeOp.LOAD: Varnode memVal = null; @@ -1843,7 +1852,7 @@ public class SymbolicPropogator { for (int i = 1; i < ins.length; i++) { Varnode vval = context.getValue(ins[i], evaluator); if (vval == null || !context.isConstant(vval)) { - return null; + return checkSegmentCallOther(payload, instr, ins, out); } inputs.add(vval); } @@ -1867,6 +1876,29 @@ public class SymbolicPropogator { return null; } + private PcodeOp[] checkSegmentCallOther(InjectPayload payload, Instruction instr, Varnode[] ins, Varnode out) { + if (!payload.getName().equals("segment_pcode")) { + return null; + } + if (ins.length != 3) { + return null; + } + Varnode vval = context.getValue(ins[2], evaluator); + if (vval == null) { + return null; + } + if (!context.isSymbolicSpace(vval.getSpace())) { + return null; + } + if (!context.isRegister(ins[1])) { + return null; + } + // morph segment into COPY as long as still symbolic + PcodeOp[] newop = new PcodeOp[1]; + newop[0] = new PcodeOp(instr.getAddress(), 1, PcodeOp.SEGMENTOP, ins, out); + return newop; + } + private InjectPayload findPcodeInjection(Program prog, PcodeInjectLibrary snippetLibrary, long callOtherIndex) { InjectPayload payload = injectPayloadCache.get(callOtherIndex); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java index cf8a14ba2f..05af19cd2e 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/AbstractListingMergeManagerTest.java @@ -35,7 +35,7 @@ import docking.test.AbstractDockingTest; import docking.widgets.dialogs.ReadTextDialog; import ghidra.app.cmd.disassemble.DisassembleCommand; import ghidra.app.cmd.function.CreateFunctionCmd; -import ghidra.app.cmd.function.FunctionStackAnalysisCmd; +import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd; import ghidra.app.merge.AbstractMergeTest; import ghidra.app.merge.ProgramMultiUserMergeManager; import ghidra.app.merge.tool.ListingMergePanel; @@ -364,7 +364,7 @@ public abstract class AbstractListingMergeManagerTest extends AbstractMergeTest // TODO For thunk functions need to call thunk analyzer here before // stack analysis occurs } - FunctionStackAnalysisCmd analyzeCmd = new FunctionStackAnalysisCmd(addr, true); + NewFunctionStackAnalysisCmd analyzeCmd = new NewFunctionStackAnalysisCmd(addr, true); assertTrue("Failed to analyze stack for " + name + " @ " + addr, analyzeCmd.applyTo(program)); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.java index d6b8bb3a2f..a4e12f09c3 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManager3Test.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. @@ -22,7 +22,7 @@ import org.junit.Test; import ghidra.app.cmd.disassemble.DisassembleCommand; import ghidra.app.cmd.function.CreateFunctionCmd; -import ghidra.app.cmd.function.FunctionStackAnalysisCmd; +import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd; import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramModifierListener; import ghidra.program.model.address.Address; @@ -154,7 +154,7 @@ public class SymbolMergeManager3Test extends AbstractListingMergeManagerTest { functionCmd.applyTo(program)); Function newFunction = program.getFunctionManager().getFunctionAt(addr); assertNotNull(newFunction); - FunctionStackAnalysisCmd analyzeCmd = new FunctionStackAnalysisCmd(addr, true); + NewFunctionStackAnalysisCmd analyzeCmd = new NewFunctionStackAnalysisCmd(addr, true); assertTrue("Failed to analyze stack for " + name + " @ " + addr, analyzeCmd.applyTo(program)); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/function/FunctionStackAnalysisCmdTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/function/FunctionStackAnalysisCmdTest.java new file mode 100644 index 0000000000..105948a613 --- /dev/null +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/cmd/function/FunctionStackAnalysisCmdTest.java @@ -0,0 +1,239 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.cmd.function; + +import static org.junit.Assert.*; + +import java.math.BigInteger; + +import org.junit.Test; + +import generic.test.AbstractGenericTest; +import ghidra.app.plugin.core.analysis.ConstantPropagationAnalyzer; +import ghidra.app.plugin.core.analysis.ConstantPropagationContextEvaluator; +import ghidra.app.plugin.core.function.StackVariableAnalyzer; +import ghidra.program.database.ProgramBuilder; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.ReferenceIterator; +import ghidra.program.util.SymbolicPropogator.Value; +import ghidra.util.task.TaskMonitor; + +/** + * quick and dirty test of the ProgramContextImpl just to see + * if the values are being set for specified address range. + * The ProgramContextPlugin will be a more complete test + * program, with a gui interface to specify the values and + * select/highlight an address range. + */ +public class FunctionStackAnalysisCmdTest extends AbstractGenericTest { + + private ProgramBuilder builder; + private Program program; + + private StackVariableAnalyzer analyzer; + + public FunctionStackAnalysisCmdTest() { + super(); + } + + public void do16bitTest(String processor) throws Exception { + + builder = new ProgramBuilder("ProtectedMode", processor); + + /** + * undefined __cdecl16near FUN_1000_00cc() + 1000:00cc 45 0 INC BP + 1000:00cd 55 0 PUSH BP + 1000:00ce 8b ec 002 MOV BP,SP + 1000:00d0 56 002 PUSH SI + 1000:00d1 57 004 PUSH DI + 1000:00d2 8a 46 f0 006 MOV AL,byte ptr [BP + local_12] + 1000:00d5 b4 4c 006 MOV AH,0x4c + 1000:00d7 8b 56 08 006 MOV DX,word ptr [BP + Stack[0x6]] + 1000:00da 8b 46 06 006 MOV AX,word ptr [BP + Stack[0x4]] + 1000:00dd ff 76 08 006 PUSH word ptr [BP + Stack[0x6]] + 1000:00e0 ff 76 ee 008 PUSH word ptr [BP + local_14] + 1000:00e3 83 7e 06 00 00a CMP word ptr [BP + Stack[0x4]],0x0 + 1000:00e7 dd 46 04 00a FLD double ptr [BP + Stack[0x2]] + 1000:00ea 07 00a POP ES + 1000:00eb c3 008 RET + + */ + builder.setBytes("0x1000:00cc", + "45 55 8b ec 56 57 8a 46 f0 b4 4c 8b 56 08 8b 46 06 ff 76 08 ff 76 ee 83 7e 06 00 dd 46 04 07 c3"); + + builder.disassemble("0x1000:0x00CC", 48); + + analyzer = new StackVariableAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + + Address codeStart = addr("0x1000:0x00CC"); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + builder.createFunction("0x1000:0x00cc"); + + Instruction instr = listing.getInstructionAt(addr("0x1000:0x00d2")); + assertNoOperandReference(0, instr); + assertNoOperandReference(1, instr); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(48)); + analyze(addressSet); + + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(0x12)); + + instr = listing.getInstructionAt(addr("0x1000:0x00d7")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x6")); + + instr = listing.getInstructionAt(addr("0x1000:0x00da")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x4")); + + instr = listing.getInstructionAt(addr("0x1000:0x00dd")); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("stack:0x6")); + + instr = listing.getInstructionAt(addr("0x1000:0x00e0")); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("stack:0x0").subtract(0x14)); + + instr = listing.getInstructionAt(addr("0x1000:0x00e3")); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("stack:0x4")); + + instr = listing.getInstructionAt(addr("0x1000:0x00e7")); + assertOperandReferenceTo(0, instr, addr("stack:0x2")); + } + + @Test + public void testOperandRef_x86ProtectedMode() throws Exception { + do16bitTest("x86:LE:16:Protected Mode"); + } + + @Test + public void testOperandRef_x86RealMode() throws Exception { + do16bitTest("x86:LE:16:Real Mode"); + } + + @Test + public void testMIPS64() throws Exception { + builder = new ProgramBuilder("MIPS", "MIPS:LE:32:default"); + + /** + * undefined FUN_9d010b2c() + 9d010b2c c0 ff bd 27 0 addiu sp,sp,-0x40 + 9d010b30 24 00 b0 af 040 sw s0,local_1c(sp) + 9d010b34 01 a0 10 3c 040 lui s0,0xa001 + 9d010b38 40 5c 02 26 040 addiu v0,s0,0x5c40 + 9d010b3c 14 00 42 8c 040 lw v0,0x14(v0)=>DAT_a0015c54 + 9d010b40 3c 00 bf af 040 sw ra,local_4(sp) + 9d010b44 31 00 43 2c 040 sltiu v1,v0,0x31 + 9d010b48 38 00 b5 af 040 sw s5,local_8(sp) + 9d010b4c 34 00 b4 af 040 sw s4,local_c(sp) + 9d010b50 30 00 b3 af 040 sw s3,local_10(sp) + 9d010b54 2c 00 b2 af 040 sw s2,local_14(sp) + 9d010b58 b7 05 60 10 040 beq v1,zero,switchD_9d010b74 + 9d010b5c 28 00 b1 af _sw s1,local_18(sp) + 9d010b60 01 9d 03 3c 040 lui v1,0x9d01 + 9d010b64 80 10 02 00 040 sll v0,v0,0x2 + 9d010b68 7c 0b 63 24 040 addiu v1,v1,0xb7c + 9d010b6c 21 10 62 00 040 addu v0,v1,v0 + 9d010b70 00 00 42 8c 040 lw v0,0x0(v0) + 9d010b74 08 00 40 00 040 jr v0 + + */ + String funcStartAddrString = "0x9d010b2c"; + builder.setBytes(funcStartAddrString, + "c0 ff bd 27 24 00 b0 af 01 a0 10 3c 40 5c 02 26 14 00 42 8c 3c 00 bf af 31 00 43 2c 38 00 b5 af 34 " + + "00 b4 af 30 00 b3 af 2c 00 b2 af b7 05 60 10 28 00 b1 af 01 9d 03 3c 80 10 02 00 7c 0b 63 24 21 " + + "10 62 00 00 00 42 8c 08 00 40 00"); + + builder.disassemble(funcStartAddrString, 72); + + analyzer = new StackVariableAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + + Address codeStart = addr(funcStartAddrString); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + builder.createFunction(funcStartAddrString); + + Instruction instr = listing.getInstructionAt(addr("0x9d010b30")); + assertNoOperandReference(0, instr); + assertNoOperandReference(1, instr); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(72)); + analyze(addressSet); + + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(0x1c)); + + // should not create any memory refs, is stack analyzer + instr = listing.getInstructionAt(addr("0x9d010b3c")); + assertNoOperandReference(0, instr); + assertNoOperandReference(1, instr); + + instr = listing.getInstructionAt(addr("0x9d010b40")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(4)); + + instr = listing.getInstructionAt(addr("0x9d010b48")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(8)); + + instr = listing.getInstructionAt(addr("0x9d010b4c")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(12)); + + // delay slot stack reference case + instr = listing.getInstructionAt(addr("0x9d010b5c")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("stack:0x0").subtract(0x18)); + } + + private void assertNoOperandReference(int opIndex, Instruction instr) { + Reference[] refs = instr.getOperandReferences(opIndex); + assertEquals("No reference on operand " + opIndex, 0, refs.length); + } + + private void assertOperandReferenceTo(int opIndex, Instruction instr, Address to) { + Reference[] refs = instr.getOperandReferences(opIndex); + assertEquals("Operand " + opIndex + " num refs", 1, refs.length); + assertEquals("Operand " + opIndex + " Ref Check", to, refs[0].getToAddress()); + } + + private void analyze(AddressSet addrs) throws Exception { + analyzer.added(program, addrs, TaskMonitor.DUMMY, null); + } + + private Address addr(String address) { + return builder.addr(address); + } +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java index 48f44d5e0b..af699b90ab 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/analysis/DecompilerSwitchAnalyzer.java @@ -433,8 +433,8 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer { if (fixupFunc.hasNoReturn()) { return fixupFunc; } - return null; } + return null; } }