From b5422faefb5f151b113358e9608bcb0e9d4aa636 Mon Sep 17 00:00:00 2001
From: dev747368 <48332326+dev747368@users.noreply.github.com>
Date: Tue, 6 Jun 2023 16:39:26 +0000
Subject: [PATCH] GP-2425 more better duffzero / duffcopy function info
---
.../core/analysis/GolangSymbolAnalyzer.java | 166 +++++++++++----
.../ProgramStartingLocationOptions.java | 2 +-
.../util/bin/format/golang/GoConstants.java | 8 +
.../bin/format/golang/GoRegisterInfo.java | 28 ++-
.../format/golang/GoRegisterInfoManager.java | 10 +-
.../format/golang/rtti/GoFunctabEntry.java | 4 +
.../bin/format/golang/rtti/GoModuledata.java | 37 +++-
.../bin/format/golang/rtti/GoRttiMapper.java | 125 ++++++++++--
.../util/bin/format/golang/rtti/GoSlice.java | 7 +
.../format/golang/rtti/types/GoPlainType.java | 3 +-
.../golang/rtti/types/GoStructType.java | 5 +
.../bin/format/golang/rtti/types/GoType.java | 13 ++
.../golang/rtti/types/GoUncommonType.java | 17 +-
.../ghidra/program/util/FunctionUtility.java | 2 +-
.../analysis/GolangDuffFixupAnalyzer.java | 191 ++++++++++++++++++
.../x86/data/languages/x86-32-golang.cspec | 50 +++++
.../x86/data/languages/x86-64-golang.cspec | 62 ++++++
17 files changed, 642 insertions(+), 88 deletions(-)
create mode 100644 Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/analysis/GolangDuffFixupAnalyzer.java
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java
index ea8350ac44..6f3907884d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java
@@ -18,30 +18,30 @@ package ghidra.app.plugin.core.analysis;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
import generic.jar.ResourceFile;
import ghidra.app.services.*;
import ghidra.app.util.MemoryBlockUtils;
+import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
import ghidra.app.util.bin.format.elf.info.ElfInfoItem.ItemWithAddress;
import ghidra.app.util.bin.format.golang.*;
-import ghidra.app.util.bin.format.golang.rtti.GoModuledata;
-import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
+import ghidra.app.util.bin.format.golang.rtti.*;
import ghidra.app.util.bin.format.golang.structmapping.MarkupSession;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
-import ghidra.program.model.data.Structure;
+import ghidra.program.model.data.*;
+import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
+import ghidra.program.model.listing.Function.FunctionUpdateType;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.InvalidInputException;
+import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.UnknownProgressWrappingTaskMonitor;
import ghidra.xml.XmlParseException;
@@ -73,34 +73,35 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
throws CancelledException {
monitor.setMessage("Golang symbol analyzer");
- try (GoRttiMapper programContext = GoRttiMapper.getMapperFor(program, log)) {
- if (programContext == null) {
+ try (GoRttiMapper goBinary = GoRttiMapper.getMapperFor(program, log)) {
+ if (goBinary == null) {
Msg.error(this, "Golang analyzer error: unable to get GoRttiMapper");
return false;
}
- programContext.discoverGoTypes(monitor);
-
- GoModuledata firstModule = programContext.getFirstModule();
-
+ goBinary.init(monitor);
+ goBinary.discoverGoTypes(monitor);
UnknownProgressWrappingTaskMonitor upwtm =
new UnknownProgressWrappingTaskMonitor(monitor, 100);
upwtm.initialize(0);
upwtm.setMessage("Marking up Golang RTTI structures");
- MarkupSession markupSession = programContext.createMarkupSession(upwtm);
+ MarkupSession markupSession = goBinary.createMarkupSession(upwtm);
+ GoModuledata firstModule = goBinary.getFirstModule();
+ if (firstModule != null) {
+ markupSession.labelStructure(firstModule, "firstmoduledata");
+ markupSession.markup(firstModule, false);
+ }
- markupSession.labelStructure(firstModule, "firstmoduledata");
- markupSession.markup(firstModule, false);
-
- markupMiscInfoStructs(program);
- markupWellknownSymbols(programContext, markupSession);
+ markupWellknownSymbols(goBinary, markupSession);
+ setupProgramContext(goBinary, markupSession);
+ goBinary.recoverDataTypes(monitor);
+ markupGoFunctions(goBinary, markupSession);
fixupNoReturnFuncs(program);
- setupProgramContext(programContext, markupSession);
- programContext.recoverDataTypes(monitor);
+ markupMiscInfoStructs(program);
if (analyzerOptions.createBootstrapDatatypeArchive) {
- createBootstrapGDT(programContext, program, monitor);
+ createBootstrapGDT(goBinary, program, monitor);
}
}
catch (IOException e) {
@@ -124,23 +125,103 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
analyzerOptions.createBootstrapDatatypeArchive);
}
- private void markupWellknownSymbols(GoRttiMapper programContext, MarkupSession session)
+ private void markupWellknownSymbols(GoRttiMapper goBinary, MarkupSession session)
throws IOException {
- Program program = programContext.getProgram();
-
+ Program program = goBinary.getProgram();
+
Symbol g0 = SymbolUtilities.getUniqueSymbol(program, "runtime.g0");
- Structure gStruct = programContext.getGhidraDataType("runtime.g", Structure.class);
+ Structure gStruct = goBinary.getGhidraDataType("runtime.g", Structure.class);
if (g0 != null && gStruct != null) {
session.markupAddressIfUndefined(g0.getAddress(), gStruct);
}
-
+
Symbol m0 = SymbolUtilities.getUniqueSymbol(program, "runtime.m0");
- Structure mStruct = programContext.getGhidraDataType("runtime.m", Structure.class);
+ Structure mStruct = goBinary.getGhidraDataType("runtime.m", Structure.class);
if (m0 != null && mStruct != null) {
session.markupAddressIfUndefined(m0.getAddress(), mStruct);
}
}
+ private void markupGoFunctions(GoRttiMapper goBinary, MarkupSession markupSession)
+ throws IOException {
+ for (GoFuncData funcdata : goBinary.getAllFunctions()) {
+ String funcname = SymbolUtilities.replaceInvalidChars(funcdata.getName(), true);
+ markupSession.createFunctionIfMissing(funcname, funcdata.getFuncAddress());
+ }
+ try {
+ fixDuffFunctions(goBinary, markupSession);
+ }
+ catch (InvalidInputException | DuplicateNameException e) {
+ Msg.error(this, "Error configuring duff functions", e);
+ }
+ }
+
+ /**
+ * Fixes the function signature of the runtime.duffzero and runtime.duffcopy functions.
+ *
+ * The alternate duff-ified entry points haven't been discovered yet, so the information
+ * set to the main function entry point will be propagated at a later time to the alternate
+ * entry points by the GolangDuffFixupAnalyzer.
+ *
+ * @param goBinary the golang binary
+ * @param session {@link MarkupSession}
+ * @throws InvalidInputException if error assigning the function signature
+ * @throws DuplicateNameException if error assigning the function signature
+ */
+ private void fixDuffFunctions(GoRttiMapper goBinary, MarkupSession session)
+ throws InvalidInputException, DuplicateNameException {
+ Program program = goBinary.getProgram();
+ GoRegisterInfo regInfo = goBinary.getRegInfo();
+ DataType voidPtr = program.getDataTypeManager().getPointer(VoidDataType.dataType);
+ DataType uintDT = goBinary.getTypeOrDefault("uint", DataType.class,
+ AbstractUnsignedIntegerDataType.getUnsignedDataType(goBinary.getPtrSize(), null));
+
+ GoFuncData duffzeroFuncdata = goBinary.getFunctionByName("runtime.duffzero");
+ Function duffzeroFunc = duffzeroFuncdata != null
+ ? program.getFunctionManager().getFunctionAt(duffzeroFuncdata.getFuncAddress())
+ : null;
+ PrototypeModel duffzeroCC = goBinary.getDuffzeroCallingConvention();
+ if (duffzeroFunc != null && duffzeroCC != null) {
+ // NOTE: some duffzero funcs need a zero value supplied to them via a register set
+ // by the caller. (depending on the arch) The duffzero calling convention defined
+ // by the callspec should take care of this by defining that register as the second
+ // storage location. Otherwise, the callspec will only have a single storage
+ // location defined.
+ boolean needZeroValueParam = regInfo.getZeroRegister() == null;
+ List params = new ArrayList<>();
+ params.add(new ParameterImpl("dest", voidPtr, program));
+ if (needZeroValueParam) {
+ params.add(new ParameterImpl("zeroValue", uintDT, program));
+ }
+
+ duffzeroFunc.updateFunction(duffzeroCC.getName(),
+ new ReturnParameterImpl(VoidDataType.dataType, program), params,
+ FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true,
+ SourceType.ANALYSIS);
+
+ DWARFUtil.appendComment(program, duffzeroFunc.getEntryPoint(), CodeUnit.PLATE_COMMENT,
+ "Golang special function: ", "duffzero", "\n");
+ }
+
+ GoFuncData duffcopyFuncdata = goBinary.getFunctionByName("runtime.duffcopy");
+ Function duffcopyFunc = duffcopyFuncdata != null
+ ? program.getFunctionManager().getFunctionAt(duffcopyFuncdata.getFuncAddress())
+ : null;
+ PrototypeModel duffcopyCC = goBinary.getDuffcopyCallingConvention();
+ if (duffcopyFuncdata != null && duffcopyCC != null) {
+ List params = List.of(
+ new ParameterImpl("dest", voidPtr, program),
+ new ParameterImpl("src", voidPtr, program));
+ duffcopyFunc.updateFunction(duffcopyCC.getName(),
+ new ReturnParameterImpl(VoidDataType.dataType, program), params,
+ FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.ANALYSIS);
+
+ DWARFUtil.appendComment(program, duffcopyFunc.getEntryPoint(), CodeUnit.PLATE_COMMENT,
+ "Golang special function: ", "duffcopy", "\n");
+ }
+
+ }
+
private void markupMiscInfoStructs(Program program) {
// this also adds "golang" info to program properties
@@ -229,15 +310,14 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
return newMB.getStart();
}
- private void setupProgramContext(GoRttiMapper programContext, MarkupSession session)
+ private void setupProgramContext(GoRttiMapper goBinary, MarkupSession session)
throws IOException {
- Program program = programContext.getProgram();
- GoRegisterInfo goRegInfo = GoRegisterInfoManager.getInstance()
- .getRegisterInfoForLang(program.getLanguage(),
- programContext.getGolangVersion());
+ Program program = goBinary.getProgram();
+ GoRegisterInfo goRegInfo = goBinary.getRegInfo();
MemoryBlock txtMemblock = program.getMemory().getBlock(".text");
- if (txtMemblock != null && goRegInfo.getZeroRegister() != null) {
+ if (txtMemblock != null && goRegInfo.getZeroRegister() != null &&
+ !goRegInfo.isZeroRegisterIsBuiltin()) {
try {
program.getProgramContext()
.setValue(goRegInfo.getZeroRegister(), txtMemblock.getStart(),
@@ -248,9 +328,9 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
}
}
- int alignment = programContext.getPtrSize();
+ int alignment = goBinary.getPtrSize();
long sizeNeeded = 0;
-
+
Symbol zerobase = SymbolUtilities.getUniqueSymbol(program, "runtime.zerobase");
long zerobaseSymbol = sizeNeeded;
sizeNeeded += zerobase == null
@@ -258,13 +338,13 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
: 0;
long gStructOffset = sizeNeeded;
- Structure gStruct = programContext.getGhidraDataType("runtime.g", Structure.class);
+ Structure gStruct = goBinary.getGhidraDataType("runtime.g", Structure.class);
sizeNeeded += gStruct != null
? NumericUtilities.getUnsignedAlignedValue(gStruct.getLength(), alignment)
: 0;
long mStructOffset = sizeNeeded;
- Structure mStruct = programContext.getGhidraDataType("runtime.m", Structure.class);
+ Structure mStruct = goBinary.getGhidraDataType("runtime.m", Structure.class);
sizeNeeded += mStruct != null
? NumericUtilities.getUnsignedAlignedValue(mStruct.getLength(), alignment)
: 0;
@@ -304,16 +384,16 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
}
}
- private void createBootstrapGDT(GoRttiMapper programContext, Program program,
+ private void createBootstrapGDT(GoRttiMapper goBinary, Program program,
TaskMonitor monitor) throws IOException {
- GoVer goVer = programContext.getGolangVersion();
+ GoVer goVer = goBinary.getGolangVersion();
String osName = GoRttiMapper.getGolangOSString(program);
String gdtFilename =
- GoRttiMapper.getGDTFilename(goVer, programContext.getPtrSize(), osName);
+ GoRttiMapper.getGDTFilename(goVer, goBinary.getPtrSize(), osName);
gdtFilename =
gdtFilename.replace(".gdt", "_%d.gdt".formatted(System.currentTimeMillis()));
File gdt = new File(System.getProperty("user.home"), gdtFilename);
- programContext.exportTypesToGDT(gdt, monitor);
+ goBinary.exportTypesToGDT(gdt, monitor);
Msg.info(this, "Golang bootstrap GDT created: " + gdt);
}
@@ -323,7 +403,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
@Override
public boolean canAnalyze(Program program) {
- return "golang".equals(
+ return GoConstants.GOLANG_CSPEC_NAME.equals(
program.getCompilerSpec().getCompilerSpecDescription().getCompilerSpecName());
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/ProgramStartingLocationOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/ProgramStartingLocationOptions.java
index 7fe38e2dfe..6d01b34a4a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/ProgramStartingLocationOptions.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/ProgramStartingLocationOptions.java
@@ -60,7 +60,7 @@ public class ProgramStartingLocationOptions implements OptionsChangeListener {
"a newly discovered starting symbol, provided the user hasn't manually moved.";
private static final String DEFAULT_STARTING_SYMBOLS =
- "main, WinMain, libc_start_main, WinMainStartup, start, entry, main.main";
+ "main, WinMain, libc_start_main, WinMainStartup, main.main, start, entry";
public static enum StartLocationType {
LOWEST_ADDRESS("Lowest Address"),
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoConstants.java
index 0757feb6b1..8b4cbd2eb0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoConstants.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoConstants.java
@@ -21,8 +21,16 @@ import ghidra.program.model.data.CategoryPath;
* Misc constant values for golang
*/
public class GoConstants {
+ public static final String GOLANG_CSPEC_NAME = "golang";
+
/**
* Category path to place golang types in
*/
public static final CategoryPath GOLANG_CATEGORYPATH = new CategoryPath("/golang");
+
+ public static final String GOLANG_ABI_INTERNAL_CALLINGCONVENTION_NAME = "abi-internal";
+ public static final String GOLANG_ABI0_CALLINGCONVENTION_NAME = "abi0";
+ public static final String GOLANG_DUFFZERO_CALLINGCONVENTION_NAME = "duffzero";
+ public static final String GOLANG_DUFFCOPY_CALLINGCONVENTION_NAME = "duffcopy";
}
+
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java
index 34a928e93e..631fc1471c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfo.java
@@ -28,22 +28,24 @@ import ghidra.program.model.lang.Register;
*/
public class GoRegisterInfo {
- private List intRegisters;
- private List floatRegisters;
- private int stackInitialOffset;
- private int maxAlign; // 4 or 8
- private Register currentGoroutineRegister; // always points to g
- private Register zeroRegister; // always contains a zero value
+ private final List intRegisters;
+ private final List floatRegisters;
+ private final int stackInitialOffset;
+ private final int maxAlign; // 4 or 8
+ private final Register currentGoroutineRegister; // always points to g
+ private final Register zeroRegister; // always contains a zero value
+ private final boolean zeroRegisterIsBuiltin; // zero register is provided by cpu, or is manually set
GoRegisterInfo(List intRegisters, List floatRegisters,
int stackInitialOffset, int maxAlign, Register currentGoroutineRegister,
- Register zeroRegister) {
+ Register zeroRegister, boolean zeroRegisterIsBuiltin) {
this.intRegisters = intRegisters;
this.floatRegisters = floatRegisters;
this.stackInitialOffset = stackInitialOffset;
this.maxAlign = maxAlign;
this.currentGoroutineRegister = currentGoroutineRegister;
this.zeroRegister = zeroRegister;
+ this.zeroRegisterIsBuiltin = zeroRegisterIsBuiltin;
}
public int getIntRegisterSize() {
@@ -62,6 +64,10 @@ public class GoRegisterInfo {
return zeroRegister;
}
+ public boolean isZeroRegisterIsBuiltin() {
+ return zeroRegisterIsBuiltin;
+ }
+
public List getIntRegisters() {
return intRegisters;
}
@@ -76,11 +82,11 @@ public class GoRegisterInfo {
public int getAlignmentForType(DataType dt) {
while (dt instanceof TypeDef || dt instanceof Array) {
- if (dt instanceof TypeDef) {
- dt = ((TypeDef) dt).getBaseDataType();
+ if (dt instanceof TypeDef td) {
+ dt = td.getBaseDataType();
}
- if (dt instanceof Array) {
- dt = ((Array) dt).getDataType();
+ if (dt instanceof Array a) {
+ dt = a.getDataType();
}
}
if (isIntType(dt) && isIntrinsicSize(dt.getLength())) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java
index 078b679fba..ab2fd04905 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java
@@ -37,7 +37,7 @@ import ghidra.util.xml.XmlUtilities;
* <float_registers list="XMM0,XMM1,XMM2,XMM3,XMM4,XMM5,XMM6,XMM7,XMM8,XMM9,XMM10,XMM11,XMM12,XMM13,XMM14"/>
* <stack initialoffset="8" maxalign="8"/>
* <current_goroutine register="R14"/>
- * <zero_register register="XMM15"/>
+ * <zero_register register="XMM15" builtin="true|false"/>
* </register_info>
* <register_info versions="V1_2">
* ...
@@ -115,7 +115,7 @@ public class GoRegisterInfoManager {
}
@SuppressWarnings("unchecked")
- public Map readFrom(Element rootElem, Language lang)
+ private Map readFrom(Element rootElem, Language lang)
throws IOException {
Map result = new HashMap<>();
@@ -152,10 +152,12 @@ public class GoRegisterInfoManager {
Register currentGoRoutineReg =
parseRegStr(goRoutineElem.getAttributeValue("register"), lang);
Register zeroReg = parseRegStr(zeroRegElem.getAttributeValue("register"), lang);
+ boolean zeroRegIsBuiltin =
+ XmlUtilities.parseOptionalBooleanAttr(zeroRegElem, "builtin", false);
GoRegisterInfo registerInfo =
new GoRegisterInfo(intRegs, floatRegs, stackInitialOffset, maxAlign,
- currentGoRoutineReg, zeroReg);
+ currentGoRoutineReg, zeroReg, zeroRegIsBuiltin);
Map result = new HashMap<>();
for (GoVer goVer : validGoVersions) {
result.put(goVer, registerInfo);
@@ -165,7 +167,7 @@ public class GoRegisterInfoManager {
private GoRegisterInfo getDefault(Language lang) {
int goSize = lang.getInstructionAlignment();
- return new GoRegisterInfo(List.of(), List.of(), goSize, goSize, null, null);
+ return new GoRegisterInfo(List.of(), List.of(), goSize, goSize, null, null, false);
}
private List parseRegListStr(String s, Language lang) throws IOException {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoFunctabEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoFunctabEntry.java
index d39ba45f8c..e2d264597c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoFunctabEntry.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoFunctabEntry.java
@@ -66,6 +66,10 @@ public class GoFunctabEntry {
: null;
}
+ public long getFuncoff() {
+ return funcoff;
+ }
+
private GoModuledata getModuledata() {
return programContext.findContainingModuleByFuncData(context.getStructureStart());
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java
index d381010b2a..f607fe2f80 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoModuledata.java
@@ -128,6 +128,21 @@ public class GoModuledata implements StructureMarkup {
return pclntable.isOffsetWithinData(offset, 1);
}
+ /**
+ * Returns an artificial slice of the functab entries that are valid.
+ *
+ * @return artificial slice of the functab entries that are valid
+ */
+ public GoSlice getFunctabEntriesSlice() {
+ // chop off the last entry as it is not a full entry (it just points to the address
+ // at the end of the text segment) and can conflict with markup of the following structs
+ long sliceElementCount = ftab.getLen() > 0 ? ftab.getLen() - 1 : 0;
+ int entryLen =
+ programContext.getStructureMappingInfo(GoFunctabEntry.class).getStructureLength();
+ GoSlice subSlice = ftab.getSubSlice(0, sliceElementCount, entryLen);
+ return subSlice;
+ }
+
public boolean isValid() {
MemoryBlock txtBlock = programContext.getProgram().getMemory().getBlock(".text");
if (txtBlock != null && txtBlock.getStart().getOffset() != text) {
@@ -153,6 +168,16 @@ public class GoModuledata implements StructureMarkup {
return funcnametab;
}
+ public List getAllFunctionData() throws IOException {
+ List functabentries =
+ getFunctabEntriesSlice().readList(GoFunctabEntry.class);
+ List result = new ArrayList<>();
+ for (GoFunctabEntry functabEntry : functabentries) {
+ result.add(functabEntry.getFuncData());
+ }
+ return result;
+ }
+
@Override
public StructureContext getStructureContext() {
return structureContext;
@@ -168,15 +193,9 @@ public class GoModuledata implements StructureMarkup {
markupStringTable(funcnametab.getArrayAddress(), funcnametab.getLen(), session);
markupStringTable(filetab.getArrayAddress(), filetab.getLen(), session);
- if (ftab.getLen() > 0) {
- // chop off the last entry as it is not a full entry (it just points to the address
- // at the end of the text segment) and can conflict with markup of the following structs
- int entryLen =
- programContext.getStructureMappingInfo(GoFunctabEntry.class).getStructureLength();
- GoSlice subSlice = ftab.getSubSlice(0, ftab.getLen() - 1, entryLen);
- subSlice.markupArray("moduledata.ftab", GoFunctabEntry.class, false, session);
- subSlice.markupArrayElements(GoFunctabEntry.class, session);
- }
+ GoSlice subSlice = getFunctabEntriesSlice();
+ subSlice.markupArray("moduledata.ftab", GoFunctabEntry.class, false, session);
+ subSlice.markupArrayElements(GoFunctabEntry.class, session);
Structure textsectDT =
programContext.getGhidraDataType("runtime.textsect", Structure.class);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java
index 69d5ae94f3..67a15279dd 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java
@@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.golang.rtti;
import java.io.File;
import java.io.IOException;
import java.util.*;
+import java.util.Map.Entry;
import java.util.stream.Collectors;
import generic.jar.ResourceFile;
@@ -34,9 +35,13 @@ import ghidra.app.util.opinion.PeLoader;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Endian;
+import ghidra.program.model.lang.PrototypeModel;
+import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock;
+import ghidra.program.model.symbol.Symbol;
+import ghidra.program.model.symbol.SymbolType;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
import ghidra.util.exception.CancelledException;
@@ -197,8 +202,15 @@ public class GoRttiMapper extends DataTypeMapper {
private final Map typeNameIndex = new HashMap<>();
private final Map cachedRecoveredDataTypes = new HashMap<>();
private final List modules = new ArrayList<>();
+ private Map funcdataByAddr = new HashMap<>();
+ private Map funcdataByName = new HashMap<>();
private GoType mapGoType;
private GoType chanGoType;
+ private GoRegisterInfo regInfo;
+ private PrototypeModel abiInternalCallingConvention;
+ private PrototypeModel abi0CallingConvention;
+ private PrototypeModel duffzeroCallingConvention;
+ private PrototypeModel duffcopyCallingConvention;
/**
* Creates a GoRttiMapper using the specified bootstrap information.
@@ -259,6 +271,41 @@ public class GoRttiMapper extends DataTypeMapper {
return goVersion;
}
+ public GoRegisterInfo getRegInfo() {
+ return regInfo;
+ }
+
+ public void init(TaskMonitor monitor) throws IOException {
+ initHiddenCompilerTypes();
+
+ this.regInfo = GoRegisterInfoManager.getInstance()
+ .getRegisterInfoForLang(program.getLanguage(), goVersion);
+
+ this.abiInternalCallingConvention = program.getFunctionManager()
+ .getCallingConvention(GoConstants.GOLANG_ABI_INTERNAL_CALLINGCONVENTION_NAME);
+ this.abi0CallingConvention = program.getFunctionManager()
+ .getCallingConvention(GoConstants.GOLANG_ABI0_CALLINGCONVENTION_NAME);
+ this.duffzeroCallingConvention = program.getFunctionManager()
+ .getCallingConvention(GoConstants.GOLANG_DUFFZERO_CALLINGCONVENTION_NAME);
+ this.duffcopyCallingConvention = program.getFunctionManager()
+ .getCallingConvention(GoConstants.GOLANG_DUFFCOPY_CALLINGCONVENTION_NAME);
+
+ GoModuledata firstModule = findFirstModuledata(monitor);
+ if (firstModule != null) {
+ addModule(firstModule);
+ }
+ initFuncdata();
+ }
+
+ private void initFuncdata() throws IOException {
+ for (GoModuledata module : modules) {
+ for (GoFuncData funcdata : module.getAllFunctionData()) {
+ funcdataByAddr.put(funcdata.getFuncAddress(), funcdata);
+ funcdataByName.put(funcdata.getName(), funcdata);
+ }
+ }
+ }
+
/**
* Returns the first module data instance
*
@@ -277,6 +324,40 @@ public class GoRttiMapper extends DataTypeMapper {
modules.add(module);
}
+ public GoParamStorageAllocator getStorageAllocator() {
+ GoParamStorageAllocator storageAllocator = new GoParamStorageAllocator(program, goVersion);
+ return storageAllocator;
+ }
+
+ public boolean isGolangAbi0Func(Function func) {
+ Address funcAddr = func.getEntryPoint();
+ for (Symbol symbol : func.getProgram().getSymbolTable().getSymbolsAsIterator(funcAddr)) {
+ if (symbol.getSymbolType() == SymbolType.LABEL) {
+ String labelName = symbol.getName();
+ if (labelName.endsWith("abi0")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public PrototypeModel getAbi0CallingConvention() {
+ return abi0CallingConvention;
+ }
+
+ public PrototypeModel getAbiInternalCallingConvention() {
+ return abiInternalCallingConvention;
+ }
+
+ public PrototypeModel getDuffzeroCallingConvention() {
+ return duffzeroCallingConvention;
+ }
+
+ public PrototypeModel getDuffcopyCallingConvention() {
+ return duffcopyCallingConvention;
+ }
+
/**
* Finds the {@link GoModuledata} that contains the specified offset.
*
@@ -415,6 +496,13 @@ public class GoRttiMapper extends DataTypeMapper {
return getGoType(addr.getOffset());
}
+ public GoType getLastGoType() {
+ Optional> max = goTypes.entrySet()
+ .stream()
+ .max((o1, o2) -> o1.getKey().compareTo(o2.getKey()));
+ return max.isPresent() ? max.get().getValue() : null;
+ }
+
/**
* Finds a go type by its go-type name, from the list of
* {@link #discoverGoTypes(TaskMonitor) discovered} go types.
@@ -662,33 +750,28 @@ public class GoRttiMapper extends DataTypeMapper {
* @throws CancelledException if cancelled
*/
public void discoverGoTypes(TaskMonitor monitor) throws IOException, CancelledException {
- GoModuledata firstModule = findFirstModuledata(monitor);
- if (firstModule == null) {
- return;
- }
- addModule(firstModule);
-
UnknownProgressWrappingTaskMonitor upwtm =
new UnknownProgressWrappingTaskMonitor(monitor, 50);
upwtm.setMessage("Iterating Golang RTTI types");
upwtm.initialize(0);
goTypes.clear();
- Set discoveredTypes = new HashSet<>();
- for (Iterator it = firstModule.iterateTypes(); it.hasNext();) {
- upwtm.checkCancelled();
- upwtm.setProgress(discoveredTypes.size());
-
- GoType type = it.next();
- type.discoverGoTypes(discoveredTypes);
- }
typeNameIndex.clear();
+ Set discoveredTypes = new HashSet<>();
+ for (GoModuledata module : modules) {
+ for (Iterator it = module.iterateTypes(); it.hasNext();) {
+ upwtm.checkCancelled();
+ upwtm.setProgress(discoveredTypes.size());
+
+ GoType type = it.next();
+ type.discoverGoTypes(discoveredTypes);
+ }
+ }
for (GoType goType : goTypes.values()) {
String typeName = goType.getNameString();
typeNameIndex.put(typeName, goType);
}
Msg.info(this, "Found %d golang types".formatted(goTypes.size()));
- initHiddenCompilerTypes();
}
/**
@@ -764,6 +847,18 @@ public class GoRttiMapper extends DataTypeMapper {
return offset != 0 ? readStructure(GoName.class, offset) : null;
}
+ public GoFuncData getFunctionData(Address funcAddr) throws IOException {
+ return funcdataByAddr.get(funcAddr);
+ }
+
+ public GoFuncData getFunctionByName(String funcName) {
+ return funcdataByName.get(funcName);
+ }
+
+ public List getAllFunctions() throws IOException {
+ return new ArrayList<>(funcdataByAddr.values());
+ }
+
//--------------------------------------------------------------------------------------------
private void initHiddenCompilerTypes() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSlice.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSlice.java
index fb9131d7f6..680b34a8aa 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSlice.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoSlice.java
@@ -94,6 +94,13 @@ public class GoSlice {
return programContext.getDataAddress(array);
}
+ public long getArrayEnd(Class> elementClass) {
+ StructureMappingInfo> elementSMI =
+ context.getDataTypeMapper().getStructureMappingInfo(elementClass);
+ int elementLength = elementSMI.getStructureLength();
+ return array + len * elementLength;
+ }
+
public long getLen() {
return len;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java
index a5427f81c8..36ce223a2e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoPlainType.java
@@ -15,9 +15,8 @@
*/
package ghidra.app.util.bin.format.golang.rtti.types;
-import java.util.Set;
-
import java.io.IOException;
+import java.util.Set;
import ghidra.app.util.bin.format.golang.rtti.GoString;
import ghidra.app.util.bin.format.golang.structmapping.StructureMapping;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java
index 748ae1e166..f31ec7f527 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java
@@ -56,6 +56,11 @@ public class GoStructType extends GoType {
return fields.readList(GoStructField.class);
}
+ @Override
+ public long getEndOfTypeInfo() throws IOException {
+ return fields.getArrayEnd(GoStructField.class);
+ }
+
@Override
public void additionalMarkup(MarkupSession session) throws IOException {
super.additionalMarkup(session);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java
index a1da8b9a73..c359a21cc4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoType.java
@@ -92,6 +92,19 @@ public abstract class GoType implements StructureMarkup {
: 0);
}
+ /**
+ * Returns the location of where this type object, and any known associated optional
+ * structures ends.
+ *
+ * @return index location of end of this type object
+ * @throws IOException if error reading
+ */
+ public long getEndOfTypeInfo() throws IOException {
+ return typ.hasUncommonType()
+ ? getUncommonType().getEndOfTypeInfo()
+ : context.getStructureEnd();
+ }
+
@Markup
public GoUncommonType getUncommonType() throws IOException {
return typ.hasUncommonType()
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoUncommonType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoUncommonType.java
index 0f8684fa5e..4e514466dc 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoUncommonType.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoUncommonType.java
@@ -15,9 +15,8 @@
*/
package ghidra.app.util.bin.format.golang.rtti.types;
-import java.util.List;
-
import java.io.IOException;
+import java.util.List;
import ghidra.app.util.bin.format.golang.rtti.*;
import ghidra.app.util.bin.format.golang.structmapping.*;
@@ -70,4 +69,18 @@ public class GoUncommonType {
return slice.readList(GoMethod.class);
}
+ /**
+ * Returns the location of where this object, and any known associated optional
+ * structures ends.
+ *
+ * @return index location of end of this type object
+ */
+ public long getEndOfTypeInfo() {
+ if (mcount == 0) {
+ return context.getStructureEnd();
+ }
+ GoSlice slice = getMethodsSlice();
+ return slice.getArrayEnd(GoMethod.class);
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java
index 23b353b7e1..b20294bdee 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java
@@ -342,7 +342,7 @@ public class FunctionUtility {
* @param function the function
* @return true if the function has a default name.
*/
- static boolean isDefaultFunctionName(Function function) {
+ public static boolean isDefaultFunctionName(Function function) {
String defaultFunctionName =
SymbolUtilities.getDefaultFunctionName(function.getEntryPoint());
return defaultFunctionName.equals(function.getName());
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/analysis/GolangDuffFixupAnalyzer.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/analysis/GolangDuffFixupAnalyzer.java
new file mode 100644
index 0000000000..ea724859a6
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/analysis/GolangDuffFixupAnalyzer.java
@@ -0,0 +1,191 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.plugin.core.analysis;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import ghidra.app.cmd.comments.SetCommentCmd;
+import ghidra.app.decompiler.DecompInterface;
+import ghidra.app.decompiler.DecompileResults;
+import ghidra.app.decompiler.parallel.DecompilerCallback;
+import ghidra.app.decompiler.parallel.ParallelDecompiler;
+import ghidra.app.services.*;
+import ghidra.app.util.bin.format.golang.GoConstants;
+import ghidra.app.util.importer.MessageLog;
+import ghidra.program.model.address.*;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.listing.Function.FunctionUpdateType;
+import ghidra.program.model.pcode.HighFunction;
+import ghidra.program.model.pcode.PcodeBlockBasic;
+import ghidra.program.model.symbol.*;
+import ghidra.program.util.FunctionUtility;
+import ghidra.util.Msg;
+import ghidra.util.exception.*;
+import ghidra.util.task.TaskMonitor;
+
+public class GolangDuffFixupAnalyzer extends AbstractAnalyzer {
+ private final static String NAME = "Golang Duff Function Fixup";
+ private final static String DESCRIPTION = """
+ Propagates function signature information from the base runtime.duffcopy \
+ and runtime.duffzero functions to the other entry points that were discovered \
+ during analysis.""";
+
+ private Program program;
+ private TaskMonitor monitor;
+ private MessageLog log;
+
+ public GolangDuffFixupAnalyzer() {
+ super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
+ setPriority(AnalysisPriority.FUNCTION_ANALYSIS.after());
+ setDefaultEnablement(true);
+ }
+
+ @Override
+ public boolean canAnalyze(Program program) {
+ return GoConstants.GOLANG_CSPEC_NAME.equals(
+ program.getCompilerSpec().getCompilerSpecDescription().getCompilerSpecName());
+ }
+
+ @Override
+ public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
+ throws CancelledException {
+ this.program = program;
+ this.monitor = monitor;
+ this.log = log;
+
+ Symbol duffzeroSym = SymbolUtilities.getUniqueSymbol(program, "runtime.duffzero");
+ Function duffzeroFunc = duffzeroSym != null ? (Function) duffzeroSym.getObject() : null;
+ Symbol duffcopySym = SymbolUtilities.getUniqueSymbol(program, "runtime.duffcopy");
+ Function duffcopyFunc = duffcopySym != null ? (Function) duffcopySym.getObject() : null;
+
+ List funcs = new ArrayList<>();
+ if (duffzeroFunc != null && duffzeroFunc.getCallingConvention() != null) {
+ funcs.add(duffzeroFunc);
+ }
+ if (duffcopyFunc != null && duffcopyFunc.getCallingConvention() != null) {
+ funcs.add(duffcopyFunc);
+ }
+
+ if (funcs.isEmpty()) {
+ return true;
+ }
+
+ Map map = getFunctionActualRanges(funcs);
+
+ if (duffzeroFunc != null) {
+ updateDuffFuncs(duffzeroFunc, map.get(duffzeroFunc.getEntryPoint()));
+ }
+ if (duffcopyFunc != null) {
+ updateDuffFuncs(duffcopyFunc, map.get(duffcopyFunc.getEntryPoint()));
+ }
+
+ return true;
+ }
+
+ /**
+ * Copy details from the base duff function to any other unnamed functions that start within
+ * the base duff function's range.
+ *
+ * @param duffFunc base duff function
+ * @param duffFuncBody the addresses the base function occupies
+ */
+ private void updateDuffFuncs(Function duffFunc, AddressSetView duffFuncBody) {
+ if (duffFunc == null || duffFuncBody == null) {
+ return;
+ }
+ String duffComment = program.getListing()
+ .getCodeUnitAt(duffFunc.getEntryPoint())
+ .getComment(CodeUnit.PLATE_COMMENT);
+ for (FunctionIterator funcIt =
+ program.getFunctionManager().getFunctions(duffFuncBody, true); funcIt.hasNext();) {
+ Function func = funcIt.next();
+ if (!FunctionUtility.isDefaultFunctionName(func)) {
+ continue;
+ }
+ try {
+ func.setName(duffFunc.getName() + "_" + func.getEntryPoint(), SourceType.ANALYSIS);
+ func.updateFunction(duffFunc.getCallingConventionName(), duffFunc.getReturn(),
+ Arrays.asList(duffFunc.getParameters()),
+ FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.ANALYSIS);
+ if (duffComment != null && !duffComment.isBlank()) {
+ new SetCommentCmd(func.getEntryPoint(), CodeUnit.PLATE_COMMENT, duffComment)
+ .applyTo(program);
+ }
+ }
+ catch (DuplicateNameException | InvalidInputException e) {
+ log.appendMsg("Error updating duff functions");
+ log.appendException(e);
+ }
+ }
+ }
+
+ private void configureDecompiler(DecompInterface decompiler) {
+ decompiler.toggleCCode(false); //only need syntax tree
+ decompiler.toggleSyntaxTree(true); // Produce syntax tree
+ decompiler.setSimplificationStyle("normalize");
+ }
+
+ record HighFunctionAddresses(Address functionEntry, AddressSetView functionAddresses) {}
+
+ /**
+ * Returns the addresses that a function occupies (as determined by the decompiler instead of
+ * the disassembler).
+ *
+ * @param funcs list of functions
+ * @return map of function entry point and addresses for that function
+ */
+ private Map getFunctionActualRanges(List funcs) {
+ DecompilerCallback callback =
+ new DecompilerCallback<>(program, this::configureDecompiler) {
+ @Override
+ public HighFunctionAddresses process(DecompileResults results, TaskMonitor tMonitor)
+ throws Exception {
+ tMonitor.checkCancelled();
+ if (results == null) {
+ return null;
+ }
+ Function func = results.getFunction();
+ HighFunction highFunc = results.getHighFunction();
+ if (func == null || highFunc == null) {
+ return null;
+ }
+ AddressSet funcAddrs = new AddressSet();
+ for (PcodeBlockBasic bb : highFunc.getBasicBlocks()) {
+ funcAddrs.add(bb.getStart(), bb.getStop());
+ }
+ return new HighFunctionAddresses(func.getEntryPoint(), funcAddrs);
+ }
+ };
+
+ try {
+ List funcAddresses =
+ ParallelDecompiler.decompileFunctions(callback, funcs, monitor);
+ Map results = funcAddresses.stream()
+ .collect(
+ Collectors.toMap(hfa -> hfa.functionEntry, hfa -> hfa.functionAddresses));
+ return results;
+ }
+ catch (Exception e) {
+ Msg.error(this, "Error: could not decompile functions with ParallelDecompiler", e);
+ return Map.of();
+ }
+ finally {
+ callback.dispose();
+ }
+ }
+
+}
diff --git a/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec b/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec
index c50e47e186..0087f87e83 100644
--- a/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec
+++ b/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec
@@ -51,6 +51,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec b/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec
index ab250c7b26..8196a9a68e 100644
--- a/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec
+++ b/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec
@@ -178,6 +178,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+