Corrected ELF Import issue where FileBytes can not be used in some load

situations (e.g., PIC-30)
This commit is contained in:
ghidra1 2019-07-19 10:56:01 -04:00
parent 6d05537b7f
commit 6a6bb63932
3 changed files with 85 additions and 40 deletions

View file

@ -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.

View file

@ -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);
} }

View file

@ -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;