From 72344ce13e920a89adb584d0394021dd7ca2d4e5 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 24 Sep 2025 19:05:30 +0000 Subject: [PATCH 1/2] GP-5989 Fix ForceUnionAction "Could not recover p-code op" --- .../decompile/actions/ForceUnionAction.java | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.java index ff6e359822..587097562c 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ForceUnionAction.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. @@ -128,28 +128,28 @@ public class ForceUnionAction extends AbstractDecompilerAction { int opcode = accessOp.getOpcode(); if (opcode == PcodeOp.PTRSUB) { parentDt = typeIsUnionRelated(accessOp.getInput(0)); - if (parentDt == null) { - accessOp = null; - return; - } - accessVn = accessOp.getInput(0); - accessSlot = 0; - if (accessOp.getInput(1).getOffset() == 0) { // Artificial op - do { - Varnode tmpVn = accessOp.getOutput(); - PcodeOp tmpOp = tmpVn.getLoneDescend(); - if (tmpOp == null) { - break; + if (parentDt != null) { + accessVn = accessOp.getInput(0); + accessSlot = 0; + if (accessOp.getInput(1).getOffset() == 0) { // Artificial op + do { + Varnode tmpVn = accessOp.getOutput(); + PcodeOp tmpOp = tmpVn.getLoneDescend(); + if (tmpOp == null) { + break; + } + accessOp = tmpOp; + accessVn = tmpVn; + accessSlot = accessOp.getSlot(accessVn); } - accessOp = tmpOp; - accessVn = tmpVn; - accessSlot = accessOp.getSlot(accessVn); + while (accessOp.getOpcode() == PcodeOp.PTRSUB && + accessOp.getInput(1).getOffset() == 0); } - while (accessOp.getOpcode() == PcodeOp.PTRSUB && - accessOp.getInput(1).getOffset() == 0); + return; } } else { + parentDt = null; for (accessSlot = 0; accessSlot < accessOp.getNumInputs(); ++accessSlot) { accessVn = accessOp.getInput(accessSlot); parentDt = typeIsUnionRelated(accessVn); @@ -157,22 +157,26 @@ public class ForceUnionAction extends AbstractDecompilerAction { break; } } - if (accessSlot >= accessOp.getNumInputs()) { - accessSlot = -1; - accessVn = accessOp.getOutput(); - parentDt = typeIsUnionRelated(accessVn); - if (parentDt == null) { - accessOp = null; - return; // Give up, could not find type associated with field + if (parentDt != null) { + if (opcode == PcodeOp.SUBPIECE && accessSlot == 0 && + !(parentDt instanceof Pointer)) { + // SUBPIECE acts directly as resolution operator + // Choose field based on output varnode, even though it isn't the union data-type + accessSlot = -1; + accessVn = accessOp.getOutput(); } - } - if (opcode == PcodeOp.SUBPIECE && accessSlot == 0 && !(parentDt instanceof Pointer)) { - // SUBPIECE acts directly as resolution operator - // Choose field based on output varnode, even though it isn't the union data-type - accessSlot = -1; - accessVn = accessOp.getOutput(); + return; } } + accessSlot = -1; + accessVn = accessOp.getOutput(); + if (accessVn != null) { + parentDt = typeIsUnionRelated(accessVn); + if (parentDt != null) { + return; + } + } + accessOp = null; // Give up, could not find type associated with field } /** From 136a28d60373cd5315c766fc089612adf97fbbe7 Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Wed, 24 Sep 2025 18:03:10 +0000 Subject: [PATCH 2/2] GP-5526 bug fix for .plt.sec and pattern matching optimization --- .../app/cmd/function/CreateThunkFunctionCmd.java | 6 ++++++ .../ghidra/app/analyzers/FunctionStartAnalyzer.java | 13 +++++++++---- .../x86/data/patterns/x86gcc_prepatterns.xml | 8 ++++---- 3 files changed, 19 insertions(+), 8 deletions(-) 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 24eb186393..1743a23304 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 @@ -566,6 +566,12 @@ public class CreateThunkFunctionCmd extends BackgroundCommand { if (instr == null) { return null; } + // if there is no pcode, go to the next instruction + // assume fallthrough (ie. x86 instruction ENDBR64) + // TODO: at some point, might need to do a NOP detection + if (instr.getPcode().length == 0) { + instr = listing.getInstructionAfter(entry); + } FlowType flowType; diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java index c02e18321e..a19668ff81 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/app/analyzers/FunctionStartAnalyzer.java @@ -17,6 +17,7 @@ package ghidra.app.analyzers; import java.math.BigInteger; import java.util.*; +import java.util.regex.Matcher; import generic.jar.ResourceFile; import ghidra.app.cmd.function.CreateFunctionCmd; @@ -209,7 +210,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa private String label = null; private boolean isThunk = false; // true if this function should be turned into a thunk private boolean noreturn = false; // true to set function non-returning - private String sectionName = null; // required section name + private java.util.regex.Pattern sectionNamePattern = null; // required section name as a regex pattern boolean validFunction = false; // must be defined at a function private boolean contiguous = true; // require validcode instructions be contiguous @@ -227,9 +228,13 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa protected boolean checkPreRequisites(Program program, Address addr) { // check required section name - if (sectionName != null) { + if (sectionNamePattern != null) { MemoryBlock block = program.getMemory().getBlock(addr); - if (block == null || !block.getName().matches(sectionName)) { + if (block == null) { + return false; + } + Matcher m = sectionNamePattern.matcher(block.getName()); + if (!m.matches()) { return false; } } @@ -651,7 +656,7 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa break; case "section": - sectionName = attrValue; + sectionNamePattern = java.util.regex.Pattern.compile(attrValue); break; case "noreturn": diff --git a/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml b/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml index 190acf223f..84b6d20dee 100644 --- a/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml +++ b/Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml @@ -6,15 +6,15 @@ 0x68......00 0xe9......ff - + - 0xf3 0x0f 0x1e 0x1a - 0xf2 0xff 0x25 .. .. .. .. + 0xf3 0x0f 0x1e 0xfa + 0xf2 0xff 0x25 - +