Merge remote-tracking branch 'origin/patch'

This commit is contained in:
ghidra1
2021-12-15 18:31:24 -05:00
5 changed files with 174 additions and 80 deletions
@@ -41,12 +41,15 @@
dead or terminated. A "dead" trace can still be manipulated and marked up, but it will not
record any new target information.</P>
<H3><A name="close_trace"></A><A name="close_all_traces"></A><A name=
"close_other_traces"></A><A name="close_dead_traces"></A>Close Trace / All / Other / Dead
Traces</H3>
<P>In most cases, a trace is ephemeral, but occasionally, interesting behavior is observed that
is difficult to store as static mark-up. When a trace is no longer needed, it can be closed by
right-clicking the tab and selecting "Close Trace." <FONT color="red">Warning:</FONT> closing a
trace that has not been saved <EM>cannot</EM> be undone. If you accumulate many unwanted
traces, use one of the "Close Others," "Close Dead," or "Close All" actions from the pop-up
menu.</P>
is difficult to store as static mark-up. When traces are no longer needed, they can be closed
by right-clicking a tab and selecting one of the actions. See <A href=
"help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html#close_trace">Trace
Management</A> for details of each action.</P>
<H2>Navigating Threads</H2>
@@ -1748,26 +1748,36 @@ public interface DebuggerResources {
.menuIcon(ICON)
.menuPath(DebuggerPluginPackage.NAME, NAME)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
interface CloseTraceAction {
String NAME_PREFIX = "Close ";
String DESCRIPTION = "Close the current trace";
String DESCRIPTION = "Close the current or selected trace";
String GROUP = GROUP_TRACE_CLOSE;
String SUB_GROUP = "a";
Icon ICON = ICON_CLOSE;
String HELP_ANCHOR = "close_trace";
static ActionBuilder builder(Plugin owner) {
static ActionBuilder builderCommon(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME_PREFIX, ownerName)
.description(DESCRIPTION)
.menuGroup(GROUP)
.menuIcon(ICON)
.menuPath(DebuggerPluginPackage.NAME, NAME_PREFIX + "...")
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
static ActionBuilder builder(Plugin owner) {
return builderCommon(owner)
.menuGroup(GROUP, SUB_GROUP)
.menuIcon(ICON)
.menuPath(DebuggerPluginPackage.NAME, NAME_PREFIX + "...");
}
static ActionBuilder builderPopup(Plugin owner) {
return builderCommon(owner)
.popupMenuGroup(GROUP, SUB_GROUP)
.popupMenuIcon(ICON)
.popupMenuPath(NAME_PREFIX + "...");
}
}
@@ -1776,14 +1786,25 @@ public interface DebuggerResources {
String DESCRIPTION = "Close all traces";
String HELP_ANCHOR = "close_all_traces";
static ActionBuilder builder(Plugin owner) {
static ActionBuilder builderCommon(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
static ActionBuilder builder(Plugin owner) {
return builderCommon(owner)
.menuGroup(GROUP)
.menuIcon(ICON)
.menuPath(DebuggerPluginPackage.NAME, NAME)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
.menuPath(DebuggerPluginPackage.NAME, NAME);
}
static ActionBuilder builderPopup(Plugin owner) {
return builderCommon(owner)
.popupMenuGroup(GROUP)
.popupMenuIcon(ICON)
.popupMenuPath(NAME);
}
}
@@ -1792,14 +1813,25 @@ public interface DebuggerResources {
String DESCRIPTION = "Close all traces except the current one";
String HELP_ANCHOR = "close_other_traces";
static ActionBuilder builder(Plugin owner) {
static ActionBuilder builderCommon(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
static ActionBuilder builder(Plugin owner) {
return builderCommon(owner)
.menuGroup(GROUP)
.menuIcon(ICON)
.menuPath(DebuggerPluginPackage.NAME, NAME)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
.menuPath(DebuggerPluginPackage.NAME, NAME);
}
static ActionBuilder builderPopup(Plugin owner) {
return builderCommon(owner)
.popupMenuGroup(GROUP)
.popupMenuIcon(ICON)
.popupMenuPath(NAME);
}
}
@@ -1808,14 +1840,25 @@ public interface DebuggerResources {
String DESCRIPTION = "Close all traces not being recorded";
String HELP_ANCHOR = "close_dead_traces";
static ActionBuilder builder(Plugin owner) {
static ActionBuilder builderCommon(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
static ActionBuilder builder(Plugin owner) {
return builderCommon(owner)
.menuGroup(GROUP)
.menuIcon(ICON)
.menuPath(DebuggerPluginPackage.NAME, NAME)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
.menuPath(DebuggerPluginPackage.NAME, NAME);
}
static ActionBuilder builderPopup(Plugin owner) {
return builderCommon(owner)
.popupMenuGroup(GROUP)
.popupMenuIcon(ICON)
.popupMenuPath(NAME);
}
}
@@ -15,11 +15,11 @@
*/
package ghidra.app.plugin.core.debug.gui.thread;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
@@ -361,6 +361,12 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
SeekTracePresentAction actionSeekTracePresent;
ToggleDockingAction actionSyncFocus;
DockingAction actionGoToTime;
DockingAction actionCloseTrace;
DockingAction actionCloseOtherTraces;
DockingAction actionCloseDeadTraces;
DockingAction actionCloseAllTraces;
Set<Object> strongRefs = new HashSet<>(); // Eww
public DebuggerThreadsProvider(final DebuggerThreadsPlugin plugin) {
@@ -554,6 +560,11 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
threadTable.getSelectionModel().addListSelectionListener(this::threadRowSelected);
threadTable.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
setThreadRowActionContext();
}
@Override
public void mouseReleased(MouseEvent e) {
int selectedRow = threadTable.getSelectedRow();
@@ -584,15 +595,13 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
list.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
checkTraceTabPopupViaMouse(e);
setTraceTabActionContext(e);
}
@Override
public void mouseReleased(MouseEvent e) {
checkTraceTabPopupViaMouse(e);
}
});
// TODO: The popup key? Only seems to have rawCode=0x93 (147) in Swing
mainPanel.add(traceTabs, BorderLayout.NORTH);
TableColumnModel columnModel = threadTable.getColumnModel();
@@ -622,53 +631,6 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
});
}
private void checkTraceTabPopupViaMouse(MouseEvent e) {
if (!e.isPopupTrigger()) {
return;
}
JList<Trace> list = traceTabs.getList();
int i = list.locationToIndex(e.getPoint());
if (i < 0) {
return;
}
Rectangle cell = list.getCellBounds(i, i);
if (!cell.contains(e.getPoint())) {
return;
}
showTraceTabPopup(e.getComponent(), e.getPoint(), i);
}
private void showTraceTabPopup(Component comp, Point p, int i) {
// TODO: Make this use action contexts and docking actions instead
traceTabPopupMenu.removeAll();
final Trace trace = traceTabs.getItem(i);
JMenuItem closeItem =
new JMenuItem("Close " + trace.getName(), DebuggerResources.ICON_CLOSE);
closeItem.addActionListener(evt -> {
traceManager.closeTrace(trace);
});
JMenuItem closeOthers = new JMenuItem("Close Others", DebuggerResources.ICON_CLOSE);
closeOthers.addActionListener(evt -> {
traceManager.closeOtherTraces(trace);
});
JMenuItem closeDead = new JMenuItem("Close Dead", DebuggerResources.ICON_CLOSE);
closeDead.addActionListener(evt -> {
traceManager.closeDeadTraces();
});
JMenuItem closeAll = new JMenuItem("Close All", DebuggerResources.ICON_CLOSE);
closeAll.addActionListener(evt -> {
for (Trace t : List.copyOf(traceManager.getOpenTraces())) {
traceManager.closeTrace(t);
}
});
traceTabPopupMenu.add(closeItem);
traceTabPopupMenu.addSeparator();
traceTabPopupMenu.add(closeOthers);
traceTabPopupMenu.add(closeDead);
traceTabPopupMenu.add(closeAll);
traceTabPopupMenu.show(comp, p.x, p.y);
}
protected void createActions() {
// TODO: Make other actions use builder?
actionStepSnapBackward = new StepSnapBackwardAction();
@@ -687,6 +649,27 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
.buildAndInstallLocal(this);
traceManager.addSynchronizeFocusChangeListener(
strongRef(new ToToggleSelectionListener(actionSyncFocus)));
actionCloseTrace = CloseTraceAction.builderPopup(plugin)
.withContext(DebuggerTraceFileActionContext.class)
.popupWhen(c -> c.getTrace() != null)
.onAction(c -> traceManager.closeTrace(c.getTrace()))
.buildAndInstallLocal(this);
actionCloseAllTraces = CloseAllTracesAction.builderPopup(plugin)
.withContext(DebuggerTraceFileActionContext.class)
.popupWhen(c -> !traceManager.getOpenTraces().isEmpty())
.onAction(c -> traceManager.closeAllTraces())
.buildAndInstallLocal(this);
actionCloseOtherTraces = CloseOtherTracesAction.builderPopup(plugin)
.withContext(DebuggerTraceFileActionContext.class)
.popupWhen(c -> traceManager.getOpenTraces().size() > 1 && c.getTrace() != null)
.onAction(c -> traceManager.closeOtherTraces(c.getTrace()))
.buildAndInstallLocal(this);
actionCloseDeadTraces = CloseDeadTracesAction.builderPopup(plugin)
.withContext(DebuggerTraceFileActionContext.class)
.popupWhen(c -> !traceManager.getOpenTraces().isEmpty() && modelService != null)
.onAction(c -> traceManager.closeDeadTraces())
.buildAndInstallLocal(this);
}
private void toggleSyncFocus(boolean enabled) {
@@ -712,24 +695,50 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
}
}
private Trace computeClickedTraceTab(MouseEvent e) {
JList<Trace> list = traceTabs.getList();
int i = list.locationToIndex(e.getPoint());
if (i < 0) {
return null;
}
Rectangle cell = list.getCellBounds(i, i);
if (!cell.contains(e.getPoint())) {
return null;
}
return traceTabs.getItem(i);
}
private Trace setTraceTabActionContext(MouseEvent e) {
Trace newTrace = e == null ? traceTabs.getSelectedItem() : computeClickedTraceTab(e);
actionCloseTrace.getPopupMenuData()
.setMenuItemName(
CloseTraceAction.NAME_PREFIX + (newTrace == null ? "..." : newTrace.getName()));
myActionContext = new DebuggerTraceFileActionContext(newTrace);
contextChanged();
return newTrace;
}
private void traceTabSelected(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
Trace newTrace = traceTabs.getSelectedItem();
myActionContext = new DebuggerThreadActionContext(newTrace, null);
contextChanged();
Trace newTrace = setTraceTabActionContext(null);
cbCoordinateActivation.invoke(() -> traceManager.activateTrace(newTrace));
}
private ThreadRow setThreadRowActionContext() {
ThreadRow row = threadFilterPanel.getSelectedItem();
myActionContext = new DebuggerThreadActionContext(current.getTrace(),
row == null ? null : row.getThread());
contextChanged();
return row;
}
private void threadRowSelected(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
ThreadRow row = threadFilterPanel.getSelectedItem();
myActionContext = new DebuggerThreadActionContext(current.getTrace(),
row == null ? null : row.getThread());
contextChanged();
ThreadRow row = setThreadRowActionContext();
if (row != null && traceManager != null) {
cbCoordinateActivation.invoke(() -> traceManager.activateThread(row.getThread()));
}
@@ -0,0 +1,31 @@
/* ###
* 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.debug.gui.thread;
import docking.ActionContext;
import ghidra.trace.model.Trace;
public class DebuggerTraceFileActionContext extends ActionContext {
private final Trace trace;
public DebuggerTraceFileActionContext(Trace trace) {
this.trace = trace;
}
public Trace getTrace() {
return trace;
}
}
@@ -23,6 +23,7 @@ import ghidra.framework.client.RepositoryAdapter;
import ghidra.framework.model.*;
import ghidra.framework.protocol.ghidra.GhidraURL;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
public enum ProgramURLUtils {
;
@@ -33,7 +34,9 @@ public enum ProgramURLUtils {
if (projectLocator == null) {
return null;
}
RepositoryAdapter repository = file.getParent().getProjectData().getRepository();
DomainFolder parent = file.getParent();
ProjectData projectData = parent == null ? null : parent.getProjectData();
RepositoryAdapter repository = projectData == null ? null : projectData.getRepository();
if (repository != null) { // There is an associated remote repo
if (file.isVersioned()) { // The domain file exists there
ServerInfo server = repository.getServerInfo();
@@ -66,6 +69,11 @@ public enum ProgramURLUtils {
}
URL localProjURL = new URL(asString.substring(0, bangLoc));
ProjectData projectData = project.getProjectData(localProjURL);
if (projectData == null) {
Msg.error(ProgramURLUtils.class, "The repository containing " + ghidraURL +
" is not open in the Project manager.");
return null;
}
return projectData.getFile(asString.substring(bangLoc + 1));
}
catch (MalformedURLException e) {