diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java index a7fd6a9be3..0ba4d9ace1 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java @@ -38,7 +38,7 @@ import ghidra.app.plugin.core.equate.EquatePlugin; import ghidra.app.plugin.core.function.FunctionPlugin; import ghidra.app.plugin.core.label.LabelMgrPlugin; import ghidra.app.plugin.core.symtable.SymbolTablePlugin; -import ghidra.app.plugin.debug.MemoryUsagePlugin; +import ghidra.app.plugin.runtimeinfo.RuntimeInfoPlugin; import ghidra.framework.plugintool.util.PluginException; import ghidra.program.model.address.AddressOverflowException; import ghidra.program.model.data.Undefined4DataType; @@ -109,7 +109,7 @@ public class DebuggerManualTest extends AbstractGhidraHeadedDebuggerTest { addPlugin(tool, LabelMgrPlugin.class); //addPlugin(tool, LocationReferencesPlugin.class); //addPlugin(tool, MarkerManagerPlugin.class); - addPlugin(tool, MemoryUsagePlugin.class); + addPlugin(tool, RuntimeInfoPlugin.class); //addPlugin(tool, MemSearchPlugin.class); //addPlugin(tool, MnemonicSearchPlugin.class); //addPlugin(tool, NextPrevAddressPlugin.class); diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index 64a1f11ba3..537ff38f3f 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -268,7 +268,6 @@ src/main/help/help/topics/FrontEndPlugin/Project_Info.htm||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/Re-opening_a_Project.htm||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/Restore_Project.htm||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/Saving_a_Ghidra_Project.htm||GHIDRA||||END| -src/main/help/help/topics/FrontEndPlugin/ShowMemoryUsage.htm||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/ArchiveFileExists.png||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/ArchiveProject.png||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/ChangeAccessList.png||GHIDRA||||END| @@ -285,7 +284,6 @@ src/main/help/help/topics/FrontEndPlugin/images/DeleteProject.png||GHIDRA||||END src/main/help/help/topics/FrontEndPlugin/images/EditPluginPath.png||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/EditProjectAccessList.png||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/LinkOtherProject.png||GHIDRA||||END| -src/main/help/help/topics/FrontEndPlugin/images/MemoryUsage.png||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/NonSharedProjectInfo.png||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/OpenProject.png||GHIDRA||||END| src/main/help/help/topics/FrontEndPlugin/images/PrivateFileIcon.png||GHIDRA||||END| @@ -500,6 +498,8 @@ src/main/help/help/topics/Repository/images/SymbolRemoveVsChangeConflict.png||GH src/main/help/help/topics/Repository/images/SymbolRenameWithScopeConflict.png||GHIDRA||reviewed||END| src/main/help/help/topics/Repository/images/UserDefinedUseForAllConflict.png||GHIDRA||reviewed||END| src/main/help/help/topics/ResourceActionsPlugin/ResourceActions.html||GHIDRA||||END| +src/main/help/help/topics/RuntimeInfoPlugin/InstalledProcessors.htm||GHIDRA||||END| +src/main/help/help/topics/RuntimeInfoPlugin/RuntimeInfo.htm||GHIDRA||||END| src/main/help/help/topics/ScalarSearchPlugin/The_Scalar_Table.htm||GHIDRA||||END| src/main/help/help/topics/ScalarSearchPlugin/images/ScalarWindow.png||GHIDRA||||END| src/main/help/help/topics/ScalarSearchPlugin/images/SearchAllScalarsDialog.png||GHIDRA||||END| diff --git a/Ghidra/Features/Base/src/main/help/help/topics/About/About_Ghidra.htm b/Ghidra/Features/Base/src/main/help/help/topics/About/About_Ghidra.htm index bf367a06e1..29c7df9edf 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/About/About_Ghidra.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/About/About_Ghidra.htm @@ -61,25 +61,6 @@ - -

Installed Processors

- -

The Installed Processors dialog displays all processors supported by the various - language modules currently installed. This list is quite brief and does not convey the - assorted variants which may be implemented for each processor.

- -
-

  This option is also available from the - Ghidra Project - Window 

-
- -

To view the Installed Processors list

- -

User Agreement

diff --git a/Ghidra/Features/Base/src/main/help/help/topics/FileSystemBrowserPlugin/FileSystemBrowserPlugin.html b/Ghidra/Features/Base/src/main/help/help/topics/FileSystemBrowserPlugin/FileSystemBrowserPlugin.html index c38bce26b3..6c49462fa8 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/FileSystemBrowserPlugin/FileSystemBrowserPlugin.html +++ b/Ghidra/Features/Base/src/main/help/help/topics/FileSystemBrowserPlugin/FileSystemBrowserPlugin.html @@ -29,16 +29,6 @@ Subdirectories of your local computer's file system can also be opened in this manner.

- -

Help Menu Actions

-
-

Display Supported File Systems - and Loaders

- -
-

Lists the currently supported file systems and loaders.

-
-

Right-click Context Menu Actions

diff --git a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/ShowMemoryUsage.htm b/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/ShowMemoryUsage.htm deleted file mode 100644 index fe3557a7dd..0000000000 --- a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/ShowMemoryUsage.htm +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Memory Usage - - - - - -

Memory Usage

- -

The Memory usage feature pops up a dialog showing continuous snapshots of the Ghidra memory - usage within the the Java Virtual Machine. It is primarily a diagnostic tool for Ghidra - developers.nbsp;

- -

To display the memory usage dialog:

- -
    -
  1. From the Project Window, Select HelpShow VM Memory from the - menu.
  2. - -
- - - - - -
- -

The four values displayed are as follows:

-
    -
  1. Max Memory - the maximum memory that the Java VM is allowed to use.
  2. -
  3. Total Memory - the amount of memory that the Java VM is currently using.
  4. -
  5. Free Memory - the amount of the "Total Memory" that is currently unused by the Ghidra application.
  6. -
  7. Used Memory - the amount of the "Total Memory" that is currently used by the Ghidra application.
  8. -
-

 

- - diff --git a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/images/MemoryUsage.png b/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/images/MemoryUsage.png deleted file mode 100644 index 749f2bcc68..0000000000 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/images/MemoryUsage.png and /dev/null differ diff --git a/Ghidra/Features/Base/src/main/help/help/topics/RuntimeInfoPlugin/InstalledProcessors.htm b/Ghidra/Features/Base/src/main/help/help/topics/RuntimeInfoPlugin/InstalledProcessors.htm new file mode 100644 index 0000000000..7500bfb74f --- /dev/null +++ b/Ghidra/Features/Base/src/main/help/help/topics/RuntimeInfoPlugin/InstalledProcessors.htm @@ -0,0 +1,27 @@ + + + + + Runtime Information + + + + + + + +

Installed Processors

+ +

The Installed Processors feature pops up a dialog showing a list of processors that the + active Ghidra application supports.

+ +

To display the Installed Processors dialog:

+ + + +

 

+ + diff --git a/Ghidra/Features/Base/src/main/help/help/topics/RuntimeInfoPlugin/RuntimeInfo.htm b/Ghidra/Features/Base/src/main/help/help/topics/RuntimeInfoPlugin/RuntimeInfo.htm new file mode 100644 index 0000000000..4307f17bc3 --- /dev/null +++ b/Ghidra/Features/Base/src/main/help/help/topics/RuntimeInfoPlugin/RuntimeInfo.htm @@ -0,0 +1,64 @@ + + + + + Runtime Information + + + + + + + +

Runtime Information

+ +

The Runtime Information feature pops up a dialog showing information about the internal + settings of the active Ghidra installation. It is primarily a diagnostic tool to aid in + debugging.

+ +

To display the Runtime Information dialog:

+ + + +

Runtime Information categories are organized in tabs. The following categories are provided: +

+ +

 

+ + diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java deleted file mode 100644 index 2f1f28cdb8..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java +++ /dev/null @@ -1,292 +0,0 @@ -/* ### - * 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 ghidra.app.plugin.core.help; - -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.Transferable; -import java.util.*; - -import javax.swing.*; - -import docking.ActionContext; -import docking.ReusableDialogComponentProvider; -import docking.action.DockingAction; -import docking.action.MenuData; -import docking.dnd.GClipboard; -import docking.dnd.StringTransferable; -import docking.tool.ToolConstants; -import docking.widgets.table.AbstractSortedTableModel; -import docking.widgets.table.GTable; -import ghidra.app.CorePluginPackage; -import ghidra.app.plugin.PluginCategoryNames; -import ghidra.app.util.HelpTopics; -import ghidra.framework.main.ApplicationLevelPlugin; -import ghidra.framework.plugintool.*; -import ghidra.framework.plugintool.util.PluginStatus; -import ghidra.program.model.lang.*; -import ghidra.program.util.DefaultLanguageService; -import ghidra.util.HelpLocation; -import ghidra.util.SystemUtilities; - -//@formatter:off -@PluginInfo( - status = PluginStatus.RELEASED, - packageName = CorePluginPackage.NAME, - category = PluginCategoryNames.COMMON, - shortDescription = "Displays list of installed processor modules", - description = "This plugin provides a Help action that displays a list of installed processor modules" -) -//@formatter:on -public class ProcessorListPlugin extends Plugin implements ApplicationLevelPlugin { - - private DockingAction processorListAction; - - private ProcessorListDialogProvider dialogProvider; - - public ProcessorListPlugin(PluginTool tool) { - super(tool); - } - - @Override - protected void init() { - setupActions(); - } - - @Override - public void dispose() { - tool.removeAction(processorListAction); - processorListAction.dispose(); - - if (dialogProvider != null) { - dialogProvider.dispose(); - } - super.dispose(); - } - - private void setupActions() { - - processorListAction = new DockingAction("Installed Processors", this.getName()) { - @Override - public void actionPerformed(ActionContext context) { - showProcessorList(); - } - }; - - processorListAction.setEnabled(true); - - processorListAction.setMenuBarData(new MenuData( - new String[] { ToolConstants.MENU_HELP, processorListAction.getName() }, null, "AAAZ")); - - processorListAction.setHelpLocation(new HelpLocation(HelpTopics.ABOUT, "ProcessorList")); - processorListAction.setDescription(getPluginDescription().getDescription()); - tool.addAction(processorListAction); - } - - private void dialogClosed() { - dialogProvider = null; - } - - private void showProcessorList() { - if (dialogProvider == null) { - dialogProvider = new ProcessorListDialogProvider(); - } - tool.showDialog(dialogProvider); - } - - private void copy(boolean asHtml) { - Clipboard systemClipboard = GClipboard.getSystemClipboard(); - Transferable transferable = new StringTransferable(getProcessorList(asHtml)); - systemClipboard.setContents(transferable, null); - } - - private Set getProcessors() { - TreeSet processors = new TreeSet<>(); - LanguageService languageService = DefaultLanguageService.getLanguageService(); - for (LanguageDescription languageDescription : languageService.getLanguageDescriptions( - true)) { - processors.add(languageDescription.getProcessor()); - } - return processors; - } - - private String getProcessorList(boolean asHtml) { - StringBuilder strBuilder = new StringBuilder(); - if (asHtml) { - strBuilder.append("\n"); - strBuilder.append("\n"); - } - - Set processors = getProcessors(); - int itemsPerColum = (processors.size() + 2) / 3; - int colCnt = 0; - - for (Processor processor : processors) { - if (asHtml) { - if ((colCnt % itemsPerColum) == 0) { - if (colCnt != 0) { - strBuilder.append("\n"); - } - strBuilder.append("\n
\n
    "); - } - strBuilder.append("
  • "); - } - ++colCnt; - strBuilder.append(processor.toString()); - if (asHtml) { - strBuilder.append("
  • "); - } - strBuilder.append("\n"); - } - if (asHtml) { - strBuilder.append("
\n
"); - strBuilder.append(""); - } - return strBuilder.toString(); - } - - private class ProcessorListDialogProvider extends ReusableDialogComponentProvider { - - ProcessorListDialogProvider() { - super("Installed Processor Modules", false, false, true, false); - ProcessorListTableProvider tableProvider = - new ProcessorListTableProvider(tool, getName()); - setRememberLocation(true); - addWorkPanel(tableProvider.getComponent()); - - setHelpLocation(new HelpLocation(HelpTopics.ABOUT, "ProcessorList")); - - if (SystemUtilities.isInDevelopmentMode()) { - - JButton copyButton = new JButton("Copy"); - copyButton.addActionListener(e -> copy(false)); - addButton(copyButton); - - JButton copyHtmlButton = new JButton("Copy as HTML"); - copyHtmlButton.addActionListener(e -> copy(true)); - addButton(copyHtmlButton); - } - - JButton closeButton = new JButton("Close"); - closeButton.addActionListener(e -> close()); - addButton(closeButton); - } - - @Override - protected void dialogClosed() { - super.dialogClosed(); - ProcessorListPlugin.this.dialogClosed(); - } - - } - - public class ProcessorListTableProvider extends ComponentProviderAdapter { - GTable table; - private ProcessorListTableModel processorTableModel; - private JScrollPane scrollPane; - - public ProcessorListTableProvider(PluginTool tool, String owner) { - super(tool, "Processor Table", owner); - buildTable(); - } - - @Override - public JComponent getComponent() { - return scrollPane; - } - - private void buildTable() { - - TreeSet processors = new TreeSet<>(); - LanguageService languageService = DefaultLanguageService.getLanguageService(); - for (LanguageDescription languageDescription : languageService.getLanguageDescriptions( - true)) { - processors.add(languageDescription.getProcessor()); - } - - processorTableModel = new ProcessorListTableModel(new ArrayList<>(processors)); - - table = new GTable(processorTableModel); - scrollPane = new JScrollPane(table); - table.getSelectionManager().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - } - - } - - public class ProcessorListTableModel extends AbstractSortedTableModel { - - private static final int PROCESSOR_COL = 0; - - private List processors; - - public ProcessorListTableModel(List processors) { - this.processors = processors; - } - - @Override - public Object getColumnValueForRow(Processor p, int columnIndex) { - switch (columnIndex) { - case PROCESSOR_COL: - return p.toString(); - } - return null; - } - - @Override - public String getName() { - return "Processors"; - } - - @Override - public List getModelData() { - return processors; - } - - @Override - public boolean isSortable(int columnIndex) { - return false; // maybe later when we add more columns - } - - @Override - public int getColumnCount() { - return 1; - } - - @Override - public int getRowCount() { - return processors.size(); - } - - @Override - public String getColumnName(int column) { - switch (column) { - case PROCESSOR_COL: - return "Processor"; - } - return null; - } - - @Override - public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case PROCESSOR_COL: - return String.class; - } - return Object.class; - } - - } - -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/InstalledProcessorsProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/InstalledProcessorsProvider.java new file mode 100644 index 0000000000..5ff316ca1f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/InstalledProcessorsProvider.java @@ -0,0 +1,85 @@ +/* ### + * 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 ghidra.app.plugin.runtimeinfo; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.*; + +import docking.ReusableDialogComponentProvider; +import ghidra.program.model.lang.LanguageDescription; +import ghidra.program.model.lang.Processor; +import ghidra.program.util.DefaultLanguageService; + +/** + * A dialog that shows the supported platforms (processors, loaders, file systems, etc) + */ +class InstalledProcessorsProvider extends ReusableDialogComponentProvider { + + private RuntimeInfoPlugin plugin; + private JTabbedPane tabbedPane; + + /** + * Creates a new {@link InstalledProcessorsProvider} + * + * @param plugin The associated {@link RuntimeInfoPlugin} + */ + InstalledProcessorsProvider(RuntimeInfoPlugin plugin) { + super("Installed Processors", false, false, true, false); + this.plugin = plugin; + + setHelpLocation(plugin.getInstalledProcessorsHelpLocation()); + addWorkPanel(createWorkPanel()); + } + + private JComponent createWorkPanel() { + tabbedPane = new JTabbedPane(); + + addProcessors(); + + JPanel mainPanel = new JPanel(new BorderLayout()) { + @Override + public Dimension getPreferredSize() { + return new Dimension(700, 400); + } + }; + mainPanel.add(tabbedPane, BorderLayout.CENTER); + return mainPanel; + } + + /** + * Adds a "processors" panel to the tabbed pane. + *

+ * The goal of this panel is to display every {@link Processor} that Ghidra discovered and + * loaded. + */ + private void addProcessors() { + Map map = new HashMap<>(); + for (LanguageDescription desc : DefaultLanguageService.getLanguageService() + .getLanguageDescriptions(true)) { + String processor = desc.getProcessor().toString(); + int count = map.getOrDefault(processor, 0); + map.put(processor, count + 1); + } + String name = "Processors"; + tabbedPane.add( + new MapTablePanel(name, map, "Name", "Variants", 300, false, plugin), + name); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/MapTablePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/MapTablePanel.java new file mode 100644 index 0000000000..2375c24eef --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/MapTablePanel.java @@ -0,0 +1,151 @@ +/* ### + * 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 ghidra.app.plugin.runtimeinfo; + +import java.awt.BorderLayout; +import java.util.*; + +import javax.swing.JPanel; + +import docking.widgets.table.*; +import ghidra.docking.settings.Settings; +import ghidra.framework.plugintool.Plugin; +import ghidra.framework.plugintool.ServiceProvider; +import ghidra.util.Disposable; + +/** + * A {@link JPanel} that displays a 2-column table created from a {@link Map} + * + * @param The {@link Map} key type + * @param The {@link Map} value type + */ +class MapTablePanel extends JPanel implements Disposable { + + private String name; + private Map map; + private String keyColumnName; + private String valueColumnName; + private int keyColumnWidth; + private boolean showValueColumn; + private Plugin plugin; + private GFilterTable> table; + + /** + * Creates a new {@link MapTablePanel} + * + * @param name The name of the panel + * @param map The {@link Map} + * @param keyColumnName The name of the key column + * @param valueName The name of the value column + * @param keyColumnWidth The width of the key column, in pixels + * @param showValueColumn True if the value column should be visible; false if it should be + * hidden + * @param plugin The {@link Plugin} associated with this {@link MapTablePanel} + */ + MapTablePanel(String name, Map map, String keyColumnName, String valueName, + int keyColumnWidth, boolean showValueColumn, Plugin plugin) { + this.name = name; + this.map = map; + this.keyColumnName = keyColumnName; + this.valueColumnName = valueName; + this.keyColumnWidth = keyColumnWidth; + this.showValueColumn = showValueColumn; + this.plugin = plugin; + this.table = new GFilterTable<>(new MapModel()); + + setLayout(new BorderLayout()); + add(table, BorderLayout.CENTER); + } + + @Override + public void dispose() { + table.dispose(); + } + + private class MapModel + extends GDynamicColumnTableModel, List>> { + + private List> entries; + + public MapModel() { + super(plugin.getTool()); + entries = new ArrayList<>(map.entrySet()); + } + + @Override + public String getName() { + return name; + } + + @Override + public List> getModelData() { + return entries; + } + + @Override + protected TableColumnDescriptor> createTableColumnDescriptor() { + TableColumnDescriptor> columnDescriptor = new TableColumnDescriptor<>(); + columnDescriptor.addVisibleColumn(new KeyColumn()); + if (showValueColumn) { + columnDescriptor.addVisibleColumn(new ValueColumn()); + } + else { + columnDescriptor.addHiddenColumn(new ValueColumn()); + } + return columnDescriptor; + } + + @Override + public List> getDataSource() { + return entries; + } + + private class KeyColumn + extends AbstractDynamicTableColumn, K, List>> { + + @Override + public String getColumnName() { + return keyColumnName; + } + + @Override + public K getValue(Map.Entry entry, Settings settings, List> data, + ServiceProvider services) throws IllegalArgumentException { + return entry.getKey(); + } + + @Override + public int getColumnPreferredWidth() { + return keyColumnWidth; + } + } + + private class ValueColumn + extends AbstractDynamicTableColumn, V, List>> { + + @Override + public String getColumnName() { + return valueColumnName; + } + + @Override + public V getValue(Map.Entry entry, Settings settings, List> data, + ServiceProvider services) throws IllegalArgumentException { + return entry.getValue(); + } + } + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/MemoryUsagePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/MemoryUsagePanel.java new file mode 100644 index 0000000000..b0d0800e32 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/MemoryUsagePanel.java @@ -0,0 +1,106 @@ +/* ### + * 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 ghidra.app.plugin.runtimeinfo; + +import java.awt.BorderLayout; +import java.text.DecimalFormat; + +import javax.swing.*; + +import docking.widgets.label.GDLabel; +import docking.widgets.label.GLabel; +import ghidra.util.Disposable; +import ghidra.util.layout.PairLayout; + +/** + * A {@link JPanel} that displays live memory usage and provides a button to initiate garbage + * collection on-demand + */ +class MemoryUsagePanel extends JPanel implements Disposable { + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat(); + + private Timer timer; + + /** + * Creates a new {@link MemoryUsagePanel} + */ + MemoryUsagePanel() { + setLayout(new BorderLayout()); + + // Center panel + JPanel centerPanel = new JPanel(new PairLayout()); + centerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + JLabel maxMem = new GDLabel("00000000000", SwingConstants.RIGHT); + JLabel totalMem = new GDLabel("00000000000", SwingConstants.RIGHT); + JLabel freeMem = new GDLabel("00000000000", SwingConstants.RIGHT); + JLabel usedMem = new GDLabel("00000000000", SwingConstants.RIGHT); + centerPanel.add(new GLabel("Max Memory:")); + centerPanel.add(maxMem); + centerPanel.add(new GLabel("Total Memory:")); + centerPanel.add(totalMem); + centerPanel.add(new GLabel("Free Memory:")); + centerPanel.add(freeMem); + centerPanel.add(new GLabel("Used Memory:")); + centerPanel.add(usedMem); + add(centerPanel, BorderLayout.CENTER); + + // Bottom panel + JPanel bottomPanel = new JPanel(); + JButton gcButton = new JButton("Collect Garbage"); + gcButton.addActionListener(e -> Runtime.getRuntime().gc()); + bottomPanel.add(gcButton); + add(bottomPanel, BorderLayout.SOUTH); + + // Garbage collection refresh timer + timer = new Timer(2000, e -> { + Runtime runtime = Runtime.getRuntime(); + maxMem.setText(formatMemoryValue(runtime.maxMemory())); + totalMem.setText(formatMemoryValue(runtime.totalMemory())); + freeMem.setText(formatMemoryValue(runtime.freeMemory())); + usedMem.setText(formatMemoryValue(runtime.totalMemory() - runtime.freeMemory())); + }); + } + + @Override + public void dispose() { + timer.stop(); + } + + /** + * Should be called when this {@link MemoryUsagePanel} is shown + */ + void shown() { + timer.start(); + } + + /** + * Should be called when this {@link MemoryUsagePanel} is hidden + */ + void hidden() { + timer.stop(); + } + + /** + * Formats the given raw memory value (in bytes) to a more human-readable string + * + * @param value A memory value in bytes + * @return A more human-readable memory value representation + */ + private String formatMemoryValue(long value) { + return DECIMAL_FORMAT.format(value >>> 20) + "MB"; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoPlugin.java new file mode 100644 index 0000000000..a4c8e1e558 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoPlugin.java @@ -0,0 +1,119 @@ +/* ### + * 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 ghidra.app.plugin.runtimeinfo; + +import docking.action.builder.ActionBuilder; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; +import ghidra.framework.main.UtilityPluginPackage; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.util.HelpLocation; + +//@formatter:off +@PluginInfo( + status = PluginStatus.RELEASED, + packageName = UtilityPluginPackage.NAME, + category = PluginCategoryNames.SUPPORT, + shortDescription = "Runtime Information", + description = "Plugin for displaying runtime information" +) +//@formatter:on +public class RuntimeInfoPlugin extends Plugin implements ApplicationLevelOnlyPlugin { + + private InstalledProcessorsProvider installedProcessorsProvider; + private RuntimeInfoProvider runtimeInfoProvider; + + /** + * Creates a new {@link RuntimeInfoPlugin} + * + * @param tool The tool + */ + public RuntimeInfoPlugin(PluginTool tool) { + super(tool); + + String supportedActionName = "Installed Processors"; + new ActionBuilder(supportedActionName, getName()) + .onAction(context -> showInstalledProcessors()) + .enabled(true) + .menuPath("Help", supportedActionName) + .menuGroup("YYY") // trying to put this just above the last menu entry + .helpLocation(getInstalledProcessorsHelpLocation()) + .buildAndInstall(tool); + + String runtimeInfoActionName = "Runtime Information"; + new ActionBuilder(runtimeInfoActionName, getName()) + .onAction(context -> showRuntimeInfo()) + .enabled(true) + .menuPath("Help", runtimeInfoActionName) + .menuGroup("YYY") + .helpLocation(getRuntimeInfoHelpLocation()) + .buildAndInstall(tool); + } + + @Override + protected void dispose() { + super.dispose(); + if (installedProcessorsProvider != null) { + installedProcessorsProvider.dispose(); + installedProcessorsProvider = null; + } + if (runtimeInfoProvider != null) { + runtimeInfoProvider.dispose(); + runtimeInfoProvider = null; + } + } + + /** + * Gets this plugin's installed processors {@link HelpLocation} + * + * @return This plugin's installed processors {@link HelpLocation} + */ + protected HelpLocation getInstalledProcessorsHelpLocation() { + return new HelpLocation("RuntimeInfoPlugin", "InstalledProcessors"); + } + + /** + * Gets this plugin's runtime info {@link HelpLocation} + * + * @return This plugin's runtime info {@link HelpLocation} + */ + protected HelpLocation getRuntimeInfoHelpLocation() { + return new HelpLocation("RuntimeInfoPlugin", "RuntimeInfo"); + } + + /** + * Displays the {@link InstalledProcessorsProvider} + */ + private void showInstalledProcessors() { + if (installedProcessorsProvider == null) { + installedProcessorsProvider = new InstalledProcessorsProvider(this); + } + + tool.showDialog(installedProcessorsProvider); + } + + /** + * Displays the {@link RuntimeInfoProvider} + */ + private void showRuntimeInfo() { + if (runtimeInfoProvider == null) { + runtimeInfoProvider = new RuntimeInfoProvider(this); + } + + tool.showDialog(runtimeInfoProvider); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoProvider.java new file mode 100644 index 0000000000..ac63281510 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/RuntimeInfoProvider.java @@ -0,0 +1,242 @@ +/* ### + * 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 ghidra.app.plugin.runtimeinfo; + +import java.awt.*; +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; + +import javax.swing.*; + +import docking.ReusableDialogComponentProvider; +import generic.jar.ResourceFile; +import ghidra.GhidraClassLoader; +import ghidra.framework.Application; +import ghidra.util.Disposable; +import ghidra.util.classfinder.ClassSearcher; +import ghidra.util.classfinder.ExtensionPoint; + +/** + * A dialog that shows useful runtime information + */ +class RuntimeInfoProvider extends ReusableDialogComponentProvider { + + private RuntimeInfoPlugin plugin; + private JTabbedPane tabbedPane; + private MemoryUsagePanel memoryUsagePanel; + + /** + * Creates a new {@link RuntimeInfoProvider} + * + * @param plugin The associated {@link RuntimeInfoPlugin} + */ + RuntimeInfoProvider(RuntimeInfoPlugin plugin) { + super("Runtime Information", false, false, true, false); + this.plugin = plugin; + + + setHelpLocation(plugin.getRuntimeInfoHelpLocation()); + addWorkPanel(createWorkPanel()); + } + + @Override + public void dispose() { + super.dispose(); + for (Component c : tabbedPane.getComponents()) { + if (c instanceof Disposable d) { + d.dispose(); + } + } + } + + @Override + protected void dialogShown() { + memoryUsagePanel.shown(); + } + + @Override + protected void dialogClosed() { + memoryUsagePanel.hidden(); + } + + + private JComponent createWorkPanel() { + tabbedPane = new JTabbedPane(); + + addVersionInfoPanel(); + addMemory(); + addApplicationLayout(); + addProperties(); + addEnvironment(); + addModules(); + addExtensionPoints(); + addClasspath(); + addExtensionsClasspath(); + + JPanel mainPanel = new JPanel(new BorderLayout()) { + @Override + public Dimension getPreferredSize() { + return new Dimension(700, 400); + } + }; + mainPanel.add(tabbedPane, BorderLayout.CENTER); + return mainPanel; + } + + /** + * Adds a "version" panel to the tabbed pane. + *

+ * The goal of this panel is to display version information that would be useful to include in + * a bug report, and provide a button that copies this information to the system clipboard. + */ + private void addVersionInfoPanel() { + tabbedPane.add(new VersionInfoPanel(), "Version"); + } + + /** + * Adds a "memory" panel to the tabbed pane. + *

+ * The goal of this panel is to display live memory usage, and provide a button to initiate + * garbage collection on-demand. + */ + private void addMemory() { + memoryUsagePanel = new MemoryUsagePanel(); + tabbedPane.add(memoryUsagePanel, "Memory"); + } + + /** + * Adds an "application layout" panel to the tabbed pane. + *

+ * The goal of this panel is to display information information about the application such as + * what directories it is using on disk, what its PID is, etc. + */ + private void addApplicationLayout() { + Map map = new HashMap<>(); + map.put("PID", ProcessHandle.current().pid() + ""); + map.put("Installation Directory", Application.getInstallationDirectory().getAbsolutePath()); + map.put("Settings Directory", Application.getUserSettingsDirectory().getPath()); + map.put("Cache Directory", Application.getUserCacheDirectory().getPath()); + map.put("Temp Directory", Application.getUserTempDirectory().getPath()); + String name = "Application Layout"; + tabbedPane.add( + new MapTablePanel(name, map, "Name", "Path", 200, true, plugin), name); + } + + /** + * Adds a "properties" panel to the tabbed pane. + *

+ * The goal of this panel is to display every defined system property in a table. + */ + private void addProperties() { + Properties properties = System.getProperties(); + Map map = new HashMap<>(); + for (Object key : properties.keySet()) { + map.put(key.toString(), properties.getOrDefault(key, "").toString()); + } + String name = "Properties"; + tabbedPane.add( + new MapTablePanel(name, map, "Name", "Value", 400, true, plugin), name); + } + + /** + * Adds an "environment" panel to the tabbed pane. + *

+ * The goal of this panel is to display every defined environment variable in a table. + */ + private void addEnvironment() { + Map map = System.getenv(); + String name = "Environment"; + tabbedPane.add( + new MapTablePanel(name, map, "Name", "Value", 400, true, plugin), name); + } + + /** + * Adds a "modules" panel to the tabbed pane. + *

+ * The goal of this panel is to display every module that Ghidra discovered and loaded. + */ + private void addModules() { + Map map = Application.getApplicationLayout() + .getModules() + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getModuleRoot())); + String name = "Modules"; + tabbedPane.add( + new MapTablePanel(name, map, "Name", "Path", 400, true, plugin), + name); + } + + /** + * Adds an "extension points" panel to the tabbed pane. + *

+ * The goal of this panel is to display every {@link ExtensionPoint} that Ghidra discovered and + * loaded. + */ + private void addExtensionPoints() { + Map map = ClassSearcher.getClasses(ExtensionPoint.class) + .stream() + .collect(Collectors.toMap(e -> e.getName(), + e -> ClassSearcher.getExtensionPointName(e.getName()))); + String name = "Extension Points"; + tabbedPane.add(new MapTablePanel(name, map, "Name", "Extension Point", 400, + true, plugin), name); + } + + /** + * Adds a "classpath" panel to the tabbed pane. + *

+ * The goal of this panel is to display Ghidra's current classpath. + */ + private void addClasspath() { + Map map = getClasspathMap(GhidraClassLoader.CP); + String name = "Classpath"; + tabbedPane.add( + new MapTablePanel(name, map, "Index", "Path", 40, true, plugin), name); + } + + /** + * Adds an "extensions classpath" panel to the tabbed pane. + *

+ * The goal of this panel is to display Ghidra's current extension classpath. + */ + private void addExtensionsClasspath() { + Map map = getClasspathMap(GhidraClassLoader.CP_EXT); + String name = "Extensions Classpath"; + tabbedPane.add( + new MapTablePanel(name, map, "Index", "Path", 40, true, plugin), name); + } + + /** + * Returns a {@link Map} of classpath entries, where the key is a 0-based integer index of each + * classpath entry + * + * @param propertyName The classpath system property name + * @return A {@link Map} of classpath entries, where the key is a 0-based integer index of each + * classpath entry + */ + private Map getClasspathMap(String propertyName) { + Map map = new HashMap<>(); + StringTokenizer st = + new StringTokenizer(System.getProperty(propertyName, ""), File.pathSeparator); + int i = 0; + while (st.hasMoreTokens()) { + map.put(i++, st.nextToken()); + } + return map; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/VersionInfoPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/VersionInfoPanel.java new file mode 100644 index 0000000000..252db04046 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/runtimeinfo/VersionInfoPanel.java @@ -0,0 +1,129 @@ +/* ### + * 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 ghidra.app.plugin.runtimeinfo; + +import java.awt.BorderLayout; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.io.*; +import java.util.*; + +import javax.swing.*; + +import docking.dnd.GClipboard; +import ghidra.framework.*; +import ghidra.util.SystemUtilities; + +/** + * A {@link JPanel} that displays version information that would be useful to include in a bug + * report, and provide a button that copies this information to the system clipboard + */ +class VersionInfoPanel extends JPanel { + + /** + * Creates a new {@link VersionInfoPanel} + */ + VersionInfoPanel() { + setLayout(new BorderLayout()); + + JTextArea textArea = new JTextArea(gatherVersionInfo()); + add(textArea, BorderLayout.CENTER); + + JPanel bottomPanel = new JPanel(); + JButton copyButton = new JButton("Copy"); + copyButton.addActionListener(e -> { + Clipboard clipboard = GClipboard.getSystemClipboard(); + clipboard.setContents(new StringSelection(textArea.getText()), null); + }); + bottomPanel.add(copyButton); + add(bottomPanel, BorderLayout.SOUTH); + + } + + /** + * Gathers version information + * + * @return The version information text + */ + private String gatherVersionInfo() { + final String def = "???"; + List lines = new ArrayList<>(); + + addApplicationInfo(lines, def); + addOperatingSystemInfo(lines, def); + addJavaInfo(lines, def); + + return String.join("\n", lines); + } + + /** + * Adds Ghidra application information to the version information + * + * @param lines A {@link List} of lines to add to + * @param def A default value to use if a piece of information cannot be found + */ + private void addApplicationInfo(List lines, String def) { + ApplicationProperties props = Application.getApplicationLayout().getApplicationProperties(); + lines.add("Ghidra Version: " + props.getApplicationVersion()); + lines.add("Ghidra Release: " + props.getApplicationReleaseName()); + lines.add("Ghidra Build Date: " + props.getApplicationBuildDate()); + lines.add("Ghidra Revision: " + + props.getProperty(ApplicationProperties.REVISION_PROPERTY_PREFIX + "ghidra", def)); + lines.add("Ghidra Development Mode: " + SystemUtilities.isInDevelopmentMode()); + } + + /** + * Adds operating system information to the version information + * + * @param lines A {@link List} of lines to add to + * @param def A default value to use if a piece of information cannot be found + */ + private void addOperatingSystemInfo(List lines, String def) { + lines.add("OS Name: " + System.getProperty("os.name", def)); + lines.add("OS Arch: " + System.getProperty("os.arch", def)); + lines.add("OS Version: " + System.getProperty("os.version", def)); + if (OperatingSystem.CURRENT_OPERATING_SYSTEM.equals(OperatingSystem.LINUX)) { + String prettyName = def; + File osReleaseFile = new File("/etc/os-release"); + if (!osReleaseFile.isFile()) { + osReleaseFile = new File("/usr/lib/os-release"); + } + try (BufferedReader reader = new BufferedReader(new FileReader(osReleaseFile))) { + Properties props = new Properties(); + props.load(reader); + prettyName = props.getProperty("PRETTY_NAME", def); + if (prettyName.startsWith("\"") && prettyName.endsWith("\"")) { + prettyName = prettyName.substring(1, prettyName.length() - 1); + } + } + catch (IOException e) { + // That's ok, pretty name is optional + } + lines.add("OS Pretty Name: " + prettyName); + } + } + + /** + * Adds Java/JVM information to the version information + * + * @param lines A {@link List} of lines to add to + * @param def A default value to use if a piece of information cannot be found + */ + private void addJavaInfo(List lines, String def) { + lines.add("Java Vendor: " + System.getProperty("java.vendor", def)); + lines.add("Java Version: " + System.getProperty("java.version", def)); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java index 777ace29cd..e927ae8df7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java @@ -27,14 +27,12 @@ import javax.swing.KeyStroke; import docking.action.DockingAction; import docking.action.builder.ActionBuilder; import docking.tool.ToolConstants; -import docking.widgets.dialogs.MultiLineMessageDialog; import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooserMode; import ghidra.app.CorePluginPackage; import ghidra.app.events.ProgramActivatedPluginEvent; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.services.*; -import ghidra.app.util.opinion.LoaderService; import ghidra.formats.gfilesystem.*; import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.main.FrontEndService; @@ -108,14 +106,6 @@ public class FileSystemBrowserPlugin extends Plugin .keyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.CTRL_DOWN_MASK)) .onAction(ac -> doOpenFileSystem()) .buildAndInstall(tool); - showFileSystemImplsAction = - new ActionBuilder("Display Supported File Systems and Loaders", this.getName()) - .description("Display Supported File Systems and Loaders") - .enabledWhen(ac -> true) - .menuPath(ToolConstants.MENU_HELP, "List File Systems") - .menuGroup("AAAZ") // this "AAAZ" is from ProcessorListPlugin - .onAction(ac -> showSupportedFileSystems()) - .buildAndInstall(tool); } @Override @@ -326,29 +316,4 @@ public class FileSystemBrowserPlugin extends Plugin } return provider; } - - /** - * Shows a list of supported file system types and loaders. - */ - private void showSupportedFileSystems() { - StringBuilder sb = new StringBuilder(); - - sb.append( - "\n"); - sb.append("
Supported File SystemsSupported Loaders
    "); - for (String fileSystemName : fsService().getAllFilesystemNames()) { - sb.append("
  • " + fileSystemName + "\n"); - } - - sb.append("
    "); - for (String loaderName : LoaderService.getAllLoaderNames()) { - sb.append("
  • " + loaderName + "\n"); - } - sb.append("
"); - - MultiLineMessageDialog.showModalMessageDialog(getTool().getActiveWindow(), - "Supported File Systems and Loaders", "", sb.toString(), - MultiLineMessageDialog.INFORMATION_MESSAGE); - } - } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java index 5f2c12a343..428b7fd272 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java @@ -21,6 +21,7 @@ import java.lang.reflect.Constructor; import java.nio.file.*; import java.util.*; import java.util.function.Predicate; +import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -278,6 +279,26 @@ public class ClassSearcher { log.info(finishedMessage); } + /** + * Gets the given class's extension point name + * + * @param className The name of the potential extension point class + * @return The given class's extension point name, or null if it is not an extension point + */ + public static String getExtensionPointName(String className) { + if (className.indexOf("Test$") > 0 || className.endsWith("Test")) { + return null; + } + int packageIndex = className.lastIndexOf('.'); + int innerClassIndex = className.lastIndexOf('$'); + int maximumIndex = StrictMath.max(packageIndex, innerClassIndex); + if (maximumIndex > 0) { + className = className.substring(maximumIndex + 1); + } + Matcher m = extensionPointSuffixPattern.matcher(className); + return m.find() && m.groupCount() == 1 ? m.group(1) : null; + } + private static List gatherSearchPaths() { // @@ -394,16 +415,7 @@ public class ClassSearcher { } static boolean isExtensionPointName(String name) { - if (name.indexOf("Test$") > 0 || name.endsWith("Test")) { - return false; - } - int packageIndex = name.lastIndexOf('.'); - int innerClassIndex = name.lastIndexOf('$'); - int maximumIndex = StrictMath.max(packageIndex, innerClassIndex); - if (maximumIndex > 0) { - name = name.substring(maximumIndex + 1); - } - return extensionPointSuffixPattern.matcher(name).matches(); + return getExtensionPointName(name) != null; } private static void fireClassListChanged() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java deleted file mode 100644 index b60b230965..0000000000 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java +++ /dev/null @@ -1,88 +0,0 @@ -/* ### - * 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 ghidra.app.plugin.debug; - -import docking.ActionContext; -import docking.DialogComponentProvider; -import docking.action.DockingAction; -import docking.action.MenuData; -import ghidra.app.plugin.PluginCategoryNames; -import ghidra.framework.main.ApplicationLevelOnlyPlugin; -import ghidra.framework.main.UtilityPluginPackage; -import ghidra.framework.plugintool.*; -import ghidra.framework.plugintool.util.PluginStatus; -import ghidra.util.HelpLocation; - -//@formatter:off -@PluginInfo( - status = PluginStatus.RELEASED, - packageName = UtilityPluginPackage.NAME, - category = PluginCategoryNames.SUPPORT, - shortDescription = "VM Memory Display", - description = "Plugin for displaying the VM memory information." -) -//@formatter:on -public class MemoryUsagePlugin extends Plugin implements ApplicationLevelOnlyPlugin { - private DialogComponentProvider dialog; - - public MemoryUsagePlugin(PluginTool tool) { - - super(tool); - - setupActions(); - } - - @Override - protected void dispose() { - super.dispose(); - - if (dialog != null) { - dialog.dispose(); - } - } - - private void setupActions() { - DockingAction action; - - // add menu action for Hello->Program - action = new DockingAction("Show VM memory", getName()) { - @Override - public void actionPerformed(ActionContext context) { - showMemory(); - } - }; - - action.setEnabled(true); - action.setHelpLocation(new HelpLocation("FrontEndPlugin", "ShowMemoryUsage")); - String group = "YYY"; // trying to put this just above the last menu entry - action.setMenuBarData(new MenuData(new String[] { "Help", "Show VM Memory" }, group)); - tool.addAction(action); - - } - - void clearDialog() { - dialog = null; - } - - public void showMemory() { - if (dialog == null) { - dialog = new ShowMemoryDialog(this); - } - else { - dialog.toFront(); - } - } -} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java deleted file mode 100644 index 8d48f7c2bd..0000000000 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java +++ /dev/null @@ -1,96 +0,0 @@ -/* ### - * 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 ghidra.app.plugin.debug; - -import java.text.DecimalFormat; - -import javax.swing.*; - -import docking.ReusableDialogComponentProvider; -import docking.widgets.label.GDLabel; -import docking.widgets.label.GLabel; -import ghidra.util.layout.PairLayout; - -class ShowMemoryDialog extends ReusableDialogComponentProvider { - private MemoryUsagePlugin plugin; - private JLabel maxMem; - private JLabel totalMem; - private JLabel freeMem; - private JLabel usedMem; - private Timer timer; - - ShowMemoryDialog(MemoryUsagePlugin plugin) { - super("VM Memory Usage", false, false, true, false); - this.plugin = plugin; - addOKButton(); - setOkButtonText("GC"); - addWorkPanel(createWorkPanel()); - plugin.getTool().showDialog(this); - final DecimalFormat df = new DecimalFormat(); - timer = new Timer(2000, e -> { - Runtime runtime = Runtime.getRuntime(); - maxMem.setText(df.format(runtime.maxMemory() / 1000) + "K"); - totalMem.setText(df.format(runtime.totalMemory() / 1000) + "K"); - freeMem.setText(df.format(runtime.freeMemory() / 1000) + "K"); - usedMem.setText( - df.format((runtime.totalMemory() - runtime.freeMemory()) / 1000) + "K"); - }); - timer.start(); - } - - boolean isInitialized() { - String text = maxMem.getText(); - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if ('0' != c) { - return true; - } - } - return false; - } - - @Override - protected void cancelCallback() { - timer.stop(); - plugin.clearDialog(); - super.cancelCallback(); - } - - @Override - protected void okCallback() { - Runtime.getRuntime().gc(); - } - - private JComponent createWorkPanel() { - JPanel panel = new JPanel(new PairLayout()); - panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - maxMem = new GDLabel("00000000000", SwingConstants.RIGHT); - totalMem = new GDLabel("00000000000", SwingConstants.RIGHT); - freeMem = new GDLabel("00000000000", SwingConstants.RIGHT); - usedMem = new GDLabel("00000000000", SwingConstants.RIGHT); - - panel.add(new GLabel("Max Memory:")); - panel.add(maxMem); - panel.add(new GLabel("Total Memory:")); - panel.add(totalMem); - panel.add(new GLabel("Free Memory:")); - panel.add(freeMem); - panel.add(new GLabel("Used Memory:")); - panel.add(usedMem); - - return panel; - } -}