mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
Add C23 enum types support for C parser
This commit is contained in:
@@ -517,35 +517,54 @@ public class CParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private DataType allocateEnumDT(Token t, ArrayList<EnumMember> list) {
|
private DataType allocateEnumDT(Token t, Declaration underlyingTypeDecl, ArrayList<EnumMember> list, boolean isPacked) {
|
||||||
String enumName = (t != null ? t.image : ("enum_" + cnt++));
|
String enumName = (t != null ? t.image : ("enum_" + cnt++));
|
||||||
|
int defaultSize = (dtMgr != null && dtMgr.getDataOrganization() != null ? dtMgr.getDataOrganization().getIntegerSize() : 4);
|
||||||
// get the normal enum size, which is an int
|
int initialEnumSize = defaultSize;
|
||||||
// TODO: allow for packing of enum to smallest value with either dataOrganization, or packing flag
|
|
||||||
int normalEnumLen = (dtMgr != null ? dtMgr.getDataOrganization().getIntegerSize() : 4);
|
|
||||||
|
|
||||||
// create an initial enum and add all new members
|
if (underlyingTypeDecl != null) {
|
||||||
EnumDataType enumDT= new EnumDataType(getCurrentCategoryPath(), enumName, 8, dtMgr);
|
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) {
|
if (list != null) {
|
||||||
for (EnumMember member : list) {
|
for (EnumMember member : list) {
|
||||||
try {
|
try {
|
||||||
enumDT.add(member.name, member.value);
|
enumDT.add(member.name, member.value);
|
||||||
} catch (IllegalArgumentException exc) {
|
} catch (IllegalArgumentException exc) {
|
||||||
addNearParseMessage("duplicate enum value: " + enumName + " : " + member.name + " : " + member.value);
|
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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// length doesn't really matter, forward declaration with no values
|
|
||||||
enumDT.setLength(normalEnumLen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int minLen = enumDT.getMinimumPossibleLength();
|
||||||
|
int finalEnumLength;
|
||||||
|
if (underlyingTypeDecl == null && isPacked) {
|
||||||
|
finalEnumLength = minLen;
|
||||||
|
} else {
|
||||||
|
finalEnumLength = Math.max(minLen, initialEnumSize);
|
||||||
|
}
|
||||||
|
enumDT.setLength(finalEnumLength);
|
||||||
return addDef(enums, enumDT.getName(), enumDT);
|
return addDef(enums, enumDT.getName(), enumDT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1211,7 +1230,7 @@ TOKEN :
|
|||||||
|
|
|
|
||||||
<UNALIGNED : "__unaligned" >
|
<UNALIGNED : "__unaligned" >
|
||||||
|
|
|
|
||||||
<PACKED : "__packed" >
|
<PACKED : ("__packed" | "__packed__" | "packed") >
|
||||||
|
|
|
|
||||||
<ATTRIBUTE : "__attribute" (["_"])* >
|
<ATTRIBUTE : "__attribute" (["_"])* >
|
||||||
|
|
|
|
||||||
@@ -1835,7 +1854,7 @@ Declaration TypeQualifier(Declaration dec) : {}
|
|||||||
<RESTRICT> |
|
<RESTRICT> |
|
||||||
<EXTENSION> |
|
<EXTENSION> |
|
||||||
<STATIC> |
|
<STATIC> |
|
||||||
<PACKED> |
|
<PACKED> { dec.addQualifier(PACKED); } |
|
||||||
<UNALIGNED> |
|
<UNALIGNED> |
|
||||||
( DeclSpec(dec) )
|
( DeclSpec(dec) )
|
||||||
)
|
)
|
||||||
@@ -2255,23 +2274,33 @@ DataType EnumSpecifier() : {
|
|||||||
Token t= null;
|
Token t= null;
|
||||||
DataType dt;
|
DataType dt;
|
||||||
ArrayList<EnumMember> list;
|
ArrayList<EnumMember> list;
|
||||||
Declaration dec = new Declaration();
|
Declaration attributeDecl = new Declaration();
|
||||||
|
Declaration typeDecl = null;
|
||||||
|
boolean isPacked = false;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
<ENUM>
|
<ENUM>
|
||||||
|
[ LOOKAHEAD(2) AttributeSpecList(attributeDecl) ]
|
||||||
(
|
(
|
||||||
LOOKAHEAD(3)
|
LOOKAHEAD(4)
|
||||||
[AttributeSpecList(dec)] [ t= <IDENTIFIER> ] "{" list= EnumeratorList() "}"
|
[ 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>
|
t= <IDENTIFIER>
|
||||||
|
[ LOOKAHEAD(2) ":" typeDecl= TypeName() ]
|
||||||
|
[ LOOKAHEAD(2) AttributeSpecList(attributeDecl) ]
|
||||||
{
|
{
|
||||||
dt= getEnumDef(t.image);
|
dt= getEnumDef(t.image);
|
||||||
// not defined yet, define an empty one
|
// not defined yet, define an empty one
|
||||||
if (dt == null) {
|
if (dt == null) {
|
||||||
dt = allocateEnumDT(t, null);
|
isPacked = attributeDecl.getQualifiers().contains(PACKED);
|
||||||
|
dt = allocateEnumDT(t, typeDecl, null, isPacked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -479,6 +479,69 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||||||
((Enum) dt).getValue("SHIFTED3"));
|
((Enum) dt).getValue("SHIFTED3"));
|
||||||
assertEquals("enum options_enum not correct", 15 >> 3 << 3,
|
assertEquals("enum options_enum not correct", 15 >> 3 << 3,
|
||||||
((Enum) dt).getValue("SHIFTED4"));
|
((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");
|
dt = dtMgr.getDataType(new CategoryPath("/functions"), "__checkint");
|
||||||
assertTrue("not a function", dt instanceof FunctionDefinition);
|
assertTrue("not a function", dt instanceof FunctionDefinition);
|
||||||
|
|||||||
@@ -958,6 +958,89 @@ typedef int FuncUseEnum(PARAM_TYPE ptype);
|
|||||||
typedef enum _PARAM_TYPE { A, B, C } PARAM_TYPE;
|
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
|
** Casting
|
||||||
**/
|
**/
|
||||||
|
|||||||
Reference in New Issue
Block a user