mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-2133 added support for byte-mapped and overlay blocks to pspec
This commit is contained in:
parent
47cda95669
commit
418925edeb
8 changed files with 228 additions and 34 deletions
|
@ -33,6 +33,7 @@ import ghidra.program.database.function.OverlappingFunctionException;
|
||||||
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.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.mem.InvalidAddressException;
|
||||||
import ghidra.program.model.mem.MemoryConflictException;
|
import ghidra.program.model.mem.MemoryConflictException;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.util.AddressLabelInfo;
|
import ghidra.program.model.util.AddressLabelInfo;
|
||||||
|
@ -335,10 +336,11 @@ public abstract class AbstractProgramLoader implements Loader {
|
||||||
blockDef);
|
blockDef);
|
||||||
log.appendMsg(" >> " + e.getMessage());
|
log.appendMsg(" >> " + e.getMessage());
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException e) {
|
catch (InvalidAddressException e) {
|
||||||
log.appendMsg(
|
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);
|
blockDef);
|
||||||
|
log.appendMsg(" >> Processor specification error (pspec): " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,7 +295,8 @@ public class DataTypesXmlMgr {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean processStructure(XmlTreeNode root, boolean firstPass) {
|
private boolean processStructure(XmlTreeNode root, boolean firstPass)
|
||||||
|
throws XmlAttributeException {
|
||||||
XmlElement element = root.getStartElement();
|
XmlElement element = root.getStartElement();
|
||||||
String name = element.getAttribute("NAME");
|
String name = element.getAttribute("NAME");
|
||||||
CategoryPath path = getCategoryPath(element);
|
CategoryPath path = getCategoryPath(element);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* @return the boolean value of the specified attribute
|
||||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
* @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);
|
String val = getAttrValue(attrName);
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
throw new XmlAttributeException("Element: "+name+": attribute "+attrName+" does not exist.");
|
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
|
* @return the integer value of the specified attribute
|
||||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
* @throws XmlAttributeException if no attribute exists with the specified name
|
||||||
*/
|
*/
|
||||||
public int getAttrValueAsInt(String attrName) {
|
public int getAttrValueAsInt(String attrName) throws XmlAttributeException {
|
||||||
try {
|
try {
|
||||||
String intStr = getAttrValue(attrName);
|
String intStr = getAttrValue(attrName);
|
||||||
return XmlUtilities.parseInt(intStr);
|
return XmlUtilities.parseInt(intStr);
|
||||||
|
@ -189,7 +188,7 @@ public class XmlParserElement {
|
||||||
* @return the long value of the specified attribute
|
* @return the long value of the specified attribute
|
||||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
* @throws XmlAttributeException if no attribute exists with the specified name
|
||||||
*/
|
*/
|
||||||
public long getAttrValueAsLong(String attrName) {
|
public long getAttrValueAsLong(String attrName) throws XmlAttributeException {
|
||||||
try {
|
try {
|
||||||
String longStr = getAttrValue(attrName);
|
String longStr = getAttrValue(attrName);
|
||||||
boolean isNegative = longStr.startsWith("-");
|
boolean isNegative = longStr.startsWith("-");
|
||||||
|
@ -220,7 +219,7 @@ public class XmlParserElement {
|
||||||
* @return the double value of the specified attribute
|
* @return the double value of the specified attribute
|
||||||
* @throws XmlAttributeException if no attribute exists with the specified name
|
* @throws XmlAttributeException if no attribute exists with the specified name
|
||||||
*/
|
*/
|
||||||
public double getAttrValueAsDouble(String attrName) {
|
public double getAttrValueAsDouble(String attrName) throws XmlAttributeException {
|
||||||
try {
|
try {
|
||||||
return Double.parseDouble(getAttrValue(attrName));
|
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
|
* @throws XmlAttributeException if the string in not one of y,n,true,false
|
||||||
* or null.
|
* or null.
|
||||||
*/
|
*/
|
||||||
public static boolean parseBoolean(String boolStr) {
|
public static boolean parseBoolean(String boolStr) throws XmlAttributeException {
|
||||||
if (boolStr == null) {
|
if (boolStr == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,13 +146,26 @@
|
||||||
<element name="memory_block">
|
<element name="memory_block">
|
||||||
<attribute name="name"/>
|
<attribute name="name"/>
|
||||||
<attribute name="start_address"/>
|
<attribute name="start_address"/>
|
||||||
<optional> <attribute name="bit_mapped_address"/> </optional>
|
<attribute name="length"/>
|
||||||
<optional> <attribute name="mode"/> </optional>
|
<choice>
|
||||||
<optional> <attribute name="length"/> </optional>
|
<attribute name="bit_mapped_address"/>
|
||||||
<optional>
|
<!--
|
||||||
|
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">
|
<attribute name="initialized">
|
||||||
<ref name="boolean_type"/>
|
<ref name="boolean_type"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
</choice>
|
||||||
|
<optional> <attribute name="mode"/> </optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="overlay">
|
||||||
|
<ref name="boolean_type"/>
|
||||||
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
</element>
|
</element>
|
||||||
</oneOrMore>
|
</oneOrMore>
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
package ghidra.app.plugin.processors.generic;
|
package ghidra.app.plugin.processors.generic;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.database.mem.ByteMappingScheme;
|
||||||
import ghidra.program.model.address.AddressOverflowException;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.util.XmlProgramUtilities;
|
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.task.TaskMonitor;
|
||||||
import ghidra.util.xml.XmlAttributeException;
|
import ghidra.util.xml.XmlAttributeException;
|
||||||
import ghidra.util.xml.XmlUtilities;
|
import ghidra.util.xml.XmlUtilities;
|
||||||
|
@ -39,23 +40,68 @@ public class MemoryBlockDefinition {
|
||||||
private String addressString;
|
private String addressString;
|
||||||
private int length;
|
private int length;
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
|
private boolean overlay;
|
||||||
private String bitMappedAddress;
|
private String bitMappedAddress;
|
||||||
|
private String byteMappedAddress;
|
||||||
|
private ByteMappingScheme byteMappingScheme;
|
||||||
private boolean readPermission = true;
|
private boolean readPermission = true;
|
||||||
private boolean writePermission = true;
|
private boolean writePermission = true;
|
||||||
private boolean executePermission = false;
|
private boolean executePermission = false;
|
||||||
private boolean volatilePermission = false;
|
private boolean volatilePermission = false;
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public String toString() {
|
* Construct <code>MemoryBlockDefinition</code> using a text-based specified.
|
||||||
return blockName + " @ " + addressString + ", length=0x" + Integer.toHexString(length);
|
* Intended for use when parsing XML.
|
||||||
}
|
* @param blockName memory block name (required)
|
||||||
|
* @param addressString start of memory block (required, see {@link AddressFactory#getAddress(String)}).
|
||||||
public MemoryBlockDefinition(String blockName, String addressString, String bitMappedAddress,
|
* @param bitMappedAddress optional specification of data source address for bit-mapped memory
|
||||||
String mode, String lengthString, String initializedString)
|
* 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 {
|
throws XmlAttributeException {
|
||||||
|
|
||||||
this.blockName = blockName;
|
this.blockName = blockName;
|
||||||
this.addressString = addressString;
|
this.addressString = addressString;
|
||||||
this.bitMappedAddress = bitMappedAddress;
|
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) {
|
if (mode != null) {
|
||||||
mode = mode.toLowerCase();
|
mode = mode.toLowerCase();
|
||||||
readPermission = mode.indexOf('r') >= 0;
|
readPermission = mode.indexOf('r') >= 0;
|
||||||
|
@ -69,42 +115,73 @@ public class MemoryBlockDefinition {
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
throw new XmlAttributeException(lengthString + " is not a valid integer");
|
throw new XmlAttributeException(lengthString + " is not a valid integer");
|
||||||
}
|
}
|
||||||
|
if (initializedString != null) {
|
||||||
|
if (bitMappedAddress != null || byteMappedAddress != null) {
|
||||||
|
throw new XmlAttributeException(
|
||||||
|
"mapped block specifications must not specify initialized attribute");
|
||||||
|
}
|
||||||
initialized = XmlUtilities.parseBoolean(initializedString);
|
initialized = XmlUtilities.parseBoolean(initializedString);
|
||||||
}
|
}
|
||||||
|
overlay = XmlUtilities.parseBoolean(overlayString);
|
||||||
public MemoryBlockDefinition(XmlElement element) {
|
|
||||||
this(element.getAttribute("name"), element.getAttribute("start_address"),
|
|
||||||
element.getAttribute("bit_mapped_address"), element.getAttribute("mode"),
|
|
||||||
element.getAttribute("length"), element.getAttribute("initialized"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MemoryBlockDefinition(XmlElement element) throws XmlAttributeException {
|
||||||
|
this(element.getAttribute("name"), element.getAttribute("start_address"),
|
||||||
|
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,
|
public void createBlock(Program program) throws LockException, MemoryConflictException,
|
||||||
AddressOverflowException, DuplicateNameException {
|
AddressOverflowException, InvalidAddressException {
|
||||||
if (blockName == null || addressString == null || length <= 0) {
|
if (blockName == null || addressString == null || length <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory mem = program.getMemory();
|
Memory mem = program.getMemory();
|
||||||
Address addr = XmlProgramUtilities.parseAddress(program.getAddressFactory(), addressString);
|
Address addr = parseAddress(addressString, program, "block address");
|
||||||
|
|
||||||
MemoryBlock block;
|
MemoryBlock block;
|
||||||
if (bitMappedAddress != null) {
|
if (bitMappedAddress != null) {
|
||||||
Address mappedAddr =
|
Address mappedAddr = parseAddress(bitMappedAddress, program, "bit-mapped address");
|
||||||
XmlProgramUtilities.parseAddress(program.getAddressFactory(), bitMappedAddress);
|
block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length, overlay);
|
||||||
block = mem.createBitMappedBlock(blockName, addr, mappedAddr, length, false);
|
}
|
||||||
|
else if (byteMappedAddress != null) {
|
||||||
|
Address mappedAddr = parseAddress(byteMappedAddress, program, "byte-mapped address");
|
||||||
|
block = mem.createByteMappedBlock(blockName, addr, mappedAddr, length,
|
||||||
|
byteMappingScheme, overlay);
|
||||||
}
|
}
|
||||||
else if (initialized) {
|
else if (initialized) {
|
||||||
try {
|
try {
|
||||||
block =
|
block =
|
||||||
mem.createInitializedBlock(blockName, addr, length, (byte) 0,
|
mem.createInitializedBlock(blockName, addr, length, (byte) 0,
|
||||||
TaskMonitor.DUMMY, false);
|
TaskMonitor.DUMMY, overlay);
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
throw new AssertException(e); // unexpected
|
throw new AssertException(e); // unexpected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
block = mem.createUninitializedBlock(blockName, addr, length, false);
|
block = mem.createUninitializedBlock(blockName, addr, length, overlay);
|
||||||
}
|
}
|
||||||
block.setRead(readPermission);
|
block.setRead(readPermission);
|
||||||
block.setWrite(writePermission);
|
block.setWrite(writePermission);
|
||||||
|
@ -112,4 +189,36 @@ public class MemoryBlockDefinition {
|
||||||
block.setVolatile(volatilePermission);
|
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;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String ratioStr = "1:1";
|
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…
Add table
Add a link
Reference in a new issue