mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-5455 golang interface method calling and decl
Improve how golang interface methods are handled. Model the 'vtable' (runtime.itab) for a golang interface so each method declared by the interface gets a funcdef that specifies the method's params.
This commit is contained in:
parent
ecfd6d39d8
commit
2d3922d41f
29 changed files with 301 additions and 182 deletions
|
@ -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<SourceFileAddr> 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++;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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<StackComponentInfo> stackResults = new ArrayList<>();
|
||||
int compNum = 0;
|
||||
for (DataTypeComponent dtc : getComponentsInOriginalOrder(struct)) {
|
||||
for (DataTypeComponent dtc : getComponentsInOriginalOrder(newStruct)) {
|
||||
List<Register> 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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,10 @@ public class GoRegisterInfo {
|
|||
return stackInitialOffset;
|
||||
}
|
||||
|
||||
public boolean hasAbiInternalParamRegisters() {
|
||||
return !intRegisters.isEmpty() || !floatRegisters.isEmpty();
|
||||
}
|
||||
|
||||
public List<Variable> getDuffzeroParams(Program program) {
|
||||
if (duffzeroDestParam == null) {
|
||||
return List.of();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<GoItab> {
|
|||
|
||||
@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<Address> funcAddrs = Arrays.stream(funSlice.readUIntList(programContext.getPtrSize()))
|
||||
.mapToObj(offset -> programContext.getCodeAddress(offset))
|
||||
|
@ -200,5 +201,21 @@ public class GoItab implements StructureMarkup<GoItab> {
|
|||
}
|
||||
}
|
||||
|
||||
public void discoverGoTypes(Set<Long> 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<GoModuledata> modules = new ArrayList<>();
|
||||
private Map<Address, GoFuncData> funcdataByAddr = new HashMap<>();
|
||||
private Map<String, GoFuncData> 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<FuncDefFlags> 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
|
||||
|
|
|
@ -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
|
|||
* <p>
|
||||
* 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<String> splitNestedStringOn(String s, char splitChar) {
|
||||
// TODO: may also have to skip chars in quoted field comments
|
||||
|
|
|
@ -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<GoItab> getInterfacesImplementedByType(GoType type) {
|
||||
TypeRec rec = getTypeRec(type);
|
||||
return rec.interfaces != null ? rec.interfaces : List.of();
|
||||
List<GoItab> 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<GoItab> getTypesThatImplementInterface(GoInterfaceType iface) {
|
||||
TypeRec rec = getTypeRec(iface);
|
||||
List<GoItab> 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<GoType> paramTypes = getParamTypes();
|
||||
List<GoType> inParamTypes = paramTypes.subList(0, inCount);
|
||||
|
@ -214,24 +220,19 @@ public class GoFuncType extends GoType {
|
|||
}
|
||||
else {
|
||||
List<DataType> 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<ParameterDefinition> newArgs = new ArrayList<>();
|
||||
ParameterDefinition[] oldArgs = funcdef.getArguments();
|
||||
for (int i = 1; i < oldArgs.length; i++) {
|
||||
|
|
|
@ -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<GoIMethod> {
|
||||
|
@ -50,8 +54,11 @@ public class GoIMethod implements StructureMarkup<GoIMethod> {
|
|||
}
|
||||
|
||||
@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<GoIMethod> {
|
|||
getStructureContext());
|
||||
}
|
||||
|
||||
public FunctionDefinition getFunctionDefinition(boolean isGeneric, GoTypeManager goTypes)
|
||||
throws IOException {
|
||||
GoFuncType methodFuncDefType = getType();
|
||||
if (methodFuncDefType == null) {
|
||||
return null;
|
||||
}
|
||||
FunctionDefinition funcdef = methodFuncDefType.getFunctionSignature(goTypes);
|
||||
List<ParameterDefinition> 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
return dt;
|
||||
|
||||
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 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<Long> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -43,25 +43,24 @@ public class GoPlainType extends GoType implements StructureReader<GoType> {
|
|||
@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) {
|
||||
|
|
|
@ -135,10 +135,10 @@ public class GoStructType extends GoType {
|
|||
List<GoStructField> 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();
|
||||
|
|
|
@ -304,7 +304,10 @@ public abstract class GoType implements StructureMarkup<GoType>, StructureVerifi
|
|||
|
||||
/**
|
||||
* Converts a golang RTTI type structure into a Ghidra data type.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
|
|
|
@ -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<T> {
|
|||
}
|
||||
|
||||
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<T> {
|
|||
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<T> createCommentMarkupFunc(Method commentGetter, int commentType,
|
||||
String sep) {
|
||||
private FieldMarkupFunction<T> createCommentMarkupFunc(Method commentGetter,
|
||||
CommentType commentType, String sep) {
|
||||
return (context, session) -> {
|
||||
T obj = context.getStructureInstance();
|
||||
Object val = ReflectionHelper.callGetter(commentGetter, obj);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T> {
|
|||
? FieldMappingInfo.createEarlyBinding(field, dtc, signedness, length)
|
||||
: FieldMappingInfo.createLateBinding(field, fieldNames[0], signedness, length);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class<? extends FieldReadFunction> fieldReadFuncClass =
|
||||
fma != null ? fma.readFunc() : FieldReadFunction.class;
|
||||
String setterNameOverride = fma != null ? fma.setter() : null;
|
||||
|
@ -381,7 +377,7 @@ public class StructureMappingInfo<T> {
|
|||
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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public interface StructureMarkupFunction<T> {
|
|||
* @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<T> context, MarkupSession markupSession)
|
||||
throws IOException, CancelledException;
|
||||
|
|
|
@ -25,9 +25,11 @@ import java.io.IOException;
|
|||
*/
|
||||
public interface StructureReader<T> {
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue