diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddress.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddress.java index f4590110a8..69f5e65cb0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddress.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddress.java @@ -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 { - this.segment = segment; - } + 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); - } - */ - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddressSpace.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddressSpace.java index 4beccba018..cba303b183 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddressSpace.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/SegmentedAddressSpace.java @@ -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); }