ghidra
ghidra copied to clipboard
ExportToHeaderAction: pointer to array has incorrect type
Describe the bug
When I export my types to a C header file using the ExportToHeaderAction
, fields in structs that are pointers to arrays will get an incorrect declaration in the header file.
To Reproduce Steps to reproduce the behavior:
- Make a struct having one field with the type
int[12]*
. Like so: - Export the type to a C header by right clicking the type in the Data Type Manager and clicking "Export C Header...".
- The result will look like this:
typedef unsigned char undefined;
typedef unsigned char byte;
typedef unsigned char dwfenc;
typedef unsigned int dword;
typedef unsigned long qword;
typedef unsigned int undefined4;
typedef unsigned long undefined8;
typedef unsigned short word;
typedef struct structA structA, *PstructA;
struct structA {
int[12] * something;
};
When I try to compile it using gcc
, it's not happy about the something
field.
Expected behavior
From what I've found online, structA
should instead look like this:
struct structA {
int (*something)[12];
};
Environment:
- Ghidra Version: 10.2.3
Similarly to my other issue #5240 , the decompiler view and export seems to handle this well:
My current workaround is to make a copy of Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeWriter.java
and change getTypeDeclaration
:
private String getTypeDeclaration(/* ... */){
// ...
if (componentString == null) {
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
name += ":" + bfDt.getDeclaredBitSize();
dataType = bfDt.getBaseDataType();
} else if (dataType instanceof Array) {
Array array = (Array) dataType;
name += getArrayDimensions(array);
dataType = getArrayBaseType(array);
} else if (dataType instanceof Pointer pointer) { // <-- Added this else if and its body
DataType element = getPointerBaseDataType(pointer);
if (element != null) {
name = "*" + name;
dataType = element;
if (dataType instanceof Array array) {
name = "(" + name + ")" + getArrayDimensions(array);
dataType = getArrayBaseType(array);
}
}
}
// ...
}
// ...
}
EDIT: This "workaround" was incorrect, I rewrote the code to something else that worked later.
EDIT: This "workaround" was incorrect, I rewrote the code to something else that worked later.
@mattiasgrenfeldt Apologies for taking so long to get to this, but I'm preparing to address it. I'm curious if you'd like to share your final solution.
I assume you added some support for pointers to pointers to pointers, for example:
struct structA {
int (*****something)[12];
};
Hello Ryan! Sorry for not answering earlier, but here is what I changed in getTypeDeclaration
:
if (componentString == null) {
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
name += ":" + bfDt.getDeclaredBitSize();
dataType = bfDt.getBaseDataType();
}
// Remove the else ifs and add a while
while (true) {
if (dataType instanceof Array array) {
name += "[" + array.getNumElements() + "]";
dataType = array.getDataType();
} else if (dataType instanceof Pointer pointer) {
DataType elem = pointer.getDataType();
if (elem == null) {
break;
}
name = "*" + name;
dataType = elem;
if (dataType instanceof Array) {
name = "(" + name + ")";
}
} else {
break;
}
}
// End of modification
DataType baseDataType = getBaseDataType(dataType);
if (baseDataType instanceof FunctionDefinition) {
componentString = getFunctionPointerString((FunctionDefinition) baseDataType, name,
dataType, writeEnabled, monitor);
} else {
componentString = getDataTypePrefix(dataType) + cleanIdentifier(dataType.getDisplayName());
if (name.length() != 0) {
componentString += " " + name;
}
}
sb.append(componentString);
}
Because it might not just be pointers in series, there might be any combination of pointer to array of pointers to arrays, etc. Example
struct structA {
int (*(*****something)[12])[2][3];
};
@mattiasgrenfeldt, thanks, i've tested this and will go with your final implementation.