diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangStringAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangStringAnalyzer.java index c5f32b2978..567645c350 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangStringAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangStringAnalyzer.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java index 9183484726..014dbf8ce8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java @@ -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> regs, int[] nextReg, GoRegisterInfo callspecInfo, long stackOffset, boolean isBigEndian, String archDescription) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java index 19f8ab1d25..236a75025f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java @@ -414,7 +414,7 @@ public class GoModuledata implements StructureMarkup { */ /* 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()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java index 4336119bf1..a33ad837a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java @@ -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); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoTypeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoTypeManager.java index 21345321f7..df05ea1c69 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoTypeManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoTypeManager.java @@ -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 paramDataTypes = new ArrayList<>(); + List 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) {