GP-388 Adding feature to simplify the display names in the listing for symbol and datatype names that have complex template info in thier names

This commit is contained in:
ghidragon 2023-03-23 15:14:00 -04:00
parent 1f72861388
commit 8bb02c47df
14 changed files with 562 additions and 57 deletions

View File

@ -936,6 +936,33 @@
<P><B>Selection Color</B> - Set the Browser <A href=
"CodeBrowser.htm#Selection">Selection</A> color.</P>
</BLOCKQUOTE>
<H3><A name="Template_Display_Options"></A>Template Display Options</H3>
<BLOCKQUOTE>
<P><B>Max Template Depth</B> - Sets the depth to display nested templates. A
depth of 0 completely simplifies the entire template, while a depth of 1 will
show 1 level of templates.For example, if the name was "foo&lt;char,bar&lt;int, dog&lt;char&gt;&gt;",
a nesting depth of 0 would display "foo&lt;&gt;" and an nesting depth of 1 would display
"foo&lt;char, bar&lt;&gt;&gt;".
</P>
<P><B>Max Template Length</B> - This is the maximum length any template string will display.
If the template string exceeds this length, the middle part of the template will be replaced
with "..." to get the string down to the minimum length. For example, the string
"foo&lt;abcdefghijklmnopqrstuvwxyz,0123456789&gt;" would display something like "foo&lt;abcd...6789&gt;"
if the max length was set to 10. Note that this restriction is applied AFTER
any simplifications from the nesting depth.
</P>
<P><B>Min Template Length</B> - This is the minimum length of a template before template
simplification is applied. In other words, if the template string is less than this length,
then the template will not be simplified. This is done so that simple templates such as
"foo&lt;char&gt;" are not simplified to "foo&lt;&gt;", even if the template nesting depth is set to 0.
</P>
<P><B>Simplify Templated Names</B> - This turns the entire templating simplification feature
on or off. If this is off, none of the other option have any effect.</P>
</BLOCKQUOTE>
<H3><A name="XREFs_Field"></A>XREFs Field</H3>

View File

@ -20,6 +20,7 @@ import java.util.ArrayList;
import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.util.DisplayableEol;
import ghidra.app.util.template.TemplateSimplifier;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
@ -85,7 +86,8 @@ class ProgramTextWriter {
writer.print("<HTML><BODY BGCOLOR=#ffffe0>");
writer.println("<FONT FACE=COURIER SIZE=3><STRONG><PRE>");
}
TemplateSimplifier simplifier = new TemplateSimplifier();
simplifier.setEnabled(false);
CodeUnitFormatOptions formatOptions = new CodeUnitFormatOptions(
options.isShowBlockNameInOperands() ? CodeUnitFormatOptions.ShowBlockName.NON_LOCAL
: CodeUnitFormatOptions.ShowBlockName.NEVER,
@ -95,7 +97,8 @@ class ProgramTextWriter {
true, // include extended reference markup
true, // include scalar adjustment
true, // include library names in namespace
true // follow referenced pointers
true, // follow referenced pointers
simplifier // disabled simplifier
);
CodeUnitFormat cuFormat = new CodeUnitFormat(formatOptions);
@ -628,9 +631,9 @@ class ProgramTextWriter {
if (options.isHTML()) {
Reference ref =
cu.getProgram()
.getReferenceManager()
.getPrimaryReferenceFrom(cuAddress,
i);
.getReferenceManager()
.getPrimaryReferenceFrom(cuAddress,
i);
addReferenceLinkedText(ref, opReps[i], true);
}
else {

View File

@ -0,0 +1,300 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.template;
import ghidra.GhidraOptions;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.util.HelpLocation;
/**
* Class for simplify names with template data. This class can be used with tool options or
* as a stand alone configurable simplifier.
*/
public class TemplateSimplifier {
public static final String SUB_OPTION_NAME = "Templates";
public static final String SIMPLIFY_TEMPLATES_OPTION =
SUB_OPTION_NAME + ".Simplify Templated Names";
public static final String TEMPLATE_NESTING_DEPTH_OPTION =
SUB_OPTION_NAME + ".Max Template Depth";
public static final String MAX_TEMPLATE_LENGTH_OPTION =
SUB_OPTION_NAME + ".Max Template Length";
public static final String MIN_TEMPLATE_LENGTH_OPTION =
SUB_OPTION_NAME + ".Min Template Length";
public static final String SIMPLY_TEMPLATES_DESCRIPTION =
"Determines whether to diplay templated names in a simplified form.";
public static final String TEMPLATE_NESTING_DEPTH_DESCRIPTION =
"Maximum template depth to display when simplify templated names.";
public static final String MAX_TEMPLATE_LENGTH_DESCRIPTION =
"Maximum number of characters to display in a template before truncating the name in the middle.";
public static final String MIN_TEMPLATE_LENGTH_DESCRIPTION =
"Minumum size of template to be simplified";
private boolean doSimplify = true;
private int templateNestingDepth = 0;
private int maxTemplateLength = 20;
private int minTemplateLength = 10;
/**
* Constructor to use for a TemplateSimplifier that doesn't use values from ToolOptions
*/
public TemplateSimplifier() {
// constructs using standard simplifying options.
}
/**
* Constructor to use for a TemplateSimplifier that operates using the current values in
* the tool options
* @param fieldOptions the "Listing Field" options
*/
public TemplateSimplifier(ToolOptions fieldOptions) {
checkForCorrectOptions(fieldOptions);
ensureRegistered(fieldOptions);
loadOptions(fieldOptions);
}
/**
* Sets the template nesting depth to be simplified. A depth of 0 simplifies the entire
* template portion of the name (everything in between <>). A depth of 1 leaves one level of
* template information
* @param depth the nesting depth
*/
public void setNestingDepth(int depth) {
this.templateNestingDepth = depth;
}
/**
* Returns the nesting depth for simplification
* @return the nesting depth for simplification
*/
public int getNestingDepth() {
return templateNestingDepth;
}
/**
* Sets the maximum length do display the template portion. If, after any nesting,
* simplification, the resulting template string is longer that the max length, the middle
* portion will be replaced with "..." to reduce the template string to the given max length.
* @param maxLength the max length of a template to display
*/
public void setMaxTemplateLength(int maxLength) {
this.maxTemplateLength = maxLength;
}
/**
* Gets the maximum length that a template will display.
* @return the maximum length that a template will display
*/
public int getMaxTemplateLength() {
return maxTemplateLength;
}
/**
* Sets if this TemplateSimplifier is enabled. If disabled, the {@link #simplify(String)}
* method will return the input string.
* @param doSimplify true to do simplification, false to do nothing
*/
public void setEnabled(boolean doSimplify) {
this.doSimplify = doSimplify;
}
/**
* Returns if this TemplateSimplifier is enabled.
* @return if this TemplateSimplifier is enabled
*/
public boolean isEnabled() {
return doSimplify;
}
/**
* Sets the minimum length for a template string to be simplified. In other words, template
* strings less than this length will not be changed.
* @param minLength the minimum length to simplify
*/
public void setMinimumTemplateLength(int minLength) {
this.minTemplateLength = minLength;
}
/**
* Returns the minimum length of a template string that will be simplified.
* @return the minimum length of a template string that will be simplified.
*/
public int getMinimumTemplateLength() {
return minTemplateLength;
}
/**
* Simplifies any template string in the given input base on the current simplification
* settings.
* @param input the input string to be simplified
* @return a simplified string
*/
public String simplify(String input) {
if (!doSimplify) {
return input;
}
return doSimplify(input, templateNestingDepth);
}
/**
* Reloads the current simplification settings from the given field options
* @param fieldOptions the options to retrieve the simplification settings.
*/
public void reloadFromOptions(ToolOptions fieldOptions) {
checkForCorrectOptions(fieldOptions);
loadOptions(fieldOptions);
}
/**
* Notification that options have changed
* @param options the options object that has changed values
* @param optionName the name of the options that changed
* @param oldValue the old value for the option that changed
* @param newValue the new value for the option that changed
* @return true if the option that changed was a template simplification option
*/
public boolean fieldOptionsChanged(Options options, String optionName, Object oldValue,
Object newValue) {
if (optionName.equals(SIMPLIFY_TEMPLATES_OPTION)) {
doSimplify = (Boolean) newValue;
return true;
}
if (optionName.equals(TEMPLATE_NESTING_DEPTH_OPTION)) {
templateNestingDepth = (Integer) newValue;
return true;
}
if (optionName.equals(MAX_TEMPLATE_LENGTH_OPTION)) {
maxTemplateLength = (Integer) newValue;
return true;
}
if (optionName.equals(MIN_TEMPLATE_LENGTH_OPTION)) {
minTemplateLength = (Integer) newValue;
return true;
}
return false;
}
private String doSimplify(String input, int depth) {
StringBuilder builder = new StringBuilder();
int pos = 0;
TemplateString ts;
while ((ts = findTemplateString(input, pos)) != null) {
builder.append(input.substring(pos, ts.start));
String template = ts.getTemplate();
if (depth == 0) {
builder.append("<");
if (template.length() <= minTemplateLength) {
builder.append(template);
}
builder.append(">");
}
else {
builder.append("<");
String simplifiedTemplate = doSimplify(template, depth - 1);
if (simplifiedTemplate.length() > maxTemplateLength) {
simplifiedTemplate = middleTruncate(template);
}
builder.append(simplifiedTemplate);
builder.append(">");
}
pos = ts.end + 1;
}
builder.append(input.substring(pos));
return builder.toString();
}
private String middleTruncate(String input) {
int partSize = maxTemplateLength / 2;
return input.substring(0, partSize) + "..." + input.substring(input.length() - partSize);
}
private static TemplateString findTemplateString(String input, int pos) {
for (int i = pos; i < input.length(); i++) {
char c = input.charAt(i);
if (c == '<') {
int end = findMatchingEnd(input, i + 1);
if (end > i) {
return new TemplateString(input, i, end);
}
}
}
return null;
}
private static int findMatchingEnd(String input, int start) {
int depth = 0;
for (int i = start; i < input.length(); i++) {
char c = input.charAt(i);
if (c == '>') {
if (depth == 0) {
return i;
}
depth--;
}
else if (c == '<') {
depth++;
}
}
return -1;
}
private record TemplateString(String input, int start, int end) {
String getTemplate() {
return input.substring(start + 1, end); // don't include the enclosing <> chars
}
}
private void loadOptions(ToolOptions options) {
doSimplify = options.getBoolean(SIMPLIFY_TEMPLATES_OPTION, doSimplify);
templateNestingDepth = options.getInt(TEMPLATE_NESTING_DEPTH_OPTION, templateNestingDepth);
maxTemplateLength = options.getInt(MAX_TEMPLATE_LENGTH_OPTION, maxTemplateLength);
minTemplateLength = options.getInt(MIN_TEMPLATE_LENGTH_OPTION, minTemplateLength);
}
private void checkForCorrectOptions(ToolOptions fieldOptions) {
if (!GhidraOptions.CATEGORY_BROWSER_FIELDS.equals(fieldOptions.getName())) {
throw new IllegalArgumentException(
"Expected options named \"" + GhidraOptions.CATEGORY_BROWSER_FIELDS + "\", not \"" +
fieldOptions.getName() + "\"");
}
}
private void ensureRegistered(Options options) {
if (options.isRegistered(SIMPLIFY_TEMPLATES_OPTION)) {
return;
}
HelpLocation help = new HelpLocation("CodeBrowserPlugin", "Template Display Options");
options.getOptions(SUB_OPTION_NAME).setOptionsHelpLocation(help);
options.registerOption(SIMPLIFY_TEMPLATES_OPTION, doSimplify, help,
SIMPLY_TEMPLATES_DESCRIPTION);
options.registerOption(TEMPLATE_NESTING_DEPTH_OPTION, templateNestingDepth, help,
TEMPLATE_NESTING_DEPTH_DESCRIPTION);
options.registerOption(MAX_TEMPLATE_LENGTH_OPTION, maxTemplateLength, help,
MAX_TEMPLATE_LENGTH_DESCRIPTION);
options.registerOption(MIN_TEMPLATE_LENGTH_OPTION, minTemplateLength, help,
MIN_TEMPLATE_LENGTH_DESCRIPTION);
}
}

View File

@ -20,6 +20,7 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import ghidra.GhidraOptions;
import ghidra.app.util.template.TemplateSimplifier;
import ghidra.framework.options.*;
import ghidra.program.model.listing.CodeUnitFormatOptions;
import ghidra.util.HelpLocation;
@ -103,7 +104,7 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
BrowserCodeUnitFormatOptions(ToolOptions fieldOptions, boolean autoUpdate) {
this.fieldOptions = fieldOptions;
this.displayOptions = new OptionsBasedDataTypeDisplayOptions(fieldOptions);
templateSimplifier = new TemplateSimplifier(fieldOptions);
boolean exists = fieldOptions.isRegistered(NAMESPACE_OPTIONS);
if (!exists) {
@ -144,7 +145,10 @@ public class BrowserCodeUnitFormatOptions extends CodeUnitFormatOptions
@Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) {
if (optionName.equals(GhidraOptions.SHOW_BLOCK_NAME_OPTION) ||
if (templateSimplifier.fieldOptionsChanged(options, optionName, oldValue, newValue)) {
notifyListeners();
}
else if (optionName.equals(GhidraOptions.SHOW_BLOCK_NAME_OPTION) ||
optionName.equals(REGISTER_VARIABLE_MARKUP_OPTION) ||
optionName.equals(STACK_VARIABLE_MARKUP_OPTION) ||
optionName.equals(INFERRED_VARIABLE_MARKUP_OPTION) ||

View File

@ -21,6 +21,7 @@ import java.math.BigInteger;
import docking.widgets.fieldpanel.support.FieldLocation;
import generic.theme.Gui;
import ghidra.app.util.HighlightProvider;
import ghidra.app.util.template.TemplateSimplifier;
import ghidra.app.util.viewer.format.FieldFormatModel;
import ghidra.app.util.viewer.proxy.ProxyObj;
import ghidra.framework.options.Options;
@ -54,6 +55,7 @@ public abstract class FieldFactory implements ExtensionPoint {
protected String colorOptionName;
protected String styleOptionName;
private TemplateSimplifier templateSimplifier;
/**
* Base constructor
@ -72,14 +74,14 @@ public abstract class FieldFactory implements ExtensionPoint {
styleOptionName = name + " Style";
width = 100;
templateSimplifier = model.getFormatManager().getTemplateSimplifier();
initDisplayOptions(displayOptions);
initFieldOptions(fieldOptions);
}
protected void initFieldOptions(Options fieldOptions) {
fieldOptions.getOptions(name)
.setOptionsHelpLocation(new HelpLocation("CodeBrowserPlugin", name));
.setOptionsHelpLocation(new HelpLocation("CodeBrowserPlugin", name));
}
protected void initDisplayOptions(Options displayOptions) {
@ -314,4 +316,8 @@ public abstract class FieldFactory implements ExtensionPoint {
fontMetrics[i] = Toolkit.getDefaultToolkit().getFontMetrics(font);
}
}
protected String simplifyTemplates(String input) {
return templateSimplifier.simplify(input);
}
}

View File

@ -59,7 +59,7 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
* @param fieldOptions the Options for field specific properties.
*/
public FunctionSignatureFieldFactory(FieldFormatModel model, HighlightProvider hlProvider,
Options displayOptions, Options fieldOptions) {
ToolOptions displayOptions, ToolOptions fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
fieldOptions.registerOption(DISPLAY_NAMESPACE, false, null,
@ -100,7 +100,7 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
elementIndex++;
}
// noreturn
// no return
if (function.hasNoReturn()) {
as = new AttributedString(Function.NORETURN + " ", FunctionColors.RETURN_TYPE,
getMetrics());
@ -110,7 +110,9 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
}
// return type
as = new AttributedString(function.getReturn().getFormalDataType().getDisplayName() + " ",
String returnTypeName = function.getReturn().getFormalDataType().getDisplayName();
returnTypeName = simplifyTemplates(returnTypeName);
as = new AttributedString(returnTypeName + " ",
FunctionColors.RETURN_TYPE, getMetrics());
textElements.add(new FunctionReturnTypeFieldElement(as, elementIndex, 0, startCol));
startCol += as.length();
@ -126,14 +128,14 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
as = new AttributedString(callingConvention + " ", FunctionColors.RETURN_TYPE,
getMetrics());
textElements
.add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol));
.add(new FunctionCallingConventionFieldElement(as, elementIndex, 0, startCol));
startCol += as.length();
elementIndex++;
}
// function name
as = new AttributedString(function.getName(displayFunctionScope),
getFunctionNameColor(function), getMetrics());
String functionName = simplifyTemplates(function.getName(displayFunctionScope));
as = new AttributedString(functionName, getFunctionNameColor(function), getMetrics());
textElements.add(new FunctionNameFieldElement(as, elementIndex, 0, startCol));
startCol += as.length();
elementIndex++;
@ -159,15 +161,15 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
Color pcolor =
params[i].isAutoParameter() ? FunctionColors.PARAM_AUTO : FunctionColors.PARAM;
String text = params[i].getFormalDataType().getDisplayName() + " ";
as = new AttributedString(text, pcolor, getMetrics());
String dtName = simplifyTemplates(params[i].getFormalDataType().getDisplayName() + " ");
as = new AttributedString(dtName, pcolor, getMetrics());
textElements.add(
new FunctionParameterFieldElement(as, elementIndex, paramOffset, startCol, i));
startCol += as.length();
paramOffset += as.length();
elementIndex++;
text = params[i].getName();
String text = params[i].getName();
as = new AttributedString(text, pcolor, getMetrics());
textElements.add(
new FunctionParameterNameFieldElement(as, elementIndex, paramOffset, startCol, i));
@ -381,7 +383,6 @@ public class FunctionSignatureFieldFactory extends FieldFactory {
@Override
public void fieldOptionsChanged(Options options, String optionName, Object oldValue,
Object newValue) {
if (optionName.equals(DISPLAY_NAMESPACE)) {
displayFunctionScope = ((Boolean) newValue).booleanValue();
model.update();

View File

@ -250,27 +250,26 @@ public class LabelFieldFactory extends FieldFactory {
private String checkLabelString(Symbol symbol, Program program) {
if (!displayLocalNamespace && !displayNonLocalNamespace) {
return symbol.getName(); // no namespaces being shown
return simplifyTemplates(symbol.getName()); // no namespaces being shown
}
Namespace addressNamespace = program.getSymbolTable().getNamespace(symbol.getAddress());
Namespace symbolNamespace = symbol.getParentNamespace();
boolean isLocal = symbolNamespace.equals(addressNamespace);
if (!isLocal) {
return symbol.getName(displayNonLocalNamespace);
return simplifyTemplates(symbol.getName(displayNonLocalNamespace));
}
// O.K., we ARE a local namespace, how to display it?
if (!displayLocalNamespace) {
return symbol.getName();
return simplifyTemplates(symbol.getName());
}
// use the namespace name or a custom, user-defined value
if (useLocalPrefixOverride) {
return localPrefixText + symbol.getName(false);
return simplifyTemplates(localPrefixText + symbol.getName(false));
}
return symbol.getName(true);
return simplifyTemplates(symbol.getName(true));
}
private List<Address> getOffcutReferenceAddress(CodeUnit cu) {

View File

@ -491,6 +491,7 @@ abstract class OperandFieldHelper extends FieldFactory {
}
ColorStyleAttributes attributes = getOpAttributes(opElem, inst, opIndex);
AttributedString as = new AttributedString(opElem.toString(), attributes.colorAttribute,
getMetrics(attributes.styleAttribute), underline, ListingColors.UNDERLINE);
elements.add(new OperandFieldElement(as, opIndex, subOpIndex, characterOffset));

View File

@ -25,7 +25,6 @@ import ghidra.app.util.HighlightProvider;
import ghidra.app.util.viewer.format.FieldFormatModel;
import ghidra.app.util.viewer.proxy.FunctionProxy;
import ghidra.app.util.viewer.proxy.ProxyObj;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Library;
@ -56,7 +55,7 @@ public class ThunkedFunctionFieldFactory extends FieldFactory {
* @param fieldOptions the Options for field specific properties.
*/
public ThunkedFunctionFieldFactory(FieldFormatModel model, HighlightProvider hlProvider,
ToolOptions displayOptions, Options fieldOptions) {
ToolOptions displayOptions, ToolOptions fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
}
@ -96,8 +95,9 @@ public class ThunkedFunctionFieldFactory extends FieldFactory {
as = new AttributedString("Thunked-Function: ", ListingColors.SEPARATOR, getMetrics());
textElements.add(new TextFieldElement(as, elementIndex++, 0));
as = new AttributedString(thunkedFunction.getName(true),
getThunkedFunctionNameColor(thunkedFunction), getMetrics());
String functionName = simplifyTemplates(thunkedFunction.getName(true));
as = new AttributedString(functionName, getThunkedFunctionNameColor(thunkedFunction),
getMetrics());
textElements.add(new TextFieldElement(as, elementIndex++, 0));
return ListingTextField.createSingleLineTextField(this, proxy,

View File

@ -23,7 +23,6 @@ import ghidra.app.util.HighlightProvider;
import ghidra.app.util.viewer.format.FieldFormatModel;
import ghidra.app.util.viewer.proxy.ProxyObj;
import ghidra.app.util.viewer.proxy.VariableProxy;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Parameter;
@ -52,7 +51,7 @@ public class VariableTypeFieldFactory extends AbstractVariableFieldFactory {
* @param fieldOptions the Options for field specific properties.
*/
private VariableTypeFieldFactory(FieldFormatModel model, HighlightProvider hlProvider,
Options displayOptions, Options fieldOptions) {
ToolOptions displayOptions, ToolOptions fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
}
@ -65,24 +64,31 @@ public class VariableTypeFieldFactory extends AbstractVariableFieldFactory {
if (!enabled || !(obj instanceof Variable)) {
return null;
}
Variable sv = (Variable) obj;
Variable variable = (Variable) obj;
DataType dt;
if (sv instanceof Parameter) {
dt = ((Parameter) sv).getFormalDataType();
if (variable instanceof Parameter) {
dt = ((Parameter) variable).getFormalDataType();
}
else {
dt = sv.getDataType();
dt = variable.getDataType();
}
String dtName = (dt != null) ? dt.getDisplayName() : null;
String dtName = getDataTypeName(dt);
AttributedString as =
new AttributedString((dtName != null) ? dtName : "", getColor(sv), getMetrics(sv));
new AttributedString(dtName, getColor(variable), getMetrics(variable));
FieldElement field = new TextFieldElement(as, 0, 0);
return ListingTextField.createSingleLineTextField(this, proxy, field, startX + varWidth,
width, hlProvider);
}
private String getDataTypeName(DataType dt) {
if (dt == null) {
return "";
}
String dtName = dt.getName();
return dtName == null ? "" : simplifyTemplates(dtName);
}
/**
* @see ghidra.app.util.viewer.field.FieldFactory#getProgramLocation(int, int, ghidra.app.util.viewer.field.ListingField)
*/

View File

@ -23,6 +23,7 @@ import org.jdom.Element;
import docking.widgets.fieldpanel.support.Highlight;
import ghidra.app.util.HighlightProvider;
import ghidra.app.util.template.TemplateSimplifier;
import ghidra.app.util.viewer.field.*;
import ghidra.framework.options.*;
import ghidra.framework.plugintool.ServiceProvider;
@ -67,6 +68,7 @@ public class FormatManager implements OptionsChangeListener {
private ServiceProvider serviceProvider;
private int arrayValuesPerLine = 1;
private boolean groupArrayElements = true;
TemplateSimplifier templateSimplifier;
// NOTE: Unused custom format code was removed. The custom format code last existed in
// commit #204e7892bf2f110ebb05ca4beee3fe5b397f88c9.
@ -80,6 +82,7 @@ public class FormatManager implements OptionsChangeListener {
public FormatManager(ToolOptions displayOptions, ToolOptions fieldOptions) {
this.fieldOptions = fieldOptions;
this.displayOptions = displayOptions;
this.templateSimplifier = new TemplateSimplifier(fieldOptions);
highlightProvider = new MultipleHighlighterProvider();
getFactorys();
for (int i = 0; i < NUM_MODELS; i++) {
@ -153,7 +156,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Adds a listener to be notified when a format changes.
*
* @param listener the listener to be added.
* @param listener the listener to be added
*/
public void addFormatModelListener(FormatModelListener listener) {
formatListeners.add(listener);
@ -171,6 +174,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the total number of model in the format manager.
* @return the total number of model in the format manager
*/
public int getNumModels() {
return NUM_MODELS;
@ -180,27 +184,31 @@ public class FormatManager implements OptionsChangeListener {
* Returns the format model for the given index.
*
* @param index the index of the format model to return.
* @return the format model for the given index
*/
public FieldFormatModel getModel(int index) {
return models[index];
}
/**
* Returns the format model for the address break (divider)
* Returns the format model for the address break (divider).
* @return the format model for the address break (divider)
*/
public FieldFormatModel getDividerModel() {
return models[FieldFormatModel.DIVIDER];
}
/**
* Returns the format model for the plate field
* Returns the format model for the plate field.
* @return the format model for the plate field
*/
public FieldFormatModel getPlateFormat() {
return models[FieldFormatModel.PLATE];
}
/**
* Returns the format model for the function signature
* Returns the format model for the function signature.
* @return the format model for the function signature
*/
public FieldFormatModel getFunctionFormat() {
return models[FieldFormatModel.FUNCTION];
@ -208,6 +216,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the format model for the function variables.
* @return the format model for the function variables
*/
public FieldFormatModel getFunctionVarFormat() {
return models[FieldFormatModel.FUNCTION_VARS];
@ -215,6 +224,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the format model for a code unit.
* @return the format model for a code unit
*/
public FieldFormatModel getCodeUnitFormat() {
return models[FieldFormatModel.INSTRUCTION_OR_DATA];
@ -261,6 +271,7 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the Options used for display properties.
* @return the Options used for display properties.
*/
public ToolOptions getDisplayOptions() {
return displayOptions;
@ -268,11 +279,20 @@ public class FormatManager implements OptionsChangeListener {
/**
* Returns the Options used for field specific properties.
* @return the Options used for field specific properties
*/
public ToolOptions getFieldOptions() {
return fieldOptions;
}
/**
* Returns the template simplifier.
* @return the template simplifier.
*/
public TemplateSimplifier getTemplateSimplifier() {
return templateSimplifier;
}
/**
* Notifies listeners that the given model has changed.
*
@ -852,6 +872,7 @@ public class FormatManager implements OptionsChangeListener {
}
}
else if (options == fieldOptions) {
templateSimplifier.fieldOptionsChanged(options, name, oldValue, newValue);
for (int i = 0; i < NUM_MODELS; i++) {
models[i].fieldOptionsChanged(options, name, oldValue, newValue);
}

View File

@ -322,17 +322,19 @@ public class CodeUnitFormat {
}
else if (options.includeInferredVariableMarkup) {
boolean isRead = isRead(reg, instr);
Variable regVar = program.getFunctionManager().getReferencedVariable(
instr.getMinAddress(), reg.getAddress(), reg.getMinimumByteSize(), isRead);
Variable regVar = program.getFunctionManager()
.getReferencedVariable(
instr.getMinAddress(), reg.getAddress(), reg.getMinimumByteSize(), isRead);
if (regVar != null) {
// TODO: If register appears more than once, how can we distinguish read vs. write occurrence in operands
if (isRead && isWritten(reg, instr) && !hasRegisterWriteReference(instr, reg) &&
instr.getRegister(opIndex) != null) {
// If register both read and written and there are no write references for this instruction
// see if there is only one reference to choose from - if not we can't determine how to markup
Variable regWriteVar = program.getFunctionManager().getReferencedVariable(
instr.getMinAddress(), reg.getAddress(), reg.getMinimumByteSize(),
false);
Variable regWriteVar = program.getFunctionManager()
.getReferencedVariable(
instr.getMinAddress(), reg.getAddress(), reg.getMinimumByteSize(),
false);
if (regWriteVar != regVar) {
continue; // TODO: tough case - not which operand is read vs. write!
}
@ -630,8 +632,10 @@ public class CodeUnitFormat {
}
Variable regVar =
instr.getProgram().getFunctionManager().getReferencedVariable(instr.getMinAddress(),
associatedRegister.getAddress(), associatedRegister.getMinimumByteSize(), true);
instr.getProgram()
.getFunctionManager()
.getReferencedVariable(instr.getMinAddress(),
associatedRegister.getAddress(), associatedRegister.getMinimumByteSize(), true);
if (regVar == null) {
return false;
}
@ -1151,8 +1155,10 @@ public class CodeUnitFormat {
public String getReferenceRepresentationString(CodeUnit fromCodeUnit, Reference ref) {
// NOTE: The isRead param is false since it really only pertains to register references which should
// generally only correspond to writes
Variable refVar = fromCodeUnit.getProgram().getFunctionManager().getReferencedVariable(
fromCodeUnit.getMinAddress(), ref.getToAddress(), 0, false);
Variable refVar = fromCodeUnit.getProgram()
.getFunctionManager()
.getReferencedVariable(
fromCodeUnit.getMinAddress(), ref.getToAddress(), 0, false);
Object repObj = getReferenceRepresentation(fromCodeUnit, ref, refVar);
return repObj != null ? repObj.toString() : null;
}
@ -1367,7 +1373,13 @@ public class CodeUnitFormat {
}
}
String name = symbol.getName();
return addNamespace(program, symbol.getParentNamespace(), name, markupAddress);
String displayName =
addNamespace(program, symbol.getParentNamespace(), name, markupAddress);
return simplifyTemplate(displayName);
}
private String simplifyTemplate(String name) {
return options.simplifyTemplate(name);
}
private boolean isStringData(CodeUnit cu) {
@ -1379,7 +1391,7 @@ public class CodeUnitFormat {
private String getLabelStringForStringData(Data data, Symbol symbol) {
if (!symbol.isDynamic()) {
return symbol.getName();
return options.simplifyTemplate(symbol.getName());
}
DataType dataType = data.getBaseDataType();
@ -1440,7 +1452,7 @@ public class CodeUnitFormat {
Symbol containingSymbol = program.getSymbolTable().getPrimarySymbol(instructionAddress);
if (containingSymbol != null) {
return containingSymbol.getName() + PLUS + diff;
return options.simplifyTemplate(containingSymbol.getName()) + PLUS + diff;
}
return getDefaultOffcutString(offsym, instruction, diff, false);
}
@ -1464,10 +1476,11 @@ public class CodeUnitFormat {
protected String getDefaultOffcutString(Symbol symbol, CodeUnit cu, long diff,
boolean decorate) {
String name = options.simplifyTemplate(symbol.getName());
if (decorate) {
return symbol.getName() + ' ' + '(' + cu.getMinAddress() + PLUS + diff + ')';
return name + ' ' + '(' + cu.getMinAddress() + PLUS + diff + ')';
}
return symbol.getName();
return name;
}
/**

View File

@ -15,6 +15,7 @@
*/
package ghidra.program.model.listing;
import ghidra.app.util.template.TemplateSimplifier;
import ghidra.program.model.data.DataTypeDisplayOptions;
public class CodeUnitFormatOptions {
@ -80,9 +81,11 @@ public class CodeUnitFormatOptions {
protected volatile boolean showOffcutInfo = true;
protected DataTypeDisplayOptions displayOptions = DataTypeDisplayOptions.DEFAULT;
protected TemplateSimplifier templateSimplifier;
public CodeUnitFormatOptions() {
// use default options;
templateSimplifier = new TemplateSimplifier();
}
/**
@ -93,6 +96,7 @@ public class CodeUnitFormatOptions {
public CodeUnitFormatOptions(ShowBlockName showBlockName, ShowNamespace showNamespace) {
this.showBlockName = showBlockName;
this.showNamespace = showNamespace;
templateSimplifier = new TemplateSimplifier();
}
/**
@ -119,7 +123,7 @@ public class CodeUnitFormatOptions {
String localPrefixOverride, boolean doRegVariableMarkup, boolean doStackVariableMarkup,
boolean includeInferredVariableMarkup, boolean alwaysShowPrimaryReference,
boolean includeScalarReferenceAdjustment, boolean showLibraryInNamespace,
boolean followReferencedPointers) {
boolean followReferencedPointers, TemplateSimplifier templateSimplifier) {
this.showBlockName = showBlockName;
this.showNamespace = showNamespace;
this.showLibraryInNamespace = showLibraryInNamespace;
@ -130,6 +134,7 @@ public class CodeUnitFormatOptions {
this.alwaysShowPrimaryReference = alwaysShowPrimaryReference;
this.followReferencedPointers = followReferencedPointers;
this.includeScalarReferenceAdjustment = includeScalarReferenceAdjustment;
this.templateSimplifier = templateSimplifier;
}
/**
@ -139,4 +144,8 @@ public class CodeUnitFormatOptions {
public ShowBlockName getShowBlockNameOption() {
return showBlockName;
}
public String simplifyTemplate(String name) {
return templateSimplifier.simplify(name);
}
}

View File

@ -0,0 +1,115 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.template;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.framework.options.ToolOptions;
public class TemplateSimplifierTest extends AbstractGenericTest {
private TemplateSimplifier simplifier = new TemplateSimplifier();
@Before
public void setUp() {
simplifier.setMinimumTemplateLength(0);
simplifier.setNestingDepth(0);
simplifier.setEnabled(true);
}
@Test
public void testSimplifyTemplates() {
assertEquals("bob<>", simplify("bob<hey>"));
assertEquals("bob<>", simplify("bob<foo<hey>>"));
assertEquals("bob<foo<>", simplify("bob<foo<bar>"));
assertEquals("bob<>", simplify("bob<foo<bar<hey>>>"));
}
@Test
public void testSimplifyTemplatesDepth1() {
simplifier.setNestingDepth(1);
assertEquals("bob<hey>", simplify("bob<hey>"));
assertEquals("bob<foo<>>", simplify("bob<foo<hey>>"));
assertEquals("bob<foo<bar>", simplify("bob<foo<bar>"));
assertEquals("bob<foo<>>", simplify("bob<foo<bar<hey>>>"));
}
@Test
public void testSimplifyTemplatesDepth2() {
simplifier.setNestingDepth(2);
assertEquals("bob<hey>", simplify("bob<hey>"));
assertEquals("bob<foo<hey>>", simplify("bob<foo<hey>>"));
assertEquals("bob<foo<bar>", simplify("bob<foo<bar>"));
assertEquals("bob<foo<bar<>>>", simplify("bob<foo<bar<hey>>>"));
}
@Test
public void testStripTemplatesWithMaxSize() {
simplifier.setMaxTemplateLength(10);
simplifier.setNestingDepth(5);
assertEquals("bob<abcde...vwxyz>", simplify("bob<abcdefghijklmnopqrstuvwxyz>"));
}
@Test
public void testStripTemplatesWithMaxSizeAndNestedTemplates() {
simplifier.setMaxTemplateLength(10);
simplifier.setNestingDepth(5);
assertEquals("bob<int, ...wxyz>>",
simplify("bob<int, foo<abcdefghijklmnopqrstuvwxyz>>"));
}
@Test
public void testMinSizeToSimplify() {
simplifier.setMinimumTemplateLength(5);
assertEquals("bob<abcde>", simplify("bob<abcde>"));
assertEquals("bob<>", simplify("bob<abcdef>"));
}
@Test
public void testOptionsGetRegistered() {
ToolOptions options = new ToolOptions("Listing Fields");
simplifier = new TemplateSimplifier(options);
assertTrue(options.isRegistered(TemplateSimplifier.SIMPLIFY_TEMPLATES_OPTION));
assertTrue(options.isRegistered(TemplateSimplifier.MAX_TEMPLATE_LENGTH_OPTION));
assertTrue(options.isRegistered(TemplateSimplifier.TEMPLATE_NESTING_DEPTH_OPTION));
assertTrue(options.isRegistered(TemplateSimplifier.MIN_TEMPLATE_LENGTH_OPTION));
}
@Test
public void testReadsOptions() {
ToolOptions options = new ToolOptions("Listing Fields");
options.setBoolean(TemplateSimplifier.SIMPLIFY_TEMPLATES_OPTION, false);
options.setInt(TemplateSimplifier.MAX_TEMPLATE_LENGTH_OPTION, 33);
options.setInt(TemplateSimplifier.TEMPLATE_NESTING_DEPTH_OPTION, 3);
options.setInt(TemplateSimplifier.MIN_TEMPLATE_LENGTH_OPTION, 7);
simplifier = new TemplateSimplifier(options);
assertEquals(false, simplifier.isEnabled());
assertEquals(33, simplifier.getMaxTemplateLength());
assertEquals(3, simplifier.getNestingDepth());
assertEquals(7, simplifier.getMinimumTemplateLength());
}
private String simplify(String in) {
return simplifier.simplify(in);
}
}