mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
Merge remote-tracking branch 'origin/GP-6945_caheckman_BadDataThreshold'
(Closds #9086)
This commit is contained in:
@@ -1421,6 +1421,7 @@ void Architecture::resetDefaultsInternal(void)
|
||||
max_basetype_size = 10; // Needs to be 8 or bigger
|
||||
flowoptions = FlowInfo::error_toomanyinstructions;
|
||||
max_instructions = 100000;
|
||||
max_baddata = 4;
|
||||
infer_pointers = true;
|
||||
analyze_for_loops = true;
|
||||
readonlypropagate = false;
|
||||
|
||||
@@ -183,6 +183,7 @@ public:
|
||||
int4 funcptr_align; ///< How many bits of alignment a function ptr has
|
||||
uint4 flowoptions; ///< options passed to flow following engine
|
||||
uint4 max_instructions; ///< Maximum instructions that can be processed in one function
|
||||
uint4 max_baddata; ///< Maximum number of bad instructions that one function can encounter
|
||||
int4 alias_block_level; ///< Aliases blocked by 0=none, 1=struct, 2=array, 3=all
|
||||
uint4 split_datatype_config; ///< Toggle for data-types splitting: Bit 0=structs, 1=arrays, 2=pointers
|
||||
vector<Rule *> extra_pool_rules; ///< Extra rules that go in the main pool (cpu specific, experimental)
|
||||
|
||||
@@ -38,6 +38,7 @@ FlowInfo::FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs
|
||||
inline_recursion = (set<Address> *)0;
|
||||
insn_count = 0;
|
||||
insn_max = ~((uint4)0);
|
||||
baddata_count = 0;
|
||||
flowoverride_present = data.getOverride().hasFlowOverride();
|
||||
}
|
||||
|
||||
@@ -72,6 +73,7 @@ FlowInfo::FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs
|
||||
inline_recursion = (set<Address> *)0;
|
||||
insn_count = op2->insn_count;
|
||||
insn_max = op2->insn_max;
|
||||
baddata_count = op2->baddata_count;
|
||||
flowoverride_present = data.getOverride().hasFlowOverride();
|
||||
}
|
||||
|
||||
@@ -80,6 +82,7 @@ void FlowInfo::clearProperties(void)
|
||||
{
|
||||
flags &= ~((uint4)(unimplemented_present|baddata_present|outofbounds_present));
|
||||
insn_count = 0;
|
||||
baddata_count = 0;
|
||||
}
|
||||
|
||||
/// For efficiency, this method assumes the given op can actually fall-thru.
|
||||
@@ -442,9 +445,10 @@ bool FlowInfo::processInstruction(const Address &curaddr,bool &startbasic)
|
||||
}
|
||||
}
|
||||
catch(BadDataError &err) {
|
||||
if ((flags & error_unimplemented)!=0)
|
||||
if ((flags & error_baddata)!=0)
|
||||
throw err; // rethrow
|
||||
else {
|
||||
countBadData(err.explain);
|
||||
// Add infinite loop instruction
|
||||
step = 1; // Pretend size 1
|
||||
artificialHalt(curaddr,PcodeOp::badinstruction);
|
||||
@@ -539,6 +543,17 @@ void FlowInfo::handleOutOfBounds(const Address &fromaddr,const Address &toaddr)
|
||||
}
|
||||
}
|
||||
|
||||
/// If the count exceeds the maximum allowable, an exception is thrown.
|
||||
/// \param errMsg is the error message associated with the current bad data
|
||||
void FlowInfo::countBadData(const string &errMsg)
|
||||
|
||||
{
|
||||
if (baddata_count >= glb->max_baddata) {
|
||||
throw BadDataError("Bad instruction count exceeded:\n ...\n "+ errMsg);
|
||||
}
|
||||
baddata_count += 1;
|
||||
}
|
||||
|
||||
/// The address at the top stack that still needs processing is popped.
|
||||
/// P-code is generated for instructions starting at this address until
|
||||
/// one no longer has fall-thru flow (or some other error occurs).
|
||||
@@ -622,6 +637,7 @@ void FlowInfo::reinterpreted(const Address &addr)
|
||||
if ((flags & error_reinterpreted)!=0)
|
||||
throw LowlevelError(s.str());
|
||||
|
||||
countBadData(s.str());
|
||||
if ((flags & reinterpreted_present)==0) {
|
||||
flags |= reinterpreted_present;
|
||||
data.warningHeader(s.str());
|
||||
|
||||
@@ -63,11 +63,12 @@ public:
|
||||
error_unimplemented = 8, ///< Throw an exception for flow into unimplemented instructions
|
||||
error_reinterpreted = 0x10, ///< Throw an exception for flow into previously encountered data at a difference \e cut
|
||||
error_toomanyinstructions = 0x20, ///< Throw an exception if too many instructions are encountered
|
||||
unimplemented_present = 0x40, ///< Indicate we have encountered unimplemented instructions
|
||||
baddata_present = 0x80, ///< Indicate we have encountered flow into unaccessible data
|
||||
outofbounds_present = 0x100, ///< Indicate we have encountered flow out of the specified range
|
||||
reinterpreted_present = 0x200, ///< Indicate we have encountered reinterpreted data
|
||||
toomanyinstructions_present = 0x400, ///< Indicate the maximum instruction threshold was reached
|
||||
error_baddata = 0x40, ///< Throw an exception if an instruction cannot be decoded
|
||||
unimplemented_present = 0x80, ///< Indicate we have encountered unimplemented instructions
|
||||
baddata_present = 0x100, ///< Indicate we have encountered flow into unaccessible data
|
||||
outofbounds_present = 0x200, ///< Indicate we have encountered flow out of the specified range
|
||||
reinterpreted_present = 0x400, ///< Indicate we have encountered reinterpreted data
|
||||
toomanyinstructions_present = 0x800, ///< Indicate the maximum instruction threshold was reached
|
||||
possible_unreachable = 0x1000, ///< Indicate a CALL was converted to a BRANCH and some code may be unreachable
|
||||
flow_forinline = 0x2000, ///< Indicate flow is being generated to in-line (a function)
|
||||
record_jumploads = 0x4000 ///< Indicate that any jump table recovery should record the table structure
|
||||
@@ -99,6 +100,7 @@ private:
|
||||
Address maxaddr; ///< End of actual function range
|
||||
bool flowoverride_present; ///< Does the function have registered flow override instructions
|
||||
uint4 flags; ///< Boolean options for flow following
|
||||
uint4 baddata_count; ///< Number of instructions that could not be disassembled
|
||||
Funcdata *inline_head; ///< First function in the in-lining chain
|
||||
set<Address> *inline_recursion; ///< Active list of addresses for function that are in-lined
|
||||
set<Address> inline_base; ///< Storage for addresses of functions that are in-lined
|
||||
@@ -122,6 +124,7 @@ private:
|
||||
void connectBasic(void); ///< Generate edges between basic blocks
|
||||
bool setFallthruBound(Address &bound); ///< Find end of the next unprocessed region
|
||||
void handleOutOfBounds(const Address &fromaddr,const Address &toaddr);
|
||||
void countBadData(const string &errMsg); ///< Increment bad data counter
|
||||
PcodeOp *artificialHalt(const Address &addr,uint4 flag); ///< Create an artificial halt p-code op
|
||||
void reinterpreted(const Address &addr); ///< Generate warning message or exception for a \e reinterpreted address
|
||||
bool checkForFlowModification(FuncCallSpecs &fspecs);
|
||||
|
||||
@@ -862,7 +862,7 @@ int4 Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop)
|
||||
Address eaddr(baseaddr.getSpace(),~((uintb)0));
|
||||
inlineflow.setRange(baddr,eaddr);
|
||||
inlineflow.setFlags(FlowInfo::error_outofbounds|FlowInfo::error_unimplemented|
|
||||
FlowInfo::error_reinterpreted|FlowInfo::flow_forinline);
|
||||
FlowInfo::error_baddata|FlowInfo::error_reinterpreted|FlowInfo::flow_forinline);
|
||||
inlineflow.forwardRecursion(flow);
|
||||
inlineflow.generateOps();
|
||||
|
||||
|
||||
@@ -1272,6 +1272,6 @@ ElementId ELEM_VAL = ElementId("val",8);
|
||||
ElementId ELEM_VALUE = ElementId("value",9);
|
||||
ElementId ELEM_VOID = ElementId("void",10);
|
||||
|
||||
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",290); // Number serves as next open index
|
||||
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",291); // Number serves as next open index
|
||||
|
||||
} // End namespace ghidra
|
||||
|
||||
@@ -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.
|
||||
@@ -33,6 +33,7 @@ ElementId ELEM_DEFAULTPROTOTYPE = ElementId("defaultprototype",183);
|
||||
ElementId ELEM_ERRORREINTERPRETED = ElementId("errorreinterpreted",184);
|
||||
ElementId ELEM_ERRORTOOMANYINSTRUCTIONS = ElementId("errortoomanyinstructions",185);
|
||||
ElementId ELEM_ERRORUNIMPLEMENTED = ElementId("errorunimplemented",186);
|
||||
ElementId ELEM_BADDATACOUNT = ElementId("baddatacount",290);
|
||||
ElementId ELEM_EXTRAPOP = ElementId("extrapop",187);
|
||||
ElementId ELEM_IGNOREUNIMPLEMENTED = ElementId("ignoreunimplemented",188);
|
||||
ElementId ELEM_INDENTINCREMENT = ElementId("indentincrement",189);
|
||||
@@ -100,6 +101,7 @@ OptionDatabase::OptionDatabase(Architecture *g)
|
||||
registerOption(new OptionErrorUnimplemented());
|
||||
registerOption(new OptionErrorReinterpreted());
|
||||
registerOption(new OptionErrorTooManyInstructions());
|
||||
registerOption(new OptionBadDataCount());
|
||||
registerOption(new OptionDefaultPrototype());
|
||||
registerOption(new OptionInferConstPtr());
|
||||
registerOption(new OptionForLoops());
|
||||
@@ -782,6 +784,33 @@ string OptionErrorTooManyInstructions::apply(Architecture *glb,const string &p1,
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \class OptionErrorBadData
|
||||
/// \brief Toggle whether disassembling bytes that can't be decoded or at a non-existent address is considered a fatal error.
|
||||
///
|
||||
/// If the first parameter is "on" then any BadDataError encountered while following flow will cause a fatal error.
|
||||
/// Otherwise, artificial halts are generated at addresses causing the BadDataError, allowing analysis to continue.
|
||||
string OptionBadDataCount::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const
|
||||
|
||||
{
|
||||
uint4 newMax;
|
||||
string res;
|
||||
if (p1.size() == 0) {
|
||||
newMax = 0xffffffff;
|
||||
res = "No limit on instructions that cannot be disassembled";
|
||||
}
|
||||
else {
|
||||
newMax = 0xdeadbeef;
|
||||
istringstream s1(p1);
|
||||
s1.unsetf(ios::dec | ios::hex | ios::oct); // Let user specify base
|
||||
s1 >> newMax;
|
||||
if (newMax == 0xdeadbeef)
|
||||
throw ParseError("Bad baddatacount parameter");
|
||||
res = "Maximum instructions that cannot be disassembled set to " + p1;
|
||||
}
|
||||
glb->max_baddata = newMax;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \class OptionProtoEval
|
||||
/// \brief Set the prototype model to use when evaluating the parameters of the \e current function
|
||||
///
|
||||
|
||||
@@ -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.
|
||||
@@ -39,6 +39,7 @@ extern ElementId ELEM_DEFAULTPROTOTYPE; ///< Marshaling element \<defaultprotot
|
||||
extern ElementId ELEM_ERRORREINTERPRETED; ///< Marshaling element \<errorreinterpreted>
|
||||
extern ElementId ELEM_ERRORTOOMANYINSTRUCTIONS; ///< Marshaling element \<errortoomanyinstructions>
|
||||
extern ElementId ELEM_ERRORUNIMPLEMENTED; ///< Marshaling element \<errorunimplemented>
|
||||
extern ElementId ELEM_BADDATACOUNT; ///< Marshaling element \<errorbaddata>
|
||||
extern ElementId ELEM_EXTRAPOP; ///< Marshaling element \<extrapop>
|
||||
extern ElementId ELEM_IGNOREUNIMPLEMENTED; ///< Marshaling element \<ignoreunimplemented>
|
||||
extern ElementId ELEM_INDENTINCREMENT; ///< Marshaling element \<indentincrement>
|
||||
@@ -283,6 +284,12 @@ public:
|
||||
virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const;
|
||||
};
|
||||
|
||||
class OptionBadDataCount : public ArchOption {
|
||||
public:
|
||||
OptionBadDataCount(void) { name = "baddatacount"; } ///< Constructor
|
||||
virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const;
|
||||
};
|
||||
|
||||
class OptionProtoEval : public ArchOption {
|
||||
public:
|
||||
OptionProtoEval(void) { name = "protoeval"; } ///< Constructor
|
||||
|
||||
@@ -477,6 +477,7 @@ public class DecompileOptions {
|
||||
private final static String MAX_INSTRUCTIONS = "Max Instructions per Function";
|
||||
private final static String MAX_JUMPTABLE_ENTRIES = "Max Entries per Jumptable";
|
||||
private final static Boolean LINE_NUMBER_DEF = Boolean.TRUE;
|
||||
private final static int SUGGESTED_MAX_BADDATA = 4; // Must match Architecture::resetDefaultsInternal
|
||||
|
||||
private boolean displayLineNumbers;
|
||||
private int decompileTimeoutSeconds;
|
||||
@@ -485,6 +486,8 @@ public class DecompileOptions {
|
||||
private int maxJumpTableEntries;
|
||||
private int cachedResultsSize;
|
||||
|
||||
private int maxBadData; // Maximum number of bad data exceptions caught before aborting
|
||||
|
||||
private DecompilerLanguage displayLanguage; // Output language displayed by the decompiler
|
||||
|
||||
private NameTransformer nameTransformer; // Transformer applied to data-type/function names
|
||||
@@ -533,6 +536,7 @@ public class DecompileOptions {
|
||||
maxIntructionsPer = SUGGESTED_MAX_INSTRUCTIONS;
|
||||
maxJumpTableEntries = SUGGESTED_MAX_JUMPTABLE_ENTRIES;
|
||||
cachedResultsSize = SUGGESTED_CACHED_RESULTS_SIZE;
|
||||
maxBadData = SUGGESTED_MAX_BADDATA;
|
||||
nameTransformer = null;
|
||||
}
|
||||
|
||||
@@ -981,6 +985,9 @@ public class DecompileOptions {
|
||||
if (maxJumpTableEntries != SUGGESTED_MAX_JUMPTABLE_ENTRIES) {
|
||||
appendOption(encoder, ELEM_JUMPTABLEMAX, Integer.toString(maxJumpTableEntries), "", "");
|
||||
}
|
||||
if (maxBadData != SUGGESTED_MAX_BADDATA) {
|
||||
appendOption(encoder, ELEM_BADDATACOUNT, Integer.toString(maxBadData), "", "");
|
||||
}
|
||||
appendOption(encoder, ELEM_PROTOEVAL, protoEvalModel, "", "");
|
||||
encoder.closeElement(ELEM_OPTIONSLIST);
|
||||
}
|
||||
@@ -1325,6 +1332,13 @@ public class DecompileOptions {
|
||||
return displayLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maximum number of times the decompiler will catch a "bad data" exception
|
||||
*/
|
||||
public int getMaxBadData() {
|
||||
return maxBadData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the transformer being applied to data-type, function, and namespace names.
|
||||
* If no transform is being applied, a pass-through object is returned.
|
||||
@@ -1377,6 +1391,14 @@ public class DecompileOptions {
|
||||
this.noCastPrint = noCastPrint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of times the decompiler will catch a "bad data" exception
|
||||
* @param val is the maximum value
|
||||
*/
|
||||
public void setMaxBadData(int val) {
|
||||
maxBadData = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source programming language that decompiler output should be rendered in.
|
||||
* @param val is the source language
|
||||
|
||||
@@ -290,6 +290,7 @@ public record ElementId(String name, int id) {
|
||||
new ElementId("errortoomanyinstructions", 185);
|
||||
public static final ElementId ELEM_ERRORUNIMPLEMENTED =
|
||||
new ElementId("errorunimplemented", 186);
|
||||
public static final ElementId ELEM_BADDATACOUNT = new ElementId("baddatacount", 290);
|
||||
public static final ElementId ELEM_EXTRAPOP = new ElementId("extrapop", 187);
|
||||
public static final ElementId ELEM_IGNOREUNIMPLEMENTED =
|
||||
new ElementId("ignoreunimplemented", 188);
|
||||
@@ -460,5 +461,5 @@ public record ElementId(String name, int id) {
|
||||
public static final ElementId ELEM_EXTRA_STACK = new ElementId("extra_stack", 287);
|
||||
public static final ElementId ELEM_CONSUME_REMAINING = new ElementId("consume_remaining", 288);
|
||||
|
||||
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 290);
|
||||
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 291);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user