GP-1981 - Checkpoint - Function Call Graph

This commit is contained in:
dragonmacher 2022-07-01 18:36:03 -04:00 committed by ghidragon
parent 16e32317f0
commit 60b1ae8b44
15 changed files with 276 additions and 41 deletions

View file

@ -5,6 +5,7 @@
##MODULE IP: Tango Icons - Public Domain
Module.manifest||GHIDRA||||END|
data/ExtensionPoint.manifest||GHIDRA||||END|
data/functiongraph.theme.properties||GHIDRA||||END|
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
src/main/help/help/shared/arrow.gif||GHIDRA||reviewed||END|
src/main/help/help/shared/close16.gif||GHIDRA||reviewed||END|

View file

@ -24,12 +24,23 @@ color.bg.functiongraph.paint.icon = rgb(189, 221, 252) // gentle pale blue
[Dark Defaults]
color.bg.functiongraph.vertex.group = rgb(226, 222, 179) // TODO confirm value
// color.bg.functiongraph = color.bg
// color.fg.label.picked = color.fg
// color.fg.label.non-picked = color.fg.disabled
color.bg.functiongraph.vertex.group = rgb(226, 222, 179) // TODO confirm value
// color.bg.functiongraph.vertex.entry = color.palette.lightgreen
// color.bg.functiongraph.vertex.exit = color.palette.lightred
// color.bg.functiongraph.vertex.picked = color.palette.yellow
// color.bg.functiongraph.edge.fall-through = color.flowtype.fall-through
color.bg.functiongraph.edge.fall-through.highlight = rgb(165, 76, 80)
// color.bg.functiongraph.edge.jump.conditional = color.flowtype.jump.conditional
color.bg.functiongraph.edge.jump.conditional.highlight = rgb(95, 160, 196)
// color.bg.functiongraph.edge.jump.unconditional = color.flowtype.jump.unconditional
color.bg.functiongraph.edge.jump.unconditional.highlight = rgb(140, 162, 88)
// TODO dark version color.bg.functiongraph.paint.icon =
// TODO dark version color.bg.functiongraph.paint.icon = // TODO

View file

@ -59,8 +59,7 @@ import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.util.HTMLUtilities;
import ghidra.util.HelpLocation;
import ghidra.util.*;
import resources.ResourceManager;
public class ListingGraphComponentPanel extends AbstractGraphComponentPanel {
@ -561,11 +560,7 @@ public class ListingGraphComponentPanel extends AbstractGraphComponentPanel {
private Color getToolTipColorForEdge(FGEdge edge) {
FunctionGraphOptions options = controller.getFunctionGraphOptions();
Color c = options.getColor(edge.getFlowType());
return withAlpha(c, 125);
}
private Color withAlpha(Color c, int alpha) {
return new Color(c.getRed(), c.getGreen(), c.getBlue(), 125);
return ColorUtils.withAlpha(c, 125);
}
private Address getPreviewAddress(boolean forward) {

View file

@ -1,3 +1,25 @@
[Defaults]
color.fcg.satellite.edge = rgba(0,0,0,0.1)
color.bg.fcg.vertex.default = rgb(110, 197, 174) // chill green
color.bg.fcg.vertex.toobig = color.palette.lightGray
color.bg.fcg.edge.primary.direct = rgb(143, 197, 143) // lightGreen
color.bg.fcg.edge.primary.indirect = rgb(233, 233, 233) // lightGray
// the satellite gets too cluttered, so wash out the edges
color.bg.fcg.edge.satellite.direct = rgba(0,0,0,0.1) // 'washed out black'
color.bg.fcg.edge.satellite.indirect = rgba(125, 125, 125, 25) // 'washed out gray'
[Dark Defaults]
// TODO dark colors
// TODO color.bg.fcg.vertex.default = rgb(110, 197, 174) // chill green
// TODO color.bg.fcg.vertex.toobig = color.palette.lightGray
// TODO color.bg.fcg.edge.primary.direct = rgb(143, 197, 143) // lightGreen
// TODO color.bg.fcg.edge.primary.indirect = rgb(233, 233, 233) // lightGray
// the satellite gets too cluttered, so wash out the edges
// TODO color.bg.fcg.edge.satellite.direct = rgba(0,0,0,0.1) // 'washed out black'
// TODO color.bg.fcg.edge.satellite.indirect = rgba(125, 125, 125, 25) // 'washed out gray'

View file

@ -26,6 +26,8 @@ import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import docking.theme.GColor;
import docking.theme.GThemeDefaults.Colors.Palette;
import docking.widgets.EmptyBorderButton;
import docking.widgets.label.GDLabel;
import ghidra.graph.viewer.vertex.AbstractVisualVertex;
@ -41,9 +43,10 @@ import resources.ResourceManager;
*/
public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvider {
// TODO to be made an option in an upcoming ticket
public static final Color DEFAULT_VERTEX_SHAPE_COLOR = new Color(110, 197, 174);
private static final Color TOO_BIG_VERTEX_SHAPE_COLOR = Color.LIGHT_GRAY;
//@formatter:off
public static final Color DEFAULT_VERTEX_SHAPE_COLOR = new GColor("color.bg.fcg.vertex.default");
private static final Color TOO_BIG_VERTEX_SHAPE_COLOR = new GColor("color.bg.fcg.vertex.toobig ");
//@formatter:on
public static final Icon NOT_ALLOWED_ICON = Icons.ERROR_ICON;
private static final Icon EXPAND_ICON =
@ -312,8 +315,8 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid
private void addToggleButtons() {
// hide the button background
toggleInsButton.setBackground(new Color(255, 255, 255, 0));
toggleOutsButton.setBackground(new Color(255, 255, 255, 0));
toggleInsButton.setBackground(Palette.NO_COLOR);
toggleOutsButton.setBackground(Palette.NO_COLOR);
Rectangle parentBounds = vertexImageLabel.getBounds();
Dimension size = toggleInsButton.getPreferredSize();

View file

@ -21,13 +21,13 @@ import java.awt.Paint;
import com.google.common.base.Function;
import functioncalls.graph.FcgEdge;
import ghidra.util.ColorUtils;
/**
* Generates colors for a given {@link FcgEdge}
*/
public class FcgEdgePaintTransformer implements Function<FcgEdge, Paint> {
// private static final Paint LESS_IMPORTANT_COLOR = new Color(125, 125, 125, 75);
private Color directColor;
private Color indirectColor;
@ -46,7 +46,7 @@ public class FcgEdgePaintTransformer implements Function<FcgEdge, Paint> {
alphad[0] = c;
for (int i = 1; i < 10; i++) {
double newAlpha = 255 - (i * 25.5);
alphad[i] = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int) newAlpha);
alphad[i] = ColorUtils.withAlpha(c, (int) newAlpha);
}
return alphad;
}

View file

@ -15,8 +15,6 @@
*/
package functioncalls.graph.view;
import java.awt.Color;
import docking.theme.GColor;
import edu.uci.ics.jung.visualization.RenderContext;
import functioncalls.graph.*;
@ -38,19 +36,14 @@ public class FcgComponent extends GraphComponent<FcgVertex, FcgEdge, FunctionCal
private FcgVertexPaintTransformer vertexPaintTransformer =
new FcgVertexPaintTransformer(FcgVertex.DEFAULT_VERTEX_SHAPE_COLOR);
private Color lightGreen = new Color(143, 197, 143);
private Color lightGray = new Color(233, 233, 233);
// the satellite gets too cluttered, so wash out the edges
private Color washedOutBlack = new GColor("color.fcg.satellite.edge");
private FcgEdgePaintTransformer edgePaintTransformer =
new FcgEdgePaintTransformer(lightGreen, lightGray);
new FcgEdgePaintTransformer(new GColor("color.bg.fcg.edge.primary.direct"),
new GColor("color.bg.fcg.edge.primary.indirect"));
private FcgEdgePaintTransformer satelliteEdgePaintTransformer =
new FcgEdgePaintTransformer(washedOutBlack, new Color(125, 125, 125, 25));
new FcgEdgePaintTransformer(new GColor("color.bg.fcg.edge.satellite.direct"),
new GColor("color.bg.fcg.edge.satellite.indirect"));
FcgComponent(FunctionCallGraph g) {
setGraph(g);
build();
}
@ -75,7 +68,6 @@ public class FcgComponent extends GraphComponent<FcgVertex, FcgEdge, FunctionCal
renderContext.setEdgeDrawPaintTransformer(edgePaintTransformer);
renderContext.setArrowFillPaintTransformer(edgePaintTransformer);
renderContext.setArrowDrawPaintTransformer(edgePaintTransformer);
}
@Override

View file

@ -1,7 +1,10 @@
[Defaults]
color.palette.nocolor = rgba(255,255,255,0)
color.palette.black = black
color.palette.cyan = cyan
color.palette.lightGray = rgb(192, 192, 192)
color.palette.lightgreen = rgb(127, 255, 127)
color.palette.lightred = rgb(255, 127, 127)
color.palette.red = red

View file

@ -21,11 +21,20 @@ import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
public class GColor extends Color implements Refreshable {
import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet;
public class GColor extends Color implements Refreshable {
private static WeakSet<GColor> inUseColors = WeakDataStructureFactory.createCopyOnReadWeakSet();
private String id;
private Color delegate;
public static void refreshAll() {
for (GColor gcolor : inUseColors) {
gcolor.refresh();
}
}
public GColor(String id) {
super(0x808080);
this.id = id;
@ -33,6 +42,7 @@ public class GColor extends Color implements Refreshable {
if (delegate == null) {
delegate = Color.gray;
}
inUseColors.add(this);
}
public String getId() {

View file

@ -55,6 +55,8 @@ public class GThemeDefaults {
* Generic palette colors, using color names, that may be changed along with the theme
*/
public static class Palette {
public static final Color NO_COLOR = new GColor("color.palette.nocolor");
public static final Color BLACK = new GColor("color.palette.black");
public static final Color CYAN = new GColor("color.palette.cyan");
public static final Color RED = new GColor("color.palette.red");

View file

@ -32,7 +32,7 @@ import ghidra.util.filechooser.GhidraFileFilter;
public class GThemeDialog extends DialogComponentProvider {
public GThemeDialog() {
super("Theme Dialog");
super("Theme Dialog", false);
addWorkPanel(createMainPanel());
addOKButton();
addCancelButton();
@ -80,6 +80,9 @@ public class GThemeDialog extends DialogComponentProvider {
colorTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
GFilterTable<ColorValue> filterTable = new GFilterTable<>(colorTableModel);
filterTable.getTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
filterTable.getTable()
.setDefaultEditor(ColorValue.class,
new ThemeColorEditor(Gui.getAllValues(), colorTableModel));
return filterTable;
}

View file

@ -307,4 +307,10 @@ public class Gui {
return map;
}
public static void setColor(String id, Color color) {
currentValues.addColor(new ColorValue(id, color));
GColor.refreshAll();
}
}

View file

@ -0,0 +1,165 @@
/* ###
* 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 docking.theme;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableCellEditor;
import docking.DialogComponentProvider;
import docking.DockingWindowManager;
import docking.options.editor.GhidraColorChooser;
import docking.widgets.label.GDLabel;
public class ThemeColorEditor extends AbstractCellEditor implements TableCellEditor {
private GhidraColorChooser colorChooser;
private Color lastUserSelectedColor;
private Color color;
private ColorDialogProvider dialog;
private JTable table;
private ColorValue colorValue;
private GThemeValueMap values;
private ThemeColorTableModel model;
public ThemeColorEditor(GThemeValueMap values, ThemeColorTableModel model) {
this.values = values;
this.model = model;
}
@Override
public Component getTableCellEditorComponent(JTable theTable, Object value, boolean isSelected,
int row, int column) {
this.table = theTable;
colorValue = (ColorValue) value;
JLabel label = new GDLabel();
label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
label.setText(colorValue.getId());
dialog = new ColorDialogProvider();
dialog.setRememberSize(false);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
DockingWindowManager.showDialog(dialog);
stopCellEditing();
}
});
return label;
}
@Override
public void cancelCellEditing() {
dialog.close();
}
@Override
public Object getCellEditorValue() {
return null;
}
@Override
public boolean stopCellEditing() {
ListSelectionModel columnSelectionModel = table.getColumnModel().getSelectionModel();
columnSelectionModel.setValueIsAdjusting(true);
int columnAnchor = columnSelectionModel.getAnchorSelectionIndex();
int columnLead = columnSelectionModel.getLeadSelectionIndex();
if (color != null) {
Gui.setColor(colorValue.getId(), color);
model.refresh();
}
dialog.close();
fireEditingStopped();
columnSelectionModel.setAnchorSelectionIndex(columnAnchor);
columnSelectionModel.setLeadSelectionIndex(columnLead);
columnSelectionModel.setValueIsAdjusting(false);
return true;
}
// only double-click edits
@Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent) anEvent).getClickCount() >= 2;
}
return true;
}
//==================================================================================================
// Inner Classes
//==================================================================================================
class ColorDialogProvider extends DialogComponentProvider {
ColorDialogProvider() {
super("Color Editor", true);
addWorkPanel(new ColorEditorPanel());
addOKButton();
addCancelButton();
}
@Override
protected void okCallback() {
color = lastUserSelectedColor;
close();
}
@Override
protected void cancelCallback() {
color = null;
close();
}
}
class ColorEditorPanel extends JPanel {
ColorEditorPanel() {
setLayout(new BorderLayout());
if (colorChooser == null) {
colorChooser = new GhidraColorChooser();
}
add(colorChooser, BorderLayout.CENTER);
colorChooser.getSelectionModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
lastUserSelectedColor = colorChooser.getColor();
// This could be a ColorUIResource, but Options only support storing Color.
lastUserSelectedColor =
new Color(lastUserSelectedColor.getRed(), lastUserSelectedColor.getGreen(),
lastUserSelectedColor.getBlue(), lastUserSelectedColor.getAlpha());
}
});
colorChooser.setColor(colorValue.get(values));
}
}
}

View file

@ -38,6 +38,11 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
colors = Gui.getAllValues().getColors();
}
public void refresh() {
colors = Gui.getAllValues().getColors();
fireTableDataChanged();
}
@Override
public String getName() {
return "Users";
@ -48,6 +53,10 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
return colors;
}
public boolean isCellEditable(int row, int column) {
return getColumnName(column).equals("Current Color");
}
@Override
protected TableColumnDescriptor<ColorValue> createTableColumnDescriptor() {
TableColumnDescriptor<ColorValue> descriptor = new TableColumnDescriptor<>();
@ -78,7 +87,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
}
class ValueColumn extends AbstractDynamicTableColumn<ColorValue, String, Object> {
class ValueColumn extends AbstractDynamicTableColumn<ColorValue, ColorValue, Object> {
private ThemeColorRenderer renderer = new ThemeColorRenderer(Gui.getAllValues());
private GThemeValueMap valueMap;
private String name;
@ -95,18 +104,19 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
@Override
public String getValue(ColorValue themeColor, Settings settings, Object data,
public ColorValue getValue(ColorValue themeColor, Settings settings, Object data,
ServiceProvider provider) throws IllegalArgumentException {
return themeColor.getId();
return themeColor;
}
@Override
public GColumnRenderer<String> getColumnRenderer() {
public GColumnRenderer<ColorValue> getColumnRenderer() {
return renderer;
}
public Comparator<String> getComparator() {
return (s1, s2) -> valueMap.getColor(s1).compareValue(valueMap.getColor(s2));
public Comparator<ColorValue> getComparator() {
return (v1, v2) -> valueMap.getColor(v1.getId())
.compareValue(valueMap.getColor(v2.getId()));
}
}
@ -125,7 +135,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
}
private class ThemeColorRenderer extends AbstractGColumnRenderer<String> {
private class ThemeColorRenderer extends AbstractGColumnRenderer<ColorValue> {
private GThemeValueMap valueMap;
@ -138,7 +148,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
String id = (String) data.getValue();
String id = ((ColorValue) data.getValue()).getId();
ColorValue colorValue = valueMap.getColor(id);
Color color;
@ -169,8 +179,9 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
@Override
public String getFilterString(String id, Settings settings) {
return id;
}
public String getFilterString(ColorValue t, Settings settings) {
return t.getId();
}
}
}

View file

@ -191,6 +191,17 @@ public class ColorUtils {
return color;
}
/**
* Returns a new color that is comprised of the given color's rgb value and the given alpha
* value.
* @param c the color
* @param alpha the alpha
* @return the new color
*/
public static Color withAlpha(Color c, int alpha) {
return new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha);
}
/**
* Blender of colors
*/