mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-29 07:55:53 +08: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) {
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
||||
@@ -1211,7 +1230,7 @@ TOKEN :
|
||||
|
|
||||
<UNALIGNED : "__unaligned" >
|
||||
|
|
||||
<PACKED : "__packed" >
|
||||
<PACKED : ("__packed" | "__packed__" | "packed") >
|
||||
|
|
||||
<ATTRIBUTE : "__attribute" (["_"])* >
|
||||
|
|
||||
@@ -1835,7 +1854,7 @@ Declaration TypeQualifier(Declaration dec) : {}
|
||||
<RESTRICT> |
|
||||
<EXTENSION> |
|
||||
<STATIC> |
|
||||
<PACKED> |
|
||||
<PACKED> { dec.addQualifier(PACKED); } |
|
||||
<UNALIGNED> |
|
||||
( DeclSpec(dec) )
|
||||
)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -479,6 +479,69 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
((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);
|
||||
|
||||
@@ -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
|
||||
**/
|
||||
|
||||
Reference in New Issue
Block a user