mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-29 15:41:45 +00:00
GP-2133 added support for byte-mapped and overlay blocks to pspec
This commit is contained in:
parent
47cda95669
commit
418925edeb
@ -33,6 +33,7 @@ import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.InvalidAddressException;
|
||||
import ghidra.program.model.mem.MemoryConflictException;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressLabelInfo;
|
||||
@ -335,10 +336,11 @@ public abstract class AbstractProgramLoader implements Loader {
|
||||
blockDef);
|
||||
log.appendMsg(" >> " + e.getMessage());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
catch (InvalidAddressException e) {
|
||||
log.appendMsg(
|
||||
"Failed to add language defined memory block due to name conflict " +
|
||||
"Failed to add language defined memory block due to invalid address: " +
|
||||
blockDef);
|
||||
log.appendMsg(" >> Processor specification error (pspec): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,8 @@ public class DataTypesXmlMgr {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processStructure(XmlTreeNode root, boolean firstPass) {
|
||||
private boolean processStructure(XmlTreeNode root, boolean firstPass)
|
||||
throws XmlAttributeException {
|
||||
XmlElement element = root.getStartElement();
|
||||
String name = element.getAttribute("NAME");
|
||||
CategoryPath path = getCategoryPath(element);
|
||||
|
@ -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.
|
||||
@ -153,7 +152,7 @@ public class XmlParserElement {
|
||||
* @return the boolean value of the specified attribute
|
||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
||||
*/
|
||||
public boolean getAttrValueAsBool(String attrName) {
|
||||
public boolean getAttrValueAsBool(String attrName) throws XmlAttributeException {
|
||||
String val = getAttrValue(attrName);
|
||||
if (val == null) {
|
||||
throw new XmlAttributeException("Element: "+name+": attribute "+attrName+" does not exist.");
|
||||
@ -171,7 +170,7 @@ public class XmlParserElement {
|
||||
* @return the integer value of the specified attribute
|
||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
||||
*/
|
||||
public int getAttrValueAsInt(String attrName) {
|
||||
public int getAttrValueAsInt(String attrName) throws XmlAttributeException {
|
||||
try {
|
||||
String intStr = getAttrValue(attrName);
|
||||
return XmlUtilities.parseInt(intStr);
|
||||
@ -189,7 +188,7 @@ public class XmlParserElement {
|
||||
* @return the long value of the specified attribute
|
||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
||||
*/
|
||||
public long getAttrValueAsLong(String attrName) {
|
||||
public long getAttrValueAsLong(String attrName) throws XmlAttributeException {
|
||||
try {
|
||||
String longStr = getAttrValue(attrName);
|
||||
boolean isNegative = longStr.startsWith("-");
|
||||
@ -220,7 +219,7 @@ public class XmlParserElement {
|
||||
* @return the double value of the specified attribute
|
||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
||||
*/
|
||||
public double getAttrValueAsDouble(String attrName) {
|
||||
public double getAttrValueAsDouble(String attrName) throws XmlAttributeException {
|
||||
try {
|
||||
return Double.parseDouble(getAttrValue(attrName));
|
||||
}
|
||||
|
@ -569,7 +569,7 @@ public class XmlUtilities {
|
||||
* @throws XmlAttributeException if the string in not one of y,n,true,false
|
||||
* or null.
|
||||
*/
|
||||
public static boolean parseBoolean(String boolStr) {
|
||||
public static boolean parseBoolean(String boolStr) throws XmlAttributeException {
|
||||
if (boolStr == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -146,13 +146,26 @@
|
||||
<element name="memory_block">
|
||||
<attribute name="name"/>
|
||||
<attribute name="start_address"/>
|
||||
<optional> <attribute name="bit_mapped_address"/> </optional>
|
||||
<optional> <attribute name="mode"/> </optional>
|
||||
<optional> <attribute name="length"/> </optional>
|
||||
<optional>
|
||||
<attribute name="length"/>
|
||||
<choice>
|
||||
<attribute name="bit_mapped_address"/>
|
||||
<!--
|
||||
byte_mapped_address - mapped memory address and optional mapping ratio
|
||||
Examples:
|
||||
byte_mapped_address="rom:1000" - maps every byte starting at rom:1000
|
||||
byte_mapped_address="rom:1000/1:2" - maps one byte for every two bytes
|
||||
starting at rom:1000. Facilitates skip of padding bytes.
|
||||
-->
|
||||
<attribute name="byte_mapped_address"/>
|
||||
<attribute name="initialized">
|
||||
<ref name="boolean_type"/>
|
||||
</attribute>
|
||||
</choice>
|
||||
<optional> <attribute name="mode"/> </optional>
|
||||
<optional>
|
||||
<attribute name="overlay">
|
||||
<ref name="boolean_type"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</element>
|
||||
</oneOrMore>
|
||||
|
@ -16,12 +16,13 @@
|
||||
package ghidra.app.plugin.processors.generic;
|
||||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
import ghidra.program.database.mem.ByteMappingScheme;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.util.XmlProgramUtilities;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.XmlAttributeException;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
@ -39,23 +40,68 @@ public class MemoryBlockDefinition {
|
||||
private String addressString;
|
||||
private int length;
|
||||
private boolean initialized;
|
||||
private boolean overlay;
|
||||
private String bitMappedAddress;
|
||||
private String byteMappedAddress;
|
||||
private ByteMappingScheme byteMappingScheme;
|
||||
private boolean readPermission = true;
|
||||
private boolean writePermission = true;
|
||||
private boolean executePermission = false;
|
||||
private boolean volatilePermission = false;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return blockName + " @ " + addressString + ", length=0x" + Integer.toHexString(length);
|
||||
}
|
||||
|
||||
public MemoryBlockDefinition(String blockName, String addressString, String bitMappedAddress,
|
||||
String mode, String lengthString, String initializedString)
|
||||
/**
|
||||
* Construct <code>MemoryBlockDefinition</code> using a text-based specified.
|
||||
* Intended for use when parsing XML.
|
||||
* @param blockName memory block name (required)
|
||||
* @param addressString start of memory block (required, see {@link AddressFactory#getAddress(String)}).
|
||||
* @param bitMappedAddress optional specification of data source address for bit-mapped memory
|
||||
* block (may be null)
|
||||
* @param byteMappedAddressRatio optional specification of data source address for byte-mapped
|
||||
* memory block which may include optional byte mapping ratio, e.g., "rom:1000/2:4" (may be
|
||||
* null). The default mapping ratio is 1-byte to 1-source-byte (1:1), although other
|
||||
* decimations may be specified using a mapping ratio. When specifying a mapping ratio both
|
||||
* values must be in the range 1..127 where the right (source-byte count) value must be
|
||||
* greater-than-or-equal to the left value (e.g., 2:4).
|
||||
* @param mode block mode as concatenation of the following mode indicator characters:
|
||||
* <pre>
|
||||
* r - read mode enabled
|
||||
* w - write mode enabled
|
||||
* x - execute mode enabled
|
||||
* v - volatile mode enabled
|
||||
* </pre>
|
||||
* @param lengthString length of memory block in bytes (required)
|
||||
* @param initializedString boolean (y | n | true | false) indicating if memory block is
|
||||
* initialialized or not (must be null for mapped block specification)
|
||||
* @param overlayString boolean (y | n | true | false) indicating if memory block is an overlay
|
||||
* (false assumed if null).
|
||||
* @throws XmlAttributeException if parse failure occurs (NOTE: address parsing is not performed)
|
||||
*/
|
||||
private MemoryBlockDefinition(String blockName, String addressString, String bitMappedAddress,
|
||||
String byteMappedAddressRatio, String mode, String lengthString,
|
||||
String initializedString, String overlayString)
|
||||
throws XmlAttributeException {
|
||||
|
||||
this.blockName = blockName;
|
||||
this.addressString = addressString;
|
||||
this.bitMappedAddress = bitMappedAddress;
|
||||
|
||||
if (byteMappedAddressRatio != null) {
|
||||
if (bitMappedAddress != null) {
|
||||
throw new XmlAttributeException(
|
||||
"may not specify both bit_mapped_address and byte_mapped_address");
|
||||
}
|
||||
int index = byteMappedAddressRatio.indexOf('/');
|
||||
if (index > 0) {
|
||||
byteMappingScheme =
|
||||
new ByteMappingScheme(byteMappedAddressRatio.substring(index + 1));
|
||||
byteMappedAddress = byteMappedAddressRatio.substring(0, index);
|
||||
}
|
||||
else {
|
||||
// 1:1 mapping scheme assumed (null byteMappingScheme)
|
||||
byteMappedAddress = byteMappedAddressRatio;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != null) {
|
||||
mode = mode.toLowerCase();
|
||||
readPermission = mode.indexOf('r') >= 0;
|
||||
@ -69,42 +115,73 @@ public class MemoryBlockDefinition {
|
||||
catch (NumberFormatException e) {
|
||||
throw new XmlAttributeException(lengthString + " is not a valid integer");
|
||||
}
|
||||
initialized = XmlUtilities.parseBoolean(initializedString);
|
||||
if (initializedString != null) {
|
||||
if (bitMappedAddress != null || byteMappedAddress != null) {
|
||||
throw new XmlAttributeException(
|
||||
"mapped block specifications must not specify initialized attribute");
|
||||
}
|
||||
initialized = XmlUtilities.parseBoolean(initializedString);
|
||||
}
|
||||
overlay = XmlUtilities.parseBoolean(overlayString);
|
||||
}
|
||||
|
||||
public MemoryBlockDefinition(XmlElement element) {
|
||||
public MemoryBlockDefinition(XmlElement element) throws XmlAttributeException {
|
||||
this(element.getAttribute("name"), element.getAttribute("start_address"),
|
||||
element.getAttribute("bit_mapped_address"), element.getAttribute("mode"),
|
||||
element.getAttribute("length"), element.getAttribute("initialized"));
|
||||
element.getAttribute("bit_mapped_address"), element.getAttribute("byte_mapped_address"),
|
||||
element.getAttribute("mode"), element.getAttribute("length"),
|
||||
element.getAttribute("initialized"), element.getAttribute("overlay"));
|
||||
}
|
||||
|
||||
private static Address parseAddress(String addressString, Program program, String description)
|
||||
throws InvalidAddressException {
|
||||
Address addr = XmlProgramUtilities.parseAddress(program.getAddressFactory(), addressString);
|
||||
if (addr == null) {
|
||||
throw new InvalidAddressException(
|
||||
"Invalid " + description + " in memory block definition: " + addressString);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create memory block within specified program based upon this block specification.
|
||||
* @param program target program
|
||||
* @throws LockException if program does not have exclusive access required when adding memory blocks.
|
||||
* @throws MemoryConflictException if this specification conflicts with an existing memory block in program
|
||||
* @throws AddressOverflowException if memory space constraints are violated by block specification
|
||||
* @throws InvalidAddressException if address defined by this block specification is invalid
|
||||
* for the specified program. May also indicate an improperly formatted address attribute.
|
||||
*/
|
||||
public void createBlock(Program program) throws LockException, MemoryConflictException,
|
||||
AddressOverflowException, DuplicateNameException {
|
||||
AddressOverflowException, InvalidAddressException {
|
||||
if (blockName == null || addressString == null || length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Memory mem = program.getMemory();
|
||||
Address addr = XmlProgramUtilities.parseAddress(program.getAddressFactory(), addressString);
|
||||
Address addr = parseAddress(addressString, program, "block address");
|
||||
|
||||
MemoryBlock block;
|
||||
if (bitMappedAddress != null) {
|
||||
Address mappedAddr =
|
||||
XmlProgramUtilities.parseAddress(program.getAddressFactory(), bitMappedAddress);
|
||||
block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length, false);
|
||||
Address mappedAddr = parseAddress(bitMappedAddress, program, "bit-mapped address");
|
||||
block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length, overlay);
|
||||
}
|
||||
else if (byteMappedAddress != null) {
|
||||
Address mappedAddr = parseAddress(byteMappedAddress, program, "byte-mapped address");
|
||||
block = mem.createByteMappedBlock(blockName, addr, mappedAddr, length,
|
||||
byteMappingScheme, overlay);
|
||||
}
|
||||
else if (initialized) {
|
||||
try {
|
||||
block =
|
||||
mem.createInitializedBlock(blockName, addr, length, (byte) 0,
|
||||
TaskMonitor.DUMMY, false);
|
||||
TaskMonitor.DUMMY, overlay);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
throw new AssertException(e); // unexpected
|
||||
}
|
||||
}
|
||||
else {
|
||||
block = mem.createUninitializedBlock(blockName, addr, length, false);
|
||||
block = mem.createUninitializedBlock(blockName, addr, length, overlay);
|
||||
}
|
||||
block.setRead(readPermission);
|
||||
block.setWrite(writePermission);
|
||||
@ -112,4 +189,36 @@ public class MemoryBlockDefinition {
|
||||
block.setVolatile(volatilePermission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(blockName);
|
||||
buf.append(':');
|
||||
if (overlay) {
|
||||
buf.append("overlay");
|
||||
}
|
||||
buf.append(" start_address=");
|
||||
buf.append(addressString);
|
||||
if (initialized) {
|
||||
buf.append(", initialized ");
|
||||
}
|
||||
else if (bitMappedAddress != null) {
|
||||
buf.append(", bit_mapped_address=");
|
||||
buf.append(bitMappedAddress);
|
||||
}
|
||||
else if (byteMappedAddress != null) {
|
||||
buf.append(", byte_mapped_address=");
|
||||
buf.append(byteMappedAddress);
|
||||
if (byteMappingScheme != null) {
|
||||
buf.append('/');
|
||||
buf.append(byteMappingScheme.toString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf.append(", uninitialized");
|
||||
}
|
||||
buf.append(", length=0x");
|
||||
buf.append(Integer.toHexString(length));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,6 +69,34 @@ public class ByteMappingScheme {
|
||||
this.nonMappedByteCount = mappedSourceByteCount - mappedByteCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct byte mapping scheme specified as a ratio of mapped bytes to source bytes.
|
||||
* The two integer values in the range 1..127 are seperated by a ':' character. The number of
|
||||
* mapped bytes must be less-than or equal to the number of source bytes.
|
||||
* @param mappingScheme mapping scheme in string form (e.g., "2:4").
|
||||
* @throws IllegalArgumentException if invalid mapping scheme specified
|
||||
*/
|
||||
public ByteMappingScheme(String mappingScheme) {
|
||||
|
||||
int index = mappingScheme.indexOf(':');
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException("invalid mapping scheme: " + mappingScheme);
|
||||
}
|
||||
String mappedByteCountStr = mappingScheme.substring(0, index);
|
||||
String sourceByteCountStr = mappingScheme.substring(index + 1);
|
||||
|
||||
try {
|
||||
mappedByteCount = Integer.parseInt(mappedByteCountStr);
|
||||
mappedSourceByteCount = Integer.parseInt(sourceByteCountStr);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("invalid mapping scheme: " + mappingScheme);
|
||||
}
|
||||
|
||||
validateMappingScheme(mappedByteCount, mappedSourceByteCount);
|
||||
this.nonMappedByteCount = mappedSourceByteCount - mappedByteCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String ratioStr = "1:1";
|
||||
|
@ -0,0 +1,42 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.mem;
|
||||
|
||||
import ghidra.util.exception.UsrException;
|
||||
|
||||
/**
|
||||
* Exception for invalid address either due to improper format
|
||||
* or address not defined within target
|
||||
*/
|
||||
public class InvalidAddressException extends UsrException {
|
||||
|
||||
/**
|
||||
* Constructs a new InvalidAddressException
|
||||
*/
|
||||
public InvalidAddressException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new InvalidAddressException with a detailed message.
|
||||
*
|
||||
* @param msg detailed message
|
||||
*/
|
||||
public InvalidAddressException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user