Merge remote-tracking branch

'origin/GP-5164_Dan_addRegionManually--SQUASHED' (#7176)
This commit is contained in:
Ryan Kurtz 2024-12-04 11:03:21 -05:00
commit ce1e6bccdc
8 changed files with 84 additions and 34 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

View file

@ -16,6 +16,8 @@
package ghidra.app.plugin.core.debug.gui.memory; package ghidra.app.plugin.core.debug.gui.memory;
import java.awt.Font; import java.awt.Font;
import java.util.List;
import java.util.Set;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
@ -25,18 +27,21 @@ import docking.ReusableDialogComponentProvider;
import docking.widgets.model.GAddressRangeField; import docking.widgets.model.GAddressRangeField;
import docking.widgets.model.GSpanField; import docking.widgets.model.GSpanField;
import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils; import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
import ghidra.dbg.target.TargetMemoryRegion;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.trace.model.Lifespan; import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceOverlappedRegionException; import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.util.exception.DuplicateNameException; import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.util.layout.PairLayout; import ghidra.util.layout.PairLayout;
public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider { public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider {
private Trace trace; private Trace trace;
private final JTextField fieldName = new JTextField(); private final JTextField fieldPath = new JTextField();
private final GAddressRangeField fieldRange = new GAddressRangeField(); private final GAddressRangeField fieldRange = new GAddressRangeField();
private final JTextField fieldLength = new JTextField(); private final JTextField fieldLength = new JTextField();
private final GSpanField fieldLifespan = new GSpanField(); private final GSpanField fieldLifespan = new GSpanField();
@ -53,8 +58,8 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider {
panel.setBorder(new EmptyBorder(10, 10, 10, 10)); panel.setBorder(new EmptyBorder(10, 10, 10, 10));
panel.add(new JLabel("Name: ")); panel.add(new JLabel("Path: "));
panel.add(fieldName); panel.add(fieldPath);
panel.add(new JLabel("Range: ")); panel.add(new JLabel("Range: "));
panel.add(fieldRange); panel.add(fieldRange);
@ -81,8 +86,8 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider {
return new AddressRangeImpl(min, min.addWrap(lengthMinus1)); return new AddressRangeImpl(min, min.addWrap(lengthMinus1));
} }
public void setName(String name) { public void setPath(String path) {
fieldName.setText(name); fieldPath.setText(path);
} }
protected void setFieldLength(long length) { protected void setFieldLength(long length) {
@ -149,17 +154,33 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider {
addRegionAndClose(); addRegionAndClose();
} }
protected void setValues(Trace trace, Lifespan lifespan) { protected String computeDefaultPath(DebuggerCoordinates current) {
this.trace = trace; TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
if (rootSchema == null) {
return "";
}
List<String> suitable = rootSchema.searchForSuitableContainer(TargetMemoryRegion.class,
current.getPath().getKeyList());
if (suitable == null) {
return "";
}
return TraceObjectKeyPath.of(suitable).index("New").toString();
}
protected void setValues(DebuggerCoordinates current) {
this.trace = current.getTrace();
AddressFactory af = trace.getBaseAddressFactory(); AddressFactory af = trace.getBaseAddressFactory();
this.fieldRange.setAddressFactory(af); this.fieldRange.setAddressFactory(af);
this.fieldRange.setRange(range(af.getDefaultAddressSpace().getAddress(0), 0)); this.fieldRange.setRange(range(af.getDefaultAddressSpace().getAddress(0), 0));
this.fieldLength.setText("0x1"); this.fieldLength.setText("0x1");
Lifespan lifespan = Lifespan.nowOn(current.getSnap());
this.fieldLifespan.setLifespan(lifespan); this.fieldLifespan.setLifespan(lifespan);
this.fieldPath.setText(computeDefaultPath(current));
} }
public void show(PluginTool tool, Trace trace, long snap) { public void show(PluginTool tool, DebuggerCoordinates current) {
setValues(trace, Lifespan.nowOn(snap)); setValues(current);
tool.showDialog(this); tool.showDialog(this);
} }
@ -171,13 +192,16 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider {
} }
protected void addRegionAndClose() { protected void addRegionAndClose() {
try (Transaction tx = trace.openTransaction("Add region: " + fieldName)) { try (Transaction tx = trace.openTransaction("Add region: " + fieldPath)) {
trace.getMemoryManager() trace.getMemoryManager()
.addRegion(fieldName.getText(), fieldLifespan.getLifespan(), .addRegion(
fieldRange.getRange()); fieldPath.getText(),
fieldLifespan.getLifespan(), fieldRange.getRange(),
Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE,
TraceMemoryFlag.EXECUTE));
close(); close();
} }
catch (TraceOverlappedRegionException | DuplicateNameException e) { catch (Exception e) {
setStatusText(e.getMessage()); setStatusText(e.getMessage());
} }
} }

View file

@ -467,7 +467,7 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
if (current.getTrace() == null) { if (current.getTrace() == null) {
return; return;
} }
addRegionDialog.show(tool, current.getTrace(), current.getSnap()); addRegionDialog.show(tool, current);
} }
private void activatedDeleteRegions(ActionContext ctx) { private void activatedDeleteRegions(ActionContext ctx) {

View file

@ -495,7 +495,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerTes
performEnabledAction(provider, provider.actionAddRegion, false); performEnabledAction(provider, provider.actionAddRegion, false);
DebuggerAddRegionDialog dialog = waitForDialogComponent(DebuggerAddRegionDialog.class); DebuggerAddRegionDialog dialog = waitForDialogComponent(DebuggerAddRegionDialog.class);
runSwing(() -> { runSwing(() -> {
dialog.setName("Memory[heap]"); dialog.setPath("Memory[heap]");
dialog.setFieldLength(0x1000); dialog.setFieldLength(0x1000);
dialog.lengthChanged(); // simulate ENTER/focus-exited dialog.lengthChanged(); // simulate ENTER/focus-exited
dialog.okCallback(); dialog.okCallback();

View file

@ -0,0 +1,30 @@
/* ###
* 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.dbg.target.schema;
/**
* An exception that indicates a path or object does not provide a required interface.
*/
public class BadSchemaException extends IllegalStateException {
/**
* Construct an exception with a human-readable message.
*
* @param message the message
*/
public BadSchemaException(String message) {
super(message);
}
}

View file

@ -893,12 +893,9 @@ public interface TargetObjectSchema {
List<TargetObjectSchema> schemas = getSuccessorSchemas(path); List<TargetObjectSchema> schemas = getSuccessorSchemas(path);
for (; path != null; path = PathUtils.parent(path)) { for (; path != null; path = PathUtils.parent(path)) {
TargetObjectSchema schema = schemas.get(path.size()); TargetObjectSchema schema = schemas.get(path.size());
if (!schema.isCanonicalContainer()) {
continue;
}
TargetObjectSchema deSchema = TargetObjectSchema deSchema =
schema.getContext().getSchema(schema.getDefaultElementSchema()); schema.getContext().getSchema(schema.getDefaultElementSchema());
if (deSchema.getInterfaces().contains(type)) { if (deSchema.getInterfaces().contains(type) && schema.isCanonicalContainer()) {
return path; return path;
} }
List<String> inAgg = Private.searchForSuitableContainerInAggregate(schema, type); List<String> inAgg = Private.searchForSuitableContainerInAggregate(schema, type);

View file

@ -310,8 +310,7 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra
public void setFlags(Lifespan lifespan, Collection<TraceMemoryFlag> flags) { public void setFlags(Lifespan lifespan, Collection<TraceMemoryFlag> flags) {
try (LockHold hold = object.getTrace().lockWrite()) { try (LockHold hold = object.getTrace().lockWrite()) {
for (TraceMemoryFlag flag : TraceMemoryFlag.values()) { for (TraceMemoryFlag flag : TraceMemoryFlag.values()) {
Boolean val = flags.contains(flag) ? true : null; object.setValue(lifespan, keyForFlag(flag), flags.contains(flag));
object.setValue(lifespan, keyForFlag(flag), val);
} }
} }
} }
@ -329,7 +328,7 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra
public void clearFlags(Lifespan lifespan, Collection<TraceMemoryFlag> flags) { public void clearFlags(Lifespan lifespan, Collection<TraceMemoryFlag> flags) {
try (LockHold hold = object.getTrace().lockWrite()) { try (LockHold hold = object.getTrace().lockWrite()) {
for (TraceMemoryFlag flag : flags) { for (TraceMemoryFlag flag : flags) {
object.setValue(lifespan, keyForFlag(flag), null); object.setValue(lifespan, keyForFlag(flag), false);
} }
} }
} }

View file

@ -539,9 +539,9 @@ public class DBTraceObjectManager implements TraceObjectManager, DBTraceManager
Class<? extends TargetObject> targetIf = TraceObjectInterfaceUtils.toTargetIf(iface); Class<? extends TargetObject> targetIf = TraceObjectInterfaceUtils.toTargetIf(iface);
TargetObjectSchema schema = rootSchema.getSuccessorSchema(keyList); TargetObjectSchema schema = rootSchema.getSuccessorSchema(keyList);
if (!schema.getInterfaces().contains(targetIf)) { if (!schema.getInterfaces().contains(targetIf)) {
throw new IllegalStateException( throw new BadSchemaException(
"Schema " + schema + " at " + PathUtils.toString(keyList) + "Schema " + schema + " at '" + PathUtils.toString(keyList) +
" does not provide interface " + iface.getSimpleName()); "' does not provide interface " + iface.getSimpleName());
} }
DBTraceObject obj = createObject(TraceObjectKeyPath.of(keyList)); DBTraceObject obj = createObject(TraceObjectKeyPath.of(keyList));
return obj.queryInterface(iface); return obj.queryInterface(iface);