mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GT-3079 Added checking to binary loader to check for memory conflicts
before loading in the "add to program" case.
This commit is contained in:
parent
6da0d9340d
commit
ae5662a50f
19 changed files with 132 additions and 99 deletions
|
@ -225,14 +225,13 @@ public class MemoryBlockUtils {
|
||||||
block = program.getMemory().createInitializedBlock(name, start, fileBytes, offset,
|
block = program.getMemory().createInitializedBlock(name, start, fileBytes, offset,
|
||||||
length, isOverlay);
|
length, isOverlay);
|
||||||
}
|
}
|
||||||
catch (MemoryConflictException e) {
|
catch (MemoryConflictException | DuplicateNameException e) {
|
||||||
block = program.getMemory().createInitializedBlock(name, start, fileBytes, offset,
|
block = createBlockNoDuplicateName(program, name, start, fileBytes, offset, length);
|
||||||
length, true);
|
|
||||||
log.appendMsg("Conflict attempting to create memory block: " + name +
|
log.appendMsg("Conflict attempting to create memory block: " + name +
|
||||||
" at address " + start.toString() + " Created block in new overlay instead");
|
" at address " + start.toString() + " Created block in new overlay instead");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (LockException | DuplicateNameException | MemoryConflictException e) {
|
catch (LockException | MemoryConflictException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +240,22 @@ public class MemoryBlockUtils {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static MemoryBlock createBlockNoDuplicateName(Program program, String blockName,
|
||||||
|
Address start, FileBytes fileBytes, long offset, long length)
|
||||||
|
throws LockException, MemoryConflictException, AddressOverflowException {
|
||||||
|
int count = 1;
|
||||||
|
String name = blockName;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
return program.getMemory().createInitializedBlock(name, start, fileBytes, offset,
|
||||||
|
length, true);
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
name = blockName + "_" + count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new initialized block in memory using the bytes from the given input stream.
|
* Creates a new initialized block in memory using the bytes from the given input stream.
|
||||||
* If there is a conflict when creating this block (some other block occupies at least some
|
* If there is a conflict when creating this block (some other block occupies at least some
|
||||||
|
|
|
@ -139,7 +139,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
|
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
for (Option option : options) {
|
for (Option option : options) {
|
||||||
|
@ -151,7 +151,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.validateOptions(provider, loadSpec, options);
|
return super.validateOptions(provider, loadSpec, options, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -188,7 +188,7 @@ public abstract class AbstractProgramLoader implements Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
for (Option option : options) {
|
for (Option option : options) {
|
||||||
String name = option.getName();
|
String name = option.getName();
|
||||||
|
|
|
@ -23,16 +23,14 @@ import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.model.DomainFolder;
|
import ghidra.framework.model.DomainFolder;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.framework.store.LockException;
|
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.NumericUtilities;
|
import ghidra.util.NumericUtilities;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class BinaryLoader extends AbstractProgramLoader {
|
public class BinaryLoader extends AbstractProgramLoader {
|
||||||
|
@ -91,7 +89,8 @@ public class BinaryLoader extends AbstractProgramLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||||
|
Program program) {
|
||||||
Address baseAddr = null;
|
Address baseAddr = null;
|
||||||
long length = 0;
|
long length = 0;
|
||||||
long fileOffset = 0;
|
long fileOffset = 0;
|
||||||
|
@ -194,7 +193,12 @@ public class BinaryLoader extends AbstractProgramLoader {
|
||||||
if (length == -1) {
|
if (length == -1) {
|
||||||
return "Invalid length specified";
|
return "Invalid length specified";
|
||||||
}
|
}
|
||||||
return super.validateOptions(provider, loadSpec, options);
|
if (program != null) {
|
||||||
|
if (program.getMemory().intersects(baseAddr, baseAddr.add(length - 1))) {
|
||||||
|
return "Memory Conflict: Use <Options...> to change the base address!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.validateOptions(provider, loadSpec, options, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address getBaseAddr(List<Option> options) {
|
private Address getBaseAddr(List<Option> options) {
|
||||||
|
@ -322,27 +326,27 @@ public class BinaryLoader extends AbstractProgramLoader {
|
||||||
if (blockName == null || blockName.length() == 0) {
|
if (blockName == null || blockName.length() == 0) {
|
||||||
blockName = generateBlockName(prog, isOverlay, baseAddr.getAddressSpace());
|
blockName = generateBlockName(prog, isOverlay, baseAddr.getAddressSpace());
|
||||||
}
|
}
|
||||||
try {
|
createBlock(prog, isOverlay, blockName, baseAddr, fileBytes, length, log);
|
||||||
MemoryBlock block = prog.getMemory().createInitializedBlock(blockName, baseAddr,
|
|
||||||
fileBytes, 0, length, isOverlay);
|
|
||||||
block.setRead(true);
|
|
||||||
block.setWrite(isOverlay ? false : true);
|
|
||||||
block.setExecute(isOverlay ? false : true);
|
|
||||||
block.setSourceName("Binary Loader");
|
|
||||||
MemoryBlockUtils.adjustFragment(prog, block.getStart(), blockName);
|
|
||||||
}
|
|
||||||
catch (LockException | MemoryConflictException e) {
|
|
||||||
Msg.error(this, "Unexpected exception creating memory block", e);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (AddressOverflowException e) {
|
catch (AddressOverflowException e) {
|
||||||
throw new IllegalArgumentException("Invalid address range specified: start:" +
|
throw new IllegalArgumentException("Invalid address range specified: start:" +
|
||||||
baseAddr + ", length:" + length + " - end address exceeds address space boundary!");
|
baseAddr + ", length:" + length + " - end address exceeds address space boundary!");
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException e) {
|
|
||||||
throw new IllegalArgumentException("Duplicate block name specified: " + blockName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createBlock(Program prog, boolean isOverlay, String blockName, Address baseAddr,
|
||||||
|
FileBytes fileBytes, long length, MessageLog log)
|
||||||
|
throws AddressOverflowException, IOException {
|
||||||
|
|
||||||
|
if (prog.getMemory().intersects(baseAddr, baseAddr.add(length - 1))) {
|
||||||
|
throw new IOException("Can't load " + length + " bytes at address " + baseAddr +
|
||||||
|
" since it conflicts with existing memory blocks!");
|
||||||
|
}
|
||||||
|
MemoryBlockUtils.createInitializedBlock(prog, isOverlay, blockName, baseAddr, fileBytes, 0,
|
||||||
|
length, null, "Binary Loader", true, !isOverlay, !isOverlay, log);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long clipToMemorySpace(long length, MessageLog log, Program program) {
|
private long clipToMemorySpace(long length, MessageLog log, Program program) {
|
||||||
|
|
|
@ -153,7 +153,7 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
for (Option option : options) {
|
for (Option option : options) {
|
||||||
String name = option.getName();
|
String name = option.getName();
|
||||||
|
@ -164,7 +164,7 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.validateOptions(provider, loadSpec, options);
|
return super.validateOptions(provider, loadSpec, options, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean performFakeLinking(List<Option> options) {
|
private boolean performFakeLinking(List<Option> options) {
|
||||||
|
|
|
@ -90,14 +90,14 @@ public class ElfLoader extends AbstractLibrarySupportLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
String validationErrorStr = ElfLoaderOptionsFactory.validateOptions(loadSpec, options);
|
String validationErrorStr = ElfLoaderOptionsFactory.validateOptions(loadSpec, options);
|
||||||
if (validationErrorStr != null) {
|
if (validationErrorStr != null) {
|
||||||
return validationErrorStr;
|
return validationErrorStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.validateOptions(provider, loadSpec, options);
|
return super.validateOptions(provider, loadSpec, options, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class GdtLoader implements Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
if (options != null && options.size() > 0) {
|
if (options != null && options.size() > 0) {
|
||||||
return "GDTLoader takes no options";
|
return "GDTLoader takes no options";
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class GzfLoader implements Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
if (options != null && options.size() > 0) {
|
if (options != null && options.size() > 0) {
|
||||||
return "GzfLoader takes no options";
|
return "GzfLoader takes no options";
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class IntelHexLoader extends AbstractProgramLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
Address baseAddr = null;
|
Address baseAddr = null;
|
||||||
|
|
||||||
for (Option option : options) {
|
for (Option option : options) {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
class IntelHexMemImage {
|
class IntelHexMemImage {
|
||||||
|
@ -212,23 +211,9 @@ class IntelHexMemImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = blockName == null ? base.getAddressSpace().getName() : blockName;
|
String name = blockName == null ? base.getAddressSpace().getName() : blockName;
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
MemoryBlockUtils.createInitializedBlock(program, isOverlay, name,
|
MemoryBlockUtils.createInitializedBlock(program, isOverlay, name,
|
||||||
blockRange.getMinAddress(), new ByteArrayInputStream(data), data.length,
|
blockRange.getMinAddress(), new ByteArrayInputStream(data), data.length,
|
||||||
"Generated by " + creator, progFile, true, !isOverlay, !isOverlay, log,
|
"Generated by " + creator, progFile, true, !isOverlay, !isOverlay, log, monitor);
|
||||||
monitor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
Throwable cause = e.getCause();
|
|
||||||
if (!(cause instanceof DuplicateNameException)) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
++count;
|
|
||||||
name = blockName + "_" + count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return log.toString();
|
return log.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,10 +124,13 @@ public interface Loader extends ExtensionPoint, Comparable<Loader> {
|
||||||
* @param provider The bytes of the thing being loaded.
|
* @param provider The bytes of the thing being loaded.
|
||||||
* @param loadSpec The proposed {@link LoadSpec}.
|
* @param loadSpec The proposed {@link LoadSpec}.
|
||||||
* @param options The list of {@link Option}s to validate.
|
* @param options The list of {@link Option}s to validate.
|
||||||
|
* @param program existing program if the loader is adding to an existing program. If it is
|
||||||
|
* a fresh import, then this will be null.
|
||||||
* @return null if all {@link Option}s are valid; otherwise, an error message describing the
|
* @return null if all {@link Option}s are valid; otherwise, an error message describing the
|
||||||
* problem is returned.
|
* problem is returned.
|
||||||
*/
|
*/
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options);
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||||
|
Program program);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link Loader}'s name, which is used both for display purposes, and to identify the
|
* Gets the {@link Loader}'s name, which is used both for display purposes, and to identify the
|
||||||
|
|
|
@ -92,7 +92,8 @@ public class MotorolaHexLoader extends AbstractProgramLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||||
|
Program program) {
|
||||||
Address baseAddr = null;
|
Address baseAddr = null;
|
||||||
|
|
||||||
for (Option option : options) {
|
for (Option option : options) {
|
||||||
|
@ -335,30 +336,16 @@ public class MotorolaHexLoader extends AbstractProgramLoader {
|
||||||
|
|
||||||
String name =
|
String name =
|
||||||
blockName == null ? baseAddr.getAddressSpace().getName() : blockName;
|
blockName == null ? baseAddr.getAddressSpace().getName() : blockName;
|
||||||
int count = 0;
|
MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start,
|
||||||
while (true) {
|
new ByteArrayInputStream(data), data.length, "", provider.getName(),
|
||||||
try {
|
true, isOverlay, isOverlay, log, monitor);
|
||||||
MemoryBlockUtils.createInitializedBlock(program, isOverlay, name,
|
|
||||||
start, new ByteArrayInputStream(data), data.length, "",
|
|
||||||
provider.getName(), true, isOverlay, isOverlay, log, monitor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
Throwable cause = e.getCause();
|
|
||||||
if (!(cause instanceof DuplicateNameException)) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
++count;
|
|
||||||
name = blockName + "_" + count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
// set up new start address of new block we are starting
|
// set up new start address of new block we are starting
|
||||||
startAddress = addr;
|
startAddress = addr;
|
||||||
endAddress = addr;
|
endAddress = addr;
|
||||||
}
|
}
|
||||||
// update endaddress to start of next contiguous line address
|
// update end address to start of next contiguous line address
|
||||||
endAddress += numBytes - addrLen - 1;
|
endAddress += numBytes - addrLen - 1;
|
||||||
|
|
||||||
// read in the data bytes on the line
|
// read in the data bytes on the line
|
||||||
|
|
|
@ -177,7 +177,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
for (Option option : options) {
|
for (Option option : options) {
|
||||||
String name = option.getName();
|
String name = option.getName();
|
||||||
|
@ -188,7 +188,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.validateOptions(provider, loadSpec, options);
|
return super.validateOptions(provider, loadSpec, options, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -335,7 +335,7 @@ public class XmlLoader extends AbstractProgramLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
// XXX will this work? is there other state that xmlOptions needs to
|
// XXX will this work? is there other state that xmlOptions needs to
|
||||||
// know?
|
// know?
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -60,10 +60,12 @@ public class AddToProgramDialog extends ImporterDialog {
|
||||||
folderButton.setEnabled(false);
|
folderButton.setEnabled(false);
|
||||||
languageButton.setEnabled(false);
|
languageButton.setEnabled(false);
|
||||||
filenameTextField.setEnabled(false);
|
filenameTextField.setEnabled(false);
|
||||||
|
validateFormInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean validateFormInput() {
|
protected boolean validateFormInput() {
|
||||||
|
|
||||||
setOkEnabled(false);
|
setOkEnabled(false);
|
||||||
optionsButton.setEnabled(false);
|
optionsButton.setEnabled(false);
|
||||||
Loader loader = getSelectedLoader();
|
Loader loader = getSelectedLoader();
|
||||||
|
@ -75,10 +77,20 @@ public class AddToProgramDialog extends ImporterDialog {
|
||||||
setStatusText(loader.getName() + " does not support add to program.");
|
setStatusText(loader.getName() + " does not support add to program.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
optionsButton.setEnabled(true);
|
||||||
|
|
||||||
|
LoadSpec loadSpec = getSelectedLoadSpec(loader);
|
||||||
|
|
||||||
|
String result =
|
||||||
|
loader.validateOptions(byteProvider, loadSpec, getOptions(loadSpec), addToProgram);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
setStatusText(result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
setStatusText("");
|
setStatusText("");
|
||||||
setOkEnabled(true);
|
setOkEnabled(true);
|
||||||
optionsButton.setEnabled(true);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,19 +114,19 @@ public class AddToProgramDialog extends ImporterDialog {
|
||||||
options = selectedLoader.getDefaultOptions(byteProvider, selectedLoadSpec, null, true);
|
options = selectedLoader.getDefaultOptions(byteProvider, selectedLoadSpec, null, true);
|
||||||
}
|
}
|
||||||
TaskLauncher.launchNonModal("Import File", monitor -> {
|
TaskLauncher.launchNonModal("Import File", monitor -> {
|
||||||
ImporterUtilities.addContentToProgram(tool, addToProgram, fsrl, selectedLoadSpec, options,
|
ImporterUtilities.addContentToProgram(tool, addToProgram, fsrl, selectedLoadSpec,
|
||||||
monitor);
|
options, monitor);
|
||||||
});
|
});
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Option> getOptions(LoadSpec loadSpec) {
|
protected List<Option> getOptions(LoadSpec loadSpec) {
|
||||||
if (options == null) {
|
if (options != null) {
|
||||||
options = loadSpec.getLoader().getDefaultOptions(byteProvider, loadSpec, null, true);
|
|
||||||
}
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
return loadSpec.getLoader().getDefaultOptions(byteProvider, loadSpec, addToProgram, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the current language/compiler spec from the program that will be added to.
|
* Retrieves the current language/compiler spec from the program that will be added to.
|
||||||
|
|
|
@ -346,10 +346,9 @@ public class ImporterDialog extends DialogComponentProvider {
|
||||||
String programPath = removeTrailingSlashes(getName());
|
String programPath = removeTrailingSlashes(getName());
|
||||||
DomainFolder importFolder = getOrCreateImportFolder(destinationFolder, programPath);
|
DomainFolder importFolder = getOrCreateImportFolder(destinationFolder, programPath);
|
||||||
String programName = FilenameUtils.getName(programPath);
|
String programName = FilenameUtils.getName(programPath);
|
||||||
List<Option> localOptions = getOptions(loadSpec);
|
|
||||||
TaskLauncher.launchNonModal("Import File", monitor -> {
|
TaskLauncher.launchNonModal("Import File", monitor -> {
|
||||||
ImporterUtilities.importSingleFile(tool, programManager, fsrl, importFolder,
|
ImporterUtilities.importSingleFile(tool, programManager, fsrl, importFolder,
|
||||||
loadSpec, programName, localOptions, monitor);
|
loadSpec, programName, getOptions(loadSpec), monitor);
|
||||||
});
|
});
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
@ -404,24 +403,24 @@ public class ImporterDialog extends DialogComponentProvider {
|
||||||
AddressFactory addressFactory = selectedLanguage.getLanguage().getAddressFactory();
|
AddressFactory addressFactory = selectedLanguage.getLanguage().getAddressFactory();
|
||||||
LoadSpec loadSpec = getSelectedLoadSpec(loader);
|
LoadSpec loadSpec = getSelectedLoadSpec(loader);
|
||||||
OptionValidator validator =
|
OptionValidator validator =
|
||||||
optionList -> loader.validateOptions(byteProvider, loadSpec, optionList);
|
optionList -> loader.validateOptions(byteProvider, loadSpec, optionList, null);
|
||||||
|
|
||||||
AddressFactoryService service = () -> addressFactory;
|
AddressFactoryService service = () -> addressFactory;
|
||||||
|
|
||||||
List<Option> defaultOptions = getOptions(loadSpec);
|
List<Option> currentOptions = getOptions(loadSpec);
|
||||||
if (defaultOptions.isEmpty()) {
|
if (currentOptions.isEmpty()) {
|
||||||
Msg.showInfo(this, null, "Options", "There are no options for this importer!");
|
Msg.showInfo(this, null, "Options", "There are no options for this importer!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionsDialog optionsDialog = new OptionsDialog(defaultOptions, validator, service);
|
OptionsDialog optionsDialog = new OptionsDialog(currentOptions, validator, service);
|
||||||
optionsDialog.setHelpLocation(
|
optionsDialog.setHelpLocation(
|
||||||
new HelpLocation("ImporterPlugin", getAnchorForSelectedLoader(loader)));
|
new HelpLocation("ImporterPlugin", getAnchorForSelectedLoader(loader)));
|
||||||
tool.showDialog(optionsDialog);
|
tool.showDialog(optionsDialog);
|
||||||
if (!optionsDialog.wasCancelled()) {
|
if (!optionsDialog.wasCancelled()) {
|
||||||
options = optionsDialog.getOptions();
|
options = optionsDialog.getOptions();
|
||||||
}
|
}
|
||||||
|
validateFormInput();
|
||||||
}
|
}
|
||||||
catch (LanguageNotFoundException e) {
|
catch (LanguageNotFoundException e) {
|
||||||
Msg.showError(this, null, "Language Error",
|
Msg.showError(this, null, "Language Error",
|
||||||
|
|
|
@ -23,8 +23,12 @@ import java.util.Arrays;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteArrayProvider;
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
import ghidra.program.database.ProgramBuilder;
|
||||||
|
import ghidra.program.database.mem.FileBytes;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
@ -72,8 +76,7 @@ public class MemoryBlockUtilTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
Arrays.fill(data, (byte) 0xb);
|
Arrays.fill(data, (byte) 0xb);
|
||||||
is = new ByteArrayInputStream(data);
|
is = new ByteArrayInputStream(data);
|
||||||
MemoryBlockUtils.createInitializedBlock(prog, false, "b", space.getAddress(3500), is, 1000,
|
MemoryBlockUtils.createInitializedBlock(prog, false, "b", space.getAddress(3500), is, 1000,
|
||||||
"bbbb", "b b b", false,
|
"bbbb", "b b b", false, false, false, log, TaskMonitor.DUMMY);
|
||||||
false, false, log, TaskMonitor.DUMMY);
|
|
||||||
|
|
||||||
MemoryBlock[] blocks = prog.getMemory().getBlocks();
|
MemoryBlock[] blocks = prog.getMemory().getBlocks();
|
||||||
assertEquals(2, blocks.length);
|
assertEquals(2, blocks.length);
|
||||||
|
@ -111,8 +114,8 @@ public class MemoryBlockUtilTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
byte[] cdata = new byte[1000];
|
byte[] cdata = new byte[1000];
|
||||||
Arrays.fill(cdata, (byte) 0xc);
|
Arrays.fill(cdata, (byte) 0xc);
|
||||||
MemoryBlockUtils.createInitializedBlock(prog, false, "c", space.getAddress(4000),
|
MemoryBlockUtils.createInitializedBlock(prog, false, "c", space.getAddress(4000),
|
||||||
new ByteArrayInputStream(cdata),
|
new ByteArrayInputStream(cdata), 1000, "Ccomment", "Csource", false, false, false, log,
|
||||||
1000, "Ccomment", "Csource", false, false, false, log, TaskMonitor.DUMMY);
|
TaskMonitor.DUMMY);
|
||||||
|
|
||||||
MemoryBlock[] blocks = prog.getMemory().getBlocks();
|
MemoryBlock[] blocks = prog.getMemory().getBlocks();
|
||||||
assertEquals(2, blocks.length);
|
assertEquals(2, blocks.length);
|
||||||
|
@ -127,5 +130,30 @@ public class MemoryBlockUtilTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue(blocks[1].isInitialized());
|
assertTrue(blocks[1].isInitialized());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO test bit blocks and code unit clearing...
|
private Address addr(long offset) {
|
||||||
|
return space.getAddress(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDuplicateExceptionHandling() throws Exception {
|
||||||
|
ByteProvider byteProvider = new ByteArrayProvider(new byte[1000]);
|
||||||
|
FileBytes fileBytes =
|
||||||
|
MemoryBlockUtils.createFileBytes(prog, byteProvider, TaskMonitor.DUMMY);
|
||||||
|
|
||||||
|
MemoryBlockUtils.createInitializedBlock(prog, true, "test", addr(0), fileBytes, 0, 10, "",
|
||||||
|
"", true, true, true, new MessageLog());
|
||||||
|
MemoryBlockUtils.createInitializedBlock(prog, true, "test", addr(0), fileBytes, 0, 10, "",
|
||||||
|
"", true, true, true, new MessageLog());
|
||||||
|
MemoryBlockUtils.createInitializedBlock(prog, true, "test", addr(0), fileBytes, 0, 10, "",
|
||||||
|
"", true, true, true, new MessageLog());
|
||||||
|
|
||||||
|
MemoryBlock[] blocks = prog.getMemory().getBlocks();
|
||||||
|
assertEquals(3, blocks.length);
|
||||||
|
|
||||||
|
assertEquals("test", blocks[0].getName());
|
||||||
|
assertEquals("test_1", blocks[1].getName());
|
||||||
|
assertEquals("test_2", blocks[2].getName());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package generic.test;
|
package generic.test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
|
@ -661,10 +661,10 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
||||||
if (button == null) {
|
if (button == null) {
|
||||||
throw new AssertionError("Couldn't find button " + buttonText + ".");
|
throw new AssertionError("Couldn't find button " + buttonText + ".");
|
||||||
}
|
}
|
||||||
if (!button.isShowing()) {
|
if (!runSwing(() -> button.isShowing())) {
|
||||||
throw new AssertionError("Button " + buttonText + " is not showing.");
|
throw new AssertionError("Button " + buttonText + " is not showing.");
|
||||||
}
|
}
|
||||||
if (!button.isEnabled()) {
|
if (!runSwing(() -> button.isEnabled())) {
|
||||||
throw new AssertionError("Button " + buttonText + " is not enabled.");
|
throw new AssertionError("Button " + buttonText + " is not enabled.");
|
||||||
}
|
}
|
||||||
pressButton(button, waitForCompletion);
|
pressButton(button, waitForCompletion);
|
||||||
|
@ -700,10 +700,10 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
||||||
if (button == null) {
|
if (button == null) {
|
||||||
throw new AssertionError("Couldn't find button " + buttonName + ".");
|
throw new AssertionError("Couldn't find button " + buttonName + ".");
|
||||||
}
|
}
|
||||||
if (!button.isVisible()) {
|
if (!runSwing(() -> button.isShowing())) {
|
||||||
throw new AssertionError("Button " + buttonName + " is not showing.");
|
throw new AssertionError("Button " + buttonName + " is not showing.");
|
||||||
}
|
}
|
||||||
if (!button.isEnabled()) {
|
if (!runSwing(() -> button.isEnabled())) {
|
||||||
throw new AssertionError("Button " + buttonName + " is not enabled.");
|
throw new AssertionError("Button " + buttonName + " is not enabled.");
|
||||||
}
|
}
|
||||||
pressButton(button, waitForCompletion);
|
pressButton(button, waitForCompletion);
|
||||||
|
|
|
@ -73,11 +73,11 @@ public class SkeletonLoader extends AbstractLibrarySupportLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options) {
|
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
|
||||||
|
|
||||||
// TODO: If this loader has custom options, validate them here. Not all options require
|
// TODO: If this loader has custom options, validate them here. Not all options require
|
||||||
// validation.
|
// validation.
|
||||||
|
|
||||||
return super.validateOptions(provider, loadSpec, options);
|
return super.validateOptions(provider, loadSpec, options, program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue