mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +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
|
# 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.abort.abi0
|
||||||
runtime.exit.abi0
|
runtime.exit.abi0
|
||||||
runtime.dieFromSignal
|
runtime.dieFromSignal
|
||||||
@ -7,6 +10,12 @@ runtime.fatal
|
|||||||
runtime.fatalthrow
|
runtime.fatalthrow
|
||||||
runtime.fatalpanic
|
runtime.fatalpanic
|
||||||
runtime.throw
|
runtime.throw
|
||||||
|
runtime.systemstack_switch
|
||||||
|
runtime.newstack
|
||||||
|
runtime.newstack.abi0
|
||||||
|
runtime.mstart
|
||||||
|
runtime.mstart.abi0
|
||||||
|
runtime.mstart0
|
||||||
|
|
||||||
runtime.gopanic
|
runtime.gopanic
|
||||||
runtime.goPanicExtendIndex
|
runtime.goPanicExtendIndex
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
<functionNamesFile>ElfFunctionsThatDoNotReturn</functionNamesFile>
|
<functionNamesFile>ElfFunctionsThatDoNotReturn</functionNamesFile>
|
||||||
</executable_format>
|
</executable_format>
|
||||||
<executable_format name="Mac OS X Mach-O">
|
<executable_format name="Mac OS X Mach-O">
|
||||||
|
<compiler id="golang">
|
||||||
|
<functionNamesFile>GolangFunctionsThatDoNotReturn</functionNamesFile>
|
||||||
|
</compiler>
|
||||||
<functionNamesFile>MachOFunctionsThatDoNotReturn</functionNamesFile>
|
<functionNamesFile>MachOFunctionsThatDoNotReturn</functionNamesFile>
|
||||||
</executable_format>
|
</executable_format>
|
||||||
<executable_format name="DYLD Cache">
|
<executable_format name="DYLD Cache">
|
||||||
|
@ -179,13 +179,13 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
|||||||
private void markupWellknownSymbols() throws IOException {
|
private void markupWellknownSymbols() throws IOException {
|
||||||
Program program = goBinary.getProgram();
|
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);
|
Structure gStruct = goBinary.getGhidraDataType("runtime.g", Structure.class);
|
||||||
if (g0 != null && gStruct != null) {
|
if (g0 != null && gStruct != null) {
|
||||||
markupSession.markupAddressIfUndefined(g0.getAddress(), gStruct);
|
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);
|
Structure mStruct = goBinary.getGhidraDataType("runtime.m", Structure.class);
|
||||||
if (m0 != null && mStruct != null) {
|
if (m0 != null && mStruct != null) {
|
||||||
markupSession.markupAddressIfUndefined(m0.getAddress(), mStruct);
|
markupSession.markupAddressIfUndefined(m0.getAddress(), mStruct);
|
||||||
@ -416,13 +416,13 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
|||||||
Program program = goBinary.getProgram();
|
Program program = goBinary.getProgram();
|
||||||
GoRegisterInfo goRegInfo = goBinary.getRegInfo();
|
GoRegisterInfo goRegInfo = goBinary.getRegInfo();
|
||||||
|
|
||||||
MemoryBlock txtMemblock = program.getMemory().getBlock(".text");
|
if (goRegInfo.getZeroRegister() != null && !goRegInfo.isZeroRegisterIsBuiltin()) {
|
||||||
if (txtMemblock != null && goRegInfo.getZeroRegister() != null &&
|
|
||||||
!goRegInfo.isZeroRegisterIsBuiltin()) {
|
|
||||||
try {
|
try {
|
||||||
|
for (AddressRange textRange : goBinary.getTextAddresses().getAddressRanges()) {
|
||||||
program.getProgramContext()
|
program.getProgramContext()
|
||||||
.setValue(goRegInfo.getZeroRegister(), txtMemblock.getStart(),
|
.setValue(goRegInfo.getZeroRegister(), textRange.getMinAddress(),
|
||||||
txtMemblock.getEnd(), BigInteger.ZERO);
|
textRange.getMaxAddress(), BigInteger.ZERO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (ContextChangeException e) {
|
catch (ContextChangeException e) {
|
||||||
Msg.error(this, "Unexpected Error", e);
|
Msg.error(this, "Unexpected Error", e);
|
||||||
@ -432,7 +432,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
|||||||
int alignment = goBinary.getPtrSize();
|
int alignment = goBinary.getPtrSize();
|
||||||
long sizeNeeded = 0;
|
long sizeNeeded = 0;
|
||||||
|
|
||||||
Symbol zerobase = SymbolUtilities.getUniqueSymbol(program, "runtime.zerobase");
|
Symbol zerobase = goBinary.getGoSymbol("runtime.zerobase");
|
||||||
long zerobaseSymbol = sizeNeeded;
|
long zerobaseSymbol = sizeNeeded;
|
||||||
sizeNeeded += zerobase == null
|
sizeNeeded += zerobase == null
|
||||||
? NumericUtilities.getUnsignedAlignedValue(1 /* sizeof(byte) */, alignment)
|
? NumericUtilities.getUnsignedAlignedValue(1 /* sizeof(byte) */, alignment)
|
||||||
@ -464,14 +464,16 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
|||||||
markupSession.labelAddress(gAddr, "CURRENT_G");
|
markupSession.labelAddress(gAddr, "CURRENT_G");
|
||||||
|
|
||||||
Register currentGoroutineReg = goRegInfo.getCurrentGoroutineRegister();
|
Register currentGoroutineReg = goRegInfo.getCurrentGoroutineRegister();
|
||||||
if (currentGoroutineReg != null && txtMemblock != null) {
|
if (currentGoroutineReg != null) {
|
||||||
// currentGoroutineReg is set in a platform's arch-golang.register.info in
|
// currentGoroutineReg is set in a platform's arch-golang.register.info in
|
||||||
// the <current_goroutine> element for arch's that have a dedicated processor
|
// the <current_goroutine> element for arch's that have a dedicated processor
|
||||||
// register that points at G
|
// register that points at G
|
||||||
try {
|
try {
|
||||||
|
for (AddressRange textRange : goBinary.getTextAddresses().getAddressRanges()) {
|
||||||
program.getProgramContext()
|
program.getProgramContext()
|
||||||
.setValue(currentGoroutineReg, txtMemblock.getStart(),
|
.setValue(currentGoroutineReg, textRange.getMinAddress(),
|
||||||
txtMemblock.getEnd(), gAddr.getOffsetAsBigInteger());
|
textRange.getMaxAddress(), gAddr.getOffsetAsBigInteger());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (ContextChangeException e) {
|
catch (ContextChangeException e) {
|
||||||
Msg.error(this, "Unexpected Error", e);
|
Msg.error(this, "Unexpected Error", e);
|
||||||
@ -582,6 +584,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer {
|
|||||||
int callingFunctionCount;
|
int callingFunctionCount;
|
||||||
|
|
||||||
public PropagateRttiBackgroundCommand(GoRttiMapper goBinary) {
|
public PropagateRttiBackgroundCommand(GoRttiMapper goBinary) {
|
||||||
|
super("Golang RTTI Propagation (deferred)", true, true, false);
|
||||||
this.goBinary = goBinary;
|
this.goBinary = goBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,9 @@ public interface ElfInfoItem {
|
|||||||
*/
|
*/
|
||||||
void markupProgram(Program program, Address address);
|
void markupProgram(Program program, Address address);
|
||||||
|
|
||||||
public record ItemWithAddress<T> (T item, Address address) {};
|
public record ItemWithAddress<T>(T item, Address address) {}
|
||||||
public interface ReaderFunc<T extends ElfInfoItem> {
|
|
||||||
|
public interface ReaderFunc<T> {
|
||||||
T read(BinaryReader br, Program program) throws IOException;
|
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 sectionName name of memory section that contains the item
|
||||||
* @param readFunc {@link ReaderFunc} that will deserialize an instance of 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) {
|
ReaderFunc<ElfInfoItem> readFunc) {
|
||||||
ItemWithAddress<ElfInfoItem> wrappedItem =
|
ItemWithAddress<ElfInfoItem> wrappedItem =
|
||||||
readItemFromSection(program, sectionName, readFunc);
|
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
|
* @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
|
* 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) {
|
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) {
|
if (memBlock != null) {
|
||||||
try (ByteProvider bp =
|
try (ByteProvider bp =
|
||||||
MemoryByteProvider.createMemoryBlockByteProvider(program.getMemory(), memBlock)) {
|
MemoryByteProvider.createMemoryBlockByteProvider(program.getMemory(), memBlock)) {
|
||||||
@ -82,10 +87,9 @@ public interface ElfInfoItem {
|
|||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
Msg.warn(ElfInfoItem.class,
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,49 +20,52 @@ import java.io.InputStream;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.*;
|
||||||
import ghidra.app.util.bin.ByteArrayProvider;
|
import ghidra.app.util.bin.format.elf.info.ElfInfoItem.ItemWithAddress;
|
||||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem;
|
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.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link NoteGoBuildId}, but re-implemented here because of the different
|
* This class represents a go build id string, along with a magic header.
|
||||||
* serialization used in PE binaries. (the logic about the buildid payload is trivial so
|
|
||||||
* there is no worry about duplicating code)
|
|
||||||
* <p>
|
* <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 =
|
private static final byte[] GO_BUILDID_MAGIC =
|
||||||
"\u00ff Go build ID: \"".getBytes(StandardCharsets.ISO_8859_1);
|
"\u00ff Go build ID: \"".getBytes(StandardCharsets.ISO_8859_1);
|
||||||
private static final int BUILDID_STR_LEN = 83;
|
private static final int BUILDID_STR_LEN = 83;
|
||||||
|
|
||||||
public static ItemWithAddress<PEGoBuildId> findBuildId(Program program) {
|
public static ItemWithAddress<GoBuildId> findBuildId(Program program) {
|
||||||
ItemWithAddress<PEGoBuildId> wrappedItem = ElfInfoItem.readItemFromSection(program,
|
MemoryBlock txtBlock = GoRttiMapper.getGoSection(program, "text");
|
||||||
".text", PEGoBuildId::read);
|
ItemWithAddress<GoBuildId> wrappedItem =
|
||||||
|
readItemFromSection(program, txtBlock, GoBuildId::read);
|
||||||
return wrappedItem;
|
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 br BinaryReader stream (typically the beginning of the ".text" section)
|
||||||
* @param program_notused not used, but needed to match functional interface
|
* @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 {
|
try {
|
||||||
byte[] magic = br.readNextByteArray(GO_BUILDID_MAGIC.length);
|
byte[] magic = br.readNextByteArray(GO_BUILDID_MAGIC.length);
|
||||||
if (!Arrays.equals(magic, GO_BUILDID_MAGIC)) {
|
if (!Arrays.equals(magic, GO_BUILDID_MAGIC)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String buildIdStr = br.readNextAsciiString(BUILDID_STR_LEN);
|
String buildIdStr = br.readNextAsciiString(BUILDID_STR_LEN);
|
||||||
return new PEGoBuildId(buildIdStr);
|
return new GoBuildId(buildIdStr);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// fall thru and return null
|
// 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).
|
* detection before file is loaded).
|
||||||
*
|
*
|
||||||
* @param is {@link InputStream} providing access to the ".text" section of a PE binary
|
* @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];
|
byte[] buffer = new byte[GO_BUILDID_MAGIC.length + BUILDID_STR_LEN];
|
||||||
try {
|
try {
|
||||||
int bytesRead = is.read(buffer);
|
int bytesRead = is.read(buffer);
|
||||||
@ -94,7 +97,7 @@ public class PEGoBuildId implements ElfInfoItem {
|
|||||||
|
|
||||||
private final String buildId;
|
private final String buildId;
|
||||||
|
|
||||||
public PEGoBuildId(String buildId) {
|
public GoBuildId(String buildId) {
|
||||||
this.buildId = buildId;
|
this.buildId = buildId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +105,6 @@ public class PEGoBuildId implements ElfInfoItem {
|
|||||||
return buildId;
|
return buildId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void markupProgram(Program program, Address address) {
|
public void markupProgram(Program program, Address address) {
|
||||||
program.getOptions(Program.PROGRAM_INFO)
|
program.getOptions(Program.PROGRAM_INFO)
|
||||||
.setString(NoteGoBuildId.PROGRAM_INFO_KEY, getBuildId());
|
.setString(NoteGoBuildId.PROGRAM_INFO_KEY, getBuildId());
|
||||||
@ -115,7 +117,7 @@ public class PEGoBuildId implements ElfInfoItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (CodeUnitInsertionException e) {
|
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;
|
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.*;
|
||||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem;
|
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.framework.options.Options;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||||
import ghidra.program.model.lang.Endian;
|
import ghidra.program.model.lang.Endian;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
|
||||||
@ -39,7 +41,9 @@ import ghidra.util.*;
|
|||||||
*/
|
*/
|
||||||
public class GoBuildInfo implements ElfInfoItem {
|
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
|
// Defined in golang src/debug/buildinfo/buildinfo.go
|
||||||
// NOTE: ISO_8859_1 charset is required to not mangle the \u00ff when converting to bytes
|
// 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
|
* @return new {@link GoBuildInfo} instance, if present, null if missing or error
|
||||||
*/
|
*/
|
||||||
public static ItemWithAddress<GoBuildInfo> findBuildInfo(Program program) {
|
public static ItemWithAddress<GoBuildInfo> findBuildInfo(Program program) {
|
||||||
// try as if binary is ELF
|
ItemWithAddress<GoBuildInfo> wrappedItem = readItemFromSection(program,
|
||||||
ItemWithAddress<GoBuildInfo> wrappedItem =
|
GoRttiMapper.getFirstGoSection(program, SECTION_NAME, MACHO_SECTION_NAME));
|
||||||
ElfInfoItem.readItemFromSection(program, SECTION_NAME, GoBuildInfo::read);
|
|
||||||
if (wrappedItem == null) {
|
if (wrappedItem == null) {
|
||||||
// if not present, try common PE location for buildinfo, using "ElfInfoItem" logic
|
// if not present, try common PE location for buildinfo
|
||||||
// even though this might be a PE binary, cause it doesn't matter
|
wrappedItem = readItemFromSection(program, GoRttiMapper.getGoSection(program, "data"));
|
||||||
wrappedItem = ElfInfoItem.readItemFromSection(program, ".data", GoBuildInfo::read);
|
|
||||||
}
|
}
|
||||||
return wrappedItem;
|
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.
|
* Reads a GoBuildInfo ".go.buildinfo" section from the specified stream.
|
||||||
*
|
*
|
||||||
|
@ -150,7 +150,7 @@ public class GoFunctionFixup {
|
|||||||
paramDT.getLength());
|
paramDT.getLength());
|
||||||
VariableStorage varStorage = new VariableStorage(program, List.of(stackVarnode));
|
VariableStorage varStorage = new VariableStorage(program, List.of(stackVarnode));
|
||||||
LocalVariableImpl localVar =
|
LocalVariableImpl localVar =
|
||||||
new LocalVariableImpl(param.getName() + "-spill", 0, paramDT, varStorage, program);
|
new LocalVariableImpl(param.getName() + "_spill", 0, paramDT, varStorage, program);
|
||||||
|
|
||||||
// TODO: needs more thought
|
// TODO: needs more thought
|
||||||
func.addLocalVariable(localVar, SourceType.USER_DEFINED);
|
func.addLocalVariable(localVar, SourceType.USER_DEFINED);
|
||||||
@ -229,12 +229,12 @@ public class GoFunctionFixup {
|
|||||||
returnDT = multiReturn.getStruct();
|
returnDT = multiReturn.getStruct();
|
||||||
|
|
||||||
for (DataTypeComponent dtc : multiReturn.getNormalStorageComponents()) {
|
for (DataTypeComponent dtc : multiReturn.getNormalStorageComponents()) {
|
||||||
allocateReturnStorage(program, dtc.getFieldName() + "-return-result-alias",
|
allocateReturnStorage(program, dtc.getFieldName() + "_return_result_alias",
|
||||||
dtc.getDataType(), storageAllocator, varnodes, returnResultAliasVars,
|
dtc.getDataType(), storageAllocator, varnodes, returnResultAliasVars,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
for (DataTypeComponent dtc : multiReturn.getStackStorageComponents()) {
|
for (DataTypeComponent dtc : multiReturn.getStackStorageComponents()) {
|
||||||
allocateReturnStorage(program, dtc.getFieldName() + "-return-result-alias",
|
allocateReturnStorage(program, dtc.getFieldName() + "_return_result_alias",
|
||||||
dtc.getDataType(), storageAllocator, varnodes, returnResultAliasVars,
|
dtc.getDataType(), storageAllocator, varnodes, returnResultAliasVars,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ public class GoFunctionFixup {
|
|||||||
varnodes.add(new Varnode(GoRttiMapper.getZerobaseAddress(program), 1));
|
varnodes.add(new Varnode(GoRttiMapper.getZerobaseAddress(program), 1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
allocateReturnStorage(program, "return-value-alias-variable", returnDT,
|
allocateReturnStorage(program, "return_value_alias_variable", returnDT,
|
||||||
storageAllocator, varnodes, returnResultAliasVars, true);
|
storageAllocator, varnodes, returnResultAliasVars, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
*/
|
*/
|
||||||
public class GolangElfInfoProducer implements ElfInfoProducer {
|
public class GolangElfInfoProducer implements ElfInfoProducer {
|
||||||
private static final Map<String, ReaderFunc<ElfInfoItem>> GOLANGINFO_READERS = Map.of(
|
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);
|
NoteGoBuildId.SECTION_NAME, NoteGoBuildId::read);
|
||||||
|
|
||||||
private ElfLoadHelper elfLoadHelper;
|
private ElfLoadHelper elfLoadHelper;
|
||||||
|
@ -21,14 +21,12 @@ import java.util.*;
|
|||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.golang.rtti.types.GoType;
|
import ghidra.app.util.bin.format.golang.rtti.types.GoType;
|
||||||
import ghidra.app.util.bin.format.golang.structmapping.*;
|
import ghidra.app.util.bin.format.golang.structmapping.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressRange;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolUtilities;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
@ -50,10 +48,25 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
|||||||
@MarkupReference
|
@MarkupReference
|
||||||
private long pcHeader; // pointer to the GoPcHeader instance, useful for bootstrapping
|
private long pcHeader; // pointer to the GoPcHeader instance, useful for bootstrapping
|
||||||
|
|
||||||
|
@FieldMapping
|
||||||
|
private long data;
|
||||||
|
|
||||||
|
@FieldMapping
|
||||||
|
private long edata;
|
||||||
|
|
||||||
@FieldMapping
|
@FieldMapping
|
||||||
@MarkupReference
|
@MarkupReference
|
||||||
private long text;
|
private long text;
|
||||||
|
|
||||||
|
@FieldMapping
|
||||||
|
private long etext;
|
||||||
|
|
||||||
|
@FieldMapping
|
||||||
|
private long noptrdata;
|
||||||
|
|
||||||
|
@FieldMapping
|
||||||
|
private long enoptrdata;
|
||||||
|
|
||||||
@FieldMapping(fieldName = "types")
|
@FieldMapping(fieldName = "types")
|
||||||
private long typesOffset;
|
private long typesOffset;
|
||||||
|
|
||||||
@ -63,6 +76,9 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
|||||||
@FieldMapping(optional = true)
|
@FieldMapping(optional = true)
|
||||||
private long gofunc;
|
private long gofunc;
|
||||||
|
|
||||||
|
@FieldMapping
|
||||||
|
private long end;
|
||||||
|
|
||||||
@FieldMapping(fieldName = "typelinks")
|
@FieldMapping(fieldName = "typelinks")
|
||||||
private GoSlice typeLinks;
|
private GoSlice typeLinks;
|
||||||
|
|
||||||
@ -120,6 +136,24 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
|||||||
return programContext.getCodeAddress(text);
|
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
|
* 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
|
* @return true if this module data structure contains sane values
|
||||||
*/
|
*/
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
MemoryBlock txtBlock = programContext.getProgram().getMemory().getBlock(".text");
|
MemoryBlock txtBlock = programContext.getGoSection("text");
|
||||||
if (txtBlock != null && !txtBlock.contains(getText())) {
|
if (txtBlock != null && !txtBlock.contains(getText())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryBlock typelinkBlock = programContext.getProgram().getMemory().getBlock(".typelink");
|
MemoryBlock typelinkBlock = programContext.getGoSection("typelink");
|
||||||
if (typelinkBlock != null &&
|
if (typelinkBlock != null &&
|
||||||
typelinkBlock.getStart().getOffset() != typeLinks.getArrayOffset()) {
|
typelinkBlock.getStart().getOffset() != typeLinks.getArrayOffset()) {
|
||||||
return false;
|
return false;
|
||||||
@ -396,8 +430,7 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
|
|||||||
/* package */ static GoModuledata getFirstModuledata(GoRttiMapper context)
|
/* package */ static GoModuledata getFirstModuledata(GoRttiMapper context)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Program program = context.getProgram();
|
Program program = context.getProgram();
|
||||||
Symbol firstModuleDataSymbol =
|
Symbol firstModuleDataSymbol = GoRttiMapper.getGoSymbol(program, "runtime.firstmoduledata");
|
||||||
SymbolUtilities.getUniqueSymbol(program, "runtime.firstmoduledata");
|
|
||||||
if (firstModuleDataSymbol == null) {
|
if (firstModuleDataSymbol == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import ghidra.program.model.listing.Program;
|
|||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolUtilities;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,7 +38,7 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
@StructureMapping(structureName = "runtime.pcHeader")
|
@StructureMapping(structureName = "runtime.pcHeader")
|
||||||
public class GoPcHeader {
|
public class GoPcHeader {
|
||||||
private static final String RUNTIME_PCLNTAB_SYMBOLNAME = "runtime.pclntab";
|
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_2_MAGIC = 0xfffffffb;
|
||||||
public static final int GO_1_16_MAGIC = 0xfffffffa;
|
public static final int GO_1_16_MAGIC = 0xfffffffa;
|
||||||
public static final int GO_1_18_MAGIC = 0xfffffff0;
|
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
|
* @return {@link Address} of go pclntab, or null if not present
|
||||||
*/
|
*/
|
||||||
public static Address getPclntabAddress(Program program) {
|
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) {
|
if (pclntabBlock != null) {
|
||||||
return pclntabBlock.getStart();
|
return pclntabBlock.getStart();
|
||||||
}
|
}
|
||||||
// PE binaries have a symbol instead of a named section
|
// 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
|
return pclntabSymbol != null
|
||||||
? pclntabSymbol.getAddress()
|
? pclntabSymbol.getAddress()
|
||||||
: null;
|
: 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.rtti.types.*;
|
||||||
import ghidra.app.util.bin.format.golang.structmapping.*;
|
import ghidra.app.util.bin.format.golang.structmapping.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.app.util.opinion.ElfLoader;
|
import ghidra.app.util.opinion.*;
|
||||||
import ghidra.app.util.opinion.PeLoader;
|
import ghidra.framework.Platform;
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
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.data.StandAloneDataTypeManager.LanguageUpdateOption;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
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.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
@ -210,10 +210,14 @@ public class GoRttiMapper extends DataTypeMapper {
|
|||||||
else if (PeLoader.PE_NAME.equals(loaderName)) {
|
else if (PeLoader.PE_NAME.equals(loaderName)) {
|
||||||
return "win";
|
return "win";
|
||||||
}
|
}
|
||||||
else {
|
else if (MachoLoader.MACH_O_NAME.equals(loaderName)) {
|
||||||
return null;
|
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.
|
* 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());
|
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.
|
* Return the address of the golang zerobase symbol, or an artificial substitute.
|
||||||
* <p>
|
* <p>
|
||||||
@ -261,7 +317,7 @@ public class GoRttiMapper extends DataTypeMapper {
|
|||||||
* @return {@link Address} of the runtime.zerobase, or artificial substitute
|
* @return {@link Address} of the runtime.zerobase, or artificial substitute
|
||||||
*/
|
*/
|
||||||
public static Address getZerobaseAddress(Program prog) {
|
public static Address getZerobaseAddress(Program prog) {
|
||||||
Symbol zerobaseSym = SymbolUtilities.getUniqueSymbol(prog, "runtime.zerobase");
|
Symbol zerobaseSym = getGoSymbol(prog, "runtime.zerobase");
|
||||||
Address zerobaseAddr =
|
Address zerobaseAddr =
|
||||||
zerobaseSym != null ? zerobaseSym.getAddress() : getArtificalZerobaseAddress(prog);
|
zerobaseSym != null ? zerobaseSym.getAddress() : getArtificalZerobaseAddress(prog);
|
||||||
if (zerobaseAddr == null) {
|
if (zerobaseAddr == null) {
|
||||||
@ -276,8 +332,7 @@ public class GoRttiMapper extends DataTypeMapper {
|
|||||||
"ARTIFICIAL.runtime.zerobase";
|
"ARTIFICIAL.runtime.zerobase";
|
||||||
|
|
||||||
private static Address getArtificalZerobaseAddress(Program program) {
|
private static Address getArtificalZerobaseAddress(Program program) {
|
||||||
Symbol zerobaseSym =
|
Symbol zerobaseSym = getGoSymbol(program, ARTIFICIAL_RUNTIME_ZEROBASE_SYMBOLNAME);
|
||||||
SymbolUtilities.getUniqueSymbol(program, ARTIFICIAL_RUNTIME_ZEROBASE_SYMBOLNAME);
|
|
||||||
return zerobaseSym != null ? zerobaseSym.getAddress() : null;
|
return zerobaseSym != null ? zerobaseSym.getAddress() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +534,7 @@ public class GoRttiMapper extends DataTypeMapper {
|
|||||||
* @return {@link GoModuledata}
|
* @return {@link GoModuledata}
|
||||||
*/
|
*/
|
||||||
public GoModuledata getFirstModule() {
|
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() {
|
private AddressRange getPclntabSearchRange() {
|
||||||
MemoryBlock memBlock = getFirstMemoryBlock(program, ".noptrdata", ".rdata");
|
MemoryBlock memBlock = getFirstGoSection(program, "noptrdata", "rdata");
|
||||||
return memBlock != null
|
return memBlock != null
|
||||||
? new AddressRangeImpl(memBlock.getStart(), memBlock.getEnd())
|
? new AddressRangeImpl(memBlock.getStart(), memBlock.getEnd())
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AddressRange getModuledataSearchRange() {
|
private AddressRange getModuledataSearchRange() {
|
||||||
MemoryBlock memBlock = getFirstMemoryBlock(program, ".noptrdata", ".data");
|
MemoryBlock memBlock = getFirstGoSection(program, "noptrdata", "data");
|
||||||
return memBlock != null
|
return memBlock != null
|
||||||
? new AddressRangeImpl(memBlock.getStart(), memBlock.getEnd())
|
? new AddressRangeImpl(memBlock.getStart(), memBlock.getEnd())
|
||||||
: null;
|
: null;
|
||||||
@ -1389,15 +1444,11 @@ public class GoRttiMapper extends DataTypeMapper {
|
|||||||
* @return {@link AddressSetView} of range that is valid to find string structs in
|
* @return {@link AddressSetView} of range that is valid to find string structs in
|
||||||
*/
|
*/
|
||||||
public AddressSetView getStringStructRange() {
|
public AddressSetView getStringStructRange() {
|
||||||
MemoryBlock datamb = program.getMemory().getBlock(".data");
|
AddressSet result = new AddressSet();
|
||||||
MemoryBlock rodatamb = getFirstMemoryBlock(program, ".rodata", ".rdata");
|
for (GoModuledata moduledata : modules) {
|
||||||
|
result.add(moduledata.getDataRange());
|
||||||
if (datamb == null || rodatamb == null) {
|
result.add(moduledata.getRoDataRange());
|
||||||
return new AddressSet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressSet result = new AddressSet(datamb.getStart(), datamb.getEnd());
|
|
||||||
result.add(rodatamb.getStart(), rodatamb.getEnd());
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1407,21 +1458,29 @@ public class GoRttiMapper extends DataTypeMapper {
|
|||||||
* @return {@link AddressSetView} of range that is valid for string char[] data
|
* @return {@link AddressSetView} of range that is valid for string char[] data
|
||||||
*/
|
*/
|
||||||
public AddressSetView getStringDataRange() {
|
public AddressSetView getStringDataRange() {
|
||||||
MemoryBlock rodatamb = getFirstMemoryBlock(program, ".rodata", ".rdata");
|
// TODO: initialized []byte("stringchars") slices can have data in noptrdata section
|
||||||
return rodatamb != null
|
AddressSet result = new AddressSet();
|
||||||
? new AddressSet(rodatamb.getStart(), rodatamb.getEnd())
|
for (GoModuledata moduledata : modules) {
|
||||||
: new AddressSet();
|
result.add(moduledata.getRoDataRange());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MemoryBlock getFirstMemoryBlock(Program program, String... blockNames) {
|
public AddressSetView getTextAddresses() {
|
||||||
Memory memory = program.getMemory();
|
AddressSet result = new AddressSet();
|
||||||
for (String blockToSearch : blockNames) {
|
for (GoModuledata moduledata : modules) {
|
||||||
MemoryBlock memBlock = memory.getBlock(blockToSearch);
|
result.add(moduledata.getTextRange());
|
||||||
if (memBlock != null) {
|
|
||||||
return memBlock;
|
|
||||||
}
|
}
|
||||||
|
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.Option;
|
||||||
import ghidra.app.util.bin.ByteProvider;
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.ByteProviderWrapper;
|
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.macho.*;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.app.util.bin.format.ubi.*;
|
import ghidra.app.util.bin.format.ubi.*;
|
||||||
@ -61,12 +63,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||||||
MachHeader machHeader = new MachHeader(provider);
|
MachHeader machHeader = new MachHeader(provider);
|
||||||
String magic =
|
String magic =
|
||||||
CpuTypes.getMagicString(machHeader.getCpuType(), machHeader.getCpuSubType());
|
CpuTypes.getMagicString(machHeader.getCpuType(), machHeader.getCpuSubType());
|
||||||
List<String> sectionNames = machHeader.parseSegments()
|
String compiler = detectCompilerName(machHeader);
|
||||||
.stream()
|
|
||||||
.flatMap(seg -> seg.getSections().stream())
|
|
||||||
.map(section -> section.getSectionName())
|
|
||||||
.toList();
|
|
||||||
String compiler = SwiftUtils.isSwift(sectionNames) ? "swift" : null;
|
|
||||||
List<QueryResult> results = QueryOpinionService.query(MACH_O_NAME, magic, compiler);
|
List<QueryResult> results = QueryOpinionService.query(MACH_O_NAME, magic, compiler);
|
||||||
for (QueryResult result : results) {
|
for (QueryResult result : results) {
|
||||||
loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result));
|
loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result));
|
||||||
@ -81,6 +78,19 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||||||
return loadSpecs;
|
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
|
@Override
|
||||||
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||||
Program program, TaskMonitor monitor, MessageLog log) throws IOException {
|
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.MemoryBlockUtils;
|
||||||
import ghidra.app.util.bin.*;
|
import ghidra.app.util.bin.*;
|
||||||
import ghidra.app.util.bin.format.RelocationException;
|
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.*;
|
||||||
import ghidra.app.util.bin.format.macho.commands.*;
|
import ghidra.app.util.bin.format.macho.commands.*;
|
||||||
import ghidra.app.util.bin.format.macho.commands.ExportTrie.ExportEntry;
|
import ghidra.app.util.bin.format.macho.commands.ExportTrie.ExportEntry;
|
||||||
@ -154,6 +158,9 @@ public class MachoProgramBuilder {
|
|||||||
// Set program info
|
// Set program info
|
||||||
setRelocatableProperty();
|
setRelocatableProperty();
|
||||||
setProgramDescription();
|
setProgramDescription();
|
||||||
|
if (GoRttiMapper.isGolangProgram(program)) {
|
||||||
|
markupAndSetGolangInitialProgramProperties();
|
||||||
|
}
|
||||||
|
|
||||||
// Perform additional actions
|
// Perform additional actions
|
||||||
renameObjMsgSendRtpSymbol();
|
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() {
|
protected void setCompiler() {
|
||||||
// Check for Rust
|
// Check for Rust
|
||||||
try {
|
try {
|
||||||
|
@ -29,7 +29,7 @@ import ghidra.app.util.bin.BinaryReader;
|
|||||||
import ghidra.app.util.bin.ByteProvider;
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem.ItemWithAddress;
|
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.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.golang.rtti.GoRttiMapper;
|
||||||
import ghidra.app.util.bin.format.mz.DOSHeader;
|
import ghidra.app.util.bin.format.mz.DOSHeader;
|
||||||
import ghidra.app.util.bin.format.pe.*;
|
import ghidra.app.util.bin.format.pe.*;
|
||||||
@ -298,7 +298,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
private void processGolangProperties(OptionalHeader optionalHeader, NTHeader ntHeader,
|
private void processGolangProperties(OptionalHeader optionalHeader, NTHeader ntHeader,
|
||||||
Program prog, TaskMonitor monitor) {
|
Program prog, TaskMonitor monitor) {
|
||||||
|
|
||||||
ItemWithAddress<PEGoBuildId> buildId = PEGoBuildId.findBuildId(prog);
|
ItemWithAddress<GoBuildId> buildId = GoBuildId.findBuildId(prog);
|
||||||
if (buildId != null) {
|
if (buildId != null) {
|
||||||
buildId.item().markupProgram(prog, buildId.address());
|
buildId.item().markupProgram(prog, buildId.address());
|
||||||
}
|
}
|
||||||
@ -1141,7 +1141,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
SectionHeader textSection = pe.getNTHeader().getFileHeader().getSectionHeader(".text");
|
SectionHeader textSection = pe.getNTHeader().getFileHeader().getSectionHeader(".text");
|
||||||
if (textSection != null) {
|
if (textSection != null) {
|
||||||
try (InputStream is = textSection.getDataStream()) {
|
try (InputStream is = textSection.getDataStream()) {
|
||||||
PEGoBuildId buildId = PEGoBuildId.read(is);
|
GoBuildId buildId = GoBuildId.read(is);
|
||||||
buildIdPresent = buildId != null;
|
buildIdPresent = buildId != null;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -11,6 +11,8 @@ data/languages/AARCH64BE.slaspec||GHIDRA||||END|
|
|||||||
data/languages/AARCH64_AMXext.sinc||GHIDRA||||END|
|
data/languages/AARCH64_AMXext.sinc||GHIDRA||||END|
|
||||||
data/languages/AARCH64_AppleSilicon.slaspec||GHIDRA||||END|
|
data/languages/AARCH64_AppleSilicon.slaspec||GHIDRA||||END|
|
||||||
data/languages/AARCH64_base_PACoptions.sinc||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_ilp32.cspec||GHIDRA||||END|
|
||||||
data/languages/AARCH64_swift.cspec||GHIDRA||||END|
|
data/languages/AARCH64_swift.cspec||GHIDRA||||END|
|
||||||
data/languages/AARCH64_win.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>
|
<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="default" spec="AARCH64.cspec" id="default"/>
|
||||||
<compiler name="Visual Studio" spec="AARCH64_win.cspec" id="windows"/>
|
<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="gnu" name="aarch64"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||||
<external_name tool="qemu" name="qemu-aarch64"/>
|
<external_name tool="qemu" name="qemu-aarch64"/>
|
||||||
@ -28,8 +29,10 @@
|
|||||||
id="AARCH64:BE:64:v8A">
|
id="AARCH64:BE:64:v8A">
|
||||||
<description>Generic ARM64 v8.5-A LE instructions, BE data, missing some 8.5 vector</description>
|
<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="default" spec="AARCH64.cspec" id="default"/>
|
||||||
|
<compiler name="golang" spec="AARCH64_golang.cspec" id="golang"/>
|
||||||
<external_name tool="gnu" name="aarch64"/>
|
<external_name tool="gnu" name="aarch64"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
<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"/>
|
<external_name tool="qemu" name="qemu-aarch64_be"/>
|
||||||
</language>
|
</language>
|
||||||
<language processor="AARCH64"
|
<language processor="AARCH64"
|
||||||
@ -44,6 +47,7 @@
|
|||||||
<description>Generic ARM64 v8.5-A LE instructions, LE data, ilp32</description>
|
<description>Generic ARM64 v8.5-A LE instructions, LE data, ilp32</description>
|
||||||
<truncate_space space="ram" size="4"/>
|
<truncate_space space="ram" size="4"/>
|
||||||
<compiler name="default" spec="AARCH64_ilp32.cspec" id="default"/>
|
<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="gnu" name="aarch64:ilp32"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||||
<external_name tool="qemu" name="qemu-aarch64"/>
|
<external_name tool="qemu" name="qemu-aarch64"/>
|
||||||
@ -61,6 +65,7 @@
|
|||||||
<description>Generic ARM64 v8.5-A LE instructions, BE data, ilp32</description>
|
<description>Generic ARM64 v8.5-A LE instructions, BE data, ilp32</description>
|
||||||
<truncate_space space="ram" size="4"/>
|
<truncate_space space="ram" size="4"/>
|
||||||
<compiler name="default" spec="AARCH64_ilp32.cspec" id="default"/>
|
<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="gnu" name="aarch64:ilp32"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||||
<external_name tool="qemu" name="qemu-aarch64_be"/>
|
<external_name tool="qemu" name="qemu-aarch64_be"/>
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
<constraint loader="Mac OS X Mach-O" compilerSpecID="swift">
|
<constraint loader="Mac OS X Mach-O" compilerSpecID="swift">
|
||||||
<constraint primary="16777228" secondary="swift" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
|
<constraint primary="16777228" secondary="swift" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
|
||||||
</constraint>
|
</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 loader="DYLD Cache" compilerSpecID="default">
|
||||||
<constraint primary="AARCH64" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
|
<constraint primary="AARCH64" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
|
||||||
<constraint primary="ARM64_32" processor="AARCH64" endian="little" size="32" variant="ilp32" />
|
<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>
|
<description>AppleSilicon ARM v8.5-A LE instructions, LE data, AMX extensions</description>
|
||||||
<compiler name="default" spec="AARCH64.cspec" id="default"/>
|
<compiler name="default" spec="AARCH64.cspec" id="default"/>
|
||||||
<compiler name="Swift" spec="AARCH64_swift.cspec" id="swift"/>
|
<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"/>
|
||||||
<external_name tool="gnu" name="aarch64:ilp32"/>
|
<external_name tool="gnu" name="aarch64:ilp32"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>
|
||||||
|
<external_name tool="Golang.register.info.file" name="AARCH64_golang.register.info"/>
|
||||||
</language>
|
</language>
|
||||||
</language_definitions>
|
</language_definitions>
|
||||||
|
Loading…
Reference in New Issue
Block a user