diff --git a/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java b/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java index 540c10f730..433649621e 100644 --- a/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java @@ -27,7 +27,7 @@ import ghidra.app.util.bin.format.dwarf.line.DWARFLine.SourceFileAddr; import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProvider; import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProviderFactory; import ghidra.program.model.address.Address; -import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.listing.CommentType; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; @@ -63,7 +63,7 @@ public class DWARFLineInfoCommentScript extends GhidraScript { List allSFA = cu.getLine().getAllSourceFileAddrInfo(cu, reader); for (SourceFileAddr sfa : allSFA) { Address addr = dprog.getCodeAddress(sfa.address()); - DWARFUtil.appendComment(currentProgram, addr, CodeUnit.EOL_COMMENT, "", + DWARFUtil.appendComment(currentProgram, addr, CommentType.EOL, "", "%s:%d".formatted(sfa.fileName(), sfa.lineNum()), ";"); count++; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java index fe1462b01a..c5f80772b5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java @@ -302,13 +302,8 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { functionSignatureFromMethod++; } - GoParamStorageAllocator storageAllocator = goBinary.newStorageAllocator(); - - boolean regAbi = !storageAllocator.isAbi0Mode() && !goBinary.isGolangAbi0Func(func); - String ccName = regAbi ? abiIntCCName : null; - - GoFunctionFixup ff = - new GoFunctionFixup(func, funcDefResult.funcDef(), ccName, storageAllocator); + GoFunctionFixup ff = new GoFunctionFixup(func, funcDefResult.funcDef(), + goBinary.getCallingConventionFor(funcdata), goBinary.newStorageAllocator()); try { ff.apply(); @@ -933,7 +928,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { @Override public boolean applyTo(Program program, TaskMonitor monitor) { - if (goBinary.newStorageAllocator().isAbi0Mode()) { + if (!goBinary.getRegInfo().hasAbiInternalParamRegisters()) { // If abi0 mode, don't even bother because currently only handles rtti passed via // register. return true; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java index 01685aef08..b4b7edc978 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java @@ -367,7 +367,7 @@ public class DWARFFunctionImporter { // because this is a zero-length data type (ie. array[0]), // don't create a variable at the location since it will prevent other elements // from occupying the same offset - appendComment(address, CodeUnit.PRE_COMMENT, + appendComment(address, CommentType.PRE, "Zero length variable: %s: %s".formatted(name, dataType.getDisplayName()), "\n"); return; @@ -384,13 +384,13 @@ public class DWARFFunctionImporter { } if (dataType instanceof Dynamic || dataType instanceof FactoryDataType) { - appendComment(address, CodeUnit.EOL_COMMENT, + appendComment(address, CommentType.EOL, "Unsupported dynamic data type: " + dataType, "\n"); dataType = Undefined.getUndefinedDataType(1); } DWARFDataInstanceHelper dih = new DWARFDataInstanceHelper(currentProgram); if (!dih.isDataTypeCompatibleWithAddress(dataType, address)) { - appendComment(address, CodeUnit.EOL_COMMENT, + appendComment(address, CommentType.EOL, "Could not place DWARF static variable %s: %s @%s because existing data type conflicts." .formatted(name, dataType.getName(), address), "\n"); @@ -414,8 +414,7 @@ public class DWARFFunctionImporter { } if (globalVar.sourceInfo != null) { - appendComment(address, CodeUnit.EOL_COMMENT, globalVar.sourceInfo.getDescriptionStr(), - "\n"); + appendComment(address, CommentType.EOL, globalVar.sourceInfo.getDescriptionStr(), "\n"); } } @@ -437,7 +436,7 @@ public class DWARFFunctionImporter { if (importOptions.isOutputLexicalBlockComments()) { boolean disjoint = blockRanges.getListCount() > 1; DWARFName dni = prog.getName(diea); - appendComment(blockStart, CodeUnit.PRE_COMMENT, + appendComment(blockStart, CommentType.PRE, "Begin: %s%s".formatted(dni.getName(), disjoint ? " - Disjoint" : ""), "\n"); } } @@ -471,22 +470,23 @@ public class DWARFFunctionImporter { long inlineFuncLen = range.getLength(); boolean isShort = inlineFuncLen < INLINE_FUNC_SHORT_LEN; if (isShort) { - appendComment(range.getMinAddress(), CodeUnit.EOL_COMMENT, + appendComment(range.getMinAddress(), CommentType.EOL, "inline " + funcDef.getPrototypeString(), "; "); } else { - appendComment(range.getMinAddress(), CodeUnit.PRE_COMMENT, + appendComment(range.getMinAddress(), CommentType.PRE, "Begin: inline " + funcDef.getPrototypeString(), "\n"); } } } - private void appendComment(Address address, int commentType, String comment, String sep) { + private void appendComment(Address address, CommentType commentType, String comment, + String sep) { DWARFUtil.appendComment(currentProgram, address, commentType, "", comment, sep); } private void appendPlateComment(Address address, String prefix, String comment) { - DWARFUtil.appendComment(currentProgram, address, CodeUnit.PLATE_COMMENT, prefix, comment, + DWARFUtil.appendComment(currentProgram, address, CommentType.PLATE, prefix, comment, "\n"); } @@ -572,7 +572,7 @@ public class DWARFFunctionImporter { String locationInfo = DWARFSourceInfo.getDescriptionStr(diea); if (locationInfo != null) { - appendComment(address, CodeUnit.EOL_COMMENT, locationInfo, "; "); + appendComment(address, CommentType.EOL, locationInfo, "; "); } } catch (InvalidInputException e) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java index 2ebf9c515b..21811ccbe9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java @@ -346,7 +346,7 @@ public class DWARFUtil { dtc.setComment(prev + description); } - public static void appendComment(Program program, Address address, int commentType, + public static void appendComment(Program program, Address address, CommentType commentType, String prefix, String comment, String sep) { if (comment == null || comment.isBlank()) { return; @@ -359,7 +359,7 @@ public class DWARFUtil { return; } } - AppendCommentCmd cmd = new AppendCommentCmd(address, commentType, + AppendCommentCmd cmd = new AppendCommentCmd(address, commentType.ordinal(), Objects.requireNonNullElse(prefix, "") + comment, sep); cmd.applyTo(program); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java index 0af993a499..6626756254 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java @@ -28,8 +28,6 @@ import ghidra.program.model.listing.*; import ghidra.program.model.listing.Function.FunctionUpdateType; import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.Symbol; -import ghidra.program.model.symbol.SymbolType; import ghidra.program.model.symbol.SymbolUtilities; import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; @@ -57,7 +55,7 @@ public class GoFunctionFixup { this.newSignature = func.getSignature(); this.newCallingConv = null; - if (isGolangAbi0Func(func)) { + if (GoRttiMapper.isAbi0Func(func.getEntryPoint(), program)) { // Some (typically lower level) functions in the binary will be marked with a // symbol that ends in the string "abi0". // Throw away all registers and force stack allocation for everything @@ -331,20 +329,6 @@ public class GoFunctionFixup { } } - public static boolean isGolangAbi0Func(Function func) { - Address funcAddr = func.getEntryPoint(); - for (Symbol symbol : func.getProgram().getSymbolTable().getSymbolsAsIterator(funcAddr)) { - if (symbol.getSymbolType() == SymbolType.LABEL || - symbol.getSymbolType() == SymbolType.FUNCTION) { - String labelName = symbol.getName(); - if (labelName.endsWith("abi0")) { - return true; - } - } - } - return false; - } - private boolean isInLocalVarStorageArea(long stackOffset) { boolean paramsHavePositiveOffset = program.getCompilerSpec().stackGrowsNegative(); return (paramsHavePositiveOffset && stackOffset < 0) || diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java index 4218bb0a03..8d568f8997 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java @@ -153,17 +153,17 @@ public class GoFunctionMultiReturn { private record StackComponentInfo(DataTypeComponent dtc, int ordinal, String comment) {} - private void regenerateMultireturnStruct(Structure struct, DataTypeManager dtm, + private void regenerateMultireturnStruct(Structure newStruct, DataTypeManager dtm, GoParamStorageAllocator storageAllocator) { - String name = getComponentsInOriginalOrder(struct).stream() + String name = getComponentsInOriginalOrder(newStruct).stream() .map(dtc -> dtc.getDataType().getName()) .collect(Collectors.joining(";", SHORT_MULTIVALUE_RETURNTYPE_PREFIX, SHORT_MULTIVALUE_RETURNTYPE_SUFFIX)); - if (struct.getName().equals(TMP_NAME)) { + if (newStruct.getName().equals(TMP_NAME)) { try { - struct.setName(name); + newStruct.setName(name); } catch (InvalidNameException | DuplicateNameException e) { // should not happen @@ -171,15 +171,15 @@ public class GoFunctionMultiReturn { } if (storageAllocator == null) { - this.struct = struct; - for (DataTypeComponent dtc : getComponentsInOriginalOrder(struct)) { + this.struct = newStruct; + for (DataTypeComponent dtc : getComponentsInOriginalOrder(newStruct)) { stackStorageComponents.add(dtc); } return; } - Structure adjustedStruct = new StructureDataType(struct.getCategoryPath(), + Structure adjustedStruct = new StructureDataType(newStruct.getCategoryPath(), name + "_" + storageAllocator.getArchDescription(), 0, dtm); adjustedStruct.setPackingEnabled(true); adjustedStruct.setExplicitPackingValue(1); @@ -187,7 +187,7 @@ public class GoFunctionMultiReturn { storageAllocator = storageAllocator.clone(); List stackResults = new ArrayList<>(); int compNum = 0; - for (DataTypeComponent dtc : getComponentsInOriginalOrder(struct)) { + for (DataTypeComponent dtc : getComponentsInOriginalOrder(newStruct)) { List regs = storageAllocator.getRegistersFor(dtc.getDataType()); if (regs == null || regs.isEmpty()) { long stackOffset = storageAllocator.getStackAllocation(dtc.getDataType()); @@ -215,8 +215,8 @@ public class GoFunctionMultiReturn { } boolean isEquiv = DWARFDataTypeConflictHandler.INSTANCE.resolveConflict(adjustedStruct, - struct) == ConflictResult.USE_EXISTING; - this.struct = isEquiv ? struct : adjustedStruct; + newStruct) == ConflictResult.USE_EXISTING; + this.struct = isEquiv ? newStruct : adjustedStruct; } private static int getOrdinalNumber(DataTypeComponent dtc) { 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 c9b94cf01b..f1cc33544e 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 @@ -261,12 +261,12 @@ public class GoParamStorageAllocator { return false; } if (dt instanceof Structure struct) { - DataTypeComponent prevDTC = null; +// DataTypeComponent prevDTC = null; for (DataTypeComponent dtc : struct.getDefinedComponents()) { - int padding = prevDTC != null ? dtc.getOffset() - prevDTC.getOffset() : 0; - if (padding != 0) { - - } +// int padding = prevDTC != null ? dtc.getOffset() - prevDTC.getOffset() : 0; +// if (padding != 0) { +// +// } if (!countRegistersFor(dtc.getDataType(), result)) { return false; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java index 782b66c4fa..4d8a965566 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java @@ -107,6 +107,10 @@ public class GoRegisterInfo { return stackInitialOffset; } + public boolean hasAbiInternalParamRegisters() { + return !intRegisters.isEmpty() || !floatRegisters.isEmpty(); + } + public List getDuffzeroParams(Program program) { if (duffzeroDestParam == null) { return List.of(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java index d1d1f0217e..354ad7e0a8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java @@ -17,13 +17,9 @@ package ghidra.app.util.bin.format.golang; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.JDOMException; +import org.jdom.*; import org.jdom.input.SAXBuilder; import generic.jar.ResourceFile; @@ -143,7 +139,6 @@ public class GoRegisterInfoManager { Element zeroRegElem = regInfoElem.getChild("zero_register"); Element duffZeroElem = regInfoElem.getChild("duffzero"); Element closureContextElem = regInfoElem.getChild("closurecontext"); - Element gcWriteBarrierElem = regInfoElem.getChild("gcwritebarrier"); if (intRegsElem == null || floatRegsElem == null || stackElem == null || goRoutineElem == null || zeroRegElem == null || duffZeroElem == null || closureContextElem == null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java index fb9a247e39..55c1194b07 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java @@ -15,32 +15,17 @@ */ package ghidra.app.util.bin.format.golang; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; -import ghidra.app.util.bin.format.dwarf.DIEAggregate; -import ghidra.app.util.bin.format.dwarf.DWARFException; -import ghidra.app.util.bin.format.dwarf.DWARFFunction; +import ghidra.app.util.bin.format.dwarf.*; import ghidra.app.util.bin.format.dwarf.DWARFFunction.CommitMode; -import ghidra.app.util.bin.format.dwarf.DWARFSourceLanguage; -import ghidra.app.util.bin.format.dwarf.DWARFUtil; -import ghidra.app.util.bin.format.dwarf.DWARFVariable; import ghidra.app.util.bin.format.dwarf.funcfixup.DWARFFunctionFixup; import ghidra.app.util.bin.format.golang.rtti.GoFuncData; import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper; import ghidra.program.model.address.Address; -import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.data.DataTypeManager; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.VoidDataType; +import ghidra.program.model.data.*; import ghidra.program.model.lang.Register; -import ghidra.program.model.listing.CodeUnit; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.Program; +import ghidra.program.model.listing.*; import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.SymbolType; import ghidra.util.classfinder.ExtensionPointProperties; @@ -301,7 +286,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup { } private void appendComment(Function func, String prefix, String comment) { - DWARFUtil.appendComment(goBinary.getProgram(), func.getEntryPoint(), CodeUnit.PLATE_COMMENT, + DWARFUtil.appendComment(goBinary.getProgram(), func.getEntryPoint(), CommentType.PLATE, prefix, comment, "\n"); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangElfInfoProducer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangElfInfoProducer.java index 301cc30800..36152c057a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangElfInfoProducer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangElfInfoProducer.java @@ -49,8 +49,8 @@ public class GolangElfInfoProducer implements ElfInfoProducer { private ElfLoadHelper elfLoadHelper; @Override - public void init(ElfLoadHelper elfLoadHelper) { - this.elfLoadHelper = elfLoadHelper; + public void init(ElfLoadHelper newElfLoadHelper) { + this.elfLoadHelper = newElfLoadHelper; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoItab.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoItab.java index 0449c31287..601bf4812a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoItab.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoItab.java @@ -19,10 +19,8 @@ import java.io.IOException; import java.util.*; import java.util.Map.Entry; -import ghidra.app.util.bin.format.golang.rtti.types.GoIMethod; +import ghidra.app.util.bin.format.golang.rtti.types.*; import ghidra.app.util.bin.format.golang.rtti.types.GoIMethod.GoIMethodInfo; -import ghidra.app.util.bin.format.golang.rtti.types.GoInterfaceType; -import ghidra.app.util.bin.format.golang.rtti.types.GoType; import ghidra.app.util.bin.format.golang.structmapping.*; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataType; @@ -167,6 +165,9 @@ public class GoItab implements StructureMarkup { @Override public void additionalMarkup(MarkupSession session) throws IOException { + // TODO: would be nice if we could override the base structure data type used to markup + // ourself, and use a specialized itab (as created by the GoInterfaceType). + GoSlice funSlice = getFunSlice(); List
funcAddrs = Arrays.stream(funSlice.readUIntList(programContext.getPtrSize())) .mapToObj(offset -> programContext.getCodeAddress(offset)) @@ -200,5 +201,21 @@ public class GoItab implements StructureMarkup { } } + public void discoverGoTypes(Set discoveredTypes) { + try { + GoInterfaceType ifaceType = getInterfaceType(); + if (ifaceType != null) { + ifaceType.discoverGoTypes(discoveredTypes); + } + GoType type = getType(); + if (type != null) { + type.discoverGoTypes(discoveredTypes); + } + } + catch (IOException e) { + // fail, don't discover the ref'd types + } + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoPcHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoPcHeader.java index 90160e0896..20103fa8b5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoPcHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoPcHeader.java @@ -205,7 +205,7 @@ public class GoPcHeader { /** * Returns true if this pcln structure contains a textStart value (only present >= 1.18) - * @return + * @return boolean true if struct has textstart value */ public boolean hasTextStart() { return textStart != 0; 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 7e6c25b3ed..29cb5be03b 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 @@ -153,6 +153,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex * Creates a {@link GoRttiMapper} representing the specified program. * * @param program {@link Program} + * @param monitor {@link TaskMonitor} * @return new {@link GoRttiMapper}, or null if basic golang information is not found in the * binary * @throws BootstrapInfoException if it is a golang binary and has an unsupported or @@ -359,6 +360,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex private final GoVer goVer; private final int ptrSize; private final GoRegisterInfo regInfo; + private final String defaultCCName; private final List modules = new ArrayList<>(); private Map funcdataByAddr = new HashMap<>(); private Map funcdataByName = new HashMap<>(); @@ -376,6 +378,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex * @param goVer version of go * @param archiveGDT path to the matching golang bootstrap gdt data type file, or null * if not present and types recovered via DWARF should be used instead + * @param apiSnapshot json func signatures and data types * @throws IOException if error linking a structure mapped structure to its matching * ghidra structure, which is a programming error or a corrupted bootstrap gdt * @throws BootstrapInfoException if there is no matching bootstrap gdt for this specific @@ -393,6 +396,10 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex this.buildInfo = buildInfo; this.goVer = goVer; this.ptrSize = ptrSize; + this.defaultCCName = regInfo.hasAbiInternalParamRegisters() && + hasCallingConvention(GOLANG_ABI_INTERNAL_CALLINGCONVENTION_NAME) + ? GOLANG_ABI_INTERNAL_CALLINGCONVENTION_NAME + : null; reader = super.createProgramReader(); @@ -598,8 +605,11 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex * @return boolean true if function uses abi0 calling convention */ public boolean isGolangAbi0Func(Function func) { - Address funcAddr = func.getEntryPoint(); - for (Symbol symbol : func.getProgram().getSymbolTable().getSymbolsAsIterator(funcAddr)) { + return isAbi0Func(func.getEntryPoint(), program); + } + + public static boolean isAbi0Func(Address funcEntry, Program program) { + for (Symbol symbol : program.getSymbolTable().getSymbolsAsIterator(funcEntry)) { if (symbol.getSymbolType() == SymbolType.LABEL) { String labelName = symbol.getName(); if (labelName.endsWith("abi0")) { @@ -610,6 +620,14 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex return false; } + public String getCallingConventionFor(GoFuncData func) { + // TODO: this logic needs work. Currently we are not strongly declaring functions + // as abi0. + return defaultCCName != null && !isAbi0Func(func.getFuncAddress(), program) + ? defaultCCName + : null; + } + /** * Returns true if the specified calling convention is defined for the program. * @param ccName calling convention name @@ -619,6 +637,10 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex return program.getFunctionManager().getCallingConvention(ccName) != null; } + public String getDefaultCallingConventionName() { + return defaultCCName; + } + @Override public MarkupSession createMarkupSession(TaskMonitor monitor) { UnknownProgressWrappingTaskMonitor upwtm = new UnknownProgressWrappingTaskMonitor(monitor); @@ -869,7 +891,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex FROM_ANALYSIS, CLOSURE, METHOD_WRAPPER - }; + } public record FuncDefResult(FunctionDefinition funcDef, GoType recvType, Set flags, String funcDefStr, GoSymbolName symbolName) { @@ -878,7 +900,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex /** * Returns function definition information for a func. * - * @param funcData + * @param funcData {@link GoFuncData} representing a go func * @return {@link FuncDefResult} record, or null if no information could be found or * generated * @throws IOException if error reading type info diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSymbolName.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSymbolName.java index 536a0d7cec..df451bc1dc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSymbolName.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSymbolName.java @@ -121,7 +121,7 @@ public record GoSymbolName(String symbolName, String packagePath, String package return result != null ? result : new GoSymbolName(s); } - public static GoSymbolName _parse(String s) { + private static GoSymbolName _parse(String s) { if (s.startsWith("go:")) { // don't try to parse "go:...." symbols return null; @@ -451,9 +451,9 @@ public record GoSymbolName(String symbolName, String packagePath, String package *

* Nesting is delimited by '(', '{', '[' chars and their matching closing element. * - * @param s - * @param splitChar - * @return + * @param s string to split + * @param splitChar char to split the string on + * @return list of strings that are each part of the original string */ private static List splitNestedStringOn(String s, char splitChar) { // TODO: may also have to skip chars in quoted field comments 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 1d1627c758..2155d3cec4 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 @@ -74,7 +74,7 @@ public class GoTypeManager { private DataType int32DT; private DataType uint32DT; private DataType uint8DT; - private DataType stringDT; + private DataType voidPtrDT; public GoTypeManager(GoRttiMapper goBinary, GoApiSnapshot apiSnapshot) { this.goBinary = goBinary; @@ -89,6 +89,7 @@ public class GoTypeManager { * @throws IOException if error reading data or cancelled */ public void init(TaskMonitor monitor) throws IOException { + this.voidPtrDT = dtm.getPointer(VoidDataType.dataType); this.uintptrDT = goBinary.getTypeOrDefault("uintptr", DataType.class, AbstractIntegerDataType.getUnsignedDataType(goBinary.getPtrSize(), dtm)); this.uintDT = goBinary.getTypeOrDefault("uint", DataType.class, @@ -100,7 +101,6 @@ public class GoTypeManager { AbstractIntegerDataType.getUnsignedDataType(4, null)); this.uint8DT = goBinary.getTypeOrDefault("uint8", DataType.class, AbstractIntegerDataType.getUnsignedDataType(1, null)); - this.stringDT = goBinary.getTypeOrDefault("string", Structure.class, null); this.genericDictDT = dtm.getPointer(dtm.getPointer(uintptrDT)); @@ -141,9 +141,13 @@ public class GoTypeManager { rec.interfaces = new ArrayList<>(); } rec.interfaces.add(itab); + TypeRec ifaceRec = getTypeRec(itab.getInterfaceType()); + if (ifaceRec.interfaces == null) { + ifaceRec.interfaces = new ArrayList<>(); + } + ifaceRec.interfaces.add(itab); - itab.getInterfaceType().discoverGoTypes(discoveredTypes); - itab.getType().discoverGoTypes(discoveredTypes); + itab.discoverGoTypes(discoveredTypes); } findUnindexedClosureStructTypes(monitor); @@ -197,6 +201,7 @@ public class GoTypeManager { gapStart += typeStructAlign; continue; } + @SuppressWarnings("unused") TypeRec newTypeRec = getTypeRec(goType); // add to index gapStart = getAlignedEndOfTypeInfo(goType, typeStructAlign); foundCount++; @@ -273,7 +278,7 @@ public class GoTypeManager { } /** - * Finds a go type by its go-type name + * Finds a go type by its go-type name, from the list of discovered go types. * * @param typeName name string * @return {@link GoType}, or null if not found @@ -421,7 +426,7 @@ public class GoTypeManager { /** * Returns the go type that represents a generic map argument value. * - * @return + * @return {@link GoType} */ public GoType getMapArgGoType() { return mapArgGoType; @@ -439,12 +444,16 @@ public class GoTypeManager { /** * Returns the go type that represents a generic chan argument value. * - * @return + * @return golang type for chan args */ public GoType getChanArgGoType() { return chanArgGoType; } + public DataType getUint8DT() { + return uint8DT; + } + public DataType getUintDT() { return uintDT; } @@ -476,6 +485,10 @@ public class GoTypeManager { return uint32DT; } + public DataType getVoidPtrDT() { + return voidPtrDT; + } + /** * Returns the name of a gotype. * @@ -507,15 +520,14 @@ public class GoTypeManager { */ public List getInterfacesImplementedByType(GoType type) { TypeRec rec = getTypeRec(type); - return rec.interfaces != null ? rec.interfaces : List.of(); + List itabs = rec.interfaces != null ? rec.interfaces : List.of(); + return itabs.stream().filter(itab -> itab._type == type.getTypeOffset()).toList(); } - public void markTypeWithInterface(GoItab itab) throws IOException { - TypeRec rec = getTypeRec(itab.getType()); - if (rec.interfaces == null) { - rec.interfaces = new ArrayList<>(); - } - rec.interfaces.add(itab); + public List getTypesThatImplementInterface(GoInterfaceType iface) { + TypeRec rec = getTypeRec(iface); + List itabs = rec.interfaces != null ? rec.interfaces : List.of(); + return itabs.stream().filter(itab -> itab.inter == iface.getTypeOffset()).toList(); } /** @@ -620,8 +632,7 @@ public class GoTypeManager { /** * Returns category path that should be used to place recovered golang types. - - * @param symbolName the symbol from which to get the package path + * @param symbolName {@link GoSymbolName} to convert to a category path * @return {@link CategoryPath} to use when creating recovered golang types */ public CategoryPath getCP(GoSymbolName symbolName) { @@ -650,6 +661,10 @@ public class GoTypeManager { return goBinary.getStructureDataType(GoIface.class); } + public Structure getGenericITabDT() { + return goBinary.getStructureDataType(GoItab.class); + } + public DataType getMethodClosureType(String recvType) throws IOException { //struct struct { F uintptr; R *atomic.Uint64 } GoType closureType = findGoType("struct { F uintptr; R %s }".formatted(recvType)); @@ -679,8 +694,7 @@ public class GoTypeManager { funcDef.setArguments(params); closureDT.add(dtm.getPointer(funcDef), "F", null); - closureDT.add(new ArrayDataType(AbstractIntegerDataType.getUnsignedDataType(1, dtm), 0), - "context", null); + closureDT.add(new ArrayDataType(uint8DT, 0), "context", null); defaultClosureType = (Structure) dtm.addDataType(closureDT, DataTypeConflictHandler.DEFAULT_HANDLER); @@ -701,7 +715,7 @@ public class GoTypeManager { funcDef.setArguments(params); closureDT.add(dtm.getPointer(funcDef), "F", null); - closureDT.add(dtm.getPointer(null), "R", "method receiver"); + closureDT.add(voidPtrDT, "R", "method receiver"); defaultMethodWrapperType = (Structure) dtm.addDataType(closureDT, DataTypeConflictHandler.DEFAULT_HANDLER); @@ -718,7 +732,7 @@ public class GoTypeManager { public GoType getSubstitutionType(String typeName) { if (typeName.startsWith("*")) { - return new GoTypeBridge(typeName, dtm.getPointer(null), goBinary); + return new GoTypeBridge(typeName, getVoidPtrDT(), goBinary); } else if (typeName.startsWith("[]") || typeName.equals("runtime.slice")) { return new GoTypeBridge(typeName, getGenericSliceDT(), goBinary); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoChanType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoChanType.java index fcaa026119..39da7d50aa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoChanType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoChanType.java @@ -56,7 +56,7 @@ public class GoChanType extends GoType { if (chanGoType == null) { // if we couldn't find the underlying/hidden runtime.hchan struct type, just return // a void* - return programContext.getDTM().getPointer(null); + return goTypes.getVoidPtrDT(); } DataType chanDT = goTypes.getGhidraDataType(chanGoType); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoFuncType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoFuncType.java index 45ed86d0a5..296451145f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoFuncType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoFuncType.java @@ -188,9 +188,15 @@ public class GoFuncType extends GoType { CategoryPath cp = goTypes.getCP(this); StructureDataType struct = new StructureDataType(cp, name, (int) typ.getSize(), dtm); + DataType structPtr = dtm.getPointer(struct); - // pre-push an empty struct into the cache to prevent endless recursive loops - goTypes.cacheRecoveredDataType(this, struct); + FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(cp, name + "_F", dtm); + struct.replace(0, dtm.getPointer(funcDef), -1, "F", null); + struct.add(new ArrayDataType(goTypes.getUint8DT(), 0), "context", null); + struct.setToDefaultPacking(); + + // pre-push an partially constructed struct into the cache to prevent endless recursive loops + goTypes.cacheRecoveredDataType(this, structPtr); List paramTypes = getParamTypes(); List inParamTypes = paramTypes.subList(0, inCount); @@ -214,24 +220,19 @@ public class GoFuncType extends GoType { } else { List paramDataTypes = new ArrayList<>(); - for (GoType typ : outParamTypes) { - paramDataTypes.add(goTypes.getGhidraDataType(typ)); + for (GoType outParamType : outParamTypes) { + paramDataTypes.add(goTypes.getGhidraDataType(outParamType)); } returnDT = goTypes.getFuncMultiReturn(paramDataTypes); } - FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(cp, name + "_F", dtm); funcDef.setArguments(params.toArray(ParameterDefinition[]::new)); funcDef.setReturnType(returnDT); - struct.replace(0, dtm.getPointer(funcDef), -1, "F", null); - struct.add(new ArrayDataType(AbstractIntegerDataType.getUnsignedDataType(1, dtm), 0), - "context", null); - struct.setToDefaultPacking(); // TODO: typ.getSize() should be ptrsize, and struct size should also be ptrsize - return dtm.getPointer(struct); + return structPtr; } public FunctionDefinition getFunctionSignature(GoTypeManager goTypes) throws IOException { @@ -242,6 +243,10 @@ public class GoFuncType extends GoType { closureStructDT.getComponent(0).getDataType() instanceof Pointer funcdefPtr && funcdefPtr.getDataType() instanceof FunctionDefinition fd ? fd : null; + if (funcdef == null) { + throw new IOException("Unable to extract function sig for " + this.toString()); + } + List newArgs = new ArrayList<>(); ParameterDefinition[] oldArgs = funcdef.getArguments(); for (int i = 1; i < oldArgs.length; i++) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoIMethod.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoIMethod.java index 9f40c1447a..0105eab77e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoIMethod.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoIMethod.java @@ -16,10 +16,14 @@ package ghidra.app.util.bin.format.golang.rtti.types; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import ghidra.app.util.bin.format.golang.GoConstants; import ghidra.app.util.bin.format.golang.rtti.*; import ghidra.app.util.bin.format.golang.structmapping.*; import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; @StructureMapping(structureName = {"runtime.imethod", "internal/abi.Imethod"}) public class GoIMethod implements StructureMarkup { @@ -50,8 +54,11 @@ public class GoIMethod implements StructureMarkup { } @Markup - public GoType getType() throws IOException { - return programContext.getGoTypes().resolveTypeOff(context.getStructureStart(), ityp); + public GoFuncType getType() throws IOException { + return programContext.getGoTypes() + .resolveTypeOff(context.getStructureStart(), ityp) instanceof GoFuncType funcType + ? funcType + : null; } @Override @@ -70,6 +77,24 @@ public class GoIMethod implements StructureMarkup { getStructureContext()); } + public FunctionDefinition getFunctionDefinition(boolean isGeneric, GoTypeManager goTypes) + throws IOException { + GoFuncType methodFuncDefType = getType(); + if (methodFuncDefType == null) { + return null; + } + FunctionDefinition funcdef = methodFuncDefType.getFunctionSignature(goTypes); + List params = new ArrayList<>(List.of(funcdef.getArguments())); + params.add(0, new ParameterDefinitionImpl(GoConstants.GOLANG_RECEIVER_PARAM_NAME, + goTypes.getVoidPtrDT(), null)); + if (isGeneric) { + params.add(1, new ParameterDefinitionImpl(GoConstants.GOLANG_GENERICS_PARAM_NAME, + goTypes.getGenericDictDT(), null)); + } + funcdef.setArguments(params.toArray(ParameterDefinition[]::new)); + return funcdef; + } + public static class GoIMethodInfo extends MethodInfo { GoItab itab; GoIMethod imethod; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoInterfaceType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoInterfaceType.java index b473400118..4ee8224853 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoInterfaceType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoInterfaceType.java @@ -21,9 +21,10 @@ import java.util.Set; import ghidra.app.util.bin.format.golang.rtti.*; import ghidra.app.util.bin.format.golang.structmapping.*; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.TypedefDataType; -import ghidra.util.exception.CancelledException; +import ghidra.app.util.viewer.field.AddressAnnotatedStringHandler; +import ghidra.program.model.data.*; +import ghidra.util.InvalidNameException; +import ghidra.util.exception.*; /** * A {@link GoType} structure that defines a golang interface. @@ -81,13 +82,55 @@ public class GoInterfaceType extends GoType { @Override public DataType recoverDataType(GoTypeManager goTypes) throws IOException { - DataType dt = programContext.getStructureDataType(GoIface.class); + Structure genericIfaceDT = programContext.getStructureDataType(GoIface.class); - String name = goTypes.getTypeName(this); - if (!dt.getName().equals(name)) { - dt = new TypedefDataType(goTypes.getCP(this), name, dt, goTypes.getDTM()); + CategoryPath ifaceCP = goTypes.getCP(this); + String ifaceName = goTypes.getTypeName(this); + StructureDataType ifaceDT = + new StructureDataType(ifaceCP, ifaceName, genericIfaceDT.getLength(), goTypes.getDTM()); + + ifaceDT.replaceWith(genericIfaceDT); + + goTypes.cacheRecoveredDataType(this, ifaceDT); + + Structure itabStruct = getSpecializedITabStruct(ifaceCP, ifaceName, goTypes); + + int itabComponentOrdinal = 0; // TODO: hacky + DataTypeComponentImpl genericItabDTC = ifaceDT.getComponent(itabComponentOrdinal); + ifaceDT.replace(itabComponentOrdinal, goTypes.getDTM().getPointer(itabStruct), -1, + genericItabDTC.getFieldName(), null); + + return ifaceDT; + } + + public Structure getSpecializedITabStruct(CategoryPath ifaceCP, String ifaceName, + GoTypeManager goTypes) throws IOException { + DataTypeManager dtm = goTypes.getDTM(); + + Structure genericItabStruct = goTypes.getGenericITabDT(); + + StructureDataType itabStruct = new StructureDataType(ifaceCP, ifaceName + "_itab", 0, dtm); + itabStruct.replaceWith(genericItabStruct); + + int funDTCOrdinal = 4; // a bit of a hack, could also lookup by name "Fun" + //DataTypeComponentImpl funDtc = itabStruct.getComponent(funDTCOrdinal); + itabStruct.delete(funDTCOrdinal); + + CategoryPath funcsCP = ifaceCP.extend(itabStruct.getName() + "_funcs"); + for (GoIMethod imethod : getMethods()) { + FunctionDefinition methodFuncDef = imethod.getFunctionDefinition(false, goTypes); + try { + methodFuncDef.setNameAndCategory(funcsCP, imethod.getName()); + itabStruct.add(dtm.getPointer(methodFuncDef), imethod.getName(), null); + methodFuncDef + .setCallingConvention(programContext.getDefaultCallingConventionName()); + } + catch (InvalidNameException | DuplicateNameException | InvalidInputException e) { + throw new IOException("Error creating itab for " + ifaceName, e); + } } - return dt; + + return itabStruct; } @Override @@ -105,6 +148,27 @@ public class GoInterfaceType extends GoType { return sb.toString(); } + protected String getTypesThatImplementInterfaceString() { + StringBuilder sb = new StringBuilder(); + for (GoItab goItab : programContext.getGoTypes().getTypesThatImplementInterface(this)) { + if (!sb.isEmpty()) { + sb.append("\n"); + } + try { + GoType type = goItab.getType(); + sb.append(AddressAnnotatedStringHandler.createAddressAnnotationString( + type.getStructureContext().getStructureAddress(), + type.getFullyQualifiedName())); + sb.append(AddressAnnotatedStringHandler.createAddressAnnotationString( + goItab.getStructureContext().getStructureAddress(), "[itab]")); + } + catch (IOException e) { + sb.append("bad type info"); + } + } + return sb.toString(); + } + @Override public boolean discoverGoTypes(Set discoveredTypes) throws IOException { if (!super.discoverGoTypes(discoveredTypes)) { @@ -124,4 +188,15 @@ public class GoInterfaceType extends GoType { return super.isValid() && typ.getSize() == programContext.getPtrSize() * 2; // runtime.iface? } + @Override + public String toString() { + String s = super.toString(); + + String implementations = getTypesThatImplementInterfaceString(); + if (!implementations.isEmpty()) { + s += "\n\n// Implemented by:\n" + implementations; + } + return s; + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoMapType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoMapType.java index 7c4f3b214b..8e38d6c547 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoMapType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoMapType.java @@ -103,7 +103,7 @@ public class GoMapType extends GoType { if (mapGoType == null) { // if we couldn't find the underlying/hidden runtime.hmap struct type, just return // a void* - return goTypes.getDTM().getPointer(null); + return goTypes.getVoidPtrDT(); } DataType mapDT = goTypes.getGhidraDataType(mapGoType); Pointer ptrMapDt = goTypes.getDTM().getPointer(mapDT); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java index 43f4cac012..265a0c4983 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java @@ -43,25 +43,24 @@ public class GoPlainType extends GoType implements StructureReader { @Override public DataType recoverDataType(GoTypeManager goTypes) throws IOException { DataTypeManager dtm = goTypes.getDTM(); + int ptrSize = programContext.getPtrSize(); DataType dt = switch (typ.getKind()) { case Bool -> BooleanDataType.dataType; case Float32 -> AbstractFloatDataType.getFloatDataType(32 / 8, null); case Float64 -> AbstractFloatDataType.getFloatDataType(64 / 8, null); - case Int -> AbstractIntegerDataType.getSignedDataType(programContext.getPtrSize(), dtm); + case Int -> AbstractIntegerDataType.getSignedDataType(ptrSize, dtm); case Int8 -> AbstractIntegerDataType.getSignedDataType(8 / 8, null); case Int16 -> AbstractIntegerDataType.getSignedDataType(16 / 8, null); case Int32 -> AbstractIntegerDataType.getSignedDataType(32 / 8, null); case Int64 -> AbstractIntegerDataType.getSignedDataType(64 / 8, null); - case Uint -> AbstractIntegerDataType.getUnsignedDataType(programContext.getPtrSize(), - dtm); + case Uint -> AbstractIntegerDataType.getUnsignedDataType(ptrSize, dtm); case Uint8 -> AbstractIntegerDataType.getUnsignedDataType(8 / 8, null); case Uint16 -> AbstractIntegerDataType.getUnsignedDataType(16 / 8, null); case Uint32 -> AbstractIntegerDataType.getUnsignedDataType(32 / 8, null); case Uint64 -> AbstractIntegerDataType.getUnsignedDataType(64 / 8, null); - case Uintptr -> AbstractIntegerDataType.getUnsignedDataType(programContext.getPtrSize(), - dtm); + case Uintptr -> AbstractIntegerDataType.getUnsignedDataType(ptrSize, dtm); case String -> programContext.getStructureDataType(GoString.class); - case UnsafePointer -> dtm.getPointer(null); + case UnsafePointer -> goTypes.getVoidPtrDT(); default -> null; }; if (dt == null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java index fde4ff8176..14c0be065a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java @@ -135,10 +135,10 @@ public class GoStructType extends GoType { List fieldList = getFields(); for (int i = 0; i < fieldList.size(); i++) { GoStructField field = fieldList.get(i); - GoStructField nextField = i < fieldList.size() - 1 ? fieldList.get(i + 1) : null; - long availSpace = nextField != null - ? nextField.getOffset() - field.getOffset() - : typ.getSize() - field.getOffset(); +// GoStructField nextField = i < fieldList.size() - 1 ? fieldList.get(i + 1) : null; +// long availSpace = nextField != null +// ? nextField.getOffset() - field.getOffset() +// : typ.getSize() - field.getOffset(); GoType fieldType = field.getType(); long fieldSize = fieldType.getBaseType().getSize(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java index 422294d8cc..fc52e41a66 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java @@ -304,7 +304,10 @@ public abstract class GoType implements StructureMarkup, StructureVerifi /** * Converts a golang RTTI type structure into a Ghidra data type. + *

+ * This default implementation just creates an opaque blob of the appropriate size * + * @param goTypes {@link GoTypeManager} * @return {@link DataType} that represents the golang type * @throws IOException if error getting name of the type */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/FieldMappingInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/FieldMappingInfo.java index d8cc90153a..5d6ccfc797 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/FieldMappingInfo.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/FieldMappingInfo.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,7 +22,7 @@ import java.util.*; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; -import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.listing.CommentType; import ghidra.util.exception.CancelledException; /** @@ -107,9 +107,9 @@ public class FieldMappingInfo { } public DataTypeComponent findDtc(Structure struct) { - for (DataTypeComponent dtc : struct.getDefinedComponents()) { - if (dtcFieldName.equals(dtc.getFieldName())) { - return dtc; + for (DataTypeComponent testDtc : struct.getDefinedComponents()) { + if (dtcFieldName.equals(testDtc.getFieldName())) { + return testDtc; } } return null; @@ -173,19 +173,19 @@ public class FieldMappingInfo { if (pca != null) { Method commentGetter = ReflectionHelper.getCommentMethod(clazz, pca.value(), field.getName()); - markupFuncs.add(createCommentMarkupFunc(commentGetter, CodeUnit.PLATE_COMMENT, "\n")); + markupFuncs.add(createCommentMarkupFunc(commentGetter, CommentType.PLATE, "\n")); } EOLComment eca = field.getAnnotation(EOLComment.class); if (eca != null) { Method commentGetter = ReflectionHelper.getCommentMethod(clazz, eca.value(), field.getName()); - markupFuncs.add(createCommentMarkupFunc(commentGetter, CodeUnit.EOL_COMMENT, ";")); + markupFuncs.add(createCommentMarkupFunc(commentGetter, CommentType.EOL, ";")); } } - private FieldMarkupFunction createCommentMarkupFunc(Method commentGetter, int commentType, - String sep) { + private FieldMarkupFunction createCommentMarkupFunc(Method commentGetter, + CommentType commentType, String sep) { return (context, session) -> { T obj = context.getStructureInstance(); Object val = ReflectionHelper.callGetter(commentGetter, obj); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java index f12b500d9b..11dbbe1a03 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java @@ -242,14 +242,13 @@ public class MarkupSession { * the operation is skipped. * * @param fieldContext the field - * @param commentType {@link CodeUnit#EOL_COMMENT}, {@link CodeUnit#PLATE_COMMENT}, - * {@link CodeUnit#POST_COMMENT}, {@link CodeUnit#PRE_COMMENT} + * @param commentType {@link CommentType} enum * @param prefix String prefix to place in front of the comment string * @param comment String value to append * @param sep separator to use between existing comments (for example, "\n") * @throws IOException if error adding comment */ - public void appendComment(FieldContext fieldContext, int commentType, String prefix, + public void appendComment(FieldContext fieldContext, CommentType commentType, String prefix, String comment, String sep) throws IOException { DWARFUtil.appendComment(program, fieldContext.getAddress(), commentType, prefix, comment, sep); @@ -261,22 +260,21 @@ public class MarkupSession { * the operation is skipped. * * @param structureContext the structure - * @param commentType {@link CodeUnit#EOL_COMMENT}, {@link CodeUnit#PLATE_COMMENT}, - * {@link CodeUnit#POST_COMMENT}, {@link CodeUnit#PRE_COMMENT} + * @param commentType {@link CommentType} enum * @param prefix String prefix to place in front of the comment string * @param comment String value to append * @param sep separator to use between existing comments (for example, "\n") * @throws IOException if error adding comment */ - public void appendComment(StructureContext structureContext, int commentType, String prefix, - String comment, String sep) throws IOException { + public void appendComment(StructureContext structureContext, CommentType commentType, + String prefix, String comment, String sep) throws IOException { DWARFUtil.appendComment(program, structureContext.getStructureAddress(), commentType, prefix, comment, sep); } public void appendComment(Function func, String prefix, String comment) { if (func != null) { - DWARFUtil.appendComment(program, func.getEntryPoint(), CodeUnit.PLATE_COMMENT, prefix, + DWARFUtil.appendComment(program, func.getEntryPoint(), CommentType.PLATE, prefix, comment, "\n"); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMappingInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMappingInfo.java index cd300c78ec..48329b5ea9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMappingInfo.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMappingInfo.java @@ -16,16 +16,11 @@ package ghidra.app.util.bin.format.golang.structmapping; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; +import java.lang.reflect.*; import java.util.*; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; -import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.CommentType; import ghidra.util.InvalidNameException; import ghidra.util.exception.DuplicateNameException; @@ -324,6 +319,7 @@ public class StructureMappingInfo { ? FieldMappingInfo.createEarlyBinding(field, dtc, signedness, length) : FieldMappingInfo.createLateBinding(field, fieldNames[0], signedness, length); + @SuppressWarnings("rawtypes") Class fieldReadFuncClass = fma != null ? fma.readFunc() : FieldReadFunction.class; String setterNameOverride = fma != null ? fma.setter() : null; @@ -381,7 +377,7 @@ public class StructureMappingInfo { T obj = context.getStructureInstance(); Object val = ReflectionHelper.callGetter(commentGetter, obj); if (val != null) { - session.appendComment(context, CodeUnit.PLATE_COMMENT, null, val.toString(), "\n"); + session.appendComment(context, CommentType.PLATE, null, val.toString(), "\n"); } }); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMarkupFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMarkupFunction.java index 612120613d..2d397817fc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMarkupFunction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureMarkupFunction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -32,7 +32,7 @@ public interface StructureMarkupFunction { * @param context {@link StructureContext} * @param markupSession state and methods to assist marking up the program * @throws IOException thrown if error performing the markup - * @throws CancelledException + * @throws CancelledException if cancelled */ void markupStructure(StructureContext context, MarkupSession markupSession) throws IOException, CancelledException; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureReader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureReader.java index be76797b81..0883556b01 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureReader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/StructureReader.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,9 +25,11 @@ import java.io.IOException; */ public interface StructureReader { /** - * Called after an instance has been created and its context has been initialized. + * Called after an instance has been created and its context has been initialized, to give + * the struct a chance to deserialize itself using the BinaryReaders and such found in the + * context information. * - * @throws IOException + * @throws IOException if error deserializing data for this struct */ void readStructure() throws IOException; }