Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2025-08-28 14:13:53 -04:00
commit 44a16fd6ba
2 changed files with 103 additions and 74 deletions

View file

@ -25,7 +25,6 @@ import ghidra.program.model.symbol.*;
class ReferenceLineDispenser extends AbstractLineDispenser { class ReferenceLineDispenser extends AbstractLineDispenser {
private static final Address[] EMPTY_ADDR_ARR = new Address[0];
private final static String XREFS_DELIM = ","; private final static String XREFS_DELIM = ",";
private int headerWidth; private int headerWidth;
@ -52,10 +51,10 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
options.getAddrWidth() + options.getBytesWidth() + options.getLabelWidth(); options.getAddrWidth() + options.getBytesWidth() + options.getLabelWidth();
this.isHTML = options.isHTML(); this.isHTML = options.isHTML();
Address[] refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu)); List<Reference> refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu));
Address[] offcuts = (forwardRefs ? EMPTY_ADDR_ARR : getOffcutXRefList(cu)); List<Reference> offcuts = (forwardRefs ? List.of() : getOffcutXRefList(cu));
processRefs(cu.getMinAddress(), refs, offcuts); processRefs(cu.getMinAddress(), forwardRefs, refs, offcuts);
} }
ReferenceLineDispenser(Variable var, Program program, ProgramTextOptions options) { ReferenceLineDispenser(Variable var, Program program, ProgramTextOptions options) {
@ -74,20 +73,14 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
List<Reference> xrefs = new ArrayList<>(); List<Reference> xrefs = new ArrayList<>();
List<Reference> offcuts = new ArrayList<>(); List<Reference> offcuts = new ArrayList<>();
XReferenceUtils.getVariableRefs(var, xrefs, offcuts); XReferenceUtils.getVariableRefs(var, xrefs, offcuts);
Address[] xrefAddr = extractFromAddr(xrefs);
Address[] offcutsAddr = extractFromAddr(offcuts);
processRefs(var.getFunction().getEntryPoint(), Comparator<? super Reference> comparator = (r1, r2) -> {
xrefAddr, offcutsAddr); return r1.getFromAddress().compareTo(r2.getFromAddress());
} };
xrefs.sort(comparator);
offcuts.sort(comparator);
private Address[] extractFromAddr(List<Reference> refs) { processRefs(var.getFunction().getEntryPoint(), false, xrefs, offcuts);
Address[] addrs = new Address[refs.size()];
for (int i = 0; i < addrs.length; i++) {
addrs[i] = refs.get(i).getFromAddress();
}
Arrays.sort(addrs);
return addrs;
} }
@Override @Override
@ -110,7 +103,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
private Address[] getForwardRefs(CodeUnit cu) { private List<Reference> getForwardRefs(CodeUnit cu) {
boolean showRefs = false; boolean showRefs = false;
Address cuAddr = cu.getMinAddress(); Address cuAddr = cu.getMinAddress();
@ -130,52 +123,48 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
} }
if (!showRefs) { if (!showRefs) {
return EMPTY_ADDR_ARR; return List.of();
} }
Reference[] mRefs = cu.getReferencesFrom(); List<Reference> refs = Arrays.asList(cu.getReferencesFrom());
Address[] refs = new Address[mRefs.length]; refs.sort((r1, r2) -> {
for (int i = 0; i < mRefs.length; ++i) { return r1.getToAddress().compareTo(r2.getToAddress());
refs[i] = mRefs[i].getToAddress(); });
}
Arrays.sort(refs);
return refs; return refs;
} }
//////////////////////////////////////////////////////////////////// private void processRefs(Address addr, boolean isForward, List<Reference> refs,
List<Reference> offcuts) {
private void processRefs(Address addr, Address[] refs, Address[] offcuts) {
if (width < 1) { if (width < 1) {
return; return;
} }
if (refs.length == 0 && offcuts.length == 0) { if (refs.isEmpty() && offcuts.isEmpty()) {
return; return;
} }
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
List<Reference> all = new ArrayList<>();
Address[] all = new Address[refs.length + offcuts.length]; all.addAll(refs);
System.arraycopy(refs, 0, all, 0, refs.length); all.addAll(offcuts);
System.arraycopy(offcuts, 0, all, refs.length, offcuts.length);
if (displayRefHeader) { if (displayRefHeader) {
if (refs.length > 0 || offcuts.length > 0) { if (!refs.isEmpty() || !offcuts.isEmpty()) {
StringBuffer tmp = new StringBuffer();
tmp.append(header);
tmp.append("[");
tmp.append(refs.length);
tmp.append(",");
tmp.append(offcuts.length);
tmp.append("]: ");
buf.append(clip(tmp.toString(), headerWidth)); String text;
if (!offcuts.isEmpty()) {
text = "%s[%d,%d]: ".formatted(header, refs.size(), offcuts.size());
}
else {
text = "%s[%d]: ".formatted(header, refs.size());
}
buf.append(clip(text, headerWidth));
} }
} }
int refsPerLine = width / (all[0].toString().length() + XREFS_DELIM.length()); int refsPerLine = width / (all.get(0).toString().length() + XREFS_DELIM.length());
int refsInCurrLine = 0; int refsInCurrLine = 0;
for (int i = 0; i < all.length; ++i) { for (int i = 0; i < all.size(); ++i) {
//if we are not displaying the xref header, //if we are not displaying the xref header,
//then we need to append the comment prefix //then we need to append the comment prefix
if (i == 0 && !displayRefHeader) { if (i == 0 && !displayRefHeader) {
@ -198,11 +187,17 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
} }
//does memory contain this address? if so, then hyperlink it //does memory contain this address? if so, then hyperlink it
boolean isInMem = memory.contains(all[i]); Reference ref = all.get(i);
Address address = isForward ? ref.getToAddress() : ref.getFromAddress();
boolean isInMem = memory.contains(address);
if (isHTML && isInMem) { if (isHTML && isInMem) {
buf.append("<A HREF=\"#" + getUniqueAddressString(all[i]) + "\">"); buf.append("<A HREF=\"#" + getUniqueAddressString(address) + "\">");
} }
buf.append(all[i].toString()); buf.append(address);
String refType = getRefTypeDisplayString(ref);
buf.append(refType);
if (isHTML && isInMem) { if (isHTML && isInMem) {
buf.append("</A>"); buf.append("</A>");
} }
@ -222,31 +217,62 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
} }
} }
public static Address[] getXRefList(CodeUnit cu) { // copied from XRefFieldFactory
Program prog = cu.getProgram(); private String getRefTypeDisplayString(Reference reference) {
if (prog == null) {
return new Address[0]; if (reference.getReferenceType().isRead() && reference.getReferenceType().isWrite()) {
} return "(RW)";
List<Address> xrefList = new ArrayList<>();
//lookup the direct xrefs to the current code unit
//
ReferenceIterator iter = prog.getReferenceManager().getReferencesTo(cu.getMinAddress());
while (iter.hasNext()) {
Reference ref = iter.next();
xrefList.add(ref.getFromAddress());
}
Address[] arr = new Address[xrefList.size()];
xrefList.toArray(arr);
Arrays.sort(arr);
return arr;
} }
private static Address[] getOffcutXRefList(CodeUnit cu) { RefType refType = reference.getReferenceType();
if (reference instanceof ThunkReference) {
return "(T)";
}
if (refType instanceof DataRefType) {
if (refType.isRead() || refType.isIndirect()) {
return "(R)";
}
else if (refType.isWrite()) {
return "(W)";
}
else if (refType.isData()) {
return "(*)";
}
}
if (refType.isCall()) {
return "(c)";
}
else if (refType.isJump()) {
return "(j)";
}
return "";
}
public static List<Reference> getXRefList(CodeUnit cu) {
Program prog = cu.getProgram(); Program prog = cu.getProgram();
if (prog == null) { if (prog == null) {
return new Address[0]; return List.of();
} }
List<Address> offcutList = new ArrayList<>();
// default value taken from XRefFieldFactory
int maxXrefs = 20;
List<Reference> refs = XReferenceUtils.getXReferences(cu, maxXrefs + 1);
int maxOffcuts = Math.max(0, maxXrefs - refs.size());
List<Reference> offcuts = XReferenceUtils.getOffcutXReferences(cu, maxOffcuts);
refs.addAll(offcuts);
refs.sort((r1, r2) -> {
return r1.getFromAddress().compareTo(r2.getFromAddress());
});
return refs;
}
private static List<Reference> getOffcutXRefList(CodeUnit cu) {
Program prog = cu.getProgram();
if (prog == null) {
return List.of();
}
List<Reference> offcutList = new ArrayList<>();
// Lookup the offcut xrefs... // Lookup the offcut xrefs...
// //
if (cu.getLength() > 1) { if (cu.getLength() > 1) {
@ -259,13 +285,14 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
ReferenceIterator refIter = refMgr.getReferencesTo(addr); ReferenceIterator refIter = refMgr.getReferencesTo(addr);
while (refIter.hasNext()) { while (refIter.hasNext()) {
Reference ref = refIter.next(); Reference ref = refIter.next();
offcutList.add(ref.getFromAddress()); offcutList.add(ref);
} }
} }
} }
Address[] arr = new Address[offcutList.size()];
offcutList.toArray(arr); offcutList.sort((r1, r2) -> {
Arrays.sort(arr); return r1.getFromAddress().compareTo(r2.getFromAddress());
return arr; });
return offcutList;
} }
} }

View file

@ -28,7 +28,8 @@ import ghidra.app.util.viewer.proxy.ProxyObj;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions; import ghidra.framework.options.ToolOptions;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.Reference;
import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramLocation;
import ghidra.program.util.XRefHeaderFieldLocation; import ghidra.program.util.XRefHeaderFieldLocation;
@ -132,8 +133,9 @@ public class XRefHeaderFieldFactory extends XRefFieldFactory {
if (cu == null) { if (cu == null) {
return null; return null;
} }
Program prog = cu.getProgram();
int xrefCount = prog.getReferenceManager().getReferenceCountTo(cu.getMinAddress()); List<Reference> xrefs = XReferenceUtils.getXReferences(cu, maxXRefs);
int xrefCount = xrefs.size();
List<Reference> offcuts = XReferenceUtils.getOffcutXReferences(cu, maxXRefs); List<Reference> offcuts = XReferenceUtils.getOffcutXReferences(cu, maxXRefs);
int offcutCount = offcuts.size(); int offcutCount = offcuts.size();