From 5c65fb102d61954ac74d78b6462fb5e98fc05086 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 5 Mar 2021 18:07:16 -0500 Subject: [PATCH] GP-752 - Add option to disable showing of automatic function comments --- .../java/ghidra/app/util/DisplayableEol.java | 34 ++++---- .../app/util/exporter/ProgramTextWriter.java | 8 +- .../viewer/field/EolCommentFieldFactory.java | 17 +++- .../core/comments/DisplayableEolTest.java | 79 +++++++++++++++++-- 4 files changed, 112 insertions(+), 26 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DisplayableEol.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DisplayableEol.java index c2dad1ca28..2457f84129 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DisplayableEol.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DisplayableEol.java @@ -36,7 +36,6 @@ import ghidra.program.util.*; */ public class DisplayableEol { - private static final String VAR_ARGS = "..."; private static final String POINTER_ARROW = "-> "; public static final int MY_EOLS = 0; @@ -48,19 +47,16 @@ public class DisplayableEol { private boolean alwaysShowRepeatable = false; private boolean alwaysShowRefRepeats = false; private boolean alwaysShowAutomatic = false; + private boolean showAutomaticFunctions; private boolean operandsFollowPointerRefs = false; private int maxDisplayLines; private int totalCommentsFound; private boolean useAbbreviatedAutomatic; - /** - * Construct a new DisplayableEol. - * @param cu code unit that may have end of line or repeatable comments. - */ public DisplayableEol(CodeUnit cu, boolean alwaysShowRepeatable, boolean alwaysShowRefRepeats, boolean alwaysShowAutomatic, boolean operandsFollowPointerRefs, int maxDisplayLines, - boolean useAbbreviatedAutomatic) { + boolean useAbbreviatedAutomatic, boolean showAutomaticFunctions) { this.codeUnit = cu; this.alwaysShowRepeatable = alwaysShowRepeatable; this.alwaysShowRefRepeats = alwaysShowRefRepeats; @@ -68,6 +64,7 @@ public class DisplayableEol { this.operandsFollowPointerRefs = operandsFollowPointerRefs; this.maxDisplayLines = maxDisplayLines; this.useAbbreviatedAutomatic = useAbbreviatedAutomatic; + this.showAutomaticFunctions = showAutomaticFunctions; initComments(); } @@ -118,7 +115,8 @@ public class DisplayableEol { } /** - * Return whether the associated code unit has an end of line comment. + * Return whether the associated code unit has an end of line comment + * @return whether the associated code unit has an end of line comment */ public boolean hasEOL() { return (displayCommentArrays[MY_EOLS] != null) && @@ -126,7 +124,8 @@ public class DisplayableEol { } /** - * Return whether the associated code unit has a repeatable comment. + * Return whether the associated code unit has a repeatable comment + * @return whether the associated code unit has a repeatable comment */ public boolean hasRepeatable() { return (displayCommentArrays[MY_REPEATABLES] != null) && @@ -135,7 +134,9 @@ public class DisplayableEol { /** * Return whether any memory reference from this code unit has a repeatable - * comment at the reference's to address. + * comment at the reference's to address + * @return whether any memory reference from this code unit has a repeatable + * comment at the reference's to address */ public boolean hasReferencedRepeatable() { return (displayCommentArrays[REF_REPEATABLES] != null) && @@ -143,10 +144,10 @@ public class DisplayableEol { } /** - * Return whether this code unit has an automatic comment. - * (i.e. any memory reference from this code unit has a - * function defined at the reference's to address, or if the to - * address is a pointer.) + * Return whether this code unit has an automatic comment. For example, a memory reference + * from this code unit has a function defined at the reference's to address, or if the to + * address is a pointer. + * @return whether this code unit has an automatic comment */ public boolean hasAutomatic() { return (displayCommentArrays[MY_AUTOMATIC] != null) && @@ -367,6 +368,10 @@ public class DisplayableEol { private boolean handleDirectFlow(Set set, Reference reference, Program program, Address toAddr) { + if (!showAutomaticFunctions) { + return false; + } + RefType type = reference.getReferenceType(); if (!type.isFlow()) { return false; @@ -537,7 +542,8 @@ public class DisplayableEol { } /** - * Return all the comments (End of Line, Repeatable, Referenced Repeatables, and Referenced Data). + * Return all the comments + * @return the comments */ public String[] getComments() { ArrayList list = new ArrayList<>(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java index aed2306b5c..e17d76ca5c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java @@ -290,7 +290,7 @@ class ProgramTextWriter { if (options.isShowComments()) { DisplayableEol displayableEol = new DisplayableEol(currentCodeUnit, false, false, - false, true, 6 /* arbitrary! */, true); + false, true, 6 /* arbitrary! */, true, true); String[] eol = displayableEol.getComments(); if (eol != null && eol.length > 0) { len = options.getAddrWidth() + options.getBytesWidth() + @@ -618,8 +618,10 @@ class ProgramTextWriter { if (options.isHTML()) { Reference ref = - cu.getProgram().getReferenceManager().getPrimaryReferenceFrom(cuAddress, - i); + cu.getProgram() + .getReferenceManager() + .getPrimaryReferenceFrom(cuAddress, + i); addReferenceLinkedText(ref, opReps[i], true); } else { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java index 1a87e82a97..aaf563dc69 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java @@ -58,6 +58,8 @@ public class EolCommentFieldFactory extends FieldFactory { GROUP_TITLE + Options.DELIMITER + "Always Show the Automatic Comment"; public static final String USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG = GROUP_TITLE + Options.DELIMITER + "Use Abbreviated Automatic Comments"; + public static final String SHOW_FUNCTION_AUTOMITIC_COMMENT_MSG = + GROUP_TITLE + Options.DELIMITER + "Show Function Reference Automatic Comments"; public final static String ENABLE_PREPEND_REF_ADDRESS_MSG = GROUP_TITLE + Options.DELIMITER + "Prepend the Address to Each Referenced Comment"; public static final Color DEFAULT_COLOR = Color.BLUE; @@ -69,6 +71,7 @@ public class EolCommentFieldFactory extends FieldFactory { private boolean alwaysShowRefRepeatables; private boolean alwaysShowAutomatic; private boolean useAbbreviatedAutomatic; + private boolean showAutomaticFunctions; private boolean prependRefAddress; private Color repeatableCommentColor; private Color automaticCommentColor; @@ -92,7 +95,7 @@ public class EolCommentFieldFactory extends FieldFactory { /** * Constructor * @param model the model that the field belongs to. - * @param hsProvider the HightLightStringProvider. + * @param hlProvider the HightLightStringProvider. * @param displayOptions the Options for display properties. * @param fieldOptions the Options for field specific properties. */ @@ -126,6 +129,9 @@ public class EolCommentFieldFactory extends FieldFactory { "aren't any EOL or repeatable comments."); fieldOptions.registerOption(USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG, true, hl, "When showing automatic comments, show the smallest amount of information possible"); + fieldOptions.registerOption(SHOW_FUNCTION_AUTOMITIC_COMMENT_MSG, true, hl, + "When showing automatic comments, show direct function references"); + fieldOptions.registerOption(ENABLE_PREPEND_REF_ADDRESS_MSG, false, hl, "Displays the address before each referenced repeatable comment."); @@ -153,6 +159,9 @@ public class EolCommentFieldFactory extends FieldFactory { alwaysShowAutomatic = fieldOptions.getBoolean(ENABLE_ALWAYS_SHOW_AUTOMATIC_MSG, false); useAbbreviatedAutomatic = fieldOptions.getBoolean(USE_ABBREVIATED_AUTOMITIC_COMMENT_MSG, true); + showAutomaticFunctions = + fieldOptions.getBoolean(SHOW_FUNCTION_AUTOMITIC_COMMENT_MSG, true); + prependRefAddress = fieldOptions.getBoolean(ENABLE_PREPEND_REF_ADDRESS_MSG, false); fieldOptions.getOptions(GROUP_TITLE).setOptionsHelpLocation(hl); @@ -300,7 +309,7 @@ public class EolCommentFieldFactory extends FieldFactory { DisplayableEol displayableEol = new DisplayableEol(cu, alwaysShowRepeatable, alwaysShowRefRepeatables, alwaysShowAutomatic, codeUnitFormatOptions.followReferencedPointers(), - maxDisplayLines, useAbbreviatedAutomatic); + maxDisplayLines, useAbbreviatedAutomatic, showAutomaticFunctions); ArrayList elementList = new ArrayList<>(); // This Code Unit's End of Line Comment @@ -500,7 +509,7 @@ public class EolCommentFieldFactory extends FieldFactory { DisplayableEol displayableEol = new DisplayableEol(cu, alwaysShowRepeatable, alwaysShowRefRepeatables, alwaysShowAutomatic, codeUnitFormatOptions.followReferencedPointers(), - maxDisplayLines, useAbbreviatedAutomatic); + maxDisplayLines, useAbbreviatedAutomatic, showAutomaticFunctions); // Hold position in connected tool if navigating within semicolon. int numLeadColumns = 0; @@ -537,7 +546,7 @@ public class EolCommentFieldFactory extends FieldFactory { DisplayableEol displayableEol = new DisplayableEol((CodeUnit) obj, alwaysShowRepeatable, alwaysShowRefRepeatables, alwaysShowAutomatic, codeUnitFormatOptions.followReferencedPointers(), - maxDisplayLines, useAbbreviatedAutomatic); + maxDisplayLines, useAbbreviatedAutomatic, showAutomaticFunctions); ListingTextField btf = (ListingTextField) bf; diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/comments/DisplayableEolTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/comments/DisplayableEolTest.java index ba13aa118b..f3c26b48dc 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/comments/DisplayableEolTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/comments/DisplayableEolTest.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.comments; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.nio.charset.StandardCharsets; @@ -32,6 +32,7 @@ import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressFactory; import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.listing.Listing; +import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.SourceType; import ghidra.test.AbstractGhidraHeadlessIntegrationTest; import ghidra.util.exception.RollbackException; @@ -60,6 +61,9 @@ public class DisplayableEolTest extends AbstractGenericTest { // testReferenceToOffcutStringData_UseAbbreviatedCommentOption() builder.createEncodedString("1001234", "one.two", StandardCharsets.US_ASCII, false); + // testReferenceToFunction() + builder.createFunction("0x1001050"); + program = builder.getProgram(); } @@ -68,7 +72,8 @@ public class DisplayableEolTest extends AbstractGenericTest { Listing listing = program.getListing(); CodeUnit cu = listing.getCodeUnitAt(addr("0x110")); - DisplayableEol displayableEol = new DisplayableEol(cu, true, true, true, false, 5, true); + DisplayableEol displayableEol = + new DisplayableEol(cu, true, true, true, false, 5, true, true); String[] comments = displayableEol.getAutomaticComment(); assertEquals(1, comments.length); @@ -84,7 +89,8 @@ public class DisplayableEolTest extends AbstractGenericTest { Listing listing = program.getListing(); CodeUnit cu = listing.getCodeUnitAt(addr("0x1001000")); - DisplayableEol displayableEol = new DisplayableEol(cu, true, true, true, false, 5, true); + DisplayableEol displayableEol = + new DisplayableEol(cu, true, true, true, false, 5, true, true); String[] comments = displayableEol.getAutomaticComment(); assertEquals(1, comments.length); @@ -107,7 +113,31 @@ public class DisplayableEolTest extends AbstractGenericTest { boolean useAbbreviatedComments = false; DisplayableEol displayableEol = - new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments); + new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments, true); + + String[] comments = displayableEol.getAutomaticComment(); + assertEquals(1, comments.length); + assertEquals("= \"one.two\"", comments[0]); + } + + @Test + public void testReferenceToFunction_ShowAutomaticFunctionsOff() throws Exception { + + Address dataStartAddress = addr("0x1001234"); + Address offcutAddress = dataStartAddress.add(2); + Command cmd = + new AddMemRefCmd(addr("0x1001000"), offcutAddress, SourceType.USER_DEFINED, 0, true); + applyCmd(cmd); + + Listing listing = program.getListing(); + CodeUnit cu = listing.getCodeUnitAt(addr("0x1001000")); + + // with this at false, all of the string will be rendered + boolean useAbbreviatedComments = false; + boolean showAutoFunctions = false; + DisplayableEol displayableEol = + new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments, + showAutoFunctions); String[] comments = displayableEol.getAutomaticComment(); assertEquals(1, comments.length); @@ -133,13 +163,52 @@ public class DisplayableEolTest extends AbstractGenericTest { boolean useAbbreviatedComments = true; DisplayableEol displayableEol = - new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments); + new DisplayableEol(cu, true, true, true, false, 5, useAbbreviatedComments, true); String[] comments = displayableEol.getAutomaticComment(); assertEquals(1, comments.length); assertEquals("= \"two\"", comments[0]);// full string is one.two } + @Test + public void testReferenceToFunction_ShowAutomaticFunctions() throws Exception { + + Address from = addr("0x1001000"); + Address toFunction = addr("0x1001050"); + + applyCmd(new AddMemRefCmd(from, toFunction, RefType.UNCONDITIONAL_CALL, SourceType.ANALYSIS, + 0, true)); + + Listing listing = program.getListing(); + CodeUnit cu = listing.getCodeUnitAt(from); + boolean showAutoFunctions = true; + DisplayableEol displayableEol = + new DisplayableEol(cu, true, true, true, false, 5, false, showAutoFunctions); + + String[] comments = displayableEol.getAutomaticComment(); + assertEquals(1, comments.length); + assertEquals("undefined FUN_01001050()", comments[0]); + } + + @Test + public void testReferenceToFunction_DontShowAutomaticFunctions() throws Exception { + + Address from = addr("0x1001000"); + Address toFunction = addr("0x1001050"); + + applyCmd(new AddMemRefCmd(from, toFunction, RefType.UNCONDITIONAL_CALL, SourceType.ANALYSIS, + 0, true)); + + Listing listing = program.getListing(); + CodeUnit cu = listing.getCodeUnitAt(from); + boolean showAutoFunctions = false; + DisplayableEol displayableEol = + new DisplayableEol(cu, true, true, true, false, 5, false, showAutoFunctions); + + String[] comments = displayableEol.getAutomaticComment(); + assertEquals(0, comments.length); + } + public boolean applyCmd(Command cmd) throws RollbackException { return AbstractGhidraHeadlessIntegrationTest.applyCmd(program, cmd); }