mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
custom highlighting for decompiler
This commit is contained in:
parent
6bac1a8712
commit
0af5a6b4fd
10 changed files with 580 additions and 2 deletions
|
@ -158,6 +158,11 @@ public class DecompileOptions { //
|
|||
private final static CommentStyleEnum COMMENTSTYLE_OPTIONDEFAULT = CommentStyleEnum.CStyle;
|
||||
private CommentStyleEnum commentStyle;
|
||||
|
||||
private final static String HIGHLIGHT_OPTIONSTRING = "Display.Custom Highlights";
|
||||
private final static String HIGHLIGHT_OPTIONDESCRIPTION = "If set, custom highlights is enabled";
|
||||
private final static boolean HIGHLIGHT_OPTIONDEFAULT = false;
|
||||
private boolean highlightInclude;
|
||||
|
||||
private final static String COMMENTPRE_OPTIONSTRING = "Display.Display PRE comments";
|
||||
private final static String COMMENTPRE_OPTIONDESCRIPTION =
|
||||
"If set, disassembly pre-instruction (PRE) comments are displayed " +
|
||||
|
@ -366,6 +371,7 @@ public class DecompileOptions { //
|
|||
indentwidth = opt.getInt(INDENTWIDTH_OPTIONSTRING, INDENTWIDTH_OPTIONDEFAULT);
|
||||
commentindent = opt.getInt(COMMENTINDENT_OPTIONSTRING, COMMENTINDENT_OPTIONDEFAULT);
|
||||
commentStyle = opt.getEnum(COMMENTSTYLE_OPTIONSTRING, COMMENTSTYLE_OPTIONDEFAULT);
|
||||
highlightInclude = opt.getBoolean(HIGHLIGHT_OPTIONSTRING, HIGHLIGHT_OPTIONDEFAULT);
|
||||
commentEOLInclude = opt.getBoolean(COMMENTEOL_OPTIONSTRING, COMMENTEOL_OPTIONDEFAULT);
|
||||
commentPREInclude = opt.getBoolean(COMMENTPRE_OPTIONSTRING, COMMENTPRE_OPTIONDEFAULT);
|
||||
commentPOSTInclude = opt.getBoolean(COMMENTPOST_OPTIONSTRING, COMMENTPOST_OPTIONDEFAULT);
|
||||
|
@ -487,6 +493,8 @@ public class DecompileOptions { //
|
|||
COMMENTSTYLE_OPTIONDESCRIPTION);
|
||||
opt.registerOption(COMMENTEOL_OPTIONSTRING, COMMENTEOL_OPTIONDEFAULT, help,
|
||||
COMMENTEOL_OPTIONDESCRIPTION);
|
||||
opt.registerOption(HIGHLIGHT_OPTIONSTRING, HIGHLIGHT_OPTIONDEFAULT, help,
|
||||
HIGHLIGHT_OPTIONDESCRIPTION);
|
||||
opt.registerOption(COMMENTPRE_OPTIONSTRING, COMMENTPRE_OPTIONDEFAULT, help,
|
||||
COMMENTPRE_OPTIONDESCRIPTION);
|
||||
opt.registerOption(COMMENTPOST_OPTIONSTRING, COMMENTPOST_OPTIONDEFAULT, help,
|
||||
|
@ -681,6 +689,10 @@ public class DecompileOptions { //
|
|||
return middleMouseHighlightButton;
|
||||
}
|
||||
|
||||
public boolean isHighlightIncluded() {
|
||||
return highlightInclude;
|
||||
}
|
||||
|
||||
public boolean isPRECommentIncluded() {
|
||||
return commentPREInclude;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
|||
private Color currentSearchHighlightColor;
|
||||
private Color currentHighlightColor;
|
||||
private SearchLocation currentSearchLocation;
|
||||
private HighlightTokenObservableList<HighlightToken> highlightedTokens = new HighlightTokenObservableList<HighlightToken>(this);
|
||||
|
||||
private DecompileData decompileData = new EmptyDecompileData("No Function");
|
||||
private final DecompilerClipboardProvider clipboard;
|
||||
|
@ -116,6 +117,10 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
|||
setDecompileData(new EmptyDecompileData("No Function"));
|
||||
}
|
||||
|
||||
public HighlightTokenObservableList<HighlightToken> getHighlightedTokens() {
|
||||
return highlightedTokens;
|
||||
}
|
||||
|
||||
public List<ClangLine> getLines() {
|
||||
return layoutMgr.getLines();
|
||||
}
|
||||
|
@ -128,6 +133,14 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
|||
return fieldPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function replace the highlighting tokens with the new list
|
||||
* @param newTokens the new data
|
||||
*/
|
||||
public void setHighlightedTokens(HighlightTokenObservableList<HighlightToken> newTokens) {
|
||||
highlightedTokens = newTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Color bg) {
|
||||
originalBackgroundColor = bg;
|
||||
|
@ -635,6 +648,43 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to add highlighting to a token.
|
||||
* The function behaves differently from highlightVariable in that
|
||||
* it does not erase existing highlights
|
||||
*
|
||||
* @param token the token to search for
|
||||
* @param highlightColor the color to apply
|
||||
*/
|
||||
public void addTokenHighlight(ClangToken token, Color highlightColor) {
|
||||
if (highlightController != null) {
|
||||
List<ClangToken> tokenList = new ArrayList<>();
|
||||
findTokensByName(tokenList, layoutMgr.getRoot(), token.getText());
|
||||
highlightController.addTokensToHighlights(tokenList, highlightColor);
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add highlighting to all the tokens in highlightedTokens,
|
||||
* the highlighting accounting structure
|
||||
*/
|
||||
public void repaintHighlightTokens(boolean clearHighlights) {
|
||||
if (clearHighlights) {
|
||||
clearHighlights();
|
||||
}
|
||||
highlightedTokens.forEach(ht -> {
|
||||
ClangToken token = ht.getToken();
|
||||
Function tokenFunc = ht.getFunction();
|
||||
Function decompiledFunc = decompileData.getFunction();
|
||||
if ((token != null) && (tokenFunc != null) && (decompiledFunc != null) &&
|
||||
(tokenFunc.getName().equals(decompileData.getFunction().getName()))) {
|
||||
addTokenHighlight(token, ht.getColor());
|
||||
}
|
||||
});
|
||||
tokenHighlightsChanged();
|
||||
}
|
||||
|
||||
Program getProgram() {
|
||||
return decompileData.getProgram();
|
||||
}
|
||||
|
@ -656,6 +706,9 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
|||
|
||||
if (highlightController != null) {
|
||||
highlightController.fieldLocationChanged(location, field, trigger);
|
||||
|
||||
// We need this because fieldLocationChanged clears the highlighting.
|
||||
repaintHighlightTokens(false);
|
||||
}
|
||||
|
||||
if (!(field instanceof ClangTextField)) {
|
||||
|
@ -900,6 +953,32 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
|||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is function is used to alert the panel that a token was renamed.
|
||||
* If the token that is being renamed had a special highlight, we must re-apply the highlight
|
||||
* to the new token.
|
||||
*
|
||||
* @param token the token being renamed
|
||||
* @param name the new name of the token
|
||||
*/
|
||||
public void tokenRenamed(ClangToken token, String name) {
|
||||
HighlightToken htoken = new HighlightToken(token, null, null);
|
||||
int idx = highlightedTokens.indexOf(htoken);
|
||||
if (idx >= 0) {
|
||||
HighlightToken hltok = highlightedTokens.get(idx);
|
||||
highlightedTokens.remove(hltok);
|
||||
ClangToken ct = new ClangToken((ClangNode)token, name);
|
||||
HighlightToken ht = new HighlightToken(ct, hltok.getColor(), null);
|
||||
highlightedTokens.add(ht);
|
||||
if (highlightController != null) {
|
||||
List<ClangToken> tokenList = new ArrayList<>();
|
||||
findTokensByName(tokenList, layoutMgr.getRoot(), name);
|
||||
highlightController.addTokensToHighlights(tokenList, getDefaultHighlightColor());
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package ghidra.app.decompiler.component;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import ghidra.app.decompiler.ClangFunction;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.ClangVariableToken;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class HighlightToken {
|
||||
private ClangToken token;
|
||||
private Color color;
|
||||
private DecompilerPanel panel;
|
||||
|
||||
public HighlightToken(ClangToken token, Color color, Function func) {
|
||||
this.token = token;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two HighlightTokens.
|
||||
*
|
||||
* Two HighlightTokens are equal if their text is equal
|
||||
* and if they reside in the same function.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
ClangToken otherToken = null;
|
||||
|
||||
if (obj.getClass() == HighlightToken.class) {
|
||||
HighlightToken hltoken = (HighlightToken)obj;
|
||||
otherToken = hltoken.token;
|
||||
}
|
||||
|
||||
if (obj.getClass() == ClangToken.class) {
|
||||
otherToken = ((ClangToken) obj);
|
||||
}
|
||||
|
||||
if (obj.getClass() == ClangVariableToken.class) {
|
||||
otherToken = ((ClangToken) obj);
|
||||
}
|
||||
|
||||
if (otherToken == null) {
|
||||
return false;
|
||||
}
|
||||
Function func1 = otherToken.getClangFunction().getHighFunction().getFunction();
|
||||
Function func2 = this.token.getClangFunction().getHighFunction().getFunction();
|
||||
return otherToken.getText().equals(this.token.getText()) &&
|
||||
(func1.equals(func2));
|
||||
}
|
||||
|
||||
public ClangToken getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(ClangToken token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public DecompilerPanel getPanel() {
|
||||
return panel;
|
||||
}
|
||||
|
||||
public void setPanel(DecompilerPanel panel) {
|
||||
this.panel = panel;
|
||||
}
|
||||
|
||||
public Function getFunction() {
|
||||
if (token == null) {
|
||||
return null;
|
||||
}
|
||||
ClangFunction clangFunc = token.getClangFunction();
|
||||
if (clangFunc == null) {
|
||||
return null;
|
||||
}
|
||||
return clangFunc.getHighFunction().getFunction();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package ghidra.app.decompiler.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HighlightTokenObservableList<T> extends ArrayList<T> {
|
||||
private ArrayList<DecompilerPanel> panels = new ArrayList<DecompilerPanel>();
|
||||
|
||||
public HighlightTokenObservableList(DecompilerPanel panel) {
|
||||
super();
|
||||
panels.add(panel);
|
||||
}
|
||||
|
||||
public HighlightTokenObservableList() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(T t){
|
||||
boolean rslt = super.add(t);
|
||||
notifyListeners();
|
||||
return rslt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object t){
|
||||
boolean rslt = super.remove(t);
|
||||
notifyListeners();
|
||||
return rslt;
|
||||
}
|
||||
|
||||
public void addListener(DecompilerPanel panel) {
|
||||
this.panels.add(panel);
|
||||
}
|
||||
|
||||
public void notifyListeners() {
|
||||
if (panels != null) {
|
||||
panels.forEach(p -> {
|
||||
p.repaintHighlightTokens(true);
|
||||
p.repaint();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,20 +33,28 @@ public class LocationClangHighlightController extends ClangHighlightController {
|
|||
@Override
|
||||
public void fieldLocationChanged(FieldLocation location, Field field, EventTrigger trigger) {
|
||||
|
||||
clearHighlights();
|
||||
|
||||
if (!(field instanceof ClangTextField)) {
|
||||
clearHighlights();
|
||||
return;
|
||||
}
|
||||
|
||||
ClangToken tok = ((ClangTextField) field).getToken(location);
|
||||
if (tok == null) {
|
||||
clearHighlights();
|
||||
return;
|
||||
}
|
||||
|
||||
// // clear any highlighted searchResults
|
||||
// decompilerPanel.setSearchResults(null);
|
||||
|
||||
// Token is already highlighted, break out
|
||||
if (tok.getHighlight() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Token is not highlighted, clear and re-apply highlighting
|
||||
clearHighlights();
|
||||
|
||||
addHighlight(tok, defaultHighlightColor);
|
||||
if (tok instanceof ClangSyntaxToken) {
|
||||
addHighlightParen((ClangSyntaxToken) tok, defaultParenColor);
|
||||
|
|
|
@ -101,6 +101,10 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||
|
||||
private SelectAllAction selectAllAction;
|
||||
|
||||
private SetHighlightAction setHighlightAction;
|
||||
private RemovePanelHighlightsAction removePanelHighlightsAction;
|
||||
private RemoveAllHighlightsAction removeAllHighlightsAction;
|
||||
|
||||
private ViewerPosition pendingViewerPosition;
|
||||
|
||||
private SwingUpdateManager redecompilerUpdater;
|
||||
|
@ -311,6 +315,16 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||
return;
|
||||
}
|
||||
|
||||
// SetHighlightAction was toggled on/off - notify the handler
|
||||
if ((setHighlightAction != null) && optionName.equals(setHighlightAction.getName())) {
|
||||
setHighlightAction.setEnabled((boolean)newValue);
|
||||
removePanelHighlightsAction.setEnabled((boolean) newValue);
|
||||
removeAllHighlightsAction.setEnabled((boolean) newValue);
|
||||
if ((boolean)newValue == false) {
|
||||
setHighlightAction.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (options.getName().equals(OPTIONS_TITLE) ||
|
||||
options.getName().equals(GhidraOptions.CATEGORY_BROWSER_FIELDS)) {
|
||||
doRefresh();
|
||||
|
@ -616,6 +630,13 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||
Swing.runLater(() -> {
|
||||
newProvider.doSetProgram(program);
|
||||
newProvider.controller.setDecompileData(controller.getDecompileData());
|
||||
|
||||
// Any change in the HighlightTokens should be delivered to the new panel
|
||||
getDecompilerPanel().getHighlightedTokens().addListener(newProvider.getDecompilerPanel());
|
||||
|
||||
// Transfer the highlighted tokens
|
||||
newProvider.getDecompilerPanel().setHighlightedTokens(getDecompilerPanel().getHighlightedTokens());
|
||||
|
||||
newProvider.setLocation(currentLocation,
|
||||
controller.getDecompilerPanel().getViewerPosition());
|
||||
});
|
||||
|
@ -768,6 +789,18 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||
lockLocalAction = new CommitLocalsAction(tool, controller);
|
||||
setGroupInfo(lockLocalAction, commitGroup, subGroupPosition++);
|
||||
|
||||
String highlightGroup = "4 - Highlight Group";
|
||||
subGroupPosition = 0; // reset for the next group
|
||||
|
||||
setHighlightAction = new SetHighlightAction(owner, controller, decompilerOptions.isHighlightIncluded());
|
||||
setGroupInfo(setHighlightAction, highlightGroup, subGroupPosition++);
|
||||
|
||||
removePanelHighlightsAction = new RemovePanelHighlightsAction(owner, controller, decompilerOptions.isHighlightIncluded());
|
||||
setGroupInfo(removePanelHighlightsAction, highlightGroup, subGroupPosition++);
|
||||
|
||||
removeAllHighlightsAction = new RemoveAllHighlightsAction(owner, controller, decompilerOptions.isHighlightIncluded());
|
||||
setGroupInfo(removeAllHighlightsAction, highlightGroup, subGroupPosition++);
|
||||
|
||||
//
|
||||
// Comments
|
||||
//
|
||||
|
@ -835,6 +868,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||
addLocalAction(lockProtoAction);
|
||||
addLocalAction(lockLocalAction);
|
||||
addLocalAction(renameVarAction);
|
||||
addLocalAction(setHighlightAction);
|
||||
addLocalAction(removePanelHighlightsAction);
|
||||
addLocalAction(removeAllHighlightsAction);
|
||||
addLocalAction(retypeVarAction);
|
||||
addLocalAction(decompilerCreateStructureAction);
|
||||
tool.addAction(listingCreateStructureAction);
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package ghidra.app.plugin.core.decompile.actions;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.decompiler.component.DecompilerController;
|
||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||
import ghidra.app.decompiler.component.HighlightToken;
|
||||
import ghidra.app.decompiler.component.HighlightTokenObservableList;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.UndefinedFunction;
|
||||
|
||||
public class RemoveAllHighlightsAction extends DockingAction {
|
||||
private DecompilerPanel panel;
|
||||
private DecompilerController controller;
|
||||
|
||||
public RemoveAllHighlightsAction(String owner, DecompilerController controller) {
|
||||
this(owner, controller, false);
|
||||
}
|
||||
|
||||
public RemoveAllHighlightsAction(String owner, DecompilerController controller, boolean isEnabled) {
|
||||
super("Remove All Highlights", owner);
|
||||
this.panel = controller.getDecompilerPanel();
|
||||
this.controller = controller;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Remove All Highlights" }, "Decompile"));
|
||||
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
|
||||
|
||||
setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (!(context instanceof DecompilerActionContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Function function = controller.getFunction();
|
||||
if (function instanceof UndefinedFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DecompilerActionContext decompilerActionContext = (DecompilerActionContext) context;
|
||||
if (decompilerActionContext.isDecompiling()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (panel != null) {
|
||||
HighlightTokenObservableList<HighlightToken> highlightTokens = panel.getHighlightedTokens();
|
||||
highlightTokens.clear();
|
||||
panel.clearHighlights();
|
||||
panel.tokenHighlightsChanged();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package ghidra.app.plugin.core.decompile.actions;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.decompiler.ClangFunction;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.component.DecompilerController;
|
||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||
import ghidra.app.decompiler.component.HighlightToken;
|
||||
import ghidra.app.decompiler.component.HighlightTokenObservableList;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.pcode.HighFunction;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.UndefinedFunction;
|
||||
|
||||
public class RemovePanelHighlightsAction extends DockingAction{
|
||||
|
||||
private DecompilerPanel panel;
|
||||
private DecompilerController controller;
|
||||
|
||||
public RemovePanelHighlightsAction(String owner, DecompilerController controller) {
|
||||
this(owner, controller, false);
|
||||
}
|
||||
|
||||
public RemovePanelHighlightsAction(String owner, DecompilerController controller, boolean isEnabled) {
|
||||
super("Remove Highlights", owner);
|
||||
this.panel = controller.getDecompilerPanel();
|
||||
this.controller = controller;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Remove Panel Highlights" }, "Decompile"));
|
||||
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
|
||||
|
||||
setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (!(context instanceof DecompilerActionContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Function function = controller.getFunction();
|
||||
if (function instanceof UndefinedFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DecompilerActionContext decompilerActionContext = (DecompilerActionContext) context;
|
||||
if (decompilerActionContext.isDecompiling()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (panel != null) {
|
||||
ClangToken tokenAtCursor = panel.getTokenAtCursor();
|
||||
removeTokensFromFunction(tokenAtCursor.getClangFunction());
|
||||
panel.clearHighlights();
|
||||
panel.tokenHighlightsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private Function getFunctionFromToken(ClangToken token) {
|
||||
if (token == null) {
|
||||
return null;
|
||||
}
|
||||
ClangFunction curClangFunction = token.getClangFunction();
|
||||
if (curClangFunction == null) {
|
||||
return null;
|
||||
}
|
||||
HighFunction curHighFunc = curClangFunction.getHighFunction();
|
||||
if (curHighFunc == null) {
|
||||
return null;
|
||||
}
|
||||
return curHighFunc.getFunction();
|
||||
}
|
||||
|
||||
private void removeTokensFromFunction(ClangFunction function) {
|
||||
if (panel != null && function != null) {
|
||||
HighlightTokenObservableList<HighlightToken> highlightTokens = panel.getHighlightedTokens();
|
||||
ClangToken curToken = panel.getTokenAtCursor();
|
||||
|
||||
Function curFunction = getFunctionFromToken(curToken);
|
||||
|
||||
if (curFunction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Iterator<HighlightToken> it = highlightTokens.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
HighlightToken tok = it.next();
|
||||
Function iterFunction = getFunctionFromToken(tok.getToken());
|
||||
if (iterFunction.equals(curFunction)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
highlightTokens.notifyListeners();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -259,6 +259,7 @@ public class RenameVariableAction extends AbstractDecompilerAction {
|
|||
}
|
||||
finally {
|
||||
program.endTransaction(transaction, commit);
|
||||
controller.getDecompilerPanel().tokenRenamed(tokenAtCursor, nameTask.getNewName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
package ghidra.app.plugin.core.decompile.actions;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.KeyBindingData;
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.component.DecompilerController;
|
||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||
import ghidra.app.decompiler.component.HighlightToken;
|
||||
import ghidra.app.decompiler.component.HighlightTokenObservableList;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.pcode.HighVariable;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.UndefinedFunction;
|
||||
|
||||
public class SetHighlightAction extends DockingAction {
|
||||
private DecompilerPanel panel;
|
||||
private DecompilerController controller;
|
||||
|
||||
private int minColorSaturation = 100;
|
||||
private int defaultColorAlpha = 100;
|
||||
|
||||
public SetHighlightAction(String owner, DecompilerController controller) {
|
||||
this(owner, controller, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the menu items, hotkeys and set the option to enabled according
|
||||
* to the decompileOptions
|
||||
*/
|
||||
public SetHighlightAction(String owner, DecompilerController controller, boolean isEnabled) {
|
||||
super("Display.Custom Highlights", owner, false);
|
||||
this.panel = controller.getDecompilerPanel();
|
||||
this.controller = controller;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Highlight Token" }, "Decompile"));
|
||||
setKeyBindingData(new KeyBindingData(KeyEvent.VK_C, 0));
|
||||
setHelpLocation(new HelpLocation(HelpTopics.SELECTION, getName()));
|
||||
|
||||
setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the highlighting accounting - This removes all highlighting.
|
||||
*/
|
||||
public void reset() {
|
||||
if (panel != null) {
|
||||
panel.getHighlightedTokens().clear();
|
||||
panel.tokenHighlightsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (!(context instanceof DecompilerActionContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Function function = controller.getFunction();
|
||||
if (function instanceof UndefinedFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DecompilerActionContext decompilerActionContext = (DecompilerActionContext) context;
|
||||
if (decompilerActionContext.isDecompiling()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClangToken tokenAtCursor = panel.getTokenAtCursor();
|
||||
if (tokenAtCursor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HighVariable variable = tokenAtCursor.getHighVariable();
|
||||
tokenAtCursor.getSyntaxType();
|
||||
if (variable == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setEnabled(boolean newValue) {
|
||||
|
||||
if (newValue == false) {
|
||||
panel.repaintHighlightTokens(true);
|
||||
}
|
||||
|
||||
return super.setEnabled(newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (panel != null) {
|
||||
ClangToken tokenAtCursor = panel.getTokenAtCursor();
|
||||
|
||||
HighlightTokenObservableList<HighlightToken> highlightTokens = panel.getHighlightedTokens();
|
||||
|
||||
Function func = controller.getDecompileData().getFunction();
|
||||
|
||||
Color highlightColor = getNewColor();
|
||||
HighlightToken htoken = new HighlightToken(tokenAtCursor, highlightColor, func);
|
||||
|
||||
// If token was already highlighted (in the list), we remove it.
|
||||
if (highlightTokens.remove(htoken)) {
|
||||
panel.clearHighlights();
|
||||
panel.setHighlightedTokens(highlightTokens);
|
||||
panel.repaintHighlightTokens(true);
|
||||
panel.tokenHighlightsChanged();
|
||||
} else {
|
||||
// Token was not in the list, this is a new request to set highlighting
|
||||
highlightTokens.add(htoken);
|
||||
panel.setHighlightedTokens(highlightTokens);
|
||||
panel.addTokenHighlight(tokenAtCursor, highlightColor);
|
||||
panel.tokenHighlightsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Color getNewColor() {
|
||||
return new Color((int)(minColorSaturation + Math.random() * (256 - minColorSaturation)),
|
||||
(int)(minColorSaturation + Math.random() * (256 - minColorSaturation)),
|
||||
(int)(minColorSaturation + Math.random() * (256 - minColorSaturation)), defaultColorAlpha);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue