GP-3182: Certify and cleanup

This commit is contained in:
Ryan Kurtz
2025-03-19 06:52:32 -04:00
parent c9ab679e53
commit 6beee36e57
9 changed files with 411 additions and 487 deletions

View File

@@ -18,14 +18,9 @@ package ghidra.app.util.bin.format.unixaout;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.bin.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.util.CodeUnitInsertionException;
@@ -74,168 +69,165 @@ public class UnixAoutHeader implements StructConverter {
// The Linux implementation of a.out appears to start the .text content at
// file offset 0x400 (rather than immediately after the 0x20 bytes of header
// data). It's possible that there exist Linux a.out executabes with other
// data). It's possible that there exist Linux a.out executabLes with other
// (unintended?) header sizes caused by a mixture of 32- and 64-bit integers
// being padded out in the struct. The intended size is eight 32-bit words
// (32 bytes total.)
private static final int sizeOfExecHeader = 0x20;
private static final int sizeOfLongExecHeader = 0x400;
private static final int SIZE_OF_EXEC_HEADER = 0x20;
private static final int SIZE_OF_LONG_EXEC_HEADER = 0x400;
/**
* Interprets binary data as an exec header from a UNIX-style a.out executable,
* and validates the contained fields.
* Interprets binary data as an exec header from a UNIX-style a.out executable, and validates
* the contained fields.
*
* @param provider Source of header binary data
* @param isLittleEndian Flag indicating whether to interpret the data as
* little-endian.
* @throws IOException
* @param provider Source of header binary data
* @param isLittleEndian Flag indicating whether to interpret the data as little-endian.
* @throws IOException if an IO-related error occurred
*/
public UnixAoutHeader(ByteProvider provider, boolean isLittleEndian) throws IOException {
this.reader = new BinaryReader(provider, isLittleEndian);
reader = new BinaryReader(provider, isLittleEndian);
this.a_magic = reader.readNextUnsignedInt();
this.a_text = reader.readNextUnsignedInt();
this.a_data = reader.readNextUnsignedInt();
this.a_bss = reader.readNextUnsignedInt();
this.a_syms = reader.readNextUnsignedInt();
this.a_entry = reader.readNextUnsignedInt();
this.a_trsize = reader.readNextUnsignedInt();
this.a_drsize = reader.readNextUnsignedInt();
this.binarySize = reader.length();
a_magic = reader.readNextUnsignedInt();
a_text = reader.readNextUnsignedInt();
a_data = reader.readNextUnsignedInt();
a_bss = reader.readNextUnsignedInt();
a_syms = reader.readNextUnsignedInt();
a_entry = reader.readNextUnsignedInt();
a_trsize = reader.readNextUnsignedInt();
a_drsize = reader.readNextUnsignedInt();
binarySize = reader.length();
checkExecutableType();
setExecutableType(a_magic);
// NOTE: In NetBSD/i386 examples of a.out, the "new-style" 32-bit a_magic/midmag
// word
// is written in big-endian regardless of the data endianness in the rest of the
// file.
if ((this.exeType == AoutType.UNKNOWN) && isLittleEndian) {
this.a_magic = Integer.reverseBytes((int) this.a_magic);
checkExecutableType();
// NOTE: In NetBSD/i386 examples of a.out, the "new-style" 32-bit a_magic/midmag word is
// written in big-endian regardless of the data endianness in the rest of the file.
if ((exeType == AoutType.UNKNOWN) && isLittleEndian) {
a_magic = Integer.reverseBytes((int) a_magic);
setExecutableType(a_magic);
}
checkMachineTypeValidity(isLittleEndian);
determineTextOffset(reader, isLittleEndian);
determineTextOffset();
this.datOffset = this.txtOffset + this.a_text;
this.txtRelOffset = this.datOffset + this.a_data;
this.datRelOffset = this.txtRelOffset + this.a_trsize;
this.symOffset = this.datRelOffset + this.a_drsize;
this.strOffset = this.symOffset + this.a_syms;
datOffset = txtOffset + a_text;
txtRelOffset = datOffset + a_data;
datRelOffset = txtRelOffset + a_trsize;
symOffset = datRelOffset + a_drsize;
strOffset = symOffset + a_syms;
this.strSize = 0;
if (this.strOffset != 0 && (this.strOffset + 4) <= binarySize) {
this.strSize = reader.readUnsignedInt(this.strOffset);
strSize = 0;
if (strOffset != 0 && (strOffset + 4) <= binarySize) {
strSize = reader.readUnsignedInt(strOffset);
}
determineTextAddr();
this.txtEndAddr = this.txtAddr + this.a_text;
this.datAddr = (this.exeType == AoutType.OMAGIC) ? this.txtEndAddr : segmentRound(this.txtEndAddr);
this.bssAddr = this.datAddr + this.a_data;
txtEndAddr = txtAddr + a_text;
datAddr = (exeType == AoutType.OMAGIC) ? txtEndAddr : segmentRound(txtEndAddr);
bssAddr = datAddr + a_data;
}
public BinaryReader getReader() {
return this.reader;
return reader;
}
/**
* Returns the processor/language specified by this header.
* {@return the processor/language specified by this header.}
*/
public String getLanguageSpec() {
return this.languageSpec;
return languageSpec;
}
/**
* Returns the compiler used by this executable. This is left as 'default' for
* all machine types other than i386, where it is assumed to be gcc.
* {@return the compiler used by this executable. This is left as 'default' for
* all machine types other than i386, where it is assumed to be gcc.}
*/
public String getCompilerSpec() {
return this.compilerSpec;
return compilerSpec;
}
/**
* Returns the enumerated type of executable contained in this A.out file.
* {@return the enumerated type of executable contained in this A.out file.}
*/
public AoutType getExecutableType() {
return this.exeType;
return exeType;
}
/**
* Returns an indication of whether this header's fields are all valid; this
* includes the machine type, executable type, and section offsets.
* {@return an indication of whether this header's fields are all valid; this
* includes the machine type, executable type, and section offsets.}
*/
public boolean isValid() {
return isMachineTypeValid() &&
(this.exeType != AoutType.UNKNOWN) &&
areOffsetsValid();
(exeType != AoutType.UNKNOWN) &&
areOffsetsValid();
}
public long getTextSize() {
return this.a_text;
return a_text;
}
public long getDataSize() {
return this.a_data;
return a_data;
}
public long getBssSize() {
return this.a_bss;
return a_bss;
}
public long getSymSize() {
return this.a_syms;
return a_syms;
}
public long getStrSize() {
return this.strSize;
return strSize;
}
public long getEntryPoint() {
return this.a_entry;
return a_entry;
}
public long getTextRelocSize() {
return this.a_trsize;
return a_trsize;
}
public long getDataRelocSize() {
return this.a_drsize;
return a_drsize;
}
public long getTextOffset() {
return this.txtOffset;
return txtOffset;
}
public long getDataOffset() {
return this.datOffset;
return datOffset;
}
public long getTextRelocOffset() {
return this.txtRelOffset;
return txtRelOffset;
}
public long getDataRelocOffset() {
return this.datRelOffset;
return datRelOffset;
}
public long getSymOffset() {
return this.symOffset;
return symOffset;
}
public long getStrOffset() {
return this.strOffset;
return strOffset;
}
public long getTextAddr() {
return this.txtAddr;
return txtAddr;
}
public long getDataAddr() {
return this.datAddr;
return datAddr;
}
public long getBssAddr() {
return this.bssAddr;
return bssAddr;
}
/**
@@ -244,9 +236,9 @@ public class UnixAoutHeader implements StructConverter {
*/
private void checkMachineTypeValidity(boolean readingAsLittleEndian) {
this.machineTypeValid = true;
this.pageSize = 4096;
final short machtype = (short) ((this.a_magic >> 16) & 0xFF);
machineTypeValid = true;
pageSize = 4096;
final short machtype = (short) ((a_magic >> 16) & 0xFF);
final String readEndianness = readingAsLittleEndian ? "LE" : "BE";
switch (machtype) {
@@ -254,108 +246,108 @@ public class UnixAoutHeader implements StructConverter {
* Motorola 68K family
*/
case UnixAoutMachineType.M_68010:
this.languageSpec = "68000:BE:32:MC68010";
languageSpec = "68000:BE:32:MC68010";
break;
case UnixAoutMachineType.M_68020:
this.languageSpec = "68000:BE:32:MC68020";
languageSpec = "68000:BE:32:MC68020";
break;
case UnixAoutMachineType.M_M68K_NETBSD:
this.pageSize = 8192;
pageSize = 8192;
case UnixAoutMachineType.M_M68K4K_NETBSD:
this.isNetBSD = true;
this.languageSpec = "68000:BE:32:default";
isNetBSD = true;
languageSpec = "68000:BE:32:default";
break;
/**
* SPARC family
*/
case UnixAoutMachineType.M_SPARC_NETBSD:
this.isNetBSD = true;
isNetBSD = true;
case UnixAoutMachineType.M_SPARC:
case UnixAoutMachineType.M_SPARCLET:
this.isSparc = true;
this.pageSize = 8192;
this.languageSpec = "sparc:BE:32:default";
isSparc = true;
pageSize = 8192;
languageSpec = "sparc:BE:32:default";
break;
case UnixAoutMachineType.M_SPARC64_NETBSD:
this.isNetBSD = true;
this.isSparc = true;
this.languageSpec = "sparc:BE:64:default";
isNetBSD = true;
isSparc = true;
languageSpec = "sparc:BE:64:default";
break;
/**
* MIPS family
*/
case UnixAoutMachineType.M_PMAX_NETBSD:
this.isNetBSD = true;
isNetBSD = true;
case UnixAoutMachineType.M_MIPS1:
case UnixAoutMachineType.M_MIPS2:
case UnixAoutMachineType.M_R3000:
this.languageSpec = "MIPS:LE:32:default";
languageSpec = "MIPS:LE:32:default";
break;
case UnixAoutMachineType.M_MIPS:
this.languageSpec = "MIPS:BE:32:default";
languageSpec = "MIPS:BE:32:default";
break;
/**
* National Semiconductor NS32000 family
*/
case UnixAoutMachineType.M_532_NETBSD:
this.isNetBSD = true;
isNetBSD = true;
case UnixAoutMachineType.M_NS32032:
case UnixAoutMachineType.M_NS32532:
this.languageSpec = "UNKNOWN:LE:32:default";
languageSpec = "UNKNOWN:LE:32:default";
break;
/**
* x86 family
*/
case UnixAoutMachineType.M_386_NETBSD:
this.isNetBSD = true;
isNetBSD = true;
case UnixAoutMachineType.M_386:
case UnixAoutMachineType.M_386_DYNIX:
this.compilerSpec = "gcc";
this.languageSpec = "x86:LE:32:default";
compilerSpec = "gcc";
languageSpec = "x86:LE:32:default";
break;
case UnixAoutMachineType.M_X86_64_NETBSD:
this.compilerSpec = "gcc";
this.languageSpec = "x86:LE:64:default";
compilerSpec = "gcc";
languageSpec = "x86:LE:64:default";
break;
/**
* ARM family
*/
case UnixAoutMachineType.M_ARM6_NETBSD:
this.isNetBSD = true;
isNetBSD = true;
case UnixAoutMachineType.M_ARM:
this.languageSpec = "ARM:" + readEndianness + ":32:default";
languageSpec = "ARM:" + readEndianness + ":32:default";
break;
case UnixAoutMachineType.M_AARCH64:
this.languageSpec = "AARCH64:" + readEndianness + ":64:default";
languageSpec = "AARCH64:" + readEndianness + ":64:default";
break;
/**
* RISC family
*/
case UnixAoutMachineType.M_OR1K:
this.languageSpec = "UNKNOWN:BE:32:default";
languageSpec = "UNKNOWN:BE:32:default";
break;
case UnixAoutMachineType.M_RISCV:
this.languageSpec = "RISCV:LE:32:default";
languageSpec = "RISCV:LE:32:default";
break;
case UnixAoutMachineType.M_HPPA_OPENBSD:
this.languageSpec = "pa-risc:BE:32:default";
languageSpec = "pa-risc:BE:32:default";
break;
/**
* PowerPC family
*/
case UnixAoutMachineType.M_POWERPC_NETBSD:
this.isNetBSD = true;
this.languageSpec = "PowerPC:" + readEndianness + ":32:default";
isNetBSD = true;
languageSpec = "PowerPC:" + readEndianness + ":32:default";
break;
case UnixAoutMachineType.M_POWERPC64:
this.languageSpec = "PowerPC:" + readEndianness + ":64:default";
languageSpec = "PowerPC:" + readEndianness + ":64:default";
break;
/**
@@ -366,52 +358,52 @@ public class UnixAoutHeader implements StructConverter {
*/
case UnixAoutMachineType.M_SH3:
case UnixAoutMachineType.M_SH5_32:
this.languageSpec = "SuperH:BE:32:default";
languageSpec = "SuperH:BE:32:default";
break;
case UnixAoutMachineType.M_SH5_64:
this.languageSpec = "SuperH:BE:64:default";
languageSpec = "SuperH:BE:64:default";
break;
/**
* VAX family
*/
case UnixAoutMachineType.M_VAX_NETBSD:
this.pageSize = 512;
pageSize = 512;
case UnixAoutMachineType.M_VAX4K_NETBSD:
this.isNetBSD = true;
this.languageSpec = "UNKNOWN:LE:32:default";
isNetBSD = true;
languageSpec = "UNKNOWN:LE:32:default";
break;
/**
* Other
*/
case UnixAoutMachineType.M_CRIS:
this.languageSpec = "UNKNOWN:LE:32:default";
languageSpec = "UNKNOWN:LE:32:default";
break;
case UnixAoutMachineType.M_ALPHA_NETBSD:
this.isNetBSD = true;
isNetBSD = true;
case UnixAoutMachineType.M_IA64:
this.languageSpec = "UNKNOWN:" + readEndianness + ":64:default";
languageSpec = "UNKNOWN:" + readEndianness + ":64:default";
break;
case UnixAoutMachineType.M_29K:
case UnixAoutMachineType.M_88K_OPENBSD:
this.languageSpec = "UNKNOWN:" + readEndianness + ":32:default";
languageSpec = "UNKNOWN:" + readEndianness + ":32:default";
break;
case UnixAoutMachineType.M_UNKNOWN:
this.languageSpec = "UNKNOWN:" + readEndianness + ":32:default";
languageSpec = "UNKNOWN:" + readEndianness + ":32:default";
break;
default:
this.machineTypeValid = false;
machineTypeValid = false;
}
// Check that the detected architecture's endianness matches the endianness
// with which we're reading the file; if there's a mismatch, clear the
// machineTypeValid flag because this was evidently a false reading.
if (this.machineTypeValid) {
String[] languageTokens = this.languageSpec.split(":");
if (machineTypeValid) {
String[] languageTokens = languageSpec.split(":");
if ((languageTokens.length < 2) ||
!languageTokens[1].equalsIgnoreCase(readEndianness)) {
this.machineTypeValid = false;
!languageTokens[1].equalsIgnoreCase(readEndianness)) {
machineTypeValid = false;
}
}
}
@@ -421,35 +413,23 @@ public class UnixAoutHeader implements StructConverter {
* ID.
*/
private boolean isMachineTypeValid() {
return this.machineTypeValid;
return machineTypeValid;
}
/**
* Returns a flag indicating whether this header contains a representation of a
* valid executable type.
* Sets the executable type based on the given magic
*
* @param magic The magic
*/
private void checkExecutableType() {
final short exetypeMagic = (short) (this.a_magic & 0xFFFF);
switch (exetypeMagic) {
case 0x111: // 0421: core file
this.exeType = AoutType.CMAGIC;
break;
case 0x108: // 0410: pure executable
this.exeType = AoutType.NMAGIC;
break;
case 0x107: // 0407: object file or impure executable
this.exeType = AoutType.OMAGIC;
break;
case 0x0CC: // 0314: demand-paged exe w/ header in .text
this.exeType = AoutType.QMAGIC;
break;
case 0x10B: // 0413: demand-paged executable
this.exeType = AoutType.ZMAGIC;
break;
default:
this.exeType = AoutType.UNKNOWN;
}
private void setExecutableType(long magic) {
exeType = switch ((short) (magic & 0xFFFF)) {
case 0x111 -> AoutType.CMAGIC; // 0421: core file
case 0x108 -> AoutType.NMAGIC; // 0410: pure executable
case 0x107 -> AoutType.OMAGIC; // 0407: object file or impure executable
case 0x0CC -> AoutType.QMAGIC; // 0314: demand-paged exe w/ header in .text
case 0x10B -> AoutType.ZMAGIC; // 0413: demand-paged executable
default -> AoutType.UNKNOWN;
};
}
/**
@@ -465,46 +445,51 @@ public class UnixAoutHeader implements StructConverter {
* the a_magic word even when the file contains code for a little-endian
* processor.
*/
private void determineTextOffset(BinaryReader reader, boolean isLittleEndian) {
private void determineTextOffset() {
boolean isLinuxStyle = false;
final long fixedContentSize = this.a_text + this.a_data + this.a_syms + this.a_trsize + this.a_drsize;
final long fixedContentSize = a_text + a_data + a_syms + a_trsize + a_drsize;
// If the file is large enough to read at least one word beyond a long-style
// header
// of 0x400 bytes plus all the sections whose sizes are specified in the
// header...
if (reader.isValidIndex(sizeOfLongExecHeader + fixedContentSize)) {
if (reader.isValidIndex(SIZE_OF_LONG_EXEC_HEADER + fixedContentSize)) {
try {
// The word that immediately follows the symbol table will contain the size of
// the string table.
final long stringTableLength = reader.readUnsignedInt(sizeOfLongExecHeader + fixedContentSize);
final long longHeaderExpectedFileSize = sizeOfLongExecHeader + fixedContentSize + stringTableLength;
final long stringTableLength =
reader.readUnsignedInt(SIZE_OF_LONG_EXEC_HEADER + fixedContentSize);
final long longHeaderExpectedFileSize =
SIZE_OF_LONG_EXEC_HEADER + fixedContentSize + stringTableLength;
// If the size of the file exactly matches what we'd expect if the .text content
// starts at offset 0x400 rather than 0, this implies that the a.out is a
// Linux-style binary.
if (this.binarySize == longHeaderExpectedFileSize) {
if (binarySize == longHeaderExpectedFileSize) {
isLinuxStyle = true;
}
} catch (IOException e) {
}
catch (IOException e) {
e.printStackTrace();
}
}
if (isLinuxStyle && (this.exeType == AoutType.ZMAGIC)) {
if (isLinuxStyle && (exeType == AoutType.ZMAGIC)) {
// Linux ZMAGICs don't start the .text content until 0x400
this.txtOffset = sizeOfLongExecHeader;
txtOffset = SIZE_OF_LONG_EXEC_HEADER;
} else if ((this.exeType == AoutType.QMAGIC) ||
(this.exeType == AoutType.ZMAGIC)) {
}
else if ((exeType == AoutType.QMAGIC) ||
(exeType == AoutType.ZMAGIC)) {
// ZMAGIC for other platforms (as well as QMAGIC) include the file header itself
// in the .text content
this.txtOffset = 0;
txtOffset = 0;
} else {
}
else {
// Otherwise, the .text content starts immediately after the 0x20-byte header
this.txtOffset = sizeOfExecHeader;
txtOffset = SIZE_OF_EXEC_HEADER;
}
}
@@ -514,15 +499,9 @@ public class UnixAoutHeader implements StructConverter {
* base address of the .text segment when loaded.
*/
private void determineTextAddr() {
if ((this.isSparc && (this.exeType == AoutType.NMAGIC)) ||
(this.isNetBSD) ||
(this.exeType == AoutType.QMAGIC)) {
this.txtAddr = this.pageSize;
} else {
this.txtAddr = 0;
}
txtAddr = (isSparc && exeType == AoutType.NMAGIC) || isNetBSD || exeType == AoutType.QMAGIC
? pageSize
: 0;
}
/**
@@ -534,11 +513,11 @@ public class UnixAoutHeader implements StructConverter {
// doesn't exist, its offset will be computed to be beyond the end of
// the file. The string table is also not given an explicit size in
// the header.
boolean status = ((this.a_text == 0) || (this.txtOffset < this.binarySize) &&
((this.a_data == 0) || (this.datOffset < this.binarySize)) &&
((this.a_trsize == 0) || (this.txtRelOffset < this.binarySize)) &&
((this.a_drsize == 0) || (this.datRelOffset < this.binarySize)) &&
((this.a_syms == 0) || (this.symOffset < this.binarySize)));
boolean status = ((a_text == 0) || (txtOffset < binarySize) &&
((a_data == 0) || (datOffset < binarySize)) &&
((a_trsize == 0) || (txtRelOffset < binarySize)) &&
((a_drsize == 0) || (datRelOffset < binarySize)) &&
((a_syms == 0) || (symOffset < binarySize)));
return status;
}
@@ -546,28 +525,27 @@ public class UnixAoutHeader implements StructConverter {
* Rounds the provided address up to the next page boundary.
*/
private long segmentRound(long addr) {
final long mask = this.pageSize - 1;
final long mask = pageSize - 1;
long rounded = ((addr + mask) & ~mask);
return rounded;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String dtName = "exec";
Structure struct = new StructureDataType(new CategoryPath("/AOUT"), dtName, 0);
struct.add(DWORD, "a_midmag", null);
struct.add(DWORD, "a_text", null);
struct.add(DWORD, "a_data", null);
struct.add(DWORD, "a_bss", null);
struct.add(DWORD, "a_syms", null);
struct.add(DWORD, "a_entry", null);
struct.add(DWORD, "a_trsize", null);
struct.add(DWORD, "a_drsize", null);
Structure struct = new StructureDataType(new CategoryPath("/AOUT"), "exec", 0);
struct.add(DWORD, "a_midmag", "magic (network byte order)");
struct.add(DWORD, "a_text", "the size of the text segment in bytes");
struct.add(DWORD, "a_data", "the size of the data segment in bytes");
struct.add(DWORD, "a_bss", "the number of bytes in the bss segment");
struct.add(DWORD, "a_syms", "the size in bytes of the symbol table section");
struct.add(DWORD, "a_entry", "the address of the entry point");
struct.add(DWORD, "a_trsize", "the size in bytes of the text relocation table");
struct.add(DWORD, "a_drsize", "the size in bytes of the data relocation table");
return struct;
}
public void markup(Program program, Address headerAddress) throws CodeUnitInsertionException, DuplicateNameException, IOException {
public void markup(Program program, Address headerAddress)
throws CodeUnitInsertionException, DuplicateNameException, IOException {
Listing listing = program.getListing();
listing.createData(headerAddress, toDataType());
}

View File

@@ -18,25 +18,17 @@ package ghidra.app.util.bin.format.unixaout;
public class UnixAoutMachineType {
// These values come from a combination of sources, including NetBSD's
// aout_mids.h
// and the GNU BFD Library's libaout.h.
// These values come from a combination of sources, including NetBSD's aout_mids.h and the GNU
// BFD Library's libaout.h.
//
// Note: some a.out header files list a few HP values (for the 300 Series, 800
// Series, etc.)
// and these values exceed a full eight-bit count. Occasionally, this is
// accounted for by
// extending the Machine ID field of the a_magic word two bits higher, leaving
// only six bits
// in the MSB for other flags. This may not be correct, because those high-value
// HP machine
// IDs probably only appear in HP UX binaries, which use a different format.
// (This format is
// still named "a.out", but has a completely different header and internal
// organization.)
// The 10-bit Machine ID field would also interfere with flags used by VxWorks,
// NetBSD, and
// probably others.
// Note: some a.out header files list a few HP values (for the 300 Series, 800 Series, etc.)
// and these values exceed a full eight-bit count. Occasionally, this is accounted for by
// extending the Machine ID field of the a_magic word two bits higher, leaving only six bits in
// the MSB for other flags. This may not be correct, because those high-value HP machine IDs
// probably only appear in HP UX binaries, which use a different format. (This format is still
// named "a.out", but has a completely different header and internal organization.) The 10-bit
// Machine ID field would also interfere with flags used by VxWorks, NetBSD, and probably
// others.
public final static short M_UNKNOWN = 0x00;
public final static short M_68010 = 0x01;
@@ -78,10 +70,9 @@ public class UnixAoutMachineType {
public final static short M_RISCV = 0xb9; // RISC-V
public final static short M_CRIS = 0xff; // Axis ETRAX CRIS
/**
* Machine IDs that should only appear in the incompatible HP UX a.out format:
* HP300 (68020+68881): 0x12c
* HP200/300 : 0x20c
* HP800 : 0x20b
*/
// Machine IDs that should only appear in the incompatible HP UX a.out format:
//
// HP300 (68020+68881): 0x12c
// HP200/300 : 0x20c
// HP800 : 0x20b
}

View File

@@ -37,8 +37,8 @@ public class UnixAoutRelocation {
/**
*
* @param address First of the two words in the table entry (a 32-bit address)
* @param flags Second of the two words in the table entry (containing several
* bitfields)
* @param flags Second of the two words in the table entry (containing several bitfields)
* @param bigEndian True if big endian; otherwise, false
*/
public UnixAoutRelocation(long address, long flags, boolean bigEndian) {
this.address = (0xFFFFFFFF & address);
@@ -53,7 +53,8 @@ public class UnixAoutRelocation {
this.jmpTable = ((flags & 0x4) != 0);
this.relative = ((flags & 0x2) != 0);
this.copy = ((flags & 0x1) != 0);
} else {
}
else {
this.symbolNum = (int) (flags & 0x00FFFFFF);
this.flags = (byte) ((flags & 0xFF000000) >> 24);
this.pcRelativeAddressing = ((this.flags & 0x01) != 0);
@@ -67,17 +68,16 @@ public class UnixAoutRelocation {
}
public String getSymbolName(UnixAoutSymbolTable symtab) {
if (extern == true && symbolNum < symtab.size()) {
if (extern && symbolNum < symtab.size()) {
return symtab.get(symbolNum).name;
} else if (extern == false) {
switch (symbolNum) {
case 4:
return UnixAoutProgramLoader.dot_text;
case 6:
return UnixAoutProgramLoader.dot_data;
case 8:
return UnixAoutProgramLoader.dot_bss;
}
}
else if (!extern) {
return switch (symbolNum) {
case 4 -> UnixAoutProgramLoader.dot_text;
case 6 -> UnixAoutProgramLoader.dot_data;
case 8 -> UnixAoutProgramLoader.dot_bss;
default -> null;
};
}
return null;

View File

@@ -16,24 +16,14 @@
package ghidra.app.util.bin.format.unixaout;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.InvalidDataTypeException;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.exception.DuplicateNameException;
@@ -45,8 +35,8 @@ public class UnixAoutRelocationTable implements Iterable<UnixAoutRelocation>, St
private final List<UnixAoutRelocation> relocations;
private final UnixAoutSymbolTable symtab;
public UnixAoutRelocationTable(BinaryReader reader, long fileOffset, long fileSize, UnixAoutSymbolTable symtab)
throws IOException {
public UnixAoutRelocationTable(BinaryReader reader, long fileOffset, long fileSize,
UnixAoutSymbolTable symtab) throws IOException {
this.fileSize = fileSize;
this.relocations = new ArrayList<>();
this.symtab = symtab;
@@ -58,7 +48,8 @@ public class UnixAoutRelocationTable implements Iterable<UnixAoutRelocation>, St
long address = reader.readNextUnsignedInt();
long flags = reader.readNextUnsignedInt();
UnixAoutRelocation relocation = new UnixAoutRelocation(address, flags, reader.isBigEndian());
UnixAoutRelocation relocation =
new UnixAoutRelocation(address, flags, reader.isBigEndian());
relocations.add(relocation);
}
}
@@ -83,7 +74,8 @@ public class UnixAoutRelocationTable implements Iterable<UnixAoutRelocation>, St
struct.addBitField(BYTE, 1, "r_jmptable", null);
struct.addBitField(BYTE, 1, "r_relative", null);
struct.addBitField(BYTE, 1, "r_copy", null);
} catch (InvalidDataTypeException e) {
}
catch (InvalidDataTypeException e) {
throw new RuntimeException(e);
}
@@ -101,7 +93,7 @@ public class UnixAoutRelocationTable implements Iterable<UnixAoutRelocation>, St
if (!StringUtils.isBlank(name)) {
Data structData = array.getComponent(idx);
structData.setComment(CodeUnit.EOL_COMMENT, name);
structData.setComment(CommentType.EOL, name);
}
idx++;

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,9 +21,7 @@ import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.TerminatedStringDataType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.util.CodeUnitInsertionException;
@@ -42,7 +40,8 @@ public class UnixAoutStringTable {
}
try {
return reader.readUtf8String(fileOffset + stringOffset).trim();
} catch (IOException e) {
}
catch (IOException e) {
// FIXME
}
return null;

View File

@@ -38,55 +38,29 @@ public class UnixAoutSymbol {
public long value;
public boolean isExt;
public UnixAoutSymbol(long nameStringOffset, byte typeByte, byte otherByte,
short desc, long value) {
public UnixAoutSymbol(long nameStringOffset, byte typeByte, byte otherByte, short desc,
long value) {
this.nameStringOffset = nameStringOffset;
this.otherByte = otherByte;
this.desc = desc;
this.value = value;
this.isExt = (typeByte & 1) == 1;
switch (typeByte & 0xfe) {
case 0:
type = SymbolType.N_UNDF;
break;
case 2:
type = SymbolType.N_ABS;
break;
case 4:
type = SymbolType.N_TEXT;
break;
case 6:
type = SymbolType.N_DATA;
break;
case 8:
type = SymbolType.N_BSS;
break;
case 10:
type = SymbolType.N_INDR;
break;
default:
if ((typeByte & 0xfe) >= 0x20) {
type = SymbolType.N_STAB;
} else {
type = SymbolType.UNKNOWN;
}
break;
}
this.type = switch (typeByte & 0xfe) {
case 0 -> SymbolType.N_UNDF;
case 2 -> SymbolType.N_ABS;
case 4 -> SymbolType.N_TEXT;
case 6 -> SymbolType.N_DATA;
case 8 -> SymbolType.N_BSS;
case 10 -> SymbolType.N_INDR;
default -> (typeByte & 0xfe) >= 0x20 ? SymbolType.N_STAB : SymbolType.UNKNOWN;
};
switch (otherByte & 0x0f) {
case 1:
kind = SymbolKind.AUX_OBJECT;
break;
case 2:
kind = SymbolKind.AUX_FUNC;
break;
case 3:
kind = SymbolKind.AUX_LABEL;
break;
default:
kind = SymbolKind.UNKNOWN;
break;
}
this.kind = switch (otherByte & 0x0f) {
case 1 -> SymbolKind.AUX_OBJECT;
case 2 -> SymbolKind.AUX_FUNC;
case 3 -> SymbolKind.AUX_LABEL;
default -> SymbolKind.UNKNOWN;
};
}
}

View File

@@ -16,9 +16,7 @@
package ghidra.app.util.bin.format.unixaout;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
@@ -26,15 +24,8 @@ import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.UnixAoutProgramLoader;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.exception.DuplicateNameException;
@@ -45,8 +36,8 @@ public class UnixAoutSymbolTable implements Iterable<UnixAoutSymbol>, StructConv
private final long fileSize;
private List<UnixAoutSymbol> symbols;
public UnixAoutSymbolTable(BinaryReader reader, long fileOffset, long fileSize, UnixAoutStringTable strtab, MessageLog log)
throws IOException {
public UnixAoutSymbolTable(BinaryReader reader, long fileOffset, long fileSize,
UnixAoutStringTable strtab, MessageLog log) throws IOException {
this.fileSize = fileSize;
this.symbols = new ArrayList<>();
@@ -63,7 +54,8 @@ public class UnixAoutSymbolTable implements Iterable<UnixAoutSymbol>, StructConv
UnixAoutSymbol symbol = new UnixAoutSymbol(strOffset, typeByte, otherByte, desc, value);
if (symbol.type == UnixAoutSymbol.SymbolType.UNKNOWN) {
log.appendMsg(UnixAoutProgramLoader.dot_symtab, String.format("Unknown symbol type 0x%02x at symbol index %d", typeByte, idx));
log.appendMsg(UnixAoutProgramLoader.dot_symtab,
String.format("Unknown symbol type 0x%02x at symbol index %d", typeByte, idx));
}
symbols.add(symbol);
@@ -93,15 +85,16 @@ public class UnixAoutSymbolTable implements Iterable<UnixAoutSymbol>, StructConv
return new ArrayDataType(struct, (int) (fileSize / ENTRY_SIZE), ENTRY_SIZE);
}
public UnixAoutSymbol get(int symbolNum) {
return symbols.get(symbolNum);
}
public UnixAoutSymbol get(int symbolNum) {
return symbols.get(symbolNum);
}
public long size() {
return symbols.size();
}
public long size() {
return symbols.size();
}
public void markup(Program program, MemoryBlock block) throws CodeUnitInsertionException, DuplicateNameException, IOException {
public void markup(Program program, MemoryBlock block)
throws CodeUnitInsertionException, DuplicateNameException, IOException {
Listing listing = program.getListing();
Data array = listing.createData(block.getStart(), toDataType());
@@ -111,7 +104,7 @@ public class UnixAoutSymbolTable implements Iterable<UnixAoutSymbol>, StructConv
Data structData = array.getComponent(idx);
if (structData != null) {
structData.setComment(CodeUnit.EOL_COMMENT, symbol.name);
structData.setComment(CommentType.EOL, symbol.name);
}
}

View File

@@ -16,9 +16,7 @@
package ghidra.app.util.opinion;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.*;
import ghidra.app.util.Option;
import ghidra.app.util.OptionException;
@@ -26,9 +24,7 @@ import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.unixaout.UnixAoutHeader;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
@@ -36,46 +32,56 @@ import ghidra.util.task.TaskMonitor;
/**
* A {@link Loader} for processing UNIX-style A.out executables
*
* This style was also used by UNIX-like systems such as SunOS, BSD, and
* VxWorks, as well as some early distributions of Linux. Although there do
* exist implementations of A.out with 64-bit and GNU extensions, this loader
* does not currently support them.
* <p>
* This style was also used by UNIX-like systems such as SunOS, BSD, and VxWorks, as well as some
* early distributions of Linux. Although there do exist implementations of A.out with 64-bit and \
* GNU extensions, this loader does not currently support them.
*
* @see <a href="https://wiki.osdev.org/A.out">OSDev.org A.out</a>
* @see <a href="https://man.freebsd.org/cgi/man.cgi?a.out(5)">FreeBSD
* manpage</a>
* @see <a href="https://man.freebsd.org/cgi/man.cgi?a.out(5)">FreeBSD manpage</a>
*/
public class UnixAoutLoader extends AbstractProgramWrapperLoader {
public final static String UNIX_AOUT_NAME = "UNIX A.out";
public static final String OPTION_NAME_BASE_ADDR = "Base Address";
@Override
public String getName() {
return "UNIX A.out executable";
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>();
// Attempt to parse the header as both little- and big-endian.
// It is likely that only one of these will produce sensible values.
UnixAoutHeader hdrBE = new UnixAoutHeader(provider, false);
UnixAoutHeader hdrLE = new UnixAoutHeader(provider, true);
boolean beValid = false;
if (hdrBE.isValid()) {
final String lang = hdrBE.getLanguageSpec();
final String comp = hdrBE.getCompilerSpec();
loadSpecs.add(new LoadSpec(this, 0, new LanguageCompilerSpecPair(lang, comp), true));
beValid = true;
}
if (hdrLE.isValid()) {
final String lang = hdrLE.getLanguageSpec();
final String comp = hdrLE.getCompilerSpec();
loadSpecs
.add(new LoadSpec(this, 0, new LanguageCompilerSpecPair(lang, comp), !beValid));
}
return loadSpecs;
}
/**
* Retrieves the Address offset given in the "Base Address" option.
* Returns 0 if the option could not be found or contains an invalid value.
*/
private long getBaseAddrOffset(List<Option> options) {
Address baseAddr = null;
if (options != null) {
for (Option option : options) {
String optName = option.getName();
if (optName.equals(OPTION_NAME_BASE_ADDR)) {
baseAddr = (Address) option.getValue();
}
}
}
@Override
protected void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program, TaskMonitor monitor, MessageLog log)
throws CancelledException, IOException {
final boolean isLittleEndian = !program.getLanguage().isBigEndian();
final UnixAoutHeader header = new UnixAoutHeader(provider, isLittleEndian);
long offset = 0;
if (baseAddr != null) {
offset = baseAddr.getOffset();
}
return offset;
final UnixAoutProgramLoader loader =
new UnixAoutProgramLoader(program, header, monitor, log);
loader.loadAout(getBaseAddrOffset(options));
}
@Override
@@ -89,7 +95,8 @@ public class UnixAoutLoader extends AbstractProgramWrapperLoader {
if (optName.equals(OPTION_NAME_BASE_ADDR)) {
baseAddr = (Address) option.getValue();
}
} catch (Exception e) {
}
catch (Exception e) {
if (e instanceof OptionException) {
return e.getMessage();
}
@@ -121,45 +128,38 @@ public class UnixAoutLoader extends AbstractProgramWrapperLoader {
List<Option> list = new ArrayList<Option>();
list.add(new Option(OPTION_NAME_BASE_ADDR, baseAddr, Address.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-baseAddr"));
Loader.COMMAND_LINE_ARG_PREFIX + "-baseAddr"));
list.addAll(super.getDefaultOptions(provider, loadSpec, domainObject, loadIntoProgram));
return list;
}
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>();
// Attempt to parse the header as both little- and big-endian.
// It is likely that only one of these will produce sensible values.
UnixAoutHeader hdrBE = new UnixAoutHeader(provider, false);
UnixAoutHeader hdrLE = new UnixAoutHeader(provider, true);
boolean beValid = false;
if (hdrBE.isValid()) {
final String lang = hdrBE.getLanguageSpec();
final String comp = hdrBE.getCompilerSpec();
loadSpecs.add(new LoadSpec(this, 0, new LanguageCompilerSpecPair(lang, comp), true));
beValid = true;
}
if (hdrLE.isValid()) {
final String lang = hdrLE.getLanguageSpec();
final String comp = hdrLE.getCompilerSpec();
loadSpecs.add(new LoadSpec(this, 0, new LanguageCompilerSpecPair(lang, comp), !beValid));
}
return loadSpecs;
public String getName() {
return UNIX_AOUT_NAME;
}
@Override
protected void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program, TaskMonitor monitor, MessageLog log)
throws CancelledException, IOException {
final boolean isLittleEndian = !program.getLanguage().isBigEndian();
final UnixAoutHeader header = new UnixAoutHeader(provider, isLittleEndian);
/**
* Retrieves the Address offset given in the "Base Address" option.
* Returns 0 if the option could not be found or contains an invalid value.
*/
private long getBaseAddrOffset(List<Option> options) {
Address baseAddr = null;
final UnixAoutProgramLoader loader = new UnixAoutProgramLoader(program, header, monitor, log);
loader.loadAout(getBaseAddrOffset(options));
if (options != null) {
for (Option option : options) {
String optName = option.getName();
if (optName.equals(OPTION_NAME_BASE_ADDR)) {
baseAddr = (Address) option.getValue();
}
}
}
long offset = 0;
if (baseAddr != null) {
offset = baseAddr.getOffset();
}
return offset;
}
}

View File

@@ -17,48 +17,28 @@ package ghidra.app.util.opinion;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.MemoryLoadable;
import ghidra.app.util.bin.format.unixaout.UnixAoutHeader;
import ghidra.app.util.bin.format.unixaout.UnixAoutRelocation;
import ghidra.app.util.bin.format.unixaout.UnixAoutRelocationTable;
import ghidra.app.util.bin.format.unixaout.UnixAoutStringTable;
import ghidra.app.util.bin.format.unixaout.UnixAoutSymbol;
import ghidra.app.util.bin.format.unixaout.UnixAoutSymbolTable;
import ghidra.app.util.bin.format.unixaout.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.*;
import ghidra.program.model.reloc.Relocation.Status;
import ghidra.program.model.reloc.RelocationTable;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.DataConverter;
import ghidra.util.MonitoredInputStream;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class UnixAoutProgramLoader extends MemorySectionResolver {
private final static String BLOCK_SOURCE_NAME = "Unix Aout Loader";
public class UnixAoutProgramLoader {
private final int EXTERNAL_BLOCK_MIN_SIZE = 0x10000; // 64K
public final static String dot_text = ".text";
@@ -69,6 +49,7 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
public final static String dot_strtab = ".strtab";
public final static String dot_symtab = ".symtab";
private final Program program;
private final TaskMonitor monitor;
private final MessageLog log;
private final UnixAoutHeader header;
@@ -84,16 +65,17 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
private int extraBssSize = 0;
private int undefinedSymbolCount = 0;
public UnixAoutProgramLoader(Program program, UnixAoutHeader header, TaskMonitor monitor, MessageLog log) {
super(program);
public UnixAoutProgramLoader(Program program, UnixAoutHeader header, TaskMonitor monitor,
MessageLog log) {
this.program = program;
this.monitor = monitor;
this.log = log;
this.header = header;
}
public void loadAout(long baseAddr) throws IOException, CancelledException {
log.appendMsg(String.format("----- Loading %s -----", header.getReader().getByteProvider().getAbsolutePath()));
log.appendMsg(String.format("----- Loading %s -----",
header.getReader().getByteProvider().getAbsolutePath()));
log.appendMsg(String.format("Found a.out type %s.", header.getExecutableType().name()));
ByteProvider byteProvider = header.getReader().getByteProvider();
@@ -106,7 +88,9 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
applyRelocations(baseAddr, program.getMemory().getBlock(dot_text), relText);
applyRelocations(baseAddr, program.getMemory().getBlock(dot_data), relData);
markupSections();
} catch (AddressOverflowException | InvalidInputException | CodeUnitInsertionException | DuplicateNameException
}
catch (AddressOverflowException | InvalidInputException | CodeUnitInsertionException
| DuplicateNameException
| MemoryAccessException e) {
throw new RuntimeException(e);
}
@@ -114,19 +98,21 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
private void buildTables(ByteProvider byteProvider) throws IOException {
if (header.getStrSize() > 0) {
strtab = new UnixAoutStringTable(header.getReader(), header.getStrOffset(), header.getStrSize());
strtab = new UnixAoutStringTable(header.getReader(), header.getStrOffset(),
header.getStrSize());
}
if (header.getSymSize() > 0) {
symtab = new UnixAoutSymbolTable(header.getReader(), header.getSymOffset(), header.getSymSize(),
strtab, log);
symtab = new UnixAoutSymbolTable(header.getReader(), header.getSymOffset(),
header.getSymSize(),
strtab, log);
}
if (header.getTextRelocSize() > 0) {
relText = new UnixAoutRelocationTable(header.getReader(), header.getTextRelocOffset(),
header.getTextRelocSize(), symtab);
header.getTextRelocSize(), symtab);
}
if (header.getDataRelocSize() > 0) {
relData = new UnixAoutRelocationTable(header.getReader(), header.getDataRelocOffset(),
header.getDataRelocSize(), symtab);
header.getDataRelocSize(), symtab);
}
}
@@ -145,7 +131,8 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
// marked as N_UNDF but has a non-zero value means that its value should be
// interpreted as a size, and the linker should reserve space in .bss for it.
possibleBssSymbols.put(symbol.name, symbol.value);
} else {
}
else {
undefinedSymbolCount++;
}
break;
@@ -165,7 +152,8 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
}
if (extraBssSize > 0) {
log.appendMsg(dot_bss, String.format("Added %d bytes for N_UNDF symbols.", extraBssSize));
log.appendMsg(dot_bss,
String.format("Added %d bytes for N_UNDF symbols.", extraBssSize));
}
}
@@ -177,62 +165,71 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
MonitoredInputStream mis = new MonitoredInputStream(fileIn, monitor)) {
// Indicate that cleanup is not neccessary for cancelled import operation.
mis.setCleanupOnCancel(false);
fileBytes = program.getMemory().createFileBytes(byteProvider.getName(), 0, byteProvider.length(), mis,
monitor);
fileBytes = program.getMemory()
.createFileBytes(byteProvider.getName(), 0, byteProvider.length(), mis,
monitor);
}
final AddressSpace defaultAddressSpace = program.getAddressFactory().getDefaultAddressSpace();
final AddressSpace defaultAddressSpace =
program.getAddressFactory().getDefaultAddressSpace();
final Address otherAddress = AddressSpace.OTHER_SPACE.getMinAddress();
Address address;
Address nextFreeAddress = defaultAddressSpace.getAddress(0);
if (header.getTextOffset() != 0 || header.getTextSize() < 32) {
addInitializedMemorySection(null, 0, 32, otherAddress, "_aoutHeader", false, false, false, null, false,
false);
MemoryBlockUtils.createInitializedBlock(program, true, "_aoutHeader", otherAddress,
fileBytes, 0, 32, null, null, false, false, false, log);
}
if (header.getTextSize() > 0) {
address = defaultAddressSpace.getAddress(baseAddr + header.getTextAddr());
nextFreeAddress = address.add(header.getTextSize());
addInitializedMemorySection(null, header.getTextOffset(), header.getTextSize(), address, dot_text, true,
true, true, null, false, true);
MemoryBlockUtils.createInitializedBlock(program, false, dot_text, address, fileBytes,
header.getTextOffset(), header.getTextSize(), null, null, true, true, true, log);
}
if (header.getDataSize() > 0) {
address = defaultAddressSpace.getAddress(baseAddr + header.getDataAddr());
nextFreeAddress = address.add(header.getDataSize());
addInitializedMemorySection(null, header.getDataOffset(), header.getDataSize(), address, dot_data, true,
true, false, null, false, true);
MemoryBlockUtils.createInitializedBlock(program, false, dot_data, address, fileBytes,
header.getDataOffset(), header.getDataSize(), null, null, true, true, false, log);
}
if ((header.getBssSize() + extraBssSize) > 0) {
address = defaultAddressSpace.getAddress(baseAddr + header.getBssAddr());
nextFreeAddress = address.add(header.getBssSize() + extraBssSize);
addUninitializedMemorySection(null, header.getBssSize() + extraBssSize, address, dot_bss, true, true, false,
null, false);
MemoryBlockUtils.createUninitializedBlock(program, false, dot_bss, address,
header.getBssSize() + extraBssSize, null, null, true, true, false, log);
}
if (undefinedSymbolCount > 0) {
int externalSectionSize = undefinedSymbolCount * 4;
if (externalSectionSize < EXTERNAL_BLOCK_MIN_SIZE) {
externalSectionSize = EXTERNAL_BLOCK_MIN_SIZE;
}
addUninitializedMemorySection(null, externalSectionSize, nextFreeAddress, MemoryBlock.EXTERNAL_BLOCK_NAME, false, false, false, "NOTE: This block is artificial and is used to make relocations work correctly", false);
MemoryBlock externalBlock = MemoryBlockUtils.createUninitializedBlock(program, false,
MemoryBlock.EXTERNAL_BLOCK_NAME, nextFreeAddress, externalSectionSize, null, null,
false, false, false, log);
if (externalBlock != null) {
externalBlock.setArtificial(true);
}
}
if (header.getStrSize() > 0) {
addInitializedMemorySection(null, header.getStrOffset(), header.getStrSize(), otherAddress, dot_strtab,
false, false, false, null, false, false);
MemoryBlockUtils.createInitializedBlock(program, true, dot_strtab, otherAddress,
fileBytes, header.getStrOffset(), header.getStrSize(), null, null, false, false,
false, log);
}
if (header.getSymSize() > 0) {
addInitializedMemorySection(null, header.getSymOffset(), header.getSymSize(), otherAddress, dot_symtab,
false, false, false, null, false, false);
MemoryBlockUtils.createInitializedBlock(program, true, dot_symtab, otherAddress,
fileBytes, header.getSymOffset(), header.getSymSize(), null, null, false, false,
false, log);
}
if (header.getTextRelocSize() > 0) {
addInitializedMemorySection(null, header.getTextRelocOffset(), header.getTextRelocSize(), otherAddress,
dot_rel_text, false, false, false, null, false, false);
MemoryBlockUtils.createInitializedBlock(program, true, dot_rel_text, otherAddress,
fileBytes, header.getTextRelocOffset(), header.getTextRelocSize(), null, null,
false, false, false, log);
}
if (header.getDataRelocSize() > 0) {
addInitializedMemorySection(null, header.getDataRelocOffset(), header.getDataRelocSize(), otherAddress,
dot_rel_data, false, false, false, null, false, false);
MemoryBlockUtils.createInitializedBlock(program, true, dot_rel_data, otherAddress,
fileBytes, header.getDataRelocOffset(), header.getDataRelocSize(), null, null,
false, false, false, log);
}
resolve(monitor);
}
private void loadSymbols() throws InvalidInputException {
@@ -275,7 +272,8 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
address = bssBlock.getEnd().add(extraBssOffset);
block = bssBlock;
extraBssOffset += symbol.value;
} else {
}
else {
address = externalBlock.getStart().add(undefinedSymbolIdx++ * 4);
block = externalBlock;
symbolTable.addExternalEntryPoint(address);
@@ -299,16 +297,20 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
switch (symbol.kind) {
case AUX_FUNC:
try {
functionManager.createFunction(symbol.name, address, new AddressSet(address),
SourceType.IMPORTED);
} catch (OverlappingFunctionException e) {
functionManager.createFunction(symbol.name, address,
new AddressSet(address),
SourceType.IMPORTED);
}
catch (OverlappingFunctionException e) {
log.appendMsg(block.getName(), String.format(
"Failed to create function %s @ %s, creating symbol instead.", symbol.name, address));
"Failed to create function %s @ %s, creating symbol instead.",
symbol.name, address));
symbolTable.createLabel(address, symbol.name, SourceType.IMPORTED);
}
break;
default:
Symbol label = symbolTable.createLabel(address, symbol.name, SourceType.IMPORTED);
Symbol label =
symbolTable.createLabel(address, symbol.name, SourceType.IMPORTED);
if (symbol.isExt) {
label.setPrimary();
}
@@ -323,13 +325,14 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
}
}
private void applyRelocations(long baseAddr, MemoryBlock targetBlock, UnixAoutRelocationTable relTable)
throws MemoryAccessException {
private void applyRelocations(long baseAddr, MemoryBlock targetBlock,
UnixAoutRelocationTable relTable) throws MemoryAccessException {
if (targetBlock == null || relTable == null) {
return;
}
monitor.setMessage(String.format("Applying relocations for section %s...", targetBlock.getName()));
monitor.setMessage(
String.format("Applying relocations for section %s...", targetBlock.getName()));
DataConverter dc = DataConverter.getInstance(program.getLanguage().isBigEndian());
SymbolTable symbolTable = program.getSymbolTable();
@@ -350,15 +353,19 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
Long value = null;
Status status = Status.FAILURE;
if (relocation.baseRelative || relocation.jmpTable || relocation.relative || relocation.copy) {
if (relocation.baseRelative || relocation.jmpTable || relocation.relative ||
relocation.copy) {
status = Status.UNSUPPORTED;
} else {
}
else {
if (relocation.extern == true && relocation.symbolNum < symtab.size()) {
SymbolIterator symbolIterator = symbolTable.getSymbols(symtab.get(relocation.symbolNum).name);
SymbolIterator symbolIterator =
symbolTable.getSymbols(symtab.get(relocation.symbolNum).name);
if (symbolIterator.hasNext()) {
value = symbolIterator.next().getAddress().getOffset();
}
} else if (relocation.extern == false) {
}
else if (relocation.extern == false) {
switch (relocation.symbolNum) {
case 4:
value = textBlock.getStart().getOffset();
@@ -389,19 +396,21 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
if (status != Status.APPLIED) {
log.appendMsg(targetBlock.getName(),
String.format("Failed to apply relocation entry %d with type 0x%02x @ %s.", idx,
relocation.flags, targetAddress));
String.format("Failed to apply relocation entry %d with type 0x%02x @ %s.", idx,
relocation.flags, targetAddress));
}
relocationTable.add(targetAddress, status, relocation.flags, new long[] { relocation.symbolNum },
originalBytes, relocation.getSymbolName(symtab));
relocationTable.add(targetAddress, status, relocation.flags,
new long[] { relocation.symbolNum },
originalBytes, relocation.getSymbolName(symtab));
idx++;
}
}
private void markupSections()
throws InvalidInputException, CodeUnitInsertionException, DuplicateNameException, IOException {
final AddressSpace defaultAddressSpace = program.getAddressFactory().getDefaultAddressSpace();
private void markupSections() throws InvalidInputException, CodeUnitInsertionException,
DuplicateNameException, IOException {
final AddressSpace defaultAddressSpace =
program.getAddressFactory().getDefaultAddressSpace();
final FunctionManager functionManager = program.getFunctionManager();
final SymbolTable symbolTable = program.getSymbolTable();
@@ -413,7 +422,8 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
MemoryBlock textBlock = program.getMemory().getBlock(dot_text);
if (aoutHeader != null) {
headerAddress = aoutHeader.getStart();
} else if (textBlock != null && header.getTextOffset() == 0 && header.getTextSize() >= 32) {
}
else if (textBlock != null && header.getTextOffset() == 0 && header.getTextSize() >= 32) {
headerAddress = textBlock.getStart();
}
if (headerAddress != null) {
@@ -424,9 +434,12 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
if (header.getEntryPoint() != 0) {
Address address = defaultAddressSpace.getAddress(header.getEntryPoint());
try {
functionManager.createFunction("entry", address, new AddressSet(address), SourceType.IMPORTED);
} catch (OverlappingFunctionException e) {
log.appendMsg(dot_text, "Failed to create entrypoint function @ %s, creating symbol instead.");
functionManager.createFunction("entry", address, new AddressSet(address),
SourceType.IMPORTED);
}
catch (OverlappingFunctionException e) {
log.appendMsg(dot_text,
"Failed to create entrypoint function @ %s, creating symbol instead.");
symbolTable.createLabel(address, "entry", SourceType.IMPORTED);
}
}
@@ -457,20 +470,4 @@ public class UnixAoutProgramLoader extends MemorySectionResolver {
strtab.markup(program, strtabBlock);
}
}
@Override
protected MemoryBlock createInitializedBlock(MemoryLoadable key, boolean isOverlay, String name, Address start,
long fileOffset, long length, String comment, boolean r, boolean w, boolean x, TaskMonitor monitor)
throws IOException, AddressOverflowException, CancelledException {
return MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start, fileBytes, fileOffset, length,
comment, BLOCK_SOURCE_NAME, r, w, x, log);
}
@Override
protected MemoryBlock createUninitializedBlock(MemoryLoadable key, boolean isOverlay, String name, Address start,
long length, String comment, boolean r, boolean w, boolean x)
throws IOException, AddressOverflowException, CancelledException {
return MemoryBlockUtils.createUninitializedBlock(program, isOverlay, name, start, length, comment, comment, r,
w, x, log);
}
}
}