mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-24 13:21:22 +08:00
GP-4037 Changes the various listing comment fields (PRE, POST, EOL, PLATE) to also display offcut comments, colored red
This commit is contained in:
@@ -37,6 +37,7 @@ color.fg.listing.comment.ref.repeatable = color.palette.cornflowerblue
|
||||
color.fg.listing.comment.plate = color.palette.gray
|
||||
color.fg.listing.comment.post = color.palette.blue
|
||||
color.fg.listing.comment.pre = color.palette.indigo
|
||||
color.fg.listing.comment.offcut = color.fg.error
|
||||
color.fg.listing.ref.bad = color.fg.error
|
||||
color.fg.listing.ext.entrypoint = color.palette.magenta
|
||||
color.fg.listing.ext.ref.resolved = color.palette.darkorange
|
||||
|
||||
@@ -73,6 +73,15 @@
|
||||
<A href="help/topics/Annotations/Annotations.html"><B>annotations</B></A> to change the display
|
||||
characteristics of data entered into the comment fields.</P>
|
||||
|
||||
<P><IMG src="help/shared/note.png" border="0">A comment can also be offcut. This means it is
|
||||
defined on an address that is in the middle of an instruction or data item. In this case,
|
||||
the offcut comment will be displayed in the appropriate field (EOL, PLATE, POST, PRE) on the
|
||||
instruction or data that contains that address and will be colored red to indicate the comment
|
||||
has been attached to an invalid address. Note that this comment can only be edited if the
|
||||
containing instruction or data is first cleared so that the individual addresses are shown in
|
||||
the listing.
|
||||
</P>
|
||||
|
||||
<H2><A name="Edit_Comments"></A> <A name="Edit_Repeatable_Comment"></A> Adding or Editing
|
||||
Comments (Set Comment)</H2>
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -20,8 +20,7 @@ import java.util.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
import ghidra.app.util.viewer.field.EolEnablement;
|
||||
import ghidra.app.util.viewer.field.EolExtraCommentsOption;
|
||||
import ghidra.app.util.viewer.field.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
@@ -53,6 +52,7 @@ public class EolComments {
|
||||
private List<RefRepeatComment> refRepeatables = new ArrayList<>();
|
||||
private List<String> autos = new ArrayList<>();
|
||||
private List<Reference> references = new ArrayList<>();
|
||||
private List<String> offcuts = new ArrayList<>();
|
||||
|
||||
// used to signal the operand is already displaying a pointer reference, so there is no need for
|
||||
// this class to create a comment to do the same
|
||||
@@ -75,6 +75,7 @@ public class EolComments {
|
||||
loadRepeatables();
|
||||
loadRefRepeatables();
|
||||
loadAutos();
|
||||
loadOffcutEols();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,10 +102,15 @@ public class EolComments {
|
||||
|
||||
private void loadEols() {
|
||||
Collection<String> comments =
|
||||
Arrays.asList(codeUnit.getCommentAsArray(CodeUnit.EOL_COMMENT));
|
||||
Arrays.asList(codeUnit.getCommentAsArray(CommentType.EOL));
|
||||
addStrings(comments, eols);
|
||||
}
|
||||
|
||||
private void loadOffcutEols() {
|
||||
Collection<String> comments = CommentUtils.getOffcutComments(codeUnit, CommentType.EOL);
|
||||
addStrings(comments, offcuts);
|
||||
}
|
||||
|
||||
private void loadRepeatables() {
|
||||
boolean hasOtherComments = !eols.isEmpty();
|
||||
if (!extraCommentsOption.isShowingRepeatables(hasOtherComments)) {
|
||||
@@ -195,6 +201,10 @@ public class EolComments {
|
||||
return !autos.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isShowingOffcutComments() {
|
||||
return !offcuts.isEmpty();
|
||||
}
|
||||
|
||||
private Collection<String> getReferencePreviews() {
|
||||
|
||||
loadReferences();
|
||||
@@ -642,6 +652,10 @@ public class EolComments {
|
||||
return Collections.unmodifiableList(autos);
|
||||
}
|
||||
|
||||
public List<String> getOffcutEolComments() {
|
||||
return Collections.unmodifiableList(offcuts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ import docking.widgets.fieldpanel.field.*;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import generic.theme.Gui;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
import ghidra.util.StringUtilities;
|
||||
@@ -440,4 +440,49 @@ public class CommentUtils {
|
||||
return Collections.unmodifiableSet(getAnnotatedStringHandlerMap().keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of offcut comments for the given code unit. All the offcut comments from
|
||||
* possibly multiple addresses will be combined into a single list of comment lines.
|
||||
* @param cu the code unit to get offcut comments for
|
||||
* @param type the type of comment to retrieve (EOL, PRE, PLATE, POST)
|
||||
* @return a list of all offcut comments for the given code unit.
|
||||
*/
|
||||
public static List<String> getOffcutComments(CodeUnit cu, CommentType type) {
|
||||
// internal data items handle EOL comments, so ignore EOL comments on items that
|
||||
// have sub-components
|
||||
if (type == CommentType.EOL && cu instanceof Data data) {
|
||||
if (data.getNumComponents() > 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
Address start = cu.getMinAddress().next();
|
||||
Address end = cu.getMaxAddress();
|
||||
if (start == null || start.compareTo(end) > 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Listing listing = cu.getProgram().getListing();
|
||||
AddressSet addrSet = new AddressSet(start, cu.getMaxAddress());
|
||||
AddressIterator it = listing.getCommentAddressIterator(type, addrSet, true);
|
||||
|
||||
if (!it.hasNext()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<String> offcutComments = new ArrayList<>();
|
||||
|
||||
while (it.hasNext()) {
|
||||
Address next = it.next();
|
||||
String comment = listing.getComment(type, next);
|
||||
if (comment != null) {
|
||||
String[] lines = StringUtilities.toLines(comment);
|
||||
for (String line : lines) {
|
||||
offcutComments.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
return offcutComments;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-1
@@ -64,6 +64,7 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
private int repeatableCommentStyle;
|
||||
private int automaticCommentStyle;
|
||||
private int refRepeatableCommentStyle;
|
||||
private int offcutCommentStyle;
|
||||
|
||||
private EolExtraCommentsOption extraCommentsOption = new EolExtraCommentsOption();
|
||||
|
||||
@@ -292,6 +293,14 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
elementList.addAll(elements);
|
||||
}
|
||||
|
||||
if (comments.isShowingOffcutComments()) {
|
||||
prefix = createPrefix(CommentStyle.OFFCUT);
|
||||
int row = getNextRow(elementList);
|
||||
List<String> offcuts = comments.getOffcutEolComments();
|
||||
List<FieldElement> elements = convertToFieldElements(program, offcuts, prefix, row);
|
||||
elementList.addAll(elements);
|
||||
}
|
||||
|
||||
if (elementList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -316,11 +325,16 @@ public class EolCommentFieldFactory extends FieldFactory {
|
||||
return new AttributedString(SEMICOLON_PREFIX, CommentColors.AUTO,
|
||||
getMetrics(automaticCommentStyle), false, null);
|
||||
}
|
||||
if (commentStyle == CommentStyle.OFFCUT) {
|
||||
return new AttributedString(SEMICOLON_PREFIX, CommentColors.OFFCUT,
|
||||
getMetrics(style), false, null);
|
||||
}
|
||||
|
||||
throw new AssertException("Unexected comment style: " + commentStyle);
|
||||
}
|
||||
|
||||
private enum CommentStyle {
|
||||
EOL, REPEATABLE, REF_REPEATABLE, AUTO;
|
||||
EOL, REPEATABLE, REF_REPEATABLE, AUTO, OFFCUT;
|
||||
}
|
||||
|
||||
private int getNextRow(List<FieldElement> elementList) {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -69,6 +69,7 @@ public class ListingColors {
|
||||
public static final GColor PRE= new GColor("color.fg.listing.comment.pre");
|
||||
public static final GColor REPEATABLE = new GColor("color.fg.listing.comment.repeatable");
|
||||
public static final GColor REF_REPEATABLE = new GColor("color.fg.listing.comment.ref.repeatable");
|
||||
public static final GColor OFFCUT = new GColor("color.fg.listing.comment.offcut");
|
||||
}
|
||||
|
||||
public static class LabelColors {
|
||||
|
||||
+26
-10
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -40,6 +40,7 @@ import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Class for showing plate comments
|
||||
@@ -142,12 +143,14 @@ public class PlateFieldFactory extends FieldFactory {
|
||||
CodeUnit cu = (CodeUnit) proxy.getObject();
|
||||
boolean isClipped = false;
|
||||
List<FieldElement> elements = new ArrayList<>();
|
||||
String commentText = getCommentText(cu);
|
||||
List<String> offcutComments = CommentUtils.getOffcutComments(cu, CommentType.PLATE);
|
||||
String commentText = getCommentText(cu, offcutComments);
|
||||
|
||||
if (StringUtils.isBlank(commentText)) {
|
||||
getDefaultFieldElements(cu, elements);
|
||||
}
|
||||
else {
|
||||
isClipped = getFormattedFieldElements(cu, elements);
|
||||
isClipped = getFormattedFieldElements(cu, elements, offcutComments);
|
||||
}
|
||||
|
||||
if (elements.isEmpty()) {
|
||||
@@ -170,14 +173,15 @@ public class PlateFieldFactory extends FieldFactory {
|
||||
return listingField;
|
||||
}
|
||||
|
||||
private boolean getFormattedFieldElements(CodeUnit cu, List<FieldElement> elements) {
|
||||
private boolean getFormattedFieldElements(CodeUnit cu, List<FieldElement> elements,
|
||||
List<String> offcutComments) {
|
||||
|
||||
int numberBlankLines = getNumberBlankLines(cu, true);
|
||||
|
||||
addBlankLines(elements, numberBlankLines, cu);
|
||||
|
||||
String[] comments = cu.getCommentAsArray(CodeUnit.PLATE_COMMENT);
|
||||
return generateFormattedPlateComment(elements, comments, cu.getProgram());
|
||||
return generateFormattedPlateComment(elements, comments, offcutComments, cu.getProgram());
|
||||
}
|
||||
|
||||
private void getDefaultFieldElements(CodeUnit cu, List<FieldElement> elements) {
|
||||
@@ -205,7 +209,7 @@ public class PlateFieldFactory extends FieldFactory {
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getCommentText(CodeUnit cu) {
|
||||
private String getCommentText(CodeUnit cu, List<String> offcutComments) {
|
||||
String[] comments = cu.getCommentAsArray(CodeUnit.PLATE_COMMENT);
|
||||
if (comments == null) {
|
||||
return null;
|
||||
@@ -218,6 +222,12 @@ public class PlateFieldFactory extends FieldFactory {
|
||||
}
|
||||
buffy.append(comment);
|
||||
}
|
||||
for (String offcut : offcutComments) {
|
||||
if (buffy.length() != 0) {
|
||||
buffy.append('\n');
|
||||
}
|
||||
buffy.append(offcut);
|
||||
}
|
||||
return buffy.toString();
|
||||
}
|
||||
|
||||
@@ -226,8 +236,8 @@ public class PlateFieldFactory extends FieldFactory {
|
||||
* data is clipped because it is too long to display.
|
||||
*/
|
||||
private boolean generateFormattedPlateComment(List<FieldElement> elements, String[] comments,
|
||||
Program p) {
|
||||
if (comments == null || comments.length == 0) {
|
||||
List<String> offcutComments, Program p) {
|
||||
if (offcutComments.isEmpty() && CollectionUtils.isBlank(comments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -245,6 +255,11 @@ public class PlateFieldFactory extends FieldFactory {
|
||||
for (String c : comments) {
|
||||
commentsList.add(CommentUtils.parseTextForAnnotations(c, p, prototype, row++));
|
||||
}
|
||||
for (String offcut : offcutComments) {
|
||||
AttributedString as = new AttributedString(offcut, CommentColors.OFFCUT,
|
||||
getMetrics(style), false, null);
|
||||
commentsList.add(new TextFieldElement(as, commentsList.size(), 0));
|
||||
}
|
||||
|
||||
if (isWordWrap) {
|
||||
int spaceWidth = getMetrics().charWidth(' ');
|
||||
@@ -554,7 +569,8 @@ public class PlateFieldFactory extends FieldFactory {
|
||||
*/
|
||||
|
||||
CodeUnit cu = (CodeUnit) obj;
|
||||
String commentText = getCommentText(cu);
|
||||
List<String> offcutComments = CommentUtils.getOffcutComments(cu, CommentType.PLATE);
|
||||
String commentText = getCommentText(cu, offcutComments);
|
||||
boolean hasComment = true;
|
||||
if (StringUtils.isBlank(commentText)) {
|
||||
String defaultComment = getDefaultComment(cu);
|
||||
|
||||
+19
-11
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -137,21 +137,22 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||
}
|
||||
|
||||
String[] autoComment = getAutoPostComment(cu);
|
||||
List<String> offcutComments = CommentUtils.getOffcutComments(cu, CommentType.POST);
|
||||
|
||||
String[] comments = cu.getCommentAsArray(CodeUnit.POST_COMMENT);
|
||||
if (comments != null && comments.length > 0 && (cu instanceof Data)) {
|
||||
return getTextField(comments, autoComment, proxy, x, false);
|
||||
return getTextField(comments, autoComment, offcutComments, proxy, x, false);
|
||||
}
|
||||
if (cu instanceof Instruction) {
|
||||
Instruction instr = (Instruction) cu;
|
||||
if (instr.getDelaySlotDepth() > 0) {
|
||||
if (comments != null && comments.length > 0) {
|
||||
return getTextField(comments, null, proxy, x, false);
|
||||
return getTextField(comments, null, offcutComments, proxy, x, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// check field options
|
||||
return getTextFieldForOptions(instr, comments, autoComment, proxy, x);
|
||||
return getTextFieldForOptions(instr, comments, autoComment, offcutComments, proxy, x);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -386,7 +387,7 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||
}
|
||||
|
||||
private ListingTextField getTextFieldForOptions(Instruction instr, String[] comments,
|
||||
String[] autoComment, ProxyObj<?> proxy, int xStart) {
|
||||
String[] autoComment, List<String> offcutComments, ProxyObj<?> proxy, int xStart) {
|
||||
Listing listing = instr.getProgram().getListing();
|
||||
Address addr = instr.getMinAddress();
|
||||
FlowType flowType = instr.getFlowType();
|
||||
@@ -405,14 +406,14 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||
String[] str = new String[] {
|
||||
FUN_EXIT_FLAG_LEADER + function.getName() + FUN_EXIT_FLAG_TAIL };
|
||||
|
||||
return getTextField(str, autoComment, proxy, xStart, true);
|
||||
return getTextField(str, autoComment, offcutComments, proxy, xStart, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add Jump/Terminator
|
||||
if (flagJMPsRETs && !instr.hasFallthrough()) {
|
||||
String[] str = new String[] { DEFAULT_FLAG_COMMENT };
|
||||
return getTextField(str, autoComment, proxy, xStart, true);
|
||||
return getTextField(str, autoComment, offcutComments, proxy, xStart, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,11 +473,12 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
return getTextField(comments, autoComment, proxy, xStart, false);
|
||||
return getTextField(comments, autoComment, offcutComments, proxy, xStart, false);
|
||||
}
|
||||
|
||||
private ListingTextField getTextField(String[] comments, String[] autoComment,
|
||||
ProxyObj<?> proxy, int xStart, boolean useLinesAfterBlock) {
|
||||
List<String> offcutComments, ProxyObj<?> proxy, int xStart,
|
||||
boolean useLinesAfterBlock) {
|
||||
|
||||
if (comments == null) {
|
||||
comments = EMPTY_STRING_ARRAY;
|
||||
@@ -489,7 +491,8 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||
((comments.length == 0 && !useLinesAfterBlock) || alwaysShowAutomatic)
|
||||
? autoComment.length
|
||||
: 0;
|
||||
if (!useLinesAfterBlock && comments.length == 0 && nLinesAutoComment == 0) {
|
||||
if (!useLinesAfterBlock && comments.length == 0 && nLinesAutoComment == 0 &&
|
||||
offcutComments.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -507,6 +510,11 @@ public class PostCommentFieldFactory extends FieldFactory {
|
||||
fields.add(CommentUtils.parseTextForAnnotations(comment, program, prototypeString,
|
||||
fields.size()));
|
||||
}
|
||||
for (String offcutComment : offcutComments) {
|
||||
AttributedString as = new AttributedString(offcutComment, CommentColors.OFFCUT,
|
||||
getMetrics(style), false, null);
|
||||
fields.add(new TextFieldElement(as, fields.size(), 0));
|
||||
}
|
||||
if (isWordWrap) {
|
||||
fields = FieldUtils.wrap(fields, width);
|
||||
}
|
||||
|
||||
+11
-3
@@ -112,8 +112,9 @@ public class PreCommentFieldFactory extends FieldFactory {
|
||||
String[] autoComment = getAutoPreComments(cu);
|
||||
|
||||
String[] comments = getDefinedPreComments(cu);
|
||||
List<String> offcutComments = CommentUtils.getOffcutComments(cu, CommentType.PRE);
|
||||
|
||||
return getTextField(comments, autoComment, proxy, x);
|
||||
return getTextField(comments, autoComment, offcutComments, proxy, x);
|
||||
}
|
||||
|
||||
private String[] getDefinedPreComments(CodeUnit cu) {
|
||||
@@ -353,7 +354,7 @@ public class PreCommentFieldFactory extends FieldFactory {
|
||||
}
|
||||
|
||||
private ListingTextField getTextField(String[] comments, String[] autoComment,
|
||||
ProxyObj<?> proxy, int xStart) {
|
||||
List<String> offcutComments, ProxyObj<?> proxy, int xStart) {
|
||||
|
||||
if (comments == null) {
|
||||
comments = EMPTY_STRING_ARRAY;
|
||||
@@ -364,7 +365,8 @@ public class PreCommentFieldFactory extends FieldFactory {
|
||||
|
||||
int nLinesAutoComment =
|
||||
(comments.length == 0 || alwaysShowAutomatic) ? autoComment.length : 0;
|
||||
if (comments.length == 0 && nLinesAutoComment == 0) {
|
||||
|
||||
if (comments.length == 0 && nLinesAutoComment == 0 && offcutComments.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -382,6 +384,12 @@ public class PreCommentFieldFactory extends FieldFactory {
|
||||
fields.add(CommentUtils.parseTextForAnnotations(comment, program, prototypeString,
|
||||
fields.size()));
|
||||
}
|
||||
for (String offcutComment : offcutComments) {
|
||||
AttributedString as = new AttributedString(offcutComment, CommentColors.OFFCUT,
|
||||
getMetrics(style), false, null);
|
||||
fields.add(new TextFieldElement(as, fields.size(), 0));
|
||||
}
|
||||
|
||||
if (isWordWrap) {
|
||||
fields = FieldUtils.wrap(fields, width);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user