Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2025-09-02 05:53:32 -04:00
commit 1ca9e32a57
4 changed files with 91 additions and 61 deletions

View file

@ -57,13 +57,13 @@ class ProgramTextOptions {
private final static int DEFAULT_OPERAND_WIDTH = 40;
private final static int DEFAULT_EOL_WIDTH = 40;
private final static int DEFAULT_REF_HEADER_WIDTH = 13;
private final static int DEFAULT_REF_WIDTH = 40;
private final static int DEFAULT_REF_WIDTH = 50; // about 4 refs per line
private final static int DEFAULT_STACK_VAR_PRENAME_WIDTH = 10;
private final static int DEFAULT_STACK_VAR_NAME_WIDTH = 15;
private final static int DEFAULT_STACK_VAR_DATATYPE_WIDTH = 15;
private final static int DEFAULT_STACK_VAR_OFFSET_WIDTH = 8;
private final static int DEFAULT_STACK_VAR_COMMENT_WIDTH = 20;
private final static int DEFAULT_STACK_VAR_XREF_WIDTH = 50;
private final static int DEFAULT_STACK_VAR_XREF_WIDTH = 60; // about 5 refs per line
private final static int DEFAULT_DATA_FIELD_NAME_WIDTH = 12;
private final static String DEFAULT_LABEL_SUFFIX = ":";

View file

@ -32,6 +32,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
private String header;
private Memory memory;
private ReferenceManager referenceManager;
private boolean forwardRefs;
private List<String> lines = new ArrayList<>();
@ -50,11 +51,11 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
this.fillAmount =
options.getAddrWidth() + options.getBytesWidth() + options.getLabelWidth();
this.isHTML = options.isHTML();
this.forwardRefs = forwardRefs;
List<Reference> refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu));
List<Reference> offcuts = (forwardRefs ? List.of() : getOffcutXRefList(cu));
processRefs(cu.getMinAddress(), forwardRefs, refs, offcuts);
processRefs(cu.getMinAddress(), refs, offcuts);
}
ReferenceLineDispenser(Variable var, Program program, ProgramTextOptions options) {
@ -69,6 +70,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
options.getStackVarDataTypeWidth() + options.getStackVarOffsetWidth() +
options.getStackVarCommentWidth();
this.isHTML = options.isHTML();
this.forwardRefs = false;
List<Reference> xrefs = new ArrayList<>();
List<Reference> offcuts = new ArrayList<>();
@ -80,7 +82,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
xrefs.sort(comparator);
offcuts.sort(comparator);
processRefs(var.getFunction().getEntryPoint(), false, xrefs, offcuts);
processRefs(var.getFunction().getEntryPoint(), xrefs, offcuts);
}
@Override
@ -133,8 +135,9 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
return refs;
}
private void processRefs(Address addr, boolean isForward, List<Reference> refs,
private void processRefs(Address addr, List<Reference> refs,
List<Reference> offcuts) {
if (width < 1) {
return;
}
@ -142,7 +145,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
return;
}
StringBuffer buf = new StringBuffer();
StringBuilder buf = new StringBuilder();
List<Reference> all = new ArrayList<>();
all.addAll(refs);
all.addAll(offcuts);
@ -160,60 +163,41 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
buf.append(clip(text, headerWidth));
}
}
else {
buf.append(getFill(headerWidth));
buf.append(prefix);
}
int refsPerLine = width / (all.get(0).toString().length() + XREFS_DELIM.length());
int refsInCurrLine = 0;
int currentXrefWidth = 0;
for (int i = 0; i < all.size(); ++i) {
//if we are not displaying the xref header,
//then we need to append the comment prefix
if (i == 0 && !displayRefHeader) {
buf.append(getFill(headerWidth));
buf.append(prefix);
}
//if we have started a new line, then
//we need to append the comment prefix
if (refsInCurrLine == 0 && i != 0) {
buf.append(getFill(headerWidth));
if (!displayRefHeader) {
buf.append(prefix);
}
}
//if we already appended a ref to the line
//and we are about to append one more,
//then we need the delim
if (refsInCurrLine > 0) {
buf.append(XREFS_DELIM);
}
//does memory contain this address? if so, then hyperlink it
// does memory contain this address? if so, then hyperlink it
Reference ref = all.get(i);
Address address = isForward ? ref.getToAddress() : ref.getFromAddress();
boolean isInMem = memory.contains(address);
if (isHTML && isInMem) {
buf.append("<A HREF=\"#" + getUniqueAddressString(address) + "\">");
}
buf.append(address);
XrefItem xrefItem = new XrefItem(ref);
String refType = getRefTypeDisplayString(ref);
buf.append(refType);
if (isHTML && isInMem) {
buf.append("</A>");
}
refsInCurrLine++;
if (refsInCurrLine == refsPerLine) {
lines.add((displayRefHeader ? prefix : "") + buf.toString());
int nextWidth = currentXrefWidth + xrefItem.getDisplayableWidth();
if (nextWidth > width) {
// line is too long for the current xref, break
lines.add(prefix + buf.toString());
buf.delete(0, buf.length());
refsInCurrLine = 0;
// since we already have the next xref, add the next line's prefix
buf.append(getFill(headerWidth));
currentXrefWidth = 0;
}
currentXrefWidth += xrefItem.getDisplayableWidth();
buf.append(xrefItem.getRawText());
if (i < all.size() - 1) {
buf.append(XREFS_DELIM);
}
}
if (refsInCurrLine > 0) {
lines.add((displayRefHeader ? prefix : "") + buf.toString());
buf.delete(0, buf.length());
// add the last xref line
if (buf.length() != 0) {
lines.add(prefix + buf.toString());
}
}
@ -295,4 +279,29 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
});
return offcutList;
}
private class XrefItem {
private Address address;
private String displayableString;
XrefItem(Reference ref) {
address = forwardRefs ? ref.getToAddress() : ref.getFromAddress();
String refType = getRefTypeDisplayString(ref);
this.displayableString = address.toString() + refType;
}
int getDisplayableWidth() {
return displayableString.length();
}
String getRawText() {
boolean isInMem = memory.contains(address);
if (isHTML && isInMem) {
String href = getUniqueAddressString(address);
return "<A HREF=\"#%s\">%s</A>".formatted(href, displayableString);
}
return displayableString;
}
}
}

View file

@ -24,10 +24,11 @@ import ghidra.util.Msg;
public class StringComparer {
public static void compareLines(List<String> expectedList, File actualFile) throws Exception {
FilePrinter filePrinter = new FilePrinter(actualFile);
int index = 0;
boolean hasFailure = false;
try (BufferedReader reader = new BufferedReader(new FileReader(actualFile))) {
int excess = 0;
while (true) {
@ -51,17 +52,21 @@ public class StringComparer {
hasFailure |= !match;
if (!match) {
Msg.debug(StringComparer.class, "Expected line does not match actual line (" + index +
"): \nExpected: " + expectedLine + "\nActual: " + actualLine);
filePrinter.print();
Msg.debug(StringComparer.class,
"Expected line does not match actual line (" + index +
"): \nExpected: " + expectedLine + "\nActual: " + actualLine);
}
}
if (excess > 0) {
filePrinter.print();
String message = "Actual file contains " + excess + " more lines than expected";
Msg.debug(StringComparer.class, message);
Assert.fail(message);
}
else if (!hasFailure && index < expectedList.size()) {
filePrinter.print();
int fewer = expectedList.size() - index;
String message = "Actual file contains " + fewer +
" fewer lines than expected";
@ -74,4 +79,20 @@ public class StringComparer {
}
}
}
private static class FilePrinter {
private File f;
private boolean printed;
FilePrinter(File f) {
this.f = f;
}
void print() {
if (!printed) {
Msg.debug(this, "Test file: " + f);
printed = true;
}
}
}
}

View file

@ -153,7 +153,7 @@ public class XrefViewerTest extends AbstractGhidraHeadedIntegrationTest {
01001046 ?? thunk_FUN_01001005 UNCONDITIONAL_CALL thunk
*/
doubleClickXRef(baseFunctionAddress, "XREF[1]: ");
doubleClickXRef(baseFunctionAddress, "XREF[2]: ");
ComponentProvider comp = waitForComponentProvider(TableComponentProvider.class);
TableComponentProvider<?> tableProvider = (TableComponentProvider<?>) comp;
GhidraProgramTableModel<?> model = tableProvider.getModel();