mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +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.DWARFSectionProvider;
|
||||||
import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProviderFactory;
|
import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProviderFactory;
|
||||||
import ghidra.program.model.address.Address;
|
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.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ public class DWARFLineInfoCommentScript extends GhidraScript {
|
||||||
List<SourceFileAddr> allSFA = cu.getLine().getAllSourceFileAddrInfo(cu, reader);
|
List<SourceFileAddr> allSFA = cu.getLine().getAllSourceFileAddrInfo(cu, reader);
|
||||||
for (SourceFileAddr sfa : allSFA) {
|
for (SourceFileAddr sfa : allSFA) {
|
||||||
Address addr = dprog.getCodeAddress(sfa.address());
|
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()), ";");
|
"%s:%d".formatted(sfa.fileName(), sfa.lineNum()), ";");
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,13 +302,8 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
||||||
functionSignatureFromMethod++;
|
functionSignatureFromMethod++;
|
||||||
}
|
}
|
||||||
|
|
||||||
GoParamStorageAllocator storageAllocator = goBinary.newStorageAllocator();
|
GoFunctionFixup ff = new GoFunctionFixup(func, funcDefResult.funcDef(),
|
||||||
|
goBinary.getCallingConventionFor(funcdata), goBinary.newStorageAllocator());
|
||||||
boolean regAbi = !storageAllocator.isAbi0Mode() && !goBinary.isGolangAbi0Func(func);
|
|
||||||
String ccName = regAbi ? abiIntCCName : null;
|
|
||||||
|
|
||||||
GoFunctionFixup ff =
|
|
||||||
new GoFunctionFixup(func, funcDefResult.funcDef(), ccName, storageAllocator);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ff.apply();
|
ff.apply();
|
||||||
|
@ -933,7 +928,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyTo(Program program, TaskMonitor monitor) {
|
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
|
// If abi0 mode, don't even bother because currently only handles rtti passed via
|
||||||
// register.
|
// register.
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -367,7 +367,7 @@ public class DWARFFunctionImporter {
|
||||||
// because this is a zero-length data type (ie. array[0]),
|
// 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
|
// don't create a variable at the location since it will prevent other elements
|
||||||
// from occupying the same offset
|
// from occupying the same offset
|
||||||
appendComment(address, CodeUnit.PRE_COMMENT,
|
appendComment(address, CommentType.PRE,
|
||||||
"Zero length variable: %s: %s".formatted(name, dataType.getDisplayName()), "\n");
|
"Zero length variable: %s: %s".formatted(name, dataType.getDisplayName()), "\n");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -384,13 +384,13 @@ public class DWARFFunctionImporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataType instanceof Dynamic || dataType instanceof FactoryDataType) {
|
if (dataType instanceof Dynamic || dataType instanceof FactoryDataType) {
|
||||||
appendComment(address, CodeUnit.EOL_COMMENT,
|
appendComment(address, CommentType.EOL,
|
||||||
"Unsupported dynamic data type: " + dataType, "\n");
|
"Unsupported dynamic data type: " + dataType, "\n");
|
||||||
dataType = Undefined.getUndefinedDataType(1);
|
dataType = Undefined.getUndefinedDataType(1);
|
||||||
}
|
}
|
||||||
DWARFDataInstanceHelper dih = new DWARFDataInstanceHelper(currentProgram);
|
DWARFDataInstanceHelper dih = new DWARFDataInstanceHelper(currentProgram);
|
||||||
if (!dih.isDataTypeCompatibleWithAddress(dataType, address)) {
|
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."
|
"Could not place DWARF static variable %s: %s @%s because existing data type conflicts."
|
||||||
.formatted(name, dataType.getName(), address),
|
.formatted(name, dataType.getName(), address),
|
||||||
"\n");
|
"\n");
|
||||||
|
@ -414,8 +414,7 @@ public class DWARFFunctionImporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalVar.sourceInfo != null) {
|
if (globalVar.sourceInfo != null) {
|
||||||
appendComment(address, CodeUnit.EOL_COMMENT, globalVar.sourceInfo.getDescriptionStr(),
|
appendComment(address, CommentType.EOL, globalVar.sourceInfo.getDescriptionStr(), "\n");
|
||||||
"\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +436,7 @@ public class DWARFFunctionImporter {
|
||||||
if (importOptions.isOutputLexicalBlockComments()) {
|
if (importOptions.isOutputLexicalBlockComments()) {
|
||||||
boolean disjoint = blockRanges.getListCount() > 1;
|
boolean disjoint = blockRanges.getListCount() > 1;
|
||||||
DWARFName dni = prog.getName(diea);
|
DWARFName dni = prog.getName(diea);
|
||||||
appendComment(blockStart, CodeUnit.PRE_COMMENT,
|
appendComment(blockStart, CommentType.PRE,
|
||||||
"Begin: %s%s".formatted(dni.getName(), disjoint ? " - Disjoint" : ""), "\n");
|
"Begin: %s%s".formatted(dni.getName(), disjoint ? " - Disjoint" : ""), "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,22 +470,23 @@ public class DWARFFunctionImporter {
|
||||||
long inlineFuncLen = range.getLength();
|
long inlineFuncLen = range.getLength();
|
||||||
boolean isShort = inlineFuncLen < INLINE_FUNC_SHORT_LEN;
|
boolean isShort = inlineFuncLen < INLINE_FUNC_SHORT_LEN;
|
||||||
if (isShort) {
|
if (isShort) {
|
||||||
appendComment(range.getMinAddress(), CodeUnit.EOL_COMMENT,
|
appendComment(range.getMinAddress(), CommentType.EOL,
|
||||||
"inline " + funcDef.getPrototypeString(), "; ");
|
"inline " + funcDef.getPrototypeString(), "; ");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
appendComment(range.getMinAddress(), CodeUnit.PRE_COMMENT,
|
appendComment(range.getMinAddress(), CommentType.PRE,
|
||||||
"Begin: inline " + funcDef.getPrototypeString(), "\n");
|
"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);
|
DWARFUtil.appendComment(currentProgram, address, commentType, "", comment, sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendPlateComment(Address address, String prefix, String comment) {
|
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");
|
"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,7 +572,7 @@ public class DWARFFunctionImporter {
|
||||||
|
|
||||||
String locationInfo = DWARFSourceInfo.getDescriptionStr(diea);
|
String locationInfo = DWARFSourceInfo.getDescriptionStr(diea);
|
||||||
if (locationInfo != null) {
|
if (locationInfo != null) {
|
||||||
appendComment(address, CodeUnit.EOL_COMMENT, locationInfo, "; ");
|
appendComment(address, CommentType.EOL, locationInfo, "; ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
|
|
|
@ -346,7 +346,7 @@ public class DWARFUtil {
|
||||||
dtc.setComment(prev + description);
|
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) {
|
String prefix, String comment, String sep) {
|
||||||
if (comment == null || comment.isBlank()) {
|
if (comment == null || comment.isBlank()) {
|
||||||
return;
|
return;
|
||||||
|
@ -359,7 +359,7 @@ public class DWARFUtil {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AppendCommentCmd cmd = new AppendCommentCmd(address, commentType,
|
AppendCommentCmd cmd = new AppendCommentCmd(address, commentType.ordinal(),
|
||||||
Objects.requireNonNullElse(prefix, "") + comment, sep);
|
Objects.requireNonNullElse(prefix, "") + comment, sep);
|
||||||
cmd.applyTo(program);
|
cmd.applyTo(program);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,6 @@ import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
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.program.model.symbol.SymbolUtilities;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
@ -57,7 +55,7 @@ public class GoFunctionFixup {
|
||||||
this.newSignature = func.getSignature();
|
this.newSignature = func.getSignature();
|
||||||
this.newCallingConv = null;
|
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
|
// Some (typically lower level) functions in the binary will be marked with a
|
||||||
// symbol that ends in the string "abi0".
|
// symbol that ends in the string "abi0".
|
||||||
// Throw away all registers and force stack allocation for everything
|
// 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) {
|
private boolean isInLocalVarStorageArea(long stackOffset) {
|
||||||
boolean paramsHavePositiveOffset = program.getCompilerSpec().stackGrowsNegative();
|
boolean paramsHavePositiveOffset = program.getCompilerSpec().stackGrowsNegative();
|
||||||
return (paramsHavePositiveOffset && stackOffset < 0) ||
|
return (paramsHavePositiveOffset && stackOffset < 0) ||
|
||||||
|
|
|
@ -153,17 +153,17 @@ public class GoFunctionMultiReturn {
|
||||||
|
|
||||||
private record StackComponentInfo(DataTypeComponent dtc, int ordinal, String comment) {}
|
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) {
|
GoParamStorageAllocator storageAllocator) {
|
||||||
|
|
||||||
String name = getComponentsInOriginalOrder(struct).stream()
|
String name = getComponentsInOriginalOrder(newStruct).stream()
|
||||||
.map(dtc -> dtc.getDataType().getName())
|
.map(dtc -> dtc.getDataType().getName())
|
||||||
.collect(Collectors.joining(";", SHORT_MULTIVALUE_RETURNTYPE_PREFIX,
|
.collect(Collectors.joining(";", SHORT_MULTIVALUE_RETURNTYPE_PREFIX,
|
||||||
SHORT_MULTIVALUE_RETURNTYPE_SUFFIX));
|
SHORT_MULTIVALUE_RETURNTYPE_SUFFIX));
|
||||||
|
|
||||||
if (struct.getName().equals(TMP_NAME)) {
|
if (newStruct.getName().equals(TMP_NAME)) {
|
||||||
try {
|
try {
|
||||||
struct.setName(name);
|
newStruct.setName(name);
|
||||||
}
|
}
|
||||||
catch (InvalidNameException | DuplicateNameException e) {
|
catch (InvalidNameException | DuplicateNameException e) {
|
||||||
// should not happen
|
// should not happen
|
||||||
|
@ -171,15 +171,15 @@ public class GoFunctionMultiReturn {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storageAllocator == null) {
|
if (storageAllocator == null) {
|
||||||
this.struct = struct;
|
this.struct = newStruct;
|
||||||
for (DataTypeComponent dtc : getComponentsInOriginalOrder(struct)) {
|
for (DataTypeComponent dtc : getComponentsInOriginalOrder(newStruct)) {
|
||||||
stackStorageComponents.add(dtc);
|
stackStorageComponents.add(dtc);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Structure adjustedStruct = new StructureDataType(struct.getCategoryPath(),
|
Structure adjustedStruct = new StructureDataType(newStruct.getCategoryPath(),
|
||||||
name + "_" + storageAllocator.getArchDescription(), 0, dtm);
|
name + "_" + storageAllocator.getArchDescription(), 0, dtm);
|
||||||
adjustedStruct.setPackingEnabled(true);
|
adjustedStruct.setPackingEnabled(true);
|
||||||
adjustedStruct.setExplicitPackingValue(1);
|
adjustedStruct.setExplicitPackingValue(1);
|
||||||
|
@ -187,7 +187,7 @@ public class GoFunctionMultiReturn {
|
||||||
storageAllocator = storageAllocator.clone();
|
storageAllocator = storageAllocator.clone();
|
||||||
List<StackComponentInfo> stackResults = new ArrayList<>();
|
List<StackComponentInfo> stackResults = new ArrayList<>();
|
||||||
int compNum = 0;
|
int compNum = 0;
|
||||||
for (DataTypeComponent dtc : getComponentsInOriginalOrder(struct)) {
|
for (DataTypeComponent dtc : getComponentsInOriginalOrder(newStruct)) {
|
||||||
List<Register> regs = storageAllocator.getRegistersFor(dtc.getDataType());
|
List<Register> regs = storageAllocator.getRegistersFor(dtc.getDataType());
|
||||||
if (regs == null || regs.isEmpty()) {
|
if (regs == null || regs.isEmpty()) {
|
||||||
long stackOffset = storageAllocator.getStackAllocation(dtc.getDataType());
|
long stackOffset = storageAllocator.getStackAllocation(dtc.getDataType());
|
||||||
|
@ -215,8 +215,8 @@ public class GoFunctionMultiReturn {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEquiv = DWARFDataTypeConflictHandler.INSTANCE.resolveConflict(adjustedStruct,
|
boolean isEquiv = DWARFDataTypeConflictHandler.INSTANCE.resolveConflict(adjustedStruct,
|
||||||
struct) == ConflictResult.USE_EXISTING;
|
newStruct) == ConflictResult.USE_EXISTING;
|
||||||
this.struct = isEquiv ? struct : adjustedStruct;
|
this.struct = isEquiv ? newStruct : adjustedStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getOrdinalNumber(DataTypeComponent dtc) {
|
private static int getOrdinalNumber(DataTypeComponent dtc) {
|
||||||
|
|
|
@ -261,12 +261,12 @@ public class GoParamStorageAllocator {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (dt instanceof Structure struct) {
|
if (dt instanceof Structure struct) {
|
||||||
DataTypeComponent prevDTC = null;
|
// DataTypeComponent prevDTC = null;
|
||||||
for (DataTypeComponent dtc : struct.getDefinedComponents()) {
|
for (DataTypeComponent dtc : struct.getDefinedComponents()) {
|
||||||
int padding = prevDTC != null ? dtc.getOffset() - prevDTC.getOffset() : 0;
|
// int padding = prevDTC != null ? dtc.getOffset() - prevDTC.getOffset() : 0;
|
||||||
if (padding != 0) {
|
// if (padding != 0) {
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
if (!countRegistersFor(dtc.getDataType(), result)) {
|
if (!countRegistersFor(dtc.getDataType(), result)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,10 @@ public class GoRegisterInfo {
|
||||||
return stackInitialOffset;
|
return stackInitialOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasAbiInternalParamRegisters() {
|
||||||
|
return !intRegisters.isEmpty() || !floatRegisters.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public List<Variable> getDuffzeroParams(Program program) {
|
public List<Variable> getDuffzeroParams(Program program) {
|
||||||
if (duffzeroDestParam == null) {
|
if (duffzeroDestParam == null) {
|
||||||
return List.of();
|
return List.of();
|
||||||
|
|
|
@ -17,13 +17,9 @@ package ghidra.app.util.bin.format.golang;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.jdom.Document;
|
import org.jdom.*;
|
||||||
import org.jdom.Element;
|
|
||||||
import org.jdom.JDOMException;
|
|
||||||
import org.jdom.input.SAXBuilder;
|
import org.jdom.input.SAXBuilder;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
|
@ -143,7 +139,6 @@ public class GoRegisterInfoManager {
|
||||||
Element zeroRegElem = regInfoElem.getChild("zero_register");
|
Element zeroRegElem = regInfoElem.getChild("zero_register");
|
||||||
Element duffZeroElem = regInfoElem.getChild("duffzero");
|
Element duffZeroElem = regInfoElem.getChild("duffzero");
|
||||||
Element closureContextElem = regInfoElem.getChild("closurecontext");
|
Element closureContextElem = regInfoElem.getChild("closurecontext");
|
||||||
Element gcWriteBarrierElem = regInfoElem.getChild("gcwritebarrier");
|
|
||||||
if (intRegsElem == null || floatRegsElem == null || stackElem == null ||
|
if (intRegsElem == null || floatRegsElem == null || stackElem == null ||
|
||||||
goRoutineElem == null || zeroRegElem == null || duffZeroElem == null ||
|
goRoutineElem == null || zeroRegElem == null || duffZeroElem == null ||
|
||||||
closureContextElem == null) {
|
closureContextElem == null) {
|
||||||
|
|
|
@ -15,32 +15,17 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.golang;
|
package ghidra.app.util.bin.format.golang;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.dwarf.DIEAggregate;
|
import ghidra.app.util.bin.format.dwarf.*;
|
||||||
import ghidra.app.util.bin.format.dwarf.DWARFException;
|
|
||||||
import ghidra.app.util.bin.format.dwarf.DWARFFunction;
|
|
||||||
import ghidra.app.util.bin.format.dwarf.DWARFFunction.CommitMode;
|
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.dwarf.funcfixup.DWARFFunctionFixup;
|
||||||
import ghidra.app.util.bin.format.golang.rtti.GoFuncData;
|
import ghidra.app.util.bin.format.golang.rtti.GoFuncData;
|
||||||
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
|
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.CategoryPath;
|
import ghidra.program.model.data.*;
|
||||||
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.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.listing.CodeUnit;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.Function;
|
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import ghidra.program.model.symbol.SymbolType;
|
import ghidra.program.model.symbol.SymbolType;
|
||||||
import ghidra.util.classfinder.ExtensionPointProperties;
|
import ghidra.util.classfinder.ExtensionPointProperties;
|
||||||
|
@ -301,7 +286,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendComment(Function func, String prefix, String comment) {
|
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");
|
prefix, comment, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,8 @@ public class GolangElfInfoProducer implements ElfInfoProducer {
|
||||||
private ElfLoadHelper elfLoadHelper;
|
private ElfLoadHelper elfLoadHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(ElfLoadHelper elfLoadHelper) {
|
public void init(ElfLoadHelper newElfLoadHelper) {
|
||||||
this.elfLoadHelper = elfLoadHelper;
|
this.elfLoadHelper = newElfLoadHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,10 +19,8 @@ import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
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.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.app.util.bin.format.golang.structmapping.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
@ -167,6 +165,9 @@ public class GoItab implements StructureMarkup<GoItab> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void additionalMarkup(MarkupSession session) throws IOException {
|
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();
|
GoSlice funSlice = getFunSlice();
|
||||||
List<Address> funcAddrs = Arrays.stream(funSlice.readUIntList(programContext.getPtrSize()))
|
List<Address> funcAddrs = Arrays.stream(funSlice.readUIntList(programContext.getPtrSize()))
|
||||||
.mapToObj(offset -> programContext.getCodeAddress(offset))
|
.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)
|
* 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() {
|
public boolean hasTextStart() {
|
||||||
return textStart != 0;
|
return textStart != 0;
|
||||||
|
|
|
@ -153,6 +153,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||||
* Creates a {@link GoRttiMapper} representing the specified program.
|
* Creates a {@link GoRttiMapper} representing the specified program.
|
||||||
*
|
*
|
||||||
* @param program {@link Program}
|
* @param program {@link Program}
|
||||||
|
* @param monitor {@link TaskMonitor}
|
||||||
* @return new {@link GoRttiMapper}, or null if basic golang information is not found in the
|
* @return new {@link GoRttiMapper}, or null if basic golang information is not found in the
|
||||||
* binary
|
* binary
|
||||||
* @throws BootstrapInfoException if it is a golang binary and has an unsupported or
|
* @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 GoVer goVer;
|
||||||
private final int ptrSize;
|
private final int ptrSize;
|
||||||
private final GoRegisterInfo regInfo;
|
private final GoRegisterInfo regInfo;
|
||||||
|
private final String defaultCCName;
|
||||||
private final List<GoModuledata> modules = new ArrayList<>();
|
private final List<GoModuledata> modules = new ArrayList<>();
|
||||||
private Map<Address, GoFuncData> funcdataByAddr = new HashMap<>();
|
private Map<Address, GoFuncData> funcdataByAddr = new HashMap<>();
|
||||||
private Map<String, GoFuncData> funcdataByName = 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 goVer version of go
|
||||||
* @param archiveGDT path to the matching golang bootstrap gdt data type file, or null
|
* @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
|
* 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
|
* @throws IOException if error linking a structure mapped structure to its matching
|
||||||
* ghidra structure, which is a programming error or a corrupted bootstrap gdt
|
* ghidra structure, which is a programming error or a corrupted bootstrap gdt
|
||||||
* @throws BootstrapInfoException if there is no matching bootstrap gdt for this specific
|
* @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.buildInfo = buildInfo;
|
||||||
this.goVer = goVer;
|
this.goVer = goVer;
|
||||||
this.ptrSize = ptrSize;
|
this.ptrSize = ptrSize;
|
||||||
|
this.defaultCCName = regInfo.hasAbiInternalParamRegisters() &&
|
||||||
|
hasCallingConvention(GOLANG_ABI_INTERNAL_CALLINGCONVENTION_NAME)
|
||||||
|
? GOLANG_ABI_INTERNAL_CALLINGCONVENTION_NAME
|
||||||
|
: null;
|
||||||
|
|
||||||
reader = super.createProgramReader();
|
reader = super.createProgramReader();
|
||||||
|
|
||||||
|
@ -598,8 +605,11 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||||
* @return boolean true if function uses abi0 calling convention
|
* @return boolean true if function uses abi0 calling convention
|
||||||
*/
|
*/
|
||||||
public boolean isGolangAbi0Func(Function func) {
|
public boolean isGolangAbi0Func(Function func) {
|
||||||
Address funcAddr = func.getEntryPoint();
|
return isAbi0Func(func.getEntryPoint(), program);
|
||||||
for (Symbol symbol : func.getProgram().getSymbolTable().getSymbolsAsIterator(funcAddr)) {
|
}
|
||||||
|
|
||||||
|
public static boolean isAbi0Func(Address funcEntry, Program program) {
|
||||||
|
for (Symbol symbol : program.getSymbolTable().getSymbolsAsIterator(funcEntry)) {
|
||||||
if (symbol.getSymbolType() == SymbolType.LABEL) {
|
if (symbol.getSymbolType() == SymbolType.LABEL) {
|
||||||
String labelName = symbol.getName();
|
String labelName = symbol.getName();
|
||||||
if (labelName.endsWith("abi0")) {
|
if (labelName.endsWith("abi0")) {
|
||||||
|
@ -610,6 +620,14 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||||
return false;
|
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.
|
* Returns true if the specified calling convention is defined for the program.
|
||||||
* @param ccName calling convention name
|
* @param ccName calling convention name
|
||||||
|
@ -619,6 +637,10 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||||
return program.getFunctionManager().getCallingConvention(ccName) != null;
|
return program.getFunctionManager().getCallingConvention(ccName) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDefaultCallingConventionName() {
|
||||||
|
return defaultCCName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MarkupSession createMarkupSession(TaskMonitor monitor) {
|
public MarkupSession createMarkupSession(TaskMonitor monitor) {
|
||||||
UnknownProgressWrappingTaskMonitor upwtm = new UnknownProgressWrappingTaskMonitor(monitor);
|
UnknownProgressWrappingTaskMonitor upwtm = new UnknownProgressWrappingTaskMonitor(monitor);
|
||||||
|
@ -869,7 +891,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||||
FROM_ANALYSIS,
|
FROM_ANALYSIS,
|
||||||
CLOSURE,
|
CLOSURE,
|
||||||
METHOD_WRAPPER
|
METHOD_WRAPPER
|
||||||
};
|
}
|
||||||
|
|
||||||
public record FuncDefResult(FunctionDefinition funcDef, GoType recvType, Set<FuncDefFlags> flags,
|
public record FuncDefResult(FunctionDefinition funcDef, GoType recvType, Set<FuncDefFlags> flags,
|
||||||
String funcDefStr, GoSymbolName symbolName) {
|
String funcDefStr, GoSymbolName symbolName) {
|
||||||
|
@ -878,7 +900,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
|
||||||
/**
|
/**
|
||||||
* Returns function definition information for a func.
|
* 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
|
* @return {@link FuncDefResult} record, or null if no information could be found or
|
||||||
* generated
|
* generated
|
||||||
* @throws IOException if error reading type info
|
* @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);
|
return result != null ? result : new GoSymbolName(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GoSymbolName _parse(String s) {
|
private static GoSymbolName _parse(String s) {
|
||||||
if (s.startsWith("go:")) {
|
if (s.startsWith("go:")) {
|
||||||
// don't try to parse "go:...." symbols
|
// don't try to parse "go:...." symbols
|
||||||
return null;
|
return null;
|
||||||
|
@ -451,9 +451,9 @@ public record GoSymbolName(String symbolName, String packagePath, String package
|
||||||
* <p>
|
* <p>
|
||||||
* Nesting is delimited by '(', '{', '[' chars and their matching closing element.
|
* Nesting is delimited by '(', '{', '[' chars and their matching closing element.
|
||||||
*
|
*
|
||||||
* @param s
|
* @param s string to split
|
||||||
* @param splitChar
|
* @param splitChar char to split the string on
|
||||||
* @return
|
* @return list of strings that are each part of the original string
|
||||||
*/
|
*/
|
||||||
private static List<String> splitNestedStringOn(String s, char splitChar) {
|
private static List<String> splitNestedStringOn(String s, char splitChar) {
|
||||||
// TODO: may also have to skip chars in quoted field comments
|
// TODO: may also have to skip chars in quoted field comments
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class GoTypeManager {
|
||||||
private DataType int32DT;
|
private DataType int32DT;
|
||||||
private DataType uint32DT;
|
private DataType uint32DT;
|
||||||
private DataType uint8DT;
|
private DataType uint8DT;
|
||||||
private DataType stringDT;
|
private DataType voidPtrDT;
|
||||||
|
|
||||||
public GoTypeManager(GoRttiMapper goBinary, GoApiSnapshot apiSnapshot) {
|
public GoTypeManager(GoRttiMapper goBinary, GoApiSnapshot apiSnapshot) {
|
||||||
this.goBinary = goBinary;
|
this.goBinary = goBinary;
|
||||||
|
@ -89,6 +89,7 @@ public class GoTypeManager {
|
||||||
* @throws IOException if error reading data or cancelled
|
* @throws IOException if error reading data or cancelled
|
||||||
*/
|
*/
|
||||||
public void init(TaskMonitor monitor) throws IOException {
|
public void init(TaskMonitor monitor) throws IOException {
|
||||||
|
this.voidPtrDT = dtm.getPointer(VoidDataType.dataType);
|
||||||
this.uintptrDT = goBinary.getTypeOrDefault("uintptr", DataType.class,
|
this.uintptrDT = goBinary.getTypeOrDefault("uintptr", DataType.class,
|
||||||
AbstractIntegerDataType.getUnsignedDataType(goBinary.getPtrSize(), dtm));
|
AbstractIntegerDataType.getUnsignedDataType(goBinary.getPtrSize(), dtm));
|
||||||
this.uintDT = goBinary.getTypeOrDefault("uint", DataType.class,
|
this.uintDT = goBinary.getTypeOrDefault("uint", DataType.class,
|
||||||
|
@ -100,7 +101,6 @@ public class GoTypeManager {
|
||||||
AbstractIntegerDataType.getUnsignedDataType(4, null));
|
AbstractIntegerDataType.getUnsignedDataType(4, null));
|
||||||
this.uint8DT = goBinary.getTypeOrDefault("uint8", DataType.class,
|
this.uint8DT = goBinary.getTypeOrDefault("uint8", DataType.class,
|
||||||
AbstractIntegerDataType.getUnsignedDataType(1, null));
|
AbstractIntegerDataType.getUnsignedDataType(1, null));
|
||||||
this.stringDT = goBinary.getTypeOrDefault("string", Structure.class, null);
|
|
||||||
|
|
||||||
this.genericDictDT = dtm.getPointer(dtm.getPointer(uintptrDT));
|
this.genericDictDT = dtm.getPointer(dtm.getPointer(uintptrDT));
|
||||||
|
|
||||||
|
@ -141,9 +141,13 @@ public class GoTypeManager {
|
||||||
rec.interfaces = new ArrayList<>();
|
rec.interfaces = new ArrayList<>();
|
||||||
}
|
}
|
||||||
rec.interfaces.add(itab);
|
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.discoverGoTypes(discoveredTypes);
|
||||||
itab.getType().discoverGoTypes(discoveredTypes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findUnindexedClosureStructTypes(monitor);
|
findUnindexedClosureStructTypes(monitor);
|
||||||
|
@ -197,6 +201,7 @@ public class GoTypeManager {
|
||||||
gapStart += typeStructAlign;
|
gapStart += typeStructAlign;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@SuppressWarnings("unused")
|
||||||
TypeRec newTypeRec = getTypeRec(goType); // add to index
|
TypeRec newTypeRec = getTypeRec(goType); // add to index
|
||||||
gapStart = getAlignedEndOfTypeInfo(goType, typeStructAlign);
|
gapStart = getAlignedEndOfTypeInfo(goType, typeStructAlign);
|
||||||
foundCount++;
|
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
|
* @param typeName name string
|
||||||
* @return {@link GoType}, or null if not found
|
* @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.
|
* Returns the go type that represents a generic map argument value.
|
||||||
*
|
*
|
||||||
* @return
|
* @return {@link GoType}
|
||||||
*/
|
*/
|
||||||
public GoType getMapArgGoType() {
|
public GoType getMapArgGoType() {
|
||||||
return mapArgGoType;
|
return mapArgGoType;
|
||||||
|
@ -439,12 +444,16 @@ public class GoTypeManager {
|
||||||
/**
|
/**
|
||||||
* Returns the go type that represents a generic chan argument value.
|
* Returns the go type that represents a generic chan argument value.
|
||||||
*
|
*
|
||||||
* @return
|
* @return golang type for chan args
|
||||||
*/
|
*/
|
||||||
public GoType getChanArgGoType() {
|
public GoType getChanArgGoType() {
|
||||||
return chanArgGoType;
|
return chanArgGoType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataType getUint8DT() {
|
||||||
|
return uint8DT;
|
||||||
|
}
|
||||||
|
|
||||||
public DataType getUintDT() {
|
public DataType getUintDT() {
|
||||||
return uintDT;
|
return uintDT;
|
||||||
}
|
}
|
||||||
|
@ -476,6 +485,10 @@ public class GoTypeManager {
|
||||||
return uint32DT;
|
return uint32DT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataType getVoidPtrDT() {
|
||||||
|
return voidPtrDT;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of a gotype.
|
* Returns the name of a gotype.
|
||||||
*
|
*
|
||||||
|
@ -507,15 +520,14 @@ public class GoTypeManager {
|
||||||
*/
|
*/
|
||||||
public List<GoItab> getInterfacesImplementedByType(GoType type) {
|
public List<GoItab> getInterfacesImplementedByType(GoType type) {
|
||||||
TypeRec rec = getTypeRec(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 {
|
public List<GoItab> getTypesThatImplementInterface(GoInterfaceType iface) {
|
||||||
TypeRec rec = getTypeRec(itab.getType());
|
TypeRec rec = getTypeRec(iface);
|
||||||
if (rec.interfaces == null) {
|
List<GoItab> itabs = rec.interfaces != null ? rec.interfaces : List.of();
|
||||||
rec.interfaces = new ArrayList<>();
|
return itabs.stream().filter(itab -> itab.inter == iface.getTypeOffset()).toList();
|
||||||
}
|
|
||||||
rec.interfaces.add(itab);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -620,8 +632,7 @@ public class GoTypeManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns category path that should be used to place recovered golang types.
|
* Returns category path that should be used to place recovered golang types.
|
||||||
|
* @param symbolName {@link GoSymbolName} to convert to a category path
|
||||||
* @param symbolName the symbol from which to get the package path
|
|
||||||
* @return {@link CategoryPath} to use when creating recovered golang types
|
* @return {@link CategoryPath} to use when creating recovered golang types
|
||||||
*/
|
*/
|
||||||
public CategoryPath getCP(GoSymbolName symbolName) {
|
public CategoryPath getCP(GoSymbolName symbolName) {
|
||||||
|
@ -650,6 +661,10 @@ public class GoTypeManager {
|
||||||
return goBinary.getStructureDataType(GoIface.class);
|
return goBinary.getStructureDataType(GoIface.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Structure getGenericITabDT() {
|
||||||
|
return goBinary.getStructureDataType(GoItab.class);
|
||||||
|
}
|
||||||
|
|
||||||
public DataType getMethodClosureType(String recvType) throws IOException {
|
public DataType getMethodClosureType(String recvType) throws IOException {
|
||||||
//struct struct { F uintptr; R *atomic.Uint64 }
|
//struct struct { F uintptr; R *atomic.Uint64 }
|
||||||
GoType closureType = findGoType("struct { F uintptr; R %s }".formatted(recvType));
|
GoType closureType = findGoType("struct { F uintptr; R %s }".formatted(recvType));
|
||||||
|
@ -679,8 +694,7 @@ public class GoTypeManager {
|
||||||
funcDef.setArguments(params);
|
funcDef.setArguments(params);
|
||||||
|
|
||||||
closureDT.add(dtm.getPointer(funcDef), "F", null);
|
closureDT.add(dtm.getPointer(funcDef), "F", null);
|
||||||
closureDT.add(new ArrayDataType(AbstractIntegerDataType.getUnsignedDataType(1, dtm), 0),
|
closureDT.add(new ArrayDataType(uint8DT, 0), "context", null);
|
||||||
"context", null);
|
|
||||||
|
|
||||||
defaultClosureType =
|
defaultClosureType =
|
||||||
(Structure) dtm.addDataType(closureDT, DataTypeConflictHandler.DEFAULT_HANDLER);
|
(Structure) dtm.addDataType(closureDT, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||||
|
@ -701,7 +715,7 @@ public class GoTypeManager {
|
||||||
funcDef.setArguments(params);
|
funcDef.setArguments(params);
|
||||||
|
|
||||||
closureDT.add(dtm.getPointer(funcDef), "F", null);
|
closureDT.add(dtm.getPointer(funcDef), "F", null);
|
||||||
closureDT.add(dtm.getPointer(null), "R", "method receiver");
|
closureDT.add(voidPtrDT, "R", "method receiver");
|
||||||
|
|
||||||
defaultMethodWrapperType =
|
defaultMethodWrapperType =
|
||||||
(Structure) dtm.addDataType(closureDT, DataTypeConflictHandler.DEFAULT_HANDLER);
|
(Structure) dtm.addDataType(closureDT, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||||
|
@ -718,7 +732,7 @@ public class GoTypeManager {
|
||||||
|
|
||||||
public GoType getSubstitutionType(String typeName) {
|
public GoType getSubstitutionType(String typeName) {
|
||||||
if (typeName.startsWith("*")) {
|
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")) {
|
else if (typeName.startsWith("[]") || typeName.equals("runtime.slice")) {
|
||||||
return new GoTypeBridge(typeName, getGenericSliceDT(), goBinary);
|
return new GoTypeBridge(typeName, getGenericSliceDT(), goBinary);
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class GoChanType extends GoType {
|
||||||
if (chanGoType == null) {
|
if (chanGoType == null) {
|
||||||
// if we couldn't find the underlying/hidden runtime.hchan struct type, just return
|
// if we couldn't find the underlying/hidden runtime.hchan struct type, just return
|
||||||
// a void*
|
// a void*
|
||||||
return programContext.getDTM().getPointer(null);
|
return goTypes.getVoidPtrDT();
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType chanDT = goTypes.getGhidraDataType(chanGoType);
|
DataType chanDT = goTypes.getGhidraDataType(chanGoType);
|
||||||
|
|
|
@ -188,9 +188,15 @@ public class GoFuncType extends GoType {
|
||||||
CategoryPath cp = goTypes.getCP(this);
|
CategoryPath cp = goTypes.getCP(this);
|
||||||
|
|
||||||
StructureDataType struct = new StructureDataType(cp, name, (int) typ.getSize(), dtm);
|
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
|
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(cp, name + "_F", dtm);
|
||||||
goTypes.cacheRecoveredDataType(this, struct);
|
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> paramTypes = getParamTypes();
|
||||||
List<GoType> inParamTypes = paramTypes.subList(0, inCount);
|
List<GoType> inParamTypes = paramTypes.subList(0, inCount);
|
||||||
|
@ -214,24 +220,19 @@ public class GoFuncType extends GoType {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
List<DataType> paramDataTypes = new ArrayList<>();
|
List<DataType> paramDataTypes = new ArrayList<>();
|
||||||
for (GoType typ : outParamTypes) {
|
for (GoType outParamType : outParamTypes) {
|
||||||
paramDataTypes.add(goTypes.getGhidraDataType(typ));
|
paramDataTypes.add(goTypes.getGhidraDataType(outParamType));
|
||||||
}
|
}
|
||||||
returnDT = goTypes.getFuncMultiReturn(paramDataTypes);
|
returnDT = goTypes.getFuncMultiReturn(paramDataTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(cp, name + "_F", dtm);
|
|
||||||
funcDef.setArguments(params.toArray(ParameterDefinition[]::new));
|
funcDef.setArguments(params.toArray(ParameterDefinition[]::new));
|
||||||
funcDef.setReturnType(returnDT);
|
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
|
// 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 {
|
public FunctionDefinition getFunctionSignature(GoTypeManager goTypes) throws IOException {
|
||||||
|
@ -242,6 +243,10 @@ public class GoFuncType extends GoType {
|
||||||
closureStructDT.getComponent(0).getDataType() instanceof Pointer funcdefPtr &&
|
closureStructDT.getComponent(0).getDataType() instanceof Pointer funcdefPtr &&
|
||||||
funcdefPtr.getDataType() instanceof FunctionDefinition fd ? fd : null;
|
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<>();
|
List<ParameterDefinition> newArgs = new ArrayList<>();
|
||||||
ParameterDefinition[] oldArgs = funcdef.getArguments();
|
ParameterDefinition[] oldArgs = funcdef.getArguments();
|
||||||
for (int i = 1; i < oldArgs.length; i++) {
|
for (int i = 1; i < oldArgs.length; i++) {
|
||||||
|
|
|
@ -16,10 +16,14 @@
|
||||||
package ghidra.app.util.bin.format.golang.rtti.types;
|
package ghidra.app.util.bin.format.golang.rtti.types;
|
||||||
|
|
||||||
import java.io.IOException;
|
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.rtti.*;
|
||||||
import ghidra.app.util.bin.format.golang.structmapping.*;
|
import ghidra.app.util.bin.format.golang.structmapping.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
|
||||||
@StructureMapping(structureName = {"runtime.imethod", "internal/abi.Imethod"})
|
@StructureMapping(structureName = {"runtime.imethod", "internal/abi.Imethod"})
|
||||||
public class GoIMethod implements StructureMarkup<GoIMethod> {
|
public class GoIMethod implements StructureMarkup<GoIMethod> {
|
||||||
|
@ -50,8 +54,11 @@ public class GoIMethod implements StructureMarkup<GoIMethod> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Markup
|
@Markup
|
||||||
public GoType getType() throws IOException {
|
public GoFuncType getType() throws IOException {
|
||||||
return programContext.getGoTypes().resolveTypeOff(context.getStructureStart(), ityp);
|
return programContext.getGoTypes()
|
||||||
|
.resolveTypeOff(context.getStructureStart(), ityp) instanceof GoFuncType funcType
|
||||||
|
? funcType
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -70,6 +77,24 @@ public class GoIMethod implements StructureMarkup<GoIMethod> {
|
||||||
getStructureContext());
|
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 {
|
public static class GoIMethodInfo extends MethodInfo {
|
||||||
GoItab itab;
|
GoItab itab;
|
||||||
GoIMethod imethod;
|
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.rtti.*;
|
||||||
import ghidra.app.util.bin.format.golang.structmapping.*;
|
import ghidra.app.util.bin.format.golang.structmapping.*;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.app.util.viewer.field.AddressAnnotatedStringHandler;
|
||||||
import ghidra.program.model.data.TypedefDataType;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.InvalidNameException;
|
||||||
|
import ghidra.util.exception.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link GoType} structure that defines a golang interface.
|
* A {@link GoType} structure that defines a golang interface.
|
||||||
|
@ -81,13 +82,55 @@ public class GoInterfaceType extends GoType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType recoverDataType(GoTypeManager goTypes) throws IOException {
|
public DataType recoverDataType(GoTypeManager goTypes) throws IOException {
|
||||||
DataType dt = programContext.getStructureDataType(GoIface.class);
|
Structure genericIfaceDT = programContext.getStructureDataType(GoIface.class);
|
||||||
|
|
||||||
String name = goTypes.getTypeName(this);
|
CategoryPath ifaceCP = goTypes.getCP(this);
|
||||||
if (!dt.getName().equals(name)) {
|
String ifaceName = goTypes.getTypeName(this);
|
||||||
dt = new TypedefDataType(goTypes.getCP(this), name, dt, goTypes.getDTM());
|
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
|
@Override
|
||||||
|
@ -105,6 +148,27 @@ public class GoInterfaceType extends GoType {
|
||||||
return sb.toString();
|
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
|
@Override
|
||||||
public boolean discoverGoTypes(Set<Long> discoveredTypes) throws IOException {
|
public boolean discoverGoTypes(Set<Long> discoveredTypes) throws IOException {
|
||||||
if (!super.discoverGoTypes(discoveredTypes)) {
|
if (!super.discoverGoTypes(discoveredTypes)) {
|
||||||
|
@ -124,4 +188,15 @@ public class GoInterfaceType extends GoType {
|
||||||
return super.isValid() && typ.getSize() == programContext.getPtrSize() * 2; // runtime.iface?
|
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 (mapGoType == null) {
|
||||||
// if we couldn't find the underlying/hidden runtime.hmap struct type, just return
|
// if we couldn't find the underlying/hidden runtime.hmap struct type, just return
|
||||||
// a void*
|
// a void*
|
||||||
return goTypes.getDTM().getPointer(null);
|
return goTypes.getVoidPtrDT();
|
||||||
}
|
}
|
||||||
DataType mapDT = goTypes.getGhidraDataType(mapGoType);
|
DataType mapDT = goTypes.getGhidraDataType(mapGoType);
|
||||||
Pointer ptrMapDt = goTypes.getDTM().getPointer(mapDT);
|
Pointer ptrMapDt = goTypes.getDTM().getPointer(mapDT);
|
||||||
|
|
|
@ -43,25 +43,24 @@ public class GoPlainType extends GoType implements StructureReader<GoType> {
|
||||||
@Override
|
@Override
|
||||||
public DataType recoverDataType(GoTypeManager goTypes) throws IOException {
|
public DataType recoverDataType(GoTypeManager goTypes) throws IOException {
|
||||||
DataTypeManager dtm = goTypes.getDTM();
|
DataTypeManager dtm = goTypes.getDTM();
|
||||||
|
int ptrSize = programContext.getPtrSize();
|
||||||
DataType dt = switch (typ.getKind()) {
|
DataType dt = switch (typ.getKind()) {
|
||||||
case Bool -> BooleanDataType.dataType;
|
case Bool -> BooleanDataType.dataType;
|
||||||
case Float32 -> AbstractFloatDataType.getFloatDataType(32 / 8, null);
|
case Float32 -> AbstractFloatDataType.getFloatDataType(32 / 8, null);
|
||||||
case Float64 -> AbstractFloatDataType.getFloatDataType(64 / 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 Int8 -> AbstractIntegerDataType.getSignedDataType(8 / 8, null);
|
||||||
case Int16 -> AbstractIntegerDataType.getSignedDataType(16 / 8, null);
|
case Int16 -> AbstractIntegerDataType.getSignedDataType(16 / 8, null);
|
||||||
case Int32 -> AbstractIntegerDataType.getSignedDataType(32 / 8, null);
|
case Int32 -> AbstractIntegerDataType.getSignedDataType(32 / 8, null);
|
||||||
case Int64 -> AbstractIntegerDataType.getSignedDataType(64 / 8, null);
|
case Int64 -> AbstractIntegerDataType.getSignedDataType(64 / 8, null);
|
||||||
case Uint -> AbstractIntegerDataType.getUnsignedDataType(programContext.getPtrSize(),
|
case Uint -> AbstractIntegerDataType.getUnsignedDataType(ptrSize, dtm);
|
||||||
dtm);
|
|
||||||
case Uint8 -> AbstractIntegerDataType.getUnsignedDataType(8 / 8, null);
|
case Uint8 -> AbstractIntegerDataType.getUnsignedDataType(8 / 8, null);
|
||||||
case Uint16 -> AbstractIntegerDataType.getUnsignedDataType(16 / 8, null);
|
case Uint16 -> AbstractIntegerDataType.getUnsignedDataType(16 / 8, null);
|
||||||
case Uint32 -> AbstractIntegerDataType.getUnsignedDataType(32 / 8, null);
|
case Uint32 -> AbstractIntegerDataType.getUnsignedDataType(32 / 8, null);
|
||||||
case Uint64 -> AbstractIntegerDataType.getUnsignedDataType(64 / 8, null);
|
case Uint64 -> AbstractIntegerDataType.getUnsignedDataType(64 / 8, null);
|
||||||
case Uintptr -> AbstractIntegerDataType.getUnsignedDataType(programContext.getPtrSize(),
|
case Uintptr -> AbstractIntegerDataType.getUnsignedDataType(ptrSize, dtm);
|
||||||
dtm);
|
|
||||||
case String -> programContext.getStructureDataType(GoString.class);
|
case String -> programContext.getStructureDataType(GoString.class);
|
||||||
case UnsafePointer -> dtm.getPointer(null);
|
case UnsafePointer -> goTypes.getVoidPtrDT();
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
if (dt == null) {
|
if (dt == null) {
|
||||||
|
|
|
@ -135,10 +135,10 @@ public class GoStructType extends GoType {
|
||||||
List<GoStructField> fieldList = getFields();
|
List<GoStructField> fieldList = getFields();
|
||||||
for (int i = 0; i < fieldList.size(); i++) {
|
for (int i = 0; i < fieldList.size(); i++) {
|
||||||
GoStructField field = fieldList.get(i);
|
GoStructField field = fieldList.get(i);
|
||||||
GoStructField nextField = i < fieldList.size() - 1 ? fieldList.get(i + 1) : null;
|
// GoStructField nextField = i < fieldList.size() - 1 ? fieldList.get(i + 1) : null;
|
||||||
long availSpace = nextField != null
|
// long availSpace = nextField != null
|
||||||
? nextField.getOffset() - field.getOffset()
|
// ? nextField.getOffset() - field.getOffset()
|
||||||
: typ.getSize() - field.getOffset();
|
// : typ.getSize() - field.getOffset();
|
||||||
|
|
||||||
GoType fieldType = field.getType();
|
GoType fieldType = field.getType();
|
||||||
long fieldSize = fieldType.getBaseType().getSize();
|
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.
|
* 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
|
* @return {@link DataType} that represents the golang type
|
||||||
* @throws IOException if error getting name of the 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.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.CodeUnit;
|
import ghidra.program.model.listing.CommentType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,9 +107,9 @@ public class FieldMappingInfo<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataTypeComponent findDtc(Structure struct) {
|
public DataTypeComponent findDtc(Structure struct) {
|
||||||
for (DataTypeComponent dtc : struct.getDefinedComponents()) {
|
for (DataTypeComponent testDtc : struct.getDefinedComponents()) {
|
||||||
if (dtcFieldName.equals(dtc.getFieldName())) {
|
if (dtcFieldName.equals(testDtc.getFieldName())) {
|
||||||
return dtc;
|
return testDtc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -173,19 +173,19 @@ public class FieldMappingInfo<T> {
|
||||||
if (pca != null) {
|
if (pca != null) {
|
||||||
Method commentGetter =
|
Method commentGetter =
|
||||||
ReflectionHelper.getCommentMethod(clazz, pca.value(), field.getName());
|
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);
|
EOLComment eca = field.getAnnotation(EOLComment.class);
|
||||||
if (eca != null) {
|
if (eca != null) {
|
||||||
Method commentGetter =
|
Method commentGetter =
|
||||||
ReflectionHelper.getCommentMethod(clazz, eca.value(), field.getName());
|
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,
|
private FieldMarkupFunction<T> createCommentMarkupFunc(Method commentGetter,
|
||||||
String sep) {
|
CommentType commentType, String sep) {
|
||||||
return (context, session) -> {
|
return (context, session) -> {
|
||||||
T obj = context.getStructureInstance();
|
T obj = context.getStructureInstance();
|
||||||
Object val = ReflectionHelper.callGetter(commentGetter, obj);
|
Object val = ReflectionHelper.callGetter(commentGetter, obj);
|
||||||
|
|
|
@ -242,14 +242,13 @@ public class MarkupSession {
|
||||||
* the operation is skipped.
|
* the operation is skipped.
|
||||||
*
|
*
|
||||||
* @param fieldContext the field
|
* @param fieldContext the field
|
||||||
* @param commentType {@link CodeUnit#EOL_COMMENT}, {@link CodeUnit#PLATE_COMMENT},
|
* @param commentType {@link CommentType} enum
|
||||||
* {@link CodeUnit#POST_COMMENT}, {@link CodeUnit#PRE_COMMENT}
|
|
||||||
* @param prefix String prefix to place in front of the comment string
|
* @param prefix String prefix to place in front of the comment string
|
||||||
* @param comment String value to append
|
* @param comment String value to append
|
||||||
* @param sep separator to use between existing comments (for example, "\n")
|
* @param sep separator to use between existing comments (for example, "\n")
|
||||||
* @throws IOException if error adding comment
|
* @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 {
|
String comment, String sep) throws IOException {
|
||||||
DWARFUtil.appendComment(program, fieldContext.getAddress(), commentType, prefix, comment,
|
DWARFUtil.appendComment(program, fieldContext.getAddress(), commentType, prefix, comment,
|
||||||
sep);
|
sep);
|
||||||
|
@ -261,22 +260,21 @@ public class MarkupSession {
|
||||||
* the operation is skipped.
|
* the operation is skipped.
|
||||||
*
|
*
|
||||||
* @param structureContext the structure
|
* @param structureContext the structure
|
||||||
* @param commentType {@link CodeUnit#EOL_COMMENT}, {@link CodeUnit#PLATE_COMMENT},
|
* @param commentType {@link CommentType} enum
|
||||||
* {@link CodeUnit#POST_COMMENT}, {@link CodeUnit#PRE_COMMENT}
|
|
||||||
* @param prefix String prefix to place in front of the comment string
|
* @param prefix String prefix to place in front of the comment string
|
||||||
* @param comment String value to append
|
* @param comment String value to append
|
||||||
* @param sep separator to use between existing comments (for example, "\n")
|
* @param sep separator to use between existing comments (for example, "\n")
|
||||||
* @throws IOException if error adding comment
|
* @throws IOException if error adding comment
|
||||||
*/
|
*/
|
||||||
public void appendComment(StructureContext<?> structureContext, int commentType, String prefix,
|
public void appendComment(StructureContext<?> structureContext, CommentType commentType,
|
||||||
String comment, String sep) throws IOException {
|
String prefix, String comment, String sep) throws IOException {
|
||||||
DWARFUtil.appendComment(program, structureContext.getStructureAddress(), commentType,
|
DWARFUtil.appendComment(program, structureContext.getStructureAddress(), commentType,
|
||||||
prefix, comment, sep);
|
prefix, comment, sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void appendComment(Function func, String prefix, String comment) {
|
public void appendComment(Function func, String prefix, String comment) {
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
DWARFUtil.appendComment(program, func.getEntryPoint(), CodeUnit.PLATE_COMMENT, prefix,
|
DWARFUtil.appendComment(program, func.getEntryPoint(), CommentType.PLATE, prefix,
|
||||||
comment, "\n");
|
comment, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,11 @@
|
||||||
package ghidra.app.util.bin.format.golang.structmapping;
|
package ghidra.app.util.bin.format.golang.structmapping;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.*;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataTypeComponent;
|
import ghidra.program.model.listing.CommentType;
|
||||||
import ghidra.program.model.data.Structure;
|
|
||||||
import ghidra.program.model.data.StructureDataType;
|
|
||||||
import ghidra.program.model.listing.CodeUnit;
|
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
|
@ -324,6 +319,7 @@ public class StructureMappingInfo<T> {
|
||||||
? FieldMappingInfo.createEarlyBinding(field, dtc, signedness, length)
|
? FieldMappingInfo.createEarlyBinding(field, dtc, signedness, length)
|
||||||
: FieldMappingInfo.createLateBinding(field, fieldNames[0], signedness, length);
|
: FieldMappingInfo.createLateBinding(field, fieldNames[0], signedness, length);
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
Class<? extends FieldReadFunction> fieldReadFuncClass =
|
Class<? extends FieldReadFunction> fieldReadFuncClass =
|
||||||
fma != null ? fma.readFunc() : FieldReadFunction.class;
|
fma != null ? fma.readFunc() : FieldReadFunction.class;
|
||||||
String setterNameOverride = fma != null ? fma.setter() : null;
|
String setterNameOverride = fma != null ? fma.setter() : null;
|
||||||
|
@ -381,7 +377,7 @@ public class StructureMappingInfo<T> {
|
||||||
T obj = context.getStructureInstance();
|
T obj = context.getStructureInstance();
|
||||||
Object val = ReflectionHelper.callGetter(commentGetter, obj);
|
Object val = ReflectionHelper.callGetter(commentGetter, obj);
|
||||||
if (val != null) {
|
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 context {@link StructureContext}
|
||||||
* @param markupSession state and methods to assist marking up the program
|
* @param markupSession state and methods to assist marking up the program
|
||||||
* @throws IOException thrown if error performing the markup
|
* @throws IOException thrown if error performing the markup
|
||||||
* @throws CancelledException
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
void markupStructure(StructureContext<T> context, MarkupSession markupSession)
|
void markupStructure(StructureContext<T> context, MarkupSession markupSession)
|
||||||
throws IOException, CancelledException;
|
throws IOException, CancelledException;
|
||||||
|
|
|
@ -25,9 +25,11 @@ import java.io.IOException;
|
||||||
*/
|
*/
|
||||||
public interface StructureReader<T> {
|
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;
|
void readStructure() throws IOException;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue