GP-1981 - Theming - Decompiler Module

This commit is contained in:
dragonmacher 2022-09-09 16:38:55 -04:00 committed by ghidragon
parent 466db9efe3
commit 2dade60b3e
16 changed files with 175 additions and 137 deletions

View file

@ -13,6 +13,24 @@ color.fg.decompiler.global = darkCyan
color.bg.decompiler.middle.mouse = rgba(255,255,0,.5) color.bg.decompiler.middle.mouse = rgba(255,255,0,.5)
color.bg.decompiler.current.variable = rgba(255,255,0,0.5) color.bg.decompiler.current.variable = rgba(255,255,0,0.5)
color.fg.line.numbers = gray
color.bg.decompiler.highlights.default = rgba(255, 255, 0, .5)
color.bg.decompiler.highlights.special = sandybrown
color.bg.decompiler.highlights.search = mediumslateblue
color.bg.decompiler.pcode.dfg.vertex.default = red
color.bg.decompiler.pcode.dfg.vertex.selected = deeppink
color.bg.decompiler.pcode.dfg.vertex.constant = darkgreen
color.bg.decompiler.pcode.dfg.vertex.register = navy
color.bg.decompiler.pcode.dfg.vertex.unique = black
color.bg.decompiler.pcode.dfg.vertex.persistent = darkorange
color.bg.decompiler.pcode.dfg.vertex.address.tied = orange
color.bg.decompiler.pcode.dfg.vertex.op = red
color.bg.decompiler.pcode.dfg.edge.default = navy
color.bg.decompiler.pcode.dfg.edge.selected = deeppink
color.bg.decompiler.pcode.dfg.edge.within.block = black
color.bg.decompiler.pcode.dfg.edge.between.blocks = red
[Dark Defaults] [Dark Defaults]

View file

@ -54,18 +54,11 @@
import java.io.File; import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import classrecovery.DecompilerScriptUtils; import classrecovery.*;
import classrecovery.RTTIClassRecoverer; import generic.theme.GThemeDefaults.Colors.Palette;
import classrecovery.RTTIGccClassRecoverer;
import classrecovery.RTTIWindowsClassRecoverer;
import classrecovery.RecoveredClass;
import classrecovery.RecoveredClassHelper;
import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompInterface;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.plugin.core.analysis.DecompilerFunctionAnalyzer; import ghidra.app.plugin.core.analysis.DecompilerFunctionAnalyzer;
@ -81,29 +74,11 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.ElfLoader; import ghidra.app.util.opinion.ElfLoader;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.*;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Parameter;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.service.graph.AttributedEdge; import ghidra.service.graph.*;
import ghidra.service.graph.AttributedGraph;
import ghidra.service.graph.AttributedVertex;
import ghidra.service.graph.GraphDisplay;
import ghidra.service.graph.GraphDisplayOptions;
import ghidra.service.graph.GraphDisplayOptionsBuilder;
import ghidra.service.graph.GraphDisplayProvider;
import ghidra.service.graph.GraphType;
import ghidra.service.graph.GraphTypeBuilder;
import ghidra.service.graph.VertexShape;
import ghidra.util.WebColors;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.GraphException; import ghidra.util.exception.GraphException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -408,7 +383,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
mgr.startAnalysis(monitor, false); mgr.startAnalysis(monitor, false);
} }
/** /**
* Method to create a class hierarchy graph where the parents are at the top of the graph and * Method to create a class hierarchy graph where the parents are at the top of the graph and
* the children at the bottom. Classes with no parents have blue nodes. Classes with a single * the children at the bottom. Classes with no parents have blue nodes. Classes with a single
@ -486,7 +460,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
edge.setEdgeType(NON_VIRTUAL_INHERITANCE); edge.setEdgeType(NON_VIRTUAL_INHERITANCE);
} }
} }
} }
@ -508,13 +481,13 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
display = service.getGraphDisplay(false, TaskMonitor.DUMMY); display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType()) GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType())
.vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE) .vertex(NO_INHERITANCE, VertexShape.RECTANGLE, Palette.BLUE)
.vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN) .vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, Palette.GREEN)
.vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED) .vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, Palette.RED)
.edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN) .edge(NON_VIRTUAL_INHERITANCE, Palette.LIME)
.edge(VIRTUAL_INHERITANCE, WebColors.ORANGE) .edge(VIRTUAL_INHERITANCE, Palette.ORANGE)
.defaultVertexColor(WebColors.PURPLE) .defaultVertexColor(Palette.PURPLE)
.defaultEdgeColor(WebColors.PURPLE) .defaultEdgeColor(Palette.PURPLE)
.defaultLayoutAlgorithm("Compact Hierarchical") .defaultLayoutAlgorithm("Compact Hierarchical")
.build(); .build();
@ -534,7 +507,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return doOutput; return doOutput;
} }
private void printClassHierarchyLists(List<RecoveredClass> recoveredClasses) private void printClassHierarchyLists(List<RecoveredClass> recoveredClasses)
throws CancelledException { throws CancelledException {
@ -551,9 +523,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
/** /**
* Script works on versions of ghidra including and after 9.2 except for 9.2.1 because a method * Script works on versions of ghidra including and after 9.2 except for 9.2.1 because a method
* was accidentally removed from FillOutStructureCmd that is needed * was accidentally removed from FillOutStructureCmd that is needed
@ -579,7 +548,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
boolean isCompilerSpecGcc = boolean isCompilerSpecGcc =
currentProgram.getCompilerSpec().getCompilerSpecID().getIdAsString().equalsIgnoreCase( currentProgram.getCompilerSpec()
.getCompilerSpecID()
.getIdAsString()
.equalsIgnoreCase(
"gcc"); "gcc");
if (isCompilerSpecGcc) { if (isCompilerSpecGcc) {
return true; return true;
@ -598,7 +570,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
byte[] gccBytes = { (byte) 0x47, (byte) 0x43, (byte) 0x43, (byte) 0x3a }; byte[] gccBytes = { (byte) 0x47, (byte) 0x43, (byte) 0x43, (byte) 0x3a };
byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
Address found = currentProgram.getMemory().findBytes(commentBlock.getStart(), Address found = currentProgram.getMemory()
.findBytes(commentBlock.getStart(),
commentBlock.getEnd(), gccBytes, maskBytes, true, monitor); commentBlock.getEnd(), gccBytes, maskBytes, true, monitor);
if (found == null) { if (found == null) {
isGcc = false; isGcc = false;
@ -621,8 +594,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return isWindows; return isWindows;
} }
/** /**
* Method to determine if somehow the constructor list and destructor list for a class contain * Method to determine if somehow the constructor list and destructor list for a class contain
* overlapping functions * overlapping functions
@ -637,11 +608,17 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
recoverClassesFromRTTI.getAllClassDestructors(recoveredClass); recoverClassesFromRTTI.getAllClassDestructors(recoveredClass);
List<Function> commonFunctions1 = List<Function> commonFunctions1 =
allClassConstructors.stream().distinct().filter(allClassDestructors::contains).collect( allClassConstructors.stream()
.distinct()
.filter(allClassDestructors::contains)
.collect(
Collectors.toList()); Collectors.toList());
List<Function> commonFunctions2 = List<Function> commonFunctions2 =
allClassDestructors.stream().distinct().filter(allClassConstructors::contains).collect( allClassDestructors.stream()
.distinct()
.filter(allClassConstructors::contains)
.collect(
Collectors.toList()); Collectors.toList());
if (commonFunctions1.isEmpty() && commonFunctions2.isEmpty()) { if (commonFunctions1.isEmpty() && commonFunctions2.isEmpty()) {
@ -661,8 +638,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
analyzer.added(currentProgram, set, monitor, new MessageLog()); analyzer.added(currentProgram, set, monitor, new MessageLog());
} }
/** /**
* Get the version of Ghidra that was used to analyze this program * Get the version of Ghidra that was used to analyze this program
* @return a string containing the version number of Ghidra used to analyze the current program * @return a string containing the version number of Ghidra used to analyze the current program
@ -673,7 +648,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return options.getString("Created With Ghidra Version", null); return options.getString("Created With Ghidra Version", null);
} }
/** /**
* Method to bookmark all of the constructor/destructor/indeterminate functions * Method to bookmark all of the constructor/destructor/indeterminate functions
* @param recoveredClasses List of classes * @param recoveredClasses List of classes
@ -686,7 +660,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
bookmarkRemainingIndeterminateConstructorsAndDestructors(recoveredClasses); bookmarkRemainingIndeterminateConstructorsAndDestructors(recoveredClasses);
} }
/** /**
* Method to print class hierarchy of the form child : parent: grandparent : etc... * Method to print class hierarchy of the form child : parent: grandparent : etc...
* @param stringBuffer the buffer to add the newly created string to * @param stringBuffer the buffer to add the newly created string to
@ -707,7 +680,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
Map<RecoveredClass, List<RecoveredClass>> classHierarchyMap = Map<RecoveredClass, List<RecoveredClass>> classHierarchyMap =
recoveredClass.getClassHierarchyMap(); recoveredClass.getClassHierarchyMap();
List<RecoveredClass> parents = new ArrayList<RecoveredClass>(classHierarchyMap.keySet()); List<RecoveredClass> parents = new ArrayList<>(classHierarchyMap.keySet());
// if single inheritance - simple linear case // if single inheritance - simple linear case
if (recoveredClass.hasSingleInheritance()) { if (recoveredClass.hasSingleInheritance()) {
@ -742,9 +715,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
/** /**
* Method to retrieve the AddressSet of the current program's initialized memory * Method to retrieve the AddressSet of the current program's initialized memory
* @return the AddressSet of the current program's initialized memory * @return the AddressSet of the current program's initialized memory
@ -765,8 +735,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return dataAddresses; return dataAddresses;
} }
/** /**
* Method to bookmark found constructor functions * Method to bookmark found constructor functions
* @param recoveredClasses List of classes * @param recoveredClasses List of classes
@ -810,7 +778,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
/** /**
* Method to add/append analysis bookmarks with the given comment to the given list of functions * Method to add/append analysis bookmarks with the given comment to the given list of functions
* @param functions List of functions * @param functions List of functions
@ -831,7 +798,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
/** /**
* Method to optionally print to console or output to file various types of class information * Method to optionally print to console or output to file various types of class information
* depending on the options set at top of script * depending on the options set at top of script
@ -894,7 +860,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
private void outputClassDefinitions(List<RecoveredClass> recoveredClasses, PrintWriter out) private void outputClassDefinitions(List<RecoveredClass> recoveredClasses, PrintWriter out)
throws CancelledException { throws CancelledException {
for (RecoveredClass recoveredClass : recoveredClasses) { for (RecoveredClass recoveredClass : recoveredClasses) {
@ -904,7 +869,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
} }
/** /**
@ -938,7 +902,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
/** /**
* Method to print class hierarchies for the given list of classes starting with the lowest child classes in each family of classes * Method to print class hierarchies for the given list of classes starting with the lowest child classes in each family of classes
* @param recoveredClasses the list of classes * @param recoveredClasses the list of classes
@ -947,7 +910,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private void printClassHierarchiesFromLowestChildren( private void printClassHierarchiesFromLowestChildren(
List<RecoveredClass> recoveredClasses) throws CancelledException { List<RecoveredClass> recoveredClasses) throws CancelledException {
StringBuffer wholeBuffer = new StringBuffer(); StringBuffer wholeBuffer = new StringBuffer();
wholeBuffer.append("\r\n"); wholeBuffer.append("\r\n");
for (RecoveredClass recoveredClass : recoveredClasses) { for (RecoveredClass recoveredClass : recoveredClasses) {
@ -1006,7 +968,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
/** /**
* Method to print counts of various class items for the given classes, such as number of constructors, destructors, etc... * Method to print counts of various class items for the given classes, such as number of constructors, destructors, etc...
* @param recoveredClasses list of classes * @param recoveredClasses list of classes
@ -1014,7 +975,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
*/ */
private void printCounts(List<RecoveredClass> recoveredClasses) throws CancelledException { private void printCounts(List<RecoveredClass> recoveredClasses) throws CancelledException {
println("Total number of constructors: " + println("Total number of constructors: " +
recoverClassesFromRTTI.getNumberOfConstructors(recoveredClasses)); recoverClassesFromRTTI.getNumberOfConstructors(recoveredClasses));
println("Total number of inlined constructors: " + println("Total number of inlined constructors: " +
@ -1050,7 +1010,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
/** /**
* Method to get the total number of * Method to get the total number of
* @param recoveredClasses list of classes * @param recoveredClasses list of classes
@ -1099,7 +1058,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
} }
/** /**
* Method to output the class, it's parents and it's children for each of the listed classes * Method to output the class, it's parents and it's children for each of the listed classes
* @param recoveredClasses the given classes * @param recoveredClasses the given classes
@ -1219,7 +1177,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
stringBuffer.append("\tNone\r\n"); stringBuffer.append("\tNone\r\n");
} }
// print child classes // print child classes
stringBuffer.append("\r\n"); stringBuffer.append("\r\n");
stringBuffer.append("child class(es):\r\n"); stringBuffer.append("child class(es):\r\n");
@ -1332,7 +1289,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return stringBuffer; return stringBuffer;
} }
/** /**
* Method to get the function signature string, from the decompiler if possible, otherwise from * Method to get the function signature string, from the decompiler if possible, otherwise from
* the listing * the listing
@ -1387,7 +1343,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return stringBuffer.toString(); return stringBuffer.toString();
} }
/** /**
* Method to create a string containing a C++-like representation of the given class * Method to create a string containing a C++-like representation of the given class
* @param recoveredClass the given class * @param recoveredClass the given class
@ -1397,7 +1352,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private StringBuffer createClassDefinitionString(RecoveredClass recoveredClass) private StringBuffer createClassDefinitionString(RecoveredClass recoveredClass)
throws CancelledException { throws CancelledException {
StringBuffer stringBuffer = new StringBuffer(); StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("\r\n\r\n"); stringBuffer.append("\r\n\r\n");
@ -1405,7 +1359,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
stringBuffer.append("\r\n{\r\n"); stringBuffer.append("\r\n{\r\n");
// print constructor signature(s) // print constructor signature(s)
stringBuffer.append("constructor(s):\r\n"); stringBuffer.append("constructor(s):\r\n");
List<Function> constructorList = recoveredClass.getConstructorList(); List<Function> constructorList = recoveredClass.getConstructorList();
@ -1474,7 +1427,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
stringBuffer.append("};\r\n"); stringBuffer.append("};\r\n");
// Then recursively process the child classes // Then recursively process the child classes
if (recoveredClass.hasChildClass()) { if (recoveredClass.hasChildClass()) {
List<RecoveredClass> childClasses = recoveredClass.getChildClasses(); List<RecoveredClass> childClasses = recoveredClass.getChildClasses();
@ -1487,6 +1439,4 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return stringBuffer; return stringBuffer;
} }
} }

View file

@ -349,7 +349,8 @@ public class DecompileOptions {
private static final String SEARCH_HIGHLIGHT_MSG = private static final String SEARCH_HIGHLIGHT_MSG =
"Display.Color for Highlighting Find Matches"; "Display.Color for Highlighting Find Matches";
private static final Color SEARCH_HIGHLIGHT_DEF = new Color(100, 100, 255); private static final Color SEARCH_HIGHLIGHT_DEF =
new GColor("color.bg.decompiler.highlights.search");
private Color defaultSearchHighlightColor = SEARCH_HIGHLIGHT_DEF; private Color defaultSearchHighlightColor = SEARCH_HIGHLIGHT_DEF;
// Color applied to a token to indicate warning/error // Color applied to a token to indicate warning/error

View file

@ -21,6 +21,7 @@ import java.awt.Graphics;
import javax.swing.JComponent; import javax.swing.JComponent;
import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.field.*;
import generic.theme.GThemeDefaults.Colors.Palette;
import ghidra.app.decompiler.ClangToken; import ghidra.app.decompiler.ClangToken;
public class ClangFieldElement extends AbstractTextFieldElement { public class ClangFieldElement extends AbstractTextFieldElement {
@ -49,7 +50,7 @@ public class ClangFieldElement extends AbstractTextFieldElement {
if (token.isMatchingToken()) { if (token.isMatchingToken()) {
// paint a bounding box around the token // paint a bounding box around the token
g.setColor(Color.GRAY); g.setColor(Palette.GRAY);
int offset = 1; int offset = 1;
g.drawRect(x - offset, y - getHeightAbove() - offset, getStringWidth() + (offset * 2), g.drawRect(x - offset, y - getHeightAbove() - offset, getStringWidth() + (offset * 2),
getHeightAbove() + getHeightBelow() + (offset * 2)); getHeightAbove() + getHeightBelow() + (offset * 2));

View file

@ -25,6 +25,7 @@ import org.apache.commons.collections4.map.LazyMap;
import docking.widgets.EventTrigger; import docking.widgets.EventTrigger;
import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.FieldLocation;
import generic.theme.GColor;
import ghidra.app.decompiler.*; import ghidra.app.decompiler.*;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.pcode.HighFunction; import ghidra.program.model.pcode.HighFunction;
@ -63,7 +64,8 @@ import util.CollectionUtils;
*/ */
public abstract class ClangHighlightController { public abstract class ClangHighlightController {
public static Color DEFAULT_HIGHLIGHT_COLOR = new Color(255, 255, 0, 128); public static Color DEFAULT_HIGHLIGHT_COLOR =
new GColor("color.bg.decompiler.highlights.default");
public static ClangHighlightController dummyIfNull(ClangHighlightController c) { public static ClangHighlightController dummyIfNull(ClangHighlightController c) {
if (c == null) { if (c == null) {

View file

@ -63,7 +63,8 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
private final static Color NON_FUNCTION_BACKGROUND_COLOR_DEF = new GColor("color.bg.undefined"); private final static Color NON_FUNCTION_BACKGROUND_COLOR_DEF = new GColor("color.bg.undefined");
// Default color for specially highlighted tokens // Default color for specially highlighted tokens
private final static Color SPECIAL_COLOR_DEF = new Color(255, 100, 0, 128); private final static Color SPECIAL_COLOR_DEF =
new GColor("color.bg.decompiler.highlights.special");
private final DecompilerController controller; private final DecompilerController controller;
private final DecompileOptions options; private final DecompileOptions options;

View file

@ -42,6 +42,6 @@ public class HighlightToken {
@Override @Override
public String toString() { public String toString() {
return token.toString() + "; color=" + color; return token.toString() + "; highlight=" + color;
} }
} }

View file

@ -18,21 +18,27 @@ package ghidra.app.decompiler.component;
import java.awt.Color; import java.awt.Color;
import java.util.*; import java.util.*;
import generic.theme.Gui;
/** /**
* A class to create and store colors related to token names * A class to create and store colors related to token names
*/ */
public class TokenHighlightColors { public class TokenHighlightColors {
private int minColorSaturation = 100;
private int defaultColorAlpha = 100;
private Map<String, Color> colorsByName = new HashMap<>(); private Map<String, Color> colorsByName = new HashMap<>();
private List<Color> recentColors = new ArrayList<>(); private List<Color> recentColors = new ArrayList<>();
private Color generateColor() { private Color generateColor() {
return new Color((int) (minColorSaturation + Math.random() * (256 - minColorSaturation)),
(int) (minColorSaturation + Math.random() * (256 - minColorSaturation)), float h = (float) Math.random(); // 0-360
(int) (minColorSaturation + Math.random() * (256 - minColorSaturation)), float s = .25f; // saturation; gray to full color; full color is too harsh for highlights
defaultColorAlpha); float b = 1f; // brightness; black to full color
if (Gui.getActiveTheme().useDarkDefaults()) {
s = .5f; // a bit more color against a dark background
b = .5f; // less brightness, as the background is not as bright
}
return Color.getHSBColor(h, s, b);
} }
public Color getColor(String text) { public Color getColor(String text) {

View file

@ -18,9 +18,11 @@ package ghidra.app.plugin.core.decompile.actions;
import static ghidra.app.plugin.core.decompile.actions.PCodeDfgGraphType.*; import static ghidra.app.plugin.core.decompile.actions.PCodeDfgGraphType.*;
import static ghidra.service.graph.VertexShape.*; import static ghidra.service.graph.VertexShape.*;
import java.awt.Color;
import generic.theme.GColor;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.service.graph.*; import ghidra.service.graph.*;
import ghidra.util.WebColors;
/** /**
* {@link GraphDisplayOptions} for {@link PCodeDfgGraphType} * {@link GraphDisplayOptions} for {@link PCodeDfgGraphType}
@ -28,6 +30,32 @@ import ghidra.util.WebColors;
public class PCodeDfgDisplayOptions extends GraphDisplayOptions { public class PCodeDfgDisplayOptions extends GraphDisplayOptions {
public static final String SHAPE_ATTRIBUTE = "Shape"; public static final String SHAPE_ATTRIBUTE = "Shape";
private static final Color BG_VERTEX_DEFAULT =
new GColor("color.bg.decompiler.pcode.dfg.vertex.default");
private static final Color BG_VERTEX_SELECTED =
new GColor("color.bg.decompiler.pcode.dfg.vertex.selected");
private static final Color BG_VERTEX_CONSTANT =
new GColor("color.bg.decompiler.pcode.dfg.vertex.constant");
private static final Color BG_VERTEX_REGISTER =
new GColor("color.bg.decompiler.pcode.dfg.vertex.register");
private static final Color BG_VERTEX_UNIQUE =
new GColor("color.bg.decompiler.pcode.dfg.vertex.unique");
private static final Color BG_VERTEX_PERSISTENT =
new GColor("color.bg.decompiler.pcode.dfg.vertex.persistent");
private static final Color BG_VERTEX_ADDRESS_TIED =
new GColor("color.bg.decompiler.pcode.dfg.vertex.address.tied");
private static final Color BG_VERTEX_OP =
new GColor("color.bg.decompiler.pcode.dfg.vertex.op");
private static final Color BG_EDGE_DEFAULT =
new GColor("color.bg.decompiler.pcode.dfg.edge.default");
private static final Color BG_EDGE_SELECTED =
new GColor("color.bg.decompiler.pcode.dfg.edge.selected");
private static final Color BG_EDGE_WITHIN_BLOCK =
new GColor("color.bg.decompiler.pcode.dfg.edge.within.block");
private static final Color BG_EDGE_BETWEEN_BLOCKS =
new GColor("color.bg.decompiler.pcode.dfg.edge.between.blocks");
/** /**
* constructor * constructor
* @param tool if non-null, will load values from tool options * @param tool if non-null, will load values from tool options
@ -39,10 +67,10 @@ public class PCodeDfgDisplayOptions extends GraphDisplayOptions {
@Override @Override
protected void initializeDefaults() { protected void initializeDefaults() {
setDefaultVertexShape(ELLIPSE); setDefaultVertexShape(ELLIPSE);
setDefaultVertexColor(WebColors.RED); setDefaultVertexColor(BG_VERTEX_DEFAULT);
setDefaultEdgeColor(WebColors.NAVY); setDefaultEdgeColor(BG_EDGE_DEFAULT);
setVertexSelectionColor(WebColors.DEEP_PINK); setVertexSelectionColor(BG_VERTEX_SELECTED);
setEdgeSelectionColor(WebColors.DEEP_PINK); setEdgeSelectionColor(BG_EDGE_SELECTED);
setDefaultLayoutAlgorithmName(LayoutAlgorithmNames.MIN_CROSS_COFFMAN_GRAHAM); setDefaultLayoutAlgorithmName(LayoutAlgorithmNames.MIN_CROSS_COFFMAN_GRAHAM);
setUsesIcons(false); setUsesIcons(false);
setArrowLength(15); setArrowLength(15);
@ -50,16 +78,16 @@ public class PCodeDfgDisplayOptions extends GraphDisplayOptions {
setVertexShapeOverrideAttributeKey(SHAPE_ATTRIBUTE); setVertexShapeOverrideAttributeKey(SHAPE_ATTRIBUTE);
setMaxNodeCount(1000); setMaxNodeCount(1000);
configureVertexType(DEFAULT_VERTEX, VertexShape.ELLIPSE, WebColors.RED); configureVertexType(DEFAULT_VERTEX, VertexShape.ELLIPSE, BG_VERTEX_DEFAULT);
configureVertexType(CONSTANT, VertexShape.ELLIPSE, WebColors.DARK_GREEN); configureVertexType(CONSTANT, VertexShape.ELLIPSE, BG_VERTEX_CONSTANT);
configureVertexType(REGISTER, VertexShape.ELLIPSE, WebColors.NAVY); configureVertexType(REGISTER, VertexShape.ELLIPSE, BG_VERTEX_REGISTER);
configureVertexType(UNIQUE, VertexShape.ELLIPSE, WebColors.BLACK); configureVertexType(UNIQUE, VertexShape.ELLIPSE, BG_VERTEX_UNIQUE);
configureVertexType(PERSISTENT, VertexShape.ELLIPSE, WebColors.DARK_ORANGE); configureVertexType(PERSISTENT, VertexShape.ELLIPSE, BG_VERTEX_PERSISTENT);
configureVertexType(ADDRESS_TIED, VertexShape.ELLIPSE, WebColors.ORANGE); configureVertexType(ADDRESS_TIED, VertexShape.ELLIPSE, BG_VERTEX_ADDRESS_TIED);
configureVertexType(OP, VertexShape.ELLIPSE, WebColors.RED); configureVertexType(OP, VertexShape.ELLIPSE, BG_VERTEX_OP);
configureEdgeType(DEFAULT_EDGE, WebColors.BLUE); configureEdgeType(DEFAULT_EDGE, BG_EDGE_DEFAULT);
configureEdgeType(WITHIN_BLOCK, WebColors.BLACK); configureEdgeType(WITHIN_BLOCK, BG_EDGE_WITHIN_BLOCK);
configureEdgeType(BETWEEN_BLOCKS, WebColors.RED); configureEdgeType(BETWEEN_BLOCKS, BG_EDGE_BETWEEN_BLOCKS);
} }
} }

View file

@ -35,6 +35,7 @@ import docking.widgets.dialogs.InputDialog;
import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.FieldLocation;
import generic.theme.GThemeDefaults.Colors.Palette;
import ghidra.app.cmd.comments.SetCommentCmd; import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.decompiler.*; import ghidra.app.decompiler.*;
import ghidra.app.decompiler.DecompileOptions.NamespaceStrategy; import ghidra.app.decompiler.DecompileOptions.NamespaceStrategy;
@ -927,7 +928,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
String secondaryHighlightText = token.getText(); String secondaryHighlightText = token.getText();
assertEquals("_printf", secondaryHighlightText); assertEquals("_printf", secondaryHighlightText);
Color myColor = Color.PINK; Color myColor = Palette.PINK;
highlightWithColorChooser(myColor); highlightWithColorChooser(myColor);
assertAllFieldsSecondaryHighlighted(token, myColor); assertAllFieldsSecondaryHighlighted(token, myColor);
} }
@ -964,7 +965,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
String secondaryHighlightText = token.getText(); String secondaryHighlightText = token.getText();
assertEquals("_printf", secondaryHighlightText); assertEquals("_printf", secondaryHighlightText);
Color myColor = Color.PINK; Color myColor = Palette.PINK;
highlightWithColorChooser(myColor); highlightWithColorChooser(myColor);
removeSecondaryHighlight(); removeSecondaryHighlight();
@ -1130,7 +1131,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1180,7 +1181,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
assertPrimaryHighlights("(\"call_structure_A: %s\\n\",a->name)"); assertPrimaryHighlights("(\"call_structure_A: %s\\n\",a->name)");
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1242,7 +1243,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
assertAllFieldsSecondaryHighlighted(secondrayToken, secondaryHlColor); assertAllFieldsSecondaryHighlighted(secondrayToken, secondaryHlColor);
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1304,7 +1305,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
assertAllFieldsSecondaryHighlighted(secondaryToken, secondaryHlColor); assertAllFieldsSecondaryHighlighted(secondaryToken, secondaryHlColor);
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1352,7 +1353,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText1 = "_printf"; String hlText1 = "_printf";
Color hlColor1 = Color.PINK; Color hlColor1 = Palette.PINK;
CTokenHighlightMatcher hlMatcher1 = token -> { CTokenHighlightMatcher hlMatcher1 = token -> {
if (token.getText().contains(hlText1)) { if (token.getText().contains(hlText1)) {
return hlColor1; return hlColor1;
@ -1370,7 +1371,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
assertNoFieldsSecondaryHighlighted(hlText1); assertNoFieldsSecondaryHighlighted(hlText1);
String hlText2 = "name"; String hlText2 = "name";
Color hlColor2 = Color.GREEN; Color hlColor2 = Palette.GREEN;
CTokenHighlightMatcher hlMatcher2 = token -> { CTokenHighlightMatcher hlMatcher2 = token -> {
if (token.getText().contains(hlText2)) { if (token.getText().contains(hlText2)) {
return hlColor2; return hlColor2;
@ -1424,7 +1425,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
assertPrimaryHighlights("(\"call_structure_A: %s\\n\",a->name)"); assertPrimaryHighlights("(\"call_structure_A: %s\\n\",a->name)");
String hlText = "_printf"; String hlText = "_printf";
Color hlColor1 = Color.PINK; Color hlColor1 = Palette.PINK;
CTokenHighlightMatcher hlMatcher1 = token -> { CTokenHighlightMatcher hlMatcher1 = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor1; return hlColor1;
@ -1436,7 +1437,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
DecompilerHighlighter highlighter1 = hlService.createHighlighter(spyMatcher1); DecompilerHighlighter highlighter1 = hlService.createHighlighter(spyMatcher1);
highlighter1.applyHighlights(); highlighter1.applyHighlights();
Color hlColor2 = Color.GREEN; Color hlColor2 = Palette.GREEN;
CTokenHighlightMatcher hlMatcher2 = token -> { CTokenHighlightMatcher hlMatcher2 = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor2; return hlColor2;
@ -1485,7 +1486,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1532,7 +1533,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1590,7 +1591,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1638,7 +1639,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1688,7 +1689,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;
@ -1736,7 +1737,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
decompile("100000d60"); // '_call_structure_A' decompile("100000d60"); // '_call_structure_A'
String hlText = "_printf"; String hlText = "_printf";
Color hlColor = Color.PINK; Color hlColor = Palette.PINK;
CTokenHighlightMatcher hlMatcher = token -> { CTokenHighlightMatcher hlMatcher = token -> {
if (token.getText().contains(hlText)) { if (token.getText().contains(hlText)) {
return hlColor; return hlColor;

View file

@ -30,6 +30,7 @@ color.palette.orange = orange
color.palette.palegreen = palegreen color.palette.palegreen = palegreen
color.palette.palevioletred = PaleVioletRed color.palette.palevioletred = PaleVioletRed
color.palette.pink = pink color.palette.pink = pink
color.palette.purple = purple
color.palette.red = red color.palette.red = red
color.palette.yellow = yellow color.palette.yellow = yellow
color.palette.yellowgreen = yellowgreen color.palette.yellowgreen = yellowgreen

View file

@ -26,20 +26,31 @@ import ghidra.util.Swing;
* Property Editor for Colors. Uses a {@link GhidraColorChooser} as its custom component * Property Editor for Colors. Uses a {@link GhidraColorChooser} as its custom component
*/ */
public class ColorPropertyEditor extends PropertyEditorSupport { public class ColorPropertyEditor extends PropertyEditorSupport {
private GhidraColorChooser colorChooser; private GhidraColorChooser colorChooser;
private void colorChanged() { private void colorChanged() {
// run later - allows debugging without hanging amazon aws // run later - allows debugging without hanging the UI in some environments
Swing.runLater(() -> setValue(colorChooser.getColor())); Swing.runLater(() -> setValue(colorChooser.getColor()));
} }
@Override @Override
public Component getCustomEditor() { public Component getCustomEditor() {
if (colorChooser != null) {
return colorChooser;
}
colorChooser = new GhidraColorChooser(); colorChooser = new GhidraColorChooser();
colorChooser.getSelectionModel().addChangeListener(e -> colorChanged()); colorChooser.getSelectionModel().addChangeListener(e -> colorChanged());
return colorChooser; return colorChooser;
} }
public void saveState() {
if (colorChooser != null) {
colorChooser.addColorToHistory(colorChooser.getColor());
}
}
@Override @Override
public boolean supportsCustomEditor() { public boolean supportsCustomEditor() {
return true; return true;

View file

@ -44,10 +44,16 @@ public class GhidraColorChooser extends JColorChooser {
this.title = title; this.title = title;
} }
public void addColorToHistory(Color c) {
recentColorCache.addColor(c);
maybeInstallSettableColorSwatchChooserPanel();
}
public void setColorHistory(List<Color> colors) { public void setColorHistory(List<Color> colors) {
for (Color color : colors) { for (Color color : colors) {
recentColorCache.addColor(color); recentColorCache.addColor(color);
} }
maybeInstallSettableColorSwatchChooserPanel();
} }
public List<Color> getColorHistory() { public List<Color> getColorHistory() {
@ -66,8 +72,6 @@ public class GhidraColorChooser extends JColorChooser {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public Color showDialog(Component centerOverComponent) { public Color showDialog(Component centerOverComponent) {
maybeInstallSettableColorSwatchChooserPanel();
OKListener okListener = new OKListener(); OKListener okListener = new OKListener();
JDialog dialog = createDialog(centerOverComponent, title, true, this, okListener, null); JDialog dialog = createDialog(centerOverComponent, title, true, this, okListener, null);
doSetActiveTab(dialog); doSetActiveTab(dialog);
@ -123,7 +127,7 @@ public class GhidraColorChooser extends JColorChooser {
} }
private void maybeInstallSettableColorSwatchChooserPanel() { private void maybeInstallSettableColorSwatchChooserPanel() {
if (recentColorCache.size() == 0) { if (recentColorCache.isEmpty()) {
return; return;
} }

View file

@ -19,7 +19,6 @@ import java.awt.Color;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import docking.options.editor.ColorPropertyEditor; import docking.options.editor.ColorPropertyEditor;
import docking.theme.*;
import generic.theme.*; import generic.theme.*;
/** /**
@ -45,4 +44,8 @@ public class ColorValueEditor extends ThemeValueEditor<Color> {
return new ColorValue(id, color); return new ColorValue(id, color);
} }
@Override
protected void storeState() {
((ColorPropertyEditor) editor).saveState();
}
} }

View file

@ -34,7 +34,7 @@ public abstract class ThemeValueEditor<T> {
protected ThemeValue<T> currentThemeValue; protected ThemeValue<T> currentThemeValue;
private EditorDialog dialog; private EditorDialog dialog;
private String typeName; private String typeName;
private PropertyEditor editor; protected PropertyEditor editor;
/** /**
* Constructor * Constructor
@ -67,6 +67,14 @@ public abstract class ThemeValueEditor<T> {
} }
/**
* Called when the user has pressed ok. This allows sub-classes to store any state for
* future dialog invocations.
*/
protected void storeState() {
// for sub-classes
}
/** /**
* Returns the actual value (Color, Font, or Icon) * Returns the actual value (Color, Font, or Icon)
* @param id the theme property id for the value * @param id the theme property id for the value
@ -136,6 +144,7 @@ public abstract class ThemeValueEditor<T> {
@Override @Override
protected void okCallback() { protected void okCallback() {
close(); close();
storeState();
dialog = null; dialog = null;
} }
@ -145,5 +154,6 @@ public abstract class ThemeValueEditor<T> {
close(); close();
dialog = null; dialog = null;
} }
} }
} }

View file

@ -100,6 +100,7 @@ public class GThemeDefaults {
public static final GColor MAGENTA = getColor("magenta"); public static final GColor MAGENTA = getColor("magenta");
public static final GColor ORANGE = getColor("orange"); public static final GColor ORANGE = getColor("orange");
public static final GColor PINK = getColor("pink"); public static final GColor PINK = getColor("pink");
public static final GColor PURPLE = getColor("purple");
public static final GColor RED = getColor("red"); public static final GColor RED = getColor("red");
public static final GColor WHITE = getColor("white"); public static final GColor WHITE = getColor("white");
public static final GColor YELLOW = getColor("yellow"); public static final GColor YELLOW = getColor("yellow");