GP-3844: Replacing the 'Show VM Memory' dialog with an upgraded 'Runtime Information' dialog

This commit is contained in:
Ryan Kurtz 2024-01-08 08:16:11 -05:00
parent f739df7c21
commit 8c89a8bb3c
19 changed files with 949 additions and 594 deletions

View file

@ -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);

View file

@ -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|

View file

@ -61,25 +61,6 @@
</UL>
</LI>
</UL>
<H2 align="center"><A name="ProcessorList"/>Installed Processors</H2>
<P>The <I>Installed Processors</I> 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.</P>
<BLOCKQUOTE>
<P><IMG border="0" src="help/shared/tip.png">&nbsp; This option is also available from the
<I><A href="help/topics/FrontEndPlugin/Ghidra_Front_end.htm">Ghidra Project
Window</A>&nbsp;</I></P>
</BLOCKQUOTE>
<H3><B>To view the Installed Processors list</B></H3>
<UL type="disc">
<LI>From the menu-bar in tool, click <B>Help <IMG src="help/shared/arrow.gif" border="0"
alt="">Installed Processors</B></LI>
</UL>
<H2 align="center"><A name="User_Agreement"/>User Agreement</H2>

View file

@ -29,16 +29,6 @@
Subdirectories of your local computer's file system can also be opened in this manner.</P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2>Help Menu Actions</H2>
<BLOCKQUOTE>
<H3><A name="Display_Supported_File_Systems_and_Loaders"></A>Display Supported File Systems
and Loaders</H3>
<BLOCKQUOTE>
<P>Lists the currently supported file systems and loaders.</P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2>Right-click Context Menu Actions</H2>

View file

@ -1,40 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Memory Usage</TITLE>
<META http-equiv="content-type" content="text/html; charset=windows-1252">
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY>
<H1 align="center"><A name="ShowMemoryUsage"></A>Memory Usage</H1>
<P>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;</P>
<P>To display the memory usage dialog:</P>
<OL>
<LI>From the Project Window, Select <B>Help<IMG border="0" src="help/shared/arrow.gif">Show VM Memory</B> from the
menu.</LI>
</OL>
<TABLE border="0" width="100%">
<TR>
<TD width="100%" align="center"><IMG border="0" src="images/MemoryUsage.png"></TD>
</TR>
</TABLE>
<P>The four values displayed are as follows:</P>
<OL>
<LI> Max Memory - the maximum memory that the Java VM is allowed to use.</LI>
<LI> Total Memory - the amount of memory that the Java VM is currently using.</LI>
<LI> Free Memory - the amount of the "Total Memory" that is currently unused by the Ghidra application.</LI>
<LI> Used Memory - the amount of the "Total Memory" that is currently used by the Ghidra application.</LI>
</OL>
<P>&nbsp;</P>
</BODY>
</HTML>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

View file

@ -0,0 +1,27 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Runtime Information</TITLE>
<META http-equiv="content-type" content="text/html; charset=windows-1252">
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY>
<A name="InstalledProcessors"></A>
<H1 align="center">Installed Processors</H1>
<P>The Installed Processors feature pops up a dialog showing a list of processors that the
active Ghidra application supports.</P>
<P>To display the Installed Processors dialog:</P>
<UL>
<LI>From the Project Window, Select <B>Help<IMG border="0" src="help/shared/arrow.gif">
Installed Processors</B> from the menu.</LI>
</UL>
<P>&nbsp;</P>
</BODY>
</HTML>

View file

@ -0,0 +1,64 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Runtime Information</TITLE>
<META http-equiv="content-type" content="text/html; charset=windows-1252">
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY>
<A name="RuntimeInfo"></A>
<H1 align="center">Runtime Information</H1>
<P>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.</P>
<P>To display the Runtime Information dialog:</P>
<UL>
<LI>From the Project Window, Select <B>Help<IMG border="0" src="help/shared/arrow.gif">
Runtime Information</B> from the menu.</LI>
</UL>
<P>Runtime Information categories are organized in tabs. The following categories are provided:
<UL>
<LI>
<B>Version</B> - Ghidra, Operating System, and Java version information. Clicking the
<B><I>Copy</I></B> button will copy this information to the clipboard for easy transfer into a bug report.
</LI>
<LI>
<B>Memory</B> - JVM memory usage. Clicking the <B><I>Collect Garbage</I></B> button will
suggest to the JVM that garbage collection should run.
</LI>
<LI>
<B>Application Layout</B> - Ghidra application layout information, including directory
locations.
</LI>
<LI>
<B>Properties</B> - Defined JVM system properties for the active Ghidra application.
</LI>
<LI>
<B>Environment</B> - Defined environment variables for the active Ghidra application.
</LI>
<LI>
<B>Modules</B> - A list of discovered Ghidra Modules.
</LI>
<LI>
<B>Extension Points</B> - A list of discovered Ghidra Extension Points.
</LI>
<LI>
<B>Classpath</B> - The ordered classpath for the active Ghidra application.
</LI>
<LI>
<B>Extensions Classpath</B> - The ordered extensions classpath, if the
<B><I>ghidra.extensions.classpath.restricted</I></B> property is set (see
<I>support/launch.properties</I>).
</LI>
</UL>
<P>&nbsp;</P>
</BODY>
</HTML>

View file

@ -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<Processor> getProcessors() {
TreeSet<Processor> 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("<HTML><BODY>\n");
strBuilder.append("<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n<tr>");
}
Set<Processor> 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("</ul>\n</td>");
}
strBuilder.append("<td width=\"33%\">\n<ul>");
}
strBuilder.append("<li>");
}
++colCnt;
strBuilder.append(processor.toString());
if (asHtml) {
strBuilder.append("</li>");
}
strBuilder.append("\n");
}
if (asHtml) {
strBuilder.append("</ul>\n</td></tr>\n</table>");
strBuilder.append("</BODY></HTML>");
}
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<Processor> 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<Processor> {
private static final int PROCESSOR_COL = 0;
private List<Processor> processors;
public ProcessorListTableModel(List<Processor> 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<Processor> 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;
}
}
}

View file

@ -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.
* <p>
* The goal of this panel is to display every {@link Processor} that Ghidra discovered and
* loaded.
*/
private void addProcessors() {
Map<String, Integer> 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<String, Integer>(name, map, "Name", "Variants", 300, false, plugin),
name);
}
}

View file

@ -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 <K> The {@link Map} key type
* @param <V> The {@link Map} value type
*/
class MapTablePanel<K, V> extends JPanel implements Disposable {
private String name;
private Map<K, V> map;
private String keyColumnName;
private String valueColumnName;
private int keyColumnWidth;
private boolean showValueColumn;
private Plugin plugin;
private GFilterTable<Map.Entry<K, V>> 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<K, V> 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<Map.Entry<K, V>, List<Map.Entry<K, V>>> {
private List<Map.Entry<K, V>> entries;
public MapModel() {
super(plugin.getTool());
entries = new ArrayList<>(map.entrySet());
}
@Override
public String getName() {
return name;
}
@Override
public List<Map.Entry<K, V>> getModelData() {
return entries;
}
@Override
protected TableColumnDescriptor<Map.Entry<K, V>> createTableColumnDescriptor() {
TableColumnDescriptor<Map.Entry<K, V>> columnDescriptor = new TableColumnDescriptor<>();
columnDescriptor.addVisibleColumn(new KeyColumn());
if (showValueColumn) {
columnDescriptor.addVisibleColumn(new ValueColumn());
}
else {
columnDescriptor.addHiddenColumn(new ValueColumn());
}
return columnDescriptor;
}
@Override
public List<Map.Entry<K, V>> getDataSource() {
return entries;
}
private class KeyColumn
extends AbstractDynamicTableColumn<Map.Entry<K, V>, K, List<Map.Entry<K, V>>> {
@Override
public String getColumnName() {
return keyColumnName;
}
@Override
public K getValue(Map.Entry<K, V> entry, Settings settings, List<Map.Entry<K, V>> data,
ServiceProvider services) throws IllegalArgumentException {
return entry.getKey();
}
@Override
public int getColumnPreferredWidth() {
return keyColumnWidth;
}
}
private class ValueColumn
extends AbstractDynamicTableColumn<Map.Entry<K, V>, V, List<Map.Entry<K, V>>> {
@Override
public String getColumnName() {
return valueColumnName;
}
@Override
public V getValue(Map.Entry<K, V> entry, Settings settings, List<Map.Entry<K, V>> data,
ServiceProvider services) throws IllegalArgumentException {
return entry.getValue();
}
}
}
}

View file

@ -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";
}
}

View file

@ -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);
}
}

View file

@ -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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<String, String> 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<String, String>(name, map, "Name", "Path", 200, true, plugin), name);
}
/**
* Adds a "properties" panel to the tabbed pane.
* <p>
* The goal of this panel is to display every defined system property in a table.
*/
private void addProperties() {
Properties properties = System.getProperties();
Map<String, String> map = new HashMap<>();
for (Object key : properties.keySet()) {
map.put(key.toString(), properties.getOrDefault(key, "").toString());
}
String name = "Properties";
tabbedPane.add(
new MapTablePanel<String, String>(name, map, "Name", "Value", 400, true, plugin), name);
}
/**
* Adds an "environment" panel to the tabbed pane.
* <p>
* The goal of this panel is to display every defined environment variable in a table.
*/
private void addEnvironment() {
Map<String, String> map = System.getenv();
String name = "Environment";
tabbedPane.add(
new MapTablePanel<String, String>(name, map, "Name", "Value", 400, true, plugin), name);
}
/**
* Adds a "modules" panel to the tabbed pane.
* <p>
* The goal of this panel is to display every module that Ghidra discovered and loaded.
*/
private void addModules() {
Map<String, ResourceFile> map = Application.getApplicationLayout()
.getModules()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getModuleRoot()));
String name = "Modules";
tabbedPane.add(
new MapTablePanel<String, ResourceFile>(name, map, "Name", "Path", 400, true, plugin),
name);
}
/**
* Adds an "extension points" panel to the tabbed pane.
* <p>
* The goal of this panel is to display every {@link ExtensionPoint} that Ghidra discovered and
* loaded.
*/
private void addExtensionPoints() {
Map<String, String> 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<String, String>(name, map, "Name", "Extension Point", 400,
true, plugin), name);
}
/**
* Adds a "classpath" panel to the tabbed pane.
* <p>
* The goal of this panel is to display Ghidra's current classpath.
*/
private void addClasspath() {
Map<Integer, String> map = getClasspathMap(GhidraClassLoader.CP);
String name = "Classpath";
tabbedPane.add(
new MapTablePanel<Integer, String>(name, map, "Index", "Path", 40, true, plugin), name);
}
/**
* Adds an "extensions classpath" panel to the tabbed pane.
* <p>
* The goal of this panel is to display Ghidra's current extension classpath.
*/
private void addExtensionsClasspath() {
Map<Integer, String> map = getClasspathMap(GhidraClassLoader.CP_EXT);
String name = "Extensions Classpath";
tabbedPane.add(
new MapTablePanel<Integer, String>(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<Integer, String> getClasspathMap(String propertyName) {
Map<Integer, String> 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;
}
}

View file

@ -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<String> 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<String> 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<String> 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<String> lines, String def) {
lines.add("Java Vendor: " + System.getProperty("java.vendor", def));
lines.add("Java Version: " + System.getProperty("java.version", def));
}
}

View file

@ -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(
"<html><table><tr><td>Supported File Systems</td><td>Supported Loaders</td></tr>\n");
sb.append("<tr valign='top'><td><ul>");
for (String fileSystemName : fsService().getAllFilesystemNames()) {
sb.append("<li>" + fileSystemName + "\n");
}
sb.append("</ul></td><td><ul>");
for (String loaderName : LoaderService.getAllLoaderNames()) {
sb.append("<li>" + loaderName + "\n");
}
sb.append("</ul></td></tr></table>");
MultiLineMessageDialog.showModalMessageDialog(getTool().getActiveWindow(),
"Supported File Systems and Loaders", "", sb.toString(),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
}

View file

@ -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<String> 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() {

View file

@ -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();
}
}
}

View file

@ -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;
}
}