diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/action.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/action.cc index 9a4e2e26d0..e02dbc38e8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/action.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/action.cc @@ -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. @@ -43,7 +43,7 @@ void Action::issueWarning(Architecture *glb) { if ((flags&(rule_warnings_on|rule_warnings_given)) == rule_warnings_on) { flags |= rule_warnings_given; - glb->printMessage("WARNING: Applied action "+name); + glb->printWarning("Applied action "+name); } } @@ -640,7 +640,7 @@ void Rule::issueWarning(Architecture *glb) { if ((flags&(warnings_on|warnings_given)) == warnings_on) { flags |= warnings_given; - glb->printMessage("WARNING: Applied rule "+name); + glb->printWarning("Applied rule "+name); } } @@ -862,11 +862,11 @@ int4 ActionPool::processOp(PcodeOp *op,Funcdata &data) rule_index = 0; } } +#ifdef CPUI_DEBUG else if (opc != op->code()) { - data.getArch()->printMessage("ERROR: Rule " + rl->getName() + " changed op without returning result of 1!"); - opc = op->code(); - rule_index = 0; + throw LowlevelError("ERROR: Rule " + rl->getName() + " changed op without returning result of 1!"); } +#endif } op_state++; rule_index = 0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh index ada0a6fd65..3c8d0ca61e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh @@ -244,11 +244,11 @@ public: /// \return the description virtual string getDescription(void) const { return archid; } - /// \brief Print an error message to console + /// \brief Print a warning message to console /// - /// Write the given message to whatever the registered error stream is + /// Write the given message to a registered stream. /// \param message is the error message - virtual void printMessage(const string &message) const=0; + virtual void printWarning(const string &message) const=0; virtual void encode(Encoder &encoder) const; ///< Encode \b this architecture to a stream virtual void restoreXml(DocumentStorage &store); ///< Restore the Architecture state from XML documents virtual void nameFunction(const Address &addr,string &name) const; ///< Pick a default name for a function diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc index b1bec9b253..5a2b0f5c85 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc @@ -2318,7 +2318,7 @@ int4 ActionReturnSplit::apply(Funcdata &data) count += 1; #ifdef BLOCKCONSISTENT_DEBUG if (!data.getBasicBlocks().isConsistent()) - data.getArch()->printMessage("Block structure is not consistent"); + data.getArch()->printWarning("Block structure is not consistent"); #endif } return 0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc index 0d2629940e..7d8f2af395 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc @@ -1598,7 +1598,7 @@ Symbol *Scope::addMapSym(Decoder &decoder) SymbolEntry entry(sym); entry.decode(decoder); if (entry.isInvalid()) { - glb->printMessage("WARNING: Throwing out symbol with invalid mapping: "+sym->getName()); + glb->printWarning("Throwing out symbol with invalid mapping: "+sym->getName()); removeSymbol(sym); decoder.closeElement(elemId); return (Symbol *)0; @@ -1623,9 +1623,9 @@ FunctionSymbol *Scope::addFunction(const Address &addr,const string &nm) SymbolEntry *overlap = queryContainer(addr,1,Address()); if (overlap != (SymbolEntry *)0) { - string errmsg = "WARNING: Function "+name; + string errmsg = "Function "+nm; errmsg += " overlaps object: "+overlap->getSymbol()->getName(); - glb->printMessage(errmsg); + glb->printWarning(errmsg); } sym = new FunctionSymbol(owner,nm,glb->min_funcsymbol_size); addSymbolInternal(sym); @@ -1672,9 +1672,12 @@ LabSymbol *Scope::addCodeLabel(const Address &addr,const string &nm) SymbolEntry *overlap = queryContainer(addr,1,addr); if (overlap != (SymbolEntry *)0) { - string errmsg = "WARNING: Codelabel "+nm; - errmsg += " overlaps object: "+overlap->getSymbol()->getName(); - glb->printMessage(errmsg); + FunctionSymbol *funcsym = dynamic_cast(overlap->getSymbol()); + if (funcsym == (FunctionSymbol *)0) { // Overlapping with something that isn't a function body + string errmsg = "Codelabel "+nm; + errmsg += " overlaps object: "+overlap->getSymbol()->getName(); + glb->printWarning(errmsg); + } } sym = new LabSymbol(owner,nm); addSymbolInternal(sym); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc index 813d955051..27c76b0a7d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc @@ -895,10 +895,13 @@ bool ArchitectureGhidra::getCPoolRef(const vector &refs,Decoder &decoder) return readAll(sin,decoder); } -void ArchitectureGhidra::printMessage(const string &message) const +void ArchitectureGhidra::printWarning(const string &message) const { - warnings += '\n'+message; + sout.write("\000\000\001\022",4); + sout << "Decompiler: " << message; + sout.write("\000\000\001\023",4); + sout.flush(); } /// \brief Construct given specification files and i/o streams diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh index 529555a7f6..81d2c8acb5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh @@ -82,7 +82,6 @@ struct JavaError : public LowlevelError { class ArchitectureGhidra : public Architecture { istream &sin; ///< Input stream for interfacing with Ghidra ostream &sout; ///< Output stream for interfacing with Ghidra - mutable string warnings; ///< Warnings accumulated by the decompiler string pspecxml; ///< XML pspec passed from Ghidra string cspecxml; ///< XML cspec passed from Ghidra string tspecxml; ///< Stripped down .sla file passed from Ghidra @@ -108,8 +107,6 @@ class ArchitectureGhidra : public Architecture { public: ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,const string &corespec, istream &i,ostream &o); - const string &getWarnings(void) const { return warnings; } ///< Get warnings produced by the last decompilation - void clearWarnings(void) { warnings.clear(); } ///< Clear warnings bool getRegister(const string ®name,Decoder &decoder); ///< Retrieve a register description given a name string getRegisterName(const VarnodeData &vndata); ///< Retrieve a register name given its storage location bool getTrackedRegisters(const Address &addr,Decoder &decoder); ///< Retrieve \e tracked register values at the given address @@ -153,7 +150,7 @@ public: bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info void getStringData(vector &buffer,const Address &addr,Datatype *ct,int4 maxBytes,bool &isTrunc); - virtual void printMessage(const string &message) const; + virtual void printWarning(const string &message) const; static int4 readToAnyBurst(istream &s); ///< Read the next message protocol marker static bool readBoolStream(istream &s); ///< Read a boolean value from the client diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc index a93aa008b2..8ac5921aca 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc @@ -99,18 +99,17 @@ void GhidraCommand::loadParameters(void) if (ghidra == (ArchitectureGhidra *)0) throw JavaError("decompiler","No architecture registered with decompiler"); - ghidra->clearWarnings(); } -/// This method sends any warnings accumulated during execution back, but it can be overloaded -/// to send back any kind of information. Individual records are sent using -/// the message protocol. -void GhidraCommand::sendResult(void) +/// This method can be overloaded to send back any kind of information as a string. Individual records +/// are sent using the message protocol. If the command failed, a string describing the error is passed in. +/// \param errorMsg is, if not empty, the error causing the commmand to fail +void GhidraCommand::sendResult(const string &errorMsg) { if (ghidra != (ArchitectureGhidra *)0) { sout.write("\000\000\001\020",4); - sout << ghidra->getWarnings(); + sout << errorMsg; sout.write("\000\000\001\021",4); } } @@ -127,6 +126,7 @@ int4 GhidraCommand::doit(void) { status = 0; sout.write("\000\000\001\006",4); // Command response header + string errorMsg; try { loadParameters(); int4 type = ArchitectureGhidra::readToAnyBurst(sin); @@ -135,25 +135,19 @@ int4 GhidraCommand::doit(void) rawAction(); } catch(DecoderError &err) { - string errmsg; - errmsg = "Marshaling error: " + err.explain; - ghidra->printMessage( errmsg ); + errorMsg = "Marshaling error: " + err.explain; } catch(JavaError &err) { ArchitectureGhidra::passJavaException(sout,err.type,err.explain); return status; // Abort sending any results } catch(RecovError &err) { - string errmsg; - errmsg = "Recoverable Error: " + err.explain; - ghidra->printMessage( errmsg ); + errorMsg = "Recoverable Error: " + err.explain; } catch(LowlevelError &err) { - string errmsg; - errmsg = "Low-level Error: " + err.explain; - ghidra->printMessage( errmsg ); + errorMsg = "Low-level Error: " + err.explain; } - sendResult(); + sendResult(errorMsg); sout.write("\000\000\001\007",4); // Command response closer sout.flush(); return status; @@ -200,13 +194,13 @@ void RegisterProgram::rawAction(void) archid = open; } -void RegisterProgram::sendResult(void) +void RegisterProgram::sendResult(const string &errorMsg) { sout.write("\000\000\001\016",4); sout << dec << archid; sout.write("\000\000\001\017",4); - GhidraCommand::sendResult(); + GhidraCommand::sendResult(errorMsg); } void DeregisterProgram::loadParameters(void) @@ -225,7 +219,6 @@ void DeregisterProgram::loadParameters(void) if (ghidra == (ArchitectureGhidra *)0) throw JavaError("decompiler","No architecture registered with decompiler"); - ghidra->clearWarnings(); } void DeregisterProgram::rawAction(void) @@ -250,13 +243,13 @@ void DeregisterProgram::rawAction(void) res = 0; } -void DeregisterProgram::sendResult(void) +void DeregisterProgram::sendResult(const string &errorMsg) { sout.write("\000\000\001\016",4); sout << dec << res; sout.write("\000\000\001\017",4); - GhidraCommand::sendResult(); + GhidraCommand::sendResult(errorMsg); } void FlushNative::rawAction(void) @@ -272,13 +265,13 @@ void FlushNative::rawAction(void) res = 0; } -void FlushNative::sendResult(void) +void FlushNative::sendResult(const string &errorMsg) { sout.write("\000\000\001\016",4); sout << dec << res; sout.write("\000\000\001\017",4); - GhidraCommand::sendResult(); + GhidraCommand::sendResult(errorMsg); } void DecompileAt::loadParameters(void) @@ -405,14 +398,14 @@ void SetAction::rawAction(void) res = true; } -void SetAction::sendResult(void) +void SetAction::sendResult(const string &errorMsg) { if (res) ArchitectureGhidra::writeStringStream(sout,"t"); else ArchitectureGhidra::writeStringStream(sout,"f"); - GhidraCommand::sendResult(); + GhidraCommand::sendResult(errorMsg); } void SetOptions::loadParameters(void) @@ -444,14 +437,14 @@ void SetOptions::rawAction(void) res = true; } -void SetOptions::sendResult(void) +void SetOptions::sendResult(const string &errorMsg) { if (res) ArchitectureGhidra::writeStringStream(sout,"t"); else ArchitectureGhidra::writeStringStream(sout,"f"); - GhidraCommand::sendResult(); + GhidraCommand::sendResult(errorMsg); } /// A command is read from the Ghidra client. The matching GhidraCommand object is diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh index db72be59bd..7b01dcc2f5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh @@ -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. @@ -82,7 +82,7 @@ protected: ArchitectureGhidra *ghidra; ///< The Architecture on which to perform the command int4 status; ///< Meta-command to system (0=wait for next command, 1=terminate process) virtual void loadParameters(void); ///< Read parameters directing command execution - virtual void sendResult(void); ///< Send results of the command (if any) back to the Ghidra client + virtual void sendResult(const string &errorMsg); ///< Send back response to the command public: GhidraCommand(void) : sin(cin),sout(cout) { ghidra = (ArchitectureGhidra *)0; @@ -112,7 +112,7 @@ class RegisterProgram : public GhidraCommand { string tspec; ///< Configuration (address-spaces) for the Translate object string corespec; ///< A description of core data-types for the TypeFactory object virtual void loadParameters(void); - virtual void sendResult(void); + virtual void sendResult(const string &errorMsg); public: int4 archid; ///< Resulting id of the program to send back virtual void rawAction(void); @@ -126,7 +126,7 @@ public: class DeregisterProgram : public GhidraCommand { int4 inid; ///< The id of the Architecture being terminated virtual void loadParameters(void); - virtual void sendResult(void); + virtual void sendResult(const string &errorMsg); public: int4 res; ///< The meta-command being issued to send back virtual void rawAction(void); @@ -140,7 +140,7 @@ public: /// (re)fetch any symbols as needed. /// The command expects a single string parameter encoding the id of the program to flush. class FlushNative : public GhidraCommand { - virtual void sendResult(void); + virtual void sendResult(const string &errorMsg); public: int4 res; ///< Success status returned to the client (0=success) virtual void rawAction(void); @@ -211,7 +211,7 @@ class SetAction : public GhidraCommand { string actionstring; ///< The \e root Action to switch to string printstring; ///< The \e printing output configuration to toggle virtual void loadParameters(void); - virtual void sendResult(void); + virtual void sendResult(const string &errorMsg); public: bool res; ///< Set to \b true if the configuration action was successful virtual void rawAction(void); @@ -229,7 +229,7 @@ public: class SetOptions : public GhidraCommand { Decoder *decoder; ///< The \ decoder virtual void loadParameters(void); - virtual void sendResult(void); + virtual void sendResult(const string &errorMsg); public: bool res; ///< Set to \b true if the option change succeeded SetOptions(void) { decoder = (Decoder *)0; res = false; } ///< Constructor diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc index cb0848a4de..3ee5e859a6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc @@ -342,7 +342,7 @@ void SleighArchitecture::resolveArchitecture(void) if (description[i].getId() == baseid) { languageindex = i; if (description[i].isDeprecated()) - printMessage("WARNING: Language "+baseid+" is deprecated"); + printWarning("Language "+baseid+" is deprecated"); break; } } @@ -476,6 +476,12 @@ void SleighArchitecture::restoreXmlHeader(const Element *el) target = el->getAttributeValue("target"); } +void SleighArchitecture::printWarning(const string &message) const + +{ + *errorstream << "WARNING: " << message << endl; +} + /// Given an architecture target string try to recover an /// appropriate processor name for use in a normalized \e language \e id. /// \param nm is the given target string diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh index 3ee506bfa6..5b40bdf10c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh @@ -135,7 +135,7 @@ public: const string &getTarget(void) const { return target; } ///< Get the \e language \e id of the active processor void encodeHeader(Encoder &encoder) const; ///< Encode basic attributes of the active executable void restoreXmlHeader(const Element *el); ///< Restore from basic attributes of an executable - virtual void printMessage(const string &message) const { *errorstream << message << endl; } + virtual void printWarning(const string &message) const; virtual ~SleighArchitecture(void); virtual string getDescription(void) const; diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java index 45fa1b9657..788e69b67e 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java @@ -129,9 +129,7 @@ public class DecompInterface { protected Program program; private SleighLanguage pcodelanguage; private PcodeDataTypeManager dtmanage; - // Last warning messages from the decompiler - // or other error message - protected String decompileMessage; + protected String errorMessage; // Last error causing decompilation to fail protected CompilerSpec compilerSpec; protected DecompileProcess decompProcess; protected DecompileCallback decompCallback; @@ -166,7 +164,7 @@ public class DecompInterface { baseEncodingSet = null; overlayEncodingSet = null; debug = null; - decompileMessage = ""; + errorMessage = ""; compilerSpec = null; actionname = "decompile"; printSyntaxTree = true; @@ -222,16 +220,14 @@ public class DecompInterface { * @return the message string or null */ public String getLastMessage() { - return decompileMessage; + return errorMessage; } - private boolean isErrorMessage() { - if (decompileMessage == null || decompileMessage.length() == 0) { - return false; - } - - // do not count warning messages as error messages - if (decompileMessage.toLowerCase().indexOf("warning") != -1) { + /** + * @return true if there was an error during the last action on this interface + */ + private boolean isError() { + if (errorMessage == null || errorMessage.length() == 0) { return false; } @@ -285,10 +281,10 @@ public class DecompInterface { String cspecxml = xmlEncode.toString(); baseEncodingSet = new EncodeDecodeSet(program); - decompCallback.setNativeMessage(null); + decompCallback.setErrorMessage(""); decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes, program); - String nativeMessage = decompCallback.getNativeMessage(); + String nativeMessage = decompCallback.getErrorMessage(); if ((nativeMessage != null) && (nativeMessage.length() != 0)) { throw new IOException("Could not register program: " + nativeMessage); } @@ -339,11 +335,11 @@ public class DecompInterface { decompProcess.sendCommand1Param("setSignatureSettings", Integer.toString(sigSettings), stringResponse); if (stringResponse.isEmpty()) { - if (decompCallback.getNativeMessage().startsWith("Bad command")) { + if (decompCallback.getErrorMessage().startsWith("Bad command")) { throw new DecompileException("Decompiler", "Decompiler executable not built with signature module"); } - throw new DecompileException("Decompiler", decompCallback.getNativeMessage()); + throw new DecompileException("Decompiler", decompCallback.getErrorMessage()); } if (!stringResponse.toString().equals("t")) { throw new IOException("Could not set signature settings"); @@ -375,18 +371,17 @@ public class DecompInterface { * @return true if the decompiler process is successfully initialized */ public synchronized boolean openProgram(Program prog) { - decompileMessage = ""; + errorMessage = ""; program = prog; Language lang = prog.getLanguage(); if (!lang.supportsPcode()) { - decompileMessage = "Language does not support PCode."; + errorMessage = "Language does not support PCode."; return false; } pcodelanguage = (SleighLanguage) lang; CompilerSpec spec = prog.getCompilerSpec(); if (!(spec instanceof BasicCompilerSpec)) { - decompileMessage = - "Language has unsupported compiler spec: " + spec.getClass().getName(); + errorMessage = "Language has unsupported compiler spec: " + spec.getClass().getName(); return false; } compilerSpec = spec; @@ -401,13 +396,13 @@ public class DecompInterface { if (!decompProcess.isReady()) { throw new IOException("Unable to start decompiler process"); } - decompileMessage = decompCallback.getNativeMessage(); - if (!isErrorMessage()) { + errorMessage = decompCallback.getErrorMessage(); + if (!isError()) { return true; } } catch (Exception ex) { - decompileMessage = ex.getMessage(); + errorMessage = ex.getMessage(); if (decompProcess == null) { return false; } @@ -427,7 +422,7 @@ public class DecompInterface { * is made again. */ public synchronized void closeProgram() { - decompileMessage = ""; + errorMessage = ""; if (program != null) { program = null; decompCallback = null; @@ -668,7 +663,7 @@ public class DecompInterface { if (dtmanage != null) { dtmanage.setNameTransformer(options.getNameTransformer()); } - decompileMessage = ""; + errorMessage = ""; // Property can be set before process exists if (decompProcess == null) { return true; @@ -731,7 +726,7 @@ public class DecompInterface { public synchronized BlockGraph structureGraph(BlockGraph ingraph, int timeoutSecs, TaskMonitor monitor) { - decompileMessage = ""; + errorMessage = ""; if (monitor != null && monitor.isCancelled()) { return null; } @@ -745,7 +740,7 @@ public class DecompInterface { baseEncodingSet.mainQuery.clear(); ingraph.encode(baseEncodingSet.mainQuery); decompProcess.sendCommandTimeout("structureGraph", timeoutSecs, baseEncodingSet); - decompileMessage = decompCallback.getNativeMessage(); + errorMessage = decompCallback.getErrorMessage(); if (!baseEncodingSet.mainResponse.isEmpty()) { resgraph = new BlockGraph(); resgraph.decode(baseEncodingSet.mainResponse); @@ -753,7 +748,7 @@ public class DecompInterface { } } catch (Exception ex) { - decompileMessage = "Exception while graph structuring: " + ex.getMessage() + '\n'; + errorMessage = "Exception while graph structuring: " + ex.getMessage() + '\n'; } finally { if (monitor != null) { @@ -775,11 +770,11 @@ public class DecompInterface { TaskMonitor monitor) { dtmanage.clearTemporaryIds(); - decompileMessage = ""; + errorMessage = ""; if (program == null || (monitor != null && monitor.isCancelled())) { return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage, - decompileMessage, null, DecompileProcess.DisposeState.DISPOSED_ON_CANCEL); + errorMessage, null, DecompileProcess.DisposeState.DISPOSED_ON_CANCEL); } if (monitor != null) { @@ -799,11 +794,11 @@ public class DecompInterface { activeSet.mainQuery.clear(); AddressXML.encode(activeSet.mainQuery, funcEntry); decompProcess.sendCommandTimeout("decompileAt", timeoutSecs, activeSet); - decompileMessage = decompCallback.getNativeMessage(); + errorMessage = decompCallback.getErrorMessage(); } catch (Exception ex) { decoder.clear(); // Clear any partial result - decompileMessage = "Exception while decompiling " + func.getEntryPoint() + ": " + + errorMessage = "Exception while decompiling " + func.getEntryPoint() + ": " + ex.getMessage() + '\n'; } finally { @@ -834,7 +829,7 @@ public class DecompInterface { processState = DecompileProcess.DisposeState.DISPOSED_ON_CANCEL; } - return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage, decompileMessage, + return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage, errorMessage, decoder, processState); } @@ -861,7 +856,7 @@ public class DecompInterface { initializeProcess(); } catch (IOException | DecompileException e) { - decompileMessage = "Exception while resetting decompiler: " + e.getMessage() + "\n"; + errorMessage = "Exception while resetting decompiler: " + e.getMessage() + "\n"; } } @@ -939,10 +934,10 @@ public class DecompInterface { try { verifyProcess(); decompProcess.sendCommand("getSignatureSettings", baseEncodingSet.mainResponse); - decompileMessage = decompCallback.getNativeMessage(); + errorMessage = decompCallback.getErrorMessage(); } catch (Exception e) { - decompileMessage = "Exception while retrieving settings: " + e.getMessage() + '\n'; + errorMessage = "Exception while retrieving settings: " + e.getMessage() + '\n'; } // flushCache(); // We don't need to flush the cache if (!baseEncodingSet.mainResponse.isEmpty()) { @@ -950,7 +945,7 @@ public class DecompInterface { decodeVersionNumber(baseEncodingSet.mainResponse); } catch (Exception e) { - decompileMessage = "Exception while parsing signatures: " + e.getMessage() + '\n'; + errorMessage = "Exception while parsing signatures: " + e.getMessage() + '\n'; } } } @@ -1024,7 +1019,7 @@ public class DecompInterface { public synchronized SignatureResult generateSignatures(Function func, boolean keepcalllist, int timeoutSecs, TaskMonitor monitor) { - decompileMessage = ""; + errorMessage = ""; if (monitor != null && monitor.isCancelled()) { return null; } @@ -1042,10 +1037,10 @@ public class DecompInterface { activeSet.mainQuery.clear(); AddressXML.encode(activeSet.mainQuery, funcEntry); decompProcess.sendCommandTimeout("generateSignatures", timeoutSecs, activeSet); - decompileMessage = decompCallback.getNativeMessage(); + errorMessage = decompCallback.getErrorMessage(); } catch (Exception ex) { - decompileMessage = "Exception while generating signatures: " + ex.getMessage() + '\n'; + errorMessage = "Exception while generating signatures: " + ex.getMessage() + '\n'; } finally { if (monitor != null) { @@ -1058,7 +1053,7 @@ public class DecompInterface { return SignatureResult.decode(decoder, func, keepcalllist); } catch (DecoderException e) { // Error walking the DOM - decompileMessage = "Exception while parsing signatures: " + e.getMessage() + '\n'; + errorMessage = "Exception while parsing signatures: " + e.getMessage() + '\n'; } } return null; @@ -1076,7 +1071,7 @@ public class DecompInterface { */ public synchronized ArrayList debugSignatures(Function func, int timeoutSecs, TaskMonitor monitor) { - decompileMessage = ""; + errorMessage = ""; if (monitor != null && monitor.isCancelled()) { return null; } @@ -1094,10 +1089,10 @@ public class DecompInterface { activeSet.mainQuery.clear(); AddressXML.encode(activeSet.mainQuery, funcEntry); decompProcess.sendCommandTimeout("debugSignatures", timeoutSecs, activeSet); - decompileMessage = decompCallback.getNativeMessage(); + errorMessage = decompCallback.getErrorMessage(); } catch (Exception ex) { - decompileMessage = "Exception while debugging signatures: " + ex.getMessage() + '\n'; + errorMessage = "Exception while debugging signatures: " + ex.getMessage() + '\n'; } finally { if (monitor != null) { @@ -1110,11 +1105,10 @@ public class DecompInterface { return DebugSignature.decodeSignatures(decoder, func); } catch (DecoderException e) { - decompileMessage = "Exception while debugging signatures: " + e.getMessage() + '\n'; + errorMessage = "Exception while debugging signatures: " + e.getMessage() + '\n'; } catch (Exception e) { // Error with the underlying stream - decompileMessage = - "Error in stream describing signatures: " + e.getMessage() + '\n'; + errorMessage = "Error in stream describing signatures: " + e.getMessage() + '\n'; } } return null; diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java index d43fa7e46e..547ddfe1c4 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java @@ -50,6 +50,8 @@ public class DecompileCallback { public final static int MAX_SYMBOL_COUNT = 16; + public final static int MAX_FUNCTION_OFFCUT = 8; // Maximum distance from function entry point where a query still returns the HighFunctionSymbol + /** * Data returned for a query about strings */ @@ -79,7 +81,7 @@ public class DecompileCallback { private AddressFactory addrfactory; private ConstantPool cpool; private PcodeDataTypeManager dtmanage; - private String nativeMessage; + private String errorMessage; private InstructionBlock lastPseudoInstructionBlock; private Disassembler pseudoDisassembler; @@ -94,7 +96,7 @@ public class DecompileCallback { dtmanage = dt; default_extrapop = pcodecompilerspec.getDefaultCallingConvention().getExtrapop(); cpool = null; - nativeMessage = null; + errorMessage = ""; debug = null; } @@ -116,7 +118,7 @@ public class DecompileCallback { if (debug != null) { debug.setPcodeDataTypeManager(dtmanage); } - nativeMessage = null; // Clear last message + errorMessage = ""; // Clear last message lastPseudoInstructionBlock = null; if (pseudoDisassembler != null) { pseudoDisassembler.resetDisassemblerContext(); @@ -124,19 +126,19 @@ public class DecompileCallback { } /** - * @return the last message from the decompiler + * @return the last error message from the decompiler, or an empty string */ - public String getNativeMessage() { - return nativeMessage; + public String getErrorMessage() { + return errorMessage; } /** - * Cache a message returned by the decompiler process + * Cache an error message returned by the decompiler process * * @param msg is the message */ - void setNativeMessage(String msg) { - nativeMessage = msg; + void setErrorMessage(String msg) { + errorMessage = msg; } /** @@ -893,9 +895,14 @@ public class DecompileCallback { private void encodeFunction(Encoder encoder, Function func, Address addr, boolean includeDefaultNames) throws IOException { Address entry = func.getEntryPoint(); - if (entry.getAddressSpace().equals(addr.getAddressSpace())) { + Address endHole = addr; // If all else fails, return hole [addr,addr] + AddressRange range = func.getBody().getRangeContaining(addr); + if (range != null && range.contains(entry)) { long diff = addr.getOffset() - entry.getOffset(); - if ((diff >= 0) && (diff < 8)) { + if (diff < 0) { + endHole = entry.subtract(1); // Return hole [addr,entry) + } + else if (diff < MAX_FUNCTION_OFFCUT) { HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage); @@ -903,7 +910,14 @@ public class DecompileCallback { hfunc.grabFromFunction(extrapop, includeDefaultNames, (extrapop != default_extrapop)); - HighSymbol functionSymbol = new HighFunctionSymbol(entry, (int) (diff + 1), hfunc); + long size = range.getMaxAddress().getOffset() - entry.getOffset() + 1; + if (size <= 0) { + size = 1; + } + else if (size > MAX_FUNCTION_OFFCUT) { + size = MAX_FUNCTION_OFFCUT; + } + HighSymbol functionSymbol = new HighFunctionSymbol(entry, (int) size, hfunc); Namespace namespc = functionSymbol.getNamespace(); if (debug != null) { debug.getFNTypes(hfunc); @@ -912,23 +926,15 @@ public class DecompileCallback { encodeResult(encoder, functionSymbol, namespc); return; } - } - - AddressRangeIterator iter = func.getBody().getAddressRanges(); - while (iter.hasNext()) { - AddressRange range = iter.next(); - if (range.contains(addr)) { - Address first = range.getMinAddress(); - Address last = range.getMaxAddress(); - encodeHole(encoder, first.getAddressSpace(), first.getUnsignedOffset(), - last.getUnsignedOffset(), MutabilitySettingsDefinition.CONSTANT); - return; + else { + endHole = range.getMaxAddress(); } } - // There is probably some sort of error, just return a block - // containing the single queried address + else if (range != null) { + endHole = range.getMaxAddress(); + } encodeHole(encoder, addr.getAddressSpace(), addr.getUnsignedOffset(), - addr.getUnsignedOffset(), MutabilitySettingsDefinition.CONSTANT); + endHole.getUnsignedOffset(), MutabilitySettingsDefinition.CONSTANT); } private int getExtraPopOverride(Function func, Address addr) { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java index 57a1818454..5752ae88f3 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java @@ -304,6 +304,17 @@ public class DecompileProcess { throw new DecompileException(type, message); } + private void generateWarning() throws IOException { + stringDecoder.open(1 << 16, programSource); + int type = readToBuffer(stringDecoder); + if (type != 19) { + throw new IOException("GHIDRA/decompiler alignment error"); + } + stringDecoder.endIngest(); + Msg.warn(this, stringDecoder.toString()); + stringDecoder.clear(); + } + private void readResponse(ByteIngest mainResponse) throws IOException, DecompileException { mainResponse.clear(); readToResponse(); @@ -420,21 +431,24 @@ public class DecompileProcess { currentResponse.endIngest(); currentResponse = null; // Reset current buffer as a native message may follow break; - case 16: // Beginning of any native message from the decompiler - if (currentResponse != null) { // Beginning of native message before end of main response + case 16: // Beginning of any error message from the decompiler + if (currentResponse != null) { // If error message comes before end of main response currentResponse.clear(); // Don't try to parse main response } currentResponse = stringDecoder; currentResponse.open(1 << 20, programSource); break; - case 17: // End of the native message from the decompiler + case 17: // End of the error message from the decompiler if (currentResponse == null) { throw new IOException("Mismatched message header"); } currentResponse.endIngest(); - callback.setNativeMessage(currentResponse.toString()); + callback.setErrorMessage(currentResponse.toString()); currentResponse = null; break; + case 18: // Beginning of informational message + generateWarning(); + break; default: throw new IOException("GHIDRA/decompiler alignment error"); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileResults.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileResults.java index a03315940c..fc32797ee5 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileResults.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileResults.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. @@ -155,11 +155,7 @@ public class DecompileResults { /** * Return any error message associated with the - * decompilation producing these results. Generally, - * there will only be an error if the decompilation was - * aborted for some reason, but there could conceivably - * be warnings obtainable via this method, even if the - * decompilation did complete. + * decompilation producing these results. * @return any error message associated with these results */ public String getErrorMessage() {