diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png index d9261e7e80..95520abc1e 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerAddRegionDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerAddRegionDialog.java index 37fd5b948d..2b8eae7b3d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerAddRegionDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerAddRegionDialog.java @@ -4,9 +4,9 @@ * 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. @@ -16,6 +16,8 @@ package ghidra.app.plugin.core.debug.gui.memory; import java.awt.Font; +import java.util.List; +import java.util.Set; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -25,18 +27,21 @@ import docking.ReusableDialogComponentProvider; import docking.widgets.model.GAddressRangeField; import docking.widgets.model.GSpanField; 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.program.model.address.*; import ghidra.trace.model.Lifespan; import ghidra.trace.model.Trace; -import ghidra.trace.model.memory.TraceOverlappedRegionException; -import ghidra.util.exception.DuplicateNameException; +import ghidra.trace.model.memory.TraceMemoryFlag; +import ghidra.trace.model.target.TraceObjectKeyPath; import ghidra.util.layout.PairLayout; public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider { private Trace trace; - private final JTextField fieldName = new JTextField(); + private final JTextField fieldPath = new JTextField(); private final GAddressRangeField fieldRange = new GAddressRangeField(); private final JTextField fieldLength = new JTextField(); private final GSpanField fieldLifespan = new GSpanField(); @@ -53,8 +58,8 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider { panel.setBorder(new EmptyBorder(10, 10, 10, 10)); - panel.add(new JLabel("Name: ")); - panel.add(fieldName); + panel.add(new JLabel("Path: ")); + panel.add(fieldPath); panel.add(new JLabel("Range: ")); panel.add(fieldRange); @@ -81,8 +86,8 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider { return new AddressRangeImpl(min, min.addWrap(lengthMinus1)); } - public void setName(String name) { - fieldName.setText(name); + public void setPath(String path) { + fieldPath.setText(path); } protected void setFieldLength(long length) { @@ -149,17 +154,33 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider { addRegionAndClose(); } - protected void setValues(Trace trace, Lifespan lifespan) { - this.trace = trace; + protected String computeDefaultPath(DebuggerCoordinates current) { + TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema(); + if (rootSchema == null) { + return ""; + } + List 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(); this.fieldRange.setAddressFactory(af); this.fieldRange.setRange(range(af.getDefaultAddressSpace().getAddress(0), 0)); this.fieldLength.setText("0x1"); + Lifespan lifespan = Lifespan.nowOn(current.getSnap()); this.fieldLifespan.setLifespan(lifespan); + this.fieldPath.setText(computeDefaultPath(current)); } - public void show(PluginTool tool, Trace trace, long snap) { - setValues(trace, Lifespan.nowOn(snap)); + public void show(PluginTool tool, DebuggerCoordinates current) { + setValues(current); tool.showDialog(this); } @@ -171,13 +192,16 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider { } protected void addRegionAndClose() { - try (Transaction tx = trace.openTransaction("Add region: " + fieldName)) { + try (Transaction tx = trace.openTransaction("Add region: " + fieldPath)) { trace.getMemoryManager() - .addRegion(fieldName.getText(), fieldLifespan.getLifespan(), - fieldRange.getRange()); + .addRegion( + fieldPath.getText(), + fieldLifespan.getLifespan(), fieldRange.getRange(), + Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE, + TraceMemoryFlag.EXECUTE)); close(); } - catch (TraceOverlappedRegionException | DuplicateNameException e) { + catch (Exception e) { setStatusText(e.getMessage()); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java index 8e0a461de7..763ffac514 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java @@ -467,7 +467,7 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter { if (current.getTrace() == null) { return; } - addRegionDialog.show(tool, current.getTrace(), current.getSnap()); + addRegionDialog.show(tool, current); } private void activatedDeleteRegions(ActionContext ctx) { diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java index 4a7dfc152c..d9012fcc91 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java @@ -4,9 +4,9 @@ * 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. @@ -495,7 +495,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerTes performEnabledAction(provider, provider.actionAddRegion, false); DebuggerAddRegionDialog dialog = waitForDialogComponent(DebuggerAddRegionDialog.class); runSwing(() -> { - dialog.setName("Memory[heap]"); + dialog.setPath("Memory[heap]"); dialog.setFieldLength(0x1000); dialog.lengthChanged(); // simulate ENTER/focus-exited dialog.okCallback(); diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/BadSchemaException.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/BadSchemaException.java new file mode 100644 index 0000000000..c39e32dbbf --- /dev/null +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/BadSchemaException.java @@ -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); + } +} diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java index 67d689ea82..e44f62afbc 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -893,12 +893,9 @@ public interface TargetObjectSchema { List schemas = getSuccessorSchemas(path); for (; path != null; path = PathUtils.parent(path)) { TargetObjectSchema schema = schemas.get(path.size()); - if (!schema.isCanonicalContainer()) { - continue; - } TargetObjectSchema deSchema = schema.getContext().getSchema(schema.getDefaultElementSchema()); - if (deSchema.getInterfaces().contains(type)) { + if (deSchema.getInterfaces().contains(type) && schema.isCanonicalContainer()) { return path; } List inAgg = Private.searchForSuitableContainerInAggregate(schema, type); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java index 43a65dadb7..0042e16bd4 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java @@ -4,9 +4,9 @@ * 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. @@ -310,8 +310,7 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra public void setFlags(Lifespan lifespan, Collection flags) { try (LockHold hold = object.getTrace().lockWrite()) { for (TraceMemoryFlag flag : TraceMemoryFlag.values()) { - Boolean val = flags.contains(flag) ? true : null; - object.setValue(lifespan, keyForFlag(flag), val); + object.setValue(lifespan, keyForFlag(flag), flags.contains(flag)); } } } @@ -329,7 +328,7 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra public void clearFlags(Lifespan lifespan, Collection flags) { try (LockHold hold = object.getTrace().lockWrite()) { for (TraceMemoryFlag flag : flags) { - object.setValue(lifespan, keyForFlag(flag), null); + object.setValue(lifespan, keyForFlag(flag), false); } } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java index a71e5bfd05..055b124216 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java @@ -539,9 +539,9 @@ public class DBTraceObjectManager implements TraceObjectManager, DBTraceManager Class targetIf = TraceObjectInterfaceUtils.toTargetIf(iface); TargetObjectSchema schema = rootSchema.getSuccessorSchema(keyList); if (!schema.getInterfaces().contains(targetIf)) { - throw new IllegalStateException( - "Schema " + schema + " at " + PathUtils.toString(keyList) + - " does not provide interface " + iface.getSimpleName()); + throw new BadSchemaException( + "Schema " + schema + " at '" + PathUtils.toString(keyList) + + "' does not provide interface " + iface.getSimpleName()); } DBTraceObject obj = createObject(TraceObjectKeyPath.of(keyList)); return obj.queryInterface(iface);