Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 55 additions & 26 deletions Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
Original file line number Diff line number Diff line change
Expand Up @@ -517,35 +517,54 @@ public class CParser {
}


private DataType allocateEnumDT(Token t, ArrayList<EnumMember> list) {
String enumName = (t != null ? t.image : ("enum_" + cnt++));

// get the normal enum size, which is an int
// TODO: allow for packing of enum to smallest value with either dataOrganization, or packing flag
int normalEnumLen = (dtMgr != null ? dtMgr.getDataOrganization().getIntegerSize() : 4);
private DataType allocateEnumDT(Token t, Declaration underlyingTypeDecl, ArrayList<EnumMember> list, boolean isPacked) {
String enumName = (t != null ? t.image : ("enum_" + cnt++));
int defaultSize = (dtMgr != null && dtMgr.getDataOrganization() != null ? dtMgr.getDataOrganization().getIntegerSize() : 4);
int initialEnumSize = defaultSize;

// create an initial enum and add all new members
EnumDataType enumDT= new EnumDataType(getCurrentCategoryPath(), enumName, 8, dtMgr);
if (underlyingTypeDecl != null) {
DataType resolvedUnderlyingType = underlyingTypeDecl.getDataType();
if (resolvedUnderlyingType == null) {
addNearParseMessage("Error: Enum '" + enumName + "' has undefined underlying type '" +
underlyingTypeDecl.getName() + "'. Using default integer size (" + defaultSize + ").");
} else {
int typeLength = resolvedUnderlyingType.getLength();
if (typeLength == 1 || typeLength == 2 || typeLength == 4 || typeLength == 8) {
initialEnumSize = typeLength;
} else {
addNearParseMessage("Warning: Enum '" + enumName + "' specified underlying type '" +
resolvedUnderlyingType.getDisplayName() +
"' has a non-standard length (" + typeLength +
"). Enums should have a length of 1, 2, 4, or 8. Using default integer size (" + defaultSize + ").");
}

if (!(resolvedUnderlyingType instanceof AbstractIntegerDataType)) {
addNearParseMessage("Warning: Enum '" + enumName + "' has underlying type '" +
resolvedUnderlyingType.getDisplayName() +
"' which is not a standard C integer or char type. Behavior may be unexpected.");
}
}
}

EnumDataType enumDT = new EnumDataType(getCurrentCategoryPath(), enumName, initialEnumSize, dtMgr);
if (list != null) {
for (EnumMember member : list) {
try {
enumDT.add(member.name, member.value);
enumDT.add(member.name, member.value);
} catch (IllegalArgumentException exc) {
addNearParseMessage("duplicate enum value: " + enumName + " : " + member.name + " : " + member.value);
}
}
// get the minimum length to represent the values and resize if too big
int minLen = enumDT.getMinimumPossibleLength();
if (minLen > normalEnumLen) {
enumDT.setLength(minLen);
} else {
enumDT.setLength(normalEnumLen);
}
}

int minLen = enumDT.getMinimumPossibleLength();
int finalEnumLength;
if (underlyingTypeDecl == null && isPacked) {
finalEnumLength = minLen;
} else {
// length doesn't really matter, forward declaration with no values
enumDT.setLength(normalEnumLen);
finalEnumLength = Math.max(minLen, initialEnumSize);
}

enumDT.setLength(finalEnumLength);
return addDef(enums, enumDT.getName(), enumDT);
}

Expand Down Expand Up @@ -1211,7 +1230,7 @@ TOKEN :
|
<UNALIGNED : "__unaligned" >
|
<PACKED : "__packed" >
<PACKED : ("__packed" | "__packed__" | "packed") >
|
<ATTRIBUTE : "__attribute" (["_"])* >
|
Expand Down Expand Up @@ -1835,7 +1854,7 @@ Declaration TypeQualifier(Declaration dec) : {}
<RESTRICT> |
<EXTENSION> |
<STATIC> |
<PACKED> |
<PACKED> { dec.addQualifier(PACKED); } |
<UNALIGNED> |
( DeclSpec(dec) )
)
Expand Down Expand Up @@ -2255,23 +2274,33 @@ DataType EnumSpecifier() : {
Token t= null;
DataType dt;
ArrayList<EnumMember> list;
Declaration dec = new Declaration();
Declaration attributeDecl = new Declaration();
Declaration typeDecl = null;
boolean isPacked = false;
}
{
<ENUM>
[ LOOKAHEAD(2) AttributeSpecList(attributeDecl) ]
(
LOOKAHEAD(3)
[AttributeSpecList(dec)] [ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}"
LOOKAHEAD(4)
[ t= <IDENTIFIER> ]
[ LOOKAHEAD(2) ":" typeDecl= TypeName() ]
"{" list= EnumeratorList() "}"
[ LOOKAHEAD(2) AttributeSpecList(attributeDecl) ]
{
dt = allocateEnumDT(t, list);
isPacked = attributeDecl.getQualifiers().contains(PACKED);
dt = allocateEnumDT(t, typeDecl, list, isPacked);
}
|
t= <IDENTIFIER>
[ LOOKAHEAD(2) ":" typeDecl= TypeName() ]
[ LOOKAHEAD(2) AttributeSpecList(attributeDecl) ]
{
dt= getEnumDef(t.image);
// not defined yet, define an empty one
if (dt == null) {
dt = allocateEnumDT(t, null);
isPacked = attributeDecl.getQualifiers().contains(PACKED);
dt = allocateEnumDT(t, typeDecl, null, isPacked);
}
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,69 @@ public void testHeaderParsing() throws Exception {
((Enum) dt).getValue("SHIFTED3"));
assertEquals("enum options_enum not correct", 15 >> 3 << 3,
((Enum) dt).getValue("SHIFTED4"));

dt = dtMgr.getDataType(new CategoryPath("/"), "_C23_enum_char");
assertTrue(dt instanceof Enum);
assertEquals("enum _C23_enum_char size not correct", 1, dt.getLength());
dt = dtMgr.getDataType(new CategoryPath("/"), "_C23_enum_short");
assertTrue(dt instanceof Enum);
assertEquals("enum _C23_enum_short size not correct", 2, dt.getLength());
dt = dtMgr.getDataType(new CategoryPath("/"), "_C23_enum_int");
assertTrue(dt instanceof Enum);
assertEquals("enum _C23_enum_int size not correct", 4, dt.getLength());
dt = dtMgr.getDataType(new CategoryPath("/"), "_C23_enum_long");
assertTrue(dt instanceof Enum);
assertEquals("enum _C23_enum_long size not correct", 4, dt.getLength());
dt = dtMgr.getDataType(new CategoryPath("/"), "_C23_enum_longlong");
assertTrue(dt instanceof Enum);
assertEquals("enum _C23_enum_longlong size not correct", 8, dt.getLength());
dt = dtMgr.getDataType(new CategoryPath("/"), "_C23_enum_DWORD");
assertTrue(dt instanceof Enum);
assertEquals("enum _C23_enum_DWORD size not correct", 4, dt.getLength());

dt = dtMgr.getDataType(new CategoryPath("/"), "packed_enum_style_1");
assertTrue(dt instanceof Enum);
assertEquals("enum packed_enum_style_1 size not correct", 1, dt.getLength());

dt = dtMgr.getDataType(new CategoryPath("/"), "packed_enum_style_2");
assertTrue(dt instanceof Enum);
assertEquals("enum packed_enum_style_2 size not correct", 1, dt.getLength());

dt = dtMgr.getDataType(new CategoryPath("/"), "packed_enum_cpp_style_1");
assertTrue(dt instanceof Enum);
assertEquals("enum packed_enum_cpp_style_1 size not correct", 1, dt.getLength());

dt = dtMgr.getDataType(new CategoryPath("/"), "packed_enum_cpp_style_2");
assertTrue(dt instanceof Enum);
assertEquals("enum packed_enum_cpp_style_2 size not correct", 1, dt.getLength());

dt = dtMgr.getDataType(new CategoryPath("/"), "packed_enum_cpp_style_gnu");
assertTrue(dt instanceof Enum);
assertEquals("enum packed_enum_cpp_style_gnu size not correct", 1, dt.getLength());

dt = dtMgr.getDataType(new CategoryPath("/"), "non_packed_enum");
assertTrue(dt instanceof Enum);
assertEquals("enum non_packed_enum size not correct", 4, dt.getLength());

dt = dtMgr.getDataType(new CategoryPath("/"), "packed_negative_enum");
assertTrue(dt instanceof Enum);
assertEquals("enum packed_negative_enum size not correct", 1, dt.getLength());
assertEquals("enum packed_negative_enum value not correct", -1,
((Enum) dt).getValue("A"));
assertEquals("enum packed_negative_enum value not correct", -2,
((Enum) dt).getValue("B"));
assertEquals("enum packed_negative_enum value not correct", -3,
((Enum) dt).getValue("C"));

dt = dtMgr.getDataType(new CategoryPath("/"), "normal_negative_enum");
assertTrue(dt instanceof Enum);
assertEquals("enum normal_negative_enum size not correct", 4, dt.getLength());
assertEquals("enum normal_negative_enum value not correct", -1,
((Enum) dt).getValue("A"));
assertEquals("enum normal_negative_enum value not correct", -2,
((Enum) dt).getValue("B"));
assertEquals("enum normal_negative_enum value not correct", -3,
((Enum) dt).getValue("C"));

dt = dtMgr.getDataType(new CategoryPath("/functions"), "__checkint");
assertTrue("not a function", dt instanceof FunctionDefinition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,89 @@ typedef int FuncUseEnum(PARAM_TYPE ptype);
typedef enum _PARAM_TYPE { A, B, C } PARAM_TYPE;


/**
** C23 enum types
**/
enum _C23_enum_char: char {
A = 1,
B = 2,
C = 3
};
enum _C23_enum_short : short
{
A = 1,
B = 2,
C = 3
};
enum _C23_enum_int : int
{
A = 1,
B = 2,
C = 3
};
enum _C23_enum_long : long
{
A = 1,
B = 2,
C = 3
};
enum _C23_enum_longlong : long long
{
A = 1,
B = 2,
C = 3
};
enum _C23_enum_DWORD : DWORD {
A = 1,
B = 2,
C = 3
};


/**
** Packed enums
**/
enum packed_enum_style_1 {
A = 1,
B = 2,
C = 3
} __attribute__((__packed__));
enum __attribute__((__packed__)) packed_enum_style_2 {
A = 1,
B = 2,
C = 3
};
enum [[packed]] packed_enum_cpp_style_1 {
A = 1,
B = 2,
C = 3
};
enum packed_enum_cpp_style_2 {
A = 1,
B = 2,
C = 3
} [[packed]];
enum [[gnu::packed]] packed_enum_cpp_style_gnu {
A = 1,
B = 2,
C = 3
};
enum non_packed_enum {
D = 4,
E = 5,
F = 6
};
enum packed_negative_enum {
A = -1,
B = -2,
C = -3
} __attribute__((__packed__));
enum normal_negative_enum {
A = -1,
B = -2,
C = -3
};

/**
** Casting
**/
Expand Down