mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-21 19:42:14 +00:00
Merge remote-tracking branch 'origin/GP-4465_dev747368_golang_macho_applesilicon--SQUASHED'
This commit is contained in:
commit
75d5737cce
@ -1,4 +1,7 @@
|
||||
# Golang function names which do not return
|
||||
|
||||
#runtime.abort and runtime.systemstack_switch intentionally have bytes that can cause undefined instruction errors in Ghidra
|
||||
runtime.abort
|
||||
runtime.abort.abi0
|
||||
runtime.exit.abi0
|
||||
runtime.dieFromSignal
|
||||
@ -7,6 +10,12 @@ runtime.fatal
|
||||
runtime.fatalthrow
|
||||
runtime.fatalpanic
|
||||
runtime.throw
|
||||
runtime.systemstack_switch
|
||||
runtime.newstack
|
||||
runtime.newstack.abi0
|
||||
runtime.mstart
|
||||
runtime.mstart.abi0
|
||||
runtime.mstart0
|
||||
|
||||
runtime.gopanic
|
||||
runtime.goPanicExtendIndex
|
||||
|
@ -9,6 +9,9 @@
|
||||
<functionNamesFile>ElfFunctionsThatDoNotReturn</functionNamesFile>
|
||||
</executable_format>
|
||||
<executable_format name="Mac OS X Mach-O">
|
||||
<compiler id="golang">
|
||||
<functionNamesFile>GolangFunctionsThatDoNotReturn</functionNamesFile>
|
||||
</compiler>
|
||||
<functionNamesFile>MachOFunctionsThatDoNotReturn</functionNamesFile>
|
||||
</executable_format>
|
||||
<executable_format name="DYLD Cache">
|
||||
|
@ -179,13 +179,13 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
||||
private void markupWellknownSymbols() throws IOException {
|
||||
Program program = goBinary.getProgram();
|
||||
|
||||
Symbol g0 = SymbolUtilities.getUniqueSymbol(program, "runtime.g0");
|
||||
Symbol g0 = goBinary.getGoSymbol("runtime.g0");
|
||||
Structure gStruct = goBinary.getGhidraDataType("runtime.g", Structure.class);
|
||||
if (g0 != null && gStruct != null) {
|
||||
markupSession.markupAddressIfUndefined(g0.getAddress(), gStruct);
|
||||
}
|
||||
|
||||
Symbol m0 = SymbolUtilities.getUniqueSymbol(program, "runtime.m0");
|
||||
Symbol m0 = goBinary.getGoSymbol("runtime.m0");
|
||||
Structure mStruct = goBinary.getGhidraDataType("runtime.m", Structure.class);
|
||||
if (m0 != null && mStruct != null) {
|
||||
markupSession.markupAddressIfUndefined(m0.getAddress(), mStruct);
|
||||
@ -416,13 +416,13 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
||||
Program program = goBinary.getProgram();
|
||||
GoRegisterInfo goRegInfo = goBinary.getRegInfo();
|
||||
|
||||
MemoryBlock txtMemblock = program.getMemory().getBlock(".text");
|
||||
if (txtMemblock != null && goRegInfo.getZeroRegister() != null &&
|
||||
!goRegInfo.isZeroRegisterIsBuiltin()) {
|
||||
if (goRegInfo.getZeroRegister() != null && !goRegInfo.isZeroRegisterIsBuiltin()) {
|
||||
try {
|
||||
for (AddressRange textRange : goBinary.getTextAddresses().getAddressRanges()) {
|
||||
program.getProgramContext()
|
||||
.setValue(goRegInfo.getZeroRegister(), txtMemblock.getStart(),
|
||||
txtMemblock.getEnd(), BigInteger.ZERO);
|
||||
.setValue(goRegInfo.getZeroRegister(), textRange.getMinAddress(),
|
||||
textRange.getMaxAddress(), BigInteger.ZERO);
|
||||
}
|
||||
}
|
||||
catch (ContextChangeException e) {
|
||||
Msg.error(this, "Unexpected Error", e);
|
||||
@ -432,7 +432,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
||||
int alignment = goBinary.getPtrSize();
|
||||
long sizeNeeded = 0;
|
||||
|
||||
Symbol zerobase = SymbolUtilities.getUniqueSymbol(program, "runtime.zerobase");
|
||||
Symbol zerobase = goBinary.getGoSymbol("runtime.zerobase");
|
||||
long zerobaseSymbol = sizeNeeded;
|
||||
sizeNeeded += zerobase == null
|
||||
? NumericUtilities.getUnsignedAlignedValue(1 /* sizeof(byte) */, alignment)
|
||||
@ -464,14 +464,16 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
||||
markupSession.labelAddress(gAddr, "CURRENT_G");
|
||||
|
||||
Register currentGoroutineReg = goRegInfo.getCurrentGoroutineRegister();
|
||||
if (currentGoroutineReg != null && txtMemblock != null) {
|
||||
if (currentGoroutineReg != null) {
|
||||
// currentGoroutineReg is set in a platform's arch-golang.register.info in
|
||||
// the <current_goroutine> element for arch's that have a dedicated processor
|
||||
// register that points at G
|
||||
try {
|
||||
for (AddressRange textRange : goBinary.getTextAddresses().getAddressRanges()) {
|
||||
program.getProgramContext()
|
||||
.setValue(currentGoroutineReg, txtMemblock.getStart(),
|
||||
txtMemblock.getEnd(), gAddr.getOffsetAsBigInteger());
|
||||
.setValue(currentGoroutineReg, textRange.getMinAddress(),
|
||||
textRange.getMaxAddress(), gAddr.getOffsetAsBigInteger());
|
||||
}
|
||||
}
|
||||
catch (ContextChangeException e) {
|
||||
Msg.error(this, "Unexpected Error", e);
|
||||
@ -582,6 +584,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
||||
int callingFunctionCount;
|
||||
|
||||
public PropagateRttiBackgroundCommand(GoRttiMapper goBinary) {
|
||||
super("Golang RTTI Propagation (deferred)", true, true, false);
|
||||
this.goBinary = goBinary;
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,9 @@ public interface ElfInfoItem {
|
||||
*/
|
||||
void markupProgram(Program program, Address address);
|
||||
|
||||
public record ItemWithAddress<T> (T item, Address address) {};
|
||||
public interface ReaderFunc<T extends ElfInfoItem> {
|
||||
public record ItemWithAddress<T>(T item, Address address) {}
|
||||
|
||||
public interface ReaderFunc<T> {
|
||||
T read(BinaryReader br, Program program) throws IOException;
|
||||
}
|
||||
|
||||
@ -50,7 +51,7 @@ public interface ElfInfoItem {
|
||||
* @param sectionName name of memory section that contains the item
|
||||
* @param readFunc {@link ReaderFunc} that will deserialize an instance of the item
|
||||
*/
|
||||
public static void markupElfInfoItemSection(Program program, String sectionName,
|
||||
static void markupElfInfoItemSection(Program program, String sectionName,
|
||||
ReaderFunc<ElfInfoItem> readFunc) {
|
||||
ItemWithAddress<ElfInfoItem> wrappedItem =
|
||||
readItemFromSection(program, sectionName, readFunc);
|
||||
@ -69,9 +70,13 @@ public interface ElfInfoItem {
|
||||
* @return a wrapped instance of the item, or null if the memory section does not exist
|
||||
* or there was an error while reading the item from the section
|
||||
*/
|
||||
public static <T extends ElfInfoItem> ItemWithAddress<T> readItemFromSection(Program program,
|
||||
static <T extends ElfInfoItem> ItemWithAddress<T> readItemFromSection(Program program,
|
||||
String sectionName, ReaderFunc<T> readFunc) {
|
||||
MemoryBlock memBlock = program.getMemory().getBlock(sectionName);
|
||||
return readItemFromSection(program, program.getMemory().getBlock(sectionName), readFunc);
|
||||
}
|
||||
|
||||
static <T extends ElfInfoItem> ItemWithAddress<T> readItemFromSection(Program program,
|
||||
MemoryBlock memBlock, ReaderFunc<T> readFunc) {
|
||||
if (memBlock != null) {
|
||||
try (ByteProvider bp =
|
||||
MemoryByteProvider.createMemoryBlockByteProvider(program.getMemory(), memBlock)) {
|
||||
@ -82,10 +87,9 @@ public interface ElfInfoItem {
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.warn(ElfInfoItem.class,
|
||||
"Unable to read Elf item in section: %s".formatted(sectionName), e);
|
||||
"Unable to read Elf item in section: %s".formatted(memBlock.getName()), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,49 +20,52 @@ import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteArrayProvider;
|
||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem.ItemWithAddress;
|
||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem.ReaderFunc;
|
||||
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* Similar to {@link NoteGoBuildId}, but re-implemented here because of the different
|
||||
* serialization used in PE binaries. (the logic about the buildid payload is trivial so
|
||||
* there is no worry about duplicating code)
|
||||
* This class represents a go build id string, along with a magic header.
|
||||
* <p>
|
||||
*
|
||||
* Similar to {@link NoteGoBuildId}, but re-implemented here because of the different
|
||||
* serialization used.
|
||||
*/
|
||||
public class PEGoBuildId implements ElfInfoItem {
|
||||
public class GoBuildId {
|
||||
private static final byte[] GO_BUILDID_MAGIC =
|
||||
"\u00ff Go build ID: \"".getBytes(StandardCharsets.ISO_8859_1);
|
||||
private static final int BUILDID_STR_LEN = 83;
|
||||
|
||||
public static ItemWithAddress<PEGoBuildId> findBuildId(Program program) {
|
||||
ItemWithAddress<PEGoBuildId> wrappedItem = ElfInfoItem.readItemFromSection(program,
|
||||
".text", PEGoBuildId::read);
|
||||
public static ItemWithAddress<GoBuildId> findBuildId(Program program) {
|
||||
MemoryBlock txtBlock = GoRttiMapper.getGoSection(program, "text");
|
||||
ItemWithAddress<GoBuildId> wrappedItem =
|
||||
readItemFromSection(program, txtBlock, GoBuildId::read);
|
||||
return wrappedItem;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to read a PEGoBuildId from the specified stream.
|
||||
* Attempts to read a GoBuildId from the specified stream.
|
||||
*
|
||||
* @param br BinaryReader stream (typically the beginning of the ".text" section)
|
||||
* @param program_notused not used, but needed to match functional interface
|
||||
* @return PEGoBuildId instance, or null if not present
|
||||
* @return GoBuildId instance, or null if not present
|
||||
*/
|
||||
public static PEGoBuildId read(BinaryReader br, Program program_notused) {
|
||||
public static GoBuildId read(BinaryReader br, Program program_notused) {
|
||||
try {
|
||||
byte[] magic = br.readNextByteArray(GO_BUILDID_MAGIC.length);
|
||||
if (!Arrays.equals(magic, GO_BUILDID_MAGIC)) {
|
||||
return null;
|
||||
}
|
||||
String buildIdStr = br.readNextAsciiString(BUILDID_STR_LEN);
|
||||
return new PEGoBuildId(buildIdStr);
|
||||
return new GoBuildId(buildIdStr);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// fall thru and return null
|
||||
@ -71,13 +74,13 @@ public class PEGoBuildId implements ElfInfoItem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read a PEGoBuildId from the specified InputStream (useful for early compiler
|
||||
* Attempts to read a GoBuildId from the specified InputStream (useful for early compiler
|
||||
* detection before file is loaded).
|
||||
*
|
||||
* @param is {@link InputStream} providing access to the ".text" section of a PE binary
|
||||
* @return PEGoBuildId instance, or null if not present
|
||||
* @return GoBuildId instance, or null if not present
|
||||
*/
|
||||
public static PEGoBuildId read(InputStream is) {
|
||||
public static GoBuildId read(InputStream is) {
|
||||
byte[] buffer = new byte[GO_BUILDID_MAGIC.length + BUILDID_STR_LEN];
|
||||
try {
|
||||
int bytesRead = is.read(buffer);
|
||||
@ -94,7 +97,7 @@ public class PEGoBuildId implements ElfInfoItem {
|
||||
|
||||
private final String buildId;
|
||||
|
||||
public PEGoBuildId(String buildId) {
|
||||
public GoBuildId(String buildId) {
|
||||
this.buildId = buildId;
|
||||
}
|
||||
|
||||
@ -102,7 +105,6 @@ public class PEGoBuildId implements ElfInfoItem {
|
||||
return buildId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markupProgram(Program program, Address address) {
|
||||
program.getOptions(Program.PROGRAM_INFO)
|
||||
.setString(NoteGoBuildId.PROGRAM_INFO_KEY, getBuildId());
|
||||
@ -115,7 +117,7 @@ public class PEGoBuildId implements ElfInfoItem {
|
||||
}
|
||||
}
|
||||
catch (CodeUnitInsertionException e) {
|
||||
Msg.error(this, "Failed to markup PEGoBuildId at %s: %s".formatted(address, this));
|
||||
Msg.error(this, "Failed to markup GoBuildId at %s: %s".formatted(address, this));
|
||||
}
|
||||
|
||||
}
|
||||
@ -128,4 +130,24 @@ public class PEGoBuildId implements ElfInfoItem {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
static <T> ItemWithAddress<T> readItemFromSection(Program program, MemoryBlock memBlock,
|
||||
ReaderFunc<T> readFunc) {
|
||||
if (memBlock != null) {
|
||||
try (ByteProvider bp =
|
||||
MemoryByteProvider.createMemoryBlockByteProvider(program.getMemory(), memBlock)) {
|
||||
BinaryReader br = new BinaryReader(bp, !program.getMemory().isBigEndian());
|
||||
|
||||
T item = readFunc.read(br, program);
|
||||
return item != null ? new ItemWithAddress<>(item, memBlock.getStart()) : null;
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.warn(GoBuildId.class,
|
||||
"Unable to read GoBuildId in section: %s".formatted(memBlock.getName()), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -24,12 +24,14 @@ import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem;
|
||||
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||
import ghidra.program.model.lang.Endian;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.*;
|
||||
|
||||
@ -39,7 +41,9 @@ import ghidra.util.*;
|
||||
*/
|
||||
public class GoBuildInfo implements ElfInfoItem {
|
||||
|
||||
public static final String SECTION_NAME = ".go.buildinfo";
|
||||
public static final String SECTION_NAME = "go.buildinfo";
|
||||
public static final String ELF_SECTION_NAME = ".go.buildinfo";
|
||||
public static final String MACHO_SECTION_NAME = "go_buildinfo";
|
||||
|
||||
// Defined in golang src/debug/buildinfo/buildinfo.go
|
||||
// NOTE: ISO_8859_1 charset is required to not mangle the \u00ff when converting to bytes
|
||||
@ -73,17 +77,32 @@ public class GoBuildInfo implements ElfInfoItem {
|
||||
* @return new {@link GoBuildInfo} instance, if present, null if missing or error
|
||||
*/
|
||||
public static ItemWithAddress<GoBuildInfo> findBuildInfo(Program program) {
|
||||
// try as if binary is ELF
|
||||
ItemWithAddress<GoBuildInfo> wrappedItem =
|
||||
ElfInfoItem.readItemFromSection(program, SECTION_NAME, GoBuildInfo::read);
|
||||
ItemWithAddress<GoBuildInfo> wrappedItem = readItemFromSection(program,
|
||||
GoRttiMapper.getFirstGoSection(program, SECTION_NAME, MACHO_SECTION_NAME));
|
||||
if (wrappedItem == null) {
|
||||
// if not present, try common PE location for buildinfo, using "ElfInfoItem" logic
|
||||
// even though this might be a PE binary, cause it doesn't matter
|
||||
wrappedItem = ElfInfoItem.readItemFromSection(program, ".data", GoBuildInfo::read);
|
||||
// if not present, try common PE location for buildinfo
|
||||
wrappedItem = readItemFromSection(program, GoRttiMapper.getGoSection(program, "data"));
|
||||
}
|
||||
return wrappedItem;
|
||||
}
|
||||
|
||||
private static ItemWithAddress<GoBuildInfo> readItemFromSection(Program program,
|
||||
MemoryBlock memBlock) {
|
||||
if (memBlock != null) {
|
||||
try (ByteProvider bp =
|
||||
MemoryByteProvider.createMemoryBlockByteProvider(program.getMemory(), memBlock)) {
|
||||
BinaryReader br = new BinaryReader(bp, !program.getMemory().isBigEndian());
|
||||
|
||||
GoBuildInfo item = read(br, program);
|
||||
return new ItemWithAddress<>(item, memBlock.getStart());
|
||||
}
|
||||
catch (IOException e) {
|
||||
// fall thru, return null
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a GoBuildInfo ".go.buildinfo" section from the specified stream.
|
||||
*
|
||||
|
@ -150,7 +150,7 @@ public class GoFunctionFixup {
|
||||
paramDT.getLength());
|
||||
VariableStorage varStorage = new VariableStorage(program, List.of(stackVarnode));
|
||||
LocalVariableImpl localVar =
|
||||
new LocalVariableImpl(param.getName() + "-spill", 0, paramDT, varStorage, program);
|
||||
new LocalVariableImpl(param.getName() + "_spill", 0, paramDT, varStorage, program);
|
||||
|
||||
// TODO: needs more thought
|
||||
func.addLocalVariable(localVar, SourceType.USER_DEFINED);
|
||||
@ -229,12 +229,12 @@ public class GoFunctionFixup {
|
||||
returnDT = multiReturn.getStruct();
|
||||
|
||||
for (DataTypeComponent dtc : multiReturn.getNormalStorageComponents()) {
|
||||
allocateReturnStorage(program, dtc.getFieldName() + "-return-result-alias",
|
||||
allocateReturnStorage(program, dtc.getFieldName() + "_return_result_alias",
|
||||
dtc.getDataType(), storageAllocator, varnodes, returnResultAliasVars,
|
||||
false);
|
||||
}
|
||||
for (DataTypeComponent dtc : multiReturn.getStackStorageComponents()) {
|
||||
allocateReturnStorage(program, dtc.getFieldName() + "-return-result-alias",
|
||||
allocateReturnStorage(program, dtc.getFieldName() + "_return_result_alias",
|
||||
dtc.getDataType(), storageAllocator, varnodes, returnResultAliasVars,
|
||||
false);
|
||||
}
|
||||
@ -249,7 +249,7 @@ public class GoFunctionFixup {
|
||||
varnodes.add(new Varnode(GoRttiMapper.getZerobaseAddress(program), 1));
|
||||
}
|
||||
else {
|
||||
allocateReturnStorage(program, "return-value-alias-variable", returnDT,
|
||||
allocateReturnStorage(program, "return_value_alias_variable", returnDT,
|
||||
storageAllocator, varnodes, returnResultAliasVars, true);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public class GolangElfInfoProducer implements ElfInfoProducer {
|
||||
private static final Map<String, ReaderFunc<ElfInfoItem>> GOLANGINFO_READERS = Map.of(
|
||||
GoBuildInfo.SECTION_NAME, GoBuildInfo::read,
|
||||
GoBuildInfo.ELF_SECTION_NAME, GoBuildInfo::read,
|
||||
NoteGoBuildId.SECTION_NAME, NoteGoBuildId::read);
|
||||
|
||||
private ElfLoadHelper elfLoadHelper;
|
||||
|
@ -21,14 +21,12 @@ import java.util.*;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.golang.rtti.types.GoType;
|
||||
import ghidra.app.util.bin.format.golang.structmapping.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
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.SymbolUtilities;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@ -50,10 +48,25 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
||||
@MarkupReference
|
||||
private long pcHeader; // pointer to the GoPcHeader instance, useful for bootstrapping
|
||||
|
||||
@FieldMapping
|
||||
private long data;
|
||||
|
||||
@FieldMapping
|
||||
private long edata;
|
||||
|
||||
@FieldMapping
|
||||
@MarkupReference
|
||||
private long text;
|
||||
|
||||
@FieldMapping
|
||||
private long etext;
|
||||
|
||||
@FieldMapping
|
||||
private long noptrdata;
|
||||
|
||||
@FieldMapping
|
||||
private long enoptrdata;
|
||||
|
||||
@FieldMapping(fieldName = "types")
|
||||
private long typesOffset;
|
||||
|
||||
@ -63,6 +76,9 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
||||
@FieldMapping(optional = true)
|
||||
private long gofunc;
|
||||
|
||||
@FieldMapping
|
||||
private long end;
|
||||
|
||||
@FieldMapping(fieldName = "typelinks")
|
||||
private GoSlice typeLinks;
|
||||
|
||||
@ -120,6 +136,24 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
||||
return programContext.getCodeAddress(text);
|
||||
}
|
||||
|
||||
public AddressRange getTextRange() {
|
||||
Address textstart = getText();
|
||||
Address textend = programContext.getCodeAddress(etext);
|
||||
return new AddressRangeImpl(textstart, textend);
|
||||
}
|
||||
|
||||
public AddressRange getRoDataRange() {
|
||||
Address roStart = programContext.getCodeAddress(etext); // TODO: rodata is avail in newer govers
|
||||
Address roEnd = programContext.getCodeAddress(end);
|
||||
return new AddressRangeImpl(roStart, roEnd);
|
||||
}
|
||||
|
||||
public AddressRange getDataRange() {
|
||||
Address dataStart = programContext.getCodeAddress(data);
|
||||
Address dataEnd = programContext.getCodeAddress(edata);
|
||||
return new AddressRangeImpl(dataStart, dataEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the starting offset of type info
|
||||
*
|
||||
@ -190,12 +224,12 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
||||
* @return true if this module data structure contains sane values
|
||||
*/
|
||||
public boolean isValid() {
|
||||
MemoryBlock txtBlock = programContext.getProgram().getMemory().getBlock(".text");
|
||||
MemoryBlock txtBlock = programContext.getGoSection("text");
|
||||
if (txtBlock != null && !txtBlock.contains(getText())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryBlock typelinkBlock = programContext.getProgram().getMemory().getBlock(".typelink");
|
||||
MemoryBlock typelinkBlock = programContext.getGoSection("typelink");
|
||||
if (typelinkBlock != null &&
|
||||
typelinkBlock.getStart().getOffset() != typeLinks.getArrayOffset()) {
|
||||
return false;
|
||||
@ -396,8 +430,7 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
||||
/* package */ static GoModuledata getFirstModuledata(GoRttiMapper context)
|
||||
throws IOException {
|
||||
Program program = context.getProgram();
|
||||
Symbol firstModuleDataSymbol =
|
||||
SymbolUtilities.getUniqueSymbol(program, "runtime.firstmoduledata");
|
||||
Symbol firstModuleDataSymbol = GoRttiMapper.getGoSymbol(program, "runtime.firstmoduledata");
|
||||
if (firstModuleDataSymbol == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ 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.SymbolUtilities;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
@ -39,7 +38,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
@StructureMapping(structureName = "runtime.pcHeader")
|
||||
public class GoPcHeader {
|
||||
private static final String RUNTIME_PCLNTAB_SYMBOLNAME = "runtime.pclntab";
|
||||
public static final String GOPCLNTAB_SECTION_NAME = ".gopclntab";
|
||||
public static final String GOPCLNTAB_SECTION_NAME = "gopclntab";
|
||||
public static final int GO_1_2_MAGIC = 0xfffffffb;
|
||||
public static final int GO_1_16_MAGIC = 0xfffffffa;
|
||||
public static final int GO_1_18_MAGIC = 0xfffffff0;
|
||||
@ -51,12 +50,12 @@ public class GoPcHeader {
|
||||
* @return {@link Address} of go pclntab, or null if not present
|
||||
*/
|
||||
public static Address getPclntabAddress(Program program) {
|
||||
MemoryBlock pclntabBlock = program.getMemory().getBlock(GOPCLNTAB_SECTION_NAME);
|
||||
MemoryBlock pclntabBlock = GoRttiMapper.getGoSection(program, GOPCLNTAB_SECTION_NAME);
|
||||
if (pclntabBlock != null) {
|
||||
return pclntabBlock.getStart();
|
||||
}
|
||||
// PE binaries have a symbol instead of a named section
|
||||
Symbol pclntabSymbol = SymbolUtilities.getUniqueSymbol(program, RUNTIME_PCLNTAB_SYMBOLNAME);
|
||||
Symbol pclntabSymbol = GoRttiMapper.getGoSymbol(program, RUNTIME_PCLNTAB_SYMBOLNAME);
|
||||
return pclntabSymbol != null
|
||||
? pclntabSymbol.getAddress()
|
||||
: null;
|
||||
|
@ -35,8 +35,8 @@ import ghidra.app.util.bin.format.golang.*;
|
||||
import ghidra.app.util.bin.format.golang.rtti.types.*;
|
||||
import ghidra.app.util.bin.format.golang.structmapping.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.ElfLoader;
|
||||
import ghidra.app.util.opinion.PeLoader;
|
||||
import ghidra.app.util.opinion.*;
|
||||
import ghidra.framework.Platform;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
@ -44,9 +44,9 @@ import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager.LanguageUpdateOption;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@ -210,10 +210,14 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
else if (PeLoader.PE_NAME.equals(loaderName)) {
|
||||
return "win";
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
else if (MachoLoader.MACH_O_NAME.equals(loaderName)) {
|
||||
LanguageID languageID = program.getLanguageCompilerSpecPair().getLanguageID();
|
||||
if ("AARCH64:LE:64:AppleSilicon".equals(languageID.getIdAsString())) {
|
||||
return Platform.MAC_ARM_64.getDirectoryName(); // mac_arm_64
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a golang bootstrap gdt file that matches the specified Go version/size/OS.
|
||||
@ -252,6 +256,58 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
program.getCompilerSpec().getCompilerSpecDescription().getCompilerSpecName());
|
||||
}
|
||||
|
||||
public static boolean hasGolangSections(List<String> sectionNames) {
|
||||
for (String sectionName : sectionNames) {
|
||||
if (sectionName.contains("gopclntab") ||
|
||||
sectionName.contains(GoBuildInfo.MACHO_SECTION_NAME) ||
|
||||
sectionName.contains(GoBuildInfo.SECTION_NAME)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final List<String> SYMBOL_SEARCH_PREFIXES = List.of("", "_" /* macho symbols */);
|
||||
private static final List<String> SECTION_PREFIXES =
|
||||
List.of("." /* ELF */, "__" /* macho sections */);
|
||||
|
||||
/**
|
||||
* Returns a matching symbol from the specified program, using golang specific logic.
|
||||
*
|
||||
* @param program {@link Program}
|
||||
* @param symbolName name of golang symbol
|
||||
* @return {@link Symbol}, or null if not found
|
||||
*/
|
||||
public static Symbol getGoSymbol(Program program, String symbolName) {
|
||||
for (String prefix : SYMBOL_SEARCH_PREFIXES) {
|
||||
List<Symbol> symbols = program.getSymbolTable().getSymbols(prefix + symbolName, null);
|
||||
if (symbols.size() == 1) {
|
||||
return symbols.get(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MemoryBlock getGoSection(Program program, String sectionName) {
|
||||
for (String prefix : SECTION_PREFIXES) {
|
||||
MemoryBlock memBlock = program.getMemory().getBlock(prefix + sectionName);
|
||||
if (memBlock != null) {
|
||||
return memBlock;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MemoryBlock getFirstGoSection(Program program, String... blockNames) {
|
||||
for (String blockToSearch : blockNames) {
|
||||
MemoryBlock memBlock = getGoSection(program, blockToSearch);
|
||||
if (memBlock != null) {
|
||||
return memBlock;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the address of the golang zerobase symbol, or an artificial substitute.
|
||||
* <p>
|
||||
@ -261,7 +317,7 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
* @return {@link Address} of the runtime.zerobase, or artificial substitute
|
||||
*/
|
||||
public static Address getZerobaseAddress(Program prog) {
|
||||
Symbol zerobaseSym = SymbolUtilities.getUniqueSymbol(prog, "runtime.zerobase");
|
||||
Symbol zerobaseSym = getGoSymbol(prog, "runtime.zerobase");
|
||||
Address zerobaseAddr =
|
||||
zerobaseSym != null ? zerobaseSym.getAddress() : getArtificalZerobaseAddress(prog);
|
||||
if (zerobaseAddr == null) {
|
||||
@ -276,8 +332,7 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
"ARTIFICIAL.runtime.zerobase";
|
||||
|
||||
private static Address getArtificalZerobaseAddress(Program program) {
|
||||
Symbol zerobaseSym =
|
||||
SymbolUtilities.getUniqueSymbol(program, ARTIFICIAL_RUNTIME_ZEROBASE_SYMBOLNAME);
|
||||
Symbol zerobaseSym = getGoSymbol(program, ARTIFICIAL_RUNTIME_ZEROBASE_SYMBOLNAME);
|
||||
return zerobaseSym != null ? zerobaseSym.getAddress() : null;
|
||||
}
|
||||
|
||||
@ -479,7 +534,7 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
* @return {@link GoModuledata}
|
||||
*/
|
||||
public GoModuledata getFirstModule() {
|
||||
return modules.get(0);
|
||||
return !modules.isEmpty() ? modules.get(0) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1370,14 +1425,14 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
}
|
||||
|
||||
private AddressRange getPclntabSearchRange() {
|
||||
MemoryBlock memBlock = getFirstMemoryBlock(program, ".noptrdata", ".rdata");
|
||||
MemoryBlock memBlock = getFirstGoSection(program, "noptrdata", "rdata");
|
||||
return memBlock != null
|
||||
? new AddressRangeImpl(memBlock.getStart(), memBlock.getEnd())
|
||||
: null;
|
||||
}
|
||||
|
||||
private AddressRange getModuledataSearchRange() {
|
||||
MemoryBlock memBlock = getFirstMemoryBlock(program, ".noptrdata", ".data");
|
||||
MemoryBlock memBlock = getFirstGoSection(program, "noptrdata", "data");
|
||||
return memBlock != null
|
||||
? new AddressRangeImpl(memBlock.getStart(), memBlock.getEnd())
|
||||
: null;
|
||||
@ -1389,15 +1444,11 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
* @return {@link AddressSetView} of range that is valid to find string structs in
|
||||
*/
|
||||
public AddressSetView getStringStructRange() {
|
||||
MemoryBlock datamb = program.getMemory().getBlock(".data");
|
||||
MemoryBlock rodatamb = getFirstMemoryBlock(program, ".rodata", ".rdata");
|
||||
|
||||
if (datamb == null || rodatamb == null) {
|
||||
return new AddressSet();
|
||||
AddressSet result = new AddressSet();
|
||||
for (GoModuledata moduledata : modules) {
|
||||
result.add(moduledata.getDataRange());
|
||||
result.add(moduledata.getRoDataRange());
|
||||
}
|
||||
|
||||
AddressSet result = new AddressSet(datamb.getStart(), datamb.getEnd());
|
||||
result.add(rodatamb.getStart(), rodatamb.getEnd());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1407,21 +1458,29 @@ public class GoRttiMapper extends DataTypeMapper {
|
||||
* @return {@link AddressSetView} of range that is valid for string char[] data
|
||||
*/
|
||||
public AddressSetView getStringDataRange() {
|
||||
MemoryBlock rodatamb = getFirstMemoryBlock(program, ".rodata", ".rdata");
|
||||
return rodatamb != null
|
||||
? new AddressSet(rodatamb.getStart(), rodatamb.getEnd())
|
||||
: new AddressSet();
|
||||
// TODO: initialized []byte("stringchars") slices can have data in noptrdata section
|
||||
AddressSet result = new AddressSet();
|
||||
for (GoModuledata moduledata : modules) {
|
||||
result.add(moduledata.getRoDataRange());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MemoryBlock getFirstMemoryBlock(Program program, String... blockNames) {
|
||||
Memory memory = program.getMemory();
|
||||
for (String blockToSearch : blockNames) {
|
||||
MemoryBlock memBlock = memory.getBlock(blockToSearch);
|
||||
if (memBlock != null) {
|
||||
return memBlock;
|
||||
public AddressSetView getTextAddresses() {
|
||||
AddressSet result = new AddressSet();
|
||||
for (GoModuledata moduledata : modules) {
|
||||
result.add(moduledata.getTextRange());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
|
||||
|
||||
public Symbol getGoSymbol(String symbolName) {
|
||||
return getGoSymbol(program, symbolName);
|
||||
}
|
||||
|
||||
public MemoryBlock getGoSection(String sectionName) {
|
||||
return getGoSection(program, sectionName);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
@ -23,6 +23,8 @@ import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.ByteProviderWrapper;
|
||||
import ghidra.app.util.bin.format.golang.GoConstants;
|
||||
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||
import ghidra.app.util.bin.format.ubi.*;
|
||||
@ -61,12 +63,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
||||
MachHeader machHeader = new MachHeader(provider);
|
||||
String magic =
|
||||
CpuTypes.getMagicString(machHeader.getCpuType(), machHeader.getCpuSubType());
|
||||
List<String> sectionNames = machHeader.parseSegments()
|
||||
.stream()
|
||||
.flatMap(seg -> seg.getSections().stream())
|
||||
.map(section -> section.getSectionName())
|
||||
.toList();
|
||||
String compiler = SwiftUtils.isSwift(sectionNames) ? "swift" : null;
|
||||
String compiler = detectCompilerName(machHeader);
|
||||
List<QueryResult> results = QueryOpinionService.query(MACH_O_NAME, magic, compiler);
|
||||
for (QueryResult result : results) {
|
||||
loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result));
|
||||
@ -81,6 +78,19 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
||||
return loadSpecs;
|
||||
}
|
||||
|
||||
private String detectCompilerName(MachHeader machHeader) throws IOException {
|
||||
List<String> sectionNames = machHeader.parseSegments()
|
||||
.stream()
|
||||
.flatMap(seg -> seg.getSections().stream())
|
||||
.map(section -> section.getSectionName())
|
||||
.toList();
|
||||
String compiler = SwiftUtils.isSwift(sectionNames) ? "swift" : null;
|
||||
compiler = compiler == null && GoRttiMapper.hasGolangSections(sectionNames)
|
||||
? GoConstants.GOLANG_CSPEC_NAME
|
||||
: null;
|
||||
return compiler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||
Program program, TaskMonitor monitor, MessageLog log) throws IOException {
|
||||
|
@ -24,6 +24,10 @@ import ghidra.app.plugin.core.analysis.rust.RustUtilities;
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.RelocationException;
|
||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem.ItemWithAddress;
|
||||
import ghidra.app.util.bin.format.golang.GoBuildId;
|
||||
import ghidra.app.util.bin.format.golang.GoBuildInfo;
|
||||
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
|
||||
import ghidra.app.util.bin.format.macho.*;
|
||||
import ghidra.app.util.bin.format.macho.commands.*;
|
||||
import ghidra.app.util.bin.format.macho.commands.ExportTrie.ExportEntry;
|
||||
@ -154,6 +158,9 @@ public class MachoProgramBuilder {
|
||||
// Set program info
|
||||
setRelocatableProperty();
|
||||
setProgramDescription();
|
||||
if (GoRttiMapper.isGolangProgram(program)) {
|
||||
markupAndSetGolangInitialProgramProperties();
|
||||
}
|
||||
|
||||
// Perform additional actions
|
||||
renameObjMsgSendRtpSymbol();
|
||||
@ -1791,6 +1798,17 @@ public class MachoProgramBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
protected void markupAndSetGolangInitialProgramProperties() {
|
||||
ItemWithAddress<GoBuildId> buildId = GoBuildId.findBuildId(program);
|
||||
if (buildId != null) {
|
||||
buildId.item().markupProgram(program, buildId.address());
|
||||
}
|
||||
ItemWithAddress<GoBuildInfo> buildInfo = GoBuildInfo.findBuildInfo(program);
|
||||
if (buildInfo != null) {
|
||||
buildInfo.item().markupProgram(program, buildInfo.address());
|
||||
}
|
||||
}
|
||||
|
||||
protected void setCompiler() {
|
||||
// Check for Rust
|
||||
try {
|
||||
|
@ -29,7 +29,7 @@ import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem.ItemWithAddress;
|
||||
import ghidra.app.util.bin.format.golang.GoBuildInfo;
|
||||
import ghidra.app.util.bin.format.golang.PEGoBuildId;
|
||||
import ghidra.app.util.bin.format.golang.GoBuildId;
|
||||
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
|
||||
import ghidra.app.util.bin.format.mz.DOSHeader;
|
||||
import ghidra.app.util.bin.format.pe.*;
|
||||
@ -298,7 +298,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
private void processGolangProperties(OptionalHeader optionalHeader, NTHeader ntHeader,
|
||||
Program prog, TaskMonitor monitor) {
|
||||
|
||||
ItemWithAddress<PEGoBuildId> buildId = PEGoBuildId.findBuildId(prog);
|
||||
ItemWithAddress<GoBuildId> buildId = GoBuildId.findBuildId(prog);
|
||||
if (buildId != null) {
|
||||
buildId.item().markupProgram(prog, buildId.address());
|
||||
}
|
||||
@ -1141,7 +1141,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
SectionHeader textSection = pe.getNTHeader().getFileHeader().getSectionHeader(".text");
|
||||
if (textSection != null) {
|
||||
try (InputStream is = textSection.getDataStream()) {
|
||||
PEGoBuildId buildId = PEGoBuildId.read(is);
|
||||
GoBuildId buildId = GoBuildId.read(is);
|
||||
buildIdPresent = buildId != null;
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -11,6 +11,8 @@ data/languages/AARCH64BE.slaspec||GHIDRA||||END|
|
||||
data/languages/AARCH64_AMXext.sinc||GHIDRA||||END|
|
||||
data/languages/AARCH64_AppleSilicon.slaspec||GHIDRA||||END|
|
||||
data/languages/AARCH64_base_PACoptions.sinc||GHIDRA||||END|
|
||||
data/languages/AARCH64_golang.cspec||GHIDRA||||END|
|
||||
data/languages/AARCH64_golang.register.info||GHIDRA||||END|
|
||||
data/languages/AARCH64_ilp32.cspec||GHIDRA||||END|
|
||||
data/languages/AARCH64_swift.cspec||GHIDRA||||END|
|
||||
data/languages/AARCH64_win.cspec||GHIDRA||||END|
|
||||
|
@ -12,6 +12,7 @@
|
||||
<description>Generic ARM64 v8.5-A LE instructions, LE data, missing some 8.5 vector</description>
|
||||
<compiler name="default" spec="AARCH64.cspec" id="default"/>
|
||||
<compiler name="Visual Studio" spec="AARCH64_win.cspec" id="windows"/>
|
||||
<compiler name="golang" spec="AARCH64_golang.cspec" id="golang"/>
|
||||
<external_name tool="gnu" name="aarch64"/>
|
||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||
<external_name tool="qemu" name="qemu-aarch64"/>
|
||||
@ -28,8 +29,10 @@
|
||||
id="AARCH64:BE:64:v8A">
|
||||
<description>Generic ARM64 v8.5-A LE instructions, BE data, missing some 8.5 vector</description>
|
||||
<compiler name="default" spec="AARCH64.cspec" id="default"/>
|
||||
<compiler name="golang" spec="AARCH64_golang.cspec" id="golang"/>
|
||||
<external_name tool="gnu" name="aarch64"/>
|
||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||
<external_name tool="Golang.register.info.file" name="AARCH64_golang.register.info"/>
|
||||
<external_name tool="qemu" name="qemu-aarch64_be"/>
|
||||
</language>
|
||||
<language processor="AARCH64"
|
||||
@ -44,6 +47,7 @@
|
||||
<description>Generic ARM64 v8.5-A LE instructions, LE data, ilp32</description>
|
||||
<truncate_space space="ram" size="4"/>
|
||||
<compiler name="default" spec="AARCH64_ilp32.cspec" id="default"/>
|
||||
<compiler name="golang" spec="AARCH64_golang.cspec" id="golang"/>
|
||||
<external_name tool="gnu" name="aarch64:ilp32"/>
|
||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||
<external_name tool="qemu" name="qemu-aarch64"/>
|
||||
@ -61,6 +65,7 @@
|
||||
<description>Generic ARM64 v8.5-A LE instructions, BE data, ilp32</description>
|
||||
<truncate_space space="ram" size="4"/>
|
||||
<compiler name="default" spec="AARCH64_ilp32.cspec" id="default"/>
|
||||
<compiler name="golang" spec="AARCH64_golang.cspec" id="golang"/>
|
||||
<external_name tool="gnu" name="aarch64:ilp32"/>
|
||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||
<external_name tool="qemu" name="qemu-aarch64_be"/>
|
||||
|
@ -12,6 +12,9 @@
|
||||
<constraint loader="Mac OS X Mach-O" compilerSpecID="swift">
|
||||
<constraint primary="16777228" secondary="swift" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
|
||||
</constraint>
|
||||
<constraint loader="Mac OS X Mach-O" compilerSpecID="golang">
|
||||
<constraint primary="16777228" secondary="golang" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
|
||||
</constraint>
|
||||
<constraint loader="DYLD Cache" compilerSpecID="default">
|
||||
<constraint primary="AARCH64" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
|
||||
<constraint primary="ARM64_32" processor="AARCH64" endian="little" size="32" variant="ilp32" />
|
||||
|
293
Ghidra/Processors/AARCH64/data/languages/AARCH64_golang.cspec
Normal file
293
Ghidra/Processors/AARCH64/data/languages/AARCH64_golang.cspec
Normal file
@ -0,0 +1,293 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<compiler_spec>
|
||||
<data_organization>
|
||||
<absolute_max_alignment value="0" />
|
||||
<machine_alignment value="2" />
|
||||
<default_alignment value="1" />
|
||||
<default_pointer_alignment value="8" />
|
||||
<pointer_size value="8" />
|
||||
<wchar_size value="4" /> <!-- matches go's 'rune' -->
|
||||
<short_size value="2" />
|
||||
<integer_size value="8" />
|
||||
<long_size value="8" />
|
||||
<long_long_size value="8" />
|
||||
<float_size value="4" />
|
||||
<double_size value="8" />
|
||||
<long_double_size value="16" />
|
||||
<size_alignment_map>
|
||||
<entry size="1" alignment="1" />
|
||||
<entry size="2" alignment="2" />
|
||||
<entry size="4" alignment="4" />
|
||||
<entry size="8" alignment="8" />
|
||||
</size_alignment_map>
|
||||
</data_organization>
|
||||
|
||||
<global>
|
||||
<range space="ram"/>
|
||||
</global>
|
||||
|
||||
<context_data>
|
||||
</context_data>
|
||||
|
||||
<stackpointer register="sp" space="ram"/>
|
||||
<funcptr align="4"/> <!-- Function pointers are word aligned and leastsig bit may encode otherstuff -->
|
||||
|
||||
<returnaddress>
|
||||
<varnode space="stack" offset="0" size="8"/>
|
||||
</returnaddress>
|
||||
|
||||
<default_proto>
|
||||
<prototype name="abi-internal" extrapop="8" stackshift="8">
|
||||
<input>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q0"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q1"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q2"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q3"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q4"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q5"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q6"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q7"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q8"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q9"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q10"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q11"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q12"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q13"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q14"/>
|
||||
</pentry>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q15"/>
|
||||
</pentry>
|
||||
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x0"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x1"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x2"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x3"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x4"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x5"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x6"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x7"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x8"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x9"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x10"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x11"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x12"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x13"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x14"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x15"/>
|
||||
</pentry>
|
||||
|
||||
<pentry minsize="1" maxsize="500" align="16">
|
||||
<addr offset="8" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
|
||||
<output>
|
||||
<pentry minsize="4" maxsize="8" metatype="float">
|
||||
<register name="q0"/>
|
||||
</pentry>
|
||||
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x0"/>
|
||||
</pentry>
|
||||
<pentry minsize="9" maxsize="16">
|
||||
<addr space="join" piece2="x0" piece1="x1"/>
|
||||
</pentry>
|
||||
<pentry minsize="17" maxsize="24">
|
||||
<addr space="join" piece3="x0" piece2="x1" piece1="x2"/>
|
||||
</pentry>
|
||||
<pentry minsize="25" maxsize="32">
|
||||
<addr space="join" piece4="x0" piece3="x1" piece2="x2" piece1="x3"/>
|
||||
</pentry>
|
||||
<pentry minsize="33" maxsize="40">
|
||||
<addr space="join" piece5="x0" piece4="x1" piece3="x2" piece2="x3" piece1="x4"/>
|
||||
</pentry>
|
||||
<pentry minsize="41" maxsize="48">
|
||||
<addr space="join" piece6="x0" piece5="x1" piece4="x2" piece3="x3" piece2="x4" piece1="x5"/>
|
||||
</pentry>
|
||||
<pentry minsize="49" maxsize="56">
|
||||
<addr space="join" piece7="x0" piece6="x1" piece5="x2" piece4="x3" piece3="x4" piece2="x5" piece1="x6"/>
|
||||
</pentry>
|
||||
<pentry minsize="57" maxsize="64">
|
||||
<addr space="join" piece8="x0" piece7="x1" piece6="x2" piece5="x3" piece4="x4" piece3="x5" piece2="x6" piece1="x7"/>
|
||||
</pentry>
|
||||
<pentry minsize="65" maxsize="72">
|
||||
<addr space="join" piece9="x0" piece8="x1" piece7="x2" piece6="x3" piece5="x4" piece4="x5" piece3="x6" piece2="x7" piece1="x8"/>
|
||||
</pentry>
|
||||
</output>
|
||||
|
||||
<killedbycall>
|
||||
<register name="x0"/>
|
||||
<register name="x1"/>
|
||||
<register name="x2"/>
|
||||
<register name="x3"/>
|
||||
<register name="x4"/>
|
||||
<register name="x5"/>
|
||||
<register name="x6"/>
|
||||
<register name="x7"/>
|
||||
<register name="x8"/>
|
||||
<register name="x9"/>
|
||||
<register name="x10"/>
|
||||
<register name="x11"/>
|
||||
<register name="x12"/>
|
||||
<register name="x13"/>
|
||||
<register name="x14"/>
|
||||
<register name="x15"/>
|
||||
</killedbycall>
|
||||
<unaffected>
|
||||
<register name="x16"/>
|
||||
<register name="x17"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
</default_proto>
|
||||
|
||||
<prototype name="abi0" extrapop="8" stackshift="8">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="8">
|
||||
<addr offset="8" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
|
||||
<output>
|
||||
</output>
|
||||
|
||||
<killedbycall>
|
||||
<register name="x0"/>
|
||||
<register name="x1"/>
|
||||
<register name="x2"/>
|
||||
<register name="x3"/>
|
||||
<register name="x4"/>
|
||||
<register name="x5"/>
|
||||
<register name="x6"/>
|
||||
<register name="x7"/>
|
||||
<register name="x8"/>
|
||||
<register name="x9"/>
|
||||
<register name="x10"/>
|
||||
<register name="x11"/>
|
||||
<register name="x12"/>
|
||||
<register name="x13"/>
|
||||
<register name="x14"/>
|
||||
<register name="x15"/>
|
||||
</killedbycall>
|
||||
<unaffected>
|
||||
<register name="x16"/>
|
||||
<register name="x17"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
|
||||
<prototype name="duffzero" extrapop="8" stackshift="8">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x20"/>
|
||||
</pentry>
|
||||
</input>
|
||||
|
||||
<output>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x20"/>
|
||||
</pentry>
|
||||
</output>
|
||||
|
||||
<killedbycall>
|
||||
<register name="x20"/>
|
||||
</killedbycall>
|
||||
<unaffected>
|
||||
<register name="x16"/>
|
||||
<register name="x17"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
|
||||
|
||||
<prototype name="duffcopy" extrapop="8" stackshift="8">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x21"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x20"/>
|
||||
</pentry>
|
||||
</input>
|
||||
|
||||
<output>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="x21"/>
|
||||
</pentry>
|
||||
<pentry minsize="9" maxsize="16">
|
||||
<addr space="join" piece2="x21" piece1="x20"/>
|
||||
</pentry>
|
||||
</output>
|
||||
|
||||
<killedbycall>
|
||||
<register name="x21"/>
|
||||
<register name="x20"/>
|
||||
</killedbycall>
|
||||
<unaffected>
|
||||
<register name="x16"/>
|
||||
<register name="x17"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
|
||||
|
||||
</compiler_spec>
|
||||
|
@ -0,0 +1,10 @@
|
||||
<golang>
|
||||
<!-- see https://github.com/golang/go/blob/master/src/internal/abi/abi_arm64.go -->
|
||||
<register_info versions="V1_17,V1_18,V1_19,V1_20,V1_21">
|
||||
<int_registers list="x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15"/>
|
||||
<float_registers list="q0,q1,q2,q3,q4,q5,q6,q7,q8,q9,q10,q11,q12,q13,q14,q15"/>
|
||||
<stack initialoffset="8" maxalign="8"/>
|
||||
<current_goroutine register="x28"/>
|
||||
<zero_register register="ZR"/>
|
||||
</register_info>
|
||||
</golang>
|
@ -12,8 +12,10 @@
|
||||
<description>AppleSilicon ARM v8.5-A LE instructions, LE data, AMX extensions</description>
|
||||
<compiler name="default" spec="AARCH64.cspec" id="default"/>
|
||||
<compiler name="Swift" spec="AARCH64_swift.cspec" id="swift"/>
|
||||
<compiler name="golang" spec="AARCH64_golang.cspec" id="golang"/>
|
||||
<external_name tool="gnu" name="aarch64"/>
|
||||
<external_name tool="gnu" name="aarch64:ilp32"/>
|
||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||
<external_name tool="Golang.register.info.file" name="AARCH64_golang.register.info"/>
|
||||
</language>
|
||||
</language_definitions>
|
||||
|
Loading…
Reference in New Issue
Block a user