mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
1ca9e32a57
4 changed files with 91 additions and 61 deletions
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -57,13 +57,13 @@ class ProgramTextOptions {
|
||||||
private final static int DEFAULT_OPERAND_WIDTH = 40;
|
private final static int DEFAULT_OPERAND_WIDTH = 40;
|
||||||
private final static int DEFAULT_EOL_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_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_PRENAME_WIDTH = 10;
|
||||||
private final static int DEFAULT_STACK_VAR_NAME_WIDTH = 15;
|
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_DATATYPE_WIDTH = 15;
|
||||||
private final static int DEFAULT_STACK_VAR_OFFSET_WIDTH = 8;
|
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_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 int DEFAULT_DATA_FIELD_NAME_WIDTH = 12;
|
||||||
|
|
||||||
private final static String DEFAULT_LABEL_SUFFIX = ":";
|
private final static String DEFAULT_LABEL_SUFFIX = ":";
|
||||||
|
|
|
@ -32,6 +32,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
private String header;
|
private String header;
|
||||||
private Memory memory;
|
private Memory memory;
|
||||||
private ReferenceManager referenceManager;
|
private ReferenceManager referenceManager;
|
||||||
|
private boolean forwardRefs;
|
||||||
|
|
||||||
private List<String> lines = new ArrayList<>();
|
private List<String> lines = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -50,11 +51,11 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
this.fillAmount =
|
this.fillAmount =
|
||||||
options.getAddrWidth() + options.getBytesWidth() + options.getLabelWidth();
|
options.getAddrWidth() + options.getBytesWidth() + options.getLabelWidth();
|
||||||
this.isHTML = options.isHTML();
|
this.isHTML = options.isHTML();
|
||||||
|
this.forwardRefs = forwardRefs;
|
||||||
|
|
||||||
List<Reference> refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu));
|
List<Reference> refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu));
|
||||||
List<Reference> offcuts = (forwardRefs ? List.of() : 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) {
|
||||||
|
@ -69,6 +70,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
options.getStackVarDataTypeWidth() + options.getStackVarOffsetWidth() +
|
options.getStackVarDataTypeWidth() + options.getStackVarOffsetWidth() +
|
||||||
options.getStackVarCommentWidth();
|
options.getStackVarCommentWidth();
|
||||||
this.isHTML = options.isHTML();
|
this.isHTML = options.isHTML();
|
||||||
|
this.forwardRefs = false;
|
||||||
|
|
||||||
List<Reference> xrefs = new ArrayList<>();
|
List<Reference> xrefs = new ArrayList<>();
|
||||||
List<Reference> offcuts = new ArrayList<>();
|
List<Reference> offcuts = new ArrayList<>();
|
||||||
|
@ -80,7 +82,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
xrefs.sort(comparator);
|
xrefs.sort(comparator);
|
||||||
offcuts.sort(comparator);
|
offcuts.sort(comparator);
|
||||||
|
|
||||||
processRefs(var.getFunction().getEntryPoint(), false, xrefs, offcuts);
|
processRefs(var.getFunction().getEntryPoint(), xrefs, offcuts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -133,8 +135,9 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processRefs(Address addr, boolean isForward, List<Reference> refs,
|
private void processRefs(Address addr, List<Reference> refs,
|
||||||
List<Reference> offcuts) {
|
List<Reference> offcuts) {
|
||||||
|
|
||||||
if (width < 1) {
|
if (width < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +145,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuilder buf = new StringBuilder();
|
||||||
List<Reference> all = new ArrayList<>();
|
List<Reference> all = new ArrayList<>();
|
||||||
all.addAll(refs);
|
all.addAll(refs);
|
||||||
all.addAll(offcuts);
|
all.addAll(offcuts);
|
||||||
|
@ -160,60 +163,41 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
buf.append(clip(text, headerWidth));
|
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 currentXrefWidth = 0;
|
||||||
int refsInCurrLine = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < all.size(); ++i) {
|
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);
|
Reference ref = all.get(i);
|
||||||
Address address = isForward ? ref.getToAddress() : ref.getFromAddress();
|
XrefItem xrefItem = new XrefItem(ref);
|
||||||
boolean isInMem = memory.contains(address);
|
|
||||||
if (isHTML && isInMem) {
|
|
||||||
buf.append("<A HREF=\"#" + getUniqueAddressString(address) + "\">");
|
|
||||||
}
|
|
||||||
buf.append(address);
|
|
||||||
|
|
||||||
String refType = getRefTypeDisplayString(ref);
|
int nextWidth = currentXrefWidth + xrefItem.getDisplayableWidth();
|
||||||
buf.append(refType);
|
if (nextWidth > width) {
|
||||||
|
// line is too long for the current xref, break
|
||||||
if (isHTML && isInMem) {
|
lines.add(prefix + buf.toString());
|
||||||
buf.append("</A>");
|
|
||||||
}
|
|
||||||
|
|
||||||
refsInCurrLine++;
|
|
||||||
|
|
||||||
if (refsInCurrLine == refsPerLine) {
|
|
||||||
lines.add((displayRefHeader ? prefix : "") + buf.toString());
|
|
||||||
buf.delete(0, buf.length());
|
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) {
|
// add the last xref line
|
||||||
lines.add((displayRefHeader ? prefix : "") + buf.toString());
|
if (buf.length() != 0) {
|
||||||
buf.delete(0, buf.length());
|
lines.add(prefix + buf.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,4 +279,29 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
});
|
});
|
||||||
return offcutList;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -24,10 +24,11 @@ import ghidra.util.Msg;
|
||||||
|
|
||||||
public class StringComparer {
|
public class StringComparer {
|
||||||
public static void compareLines(List<String> expectedList, File actualFile) throws Exception {
|
public static void compareLines(List<String> expectedList, File actualFile) throws Exception {
|
||||||
|
|
||||||
|
FilePrinter filePrinter = new FilePrinter(actualFile);
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
boolean hasFailure = false;
|
boolean hasFailure = false;
|
||||||
|
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(actualFile))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(actualFile))) {
|
||||||
int excess = 0;
|
int excess = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -51,17 +52,21 @@ public class StringComparer {
|
||||||
hasFailure |= !match;
|
hasFailure |= !match;
|
||||||
|
|
||||||
if (!match) {
|
if (!match) {
|
||||||
Msg.debug(StringComparer.class, "Expected line does not match actual line (" + index +
|
filePrinter.print();
|
||||||
"): \nExpected: " + expectedLine + "\nActual: " + actualLine);
|
Msg.debug(StringComparer.class,
|
||||||
|
"Expected line does not match actual line (" + index +
|
||||||
|
"): \nExpected: " + expectedLine + "\nActual: " + actualLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (excess > 0) {
|
if (excess > 0) {
|
||||||
|
filePrinter.print();
|
||||||
String message = "Actual file contains " + excess + " more lines than expected";
|
String message = "Actual file contains " + excess + " more lines than expected";
|
||||||
Msg.debug(StringComparer.class, message);
|
Msg.debug(StringComparer.class, message);
|
||||||
Assert.fail(message);
|
Assert.fail(message);
|
||||||
}
|
}
|
||||||
else if (!hasFailure && index < expectedList.size()) {
|
else if (!hasFailure && index < expectedList.size()) {
|
||||||
|
filePrinter.print();
|
||||||
int fewer = expectedList.size() - index;
|
int fewer = expectedList.size() - index;
|
||||||
String message = "Actual file contains " + fewer +
|
String message = "Actual file contains " + fewer +
|
||||||
" fewer lines than expected";
|
" 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ public class XrefViewerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
01001046 ?? thunk_FUN_01001005 UNCONDITIONAL_CALL thunk
|
01001046 ?? thunk_FUN_01001005 UNCONDITIONAL_CALL thunk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
doubleClickXRef(baseFunctionAddress, "XREF[1]: ");
|
doubleClickXRef(baseFunctionAddress, "XREF[2]: ");
|
||||||
ComponentProvider comp = waitForComponentProvider(TableComponentProvider.class);
|
ComponentProvider comp = waitForComponentProvider(TableComponentProvider.class);
|
||||||
TableComponentProvider<?> tableProvider = (TableComponentProvider<?>) comp;
|
TableComponentProvider<?> tableProvider = (TableComponentProvider<?>) comp;
|
||||||
GhidraProgramTableModel<?> model = tableProvider.getModel();
|
GhidraProgramTableModel<?> model = tableProvider.getModel();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue