diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java index 639ea7133a..d64543b57c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -15,6 +15,8 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import java.util.regex.Matcher; + import ghidra.app.util.NamespaceUtils; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractLabelMsSymbol; @@ -22,8 +24,6 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.FunctionManager; -import ghidra.program.model.symbol.Namespace; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -38,7 +38,6 @@ public class LabelSymbolApplier extends MsSymbolApplier { * Constructor * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed - * @throws CancelledException upon user cancellation */ public LabelSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); @@ -52,28 +51,74 @@ public class LabelSymbolApplier extends MsSymbolApplier { @Override void apply() throws PdbException, CancelledException { - if (!applicator.getPdbApplicatorOptions().applyInstructionLabels()) { + String label = getLabel(); + if (label == null) { return; } - // Place compiler generated symbols (e.g., $LN9) within containing function when possible - String name = symbol.getName(); + Address symbolAddress = applicator.getAddress(symbol); - if (applicator.isInvalidAddress(symbolAddress, name)) { + if (applicator.isInvalidAddress(symbolAddress, label)) { return; } - FunctionManager functionManager = applicator.getProgram().getFunctionManager(); - // TODO: What do we do with labels such as this?... "__catch$?test_eh1@@YAHXZ$7" - if (name.startsWith("$") && !name.contains(Namespace.DELIMITER)) { - Function f = functionManager.getFunctionContaining(symbolAddress); - if (f != null && !f.getName().equals(name)) { - name = NamespaceUtils.getNamespaceQualifiedName(f, name, true); - } - } - applicator.createSymbol(symbolAddress, name, false); + applicator.createSymbol(symbolAddress, label, false); } @Override void applyTo(MsSymbolApplier applyToApplier) { - // Do nothing + String label = getLabel(); + if (label == null) { + return; + } + + Address symbolAddress = applicator.getAddress(symbol); + if (applicator.isInvalidAddress(symbolAddress, label)) { + return; + } + + if (applyToApplier instanceof FunctionSymbolApplier functionSymbolApplier) { + Function f = functionSymbolApplier.getFunction(); + if (f != null && !f.getName().equals(label)) { + label = NamespaceUtils.getNamespaceQualifiedName(f, label, true); + } + } + + // No longer doing this, but instead letting namespace come from GPROC sequence... that way, + // labels will pertain to functions even if landing inside other function address range. + // Keeping code here (commented out), replaced by above code, until we get other issues + // figured out. +// FunctionManager functionManager = applicator.getProgram().getFunctionManager(); +// // TODO: What do we do with labels such as this?... "__catch$?test_eh1@@YAHXZ$7" +// if (!label.contains(Namespace.DELIMITER)) { +// Function f = functionManager.getFunctionContaining(symbolAddress); +// if (f != null && !f.getName().equals(label)) { +// label = NamespaceUtils.getNamespaceQualifiedName(f, label, true); +// } +// } + + // TODO: Before we turn on label applications.... we probably need to change order on + // how function symbols are applied. Perhaps we need to apply all GPROC symbols before + // we apply their internals (frames, local vars, labels, blocks) because some labels (here) + // are getting applied and becoming primary (because some have addresses that are located + // outside of the the address range of their GPROC, and will prevent another GPROC at the + // same address as the label from becoming primary (e.g., $LN7 of cn3 at a750). + applicator.createSymbol(symbolAddress, label, false); + } + + /** + * Returns label to apply or null if label excluded + * @return label to process or null + */ + private String getLabel() { + if (!applicator.getPdbApplicatorOptions().applyInstructionLabels()) { + return null; + } + // Place compiler generated symbols (e.g., $LN9) within containing function when possible + String label = symbol.getName(); + Matcher m = + applicator.getPdbApplicatorOptions().excludeInstructionLabelsPattern().matcher(label); + if (m.find()) { + return null; + } + return label; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java index 81a64bebb6..60693fb83c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java @@ -15,9 +15,14 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb; import ghidra.framework.options.Options; import ghidra.util.HelpLocation; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; /** * Options used while using a {@link DefaultPdbApplicator} to apply a PDB ({@link AbstractPdb}) to a @@ -51,6 +56,29 @@ public class PdbApplicatorOptions { "If checked, labels associated with instructions will be applied."; private static final boolean DEFAULT_APPLY_INSTRUCTION_LABELS = false; private boolean applyInstructionLabels; + // If the above option is enabled, allowing instruction labels to be applied, this + // edit box provides a filter to prevent any labels matching this pattern from being + // applied to the program. + private static final String OPTION_NAME_EXCLUDE_INSTRUCTION_LABELS = + "Exclude Instruction Labels"; + private static final String OPTION_DESCRIPTION_EXCLUDE_INSTRUCTION_LABELS = + "Regular expression describing instruction labels to be excluded when \"" + + OPTION_NAME_APPLY_INSTRUCTION_LABELS + "\" is enabled."; + private static final String DEFAULT_EXCLUDE_INSTRUCTION_LABELS = "$a"; // "$a" will never match + private Pattern DEFAULT_EXCLUDE_INSTRUCTION_LABELS_PATTERN; + { + try { + DEFAULT_EXCLUDE_INSTRUCTION_LABELS_PATTERN = + Pattern.compile(DEFAULT_EXCLUDE_INSTRUCTION_LABELS); + } + catch (PatternSyntaxException e) { + throw new AssertException( + "Programming error: invalid default exclude labels pattern"); + } + } + + private String excludeInstructionLabels; + private Pattern excludeInstructionLabelsPattern; // Attempt to map address using existing mangled symbols. private static final String OPTION_NAME_ADDRESS_REMAP = "Address Remap Using Existing Symbols"; @@ -169,6 +197,14 @@ public class PdbApplicatorOptions { options.registerOption(OPTION_NAME_APPLY_INSTRUCTION_LABELS, applyInstructionLabels, help, OPTION_DESCRIPTION_APPLY_INSTRUCTION_LABELS); + // If the above option is enabled, allowing instruction labels to be applied, this + // edit box provides a filter to prevent any labels matching this pattern from being + // applied to the program. + options.registerOption(OPTION_NAME_EXCLUDE_INSTRUCTION_LABELS, excludeInstructionLabels, + help, OPTION_DESCRIPTION_EXCLUDE_INSTRUCTION_LABELS); + validatePattern(options); + // Can we disable this one above based upon the one above it? Do it with custom editor. + // The remap capability is not completely implemented... do not turn on. options.registerOption(OPTION_NAME_ADDRESS_REMAP, remapAddressUsingExistingPublicMangledSymbols, help, @@ -206,10 +242,17 @@ public class PdbApplicatorOptions { applyCodeScopeBlockComments = options.getBoolean( OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, applyCodeScopeBlockComments); - // Mechanism to apply instruction labels is not yet implemented-> does nothing + // Mechanism to apply instruction labels applyInstructionLabels = options.getBoolean(OPTION_NAME_APPLY_INSTRUCTION_LABELS, applyInstructionLabels); + // If the above option is enabled, allowing instruction labels to be applied, this + // edit box provides a filter to prevent any labels matching this pattern from being + // applied to the program + excludeInstructionLabels = + options.getString(OPTION_NAME_EXCLUDE_INSTRUCTION_LABELS, excludeInstructionLabels); + validatePattern(options); + remapAddressUsingExistingPublicMangledSymbols = options.getBoolean( OPTION_NAME_ADDRESS_REMAP, remapAddressUsingExistingPublicMangledSymbols); @@ -223,12 +266,32 @@ public class PdbApplicatorOptions { } } + // The following code cannot remain in a final solution... The options editor does + // not get an updated String written to it. Ultimately, there is no way to validate + // this value other than have a custom options editor, which is the direction we + // already believe we need to take for purposes of appropriately grouping options + // (other than in an alphabetical order). + private void validatePattern(Options options) { + try { + excludeInstructionLabelsPattern = Pattern.compile(excludeInstructionLabels); + } + catch (PatternSyntaxException e) { + Msg.error(this, "Invalid " + OPTION_NAME_EXCLUDE_INSTRUCTION_LABELS + " value: " + + excludeInstructionLabels + "\n Resetting to default value."); + excludeInstructionLabels = DEFAULT_EXCLUDE_INSTRUCTION_LABELS; + excludeInstructionLabelsPattern = DEFAULT_EXCLUDE_INSTRUCTION_LABELS_PATTERN; + options.restoreDefaultValue(OPTION_NAME_EXCLUDE_INSTRUCTION_LABELS); + } + } + /** * Set the options to their default values */ public void setDefaults() { applyCodeScopeBlockComments = DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS; applyInstructionLabels = DEFAULT_APPLY_INSTRUCTION_LABELS; + excludeInstructionLabels = DEFAULT_EXCLUDE_INSTRUCTION_LABELS; + excludeInstructionLabelsPattern = DEFAULT_EXCLUDE_INSTRUCTION_LABELS_PATTERN; control = DEFAULT_CONTROL; remapAddressUsingExistingPublicMangledSymbols = DEFAULT_REMAP_ADDRESSES_USING_EXISTING_SYMBOLS; @@ -269,6 +332,34 @@ public class PdbApplicatorOptions { return applyInstructionLabels; } + // If the above option is enabled, allowing instruction labels to be applied, this + // edit box provides a filter to prevent any labels matching this pattern from being + // applied to the program + /** + * Set regular expression string describing labels to exclude from application. + * @param excludeInstructionLabels regular expression describing instruction labels to exclude + */ + public void setApplyInstructionLabels(String excludeInstructionLabels) { + this.excludeInstructionLabels = excludeInstructionLabels; + } + + /** + * Returns the string containing the regular expression describing instruction labels being + * excluded from application. Applicable when {@code applyInstructionLabels} is enabled + * @return the regular expression String + */ + public String excludeInstructionLabels() { + return excludeInstructionLabels; + } + + /** + * Returns the Regex Pattern for the Exclude Instruction Labels field. + * @return the Pattern. + */ + public Pattern excludeInstructionLabelsPattern() { + return excludeInstructionLabelsPattern; + } + /** * Set processing control for PdbApplicator * @param control the processing control