Merge remote-tracking branch 'origin/GT-3064_ghidravore_cancel_create_memory'

This commit is contained in:
Ryan Kurtz 2019-08-08 07:33:45 -04:00
commit 70b5c0478c
22 changed files with 279 additions and 252 deletions

View File

@ -108,8 +108,6 @@ public class MemoryBlockUtils {
return null;
}
/**
* Creates a new bit mapped memory block. (A bit mapped block is a block where each byte value
* is either 1 or 0 and the value is taken from a bit in a byte at some other address in memory)
@ -279,12 +277,12 @@ public class MemoryBlockUtils {
MemoryBlock block;
try {
try {
block = memory.createInitializedBlock(name, start, dataInput, dataLength,
monitor, isOverlay);
block = memory.createInitializedBlock(name, start, dataInput, dataLength, monitor,
isOverlay);
}
catch (MemoryConflictException e) {
block = memory.createInitializedBlock(name, start, dataInput, dataLength,
monitor, true);
block = memory.createInitializedBlock(name, start, dataInput, dataLength, monitor,
true);
}
}
catch (LockException | DuplicateNameException | MemoryConflictException e) {
@ -325,11 +323,12 @@ public class MemoryBlockUtils {
* @param program the program in which to create a new FileBytes object
* @param provider the ByteProvider from which to get the bytes.
* @return the newly created FileBytes object.
* @param monitor the monitor for canceling this potentially long running operation.
* @throws IOException if an IOException occurred.
*/
public static FileBytes createFileBytes(Program program, ByteProvider provider)
throws IOException {
return createFileBytes(program, provider, 0, provider.length());
public static FileBytes createFileBytes(Program program, ByteProvider provider,
TaskMonitor monitor) throws IOException, CancelledException {
return createFileBytes(program, provider, 0, provider.length(), monitor);
}
/**
@ -338,14 +337,16 @@ public class MemoryBlockUtils {
* @param provider the ByteProvider from which to get the bytes.
* @param offset the offset into the ByteProvider from which to start loading bytes.
* @param length the number of bytes to load
* @param monitor the monitor for canceling this potentially long running operation.
* @return the newly created FileBytes object.
* @throws IOException if an IOException occurred.
* @throws CancelledException if the user cancelled the operation
*/
public static FileBytes createFileBytes(Program program, ByteProvider provider, long offset,
long length) throws IOException {
long length, TaskMonitor monitor) throws IOException, CancelledException {
Memory memory = program.getMemory();
try (InputStream fis = provider.getInputStream(offset)) {
return memory.createFileBytes(provider.getName(), offset, length, fis);
return memory.createFileBytes(provider.getName(), offset, length, fis, monitor);
}
}

View File

@ -298,7 +298,7 @@ public class BinaryLoader extends AbstractProgramLoader {
@Override
protected boolean loadProgramInto(ByteProvider provider, LoadSpec loadSpec,
List<Option> options, MessageLog log, Program prog, TaskMonitor monitor)
throws IOException {
throws IOException, CancelledException {
long length = getLength(options);
//File file = provider.getFile();
long fileOffset = getFileOffset(options);
@ -312,7 +312,8 @@ public class BinaryLoader extends AbstractProgramLoader {
length = clipToMemorySpace(length, log, prog);
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(prog, provider, fileOffset, length);
FileBytes fileBytes =
MemoryBlockUtils.createFileBytes(prog, provider, fileOffset, length, monitor);
try {
AddressSpace space = prog.getAddressFactory().getDefaultAddressSpace();
if (baseAddr == null) {

View File

@ -38,8 +38,7 @@ import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.exception.NotFoundException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class CoffLoader extends AbstractLibrarySupportLoader {
@ -183,7 +182,8 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
@Override
protected 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, CancelledException {
boolean performFakeLinking = performFakeLinking(options);
@ -193,7 +193,7 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
Map<CoffSectionHeader, Address> sectionsMap = new HashMap<>();
Map<CoffSymbol, Symbol> symbolsMap = new HashMap<>();
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider);
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, monitor);
int id = program.startTransaction("loading program from COFF");
boolean success = false;

View File

@ -49,7 +49,6 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
/** Default value for loader option to create memory blocks for DYLIB sections */
static final boolean CREATE_DYLIB_SECTIONS_OPTION_DEFAULT = false;
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>();
@ -84,8 +83,8 @@ public class DyldCacheLoader extends AbstractLibrarySupportLoader {
try {
DyldCacheProgramBuilder.buildProgram(program, provider,
MemoryBlockUtils.createFileBytes(program, provider), shouldProcessSymbols(options),
shouldCreateDylibSections(options), log, monitor);
MemoryBlockUtils.createFileBytes(program, provider, monitor),
shouldProcessSymbols(options), shouldCreateDylibSections(options), log, monitor);
}
catch (CancelledException e) {
return;

View File

@ -120,7 +120,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
ByteProvider byteProvider = elf.getReader().getByteProvider();
try (InputStream fileIn = byteProvider.getInputStream(0)) {
fileBytes = program.getMemory().createFileBytes(byteProvider.getName(), 0,
byteProvider.length(), fileIn);
byteProvider.length(), fileIn, monitor);
}
// process headers and define "section" within memory elfProgramBuilder
@ -2984,7 +2984,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// Are we immune from such errors? If not, how should they be handled?
long revisedLength = checkBlockLimit(name, dataLength, false);
if (start.isNonLoadedMemoryAddress()) {
r = false;
w = false;

View File

@ -81,7 +81,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
Program program, TaskMonitor monitor, MessageLog log) throws IOException {
try {
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider);
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, monitor);
// A Mach-O file may contain PRELINK information. If so, we use a special
// program builder that knows how to deal with it.
@ -134,7 +134,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
log.appendMsg("WARNING! No archives found in the UBI: " + libFile);
return false;
}
for (FatArch architecture : architectures) {
// Note: The creation of the byte provider that we pass to the importer deserves a

View File

@ -87,9 +87,9 @@ public class MzLoader extends AbstractLibrarySupportLoader {
@Override
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program prog,
TaskMonitor monitor, MessageLog log) throws IOException {
TaskMonitor monitor, MessageLog log) throws IOException, CancelledException {
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(prog, provider);
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(prog, provider, monitor);
AddressFactory af = prog.getAddressFactory();
if (!(af.getDefaultAddressSpace() instanceof SegmentedAddressSpace)) {
throw new IOException("Selected Language must have a segmented address space.");
@ -350,7 +350,7 @@ public class MzLoader extends AbstractLibrarySupportLoader {
try {
Memory mem = prog.getMemory();
SegmentedAddressSpace space =
(SegmentedAddressSpace) prog.getAddressFactory().getDefaultAddressSpace();
(SegmentedAddressSpace) prog.getAddressFactory().getDefaultAddressSpace();
int relocationTableOffset = Conv.shortToInt(dos.e_lfarlc());
int csStart = INITIAL_SEGMENT_VAL;

View File

@ -40,8 +40,7 @@ import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Conv;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
@ -84,7 +83,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
@Override
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program prog,
TaskMonitor monitor, MessageLog log) throws IOException {
TaskMonitor monitor, MessageLog log) throws IOException, CancelledException {
if (monitor.isCancelled()) {
return;
@ -98,7 +97,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
// We don't use the file bytes to create block because the bytes are manipulated before
// forming the block. Creating the FileBytes anyway in case later we want access to all
// the original bytes.
MemoryBlockUtils.createFileBytes(prog, provider);
MemoryBlockUtils.createFileBytes(prog, provider, monitor);
NewExecutable ne = new NewExecutable(factory, provider);
WindowsHeader wh = ne.getWindowsHeader();

View File

@ -34,6 +34,7 @@ import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
@ -107,7 +108,8 @@ public class OmfLoader extends AbstractLibrarySupportLoader {
@Override
protected 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, CancelledException {
OmfFileHeader header = null;
BinaryReader reader = OmfFileHeader.createReader(provider);
@ -127,7 +129,7 @@ public class OmfLoader extends AbstractLibrarySupportLoader {
// We don't use the file bytes to create block because the bytes are manipulated before
// forming the block. Creating the FileBytes anyway in case later we want access to all
// the original bytes.
MemoryBlockUtils.createFileBytes(program, provider);
MemoryBlockUtils.createFileBytes(program, provider, monitor);
int id = program.startTransaction("loading program from OMF");
boolean success = false;

View File

@ -44,8 +44,7 @@ import ghidra.program.model.symbol.*;
import ghidra.program.model.util.AddressSetPropertyMap;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.*;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
@ -94,7 +93,8 @@ public class PeLoader extends AbstractPeDebugLoader {
@Override
protected 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, CancelledException {
if (monitor.isCancelled()) {
return;
@ -112,7 +112,7 @@ public class PeLoader extends AbstractPeDebugLoader {
FileHeader fileHeader = ntHeader.getFileHeader();
monitor.setMessage("Completing PE header parsing...");
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider);
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, monitor);
try {
Map<Integer, Address> sectionNumberToAddress =
processMemoryBlocks(pe, program, fileBytes, monitor, log);

View File

@ -33,6 +33,7 @@ import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class PefLoader extends AbstractLibrarySupportLoader {
@ -68,9 +69,10 @@ public class PefLoader extends AbstractLibrarySupportLoader {
@Override
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, CancelledException {
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider);
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, monitor);
ImportStateCache importState = null;
try {
@ -154,8 +156,8 @@ public class PefLoader extends AbstractLibrarySupportLoader {
}
if (mainSection.getSectionKind() == SectionKind.PackedData ||
mainSection.getSectionKind() == SectionKind.UnpackedData ||
mainSection.getSectionKind() == SectionKind.ExecutableData) {
mainSection.getSectionKind() == SectionKind.UnpackedData ||
mainSection.getSectionKind() == SectionKind.ExecutableData) {
CreateDataCmd cmd = new CreateDataCmd(mainAddress, new PointerDataType());
cmd.applyTo(program);
@ -258,12 +260,13 @@ public class PefLoader extends AbstractLibrarySupportLoader {
}
if (symbolIndex % 100 == 0) {
monitor.setMessage("Processing import " + symbolIndex + " of " + symbols.size());
monitor.setMessage(
"Processing import " + symbolIndex + " of " + symbols.size());
}
++symbolIndex;
String symbolName =
SymbolUtilities.replaceInvalidChars(symbols.get(i).getName(), true);
SymbolUtilities.replaceInvalidChars(symbols.get(i).getName(), true);
boolean success = importState.createLibrarySymbol(library, symbolName, start);
if (!success) {
@ -291,8 +294,8 @@ public class PefLoader extends AbstractLibrarySupportLoader {
private void addExternalReference(Program program, Address start, String libraryName,
String symbolName, MessageLog log) {
try {
program.getReferenceManager().addExternalReference(start, libraryName, symbolName,
null, SourceType.IMPORTED, 0, RefType.DATA);
program.getReferenceManager().addExternalReference(start, libraryName, symbolName, null,
SourceType.IMPORTED, 0, RefType.DATA);
}
catch (Exception e) {
log.appendMsg(e.getMessage());
@ -324,7 +327,7 @@ public class PefLoader extends AbstractLibrarySupportLoader {
return;
}
RelocationState state =
new RelocationState(header, relocationHeader, program, importState);
new RelocationState(header, relocationHeader, program, importState);
List<Relocation> relocations = relocationHeader.getRelocations();
int relocationIndex = 0;
for (Relocation relocation : relocations) {
@ -332,8 +335,8 @@ public class PefLoader extends AbstractLibrarySupportLoader {
return;
}
if (relocationIndex % 100 == 0) {
monitor.setMessage("Processing relocation " + relocationIndex + " of " +
relocations.size());
monitor.setMessage(
"Processing relocation " + relocationIndex + " of " + relocations.size());
}
++relocationIndex;
@ -362,7 +365,7 @@ public class PefLoader extends AbstractLibrarySupportLoader {
MemoryBlock block = importState.getMemoryBlockForSection(section);
Address symbolAddr = block.getStart().add(symbol.getSymbolValue());
AddUniqueLabelCmd cmd =
new AddUniqueLabelCmd(symbolAddr, symbol.getName(), null, SourceType.IMPORTED);
new AddUniqueLabelCmd(symbolAddr, symbol.getName(), null, SourceType.IMPORTED);
if (!cmd.applyTo(program)) {
log.appendMsg(cmd.getStatusMsg());
}
@ -372,7 +375,7 @@ public class PefLoader extends AbstractLibrarySupportLoader {
private void processSections(ContainerHeader header, Program program, FileBytes fileBytes,
ImportStateCache importState, MessageLog log, TaskMonitor monitor)
throws AddressOverflowException, IOException {
throws AddressOverflowException, IOException {
List<SectionHeader> sections = header.getSections();
for (SectionHeader section : sections) {

View File

@ -114,8 +114,8 @@ class MyTestMemory extends AddressSet implements Memory {
}
@Override
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is)
throws IOException {
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is,
TaskMonitor monitor) throws IOException {
throw new UnsupportedOperationException();
}

View File

@ -187,7 +187,7 @@ public class PrelinkFileSystem extends GFileSystemBase implements GFileSystemPro
boolean success = false;
try {
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, offset,
provider.length() - offset);
provider.length() - offset, monitor);
ByteProvider providerWrapper =
new ByteProviderWrapper(provider, offset, provider.length() - offset);
MachoProgramBuilder.buildProgram(program, providerWrapper, fileBytes, new MessageLog(),

View File

@ -328,8 +328,8 @@ public class MemoryTestDummy extends AddressSet implements Memory {
}
@Override
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is)
throws IOException {
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is,
TaskMonitor monitor) throws IOException {
throw new UnsupportedOperationException();
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,231 +15,234 @@
*/
package ghidra.util;
import java.io.IOException;
import java.io.InputStream;
import ghidra.util.exception.IOCancelledException;
import ghidra.util.task.TaskMonitor;
import java.io.*;
/**
* An InputStream which utilizes a TaskMonitor to indicate input progress and
* allows the operation to be cancelled via the TaskMonitor.
*/
public class MonitoredInputStream extends InputStream {
private final static int PROGRESS_INCREMENT = 32*1024;
private final static int PROGRESS_INCREMENT = 32 * 1024;
protected InputStream in;
private TaskMonitor monitor;
private int smallCount = 0;
private int count = 0;
public MonitoredInputStream(InputStream in, TaskMonitor monitor) {
this.in = in;
this.monitor = monitor;
this.monitor = monitor;
}
/**
* Reset the current progress count to the specified value.
*/
*/
public void setProgress(int count) {
this.count = count;
}
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
* <p>
* This method
* simply performs <code>in.read()</code> and returns the result.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
*/
@Override
public int read() throws IOException {
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
* <p>
* This method
* simply performs <code>in.read()</code> and returns the result.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
*/
@Override
public int read() throws IOException {
if (monitor.isCancelled()) {
throw new IOCancelledException();
}
int n = in.read();
if (n != -1) {
++smallCount;
if (smallCount >= PROGRESS_INCREMENT) {
if (monitor.isCancelled())
throw new IOCancelledException();
count += smallCount;
smallCount = 0;
monitor.setProgress(count);
monitor.setProgress(count);
}
}
return n;
}
}
/**
* Reads up to <code>byte.length</code> bytes of data from this
* input stream into an array of bytes. This method blocks until some
* input is available.
* <p>
* This method simply performs the call
* <code>read(b, 0, b.length)</code> and returns
* the result. It is important that it does
* <i>not</i> do <code>in.read(b)</code> instead;
* certain subclasses of <code>FilterInputStream</code>
* depend on the implementation strategy actually
* used.
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterInputStream#read(byte[], int, int)
*/
@Override
public int read(byte b[]) throws IOException {
/**
* Reads up to <code>byte.length</code> bytes of data from this
* input stream into an array of bytes. This method blocks until some
* input is available.
* <p>
* This method simply performs the call
* <code>read(b, 0, b.length)</code> and returns
* the result. It is important that it does
* <i>not</i> do <code>in.read(b)</code> instead;
* certain subclasses of <code>FilterInputStream</code>
* depend on the implementation strategy actually
* used.
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterInputStream#read(byte[], int, int)
*/
@Override
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
}
/**
* Reads up to <code>len</code> bytes of data from this input stream
* into an array of bytes. This method blocks until some input is
* available.
* <p>
* This method simply performs <code>in.read(b, off, len)</code>
* and returns the result.
*
* @param b the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
@Override
public int read(byte b[], int off, int len) throws IOException {
/**
* Reads up to <code>len</code> bytes of data from this input stream
* into an array of bytes. This method blocks until some input is
* available.
* <p>
* This method simply performs <code>in.read(b, off, len)</code>
* and returns the result.
*
* @param b the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
@Override
public int read(byte b[], int off, int len) throws IOException {
if (monitor.isCancelled()) {
throw new IOCancelledException();
}
int n = in.read(b, off, len);
smallCount += n;
if (smallCount >= PROGRESS_INCREMENT) {
if (monitor.isCancelled())
throw new IOCancelledException();
count += smallCount;
smallCount = 0;
monitor.setProgress(count);
monitor.setProgress(count);
}
return n;
}
}
/**
* Skips over and discards <code>n</code> bytes of data from the
* input stream. The <code>skip</code> method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
* possibly <code>0</code>. The actual number of bytes skipped is
* returned.
* <p>
* This method
* simply performs <code>in.skip(n)</code>.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @exception IOException if an I/O error occurs.
*/
@Override
public long skip(long n) throws IOException {
/**
* Skips over and discards <code>n</code> bytes of data from the
* input stream. The <code>skip</code> method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
* possibly <code>0</code>. The actual number of bytes skipped is
* returned.
* <p>
* This method
* simply performs <code>in.skip(n)</code>.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @exception IOException if an I/O error occurs.
*/
@Override
public long skip(long n) throws IOException {
return in.skip(n);
}
}
/**
* Returns the number of bytes that can be read from this input
* stream without blocking.
* <p>
* This method
* simply performs <code>in.available()</code> and
* returns the result.
*
* @return the number of bytes that can be read from the input stream
* without blocking.
* @exception IOException if an I/O error occurs.
*/
@Override
public int available() throws IOException {
/**
* Returns the number of bytes that can be read from this input
* stream without blocking.
* <p>
* This method
* simply performs <code>in.available()</code> and
* returns the result.
*
* @return the number of bytes that can be read from the input stream
* without blocking.
* @exception IOException if an I/O error occurs.
*/
@Override
public int available() throws IOException {
return in.available();
}
}
/**
* Closes this input stream and releases any system resources
* associated with the stream.
* This
* method simply performs <code>in.close()</code>.
*
* @exception IOException if an I/O error occurs.
*/
@Override
public void close() throws IOException {
/**
* Closes this input stream and releases any system resources
* associated with the stream.
* This
* method simply performs <code>in.close()</code>.
*
* @exception IOException if an I/O error occurs.
*/
@Override
public void close() throws IOException {
in.close();
}
}
/**
* Marks the current position in this input stream. A subsequent
* call to the <code>reset</code> method repositions this stream at
* the last marked position so that subsequent reads re-read the same bytes.
* <p>
* The <code>readlimit</code> argument tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
* <p>
* This method simply performs <code>in.mark(readlimit)</code>.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.FilterInputStream#reset
*/
@Override
public synchronized void mark(int readlimit) {
/**
* Marks the current position in this input stream. A subsequent
* call to the <code>reset</code> method repositions this stream at
* the last marked position so that subsequent reads re-read the same bytes.
* <p>
* The <code>readlimit</code> argument tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
* <p>
* This method simply performs <code>in.mark(readlimit)</code>.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.FilterInputStream#reset
*/
@Override
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}
}
/**
* Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream.
* <p>
* This method
* simply performs <code>in.reset()</code>.
* <p>
* Stream marks are intended to be used in
* situations where you need to read ahead a little to see what's in
* the stream. Often this is most easily done by invoking some
* general parser. If the stream is of the type handled by the
* parse, it just chugs along happily. If the stream is not of
* that type, the parser should toss an exception when it fails.
* If this happens within readlimit bytes, it allows the outer
* code to reset the stream and try another parser.
*
* @exception IOException if the stream has not been marked or if the
* mark has been invalidated.
* @see java.io.FilterInputStream#mark(int)
*/
@Override
public synchronized void reset() throws IOException {
/**
* Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream.
* <p>
* This method
* simply performs <code>in.reset()</code>.
* <p>
* Stream marks are intended to be used in
* situations where you need to read ahead a little to see what's in
* the stream. Often this is most easily done by invoking some
* general parser. If the stream is of the type handled by the
* parse, it just chugs along happily. If the stream is not of
* that type, the parser should toss an exception when it fails.
* If this happens within readlimit bytes, it allows the outer
* code to reset the stream and try another parser.
*
* @exception IOException if the stream has not been marked or if the
* mark has been invalidated.
* @see java.io.FilterInputStream#mark(int)
*/
@Override
public synchronized void reset() throws IOException {
in.reset();
}
}
/**
* Tests if this input stream supports the <code>mark</code>
* and <code>reset</code> methods.
* This method
* simply performs <code>in.markSupported()</code>.
*
* @return <code>true</code> if this stream type supports the
* <code>mark</code> and <code>reset</code> method;
* <code>false</code> otherwise.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
@Override
public boolean markSupported() {
/**
* Tests if this input stream supports the <code>mark</code>
* and <code>reset</code> methods.
* This method
* simply performs <code>in.markSupported()</code>.
*
* @return <code>true</code> if this stream type supports the
* <code>mark</code> and <code>reset</code> method;
* <code>false</code> otherwise.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
@Override
public boolean markSupported() {
return in.markSupported();
}
}
}

View File

@ -20,6 +20,7 @@ import java.io.InputStream;
import java.util.*;
import db.*;
import ghidra.util.exception.IOCancelledException;
import ghidra.util.exception.VersionException;
/**
@ -158,9 +159,18 @@ class FileBytesAdapterV0 extends FileBytesAdapter {
}
buffers[bufCount - 1] = handle.createBuffer(sizeLastBuf);
for (DBBuffer buffer : buffers) {
buffer.fill(is);
try {
for (DBBuffer buffer : buffers) {
buffer.fill(is);
}
}
catch (IOCancelledException e) {
for (DBBuffer buffer : buffers) {
buffer.delete();
}
throw e;
}
return buffers;
}
}

View File

@ -494,8 +494,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
return newBlock;
}
catch (IOCancelledException e) {
// TODO: this could leave things in a bad state.
// Canceling requires additional improvements (see GT-3064)
// this assumes the adapter has already cleaned up any partially created buffers.
if (overlay) {
checkRemoveAddressSpace(start.getAddressSpace());
}
throw new CancelledException();
}
catch (IOException e) {
@ -2022,14 +2024,18 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
}
@Override
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is)
throws IOException {
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is,
TaskMonitor monitor) throws IOException, CancelledException {
lock.acquire();
try {
// TODO: this should accept task monitor to permit cancellation although
// canceling requires additional improvements (see GT-3064)
if (monitor != null && is != null) {
is = new MonitoredInputStream(is, monitor);
}
return fileBytesAdapter.createFileBytes(filename, offset, size, is);
}
catch (IOCancelledException e) {
throw new CancelledException();
}
finally {
lock.release();
}

View File

@ -148,6 +148,8 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
@Override
MemoryBlockDB createInitializedBlock(String name, Address startAddr, InputStream is,
long length, int permissions) throws AddressOverflowException, IOException {
// TODO verify that it is necessary to pre-define all segments in the address map
updateAddressMapForAllAddresses(startAddr, length);
List<SubMemoryBlock> subBlocks = new ArrayList<>();
@ -171,7 +173,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
Collections.sort(memoryBlocks);
return newBlock;
}
catch (IOException e) {
catch (IOCancelledException e) {
// clean up any created DBBufferss
for (SubMemoryBlock subMemoryBlock : subBlocks) {
BufferSubMemoryBlock bufferSubMemoryBlock = (BufferSubMemoryBlock) subMemoryBlock;

View File

@ -729,11 +729,14 @@ public interface Memory extends AddressSetView {
* @param offset the offset into the file for the first byte in the input stream.
* @param size the number of bytes to store from the input stream.
* @param is the input stream that will supply the bytes to store in the program.
* @param monitor
* @return a FileBytes that was created to access the bytes.
* @throws IOException if there was an IOException saving the bytes to the program database.
* @throws CancelledException if the user cancelled this operation. Note: the database will
* be stable, but the buffers may contain 0s instead of the actual bytes.
*/
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is)
throws IOException;
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is,
TaskMonitor monitor) throws IOException, CancelledException;
/**
* Returns a list of all the stored original file bytes objects

View File

@ -469,8 +469,8 @@ public class MemoryStub implements Memory {
}
@Override
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is)
throws IOException {
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is,
TaskMonitor monitor) throws IOException {
throw new UnsupportedOperationException();
}

View File

@ -47,7 +47,7 @@ public class FileBytesTest extends AbstractGenericTest {
}
@Test
public void testStoreAndRetrieveFileBytes() throws IOException {
public void testStoreAndRetrieveFileBytes() throws Exception {
int dataSize = MAX_BUFFER_SIZE_FOR_TESTING / 2;
FileBytes fileBytes = createFileBytes("testFile", dataSize);
@ -186,13 +186,13 @@ public class FileBytesTest extends AbstractGenericTest {
}
}
private FileBytes createFileBytes(String name, int size) throws IOException {
private FileBytes createFileBytes(String name, int size) throws Exception {
byte[] bytes = new byte[size];
for (int i = 0; i < size; i++) {
bytes[i] = (byte) i;
}
try (ByteArrayInputStream is = new ByteArrayInputStream(bytes)) {
return mem.createFileBytes(name, 0, size, is);
return mem.createFileBytes(name, 0, size, is, TaskMonitor.DUMMY);
}
}

View File

@ -18,7 +18,6 @@ package ghidra.program.database.mem;
import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import org.junit.*;
@ -282,7 +281,8 @@ public class MemBlockDBTest extends AbstractGenericTest {
@Test
public void testCreateFileBytesBlockOutSideRange() throws Exception {
byte[] bytes = new byte[256];
FileBytes fileBytes = mem.createFileBytes("test", 0, 100, new ByteArrayInputStream(bytes));
FileBytes fileBytes =
mem.createFileBytes("test", 0, 100, new ByteArrayInputStream(bytes), TaskMonitor.DUMMY);
try {
mem.createInitializedBlock("test", addr(100), fileBytes, 10, 100, false);
fail(
@ -379,7 +379,6 @@ public class MemBlockDBTest extends AbstractGenericTest {
}
}
@Test
public void testJoinFileBytesBlockAndBufferBlock() throws Exception {
FileBytes fileBytes = createFileBytes();
@ -695,7 +694,6 @@ public class MemBlockDBTest extends AbstractGenericTest {
assertEquals(2, ranges.getRangeCount()); // we have two sublocks so two distinct ranges
assertEquals(10, ranges.get(0).getSize() + ranges.get(1).getSize());
ByteSourceRange range = ranges.get(0);
assertEquals(10, range.getStart().getOffset());
assertEquals(15, range.getEnd().getOffset());
@ -857,7 +855,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
assertEquals(0, range.getOffset());
}
@Test
@Test
public void testAddressSourceInfoForFileBytesBlock() throws Exception {
FileBytes fileBytes = createFileBytes();
mem.createInitializedBlock("block", addr(100), fileBytes, 10, 50, false);
@ -919,12 +917,13 @@ public class MemBlockDBTest extends AbstractGenericTest {
false);
}
private FileBytes createFileBytes() throws IOException {
private FileBytes createFileBytes() throws Exception {
byte[] bytes = new byte[256];
for (int i = 0; i < 256; i++) {
bytes[i] = (byte) i;
}
FileBytes fileBytes = mem.createFileBytes("test", 0, 100, new ByteArrayInputStream(bytes));
FileBytes fileBytes =
mem.createFileBytes("test", 0, 100, new ByteArrayInputStream(bytes), TaskMonitor.DUMMY);
return fileBytes;
}