@Override public int compare(LayoutDecision d0, LayoutDecision d1) { /* * Null/undecided values go either at the beginning or end; our client decides which. * Usually if we're searching for a maximum, we want null/undecided to be low, and if * we're searching for a minimum, we want null/undecided to be high. */ int off0 = (d0 == null || !d0.isTaken()) ? undecidedValue : (int) d0.getValue(); int off1 = (d1 == null || !d1.isTaken()) ? undecidedValue : (int) d1.getValue(); return Integer.compare(off0, off1); } }
public Object getDecidedValue(LayoutDecision.Kind key) { return getDecision(key).getValue(); }
public void putDecidedValues(LayoutDecisionMap copyingIn) { assert !copyingIn.getDecisions().stream().filter(d -> d.getValue() == null).findAny().isPresent(); decisions.putAll(copyingIn.decisions); }
public void writeBuffer(List<Element> sortedObjectFileElements, ByteBuffer out) { /* Emit each one! */ for (Element e : sortedObjectFileElements) { int off = (int) decisionsTaken.get(e).getDecision(LayoutDecision.Kind.OFFSET).getValue(); assert off != Integer.MAX_VALUE; // not allowed any more -- this was a broken approach out.position(off); int expectedSize = (int) decisionsTaken.get(e).getDecidedValue(LayoutDecision.Kind.SIZE); byte[] content = (byte[]) decisionsTaken.get(e).getDecidedValue(LayoutDecision.Kind.CONTENT); out.put(content); int emittedSize = out.position() - off; assert emittedSize >= 0; if (emittedSize != expectedSize) { throw new IllegalStateException("For element " + e + ", expected size " + expectedSize + " but emitted size " + emittedSize); } } }
@Override public int compare(LayoutDecision d0, LayoutDecision d1) { // elements of undecided property come first LayoutDecision sizeDecision0 = d0 == null ? null : alreadyDecided.get(d0.getElement()).getDecision(LayoutDecision.Kind.SIZE); LayoutDecision sizeDecision1 = d1 == null ? null : alreadyDecided.get(d1.getElement()).getDecision(LayoutDecision.Kind.SIZE); int defaultValue = nullsToTail ? Integer.MAX_VALUE : Integer.MIN_VALUE; int s0 = (sizeDecision0 == null || !sizeDecision0.isTaken()) ? defaultValue : (int) sizeDecision0.getValue(); int s1 = (sizeDecision1 == null || !sizeDecision1.isTaken()) ? defaultValue : (int) sizeDecision1.getValue(); return Integer.compare(s0, s1); } }
@Override public int compare(Element e1, Element e2) { // if an offset is not decided, it is treated as maximal // i.e. can "float to the end" LayoutDecisionMap e1decisions = decisionsByElement.get(e1); LayoutDecision e1OffsetDecision = e1decisions.getDecision(LayoutDecision.Kind.OFFSET); int e1offset = (e1OffsetDecision != null && e1OffsetDecision.isTaken()) ? (int) e1OffsetDecision.getValue() : Integer.MAX_VALUE; LayoutDecisionMap e2decisions = decisionsByElement.get(e2); LayoutDecision e2OffsetDecision = e2decisions.getDecision(LayoutDecision.Kind.OFFSET); int e2offset = (e2OffsetDecision != null && e2OffsetDecision.isTaken()) ? (int) e2OffsetDecision.getValue() : Integer.MAX_VALUE; if (e1offset < e2offset) { return -1; } else if (e1offset > e2offset) { return 1; } else { return 0; } } }
protected static int nextAvailableOffset(final Map<Element, LayoutDecisionMap> alreadyDecided) { int ret = -1; List<LayoutDecision> maxOffsetDecisions = maximalDecisionValues(alreadyDecided, LayoutDecision.Kind.OFFSET, new IntegerDecisionComparator(false)); // break ties using size (nulls to head) Collections.sort(maxOffsetDecisions, new SizeTiebreakComparator(alreadyDecided, false)); // we sorted into ascending size order, so get the biggest LayoutDecision maxOffsetDecision = maxOffsetDecisions.get(maxOffsetDecisions.size() - 1); if (maxOffsetDecision == null || !maxOffsetDecision.isTaken()) { // means we have not decided any offsets yet -- return 0 ret = 0; } else { assert alreadyDecided.get(maxOffsetDecision.getElement()).getDecision(LayoutDecision.Kind.SIZE).isTaken(); int offset = (int) alreadyDecided.get(maxOffsetDecision.getElement()).getDecision(LayoutDecision.Kind.OFFSET).getValue(); int size = (int) alreadyDecided.get(maxOffsetDecision.getElement()).getDecision(LayoutDecision.Kind.SIZE).getValue(); ret = offset + size; } return ret; }
@Override public byte[] getOrDecideContent(Map<Element, LayoutDecisionMap> alreadyDecided, byte[] contentHint) { OutputAssembler out = AssemblyBuffer.createOutputAssembler(getOwner().getByteOrder()); ArrayList<LayoutDecision> decisionsOfInterest = new ArrayList<>(); for (Section s : getSections()) { MachOSection ms = (MachOSection) s; if (ms.flags.contains(SectionFlag.SOME_INSTRUCTIONS)) { decisionsOfInterest.add(alreadyDecided.get(s).getDecision(LayoutDecision.Kind.OFFSET)); } } // sort these sections by their decided offset Collections.sort(decisionsOfInterest, new IntegerDecisionComparator(false)); // we should not have any undecideds! assert decisionsOfInterest.size() == 0 || decisionsOfInterest.get(0).isTaken(); EntryStruct ent = new EntryStruct(); for (int i = 0; i < decisionsOfInterest.size(); ++i) { LayoutDecision decision = decisionsOfInterest.get(i); ent.fileOffset = (int) decision.getValue(); int fileSize = (int) alreadyDecided.get(decision.getElement()).getDecidedValue(LayoutDecision.Kind.SIZE); int sectionEndInFile = ent.fileOffset + fileSize; Integer nextOffset = (i + 1 < decisionsOfInterest.size()) ? (int) decisionsOfInterest.get(i + 1).getValue() : null; int nextPageBoundary = (sectionEndInFile % getPageSize()) == 0 ? sectionEndInFile : (((sectionEndInFile >> getPageSizeShift()) + 1) << getPageSizeShift()); ent.length = (short) (nextOffset == null ? nextPageBoundary : Math.min(nextPageBoundary, nextOffset)); ent.entryKind = (short) 0; // FIXME ent.write(out); } return out.getBlob(); } }
protected Iterable<Element> elementsMappedOnPage(long vaddr, Map<Element, LayoutDecisionMap> alreadyDecided) { final long vaddrRoundedDown = (vaddr >> getPageSizeShift()) << getPageSizeShift(); // FIXME: use FilteringIterator instead of copying ArrayList<Element> ss = new ArrayList<>(); for (LayoutDecision d : decisionsByKind(LayoutDecision.Kind.VADDR, alreadyDecided)) { Element s = d.getElement(); assert d.getKind() == LayoutDecision.Kind.VADDR; int va = (int) d.getValue(); int sizeInMemory = d.getElement().getMemSize(alreadyDecided); assert sizeInMemory != -1; // if it begins before the end of this page // and doesn't end before the start, // it overlaps the page. int mappingBegin = va; int mappingEnd = va + sizeInMemory; long pageBegin = vaddrRoundedDown; long pageEnd = vaddrRoundedDown + getPageSize(); if (mappingBegin < pageEnd && mappingEnd > pageBegin) { ss.add(s); } } return ss; }
valueDecided = d.getValue(); } else { switch (d.getKind()) { decidedContent = (byte[]) decisionsTaken.get(e).getDecision(LayoutDecision.Kind.CONTENT).getValue(); totalSize = Math.max(totalSize, (int) decisionsTaken.get(e).getDecision(LayoutDecision.Kind.OFFSET).getValue() + (int) decisionsTaken.get(e).getDecidedValue(LayoutDecision.Kind.SIZE));
byte[] shstrtabContents = (byte[]) shstrtabDecision.getValue(); StringTable strings = new StringTable(shstrtabContents);
int minVaddr = (minVaddrDecisions == null || minVaddrDecisions.size() == 0) ? 0 : (int) minVaddrDecisions.get(0).getValue(); int maxVaddr = (maxVaddrDecision == null) ? 0 : ((int) maxVaddrDecision.getValue() + maxVaddrDecision.getElement().getMemSize(alreadyDecided)); int vmSize = ObjectFile.nextIntegerMultiple(maxVaddr - minVaddr, getPageSize()); int minOffset = (minOffsetDecisions == null || minOffsetDecisions.size() == 0) ? 0 : (int) minOffsetDecisions.get(0).getValue(); List<LayoutDecision> maxOffsetDecisions = ObjectFile.maximalDecisionValues(decidedAboutOurElements, LayoutDecision.Kind.OFFSET, new IntegerDecisionComparator(false)); int maxOffset = (maxOffsetDecision == null) ? 0 : ((int) maxOffsetDecision.getValue() + (int) alreadyDecided.get(maxOffsetDecision.getElement()).getDecidedValue(LayoutDecision.Kind.SIZE)); int fileSize = maxOffset - minOffset;