From 3ebc46a2ca8f54fc48eb8ddb05da1d5db4907cf5 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Thu, 6 Jun 2024 15:11:14 -0400 Subject: [PATCH] GP-0 Improved process error handling for Decompiler and GNU Demangler. Corrected minor GNU Demangler demangler command and script issues. --- .../ghidra_scripts/DemangleSymbolScript.java | 7 ++- ...compilerParallelConventionAnalysisCmd.java | 7 ++- .../app/decompiler/DecompileProcess.java | 52 ++++++++++++--- .../decompiler/DecompileProcessFactory.java | 13 +++- .../app/util/demangler/gnu/GnuDemangler.java | 6 ++ .../gnu/GnuDemanglerNativeProcess.java | 63 ++++++++++++++++--- 6 files changed, 128 insertions(+), 20 deletions(-) diff --git a/Ghidra/Features/Base/ghidra_scripts/DemangleSymbolScript.java b/Ghidra/Features/Base/ghidra_scripts/DemangleSymbolScript.java index 83ab481a6b..3335021bb4 100644 --- a/Ghidra/Features/Base/ghidra_scripts/DemangleSymbolScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/DemangleSymbolScript.java @@ -104,7 +104,12 @@ public class DemangleSymbolScript extends GhidraScript { println("Successfully demangled\n" + name + '\n' + cmd.getResult()); } else { - println("Failed to demangle\n" + name + '\n' + cmd.getStatusMsg()); + String statusMsg = cmd.getStatusMsg(); + String msg = "Failed to demangle\n" + name; + if (statusMsg != null) { + msg += "\n" + statusMsg; + } + println(msg); } } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParallelConventionAnalysisCmd.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParallelConventionAnalysisCmd.java index 23e5687dcc..b1d2ab2c2c 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParallelConventionAnalysisCmd.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/cmd/function/DecompilerParallelConventionAnalysisCmd.java @@ -59,7 +59,12 @@ public class DecompilerParallelConventionAnalysisCmd extends BackgroundCommand

0) { + return false; + } + } if (mangled.startsWith("_Z")) { return false; } diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerNativeProcess.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerNativeProcess.java index 396620b7e9..959396fad5 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerNativeProcess.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerNativeProcess.java @@ -18,6 +18,7 @@ package ghidra.app.util.demangler.gnu; import java.io.*; import java.nio.charset.Charset; import java.util.*; +import java.util.concurrent.TimeUnit; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; @@ -25,6 +26,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import ghidra.framework.*; +import ghidra.util.Msg; /** * A class that allows for the reuse of native demangler executable processes. This class will @@ -37,6 +39,16 @@ public class GnuDemanglerNativeProcess { private static final String DEFAULT_NATIVE_OPTIONS = ""; private static final Map processesByName = new HashMap<>(); + + private static boolean errorDisplayed = false; + + private static synchronized boolean getAndSetErrorDisplayed() { + boolean b = errorDisplayed; + if (!b) { + errorDisplayed = true; + } + return b; + } private String applicationName; private String options; @@ -153,16 +165,51 @@ public class GnuDemanglerNativeProcess { private void createProcess() throws IOException { String[] command = buildCommand(); - process = Runtime.getRuntime().exec(command); - - InputStream in = process.getInputStream(); - OutputStream out = process.getOutputStream(); - reader = new BufferedReader(new InputStreamReader(in)); - writer = new PrintWriter(out); - + IOException exc = null; + String err = ""; + isDisposed = true; + try { + process = Runtime.getRuntime().exec(command); + // Give process time to load and report possible error + process.waitFor(200, TimeUnit.MILLISECONDS); + InputStream in = process.getInputStream(); + OutputStream out = process.getOutputStream(); + reader = new BufferedReader(new InputStreamReader(in)); + writer = new PrintWriter(out); + isDisposed = !process.isAlive(); + if (isDisposed) { + err = new String(process.getErrorStream().readAllBytes()); + process.destroy(); + process = null; + } + } + catch (IOException e) { + exc = e; + } + catch (InterruptedException e) { + // ignore + } + finally { + if (isDisposed) { + if (!getAndSetErrorDisplayed()) { + String errorDetail = err; + if (exc != null) { + errorDetail = exc.getMessage() + "\n" + errorDetail; + } + errorDetail = "GNU Demangler executable may not be compatible with your system and may need to be rebuilt.\n" + + "(see InstallationGuide.html, 'Building Native Components').\n\n" + + errorDetail; + Msg.showError(this, null, "Failed to launch GNU Demangler process", errorDetail); + } + if (exc == null) { + throw new IOException("GNU Demangler process failed to launch (see log for details)"); + } + throw exc; + } + } + checkForError(command); - isDisposed = false; String key = getKey(applicationName, options); processesByName.put(key, this); }