mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-0 Improved process error handling for Decompiler and GNU Demangler.
Corrected minor GNU Demangler demangler command and script issues.
This commit is contained in:
parent
7079179b59
commit
3ebc46a2ca
6 changed files with 128 additions and 20 deletions
|
@ -104,7 +104,12 @@ public class DemangleSymbolScript extends GhidraScript {
|
||||||
println("Successfully demangled\n" + name + '\n' + cmd.getResult());
|
println("Successfully demangled\n" + name + '\n' + cmd.getResult());
|
||||||
}
|
}
|
||||||
else {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,12 @@ public class DecompilerParallelConventionAnalysisCmd extends BackgroundCommand<P
|
||||||
newInterface.setOptions(opts);
|
newInterface.setOptions(opts);
|
||||||
|
|
||||||
if (!newInterface.openProgram(program)) {
|
if (!newInterface.openProgram(program)) {
|
||||||
throw new IOException("Unable to create decompiler for program: " + program);
|
String msg = "Unable to create decompiler for program: " + program;
|
||||||
|
String lastMessage = newInterface.getLastMessage();
|
||||||
|
if (lastMessage != null) {
|
||||||
|
msg += "\n" + lastMessage;
|
||||||
|
}
|
||||||
|
throw new IOException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newInterface;
|
return newInterface;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import static ghidra.program.model.pcode.AttributeId.*;
|
||||||
import static ghidra.program.model.pcode.ElementId.*;
|
import static ghidra.program.model.pcode.ElementId.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.lang.InjectPayload;
|
import ghidra.program.model.lang.InjectPayload;
|
||||||
|
@ -47,6 +48,8 @@ import ghidra.util.timer.GTimerMonitor;
|
||||||
|
|
||||||
public class DecompileProcess {
|
public class DecompileProcess {
|
||||||
|
|
||||||
|
private static boolean errorDisplayed = false; // launch failure previously displayed
|
||||||
|
|
||||||
// public static DecompileProcess decompProcess = null;
|
// public static DecompileProcess decompProcess = null;
|
||||||
private final static byte[] command_start = { 0, 0, 1, 2 };
|
private final static byte[] command_start = { 0, 0, 1, 2 };
|
||||||
private final static byte[] command_end = { 0, 0, 1, 3 };
|
private final static byte[] command_end = { 0, 0, 1, 3 };
|
||||||
|
@ -104,6 +107,14 @@ public class DecompileProcess {
|
||||||
stringDecoder = new StringIngest();
|
stringDecoder = new StringIngest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static synchronized boolean getAndSetErrorDisplayed() {
|
||||||
|
boolean b = errorDisplayed;
|
||||||
|
if (!b) {
|
||||||
|
errorDisplayed = true;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (disposestate != DisposeState.NOT_DISPOSED) {
|
if (disposestate != DisposeState.NOT_DISPOSED) {
|
||||||
return;
|
return;
|
||||||
|
@ -133,19 +144,46 @@ public class DecompileProcess {
|
||||||
if (exepath == null || exepath.length == 0 || exepath[0] == null) {
|
if (exepath == null || exepath.length == 0 || exepath[0] == null) {
|
||||||
throw new IOException("Could not find decompiler executable");
|
throw new IOException("Could not find decompiler executable");
|
||||||
}
|
}
|
||||||
|
IOException exc = null;
|
||||||
|
String err = "";
|
||||||
|
statusGood = false;
|
||||||
try {
|
try {
|
||||||
nativeProcess = runtime.exec(exepath);
|
nativeProcess = runtime.exec(exepath);
|
||||||
|
// Give process time to load and report possible error
|
||||||
|
nativeProcess.waitFor(200, TimeUnit.MILLISECONDS);
|
||||||
nativeIn = nativeProcess.getInputStream();
|
nativeIn = nativeProcess.getInputStream();
|
||||||
nativeOut = nativeProcess.getOutputStream();
|
nativeOut = nativeProcess.getOutputStream();
|
||||||
statusGood = true;
|
statusGood = nativeProcess.isAlive();
|
||||||
|
if (!statusGood) {
|
||||||
|
err = new String(nativeProcess.getErrorStream().readAllBytes());
|
||||||
|
nativeProcess.destroy();
|
||||||
|
nativeProcess = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
exc = e;
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (!statusGood) {
|
||||||
disposestate = DisposeState.DISPOSED_ON_STARTUP_FAILURE;
|
disposestate = DisposeState.DISPOSED_ON_STARTUP_FAILURE;
|
||||||
statusGood = false;
|
if (!getAndSetErrorDisplayed()) {
|
||||||
Msg.showError(this, null, "Problem launching decompiler",
|
String errorDetail = err;
|
||||||
"Please report this stack trace to the Ghidra Team", e);
|
if (exc != null) {
|
||||||
throw e;
|
errorDetail = exc.getMessage() + "\n" + errorDetail;
|
||||||
|
}
|
||||||
|
errorDetail = "Decompiler 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 Decompiler process", errorDetail);
|
||||||
|
}
|
||||||
|
if (exc == null) {
|
||||||
|
throw new IOException("Decompiler process failed to launch (see log for details)");
|
||||||
|
}
|
||||||
|
throw exc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,14 @@ public class DecompileProcessFactory {
|
||||||
|
|
||||||
private static boolean errorDisplayed = false;
|
private static boolean errorDisplayed = false;
|
||||||
|
|
||||||
|
private static synchronized boolean getAndSetErrorDisplayed() {
|
||||||
|
boolean b = errorDisplayed;
|
||||||
|
if (!b) {
|
||||||
|
errorDisplayed = true;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized static DecompileProcess get() {
|
public synchronized static DecompileProcess get() {
|
||||||
getExePath();
|
getExePath();
|
||||||
DecompileProcess currentProcess = new DecompileProcess(exepath);
|
DecompileProcess currentProcess = new DecompileProcess(exepath);
|
||||||
|
@ -59,9 +67,8 @@ public class DecompileProcessFactory {
|
||||||
exepath = file.getAbsolutePath();
|
exepath = file.getAbsolutePath();
|
||||||
}
|
}
|
||||||
catch (OSFileNotFoundException e) {
|
catch (OSFileNotFoundException e) {
|
||||||
if (!errorDisplayed) {
|
if (!getAndSetErrorDisplayed()) {
|
||||||
errorDisplayed = true;
|
Msg.showError(DecompileProcessFactory.class, null, "Decompiler Not Found",
|
||||||
Msg.showError(DecompileProcessFactory.class, null, "Decompiler missing",
|
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,6 +196,12 @@ public class GnuDemangler implements Demangler {
|
||||||
|
|
||||||
// This is the current list of known demangler start patterns. Add to this list if we
|
// This is the current list of known demangler start patterns. Add to this list if we
|
||||||
// find any other known GNU start patterns.
|
// find any other known GNU start patterns.
|
||||||
|
if (mangled.startsWith(GLOBAL_PREFIX)) {
|
||||||
|
int index = mangled.indexOf("_Z");
|
||||||
|
if (index > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mangled.startsWith("_Z")) {
|
if (mangled.startsWith("_Z")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.util.demangler.gnu;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
@ -25,6 +26,7 @@ import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.framework.*;
|
import ghidra.framework.*;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that allows for the reuse of native demangler executable processes. This class will
|
* A class that allows for the reuse of native demangler executable processes. This class will
|
||||||
|
@ -38,6 +40,16 @@ public class GnuDemanglerNativeProcess {
|
||||||
private static final Map<String, GnuDemanglerNativeProcess> processesByName =
|
private static final Map<String, GnuDemanglerNativeProcess> processesByName =
|
||||||
new HashMap<>();
|
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 applicationName;
|
||||||
private String options;
|
private String options;
|
||||||
|
|
||||||
|
@ -153,16 +165,51 @@ public class GnuDemanglerNativeProcess {
|
||||||
private void createProcess() throws IOException {
|
private void createProcess() throws IOException {
|
||||||
|
|
||||||
String[] command = buildCommand();
|
String[] command = buildCommand();
|
||||||
|
IOException exc = null;
|
||||||
|
String err = "";
|
||||||
|
isDisposed = true;
|
||||||
|
try {
|
||||||
process = Runtime.getRuntime().exec(command);
|
process = Runtime.getRuntime().exec(command);
|
||||||
|
// Give process time to load and report possible error
|
||||||
|
process.waitFor(200, TimeUnit.MILLISECONDS);
|
||||||
InputStream in = process.getInputStream();
|
InputStream in = process.getInputStream();
|
||||||
OutputStream out = process.getOutputStream();
|
OutputStream out = process.getOutputStream();
|
||||||
reader = new BufferedReader(new InputStreamReader(in));
|
reader = new BufferedReader(new InputStreamReader(in));
|
||||||
writer = new PrintWriter(out);
|
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);
|
checkForError(command);
|
||||||
|
|
||||||
isDisposed = false;
|
|
||||||
String key = getKey(applicationName, options);
|
String key = getKey(applicationName, options);
|
||||||
processesByName.put(key, this);
|
processesByName.put(key, this);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue