Refactor SegmentedAddress preparing for protected mode

This commit is contained in:
caheckman 2019-08-21 13:32:05 -04:00
parent 90f832bf1d
commit cabe66e282
2 changed files with 113 additions and 208 deletions

View File

@ -21,70 +21,48 @@ package ghidra.program.model.address;
*/
public class SegmentedAddress extends GenericAddress {
private static final long serialVersionUID = 0;
public static final int OFFSET_SIZE = 16;
public static final int SEGMENT_SIZE = 16;
private final SegmentedAddressSpace addrSpace;
private final int segment;
/**
* Constructor for SegmentedAddress.
* Offset is not validated against address space.
* @param addrSpace address space for this address
* @param offset offset into the space
* @param addrSpace is the address space for this address
* @param flat is the flat offset into the space
*/
SegmentedAddress(long offset, SegmentedAddressSpace addrSpace) {
super(adjustOffset(offset), addrSpace);
this.addrSpace = addrSpace;
if (offset > 0xFFFFF) {
this.segment = 0xFFFF;
} else {
this.segment = (int) ((offset >> 4) & 0xf000);
}
SegmentedAddress(long flat, SegmentedAddressSpace addrSpace) {
super(adjustOffset(flat, addrSpace), addrSpace);
segment = addrSpace.getSegmentFromFlat(flat);
}
/**
* Constructor for SegmentedAddress.
* @param addrSpace address space for this address
* @param segmentOffset offset into the segment
* @param overlayId overlay number
* @param segment segment number
* @param addrSpace is the address space for this address
* @param segment is the segment number
* @param segmentOffset is the offset into the segment
* @throws AddressOutOfBoundsException if the address does not fit in the space
*/
SegmentedAddress(SegmentedAddressSpace addrSpace, int segment, int segmentOffset)
throws AddressOutOfBoundsException {
super(addrSpace, (segment << 4) + segmentOffset);
this.addrSpace = addrSpace;
if (offset > 0xFFFFF) {
this.segment = 0xFFFF;
} else {
super(addrSpace, addrSpace.getFlatOffset(segment, segmentOffset));
this.segment = segment;
}
}
/**
* Constructor for SegmentedAddress.
* @param addrSpace address space for this address
* @param offset offset into the space
* @param flat is the flat offset into the space
* @throws AddressOutOfBoundsException if the flat address does not fit in the space
*/
SegmentedAddress(SegmentedAddressSpace addrSpace, long offset)
SegmentedAddress(SegmentedAddressSpace addrSpace, long flat)
throws AddressOutOfBoundsException {
super(addrSpace, adjustOffset(offset));
this.addrSpace = addrSpace;
if (offset > 0xFFFFF) {
this.segment = 0xFFFF;
} else {
this.segment = (int) ((offset >> 4) & 0xf000);
}
super(addrSpace, adjustOffset(flat, addrSpace));
segment = addrSpace.getSegmentFromFlat(flat);
}
private static long adjustOffset(long offset) {
// Decompiler treats segmented space as a 32-bit space and may produce an address offset
// of 0xffffffff for a first use offset (= 0 minus 1).
if (offset == 0x0ffffffffL) {
offset = 0x0fffffL;
}
return offset;
private static long adjustOffset(long flat, SegmentedAddressSpace addrSpace) {
int seg = addrSpace.getSegmentFromFlat(flat);
long offset = addrSpace.getOffsetFromFlat(flat);
return addrSpace.getFlatOffset(seg, offset);
}
/**
@ -97,25 +75,24 @@ public class SegmentedAddress extends GenericAddress {
/**
* Returns the offset within the segment.
* @return the offset value
*/
public int getSegmentOffset() {
return (int) (offset - (segment << 4));
return (int) ((SegmentedAddressSpace) addrSpace).getOffsetFromFlat(offset);
}
/**
* Returns a new address that is equivalent to this address using
* the given segment number.
* @param seg the seqment value to normalize to.
* @return the new address
*/
public SegmentedAddress normalize(int seg) {
if ((seg << 4) > offset) {
SegmentedAddress res = ((SegmentedAddressSpace) addrSpace).getAddressInSegment(offset, seg);
if (res == null) {
return this;
}
int off = (int) (offset - (seg << 4));
if (off > 0xffff) {
return this;
}
return new SegmentedAddress(addrSpace, seg, off);
return res;
}
/**
@ -124,8 +101,12 @@ public class SegmentedAddress extends GenericAddress {
*/
@Override
public Address getNewAddress(long byteOffset) {
SegmentedAddress segAddr = addrSpace.getAddress(byteOffset);
return segAddr.normalize(segment);
SegmentedAddress res =
((SegmentedAddressSpace) addrSpace).getAddressInSegment(byteOffset, segment);
if (res == null) {
return this;
}
return res;
}
@Override
@ -174,33 +155,4 @@ public class SegmentedAddress extends GenericAddress {
}
return addr;
}
/**
* @see ghidra.program.model.address.GenericAddress#next()
*/
/*
@Override
public Address next() {
if ((offset & SegmentedAddressSpace.MASK) == SegmentedAddressSpace.MASK) {
return null;
}
long newOffset = (offset + 1) & SegmentedAddressSpace.MASK;
return new SegmentedAddress(addrSpace, newOffset).normalize(segment);
}
*/
/**
* @see ghidra.program.model.address.GenericAddress#previous()
*/
/*
@Override
public Address previous() {
if ((offset & SegmentedAddressSpace.MASK) == 0) {
return null;
}
long newOffset = (offset - 1) & SegmentedAddressSpace.MASK;
return new SegmentedAddress(addrSpace, newOffset).normalize(segment);
}
*/
}

View File

@ -26,16 +26,10 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
private final static int SIZE = 21;
//private final static int SEGMENT_OFFSET_MASK = 0xffff;
//final static long MASK = (1L << SIZE) - 1;
/**
* Constructs a new Segmented AddressSpace.
*
* @param name
* the name of the space
* @param unique
* the unique id for the space.
* @param name is the name of the space
* @param unique is the unique id for the space.
*/
public SegmentedAddressSpace(String name, int unique) {
super(name, SIZE, TYPE_RAM, unique);
@ -44,6 +38,65 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
maxAddress = getUncheckedAddress(maxOffset);
}
/**
* Given a 16-bit segment and an offset, produce the flat address offset
* @param segment is the segment value
* @param offset is the 16-bit offset into the segment
* @return the encoded flat offset
*/
protected long getFlatOffset(int segment, long offset) {
long res = segment;
res <<= 4;
res += offset;
return res;
}
/**
* Given a flat address offset, extract the 16-bit segment portion
* @param flat is the flat offset
* @return the segment value
*/
protected int getSegmentFromFlat(long flat) {
if (flat > 0xFFFFFL) {
return 0xFFFF;
}
return (int) ((flat >> 4) & 0xF000);
}
/**
* Given a flat address offset, extract the offset portion
* @param flat is the flat offset
* @return the offset value
*/
protected long getOffsetFromFlat(long flat) {
if (flat > 0xFFFFFL) {
return flat - 0xFFFF0;
}
return flat & 0xFFFFL;
}
/**
* Given a flat address offset and a preferred segment, try
* to create an address that maps to the offset and is in the segment. For
* architectures like x86 real-mode, multiple address encodings can map to
* the same flat address offset. This method tries to select between the different
* encodings. If the flat offset cannot be encoded with the preferred segment,
* null is returned.
*
* @param flat is the flat offset
* @param preferredSegment is the 16-bit preferred segment value
* @return the segment encoded address or null
*/
protected SegmentedAddress getAddressInSegment(long flat, int preferredSegment) {
if ((preferredSegment << 4) <= flat) {
int off = (int) (flat - (preferredSegment << 4));
if (off <= 0xffff) {
return new SegmentedAddress(this, preferredSegment, off);
}
}
return null;
}
/**
*
* @see ghidra.program.model.address.AddressSpace#getAddress(java.lang.String)
@ -98,62 +151,16 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
long off = addr.getOffset() - displacement;
if (off >= 0) {
SegmentedAddress saddr = (SegmentedAddress) addr;
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
Address resaddr = getAddressInSegment(off, saddr.getSegment());
if (resaddr == null) { // Could not map into desired segment
resaddr = new SegmentedAddress(this, off); // just use default
}
return resaddr;
}
throw new AddressOutOfBoundsException(
"Address Overflow in subtract: " + addr + " + " + displacement);
}
/**
*
* @see ghidra.program.model.address.AddressSpace#subtractWrap(ghidra.program.model.address.Address,
* long)
*/
/*
@Override
public Address subtractWrap(Address addr, long displacement) {
testAddressSpace(addr);
SegmentedAddress saddr = (SegmentedAddress) addr;
int segOffset = (int) ((saddr.getSegmentOffset() - displacement) & SEGMENT_OFFSET_MASK);
return new SegmentedAddress(this, saddr.getSegment(), segOffset);
}
*/
/**
* @see ghidra.program.model.address.AbstractAddressSpace#subtractWrapSpace(ghidra.program.model.address.Address, long)
*/
/*
@Override
public Address subtractWrapSpace(Address addr, long displacement) {
testAddressSpace(addr);
return new SegmentedAddress(this, (addr.getOffset() - displacement) & MASK);
}
*/
/**
*
* @see ghidra.program.model.address.AddressSpace#subtractNoWrap(ghidra.program.model.address.Address,
* long)
*/
/*
@Override
public Address subtractNoWrap(Address addr, long displacement) throws AddressOverflowException {
testAddressSpace(addr);
SegmentedAddress saddr = (SegmentedAddress) addr;
long off = addr.getOffset() - displacement;
if ((off & MASK) != off) {
throw new AddressOverflowException();
}
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
}
*/
/**
*
* @see ghidra.program.model.address.AddressSpace#add(ghidra.program.model.address.Address,
@ -175,110 +182,56 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
//if ((off & MASK) == off) {
if (off >= 0 && off <= maxOffset) {
SegmentedAddress saddr = (SegmentedAddress) addr;
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
Address resaddr = getAddressInSegment(off, saddr.getSegment());
if (resaddr == null) { // Could not map into desired segment
resaddr = new SegmentedAddress(this, off); // just use default
}
return resaddr;
}
throw new AddressOutOfBoundsException(
"Address Overflow in add: " + addr + " + " + displacement);
}
/**
*
* @see ghidra.program.model.address.AddressSpace#addWrap(ghidra.program.model.address.Address,
* long)
*/
/*
@Override
public Address addWrap(Address addr, long displacement) {
testAddressSpace(addr);
SegmentedAddress saddr = (SegmentedAddress) addr;
int segOffset = (int) ((saddr.getSegmentOffset() + displacement) & SEGMENT_OFFSET_MASK);
return new SegmentedAddress(this, saddr.getSegment(), segOffset);
}
*/
/**
* @see ghidra.program.model.address.AddressSpace#addWrapSpace(ghidra.program.model.address.Address,
* long)
*/
/*
@Override
public Address addWrapSpace(Address addr, long displacement) {
testAddressSpace(addr);
return new SegmentedAddress(this, (addr.getOffset() + displacement) & MASK);
}
*/
/**
*
* @see ghidra.program.model.address.AddressSpace#addNoWrap(ghidra.program.model.address.Address,
* long)
*/
/*
@Override
public Address addNoWrap(Address addr, long displacement) throws AddressOverflowException {
SegmentedAddress saddr = (SegmentedAddress) addr;
testAddressSpace(addr);
long off = addr.getOffset() + displacement;
if ((off & MASK) != off) {
throw new AddressOverflowException();
}
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
}
*/
private long parseString(String addr) {
if (addr.startsWith("0x") || addr.startsWith("0X")) {
return NumericUtilities.parseHexLong(addr.substring(2));
}
return NumericUtilities.parseHexLong(addr);
}
private SegmentedAddress parseNonSegmented(String offStr) throws AddressFormatException {
try {
long off = (int) parseString(offStr);
if (off < 0 || off > 0xfffff) {
throw new AddressFormatException("Offset is outside the range 0 to 0xfffff");
}
return new SegmentedAddress(this, off);
}
catch (NumberFormatException e) {
throw new AddressFormatException("Cannot parse (" + offStr + ") as a number.");
}
catch (AddressOutOfBoundsException e) {
throw new AddressFormatException(e.getMessage());
}
}
private SegmentedAddress parseSegmented(String segStr, String offStr)
throws AddressFormatException {
int seg = -1;
int off = -1;
try {
seg = (int) parseString(segStr);
off = (int) parseString(offStr);
}
catch (NumberFormatException e) {
return null;
}
if (seg < 0 || seg > 0xffff) {
throw new AddressFormatException("Segment is outside the range 0 to 0xffff");
throw new AddressFormatException(
"Cannot parse (" + segStr + ':' + offStr + ") as a number.");
}
try {
int off = (int) parseString(offStr);
if (off < 0 || off > 0xffff) {
throw new AddressFormatException("Offset is outside the range 0 to 0xffff");
}
return new SegmentedAddress(this, seg, off);
return getAddress(seg, off);
}
catch (AddressOutOfBoundsException e) {
throw new AddressFormatException(e.getMessage());
}
catch (NumberFormatException e) {
throw new AddressFormatException("Cannot parse (" + offStr + ") as a number.");
}
}
/**
@ -315,8 +268,8 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
if (segmentOffset > 0xffff) {
throw new AddressOutOfBoundsException("Offset is too large.");
}
if ((segment << 4) + segmentOffset > maxOffset) {
throw new AddressOutOfBoundsException("Segmented address is too large.");
if (segment > 0xffff) {
throw new AddressOutOfBoundsException("Segment is too large.");
}
return new SegmentedAddress(this, segment, segmentOffset);
}