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 { 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; private final int segment;
/** /**
* Constructor for SegmentedAddress. * Constructor for SegmentedAddress.
* Offset is not validated against address space. * Offset is not validated against address space.
* @param addrSpace address space for this address * @param addrSpace is the address space for this address
* @param offset offset into the space * @param flat is the flat offset into the space
*/ */
SegmentedAddress(long offset, SegmentedAddressSpace addrSpace) { SegmentedAddress(long flat, SegmentedAddressSpace addrSpace) {
super(adjustOffset(offset), addrSpace); super(adjustOffset(flat, addrSpace), addrSpace);
this.addrSpace = addrSpace; segment = addrSpace.getSegmentFromFlat(flat);
if (offset > 0xFFFFF) {
this.segment = 0xFFFF;
} else {
this.segment = (int) ((offset >> 4) & 0xf000);
}
} }
/** /**
* Constructor for SegmentedAddress. * Constructor for SegmentedAddress.
* @param addrSpace address space for this address * @param addrSpace is the address space for this address
* @param segmentOffset offset into the segment * @param segment is the segment number
* @param overlayId overlay number * @param segmentOffset is the offset into the segment
* @param segment segment number * @throws AddressOutOfBoundsException if the address does not fit in the space
*/ */
SegmentedAddress(SegmentedAddressSpace addrSpace, int segment, int segmentOffset) SegmentedAddress(SegmentedAddressSpace addrSpace, int segment, int segmentOffset)
throws AddressOutOfBoundsException { throws AddressOutOfBoundsException {
super(addrSpace, (segment << 4) + segmentOffset); super(addrSpace, addrSpace.getFlatOffset(segment, segmentOffset));
this.addrSpace = addrSpace; this.segment = segment;
if (offset > 0xFFFFF) {
this.segment = 0xFFFF;
} else {
this.segment = segment;
}
} }
/** /**
* Constructor for SegmentedAddress. * Constructor for SegmentedAddress.
* @param addrSpace address space for this address * @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 { throws AddressOutOfBoundsException {
super(addrSpace, adjustOffset(offset)); super(addrSpace, adjustOffset(flat, addrSpace));
this.addrSpace = addrSpace; segment = addrSpace.getSegmentFromFlat(flat);
if (offset > 0xFFFFF) {
this.segment = 0xFFFF;
} else {
this.segment = (int) ((offset >> 4) & 0xf000);
}
} }
private static long adjustOffset(long offset) { private static long adjustOffset(long flat, SegmentedAddressSpace addrSpace) {
// Decompiler treats segmented space as a 32-bit space and may produce an address offset int seg = addrSpace.getSegmentFromFlat(flat);
// of 0xffffffff for a first use offset (= 0 minus 1). long offset = addrSpace.getOffsetFromFlat(flat);
if (offset == 0x0ffffffffL) { return addrSpace.getFlatOffset(seg, offset);
offset = 0x0fffffL;
}
return offset;
} }
/** /**
@ -97,25 +75,24 @@ public class SegmentedAddress extends GenericAddress {
/** /**
* Returns the offset within the segment. * Returns the offset within the segment.
* @return the offset value
*/ */
public int getSegmentOffset() { 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 * Returns a new address that is equivalent to this address using
* the given segment number. * the given segment number.
* @param seg the seqment value to normalize to. * @param seg the seqment value to normalize to.
* @return the new address
*/ */
public SegmentedAddress normalize(int seg) { public SegmentedAddress normalize(int seg) {
if ((seg << 4) > offset) { SegmentedAddress res = ((SegmentedAddressSpace) addrSpace).getAddressInSegment(offset, seg);
if (res == null) {
return this; return this;
} }
int off = (int) (offset - (seg << 4)); return res;
if (off > 0xffff) {
return this;
}
return new SegmentedAddress(addrSpace, seg, off);
} }
/** /**
@ -124,8 +101,12 @@ public class SegmentedAddress extends GenericAddress {
*/ */
@Override @Override
public Address getNewAddress(long byteOffset) { public Address getNewAddress(long byteOffset) {
SegmentedAddress segAddr = addrSpace.getAddress(byteOffset); SegmentedAddress res =
return segAddr.normalize(segment); ((SegmentedAddressSpace) addrSpace).getAddressInSegment(byteOffset, segment);
if (res == null) {
return this;
}
return res;
} }
@Override @Override
@ -174,33 +155,4 @@ public class SegmentedAddress extends GenericAddress {
} }
return addr; 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 SIZE = 21;
//private final static int SEGMENT_OFFSET_MASK = 0xffff;
//final static long MASK = (1L << SIZE) - 1;
/** /**
* Constructs a new Segmented AddressSpace. * Constructs a new Segmented AddressSpace.
* * @param name is the name of the space
* @param name * @param unique is the unique id for the space.
* the name of the space
* @param unique
* the unique id for the space.
*/ */
public SegmentedAddressSpace(String name, int unique) { public SegmentedAddressSpace(String name, int unique) {
super(name, SIZE, TYPE_RAM, unique); super(name, SIZE, TYPE_RAM, unique);
@ -44,6 +38,65 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
maxAddress = getUncheckedAddress(maxOffset); 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) * @see ghidra.program.model.address.AddressSpace#getAddress(java.lang.String)
@ -98,62 +151,16 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
long off = addr.getOffset() - displacement; long off = addr.getOffset() - displacement;
if (off >= 0) { if (off >= 0) {
SegmentedAddress saddr = (SegmentedAddress) addr; 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( throw new AddressOutOfBoundsException(
"Address Overflow in subtract: " + addr + " + " + displacement); "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, * @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 & MASK) == off) {
if (off >= 0 && off <= maxOffset) { if (off >= 0 && off <= maxOffset) {
SegmentedAddress saddr = (SegmentedAddress) addr; 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( throw new AddressOutOfBoundsException(
"Address Overflow in add: " + addr + " + " + displacement); "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) { private long parseString(String addr) {
if (addr.startsWith("0x") || addr.startsWith("0X")) { if (addr.startsWith("0x") || addr.startsWith("0X")) {
return NumericUtilities.parseHexLong(addr.substring(2)); return NumericUtilities.parseHexLong(addr.substring(2));
} }
return NumericUtilities.parseHexLong(addr); return NumericUtilities.parseHexLong(addr);
} }
private SegmentedAddress parseNonSegmented(String offStr) throws AddressFormatException { private SegmentedAddress parseNonSegmented(String offStr) throws AddressFormatException {
try { try {
long off = (int) parseString(offStr); 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); return new SegmentedAddress(this, off);
} }
catch (NumberFormatException e) { catch (NumberFormatException e) {
throw new AddressFormatException("Cannot parse (" + offStr + ") as a number."); throw new AddressFormatException("Cannot parse (" + offStr + ") as a number.");
} }
catch (AddressOutOfBoundsException e) {
throw new AddressFormatException(e.getMessage());
}
} }
private SegmentedAddress parseSegmented(String segStr, String offStr) private SegmentedAddress parseSegmented(String segStr, String offStr)
throws AddressFormatException { throws AddressFormatException {
int seg = -1; int seg = -1;
int off = -1;
try { try {
seg = (int) parseString(segStr); seg = (int) parseString(segStr);
off = (int) parseString(offStr);
} }
catch (NumberFormatException e) { catch (NumberFormatException e) {
return null; throw new AddressFormatException(
} "Cannot parse (" + segStr + ':' + offStr + ") as a number.");
if (seg < 0 || seg > 0xffff) {
throw new AddressFormatException("Segment is outside the range 0 to 0xffff");
} }
try { try {
int off = (int) parseString(offStr); return getAddress(seg, off);
if (off < 0 || off > 0xffff) {
throw new AddressFormatException("Offset is outside the range 0 to 0xffff");
}
return new SegmentedAddress(this, seg, off);
} }
catch (AddressOutOfBoundsException e) { catch (AddressOutOfBoundsException e) {
throw new AddressFormatException(e.getMessage()); 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) { if (segmentOffset > 0xffff) {
throw new AddressOutOfBoundsException("Offset is too large."); throw new AddressOutOfBoundsException("Offset is too large.");
} }
if ((segment << 4) + segmentOffset > maxOffset) { if (segment > 0xffff) {
throw new AddressOutOfBoundsException("Segmented address is too large."); throw new AddressOutOfBoundsException("Segment is too large.");
} }
return new SegmentedAddress(this, segment, segmentOffset); return new SegmentedAddress(this, segment, segmentOffset);
} }