GP-1744_emteere CParser fixes for Macros, pragma(push), reincluded header files, unicode BOM files, #if/defined() on values, and full evaluation of macro expansion. Added output of more information in CParser prefixed with /// comments. Reparsed current standard data archives with correct 64/32 data organizations. Use dtMgr for all new data types in preparation for Data Organization changes.

This commit is contained in:
emteere 2022-04-19 11:08:23 -04:00
parent 026fad27ab
commit 33fe035d84
13 changed files with 1022 additions and 417 deletions

View File

@ -27,6 +27,8 @@ import ghidra.util.Msg;
* *
*/ */
public class DefineTable { public class DefineTable {
private static final int ARBITRARY_MAX_REPLACEMENTS = 900000;
// Hastable for storing #defs // Hastable for storing #defs
Hashtable<String, PPToken> defs = new Hashtable<String, PPToken>(); Hashtable<String, PPToken> defs = new Hashtable<String, PPToken>();
@ -267,40 +269,32 @@ public class DefineTable {
* return a string with all the macros substitute starting at pos in the input string. * return a string with all the macros substitute starting at pos in the input string.
* @param image string to expand * @param image string to expand
* @param pos position within string to start expanding * @param pos position within string to start expanding
* @return * @return string with all substitutions applied
*/ */
private String macroSub(String image, int pos, ArrayList<String> sublist) { private String macroSub(String image, int pos, ArrayList<String> sublist) {
int replaceCount = 0; int replaceCount = 0;
StringBuffer buf = new StringBuffer(image); StringBuffer buf = new StringBuffer(image);
int lastReplPos = pos;
// don't replace an infinite number of times. // don't replace an infinite number of times. Fail safe for possible ininite loop
//HashMap<String,Integer> lastReplStrings = new HashMap<String,Integer>(); while (pos < buf.length() && replaceCount < ARBITRARY_MAX_REPLACEMENTS) {
while (pos < buf.length() && replaceCount < 900000) { // clear list of used macros when move past replacement area
if (pos == lastReplPos) {
sublist = new ArrayList<String> (); // ok to clear list of used macro names
}
String defName = getDefineAt(buf, pos); String defName = getDefineAt(buf, pos);
if (shouldReplace(buf, defName, pos)) { if (shouldReplace(buf, defName, pos)) {
// stop recursion on the same replacement string // stop recursion on the same replacement string
// if (lastReplStrings.containsKey(defName)) { int replPos = replace(buf, defName, pos, sublist);
// int lastpos = lastReplStrings.get(defName);
// Vector<PPToken> argv = getArgs(defName); if (replPos == -1) {
// // if it has no args, don't replace already replaced. // if no replacement string, move on
// if (argv == null && pos < lastpos) {
// System.out.println("Already did : " + defName);
// System.out.println(" No repl at " + pos + " lastpos " + lastpos + " : " + buf);
// pos++;
// continue;
// }
// lastReplStrings.remove(defName);
// }
int newpos = replace(buf, defName, pos, sublist);
// is there a replacement string
if (newpos == -1) {
pos++; pos++;
} }
else { else {
//System.err.println(" replace " + defName + " with " + buf.substring(pos,newpos)); // replaced text, update the last place a replacement was made
//lastReplStrings.put(defName,pos + defName.length()); lastReplPos = replPos;
pos = newpos;
replaceCount++; replaceCount++;
} }
} }
@ -308,7 +302,7 @@ public class DefineTable {
pos++; pos++;
} }
} }
if (replaceCount >= 100000) { if (replaceCount >= ARBITRARY_MAX_REPLACEMENTS) {
System.err.println(" replace " + image + " hit limit"); System.err.println(" replace " + image + " hit limit");
} }
return buf.toString(); return buf.toString();
@ -319,7 +313,6 @@ public class DefineTable {
return false; return false;
} }
//String nextRepl = "";
int currIndex = buf.indexOf(defName, pos); int currIndex = buf.indexOf(defName, pos);
if (currIndex < 0) { if (currIndex < 0) {
return false; // nothing to replace return false; // nothing to replace
@ -342,25 +335,6 @@ public class DefineTable {
return false; // no need to replace return false; // no need to replace
} }
// // check that macro argv arguments match
// Vector<PPToken> argv = getArgs(defName);
// if (argv != null && argv.size() > 0) {
// // need to scan carefully, and recursively
// // there shouldn't be so many globals...
// // could be screwed up by so many things
// String parms = getParams(buf, currIndex + defName.length(),
// (char) 0);
//
// int parmslen = parms.length();
// if (parmslen < 2) {
// return false;
// }
// parms = parms.trim();
// if (!parms.startsWith("(") || !parms.endsWith(")")) {
// return false;
// }
// }
return true; return true;
} }
@ -423,19 +397,9 @@ public class DefineTable {
replacedSubpieceLen += parmslen; replacedSubpieceLen += parmslen;
} }
// you may add an else if{} block to warn of malformed macros
// but the actual culprit may be the Define() non-terminal
//if (replString != null)
// nextRepl += replString;
sublist = new ArrayList<String>(sublist);
sublist.add(currKey); sublist.add(currKey);
String newReplString = macroSub(replacementString, 0, sublist);
if (newReplString != null) {
replacementString = newReplString;
}
buf.replace(currIndex, currIndex + replacedSubpieceLen, replacementString); buf.replace(currIndex, currIndex + replacedSubpieceLen, replacementString);
//nextRepl += image.substring(currIndex + currKey.length());
return currIndex + replacementString.length(); return currIndex + replacementString.length();
} }
@ -543,19 +507,25 @@ public class DefineTable {
if (pos >= len) { if (pos >= len) {
return ""; return "";
} }
char ch = buf.charAt(pos); char ch = buf.charAt(pos);
char lastChar = 0;
boolean hitQuote = false; boolean hitQuote = false;
boolean hitTick = false;
while (pos < len) { while (pos < len) {
ch = buf.charAt(pos++); ch = buf.charAt(pos++);
if (ch == '"') { if (ch == '"' && lastChar != '\\') {
hitQuote = !hitQuote; hitQuote = !hitQuote;
} }
if (!hitQuote && ch == endChar && depth == 0) { if (ch == '\'' && lastChar != '\\') {
hitTick = !hitTick;
}
if (!(hitQuote||hitTick) && ch == endChar && depth == 0) {
pos--; pos--;
break; break;
} }
if (!hitQuote && ch == ')') { if (!(hitQuote||hitTick) && ch == ')') {
depth--; depth--;
if (depth == 0 && endChar == 0) { if (depth == 0 && endChar == 0) {
break; break;
@ -566,9 +536,10 @@ public class DefineTable {
break; break;
} }
} }
if (!hitQuote && ch == '(') { if (!(hitQuote||hitTick) && ch == '(') {
depth++; depth++;
} }
lastChar = ch;
} }
return buf.substring(start, pos); return buf.substring(start, pos);
} }

View File

@ -52,8 +52,22 @@
*/ */
options { options {
// Methods and class variables should not be static to allow multiple parsers to be in use.
// This is at the expense of some speed.
STATIC= false; STATIC= false;
// Don't interpret unicode escape sequences, they can appear in embedded text in macros and strings,
// which if interpreted can mess up parsing if they are pre-interpreted by the input stream.
JAVA_UNICODE_ESCAPE = false;
// However, if the file has real embedded unicode characters, such as some microsoft header files,
// they need to be read correctly by the parser. An example is the embedded code at the beginning
// of a file that states that it is in unicode. The characters might be all ascii, which for parsing
// purposes is most likely the case.
UNICODE_INPUT = true;
} }
@ -89,9 +103,12 @@ public class CParser {
private Map<String, DataType> enums = new HashMap<String, DataType>(); private Map<String, DataType> enums = new HashMap<String, DataType>();
private Map<String, DataType> declarations = new HashMap<String, DataType>(); private Map<String, DataType> declarations = new HashMap<String, DataType>();
private Map<String, DataType> internalTypes = new HashMap<String, DataType>();
private DataType lastDataType = null; private DataType lastDataType = null;
private boolean storeNewDT = true; private boolean storeNewDT = true;
private String possiblyUndefinedType = null;
DataTypeManager dtMgr = null; DataTypeManager dtMgr = null;
private DataTypeManager[] subDTMgrs = new DataTypeManager[0]; private DataTypeManager[] subDTMgrs = new DataTypeManager[0];
@ -181,7 +198,7 @@ public class CParser {
} }
} }
dt = new TypedefDataType(type, dt); dt = new TypedefDataType(CategoryPath.ROOT, type, dt, dtMgr);
dt = addDef(types, type, dt); dt = addDef(types, type, dt);
return dt; return dt;
} }
@ -223,6 +240,7 @@ public class CParser {
return dt; return dt;
} }
possiblyUndefinedType = type;
return null; return null;
} }
@ -320,6 +338,20 @@ public class CParser {
table.put(name, dt); table.put(name, dt);
return dt; return dt;
} }
// resolve data types using data type manager so that data organization is considered
//
private DataType resolveInternal(DataType datatype) {
DataType existingDT = internalTypes.get(datatype.getName());
if (existingDT != null) {
return existingDT;
}
existingDT = datatype.copy(dtMgr);
internalTypes.put(datatype.getName(), existingDT);
return existingDT;
}
// rename a data type in the given table // rename a data type in the given table
@ -440,7 +472,7 @@ public class CParser {
if (currentFuncDT != null) { if (currentFuncDT != null) {
return currentFuncDT; return currentFuncDT;
} }
return new FunctionDefinitionDataType(ANONYMOUS_FUNC_PREFIX+func_cnt++); return new FunctionDefinitionDataType(CategoryPath.ROOT, ANONYMOUS_FUNC_PREFIX+func_cnt++, dtMgr);
} }
private void checkReturnDataType(DataType retDT) throws ParseException { private void checkReturnDataType(DataType retDT) throws ParseException {
@ -688,7 +720,9 @@ public class CParser {
if (headerFileName != null) { if (headerFileName != null) {
parseMessage += " in " + headerFileName + " near line " + subLinenum + "\n"; parseMessage += " in " + headerFileName + " near line " + subLinenum + "\n";
} }
parseMessage += "Error: " + e.getMessage() + "\n";
parseMessage += " near token: " + e.currentToken + "\n"; parseMessage += " near token: " + e.currentToken + "\n";
parseMessage += "Possibly Undefined : " + possiblyUndefinedType + "\n";
parseMessage += " Last Valid Datatype: " parseMessage += " Last Valid Datatype: "
+ (lastDataType == null ? "- none -" : lastDataType.getDisplayName()) + "\n"; + (lastDataType == null ? "- none -" : lastDataType.getDisplayName()) + "\n";
parseMessage += " Check around CParserPlugin.out around line: " parseMessage += " Check around CParserPlugin.out around line: "
@ -800,7 +834,9 @@ TOKEN_MGR_DECLS :
SKIP : SKIP :
{ {
" " "\ufeff" // BOM character at beginning of file
|
" "
| |
"\f" "\f"
| |
@ -1262,7 +1298,7 @@ DataType ObjcDef() : {
{ {
( nameTok=<OBJC_IDENTIFIER> ) ( <OBJC_IDENTIFIER> | <OBJC_IGNORE> | <OBJC2_IGNORE> )* ( <OBJC_SEMI> | <OBJC2_END> ) ( nameTok=<OBJC_IDENTIFIER> ) ( <OBJC_IDENTIFIER> | <OBJC_IGNORE> | <OBJC2_IGNORE> )* ( <OBJC_SEMI> | <OBJC2_END> )
{ {
return addTypedef(nameTok.image, VoidDataType.dataType); return addTypedef(nameTok.image, resolveInternal(VoidDataType.dataType));
} }
} }
@ -1381,33 +1417,33 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : {
} }
{ {
( (
<VOID> { dec.setDataType(VoidDataType.dataType); } <VOID> { dec.setDataType(resolveInternal(VoidDataType.dataType)); }
| |
<CHAR> { dt = dec.getDataType(); <CHAR> { dt = dec.getDataType();
if (dt != null) { if (dt != null) {
if (dt == UnsignedIntegerDataType.dataType) { if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) {
dt = UnsignedCharDataType.dataType; dt = resolveInternal(UnsignedCharDataType.dataType);
} else if (dt == IntegerDataType.dataType) { } else if (dt == resolveInternal(IntegerDataType.dataType)) {
dt = CharDataType.dataType; dt = resolveInternal(CharDataType.dataType);
} else { } else {
throw new ParseException("Bad datatype " + dt + " char"); throw new ParseException("Bad datatype " + dt + " char");
} }
} }
else { else {
dt = CharDataType.dataType; dt = resolveInternal(CharDataType.dataType);
} }
dec.setDataType(dt); dec.setDataType(dt);
} }
| |
<WCHAR> { dec.setDataType(WideCharDataType.dataType); } <WCHAR> { dec.setDataType(resolveInternal(WideCharDataType.dataType)); }
| |
<SHORT> { dt = dec.getDataType(); <SHORT> { dt = dec.getDataType();
if (dt == null) { if (dt == null) {
dt = ShortDataType.dataType; dt = resolveInternal(ShortDataType.dataType);
} else if (dt == UnsignedIntegerDataType.dataType) { } else if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) {
dt = UnsignedShortDataType.dataType; dt = resolveInternal(UnsignedShortDataType.dataType);
} else if (dt == IntegerDataType.dataType) { } else if (dt == resolveInternal(IntegerDataType.dataType)) {
dt = ShortDataType.dataType; dt = resolveInternal(ShortDataType.dataType);
} else { } else {
throw new ParseException("Bad datatype " + dt + " short"); throw new ParseException("Bad datatype " + dt + " short");
} }
@ -1420,21 +1456,21 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : {
| |
<INT> { dt = dec.getDataType(); <INT> { dt = dec.getDataType();
if (dt == null ) { if (dt == null ) {
dec.setDataType(IntegerDataType.dataType); dec.setDataType(resolveInternal(IntegerDataType.dataType));
} }
} }
| |
<LONG> { dt = dec.getDataType(); <LONG> { dt = dec.getDataType();
if ( dt == null) { if ( dt == null) {
dt = LongDataType.dataType; dt = resolveInternal(LongDataType.dataType);
} else if ( dt == UnsignedIntegerDataType.dataType) { } else if ( dt == resolveInternal(UnsignedIntegerDataType.dataType)) {
dt = UnsignedLongDataType.dataType; dt = resolveInternal(UnsignedLongDataType.dataType);
} else if (dt == IntegerDataType.dataType) { } else if (dt == resolveInternal(IntegerDataType.dataType)) {
dt = LongDataType.dataType; dt = resolveInternal(LongDataType.dataType);
} else if (dt == LongDataType.dataType) { } else if (dt == resolveInternal(LongDataType.dataType)) {
dt = LongLongDataType.dataType; dt = resolveInternal(LongLongDataType.dataType);
} else if (dt == UnsignedLongDataType.dataType) { } else if (dt == resolveInternal(UnsignedLongDataType.dataType)) {
dt = UnsignedLongLongDataType.dataType; dt = resolveInternal(UnsignedLongLongDataType.dataType);
} else { } else {
throw new ParseException("Bad datatype " + dt + " long"); throw new ParseException("Bad datatype " + dt + " long");
} }
@ -1447,20 +1483,20 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : {
| |
<FLOAT> { dt = dec.getDataType(); <FLOAT> { dt = dec.getDataType();
if ( dt == null) { if ( dt == null) {
dt = FloatDataType.dataType; dt = resolveInternal(FloatDataType.dataType);
} else if ( dt == LongDataType.dataType) { } else if ( dt == resolveInternal(LongDataType.dataType)) {
dt = DoubleDataType.dataType; dt = resolveInternal(DoubleDataType.dataType);
} else { } else {
throw new ParseException("Bad datatype " + dt + " long"); throw new ParseException("Bad datatype " + dt + " long");
} }
dec.setDataType(dt); dec.setDataType(dt);
} }
| |
<DOUBLE> { dec.setDataType(new DoubleDataType()); } <DOUBLE> { dec.setDataType(resolveInternal(DoubleDataType.dataType)); }
| |
<SIGNED> { dt = dec.getDataType(); <SIGNED> { dt = dec.getDataType();
if ( dt == null) { if ( dt == null) {
dt = IntegerDataType.dataType; dt = resolveInternal(IntegerDataType.dataType);
} else { } else {
// data type already set, don't do anything? // data type already set, don't do anything?
dt = dt; dt = dt;
@ -1475,13 +1511,13 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : {
| |
<UNSIGNED> { dt = dec.getDataType(); <UNSIGNED> { dt = dec.getDataType();
if ( dt == null) { if ( dt == null) {
dt = UnsignedIntegerDataType.dataType; dt = resolveInternal(UnsignedIntegerDataType.dataType);
} else if (dt == ShortDataType.dataType) { } else if (dt == resolveInternal(ShortDataType.dataType)) {
dt = UnsignedShortDataType.dataType; dt = resolveInternal(UnsignedShortDataType.dataType);
} else if (dt == LongDataType.dataType) { } else if (dt == resolveInternal(LongDataType.dataType)) {
dt = UnsignedLongDataType.dataType; dt = resolveInternal(UnsignedLongDataType.dataType);
} else if (dt == LongLongDataType.dataType) { } else if (dt == resolveInternal(LongLongDataType.dataType)) {
dt = UnsignedLongLongDataType.dataType; dt = resolveInternal(UnsignedLongLongDataType.dataType);
} else { } else {
throw new ParseException("Bad datatype " + dt + " unsigned"); throw new ParseException("Bad datatype " + dt + " unsigned");
} }
@ -1492,13 +1528,13 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : {
dec = BuiltInDeclarationSpecifier(dec) dec = BuiltInDeclarationSpecifier(dec)
] ]
| |
<INT8> { dec.setDataType(SignedByteDataType.dataType); } <INT8> { dec.setDataType(resolveInternal(SignedByteDataType.dataType)); }
| |
<INT16> { dec.setDataType(ShortDataType.dataType); } <INT16> { dec.setDataType(resolveInternal(ShortDataType.dataType)); }
| |
<INT32> { dec.setDataType(IntegerDataType.dataType); } <INT32> { dec.setDataType(resolveInternal(IntegerDataType.dataType)); }
| |
<INT64> { dec.setDataType(LongLongDataType.dataType); } <INT64> { dec.setDataType(resolveInternal(LongLongDataType.dataType)); }
) )
{ {
return dec; return dec;
@ -1631,8 +1667,7 @@ void PragmaSpecifier() : {
packSize = popPack(ID); packSize = popPack(ID);
newPackVal = null; newPackVal = null;
} }
else if (ds1.image.equals("push")) { else if (ds1.image.equals("push") && ds2 != null) {
// push current and set value
try { try {
// check if second arg is an integer // check if second arg is an integer
int ival = Integer.parseInt(ds2.image); int ival = Integer.parseInt(ds2.image);
@ -1750,7 +1785,7 @@ DataType StructOrUnionSpecifier() : {
Composite StructOrUnion() : {Composite comp;} Composite StructOrUnion() : {Composite comp;}
{ {
( (
<STRUCT> ( DeclSpec() )* { comp = new StructureDataType(ANONYMOUS_STRUCT_PREFIX + cnt++, 0); <STRUCT> ( DeclSpec() | PragmaSpec() )* { comp = new StructureDataType(CategoryPath.ROOT, ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr);
// Always set the packing, because by default structures should be aligned // Always set the packing, because by default structures should be aligned
if (packSize > 0) { if (packSize > 0) {
@ -1762,7 +1797,7 @@ Composite StructOrUnion() : {Composite comp;}
} }
| |
<UNION> ( DeclSpec() )* { comp = new UnionDataType(ANONYMOUS_UNION_PREFIX + cnt++); <UNION> ( DeclSpec() )* { comp = new UnionDataType(CategoryPath.ROOT, ANONYMOUS_UNION_PREFIX + cnt++, dtMgr);
// Always set the packing, because by default structures should be aligned // Always set the packing, because by default structures should be aligned
if (packSize > 0) { if (packSize > 0) {
@ -1821,6 +1856,7 @@ void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
} }
{ {
LineDef() | LineDef() |
PragmaSpec() |
( (
[ dt = SpecifierQualifierList() ] [ dt = SpecifierQualifierList() ]
[ [
@ -1928,7 +1964,7 @@ DataType EnumSpecifier() : {
[ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}" [ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}"
{ {
String enumName= (t != null ? t.image : ("enum_" + cnt++)); String enumName= (t != null ? t.image : ("enum_" + cnt++));
EnumDataType enuum= new EnumDataType(enumName, 4); EnumDataType enuum= new EnumDataType(CategoryPath.ROOT, enumName, 4, dtMgr);
for (EnumMember member : list) { for (EnumMember member : list) {
try { try {
enuum.add(member.name, member.value); enuum.add(member.name, member.value);
@ -2147,7 +2183,7 @@ Declaration ParameterTypeList(FunctionDefinitionDataType funcDT, DataType retDT)
{ {
checkReturnDataType(retDT); checkReturnDataType(retDT);
if (funcDT == null) { if (funcDT == null) {
funcDT= new FunctionDefinitionDataType(ANONYMOUS_FUNC_PREFIX); funcDT= new FunctionDefinitionDataType(CategoryPath.ROOT, ANONYMOUS_FUNC_PREFIX, dtMgr);
} }
funcDT.setVarArgs(varargs!=null); funcDT.setVarArgs(varargs!=null);
ParameterDefinition[] variables= new ParameterDefinition[list.size()]; ParameterDefinition[] variables= new ParameterDefinition[list.size()];
@ -2260,13 +2296,13 @@ void Designator() : { }
"." <IDENTIFIER> "." <IDENTIFIER>
} }
DataType TypeName() : { Declaration TypeName() : {
Declaration dt = null; Declaration dec = null;
} }
{ {
dt = SpecifierQualifierList() [ AbstractDeclarator(new Declaration()) ] dec = SpecifierQualifierList() [ dec = AbstractDeclarator(new Declaration(dec)) ]
{ {
return dt.getDataType(); return dec;
} }
} }
@ -2608,9 +2644,10 @@ Object CastExpression() : {
} }
Object UnaryExpression() : { Object UnaryExpression() : {
DataType dt = null;
Object obj = null; Object obj = null;
Token op = null; Token op = null;
Token id = null;
Declaration dec = null;
} }
{ {
( (
@ -2633,13 +2670,19 @@ Object UnaryExpression() : {
| |
<SIZEOF> <SIZEOF>
( (
"(" (dt = TypeName() | <IDENTIFIER> | obj = ConstantExpression() ) ")" "(" ( dec = TypeName() | id = <IDENTIFIER> | obj = ConstantExpression() ) ")"
{ {
if (dt != null) { if (obj != null && obj instanceof String) {
obj = Long.valueOf(dt.getLength());
} else if (obj != null && obj instanceof String) {
obj = Long.valueOf(((String) obj).length() - 1); // will include "" plus \0 obj = Long.valueOf(((String) obj).length() - 1); // will include "" plus \0
} }
else if (dec != null) {
obj = Long.valueOf(dec.getDataType().getLength());
}
else if (id != null) {
// TODO: try to look up the type of the identifier
// TODO: Throw error if identifier is not defined
// may need to actually track declarations!
}
} }
) )
) )

View File

@ -124,12 +124,6 @@ public class CParserTest extends AbstractGenericTest {
return dtm; return dtm;
} }
@Test
public void testPreProcessor() throws Exception {
// TODO: parse a header file with lots of CPP defines, etc
// TODO: Do a simple parse to make sure the data came out correctly
}
@Test @Test
public void testHeaderParsing() throws Exception { public void testHeaderParsing() throws Exception {
// Uncomment to save the parse results to a GDT file to check out // Uncomment to save the parse results to a GDT file to check out
@ -154,6 +148,11 @@ public class CParserTest extends AbstractGenericTest {
DataType dt; DataType dt;
String str; String str;
dt = dtMgr.getDataType(new CategoryPath("/"), "_IO_FILE_complete");
Structure sldt = (Structure) dt;
DataTypeComponent data3 = sldt.getComponent(2);
assertEquals("Computed Array correct", 40, data3.getLength());
dt = dtMgr.getDataType(new CategoryPath("/"), "fnptr"); // typedef int (*fnptr)(struct fstruct); dt = dtMgr.getDataType(new CategoryPath("/"), "fnptr"); // typedef int (*fnptr)(struct fstruct);
// "fnptr" named typedef of pointer to "int fnptr(fstruct )" --- should an anonymous function name be used? // "fnptr" named typedef of pointer to "int fnptr(fstruct )" --- should an anonymous function name be used?

View File

@ -20,24 +20,44 @@ import static org.junit.Assert.*;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.net.URL; import java.net.URL;
import org.junit.Test; import org.junit.*;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.app.util.cparser.CPP.ParseException;
import ghidra.app.util.cparser.CPP.PreProcessor; import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
public class PreProcessorTest extends AbstractGenericTest { public class PreProcessorTest extends AbstractGenericTest {
private static String resourceName = "PreProcessorTest.h";
private static CategoryPath path = new CategoryPath(new CategoryPath("/PreProcessorTest.h"), "defines");
// must get rid of after all tests
private static StandAloneDataTypeManager dtMgr;
private static ByteArrayOutputStream baos = new ByteArrayOutputStream();
private static PreProcessor parser;
long value;
String defname;
public PreProcessorTest() { public PreProcessorTest() {
super(); super();
} }
@Test @BeforeClass
public void testHeaderParsing() throws Exception { public static void init() {
PreProcessor parser = new PreProcessor(); URL url = PreProcessorTest.class.getResource(resourceName);
String[] args = new String[] {"-I"+url.getPath()+"/..","-DFROM_ARG_VALUE=300", "-DFROM_ARG_DEF", "-DFROM_ARG_EMPTY=\"\""};
parser = null;
try {
parser = new PreProcessor(args);
}
catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
parser.setOutputStream(baos); parser.setOutputStream(baos);
//// String[] args = new String[] {"-I/local/VisualStudio/Windows/v7.0a/Include", "-I/local/VisualStudio/VS12/include", "-D_WIN32", "-D_CRT_SECURE_NO_WARNINGS"}; //// String[] args = new String[] {"-I/local/VisualStudio/Windows/v7.0a/Include", "-I/local/VisualStudio/VS12/include", "-D_WIN32", "-D_CRT_SECURE_NO_WARNINGS"};
@ -53,14 +73,25 @@ public class PreProcessorTest extends AbstractGenericTest {
//// fullName = "adoguids.h"; //// fullName = "adoguids.h";
//// parser.parse(fullName); //// parser.parse(fullName);
String resourceName = "PreProcessorTest.h";
URL url = PreProcessorTest.class.getResource(resourceName);
parser.parse(url.getFile()); parser.parse(url.getFile());
// Uncomment to print out parse results // Uncomment to print out parse results
System.err.println(baos.toString()); // System.err.println(baos.toString());
dtMgr = new StandAloneDataTypeManager("parsed");
parser.getDefinitions().populateDefineEquates(dtMgr);
}
@AfterClass
public static void destroy() {
dtMgr = null;
baos = null;
parser = null;
}
@Test
public void testHeaderParsed() throws Exception {
String results = baos.toString("ASCII"); String results = baos.toString("ASCII");
int end = results.lastIndexOf(";") + 1; int end = results.lastIndexOf(";") + 1;
String endStr = results.substring(end - 9, end); String endStr = results.substring(end - 9, end);
@ -68,15 +99,15 @@ public class PreProcessorTest extends AbstractGenericTest {
assertTrue("macro expansion _fpl(bob) failed ", results assertTrue("macro expansion _fpl(bob) failed ", results
.indexOf("extern int __declspec(\"fp(\\\"l\\\", \" #bob \")\") __ifplbob;") != -1); .indexOf("extern int __declspec(\"fp(\\\"l\\\", \" #bob \")\") __ifplbob;") != -1);
}
@Test
public void testDefines() throws Exception {
long value;
String defname;
StandAloneDataTypeManager dtMgr = new StandAloneDataTypeManager("parsed"); value = 32516;
parser.getDefinitions().populateDefineEquates(dtMgr); defname = "DefVal1";
CategoryPath path = new CategoryPath("/PreProcessorTest.h");
path = new CategoryPath(path, "defines");
long value = 32516;
String defname = "DefVal1";
checkDefine(dtMgr, path, value, defname); checkDefine(dtMgr, path, value, defname);
value = 0x06010000 + 0xf1; value = 0x06010000 + 0xf1;
@ -129,10 +160,145 @@ public class PreProcessorTest extends AbstractGenericTest {
defname = "isDefineOnValue"; defname = "isDefineOnValue";
value = 1; value = 1;
checkDefine(dtMgr, path, value, defname); checkDefine(dtMgr, path, value, defname);
defname = "DID_EXPANSION";
value = 1;
checkDefine(dtMgr, path, value, defname);
defname = "BIGNUM"; defname = "BIGNUM";
value = 64 * 16 + 16; value = 64 * 16 + 16;
checkDefine(dtMgr, path, value, defname); checkDefine(dtMgr, path, value, defname);
defname = "NEWLINETEST1";
value = 1;
checkDefine(dtMgr, path, value, defname);
defname = "NEWLINETEST2";
value = 2;
checkDefine(dtMgr, path, value, defname);
defname = "NEWLINETEST3";
value = 3;
checkDefine(dtMgr, path, value, defname);
defname = "SEPERATORC";
String defval = parser.getDef(defname);
assertEquals(defval, "','");
}
@Test
public void testDefinesArgValue() {
defname = "DID_ARG_VALUE";
value = 1;
checkDefine(dtMgr, path, value, defname);
// This is from a -D arg define, not from a file
CategoryPath argCategoryPath = new CategoryPath(CategoryPath.ROOT, "defines");
defname = "FROM_ARG_VALUE";
value = 300;
checkDefine(dtMgr, argCategoryPath, value, defname);
}
@Test
public void testDefinesArgEmpty() {
defname = "DID_ARG_EMPTY";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesArgDef() {
defname = "DID_ARG_DEF";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesArgIsDefValue() {
defname = "DID_ARG_ISDEF_VALUE";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesArgIsDefEmpty() {
defname = "DID_ARG_ISDEF_EMPTY";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesArgIsDefDef() {
defname = "DID_ARG_ISDEF_DEF";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testFileDefinesValue() {
defname = "DID_FILE_VALUE";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesFileEmpty() {
defname = "DID_FILE_EMPTY";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesFileDef() {
defname = "DID_FILE_DEF";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesFileIsDefValue() {
defname = "DID_FILE_ISDEF_VALUE";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesFileIsDefEmpty() {
defname = "DID_FILE_ISDEF_EMPTY";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testDefinesFileIsDefDef() {
defname = "DID_FILE_ISDEF_DEF";
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testMultipleInclude() {
defname = "INCLUDE1";
String defval = parser.getDef(defname);
assertNotNull("Had 1 duplicate include", defval);
defname = "INCLUDE2";
defval = parser.getDef(defname);
assertNotNull("Had 2 duplicate include", defval);
defname = "INCLUDE3";
defval = parser.getDef(defname);
assertNotNull("Had 3 duplicate include", defval);
defname = "INCLUDE4";
defval = parser.getDef(defname);
assertNotNull("Had 4 duplicate include", defval);
defname = "INCLUDE5";
defval = parser.getDef(defname);
// if a define is not defined, getDef() returns name of define as value
assertEquals("No INCLUDE5 define", "INCLUDE5", defval);
} }
private void checkDefine(StandAloneDataTypeManager dtMgr, CategoryPath path, long value, private void checkDefine(StandAloneDataTypeManager dtMgr, CategoryPath path, long value,

View File

@ -18,6 +18,26 @@
** Some data types are checked. More checking of the parsed information would be beneficial at some point. ** Some data types are checked. More checking of the parsed information would be beneficial at some point.
**/ **/
void blarg(int *);
void * foo;
typedef void *bar;
typedef int size_t;
typedef int pid_t;
struct _IO_FILE_complete
{
size_t __pad5;
int _mode;
/* Make sure we don't get into trouble again. */
char _unused2[15 * sizeof (int) - 4 * sizeof (void **) - sizeof (size_t)];
};
/** /**
** use of long as an attribute ** use of long as an attribute
@ -60,7 +80,7 @@ int (__stdcall * GetSectionBlock) (
#pragma pack(push, 4) #pragma pack(push, 4)
__pragma(pack(push, MyName, 8)) __pragma(pack(push, MyName, 8))
struct packed8 { struct __declspec(align(16)) __pragma(warning(push)) __pragma(warning(disable:4845)) __declspec(no_init_all) __pragma(warning(pop)) packed8 {
char a; char a;
short b; short b;
int c; int c;
@ -91,6 +111,10 @@ struct packed1 {
char a; char a;
}; };
#pragma pack(push);
#pragma pack(1);
#pragma pack(pop);
#pragma pack(); // reset to none #pragma pack(); // reset to none
struct packed_none { struct packed_none {

View File

@ -13,8 +13,125 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/* definition coming from -D, should evaluate to true */
#if FROM_ARG_VALUE
#define DID_ARG_VALUE 1
#endif
#if FROM_ARG_DEF
#define DID_ARG_DEF 1
#endif
#if FROM_ARG_EMPTY
#define DID_ARG_EMPTY 1
#endif
#if defined(FROM_ARG_VALUE)
#define DID_ARG_ISDEF_VALUE 1
#endif
#if defined(FROM_ARG_DEF)
#define DID_ARG_ISDEF_DEF 1
#endif
#if defined(FROM_ARG_EMPTY)
#define DID_ARG_ISDEF_EMPTY 1
#endif
/* Defined checks from file */
#define FROM_FILE_VALUE 300
#define FROM_FILE_EMPTY ""
#define FROM_FILE_DEF
#if FROM_FILE_VALUE
#define DID_FILE_VALUE 1
#endif
#if FROM_FILE_EMPTY
#define DID_FILE_EMPTY 1
#endif
#if FROM_FILE_DEF
#define DID_FILE_DEF 1
#endif
#if defined(FROM_FILE_VALUE)
#define DID_FILE_ISDEF_VALUE 1
#endif
#if defined(FROM_FILE_EMPTY)
#define DID_FILE_ISDEF_EMPTY 1
#endif
#if defined(FROM_FILE_DEF)
#define DID_FILE_ISDEF_DEF 1
#endif
#include "multinclude.h"
#include "multinclude.h"
#include "multinclude.h"
#include "multinclude.h"
#define __TEXT(quote) quote
#define TEXT(quote) __TEXT(quote)
#define SEPERATORC TEXT(',')
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
#define ZeroMemory RtlZeroMemory
#define foo ZeroMemory(&Filter->gf_group, sizeof(Filter->gf_group));
int foo;
#pragma once #pragma once
#define PTYPE 4
#define TYPE2 2 /* 2 */
#define TYPE3 3 /* 3 */
#define TYPE4 4 /* 4 */
#define TYPE5 5 /* 5 */
#define TYPE6 6 /* 6 */
#ifndef P1
#define P1 \
(PTYPE == TYPE3 || \
PTYPE == TYPE4 || \
PTYPE == TYPE5 )
#endif
#ifndef P2
#define P2 \
(PTYPE == TYPE5 || \
PTYPE == TYPE6)
#endif
#ifndef P3
#define P3 \
(PTYPE == TYPE1 || \
PTYPE == TYPE5 )
#endif
#define PPTYPE(Partition) (Partition)
#if PPTYPE(P1 | P2 | P3)
#define DID_EXPANSION 1
#else
#define DID_EXPANSION 0
#endif
#ifndef _CRTIMP #ifndef _CRTIMP
#define _VCRT_DEFINED_CRTIMP #define _VCRT_DEFINED_CRTIMP
@ -39,6 +156,8 @@
#error "Too many fish" #error "Too many fish"
#define TOO_MANY_FISH 0 #define TOO_MANY_FISH 0
int TooManyFish; int TooManyFish;
#else
int NotEnoughFish;
#endif #endif
#define TEST1 one #define TEST1 one
@ -98,10 +217,10 @@ int TEST_FAILED;
#define AVERSION enum AVERSION #define AVERSION enum AVERSION
AVERSION AVERSION
{ {
AVERSION_5 = 1, AVERSION_5 = 1, // version 5
AVERSION_6, AVERSION_6, // version 6
AVERSION_7, AVERSION_7, // version 7
AVERSION_8, AVERSION_8, // version 9
}; };
#define Group(a,b) #define Group(a,b)
@ -146,7 +265,9 @@ _fpl(bob)
EXTERN_C const GUID DECLSPEC_SELECTANY name \ EXTERN_C const GUID DECLSPEC_SELECTANY name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
BUILD_GUID(LIBID_ADO20,0x##00000200,0x##0000,0x##0010,0x##80,0x##00,0x##00,0x##AA,0x##00,0x##6D,0x##2E,0x##A4) BUILD_GUID(LIBID_ADO20,0x##00000200,0x##0000,
0x##0010,0x##80,0x##00,0x##00,
0x##AA,0x##00,0x##6D,0x##2E,0x##A4)
#define ___POSIX_C_DEPRECATED_STARTING_199506L #define ___POSIX_C_DEPRECATED_STARTING_199506L
@ -276,5 +397,26 @@ int does_not_has_include();
# include_next <float.h> # include_next <float.h>
#endif #endif
#if 0
#define NEWLINETEST1 0 // uh oh
#else
#define NEWLINETEST1 1 // strange
#endif
#define NEWLINETEST2 2 /* Comment with */
/* linefeed */
#define NEWLINETEST3 3
// Should be blank line below
#define AVALUE 1
// Should be blank line above
// 5 blank lines below
#if 0
#define BVALUE 0
#else
#define BVALUE 2
#endif
// 5 blank lines above
theEnd(); theEnd();

View File

@ -0,0 +1,34 @@
/* ###
* 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.
*/
#ifndef INCLUDE1
#define INCLUDE1
#pragma pack(push,1)
#else if !defined(INCLUDE2)
#define INCLUDE2
#pragma pack(push, 2)
#else if !defined(INCLUDE3)
#define INCLUDE3
#pragma pack(push, 4)
#else if !defined(INCLUDE4)
#define INCLUDE4
#pragma pack(push, 8)
#else
#define INCLUDE5 // never gets to this
#endif

View File

@ -56,7 +56,7 @@ public class AddressEvaluator {
} }
else if (obj instanceof Long) { else if (obj instanceof Long) {
try { try {
return af.getDefaultAddressSpace().getAddress(((Long) obj).longValue()); return af.getDefaultAddressSpace().getAddress(((Long) obj).longValue(), true);
} }
catch (Exception e) { catch (Exception e) {
// ignore // ignore
@ -100,7 +100,7 @@ public class AddressEvaluator {
} }
// = must be followed by =, others can be followed // = must be followed by =, others can be followed
if (tok.equals("=") || tok.equals("!") || tok.equals("<") || tok.equals(">")) { if ("=!<>|&".contains(tok)) {
lookahead = parser.nextToken(); lookahead = parser.nextToken();
tok = checkDoubleToken(tok, lookahead); tok = checkDoubleToken(tok, lookahead);
// if tok is now longer, consumed lookahead // if tok is now longer, consumed lookahead
@ -151,6 +151,18 @@ public class AddressEvaluator {
return "!="; return "!=";
} }
break; break;
case "|":
if (lookahead.equals("|")) {
return "||";
}
break;
case "&":
if (lookahead.equals("&")) {
return "&&";
}
break;
} }
return tok; return tok;
@ -365,6 +377,14 @@ public class AddressEvaluator {
if (!evaluateOperator(list, Operator.LESSEQUALS, Operator.GREATEREQUALS)) { if (!evaluateOperator(list, Operator.LESSEQUALS, Operator.GREATEREQUALS)) {
return null; return null;
} }
if (!evaluateOperator(list, Operator.LOG_AND, null)) {
return null;
}
if (!evaluateOperator(list, Operator.LOG_OR, null)) {
return null;
}
if (list.size() != 1) { if (list.size() != 1) {
return null; return null;
@ -498,6 +518,18 @@ public class AddressEvaluator {
return diff > 0L ? 1L : 0L; return diff > 0L ? 1L : 0L;
} }
} }
else if (op == Operator.LOG_AND) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
boolean test = (((Long) v1).longValue()) != 0 && (((Long) v2).longValue()) != 0;
return test ? 1L : 0L;
}
}
else if (op == Operator.LOG_OR) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
boolean test = (((Long) v1).longValue()) != 0 || (((Long) v2).longValue()) != 0;
return test ? 1L : 0L;
}
}
return null; return null;
} }
@ -544,6 +576,8 @@ class Operator {
static Operator RIGHTSHIFT = new Operator(">>"); static Operator RIGHTSHIFT = new Operator(">>");
static Operator LEFT_PAREN = new Operator("("); static Operator LEFT_PAREN = new Operator("(");
static Operator RIGHT_PAREN = new Operator(")"); static Operator RIGHT_PAREN = new Operator(")");
static Operator LOG_OR = new Operator("||");
static Operator LOG_AND = new Operator("&&");
static Operator EQUALS = new Operator("=="); static Operator EQUALS = new Operator("==");
static Operator NOTEQUALS = new Operator("!="); static Operator NOTEQUALS = new Operator("!=");
static Operator LESS = new Operator("<"); static Operator LESS = new Operator("<");
@ -622,6 +656,12 @@ class Operator {
else if (tok.equals(">=")) { else if (tok.equals(">=")) {
return GREATEREQUALS; return GREATEREQUALS;
} }
else if (tok.equals("||")) {
return LOG_OR;
}
else if (tok.equals("&&")) {
return LOG_AND;
}
return null; return null;
} }
} }