diff --git a/.gitignore b/.gitignore index c3fb9d3ddc..90f4b9de6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,14 @@ -*.class +excludedFiles.txt +ghidra.repos.config + +# Misc files produced while executing application +repositories/ +Ghidra/.ghidraSvrKeys +wrapper.log* + Thumbs.db .DS_Store .svn -excludedFiles.txt -.classpath -.project -ghidra.repos.config /*/*/*/*/*/bin/ /*/*/*/*/*/build/ @@ -21,7 +24,8 @@ ghidra.repos.config /bin/ **/dist -repositories/ + +# Ignore Sleigh generated files *.sla **/data/build.xml @@ -30,22 +34,15 @@ repositories/ *.settings *.directory .gradle/ -.settings/ # File locks *.ulock *.lock -# Gradle creates these per developer -**/vs/ - -# Misc files produced while executing application -Ghidra/.ghidraSvrKeys -wrapper.log* - # Ignore object files *.o *.obj +*.class # Ignore MS Visual Studio artifcats Release @@ -54,6 +51,8 @@ Release *.suo *.aps *.vcproj.* +*.vcxproj.* +.vs/ # Ignore UNIX backup files *~ @@ -62,3 +61,4 @@ Release # Ignore eclipse project files .project .classpath +.settings/ 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 9986088ee7..ed92fbfb7d 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 @@ -679,8 +679,11 @@ public class CreateThunkFunctionCmd extends BackgroundCommand { flowType.equals(RefType.CALL_TERMINATOR)) && !flowType.isConditional()) { // program counter should be assumed to be used + // assume PC is used when considering registers that have been set Register PC = program.getLanguage().getProgramCounter(); - usedRegisters.add(new Varnode(PC.getAddress(), PC.getMinimumByteSize())); + if (PC != null) { + usedRegisters.add(new Varnode(PC.getAddress(), PC.getMinimumByteSize())); + } setRegisters.removeAll(usedRegisters); // check that the setRegisters are all hidden, meaning don't care. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index 2edfd4dbe3..7c3fa0f073 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -1250,7 +1250,7 @@ bool PrintC::printCharacterConstant(ostream &s,const Address &addr,int4 charsize /// \brief Push a single character constant to the RPN stack /// /// For C, a character constant is usually emitted as the character in single quotes. -/// Handle unicode, wide characters, etc. +/// Handle unicode, wide characters, etc. Characters come in with the compiler's raw encoding. /// \param val is the constant value /// \param ct is data-type attached to the value /// \param vn is the Varnode holding the value @@ -1259,10 +1259,17 @@ void PrintC::pushCharConstant(uintb val,const TypeChar *ct,const Varnode *vn,con { ostringstream t; - if ((ct->getSize()==1)&& - ((val<7)||(val>0x7e)||((val>13)&&(val<0x20)))) // not a good character constant + if ((ct->getSize()==1)&&(val >= 0x80)) { + // For byte characters, the encoding is assumed to be ASCII, UTF-8, or some other + // code-page that extends ASCII. At 0x80 and above, we cannot treat the value as a + // unicode code-point. Its either part of a multi-byte UTF-8 encoding or an unknown + // code-page value. In either case, we print it as an integer. push_integer(val,1,true,vn,op); + } else { + // From here we assume, the constant value is a direct unicode code-point. + // The value could be an illegal code-point (surrogates or beyond the max code-point), + // but this will just be emitted as an escape sequence. if (doEmitWideCharPrefix() && ct->getSize() > 1) t << 'L'; // Print symbol indicating wide character t << '\''; // char is surrounded with single quotes diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc index 0b46e6dfe0..94fe032e51 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc @@ -446,6 +446,10 @@ bool PrintLanguage::unicodeNeedsEscape(int4 codepoint) if (codepoint == 0x3000) { return true; // ideographic space } + if (codepoint >= 0xd7fc) { // D7FC - D7FF are currently unassigned. + // D800 - DFFF are high and low surrogates, technically illegal. + return true; // Treat as needing to be escaped + } return false; } if (codepoint < 0xf900) { diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/AnonymousVariableAccessDR.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/AnonymousVariableAccessDR.java new file mode 100644 index 0000000000..129bc89662 --- /dev/null +++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/AnonymousVariableAccessDR.java @@ -0,0 +1,69 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.extension.datatype.finder; + +import java.util.List; + +import ghidra.app.decompiler.ClangFieldToken; +import ghidra.app.decompiler.ClangLine; +import ghidra.app.services.DataTypeReference; +import ghidra.program.model.data.Composite; +import ghidra.program.model.data.DataType; + +/** + * This class represents the use of a field of a {@link Composite} data type where there is + * no variable in the Decompiler for that data type. A normal variable access in the + * Decompiler may look like so: + *
+ * 	Foo f;
+ * 	...
+ * 	return f.some_field;
+ * 
+ * + * Alternatively, an anonymous variable access would look like this: + *
+ *	Bar b;
+ * 	...
+ *	return b->foo_array[1].some_field;
+ * 
+ * + * In this case, foo_array[1] is a Foo, whose + * some_field is + * being accessed anonymously, since there is no variable of Foo declared + * in the current function. + */ +public class AnonymousVariableAccessDR extends DecompilerReference { + + protected AnonymousVariableAccessDR(ClangLine line, ClangFieldToken token) { + super(line, token); + } + + @Override + public void accumulateMatches(DataType dt, String fieldName, List results) { + + ClangFieldToken field = (ClangFieldToken) sourceToken; + DataType fieldDt = field.getDataType(); + if (!isEqual(dt, fieldDt)) { + return; + } + + if (field.getText().equals(fieldName)) { + results.add(new DataTypeReference(fieldDt, fieldName, getFunction(), getAddress(), + getContext())); + } + } + +} diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerDataTypeReferenceFinder.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerDataTypeReferenceFinder.java index 8b50998355..d54cf355c0 100644 --- a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerDataTypeReferenceFinder.java +++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerDataTypeReferenceFinder.java @@ -20,6 +20,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Predicate; +import org.apache.commons.collections4.IterableUtils; + import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.DecompilerUtils; import ghidra.app.decompiler.parallel.*; @@ -225,13 +227,13 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde private DataType dataType; private String fieldName; - /** Search for Data Type access only--no field usage */ + /* Search for Data Type access only--no field usage */ DecompilerDataTypeFinderQCallback(Program program, DataType dataType, Consumer callback) { this(program, dataType, null, callback); } - /** Search for composite field access */ + /* Search for composite field access */ DecompilerDataTypeFinderQCallback(Program program, DataType dataType, String fieldName, Consumer callback) { @@ -336,14 +338,38 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde return result; } + /** + * Uses the given line to find variables (also parameters and return types) and any + * accesses to them in that line. A given variable may be used directly or, as in + * the case with Composite types, may have one of its fields accessed. Each result + * found by this method will be at least a variable access and may also itself have + * field accesses. + * + *

Sometimes a line is structured such that there are anonymous variable accesses. This + * is the case where a Composite is being accessed, but the Composite itself is + * not a variable in the current function. See {@link AnonymousVariableAccessDR} for + * more details. + * + * @param line the current line being processed from the Decompiler + * @param results the accumulator into which matches will be placed + */ private void findVariablesInLine(ClangLine line, List results) { + List allTokens = line.getAllTokens(); + Iterable filteredTokens = IterableUtils.filteredIterable(allTokens, + token -> { + // Only include desirable tokens (this is really just for easier debugging). + // Update this filter if the loop below ever needs other types of tokens. + return (token instanceof ClangTypeToken) || + (token instanceof ClangVariableToken) || (token instanceof ClangFieldToken); + }); + // gather any casts until we can use them (the type they modify will follow) List castsSoFar = new ArrayList<>(); VariableDR declaration = null; VariableAccessDR access = null; - for (ClangToken token : line.getAllTokens()) { + for (ClangToken token : filteredTokens) { if (token instanceof ClangTypeToken) { @@ -371,16 +397,15 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde // // Observations: - // 1) 'variableAccess' will be null if we are on a C statement that - // is a declaration (parameter or variable). In this case, 'ref' will - // be an instance of VariableDR. - // 2) 'variableAccess' will be null the first time a variable is used in + // 1) 'access' will be null if we are on a C statement that + // is a declaration (parameter or variable). In this case, + // 'declaration' will be an instance of VariableDR. + // 2) 'access' will be null the first time a variable is used in // a statement. - // 3) if 'variableAccess' is non-null, but already has a variable assigned, + // 3) if 'access' is non-null, but already has a variable assigned, // then this means the current ClangVariableToken represents a new // variable access/usage. // - if (declaration != null) { declaration.setVariable((ClangVariableToken) token); declaration = null; @@ -415,12 +440,32 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde } } - access.addField((ClangFieldToken) token, casts); + ClangFieldToken field = (ClangFieldToken) token; + if (typesDoNotMatch(access, field)) { + // this can happen when a field is used anonymously, such as directly + // after a nested array index operation + results.add(new AnonymousVariableAccessDR(line, field)); + continue; + } + + access.addField(field, casts); castsSoFar.clear(); } } } + private boolean typesDoNotMatch(VariableAccessDR access, ClangFieldToken field) { + + DecompilerVariable variable = access.getVariable(); + if (variable == null) { + return false; // should not happen + } + + DataType variableDt = variable.getDataType(); + DataType fieldDt = field.getDataType(); + return !DecompilerReference.isEqual(variableDt, fieldDt); + } + private VariableAccessDR getLastAccess(List variables) { // for now, assume that the last access will be the last item we added if (variables.isEmpty()) { diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerReference.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerReference.java index 19a377fd23..d2d511ba1c 100644 --- a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerReference.java +++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerReference.java @@ -83,6 +83,10 @@ public abstract class DecompilerReference { return var.getAddress(); } + public ClangLine getLine() { + return line; + } + protected String getContext() { String context = getContext(variable); return context; diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java index df55a3cd3b..e20b59157d 100644 --- a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java +++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java @@ -52,7 +52,7 @@ public abstract class DecompilerVariable { } // Note: this is the icky part of the API. How to know from where to get the data type? - HighVariable highVariable = variable.getHighVariable(); + HighVariable highVariable = variable.getHighVariable(); if (highVariable != null) { return highVariable.getDataType(); } @@ -62,7 +62,7 @@ public abstract class DecompilerVariable { if (dataType != null) { return dataType; } - + // Prefer the type of the first input varnode, unless that type is a 'void *'. // Usually, in that special case, the output varnode has the correct type information. PcodeOp op = variable.getPcodeOp(); @@ -104,7 +104,19 @@ public abstract class DecompilerVariable { } Varnode output = op.getOutput(); - return output.getHigh().getDataType(); + if (output == null) { + // can happen when a variable in volatile memory is used in a write_volatile + // pseudo operation + return null; + } + + HighVariable high = output.getHigh(); + if (high == null) { + // not sure if this can happen; just in case + return null; + } + + return high.getDataType(); } private DataType getDataType(Varnode varnode) { diff --git a/Ghidra/Framework/Generic/build.gradle b/Ghidra/Framework/Generic/build.gradle index a9b1d6a613..0fd371c61b 100644 --- a/Ghidra/Framework/Generic/build.gradle +++ b/Ghidra/Framework/Generic/build.gradle @@ -8,8 +8,8 @@ dependencies { compile "cglib:cglib-nodep:2.2" compile "com.google.guava:guava:19.0" compile "org.jdom:jdom-legacy:1.1.3" - compile "org.apache.logging.log4j:log4j-api:2.8.1" - compile "org.apache.logging.log4j:log4j-core:2.8.1" + compile "org.apache.logging.log4j:log4j-api:2.8.2" + compile "org.apache.logging.log4j:log4j-core:2.8.2" compile "org.apache.commons:commons-collections4:4.1" compile "org.apache.commons:commons-lang3:3.5" compile "org.lucee:commons-io:2.6.0" diff --git a/Ghidra/Framework/Generic/certification.manifest b/Ghidra/Framework/Generic/certification.manifest index 348cdd700a..f6b8cb7877 100644 --- a/Ghidra/Framework/Generic/certification.manifest +++ b/Ghidra/Framework/Generic/certification.manifest @@ -2,13 +2,13 @@ ##MODULE IP: Apache License 2.0 ##MODULE IP: BSD ##MODULE IP: Christian Plattner +##MODULE IP: Crystal Clear Icons - LGPL 2.1 ##MODULE IP: JDOM License ##MODULE IP: MIT -##MODULE IP: Nuvola Icons - LGPL 2.1 ##MODULE IP: Modified Nuvola Icons - LGPL 2.1 -##MODULE IP: Tango Icons - Public Domain +##MODULE IP: Nuvola Icons - LGPL 2.1 ##MODULE IP: Oxygen Icons - LGPL 3.0 -##MODULE IP: Crystal Clear Icons - LGPL 2.1 +##MODULE IP: Tango Icons - Public Domain .classpath||GHIDRA||||END| .gitignore||GHIDRA||||END| .project||GHIDRA||||END| diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java index 8a8bd055f2..4274fa637e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java @@ -261,7 +261,16 @@ public class PcodeDataTypeManager { if (type instanceof Array) { return buildType(type, size); } - if (!(type instanceof FunctionDefinition) && type.getLength() <= 0) { + if (type instanceof FunctionDefinition) { + long id = progDataTypes.getID(type); + if (id <= 0) { + // Its possible the FunctionDefinition was built on the fly and is not + // a permanent data-type of the program with an ID. In this case, we can't + // construct a tag but must build a full tag. + return buildType(type, size); + } + } + else if (type.getLength() <= 0) { return buildType(type, size); } StringBuilder resBuf = new StringBuilder(); diff --git a/Ghidra/Processors/6502/data/languages/6502.slaspec b/Ghidra/Processors/6502/data/languages/6502.slaspec index 0f1833aeac..71394f02ec 100644 --- a/Ghidra/Processors/6502/data/languages/6502.slaspec +++ b/Ghidra/Processors/6502/data/languages/6502.slaspec @@ -78,35 +78,46 @@ define pcodeop readIRQ; ################################################################ REL: reloc is rel [ reloc = inst_next + rel; ] { export *:2 reloc; } +# Immediate +OP1: "#"imm8 is bbb=2; imm8 { tmp:1 = imm8; export tmp; } +# Zero Page +OP1: imm8 is bbb=1; imm8 { export *:1 imm8; } +# Zero Page Indexed X +OP1: imm8,X is bbb=5 & X; imm8 { tmp:2 = zext(imm8 + X); export *:1 tmp; } +# Absolute +OP1: imm16 is bbb=3; imm16 { export *:1 imm16; } +# Absolute Indexed X +OP1: imm16,X is bbb=7 & X; imm16 { tmp:2 = imm16 + zext(X); export *:1 tmp; } +# Absolute Indexed Y +OP1: imm16,Y is bbb=6 & Y; imm16 { tmp:2 = imm16 + zext(Y); export *:1 tmp; } +# Indirect X +OP1: (imm8,X) is bbb=0 & X; imm8 { addr:2 = zext(imm8 + X); tmp:2 = *:2 addr; export *:1 tmp; } +# Indirect Y +OP1: (imm8),Y is bbb=4 & Y; imm8 { addr:2 = imm8; tmp:2 = *:2 addr; tmp = tmp + zext(Y); export *:1 tmp; } -OP1: (imm8,X) is bbb=0 & X; imm8 { addr:2 = imm8 + zext(X); tmp:2 = *:2 addr; export *:1 tmp; } -OP1: imm8 is bbb=1; imm8 { export *:1 imm8; } -OP1: "#"imm8 is bbb=2; imm8 { tmp:1 = imm8; export tmp; } -OP1: imm16 is bbb=3; imm16 { export *:1 imm16; } -OP1: (imm8),Y is bbb=4 & Y; imm8 { addr:2 = imm8; tmp:2 = *:2 addr; tmp = tmp + zext(Y); export *:1 tmp; } -OP1: imm8,X is bbb=5 & X; imm8 { tmp:2 = imm8 + zext(X); export *:1 tmp; } -OP1: imm16,Y is bbb=6 & Y; imm16 { tmp:2 = imm16 + zext(Y); export *:1 tmp; } -OP1: imm16,X is bbb=7 & X; imm16 { tmp:2 = imm16 + zext(X); export *:1 tmp; } +# Immediate +OP2: "#"imm8 is bbb=0; imm8 { tmp:1 = imm8; export tmp; } +# Zero Page +OP2: imm8 is bbb=1; imm8 { export *:1 imm8; } +OP2: A is bbb=2 & A { export A; } +# Absolute +OP2: imm16 is bbb=3; imm16 { export *:1 imm16; } +# Zero Page Indexed X +OP2: imm8,X is bbb=5 & X; imm8 { tmp:2 = zext(imm8 + X); export *:1 tmp; } +# Absolute Indexed X +OP2: imm16,X is bbb=7 & X; imm16 { tmp:2 = imm16 + zext(X); export *:1 tmp; } + +OP2ST: OP2 is OP2 { export OP2; } +OP2ST: imm8,Y is bbb=5 & Y; imm8 { tmp:2 = zext(imm8 + Y); export *:1 tmp; } + +OP2LD: OP2 is OP2 { export OP2; } +OP2LD: imm8,Y is bbb=5 & Y; imm8 { tmp:2 = zext(imm8 + Y); export *:1 tmp; } +OP2LD: imm16,Y is bbb=7 & Y; imm16 { tmp:2 = imm16 + zext(Y); export *:1 tmp; } -OP2: "#"imm8 is bbb=0; imm8 { tmp:1 = imm8; export tmp; } -OP2: imm8 is bbb=1; imm8 { export *:1 imm8; } -OP2: A is bbb=2 & A { export A; } -OP2: imm16 is bbb=3; imm16 { export *:1 imm16; } -OP2: imm8,X is bbb=5 & X; imm8 { tmp:2 = imm8 + zext(X); export *:1 tmp; } -OP2: imm16,X is bbb=7 & X; imm16 { tmp:2 = imm16 + zext(X); export *:1 tmp; } - -OP2ST: OP2 is OP2 { export OP2; } -OP2ST: imm8,Y is bbb=5 & Y; imm8 { tmp:2 = imm8 + zext(Y); export *:1 tmp; } - -OP2LD: OP2 is OP2 { export OP2; } -OP2LD: imm8,Y is bbb=5 & Y; imm8 { tmp:2 = imm8 + zext(Y); export *:1 tmp; } -OP2LD: imm16,Y is bbb=7 & Y; imm16 { tmp:2 = imm16 + zext(Y); export *:1 tmp; } - - -ADDR8: imm8 is imm8 { export *:1 imm8; } -ADDR16: imm16 is imm16 { export *:1 imm16; } -ADDRI: imm16 is imm16 { tmp:2 = imm16; export *:2 tmp; } +ADDR8: imm8 is imm8 { export *:1 imm8; } +ADDR16: imm16 is imm16 { export *:1 imm16; } +ADDRI: imm16 is imm16 { tmp:2 = imm16; export *:2 tmp; } # Instructions diff --git a/Ghidra/Processors/68000/data/languages/68000.sinc b/Ghidra/Processors/68000/data/languages/68000.sinc index aab63359fd..92d8346636 100644 --- a/Ghidra/Processors/68000/data/languages/68000.sinc +++ b/Ghidra/Processors/68000/data/languages/68000.sinc @@ -306,6 +306,8 @@ define pcodeop saveFPUStateFrame; define pcodeop restoreFPUStateFrame; define pcodeop pushInvalidateCaches; +define pcodeop bcdAdjust; + define pcodeop sin; define pcodeop cos; define pcodeop tan; @@ -638,12 +640,15 @@ macro clearflags_fp() { $(NAN_FP) = 0; } -# SCR 10997: +macro bcdflags(result) { + XF = CF; + ZF = (result == 0) * ZF + (result != 0); +} + macro getbit(res,in,bitnum) { res = ((in >> bitnum) & 1) != 0; } -# SCR 10997: macro bitmask(res, width) { res = (1 << width) - 1; } @@ -656,7 +661,6 @@ macro getbitfield(res, off, width) { res = (res << off) >> (32 - width); } -# SCR 10997: macro resbitflags(result, bitnum) { NF = ((result >> bitnum) & 1) != 0; ZF = result == 0; @@ -687,7 +691,7 @@ macro extendedResultFlags(result) { with : extGUARD=1 { -:abcd Tyb,Txb is op=12 & op48=16 & Tyb & Txb unimpl +:abcd Tyb,Txb is op=12 & op48=16 & Tyb & Txb { CF = carry(Tyb,carry(Txb,XF)); Tyb = Tyb + Txb + XF; Tyb = bcdAdjust(Tyb); bcdflags(Tyb); } :add.b eab,reg9dnb is (op=13 & reg9dnb & op68=0)... & eab { addflags(eab,reg9dnb); reg9dnb = reg9dnb + eab; resflags(reg9dnb); } :add.w eaw,reg9dnw is (op=13 & reg9dnw & op68=1)... & eaw { addflags(eaw,reg9dnw); reg9dnw = reg9dnw + eaw; resflags(reg9dnw); } @@ -1391,7 +1395,8 @@ submul: regdr-regdq is regdq & divsgn=0 & divsz=1 & regdr { tmp1:8 = zext(glb regdr=res(4); resflags(res); CF=0; VF=0; } :mul^mulsize e2l,submul is opbig=0x4c & op67=0 & $(DAT_ALTER_ADDR_MODES); submul & mulsize; e2l [ savmod2=savmod1; regtsan=regtfan; ] { glbdenom=e2l; build submul; } -:nbcd eab is (opbig=0x48 & op67=0 & $(DAT_ALTER_ADDR_MODES))... & eab unimpl +:nbcd eab is (opbig=0x48 & op67=0 & $(DAT_ALTER_ADDR_MODES))... & eab + { tmp:1 = eab; CF = (tmp != 0) || (XF == 1); tmp = 0 - tmp - XF; eab = bcdAdjust(tmp); bcdflags(tmp); } # NB: For the neg insn the CF carry flag is not set like other insns, from the manual: @@ -1600,7 +1605,8 @@ ptestLevel: "#"^mregn is mregn { export *[const]:1 mregn; } :rts is opbig=0x4e & op37=14 & op02=5 { PC = *SP; SP = SP+4; return [PC]; } -:sbcd Tyb,Txb is op=8 & op48=16 & Txb & Tyb unimpl +:sbcd Tyb,Txb is op=8 & op48=16 & Txb & Tyb + { CF = (Tyb < Txb) || ( (XF == 1) && (Tyb == Txb) ); Tyb = Tyb - Txb - XF; Tyb = bcdAdjust(Tyb); bcdflags(Tyb); } :s^cc eab is (op=5 & cc & op67=3 & $(DAT_ALTER_ADDR_MODES))... & eab { eab = -cc; } diff --git a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java index cb64e5bac2..f0e3211c86 100644 --- a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java +++ b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/ConstantPoolDex.java @@ -56,8 +56,9 @@ public class ConstantPoolDex extends ConstantPool { String classString = DexUtil.convertTypeIndexToString(dexHeader, fieldIDItem.getClassIndex()); String[] pathArray = DexUtil.convertClassStringToPathArray("", classString); - if (pathArray != null) + if (pathArray != null) { res.token = pathArray[pathArray.length - 1] + '.' + res.token; + } } DataType fieldDT = dexHeader.getDataType(program, fieldIDItem.getTypeIndex()); @@ -72,13 +73,16 @@ public class ConstantPoolDex extends ConstantPool { private String removeUniquifier(String name) { int len = name.length(); - if (len < 10 || name.charAt(len - 9) != '_') + if (len < 10 || name.charAt(len - 9) != '_') { return name; + } char matchChar = name.charAt(len - 8); - if (matchChar != '5' && matchChar != 'e') + if (matchChar != '5' && matchChar != 'e') { return name; - if (name.charAt(len - 7) != '0') + } + if (name.charAt(len - 7) != '0') { return name; + } return name.substring(0, len - 9); } @@ -103,14 +107,19 @@ public class ConstantPoolDex extends ConstantPool { String classString = DexUtil.convertTypeIndexToString(dexHeader, methodIDItem.getClassIndex()); String[] pathArray = DexUtil.convertClassStringToPathArray("", classString); - if (pathArray != null) + if (pathArray != null) { namespaceString = pathArray[pathArray.length - 1]; + } } - if (namespaceString != null) + if (namespaceString != null) { res.token = namespaceString + '.' + res.token; + } } res.tag = ConstantPool.POINTER_METHOD; - FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(res.token, dtManager); + // The FunctionDefinition is constructed on the fly, essentially as an anonymous type + // We use an internal naming scheme involding the the methodID to avoid name collisions + String defName = res.token + '_' + Integer.toHexString(methodID); + FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(defName, dtManager); res.type = new PointerDataType(funcDef); res.hasThisPtr = !isStatic; diff --git a/GhidraBuild/BuildFiles/JsonDoclet/build.gradle b/GhidraBuild/BuildFiles/JsonDoclet/build.gradle index f9b749d998..db5fa4daf4 100644 --- a/GhidraBuild/BuildFiles/JsonDoclet/build.gradle +++ b/GhidraBuild/BuildFiles/JsonDoclet/build.gradle @@ -4,5 +4,7 @@ eclipse.project.name = '_JsonDoclet' apply plugin: 'java' dependencies { - compile 'com.googlecode.json-simple:json-simple:1.1.1' + compile('com.googlecode.json-simple:json-simple:1.1.1') { + exclude group: 'junit', module: 'junit' + } }