diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/extend/ElfLoadAdapter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/extend/ElfLoadAdapter.java index 471b07b8ee..3da7000d45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/extend/ElfLoadAdapter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/extend/ElfLoadAdapter.java @@ -392,6 +392,8 @@ public class ElfLoadAdapter { /** * 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 loadable Corresponding ElfSectionHeader or ElfProgramHeader for the memory block to be created. * @param start memory load address @@ -404,6 +406,20 @@ public class ElfLoadAdapter { 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 * the relocation tables. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java index 1d745378c8..76a397ef39 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java @@ -2845,6 +2845,15 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { 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, long fileOffset, long dataLength) throws IOException { InputStream dataInput = elf.getReader().getByteProvider().getInputStream(fileOffset); @@ -2909,6 +2918,17 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { 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, fileOffset, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x, log); } diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java index 1dd345d2e7..e563eeb766 100644 --- a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java +++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java @@ -26,17 +26,16 @@ import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; public class PIC30_ElfExtension extends ElfExtension { - - 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 EM_DSPIC30F = 118; /* Microchip Technology dsPIC30F DSC */ + + public static final int SHF_PSV = (1 << 28); /* Constants in program memory */ @Override public boolean canHandle(ElfHeader elf) { return elf.e_machine() == EM_DSPIC30F; } - + @Override public boolean canHandle(ElfLoadHelper elfLoadHelper) { // 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 { // TODO: Create mapped blocks } - + @Override public AddressSpace getPreferredSegmentAddressSpace(ElfLoadHelper elfLoadHelper, ElfProgramHeader elfProgramHeader) { @@ -64,7 +63,7 @@ public class PIC30_ElfExtension extends ElfExtension { } return language.getDefaultSpace(); } - + @Override public AddressSpace getPreferredSectionAddressSpace(ElfLoadHelper elfLoadHelper, ElfSectionHeader elfSectionHeader) { @@ -74,15 +73,15 @@ public class PIC30_ElfExtension extends ElfExtension { } return language.getDefaultSpace(); } - + private long getAdjustedDataLoadSize(long dataLoadFileSize) { return dataLoadFileSize / 2; } - + private boolean isDataLoad(ElfProgramHeader elfProgramHeader) { return !elfProgramHeader.isExecute(); } - + private boolean isDataLoad(ElfSectionHeader section) { if (!section.isAlloc()) { return false; @@ -109,13 +108,13 @@ public class PIC30_ElfExtension extends ElfExtension { } @Override - public InputStream getFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, MemoryLoadable loadable, Address start, long dataLength, - InputStream dataInput) { + public InputStream getFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, + MemoryLoadable loadable, Address start, long dataLength, InputStream dataInput) { Language language = elfLoadHelper.getProgram().getLanguage(); if (!language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace())) { - return dataInput; + return dataInput; } - + if (loadable instanceof ElfSectionHeader) { ElfSectionHeader section = (ElfSectionHeader) loadable; if ((section.getFlags() & SHF_PSV) != 0) { @@ -124,25 +123,32 @@ public class PIC30_ElfExtension extends ElfExtension { return new PIC30FilteredPSVDataInputStream(dataInput); } } - + // Data space loading pads after every byte with Microchip toolchain // NOTE: this could vary and we may need to improve detection of this situation - + 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 { - + // BYTES: - - protected boolean padByteToggle; + + protected boolean padByteToggle; protected long pos; protected PIC30FilteredDataInputStream(InputStream in) { super(in); padByteToggle = false; // first byte is data not padding } - + protected int readNextByte() throws IOException { int r = in.read(); if (padByteToggle && r != 0) { @@ -153,7 +159,7 @@ public class PIC30_ElfExtension extends ElfExtension { padByteToggle = !padByteToggle; return r; } - + @Override public int read() throws IOException { while (padByteToggle) { @@ -164,42 +170,45 @@ public class PIC30_ElfExtension extends ElfExtension { } return readNextByte(); } - + @Override public int read(byte b[], int off, int len) throws IOException { if (b == null) { - throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - + throw new NullPointerException(); + } + else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + else if (len == 0) { + return 0; + } + int numRead = -1; for (int i = 1; i <= len; i++) { int c = read(); - if (c == -1) { - break; - } - b[off++] = (byte)c; - numRead = i; + if (c == -1) { + break; + } + b[off++] = (byte) c; + numRead = i; } return numRead; } - + } private static class PIC30FilteredPSVDataInputStream extends PIC30FilteredDataInputStream { // BYTES: - + private boolean firstByteToggle; // firstByte of data or pad - + protected PIC30FilteredPSVDataInputStream(InputStream in) { super(in); firstByteToggle = true; } - + + @Override protected int readNextByte() throws IOException { int r = in.read(); ++pos;