mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-19 22:51:51 +08:00
GP-6645 fix NPE in apisnapshot funcdef creation, chan types, xml
Replace missing types in a funcdef's return with an empty stub struct. Handle chan types better. Don't re-read the golang register info xml file every time a function is fixed. Fix macho go1.26 failure to find the first moduledata.
This commit is contained in:
+13
-3
@@ -302,10 +302,14 @@ public class GolangStringAnalyzer extends AbstractAnalyzer {
|
||||
throws IOException, CancelledException {
|
||||
// test to see if its a slice first because strings can kinda look like slices (a pointer
|
||||
// then a length field).
|
||||
boolean isUndefined3x =
|
||||
DataUtilities.isUndefinedRange(program, addr, addr.add(sliceStructLen));
|
||||
boolean isDefPtr = isDefaultPointer(addr);
|
||||
boolean isUndefined3x = (isDefPtr && DataUtilities.isUndefinedRange(program,
|
||||
addr.add(goBinary.getPtrSize()), addr.add(sliceStructLen - 1))) ||
|
||||
DataUtilities.isUndefinedRange(program, addr, addr.add(sliceStructLen - 1));
|
||||
boolean isUndefined2x = isUndefined3x ||
|
||||
DataUtilities.isUndefinedRange(program, addr, addr.add(stringStructLen));
|
||||
(isDefPtr && DataUtilities.isUndefinedRange(program,
|
||||
addr.add(goBinary.getPtrSize()), addr.add(stringStructLen - 1))) ||
|
||||
DataUtilities.isUndefinedRange(program, addr, addr.add(stringStructLen - 1));
|
||||
|
||||
Object newObj = isUndefined3x ? tryReadSliceStruct(addr) : null;
|
||||
if (newObj == null && isUndefined2x) {
|
||||
@@ -323,6 +327,12 @@ public class GolangStringAnalyzer extends AbstractAnalyzer {
|
||||
return newObj;
|
||||
}
|
||||
|
||||
private boolean isDefaultPointer(Address addr) {
|
||||
Data data = program.getListing().getDataAt(addr);
|
||||
return data != null && data.getDataType() instanceof DataType dt &&
|
||||
((dt instanceof Pointer ptr && ptr.getDataType() == null) || Undefined.isUndefined(dt));
|
||||
}
|
||||
|
||||
private GoString tryReadStringStruct(AddressSetView stringDataRange, Address addr) {
|
||||
try {
|
||||
GoString goString = goBinary.readStructure(GoString.class, addr);
|
||||
|
||||
+12
@@ -61,6 +61,18 @@ public class GoParamStorageAllocator {
|
||||
lang.getLanguageDescription().getSize());
|
||||
}
|
||||
|
||||
public GoParamStorageAllocator(GoRegisterInfo callspecInfo, Program program) {
|
||||
Language lang = program.getLanguage();
|
||||
|
||||
this.callspecInfo = callspecInfo;
|
||||
this.stackOffset = callspecInfo.getStackInitialOffset();
|
||||
this.regs = List.of(callspecInfo.getIntRegisters(), callspecInfo.getFloatRegisters());
|
||||
this.isBigEndian = lang.isBigEndian();
|
||||
this.archDescription =
|
||||
"%s_%d".formatted(lang.getLanguageDescription().getProcessor().toString(),
|
||||
lang.getLanguageDescription().getSize());
|
||||
}
|
||||
|
||||
private GoParamStorageAllocator(List<List<Register>> regs, int[] nextReg,
|
||||
GoRegisterInfo callspecInfo, long stackOffset, boolean isBigEndian,
|
||||
String archDescription) {
|
||||
|
||||
+1
-1
@@ -414,7 +414,7 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
||||
*/
|
||||
/* package */ static GoModuledata getFirstModuledata(GoRttiMapper context) throws IOException {
|
||||
Program program = context.getProgram();
|
||||
MemoryBlock memblk = context.getGoSection("go.module");
|
||||
MemoryBlock memblk = context.getFirstGoSection("go.module", "go_module");
|
||||
if (memblk != null) {
|
||||
return context.readStructure(GoModuledata.class, memblk.getStart());
|
||||
}
|
||||
|
||||
+13
-4
@@ -236,8 +236,8 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MemoryBlock getFirstGoSection(Program program, String... blockNames) {
|
||||
for (String blockToSearch : blockNames) {
|
||||
public static MemoryBlock getFirstGoSection(Program program, String... sectionNames) {
|
||||
for (String blockToSearch : sectionNames) {
|
||||
MemoryBlock memBlock = getGoSection(program, blockToSearch);
|
||||
if (memBlock != null) {
|
||||
return memBlock;
|
||||
@@ -522,7 +522,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||
* {@return new {@link GoParamStorageAllocator} param storage allocator instance}
|
||||
*/
|
||||
public GoParamStorageAllocator newStorageAllocator() {
|
||||
GoParamStorageAllocator storageAllocator = new GoParamStorageAllocator(program, goVer);
|
||||
GoParamStorageAllocator storageAllocator = new GoParamStorageAllocator(regInfo, program);
|
||||
return storageAllocator;
|
||||
}
|
||||
|
||||
@@ -709,7 +709,12 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||
GoFuncDef snapshotFuncdef =
|
||||
apiSnapshot.getFuncdef(symbolName.getStrippedSymbolString());
|
||||
if (snapshotFuncdef != null) {
|
||||
return createFuncDefFromApiSnapshot(symbolName, recvType, snapshotFuncdef);
|
||||
try {
|
||||
return createFuncDefFromApiSnapshot(symbolName, recvType, snapshotFuncdef);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// fail, fall thru to catch-all at bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1197,4 +1202,8 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||
public MemoryBlock getGoSection(String sectionName) {
|
||||
return getGoSection(program, sectionName);
|
||||
}
|
||||
|
||||
public MemoryBlock getFirstGoSection(String... sectionNames) {
|
||||
return getFirstGoSection(program, sectionNames);
|
||||
}
|
||||
}
|
||||
|
||||
+54
-8
@@ -53,6 +53,14 @@ public class GoTypeManager {
|
||||
")" + // group=1
|
||||
"(.*)" // everything else, group=2
|
||||
);
|
||||
|
||||
private static final Pattern CHAN_TYPENAME_REGEX = Pattern.compile(
|
||||
"(<-)?" + // maybe <-
|
||||
"chan" + // 'chan'
|
||||
"(<-)?" + // maybe <-
|
||||
" " + // mandatory ' '
|
||||
"(.+)" // everything else, group 3
|
||||
);
|
||||
//@formatter:on
|
||||
|
||||
static class TypeRec {
|
||||
@@ -194,8 +202,7 @@ public class GoTypeManager {
|
||||
long gapStart = t1.end;
|
||||
while (t2.start - gapStart > typeStructMinSize) {
|
||||
GoType goType = readTypeUnchecked(gapStart);
|
||||
if (goType == null ||
|
||||
!(goType instanceof GoStructType && goType.getSymbolName().isAnonType())) {
|
||||
if (goType == null) {
|
||||
gapStart += typeStructAlign;
|
||||
continue;
|
||||
}
|
||||
@@ -440,6 +447,9 @@ public class GoTypeManager {
|
||||
else if (typeName.startsWith("map[")) { // not handled by splitTypeName()
|
||||
result = newTypeRecFromDT(typeName, createSpecializedMapDT(typeName));
|
||||
}
|
||||
else if (CHAN_TYPENAME_REGEX.matcher(typeName) instanceof Matcher m && m.matches()) {
|
||||
result = newTypeRecFromDT(typeName, createSpecializedChanDT(typeName, m.group(3)));
|
||||
}
|
||||
else {
|
||||
GoKind primitiveTypeKind = GoKind.parseTypename(typeName);
|
||||
GoTypeDef typeDef;
|
||||
@@ -475,6 +485,8 @@ public class GoTypeManager {
|
||||
return convertStructDef(typeName, struct);
|
||||
case GoFuncTypeDef func:
|
||||
return convertFuncDef(typeName, func);
|
||||
case GoInterfaceDef iface:
|
||||
return convertIfaceDef(typeName, iface);
|
||||
default:
|
||||
throw new IOException("Go unhandled type definition: " + typeDef.toString());
|
||||
}
|
||||
@@ -512,11 +524,15 @@ public class GoTypeManager {
|
||||
returnDT = findDataType(func.Results.get(0).DataType);
|
||||
}
|
||||
else {
|
||||
List<DataType> paramDataTypes = new ArrayList<>();
|
||||
List<DataType> returnDataTypes = new ArrayList<>();
|
||||
for (GoNameTypePair outParam : func.Results) {
|
||||
paramDataTypes.add(findDataType(outParam.DataType));
|
||||
DataType dt = findDataType(outParam.DataType);
|
||||
if (dt == null) {
|
||||
dt = new StructureDataType(cp, ".missing_" + outParam.DataType, 0);
|
||||
}
|
||||
returnDataTypes.add(dt);
|
||||
}
|
||||
returnDT = getFuncMultiReturn(paramDataTypes);
|
||||
returnDT = getFuncMultiReturn(returnDataTypes);
|
||||
}
|
||||
|
||||
funcDef.setArguments(params.toArray(ParameterDefinition[]::new));
|
||||
@@ -525,6 +541,21 @@ public class GoTypeManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
private TypeRec convertIfaceDef(GoSymbolName typeName, GoInterfaceDef iface)
|
||||
throws IOException {
|
||||
TypeRec baseIface = findTypeRec("interface {}");
|
||||
if (baseIface == null) {
|
||||
throw new IOException("Missing type info for base interface {}");
|
||||
}
|
||||
String name = typeName.asString();
|
||||
if (baseIface.name.equals(name)) {
|
||||
return baseIface;
|
||||
}
|
||||
CategoryPath cp = getCP(typeName);
|
||||
TypeDef td = new TypedefDataType(cp, name, baseIface.recoveredDT);
|
||||
return newTypeRecFromDT(name, td);
|
||||
}
|
||||
|
||||
private TypeRec convertBasicDef(GoSymbolName typeName, GoBasicDef basicDef) throws IOException {
|
||||
GoKind kind = GoKind.parseTypename(basicDef.DataType);
|
||||
if (kind == null) {
|
||||
@@ -581,6 +612,7 @@ public class GoTypeManager {
|
||||
GoNameTypePair field = structDef.Fields.get(i);
|
||||
DataType dtcDT = findDataType(field.DataType);
|
||||
if (dtcDT == null) {
|
||||
dtcDT = findDataType(field.DataType);
|
||||
throw new IOException("Failed to get type for field [%d %s: %s] in %s"
|
||||
.formatted(i, field.Name, field.DataType, typeName));
|
||||
}
|
||||
@@ -879,6 +911,21 @@ public class GoTypeManager {
|
||||
return voidPtrDT;
|
||||
}
|
||||
|
||||
public DataType createSpecializedChanDT(String fullChanTypeName, String elementTypeName) {
|
||||
try {
|
||||
Structure hchanStruct = findDataType("runtime.hchan", Structure.class);
|
||||
if (hchanStruct != null) {
|
||||
GoSymbolName typeSymbolName = GoSymbolName.parseTypeName(elementTypeName);
|
||||
return new TypedefDataType(getCP(typeSymbolName), fullChanTypeName,
|
||||
dtm.getPointer(hchanStruct), dtm);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// fall thru
|
||||
}
|
||||
return voidPtrDT;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return data type that represents a generic Go slice}
|
||||
* @throws IOException
|
||||
@@ -1076,7 +1123,7 @@ public class GoTypeManager {
|
||||
}
|
||||
throw new IOException("Unknown type prefix: " + name);
|
||||
}
|
||||
else if (name.startsWith("map[") || name.startsWith("chan ")) {
|
||||
else if (name.startsWith("map[") || CHAN_TYPENAME_REGEX.matcher(name).matches()) {
|
||||
return new LengthAlignment(ptrSize, align(ptrSize));
|
||||
}
|
||||
else {
|
||||
@@ -1112,8 +1159,7 @@ public class GoTypeManager {
|
||||
return new LengthAlignment(ptrSize * 2, align(ptrSize));
|
||||
}
|
||||
|
||||
private LengthAlignment getDataTypeLength(GoStructDef structDef)
|
||||
throws IOException {
|
||||
private LengthAlignment getDataTypeLength(GoStructDef structDef) throws IOException {
|
||||
int len = 0;
|
||||
int align = 1;
|
||||
for (GoNameTypePair field : structDef.Fields) {
|
||||
|
||||
Reference in New Issue
Block a user