mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Corrected ELF Import issue where FileBytes can not be used in some load
situations (e.g., PIC-30)
This commit is contained in:
parent
6d05537b7f
commit
6a6bb63932
3 changed files with 85 additions and 40 deletions
|
@ -392,6 +392,8 @@ public class ElfLoadAdapter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return filtered InputStream for loading a memory block (includes non-loaded OTHER blocks).
|
* Return filtered InputStream for loading a memory block (includes non-loaded OTHER blocks).
|
||||||
|
* NOTE: If this method is overriden, the {@link #hasFilteredLoadInputStream(ElfLoadHelper, MemoryLoadable, Address)}
|
||||||
|
* must also be overriden in a consistent fashion.
|
||||||
* @param elfLoadHelper
|
* @param elfLoadHelper
|
||||||
* @param loadable Corresponding ElfSectionHeader or ElfProgramHeader for the memory block to be created.
|
* @param loadable Corresponding ElfSectionHeader or ElfProgramHeader for the memory block to be created.
|
||||||
* @param start memory load address
|
* @param start memory load address
|
||||||
|
@ -404,6 +406,20 @@ public class ElfLoadAdapter {
|
||||||
return dataInput;
|
return dataInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the use of {@link #getFilteredLoadInputStream(ElfLoadHelper, MemoryLoadable, Address, long, InputStream)}
|
||||||
|
* is required when loading a memory block. If a filtered input stream is required this will prevent the use of a direct
|
||||||
|
* mapping to file bytes.
|
||||||
|
* @param elfLoadHelper
|
||||||
|
* @param loadable Corresponding ElfSectionHeader or ElfProgramHeader for the memory block to be loaded.
|
||||||
|
* @param start memory load address
|
||||||
|
* @return true if the use of a filtered input stream is required
|
||||||
|
*/
|
||||||
|
public boolean hasFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, MemoryLoadable loadable,
|
||||||
|
Address start) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ElfRelocation class which should be used to properly parse
|
* Get the ElfRelocation class which should be used to properly parse
|
||||||
* the relocation tables.
|
* the relocation tables.
|
||||||
|
|
|
@ -2845,6 +2845,15 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a suitable input stream for loading a memory block defined by a specified loadable.
|
||||||
|
* @param loadable Corresponding ElfSectionHeader or ElfProgramHeader for the memory block to be created.
|
||||||
|
* @param start memory load address
|
||||||
|
* @param fileOffset byte provider offset
|
||||||
|
* @param dataLength the in-memory data length in bytes (actual bytes read from dataInput may be more)
|
||||||
|
* @return input stream for loading memory block
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private InputStream getInitializedBlockInputStream(MemoryLoadable loadable, Address start,
|
private InputStream getInitializedBlockInputStream(MemoryLoadable loadable, Address start,
|
||||||
long fileOffset, long dataLength) throws IOException {
|
long fileOffset, long dataLength) throws IOException {
|
||||||
InputStream dataInput = elf.getReader().getByteProvider().getInputStream(fileOffset);
|
InputStream dataInput = elf.getReader().getByteProvider().getInputStream(fileOffset);
|
||||||
|
@ -2909,6 +2918,17 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||||
blockComment += " (section truncated to " + sizeGB + " GByte)";
|
blockComment += " (section truncated to " + sizeGB + " GByte)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elf.getLoadAdapter().hasFilteredLoadInputStream(this, loadable, start)) {
|
||||||
|
// block is unable to map directly to file bytes - load from input stream
|
||||||
|
try (InputStream dataInput =
|
||||||
|
getInitializedBlockInputStream(loadable, start, fileOffset, revisedLength)) {
|
||||||
|
return MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start,
|
||||||
|
dataInput, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x, log,
|
||||||
|
monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create block using direct mapping to file bytes
|
||||||
return MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start, fileBytes,
|
return MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start, fileBytes,
|
||||||
fileOffset, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x, log);
|
fileOffset, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x, log);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,17 +26,16 @@ import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class PIC30_ElfExtension extends ElfExtension {
|
public class PIC30_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
public static final int EM_DSPIC30F = 118; /* Microchip Technology dsPIC30F DSC */
|
public static final int EM_DSPIC30F = 118; /* Microchip Technology dsPIC30F DSC */
|
||||||
|
|
||||||
public static final int SHF_PSV = (1 << 28); /* Constants in program memory */
|
public static final int SHF_PSV = (1 << 28); /* Constants in program memory */
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canHandle(ElfHeader elf) {
|
public boolean canHandle(ElfHeader elf) {
|
||||||
return elf.e_machine() == EM_DSPIC30F;
|
return elf.e_machine() == EM_DSPIC30F;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
|
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
|
||||||
// TODO: The PIC-30/24 utilize too many different processor names instead of
|
// TODO: The PIC-30/24 utilize too many different processor names instead of
|
||||||
|
@ -54,7 +53,7 @@ public class PIC30_ElfExtension extends ElfExtension {
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
// TODO: Create mapped blocks
|
// TODO: Create mapped blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSpace getPreferredSegmentAddressSpace(ElfLoadHelper elfLoadHelper,
|
public AddressSpace getPreferredSegmentAddressSpace(ElfLoadHelper elfLoadHelper,
|
||||||
ElfProgramHeader elfProgramHeader) {
|
ElfProgramHeader elfProgramHeader) {
|
||||||
|
@ -64,7 +63,7 @@ public class PIC30_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
return language.getDefaultSpace();
|
return language.getDefaultSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSpace getPreferredSectionAddressSpace(ElfLoadHelper elfLoadHelper,
|
public AddressSpace getPreferredSectionAddressSpace(ElfLoadHelper elfLoadHelper,
|
||||||
ElfSectionHeader elfSectionHeader) {
|
ElfSectionHeader elfSectionHeader) {
|
||||||
|
@ -74,15 +73,15 @@ public class PIC30_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
return language.getDefaultSpace();
|
return language.getDefaultSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getAdjustedDataLoadSize(long dataLoadFileSize) {
|
private long getAdjustedDataLoadSize(long dataLoadFileSize) {
|
||||||
return dataLoadFileSize / 2;
|
return dataLoadFileSize / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDataLoad(ElfProgramHeader elfProgramHeader) {
|
private boolean isDataLoad(ElfProgramHeader elfProgramHeader) {
|
||||||
return !elfProgramHeader.isExecute();
|
return !elfProgramHeader.isExecute();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDataLoad(ElfSectionHeader section) {
|
private boolean isDataLoad(ElfSectionHeader section) {
|
||||||
if (!section.isAlloc()) {
|
if (!section.isAlloc()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -109,13 +108,13 @@ public class PIC30_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream getFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, MemoryLoadable loadable, Address start, long dataLength,
|
public InputStream getFilteredLoadInputStream(ElfLoadHelper elfLoadHelper,
|
||||||
InputStream dataInput) {
|
MemoryLoadable loadable, Address start, long dataLength, InputStream dataInput) {
|
||||||
Language language = elfLoadHelper.getProgram().getLanguage();
|
Language language = elfLoadHelper.getProgram().getLanguage();
|
||||||
if (!language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace())) {
|
if (!language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace())) {
|
||||||
return dataInput;
|
return dataInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadable instanceof ElfSectionHeader) {
|
if (loadable instanceof ElfSectionHeader) {
|
||||||
ElfSectionHeader section = (ElfSectionHeader) loadable;
|
ElfSectionHeader section = (ElfSectionHeader) loadable;
|
||||||
if ((section.getFlags() & SHF_PSV) != 0) {
|
if ((section.getFlags() & SHF_PSV) != 0) {
|
||||||
|
@ -124,25 +123,32 @@ public class PIC30_ElfExtension extends ElfExtension {
|
||||||
return new PIC30FilteredPSVDataInputStream(dataInput);
|
return new PIC30FilteredPSVDataInputStream(dataInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data space loading pads after every byte with Microchip toolchain
|
// Data space loading pads after every byte with Microchip toolchain
|
||||||
// NOTE: this could vary and we may need to improve detection of this situation
|
// NOTE: this could vary and we may need to improve detection of this situation
|
||||||
|
|
||||||
return new PIC30FilteredDataInputStream(dataInput);
|
return new PIC30FilteredDataInputStream(dataInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, MemoryLoadable loadable,
|
||||||
|
Address start) {
|
||||||
|
Language language = elfLoadHelper.getProgram().getLanguage();
|
||||||
|
return language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace());
|
||||||
|
}
|
||||||
|
|
||||||
private static class PIC30FilteredDataInputStream extends FilterInputStream {
|
private static class PIC30FilteredDataInputStream extends FilterInputStream {
|
||||||
|
|
||||||
// BYTES: <byte> <pad>
|
// BYTES: <byte> <pad>
|
||||||
|
|
||||||
protected boolean padByteToggle;
|
protected boolean padByteToggle;
|
||||||
protected long pos;
|
protected long pos;
|
||||||
|
|
||||||
protected PIC30FilteredDataInputStream(InputStream in) {
|
protected PIC30FilteredDataInputStream(InputStream in) {
|
||||||
super(in);
|
super(in);
|
||||||
padByteToggle = false; // first byte is data not padding
|
padByteToggle = false; // first byte is data not padding
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int readNextByte() throws IOException {
|
protected int readNextByte() throws IOException {
|
||||||
int r = in.read();
|
int r = in.read();
|
||||||
if (padByteToggle && r != 0) {
|
if (padByteToggle && r != 0) {
|
||||||
|
@ -153,7 +159,7 @@ public class PIC30_ElfExtension extends ElfExtension {
|
||||||
padByteToggle = !padByteToggle;
|
padByteToggle = !padByteToggle;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
while (padByteToggle) {
|
while (padByteToggle) {
|
||||||
|
@ -164,42 +170,45 @@ public class PIC30_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
return readNextByte();
|
return readNextByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte b[], int off, int len) throws IOException {
|
public int read(byte b[], int off, int len) throws IOException {
|
||||||
if (b == null) {
|
if (b == null) {
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
} else if (off < 0 || len < 0 || len > b.length - off) {
|
}
|
||||||
throw new IndexOutOfBoundsException();
|
else if (off < 0 || len < 0 || len > b.length - off) {
|
||||||
} else if (len == 0) {
|
throw new IndexOutOfBoundsException();
|
||||||
return 0;
|
}
|
||||||
}
|
else if (len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int numRead = -1;
|
int numRead = -1;
|
||||||
for (int i = 1; i <= len; i++) {
|
for (int i = 1; i <= len; i++) {
|
||||||
int c = read();
|
int c = read();
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
b[off++] = (byte)c;
|
b[off++] = (byte) c;
|
||||||
numRead = i;
|
numRead = i;
|
||||||
}
|
}
|
||||||
return numRead;
|
return numRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PIC30FilteredPSVDataInputStream extends PIC30FilteredDataInputStream {
|
private static class PIC30FilteredPSVDataInputStream extends PIC30FilteredDataInputStream {
|
||||||
|
|
||||||
// BYTES: <byte0> <byte1> <pad0> <pad1>
|
// BYTES: <byte0> <byte1> <pad0> <pad1>
|
||||||
|
|
||||||
private boolean firstByteToggle; // firstByte of data or pad
|
private boolean firstByteToggle; // firstByte of data or pad
|
||||||
|
|
||||||
protected PIC30FilteredPSVDataInputStream(InputStream in) {
|
protected PIC30FilteredPSVDataInputStream(InputStream in) {
|
||||||
super(in);
|
super(in);
|
||||||
firstByteToggle = true;
|
firstByteToggle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected int readNextByte() throws IOException {
|
protected int readNextByte() throws IOException {
|
||||||
int r = in.read();
|
int r = in.read();
|
||||||
++pos;
|
++pos;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue