mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-1585: Change TargetBreakpointLocation to range, not address,length
This commit is contained in:
parent
6a2cd80550
commit
cb16d8dd9e
23 changed files with 1143 additions and 1161 deletions
|
@ -16,12 +16,12 @@
|
||||||
package agent.dbgeng.model.iface2;
|
package agent.dbgeng.model.iface2;
|
||||||
|
|
||||||
import ghidra.dbg.target.TargetBreakpointLocation;
|
import ghidra.dbg.target.TargetBreakpointLocation;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.AddressRange;
|
||||||
|
|
||||||
public interface DbgModelTargetBreakpointLocation
|
public interface DbgModelTargetBreakpointLocation
|
||||||
extends DbgModelTargetObject, TargetBreakpointLocation {
|
extends DbgModelTargetObject, TargetBreakpointLocation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress();
|
public AddressRange getRange();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import agent.dbgeng.model.iface1.DbgModelTargetBptHelper;
|
||||||
import ghidra.dbg.target.*;
|
import ghidra.dbg.target.*;
|
||||||
import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet;
|
import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
public interface DbgModelTargetBreakpointSpec extends //
|
public interface DbgModelTargetBreakpointSpec extends //
|
||||||
DbgModelTargetObject, //
|
DbgModelTargetObject, //
|
||||||
|
@ -99,12 +100,13 @@ public interface DbgModelTargetBreakpointSpec extends //
|
||||||
setBreakpointId(idstr);
|
setBreakpointId(idstr);
|
||||||
//String uidstr = unique.getCachedAttribute(VALUE_ATTRIBUTE_NAME).toString();
|
//String uidstr = unique.getCachedAttribute(VALUE_ATTRIBUTE_NAME).toString();
|
||||||
String enstr = enabled.getCachedAttribute(VALUE_ATTRIBUTE_NAME).toString();
|
String enstr = enabled.getCachedAttribute(VALUE_ATTRIBUTE_NAME).toString();
|
||||||
|
Address address = null;
|
||||||
try {
|
try {
|
||||||
Address address = space.getAddress(addstr);
|
address = space.getAddress(addstr);
|
||||||
map.put(ADDRESS_ATTRIBUTE_NAME, address);
|
//map.put(ADDRESS_ATTRIBUTE_NAME, address);
|
||||||
}
|
}
|
||||||
catch (AddressFormatException e) {
|
catch (AddressFormatException e) {
|
||||||
e.printStackTrace();
|
Msg.error(this, "Could not parse breakpoint address", e);
|
||||||
}
|
}
|
||||||
map.put(SPEC_ATTRIBUTE_NAME, this);
|
map.put(SPEC_ATTRIBUTE_NAME, this);
|
||||||
map.put(EXPRESSION_ATTRIBUTE_NAME, addstr);
|
map.put(EXPRESSION_ATTRIBUTE_NAME, addstr);
|
||||||
|
@ -113,7 +115,15 @@ public interface DbgModelTargetBreakpointSpec extends //
|
||||||
map.put(ENABLED_ATTRIBUTE_NAME, enstr.equals("-1"));
|
map.put(ENABLED_ATTRIBUTE_NAME, enstr.equals("-1"));
|
||||||
setEnabled(enstr.equals("-1"), "Refreshed");
|
setEnabled(enstr.equals("-1"), "Refreshed");
|
||||||
int size = getBreakpointInfo().getSize();
|
int size = getBreakpointInfo().getSize();
|
||||||
map.put(LENGTH_ATTRIBUTE_NAME, size);
|
//map.put(LENGTH_ATTRIBUTE_NAME, size);
|
||||||
|
if (address != null) {
|
||||||
|
try {
|
||||||
|
map.put(RANGE_ATTRIBUTE_NAME, new AddressRangeImpl(address, size));
|
||||||
|
}
|
||||||
|
catch (AddressOverflowException e) {
|
||||||
|
Msg.error(this, "Address overflow in breakpoint range", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String oldval = (String) getCachedAttribute(DISPLAY_ATTRIBUTE_NAME);
|
String oldval = (String) getCachedAttribute(DISPLAY_ATTRIBUTE_NAME);
|
||||||
String display = "[" + idstr + "] " + addstr;
|
String display = "[" + idstr + "] " + addstr;
|
||||||
|
@ -125,9 +135,13 @@ public interface DbgModelTargetBreakpointSpec extends //
|
||||||
|
|
||||||
private long orZero(Long l) {
|
private long orZero(Long l) {
|
||||||
if (l == null) {
|
if (l == null) {
|
||||||
return 0;
|
Msg.warn(this, "Breakpoint had null offset. Defaulting to ram:00000000");
|
||||||
}
|
}
|
||||||
return l;
|
return l == null ? 0 : l;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int orOne(Integer i) {
|
||||||
|
return i == null ? 1 : i;
|
||||||
}
|
}
|
||||||
|
|
||||||
public default Address doGetAddress() {
|
public default Address doGetAddress() {
|
||||||
|
@ -135,6 +149,14 @@ public interface DbgModelTargetBreakpointSpec extends //
|
||||||
return getModel().getAddress("ram", orZero(info.getOffset()));
|
return getModel().getAddress("ram", orZero(info.getOffset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public default AddressRange doGetRange() {
|
||||||
|
DbgBreakpointInfo info = getBreakpointInfo();
|
||||||
|
AddressSpace ram = getModel().getAddressSpace("ram");
|
||||||
|
Address min = ram.getAddress(orZero(info.getOffset()));
|
||||||
|
Address max = min.add(orOne(info.getSize()) - 1);
|
||||||
|
return new AddressRangeImpl(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
public default void updateInfo(DbgBreakpointInfo oldInfo, DbgBreakpointInfo newInfo,
|
public default void updateInfo(DbgBreakpointInfo oldInfo, DbgBreakpointInfo newInfo,
|
||||||
String reason) {
|
String reason) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
@ -147,6 +169,7 @@ public interface DbgModelTargetBreakpointSpec extends //
|
||||||
/**
|
/**
|
||||||
* Update the enabled field
|
* Update the enabled field
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* This does not actually toggle the breakpoint. It just updates the field and calls the proper
|
* This does not actually toggle the breakpoint. It just updates the field and calls the proper
|
||||||
* listeners. To actually toggle the breakpoint, use {@link #toggle(boolean)} instead, which if
|
* listeners. To actually toggle the breakpoint, use {@link #toggle(boolean)} instead, which if
|
||||||
* effective, should eventually cause this method to be called.
|
* effective, should eventually cause this method to be called.
|
||||||
|
|
|
@ -67,20 +67,18 @@ public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl
|
||||||
protected boolean enabled;
|
protected boolean enabled;
|
||||||
|
|
||||||
public void changeAttributeSet(String reason) {
|
public void changeAttributeSet(String reason) {
|
||||||
this.changeAttributes(List.of(), List.of(), Map.of( //
|
this.changeAttributes(List.of(), List.of(), Map.of(
|
||||||
DISPLAY_ATTRIBUTE_NAME, "[" + info.getNumber() + "] " + info.getExpression(), //
|
DISPLAY_ATTRIBUTE_NAME, "[" + info.getNumber() + "] " + info.getExpression(),
|
||||||
ADDRESS_ATTRIBUTE_NAME, doGetAddress(), //
|
RANGE_ATTRIBUTE_NAME, doGetRange(),
|
||||||
LENGTH_ATTRIBUTE_NAME, info.getSize(), //
|
SPEC_ATTRIBUTE_NAME, this,
|
||||||
SPEC_ATTRIBUTE_NAME, this, //
|
EXPRESSION_ATTRIBUTE_NAME, info.getExpression(),
|
||||||
EXPRESSION_ATTRIBUTE_NAME, info.getExpression(), //
|
KINDS_ATTRIBUTE_NAME, getKinds(),
|
||||||
KINDS_ATTRIBUTE_NAME, getKinds() //
|
|
||||||
), reason);
|
BPT_TYPE_ATTRIBUTE_NAME, info.getType().name(),
|
||||||
this.changeAttributes(List.of(), List.of(), Map.of( //
|
BPT_DISP_ATTRIBUTE_NAME, info.getDisp().name(),
|
||||||
BPT_TYPE_ATTRIBUTE_NAME, info.getType().name(), //
|
BPT_PENDING_ATTRIBUTE_NAME, info.getPending(),
|
||||||
BPT_DISP_ATTRIBUTE_NAME, info.getDisp().name(), //
|
BPT_TIMES_ATTRIBUTE_NAME, info.getTimes()),
|
||||||
BPT_PENDING_ATTRIBUTE_NAME, info.getPending(), //
|
reason);
|
||||||
BPT_TIMES_ATTRIBUTE_NAME, info.getTimes() //
|
|
||||||
), reason);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ListenerSet<TargetBreakpointAction> actions =
|
private final ListenerSet<TargetBreakpointAction> actions =
|
||||||
|
|
|
@ -503,8 +503,7 @@
|
||||||
<attribute name="_container" schema="BreakpointContainer" />
|
<attribute name="_container" schema="BreakpointContainer" />
|
||||||
<attribute name="_affects" schema="LIST_OBJECT" hidden="yes" />
|
<attribute name="_affects" schema="LIST_OBJECT" hidden="yes" />
|
||||||
<attribute name="_spec" schema="BreakpointSpec" />
|
<attribute name="_spec" schema="BreakpointSpec" />
|
||||||
<attribute name="_length" schema="INT" hidden="yes" />
|
<attribute name="_range" schema="RANGE" hidden="yes" />
|
||||||
<attribute name="_address" schema="ADDRESS" required="yes" hidden="yes" />
|
|
||||||
<attribute name="_modified" schema="BOOL" hidden="yes" />
|
<attribute name="_modified" schema="BOOL" hidden="yes" />
|
||||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
|
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
|
||||||
|
@ -585,6 +584,5 @@
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="VOID" />
|
<attribute schema="VOID" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="UPDATE_MODE" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="UPDATE_MODE" elementResync="NEVER" attributeResync="NEVER"></schema>
|
||||||
</schema>
|
|
||||||
</context>
|
</context>
|
||||||
|
|
|
@ -28,7 +28,7 @@ import ghidra.dbg.target.TargetBreakpointLocation;
|
||||||
import ghidra.dbg.target.TargetObject;
|
import ghidra.dbg.target.TargetObject;
|
||||||
import ghidra.dbg.target.schema.*;
|
import ghidra.dbg.target.schema.*;
|
||||||
import ghidra.dbg.util.PathUtils;
|
import ghidra.dbg.util.PathUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
@TargetObjectSchemaInfo(
|
@TargetObjectSchemaInfo(
|
||||||
|
@ -55,8 +55,7 @@ public class GdbModelTargetBreakpointLocation
|
||||||
protected final GdbModelImpl impl;
|
protected final GdbModelImpl impl;
|
||||||
protected final GdbBreakpointLocation loc;
|
protected final GdbBreakpointLocation loc;
|
||||||
|
|
||||||
protected Address address;
|
protected AddressRange range;
|
||||||
protected Integer length;
|
|
||||||
protected String display;
|
protected String display;
|
||||||
|
|
||||||
public GdbModelTargetBreakpointLocation(GdbModelTargetBreakpointSpec spec,
|
public GdbModelTargetBreakpointLocation(GdbModelTargetBreakpointSpec spec,
|
||||||
|
@ -67,8 +66,8 @@ public class GdbModelTargetBreakpointLocation
|
||||||
impl.addModelObject(loc, this);
|
impl.addModelObject(loc, this);
|
||||||
|
|
||||||
if (!spec.info.getType().isWatchpoint()) {
|
if (!spec.info.getType().isWatchpoint()) {
|
||||||
this.address = doGetAddress();
|
Address addr = impl.space.getAddress(loc.addrAsLong());
|
||||||
this.length = 1;
|
this.range = new AddressRangeImpl(addr, addr);
|
||||||
doChangeAttributes("Initialized");
|
doChangeAttributes("Initialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,8 +75,7 @@ public class GdbModelTargetBreakpointLocation
|
||||||
protected void doChangeAttributes(String reason) {
|
protected void doChangeAttributes(String reason) {
|
||||||
this.changeAttributes(List.of(), Map.of(
|
this.changeAttributes(List.of(), Map.of(
|
||||||
SPEC_ATTRIBUTE_NAME, parent,
|
SPEC_ATTRIBUTE_NAME, parent,
|
||||||
ADDRESS_ATTRIBUTE_NAME, address,
|
RANGE_ATTRIBUTE_NAME, range,
|
||||||
LENGTH_ATTRIBUTE_NAME, length,
|
|
||||||
DISPLAY_ATTRIBUTE_NAME, display = computeDisplay()),
|
DISPLAY_ATTRIBUTE_NAME, display = computeDisplay()),
|
||||||
reason);
|
reason);
|
||||||
placeLocations();
|
placeLocations();
|
||||||
|
@ -112,29 +110,26 @@ public class GdbModelTargetBreakpointLocation
|
||||||
throw new AssertionError("Unexpected result count: " + result);
|
throw new AssertionError("Unexpected result count: " + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
address = impl.space.getAddress(vals.get(0));
|
range = makeRange(impl.space.getAddress(vals.get(0)), vals.get(1).intValue());
|
||||||
length = vals.get(1).intValue();
|
|
||||||
doChangeAttributes("Initialized");
|
doChangeAttributes("Initialized");
|
||||||
}).exceptionally(ex -> {
|
}).exceptionally(ex -> {
|
||||||
Msg.warn(this, "Could not evaluated breakpoint location and/or size: " + ex);
|
Msg.warn(this, "Could not evaluated breakpoint location and/or size: " + ex);
|
||||||
address = impl.space.getAddress(0);
|
Address addr = impl.space.getAddress(0);
|
||||||
length = 1;
|
range = new AddressRangeImpl(addr, addr);
|
||||||
doChangeAttributes("Defaulted for eval/parse error");
|
doChangeAttributes("Defaulted for eval/parse error");
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String computeDisplay() {
|
protected String computeDisplay() {
|
||||||
return String.format("%d.%d %s", parent.info.getNumber(), loc.getSub(), address);
|
return String.format("%d.%d %s", parent.info.getNumber(), loc.getSub(),
|
||||||
|
range.getMinAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Address doGetAddress() {
|
// Avoid the checked exception on new AddressRangeImpl(min, length)
|
||||||
return impl.space.getAddress(loc.addrAsLong());
|
protected static AddressRange makeRange(Address min, int length) {
|
||||||
}
|
Address max = min.add(length - 1);
|
||||||
|
return new AddressRangeImpl(min, max);
|
||||||
@Override
|
|
||||||
public Integer getLength() {
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void placeLocations() {
|
protected void placeLocations() {
|
||||||
|
@ -161,6 +156,11 @@ public class GdbModelTargetBreakpointLocation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AddressRange getRange() {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GdbModelTargetBreakpointSpec getSpecification() {
|
public GdbModelTargetBreakpointSpec getSpecification() {
|
||||||
return parent;
|
return parent;
|
||||||
|
|
|
@ -16,13 +16,13 @@
|
||||||
package agent.lldb.model.iface2;
|
package agent.lldb.model.iface2;
|
||||||
|
|
||||||
import ghidra.dbg.target.TargetBreakpointLocation;
|
import ghidra.dbg.target.TargetBreakpointLocation;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.AddressRange;
|
||||||
|
|
||||||
public interface LldbModelTargetBreakpointLocation
|
public interface LldbModelTargetBreakpointLocation
|
||||||
extends LldbModelTargetObject, TargetBreakpointLocation {
|
extends LldbModelTargetObject, TargetBreakpointLocation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress();
|
AddressRange getRange();
|
||||||
|
|
||||||
public int getLocationId();
|
public int getLocationId();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import ghidra.dbg.target.TargetObject;
|
||||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||||
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
||||||
import ghidra.dbg.util.PathUtils;
|
import ghidra.dbg.util.PathUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
|
|
||||||
@TargetObjectSchemaInfo(
|
@TargetObjectSchemaInfo(
|
||||||
name = "BreakpointLocation",
|
name = "BreakpointLocation",
|
||||||
|
@ -46,11 +46,9 @@ public class LldbModelTargetBreakpointLocationImpl extends LldbModelTargetObject
|
||||||
protected LldbModelTargetAbstractXpointSpec spec;
|
protected LldbModelTargetAbstractXpointSpec spec;
|
||||||
protected SBBreakpointLocation loc;
|
protected SBBreakpointLocation loc;
|
||||||
|
|
||||||
protected Address address;
|
protected AddressRange range;
|
||||||
protected Integer length;
|
|
||||||
protected String display;
|
protected String display;
|
||||||
|
|
||||||
|
|
||||||
public LldbModelTargetBreakpointLocationImpl(LldbModelTargetAbstractXpointSpec spec,
|
public LldbModelTargetBreakpointLocationImpl(LldbModelTargetAbstractXpointSpec spec,
|
||||||
SBBreakpointLocation loc) {
|
SBBreakpointLocation loc) {
|
||||||
super(spec.getModel(), spec, keyLocation(loc), loc, "BreakpointLocation");
|
super(spec.getModel(), spec, keyLocation(loc), loc, "BreakpointLocation");
|
||||||
|
@ -60,21 +58,28 @@ public class LldbModelTargetBreakpointLocationImpl extends LldbModelTargetObject
|
||||||
doChangeAttributes("Initialization");
|
doChangeAttributes("Initialization");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: A separate class for Impl wrapping SBWatchpoint?
|
||||||
public LldbModelTargetBreakpointLocationImpl(LldbModelTargetAbstractXpointSpec spec,
|
public LldbModelTargetBreakpointLocationImpl(LldbModelTargetAbstractXpointSpec spec,
|
||||||
SBWatchpoint wpt) {
|
SBWatchpoint wpt) {
|
||||||
super(spec.getModel(), spec, keyLocation(wpt), wpt, "BreakpointLocation");
|
super(spec.getModel(), spec, keyLocation(wpt), wpt, "BreakpointLocation");
|
||||||
this.loc = null;
|
this.loc = null;
|
||||||
|
|
||||||
address = getModel().getAddress("ram", wpt.GetWatchAddress().longValue());
|
Address address = getModel().getAddress("ram", wpt.GetWatchAddress().longValue());
|
||||||
|
long length = wpt.GetWatchSize();
|
||||||
this.changeAttributes(List.of(), Map.of(
|
this.changeAttributes(List.of(), Map.of(
|
||||||
SPEC_ATTRIBUTE_NAME, parent,
|
SPEC_ATTRIBUTE_NAME, parent,
|
||||||
ADDRESS_ATTRIBUTE_NAME, address,
|
RANGE_ATTRIBUTE_NAME, range = makeRange(address, length),
|
||||||
LENGTH_ATTRIBUTE_NAME, length = (int) wpt.GetWatchSize(),
|
|
||||||
DISPLAY_ATTRIBUTE_NAME, display = getDescription(1)),
|
DISPLAY_ATTRIBUTE_NAME, display = getDescription(1)),
|
||||||
"Initialization");
|
"Initialization");
|
||||||
placeLocations();
|
placeLocations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static AddressRange makeRange(Address min, long length) {
|
||||||
|
Address max = min.add(length - 1);
|
||||||
|
return new AddressRangeImpl(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getDescription(int level) {
|
public String getDescription(int level) {
|
||||||
Object modelObject = getModelObject();
|
Object modelObject = getModelObject();
|
||||||
SBStream stream = new SBStream();
|
SBStream stream = new SBStream();
|
||||||
|
@ -91,12 +96,10 @@ public class LldbModelTargetBreakpointLocationImpl extends LldbModelTargetObject
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doChangeAttributes(String reason) {
|
protected void doChangeAttributes(String reason) {
|
||||||
address = getModel().getAddress("ram", loc.GetLoadAddress().longValue());
|
Address address = getModel().getAddress("ram", loc.GetLoadAddress().longValue());
|
||||||
length = 1;
|
|
||||||
this.changeAttributes(List.of(), Map.of(
|
this.changeAttributes(List.of(), Map.of(
|
||||||
SPEC_ATTRIBUTE_NAME, parent,
|
SPEC_ATTRIBUTE_NAME, parent,
|
||||||
ADDRESS_ATTRIBUTE_NAME, address,
|
RANGE_ATTRIBUTE_NAME, range = new AddressRangeImpl(address, address),
|
||||||
LENGTH_ATTRIBUTE_NAME, length,
|
|
||||||
DISPLAY_ATTRIBUTE_NAME, display = getDescription(1)),
|
DISPLAY_ATTRIBUTE_NAME, display = getDescription(1)),
|
||||||
reason);
|
reason);
|
||||||
placeLocations();
|
placeLocations();
|
||||||
|
@ -104,7 +107,8 @@ public class LldbModelTargetBreakpointLocationImpl extends LldbModelTargetObject
|
||||||
|
|
||||||
protected void placeLocations() {
|
protected void placeLocations() {
|
||||||
LldbModelTargetSession parentSession = getParentSession();
|
LldbModelTargetSession parentSession = getParentSession();
|
||||||
Map<String, ? extends TargetObject> cachedElements = parentSession.getProcesses().getCachedElements();
|
Map<String, ? extends TargetObject> cachedElements =
|
||||||
|
parentSession.getProcesses().getCachedElements();
|
||||||
for (TargetObject obj : cachedElements.values()) {
|
for (TargetObject obj : cachedElements.values()) {
|
||||||
if (obj instanceof LldbModelTargetProcess) {
|
if (obj instanceof LldbModelTargetProcess) {
|
||||||
LldbModelTargetProcessImpl process = (LldbModelTargetProcessImpl) obj;
|
LldbModelTargetProcessImpl process = (LldbModelTargetProcessImpl) obj;
|
||||||
|
@ -123,19 +127,16 @@ public class LldbModelTargetBreakpointLocationImpl extends LldbModelTargetObject
|
||||||
TargetObject modelObject = getModel().getModelObject(getManager().getCurrentProcess());
|
TargetObject modelObject = getModel().getModelObject(getManager().getCurrentProcess());
|
||||||
if (modelObject instanceof LldbModelTargetProcess) {
|
if (modelObject instanceof LldbModelTargetProcess) {
|
||||||
LldbModelTargetProcess targetProcess = (LldbModelTargetProcess) modelObject;
|
LldbModelTargetProcess targetProcess = (LldbModelTargetProcess) modelObject;
|
||||||
LldbModelTargetBreakpointLocationContainer locs = (LldbModelTargetBreakpointLocationContainer) targetProcess.getCachedAttribute("Breakpoints");
|
LldbModelTargetBreakpointLocationContainer locs =
|
||||||
|
(LldbModelTargetBreakpointLocationContainer) targetProcess
|
||||||
|
.getCachedAttribute("Breakpoints");
|
||||||
locs.removeBreakpointLocation(this);
|
locs.removeBreakpointLocation(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getLength() {
|
public AddressRange getRange() {
|
||||||
return length;
|
return range;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -56,6 +56,7 @@ public class LldbModelTargetBreakpointSpecImpl extends LldbModelTargetAbstractXp
|
||||||
super(breakpoints, info, "BreakpointSpec");
|
super(breakpoints, info, "BreakpointSpec");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getDescription(int level) {
|
public String getDescription(int level) {
|
||||||
SBStream stream = new SBStream();
|
SBStream stream = new SBStream();
|
||||||
SBBreakpoint bpt = (SBBreakpoint) getModelObject();
|
SBBreakpoint bpt = (SBBreakpoint) getModelObject();
|
||||||
|
@ -63,16 +64,17 @@ public class LldbModelTargetBreakpointSpecImpl extends LldbModelTargetAbstractXp
|
||||||
return stream.GetData();
|
return stream.GetData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected TargetBreakpointKindSet computeKinds(Object from) {
|
protected TargetBreakpointKindSet computeKinds(Object from) {
|
||||||
if (from instanceof SBBreakpoint) {
|
if (from instanceof SBBreakpoint) {
|
||||||
SBBreakpoint bpt = (SBBreakpoint) from;
|
SBBreakpoint bpt = (SBBreakpoint) from;
|
||||||
return bpt.IsHardware() ?
|
return bpt.IsHardware() ? TargetBreakpointKindSet.of(TargetBreakpointKind.HW_EXECUTE)
|
||||||
TargetBreakpointKindSet.of(TargetBreakpointKind.HW_EXECUTE) :
|
: TargetBreakpointKindSet.of(TargetBreakpointKind.SW_EXECUTE);
|
||||||
TargetBreakpointKindSet.of(TargetBreakpointKind.SW_EXECUTE);
|
|
||||||
}
|
}
|
||||||
return TargetBreakpointKindSet.of();
|
return TargetBreakpointKindSet.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateInfo(Object info, String reason) {
|
public void updateInfo(Object info, String reason) {
|
||||||
setModelObject(info);
|
setModelObject(info);
|
||||||
updateAttributesFromInfo(reason);
|
updateAttributesFromInfo(reason);
|
||||||
|
@ -91,6 +93,7 @@ public class LldbModelTargetBreakpointSpecImpl extends LldbModelTargetAbstractXp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateAttributesFromInfo(String reason) {
|
public void updateAttributesFromInfo(String reason) {
|
||||||
SBBreakpoint bpt = (SBBreakpoint) getModelObject();
|
SBBreakpoint bpt = (SBBreakpoint) getModelObject();
|
||||||
String description = getDescription(1);
|
String description = getDescription(1);
|
||||||
|
@ -118,15 +121,17 @@ public class LldbModelTargetBreakpointSpecImpl extends LldbModelTargetAbstractXp
|
||||||
LldbModelTargetBreakpointLocationImpl loc =
|
LldbModelTargetBreakpointLocationImpl loc =
|
||||||
(LldbModelTargetBreakpointLocationImpl) elements[0];
|
(LldbModelTargetBreakpointLocationImpl) elements[0];
|
||||||
this.changeAttributes(List.of(), List.of(), Map.of( //
|
this.changeAttributes(List.of(), List.of(), Map.of( //
|
||||||
TargetBreakpointLocation.ADDRESS_ATTRIBUTE_NAME, loc.address //
|
TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME, loc.range //
|
||||||
), reason);
|
), reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ListenerSet<TargetBreakpointAction> getActions() {
|
public ListenerSet<TargetBreakpointAction> getActions() {
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public LldbModelTargetBreakpointLocation findLocation(Object obj) {
|
public LldbModelTargetBreakpointLocation findLocation(Object obj) {
|
||||||
if (!(obj instanceof BigInteger)) {
|
if (!(obj instanceof BigInteger)) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -70,7 +70,8 @@ import ghidra.framework.options.annotation.*;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.annotation.AutoConfigStateField;
|
import ghidra.framework.plugintool.annotation.AutoConfigStateField;
|
||||||
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.program.util.ProgramSelection;
|
import ghidra.program.util.ProgramSelection;
|
||||||
|
@ -2097,9 +2098,9 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||||
if (listingService == null || listingService == null) {
|
if (listingService == null || listingService == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// TODO: Could probably inspect schema for any attribute of type Address[Range], or String
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value =
|
value = object.getCachedAttribute(TargetObject.PREFIX_INVISIBLE + "address");
|
||||||
object.getCachedAttribute(TargetBreakpointLocation.ADDRESS_ATTRIBUTE_NAME);
|
|
||||||
}
|
}
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = object.getCachedAttribute(TargetObject.PREFIX_INVISIBLE + "range");
|
value = object.getCachedAttribute(TargetObject.PREFIX_INVISIBLE + "range");
|
||||||
|
@ -2112,19 +2113,16 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
Address addr = null;
|
Address addr = null;
|
||||||
if (value instanceof Address) {
|
if (value instanceof Address a) {
|
||||||
addr = (Address) value;
|
addr = a;
|
||||||
}
|
}
|
||||||
else if (value instanceof AddressRangeImpl) {
|
else if (value instanceof AddressRange range) {
|
||||||
AddressRangeImpl range = (AddressRangeImpl) value;
|
|
||||||
addr = range.getMinAddress();
|
addr = range.getMinAddress();
|
||||||
}
|
}
|
||||||
else if (value instanceof Long) {
|
else if (value instanceof Long lval) {
|
||||||
Long lval = (Long) value;
|
|
||||||
addr = object.getModel().getAddress("ram", lval);
|
addr = object.getModel().getAddress("ram", lval);
|
||||||
}
|
}
|
||||||
else if (value instanceof String) {
|
else if (value instanceof String sval) {
|
||||||
String sval = (String) value;
|
|
||||||
addr = stringToAddress(object, addr, sval);
|
addr = stringToAddress(object, addr, sval);
|
||||||
}
|
}
|
||||||
if (addr != null) {
|
if (addr != null) {
|
||||||
|
|
|
@ -23,8 +23,7 @@ import ghidra.app.services.LogicalBreakpoint;
|
||||||
import ghidra.app.services.TraceRecorder;
|
import ghidra.app.services.TraceRecorder;
|
||||||
import ghidra.dbg.target.*;
|
import ghidra.dbg.target.*;
|
||||||
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
|
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressSet;
|
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
@ -394,10 +393,11 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
|
||||||
Set<TargetBreakpointKind> tKinds = TraceRecorder.traceToTargetBreakpointKinds(kinds);
|
Set<TargetBreakpointKind> tKinds = TraceRecorder.traceToTargetBreakpointKinds(kinds);
|
||||||
Address targetAddr = computeTargetAddress();
|
Address targetAddr = computeTargetAddress();
|
||||||
for (TargetBreakpointLocation loc : recorder.collectBreakpoints(null)) {
|
for (TargetBreakpointLocation loc : recorder.collectBreakpoints(null)) {
|
||||||
if (!targetAddr.equals(loc.getAddress())) {
|
AddressRange range = loc.getRange();
|
||||||
|
if (!targetAddr.equals(range.getMinAddress())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (length != loc.getLength().longValue()) {
|
if (length != range.getLength()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TargetBreakpointSpec spec = loc.getSpecification();
|
TargetBreakpointSpec spec = loc.getSpecification();
|
||||||
|
@ -413,10 +413,11 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
|
||||||
Set<TargetBreakpointKind> tKinds = TraceRecorder.traceToTargetBreakpointKinds(kinds);
|
Set<TargetBreakpointKind> tKinds = TraceRecorder.traceToTargetBreakpointKinds(kinds);
|
||||||
Address targetAddr = computeTargetAddress();
|
Address targetAddr = computeTargetAddress();
|
||||||
for (TargetBreakpointLocation loc : recorder.collectBreakpoints(null)) {
|
for (TargetBreakpointLocation loc : recorder.collectBreakpoints(null)) {
|
||||||
if (!targetAddr.equals(loc.getAddress())) {
|
AddressRange range = loc.getRange();
|
||||||
|
if (!targetAddr.equals(range.getMinAddress())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (length != loc.getLength().longValue()) {
|
if (length != range.getLength()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TargetBreakpointSpec spec = loc.getSpecification();
|
TargetBreakpointSpec spec = loc.getSpecification();
|
||||||
|
|
|
@ -31,18 +31,6 @@ import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
|
public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
|
||||||
|
|
||||||
public static AddressRange range(Address min, Integer length) {
|
|
||||||
if (length == null) {
|
|
||||||
length = 1;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new AddressRangeImpl(min, length);
|
|
||||||
}
|
|
||||||
catch (AddressOverflowException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static String nameBreakpoint(TargetBreakpointLocation bpt) {
|
protected static String nameBreakpoint(TargetBreakpointLocation bpt) {
|
||||||
if (bpt instanceof TargetBreakpointSpec) {
|
if (bpt instanceof TargetBreakpointSpec) {
|
||||||
return bpt.getIndex();
|
return bpt.getIndex();
|
||||||
|
@ -93,8 +81,7 @@ public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
|
||||||
}
|
}
|
||||||
String path = PathUtils.toString(loc.getPath());
|
String path = PathUtils.toString(loc.getPath());
|
||||||
String name = nameBreakpoint(loc);
|
String name = nameBreakpoint(loc);
|
||||||
Address traceAddr = recorder.getMemoryMapper().targetToTrace(loc.getAddress());
|
AddressRange traceRange = recorder.getMemoryMapper().targetToTrace(loc.getRange());
|
||||||
AddressRange traceRange = range(traceAddr, loc.getLength());
|
|
||||||
try {
|
try {
|
||||||
TargetBreakpointSpec spec = loc.getSpecification();
|
TargetBreakpointSpec spec = loc.getSpecification();
|
||||||
boolean enabled = spec.isEnabled();
|
boolean enabled = spec.isEnabled();
|
||||||
|
@ -151,11 +138,9 @@ public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
|
||||||
}, path);
|
}, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doBreakpointLocationChanged(long snap, int length, Address traceAddr,
|
protected void doBreakpointLocationChanged(long snap, AddressRange traceRng, String path) {
|
||||||
String path) {
|
|
||||||
for (TraceBreakpoint traceBpt : breakpointManager.getBreakpointsByPath(path)) {
|
for (TraceBreakpoint traceBpt : breakpointManager.getBreakpointsByPath(path)) {
|
||||||
AddressRange range = range(traceAddr, length);
|
if (traceBpt.getRange().equals(traceRng)) {
|
||||||
if (traceBpt.getRange().equals(range)) {
|
|
||||||
continue; // Nothing to change
|
continue; // Nothing to change
|
||||||
}
|
}
|
||||||
// TODO: Verify all other attributes match?
|
// TODO: Verify all other attributes match?
|
||||||
|
@ -167,7 +152,7 @@ public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
|
||||||
traceBpt.setClearedSnap(snap - 1);
|
traceBpt.setClearedSnap(snap - 1);
|
||||||
}
|
}
|
||||||
TraceBreakpoint newtraceBpt =
|
TraceBreakpoint newtraceBpt =
|
||||||
breakpointManager.placeBreakpoint(path, snap, range,
|
breakpointManager.placeBreakpoint(path, snap, traceRng,
|
||||||
traceBpt.getThreads(), traceBpt.getKinds(), traceBpt.isEnabled(snap),
|
traceBpt.getThreads(), traceBpt.getKinds(), traceBpt.isEnabled(snap),
|
||||||
traceBpt.getComment());
|
traceBpt.getComment());
|
||||||
// placeBreakpoint resets the name - maybe pass name in?
|
// placeBreakpoint resets the name - maybe pass name in?
|
||||||
|
@ -182,11 +167,11 @@ public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void breakpointLocationChanged(int length, Address traceAddr, String path)
|
public void breakpointLocationChanged(AddressRange traceRng, String path)
|
||||||
throws AssertionError {
|
throws AssertionError {
|
||||||
long snap = recorder.getSnap();
|
long snap = recorder.getSnap();
|
||||||
recorder.parTx.execute("Breakpoint length changed", () -> {
|
recorder.parTx.execute("Breakpoint length changed", () -> {
|
||||||
doBreakpointLocationChanged(snap, length, traceAddr, path);
|
doBreakpointLocationChanged(snap, traceRng, path);
|
||||||
}, path);
|
}, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ghidra.async.AsyncLazyMap;
|
||||||
import ghidra.dbg.target.*;
|
import ghidra.dbg.target.*;
|
||||||
import ghidra.dbg.util.PathUtils;
|
import ghidra.dbg.util.PathUtils;
|
||||||
import ghidra.dbg.util.PathUtils.PathComparator;
|
import ghidra.dbg.util.PathUtils.PathComparator;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
||||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||||
|
@ -496,12 +496,10 @@ public class TraceObjectManager {
|
||||||
|
|
||||||
public void attributesChangedBreakpointLocation(TargetObject obj, Map<String, ?> added) {
|
public void attributesChangedBreakpointLocation(TargetObject obj, Map<String, ?> added) {
|
||||||
TargetBreakpointLocation loc = (TargetBreakpointLocation) obj;
|
TargetBreakpointLocation loc = (TargetBreakpointLocation) obj;
|
||||||
if (added.containsKey(TargetBreakpointLocation.LENGTH_ATTRIBUTE_NAME) ||
|
if (added.containsKey(TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME)) {
|
||||||
added.containsKey(TargetBreakpointLocation.ADDRESS_ATTRIBUTE_NAME)) {
|
AddressRange traceRng = recorder.getMemoryMapper().targetToTrace(loc.getRange());
|
||||||
Address traceAddr = recorder.getMemoryMapper().targetToTrace(loc.getAddress());
|
|
||||||
String path = loc.getJoinedPath(".");
|
String path = loc.getJoinedPath(".");
|
||||||
int length = loc.getLengthOrDefault(1);
|
recorder.breakpointRecorder.breakpointLocationChanged(traceRng, path);
|
||||||
recorder.breakpointRecorder.breakpointLocationChanged(length, traceAddr, path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import ghidra.dbg.target.*;
|
import ghidra.dbg.target.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
|
@ -41,11 +41,10 @@ public interface ManagedBreakpointRecorder {
|
||||||
/**
|
/**
|
||||||
* The range of a breakpoint location has changed
|
* The range of a breakpoint location has changed
|
||||||
*
|
*
|
||||||
* @param length the new length
|
* @param traceRng the address range of the location in the trace
|
||||||
* @param traceAddr the address of the location in the trace
|
|
||||||
* @param path the dot-separated path of the breakpoint location in the model
|
* @param path the dot-separated path of the breakpoint location in the model
|
||||||
*/
|
*/
|
||||||
void breakpointLocationChanged(int length, Address traceAddr, String path);
|
void breakpointLocationChanged(AddressRange traceRng, String path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A breakpoint specification has changed (typically, toggled)
|
* A breakpoint specification has changed (typically, toggled)
|
||||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.dbg.target;
|
||||||
import ghidra.dbg.DebuggerTargetObjectIface;
|
import ghidra.dbg.DebuggerTargetObjectIface;
|
||||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressRange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The location of a breakpoint
|
* The location of a breakpoint
|
||||||
|
@ -31,20 +32,33 @@ import ghidra.program.model.address.Address;
|
||||||
@DebuggerTargetObjectIface("BreakpointLocation")
|
@DebuggerTargetObjectIface("BreakpointLocation")
|
||||||
public interface TargetBreakpointLocation extends TargetObject {
|
public interface TargetBreakpointLocation extends TargetObject {
|
||||||
|
|
||||||
String ADDRESS_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "address";
|
String RANGE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "range";
|
||||||
// NOTE: address and length are treated separately (not using AddressRange)
|
|
||||||
// On GDB, e.g., the length may not be offered immediately.
|
|
||||||
String LENGTH_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "length";
|
|
||||||
String SPEC_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "spec";
|
String SPEC_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "spec";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The range covered by this location
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Typically, watchpoints (or access breakpoints) have a length, so the range would cover all
|
||||||
|
* addresses in the variable being watched. Execution breakpoints likely have a "length" of 1,
|
||||||
|
* meaning they cover only the address of the trap.
|
||||||
|
*
|
||||||
|
* @return the address range of the location
|
||||||
|
*/
|
||||||
|
@TargetAttributeType(name = RANGE_ATTRIBUTE_NAME, hidden = true)
|
||||||
|
public default AddressRange getRange() {
|
||||||
|
return getTypedAttributeNowByName(RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimum address of this location
|
* The minimum address of this location
|
||||||
*
|
*
|
||||||
* @return the address
|
* @return the address
|
||||||
|
* @deprecated use {@link #getRange()} instead
|
||||||
*/
|
*/
|
||||||
@TargetAttributeType(name = ADDRESS_ATTRIBUTE_NAME, required = true, hidden = true)
|
@Deprecated(forRemoval = true, since = "10.2")
|
||||||
public default Address getAddress() {
|
public default Address getAddress() {
|
||||||
return getTypedAttributeNowByName(ADDRESS_ATTRIBUTE_NAME, Address.class, null);
|
return getRange().getMinAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,18 +67,26 @@ public interface TargetBreakpointLocation extends TargetObject {
|
||||||
* <p>
|
* <p>
|
||||||
* In most cases, where the length is not available, a length of 1 should be presumed.
|
* In most cases, where the length is not available, a length of 1 should be presumed.
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
* TODO: Should this be Long?
|
|
||||||
*
|
|
||||||
* @return the length, or {@code null} if not known
|
* @return the length, or {@code null} if not known
|
||||||
|
* @deprecated use {@link #getRange()} instead
|
||||||
*/
|
*/
|
||||||
@TargetAttributeType(name = LENGTH_ATTRIBUTE_NAME, hidden = true)
|
@Deprecated(forRemoval = true, since = "10.2")
|
||||||
public default Integer getLength() {
|
public default Integer getLength() {
|
||||||
return getTypedAttributeNowByName(LENGTH_ATTRIBUTE_NAME, Integer.class, null);
|
AddressRange range = getRange();
|
||||||
|
return range == null ? null : (int) range.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the length, defaulting to a given fallback, usually 1
|
||||||
|
*
|
||||||
|
* @param fallback the fallback value
|
||||||
|
* @return the length, or the fallback
|
||||||
|
* @deprecated use {@link #getRange()} instead
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "10.2")
|
||||||
public default int getLengthOrDefault(int fallback) {
|
public default int getLengthOrDefault(int fallback) {
|
||||||
return getTypedAttributeNowByName(LENGTH_ATTRIBUTE_NAME, Integer.class, fallback);
|
Integer length = getLength();
|
||||||
|
return length == null ? 1 : length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,7 +94,8 @@ public interface TargetBreakpointLocation extends TargetObject {
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If the debugger does not separate specifications from actual breakpoints, then the
|
* If the debugger does not separate specifications from actual breakpoints, then the
|
||||||
* "specification" is this breakpoint. Otherwise, the specification is the parent.
|
* "specification" is this breakpoint. Otherwise, the specification is identified by an
|
||||||
|
* attribute, usually a link.
|
||||||
*
|
*
|
||||||
* @return the reference to the specification
|
* @return the reference to the specification
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -92,8 +92,8 @@ public class TestDebuggerObjectModel extends EmptyDebuggerObjectModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TestTargetBreakpoint newTestTargetBreakpoint(TestTargetBreakpointContainer container,
|
protected TestTargetBreakpoint newTestTargetBreakpoint(TestTargetBreakpointContainer container,
|
||||||
int num, Address address, int length, Set<TargetBreakpointKind> kinds) {
|
int num, AddressRange range, Set<TargetBreakpointKind> kinds) {
|
||||||
return new TestTargetBreakpoint(container, num, address, length, kinds);
|
return new TestTargetBreakpoint(container, num, range, kinds);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TestTargetMemory newTestTargetMemory(TestTargetProcess process, AddressSpace space) {
|
protected TestTargetMemory newTestTargetMemory(TestTargetProcess process, AddressSpace space) {
|
||||||
|
|
|
@ -21,24 +21,23 @@ import java.util.concurrent.CompletableFuture;
|
||||||
import ghidra.dbg.target.*;
|
import ghidra.dbg.target.*;
|
||||||
import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet;
|
import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet;
|
||||||
import ghidra.dbg.util.PathUtils;
|
import ghidra.dbg.util.PathUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
|
|
||||||
public class TestTargetBreakpoint
|
public class TestTargetBreakpoint
|
||||||
extends DefaultTestTargetObject<TestTargetBreakpoint, TestTargetBreakpointContainer>
|
extends DefaultTestTargetObject<TestTargetBreakpoint, TestTargetBreakpointContainer>
|
||||||
implements TargetBreakpointSpec, TargetBreakpointLocation, TargetDeletable {
|
implements TargetBreakpointSpec, TargetBreakpointLocation, TargetDeletable {
|
||||||
|
|
||||||
public TestTargetBreakpoint(TestTargetBreakpointContainer parent, int num, Address address,
|
public TestTargetBreakpoint(TestTargetBreakpointContainer parent, int num, AddressRange range,
|
||||||
int length, Set<TargetBreakpointKind> kinds) {
|
Set<TargetBreakpointKind> kinds) {
|
||||||
super(parent, PathUtils.makeKey(PathUtils.makeIndex(num)), "Breakpoint");
|
super(parent, PathUtils.makeKey(PathUtils.makeIndex(num)), "Breakpoint");
|
||||||
|
|
||||||
changeAttributes(List.of(), Map.of(
|
changeAttributes(List.of(), Map.of(
|
||||||
SPEC_ATTRIBUTE_NAME, this,
|
SPEC_ATTRIBUTE_NAME, this,
|
||||||
ADDRESS_ATTRIBUTE_NAME, address,
|
RANGE_ATTRIBUTE_NAME, range,
|
||||||
ENABLED_ATTRIBUTE_NAME, true,
|
ENABLED_ATTRIBUTE_NAME, true,
|
||||||
EXPRESSION_ATTRIBUTE_NAME, address.toString(),
|
EXPRESSION_ATTRIBUTE_NAME, range.getMinAddress().toString(),
|
||||||
KINDS_ATTRIBUTE_NAME, TargetBreakpointKindSet.copyOf(kinds),
|
KINDS_ATTRIBUTE_NAME, TargetBreakpointKindSet.copyOf(kinds)),
|
||||||
LENGTH_ATTRIBUTE_NAME, length //
|
"Initialized");
|
||||||
), "Initialized");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -57,8 +57,7 @@ public class TestTargetBreakpointContainer
|
||||||
public CompletableFuture<Void> placeBreakpoint(AddressRange range,
|
public CompletableFuture<Void> placeBreakpoint(AddressRange range,
|
||||||
Set<TargetBreakpointKind> kinds) {
|
Set<TargetBreakpointKind> kinds) {
|
||||||
TestTargetBreakpoint bpt =
|
TestTargetBreakpoint bpt =
|
||||||
getModel().newTestTargetBreakpoint(this, counter.getAndIncrement(),
|
getModel().newTestTargetBreakpoint(this, counter.getAndIncrement(), range, kinds);
|
||||||
range.getMinAddress(), (int) range.getLength(), kinds);
|
|
||||||
changeElements(List.of(), List.of(bpt), "Breakpoint Added");
|
changeElements(List.of(), List.of(bpt), "Breakpoint Added");
|
||||||
return getModel().future(null);
|
return getModel().future(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
package ghidra.dbg.test;
|
package ghidra.dbg.test;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assume.*;
|
import static org.junit.Assume.assumeNotNull;
|
||||||
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -31,7 +32,6 @@ import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet;
|
||||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||||
import ghidra.dbg.util.DebuggerCallbackReorderer;
|
import ghidra.dbg.util.DebuggerCallbackReorderer;
|
||||||
import ghidra.program.model.address.AddressRange;
|
import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.program.model.address.AddressRangeImpl;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,10 +141,10 @@ public abstract class AbstractDebuggerModelBreakpointsTest extends AbstractDebug
|
||||||
if (spec == null) { // Mid construction?
|
if (spec == null) { // Mid construction?
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (l.getAddress() == null || l.getLength() == null) {
|
AddressRange actualRange = l.getRange();
|
||||||
|
if (actualRange == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AddressRange actualRange = new AddressRangeImpl(l.getAddress(), l.getLength());
|
|
||||||
if (!actualRange.contains(range.getMinAddress()) ||
|
if (!actualRange.contains(range.getMinAddress()) ||
|
||||||
!actualRange.contains(range.getMaxAddress())) {
|
!actualRange.contains(range.getMaxAddress())) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -318,8 +318,7 @@
|
||||||
<attribute name="_container" schema="BreakpointContainer" />
|
<attribute name="_container" schema="BreakpointContainer" />
|
||||||
<attribute name="_affects" schema="LIST_OBJECT" hidden="yes" />
|
<attribute name="_affects" schema="LIST_OBJECT" hidden="yes" />
|
||||||
<attribute name="_spec" schema="Breakpoint" />
|
<attribute name="_spec" schema="Breakpoint" />
|
||||||
<attribute name="_length" schema="INT" hidden="yes" />
|
<attribute name="_range" schema="RANGE" hidden="yes" />
|
||||||
<attribute name="_address" schema="ADDRESS" required="yes" hidden="yes" />
|
|
||||||
<attribute name="_modified" schema="BOOL" hidden="yes" />
|
<attribute name="_modified" schema="BOOL" hidden="yes" />
|
||||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
|
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
|
|
||||||
import db.DBHandle;
|
import db.DBHandle;
|
||||||
|
import ghidra.dbg.target.TargetBreakpointLocation;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
|
@ -142,7 +143,8 @@ public class DBTraceBreakpointManager
|
||||||
public Collection<? extends TraceBreakpoint> getBreakpointsAt(long snap, Address address) {
|
public Collection<? extends TraceBreakpoint> getBreakpointsAt(long snap, Address address) {
|
||||||
if (trace.getObjectManager().hasSchema()) {
|
if (trace.getObjectManager().hasSchema()) {
|
||||||
return trace.getObjectManager()
|
return trace.getObjectManager()
|
||||||
.getObjectsContaining(snap, address, TraceObjectBreakpointLocation.KEY_RANGE,
|
.getObjectsContaining(snap, address,
|
||||||
|
TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME,
|
||||||
TraceObjectBreakpointLocation.class);
|
TraceObjectBreakpointLocation.class);
|
||||||
}
|
}
|
||||||
return delegateRead(address.getAddressSpace(), m -> m.getBreakpointsAt(snap, address),
|
return delegateRead(address.getAddressSpace(), m -> m.getBreakpointsAt(snap, address),
|
||||||
|
@ -154,7 +156,8 @@ public class DBTraceBreakpointManager
|
||||||
AddressRange range) {
|
AddressRange range) {
|
||||||
if (trace.getObjectManager().hasSchema()) {
|
if (trace.getObjectManager().hasSchema()) {
|
||||||
return trace.getObjectManager()
|
return trace.getObjectManager()
|
||||||
.getObjectsIntersecting(span, range, TraceObjectBreakpointLocation.KEY_RANGE,
|
.getObjectsIntersecting(span, range,
|
||||||
|
TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME,
|
||||||
TraceObjectBreakpointLocation.class);
|
TraceObjectBreakpointLocation.class);
|
||||||
}
|
}
|
||||||
return delegateRead(range.getAddressSpace(), m -> m.getBreakpointsIntersecting(span, range),
|
return delegateRead(range.getAddressSpace(), m -> m.getBreakpointsIntersecting(span, range),
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class DBTraceObjectBreakpointLocation
|
||||||
|
|
||||||
protected class BreakpointChangeTranslator extends Translator<TraceBreakpoint> {
|
protected class BreakpointChangeTranslator extends Translator<TraceBreakpoint> {
|
||||||
protected BreakpointChangeTranslator(DBTraceObject object, TraceBreakpoint iface) {
|
protected BreakpointChangeTranslator(DBTraceObject object, TraceBreakpoint iface) {
|
||||||
super(KEY_RANGE, object, iface);
|
super(TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME, object, iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -64,7 +64,7 @@ public class DBTraceObjectBreakpointLocation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean appliesToKey(String key) {
|
protected boolean appliesToKey(String key) {
|
||||||
return KEY_RANGE.equals(key) ||
|
return TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME.equals(key) ||
|
||||||
TargetObject.DISPLAY_ATTRIBUTE_NAME.equals(key) ||
|
TargetObject.DISPLAY_ATTRIBUTE_NAME.equals(key) ||
|
||||||
TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME.equals(key) ||
|
TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME.equals(key) ||
|
||||||
KEY_COMMENT.equals(key);
|
KEY_COMMENT.equals(key);
|
||||||
|
@ -122,7 +122,7 @@ public class DBTraceObjectBreakpointLocation
|
||||||
@Override
|
@Override
|
||||||
public void setRange(Range<Long> lifespan, AddressRange range) {
|
public void setRange(Range<Long> lifespan, AddressRange range) {
|
||||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||||
object.setValue(lifespan, KEY_RANGE, range);
|
object.setValue(lifespan, TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME, range);
|
||||||
this.range = range;
|
this.range = range;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,8 +133,8 @@ public class DBTraceObjectBreakpointLocation
|
||||||
if (object.getLife().isEmpty()) {
|
if (object.getLife().isEmpty()) {
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
return range = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), KEY_RANGE,
|
return range = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||||
AddressRange.class, range);
|
TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME, AddressRange.class, range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ public class DBTraceObjectBreakpointLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
public TraceAddressSpace getTraceAddressSpace() {
|
public TraceAddressSpace getTraceAddressSpace() {
|
||||||
return spaceForValue(computeMinSnap(), KEY_RANGE);
|
return spaceForValue(computeMinSnap(), TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,11 +27,10 @@ import com.google.common.collect.*;
|
||||||
|
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
import db.StringField;
|
import db.StringField;
|
||||||
import ghidra.dbg.target.TargetBreakpointLocation;
|
|
||||||
import ghidra.dbg.target.TargetObject;
|
import ghidra.dbg.target.TargetObject;
|
||||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||||
import ghidra.dbg.util.*;
|
import ghidra.dbg.util.*;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceUtils;
|
import ghidra.trace.database.DBTraceUtils;
|
||||||
import ghidra.trace.database.breakpoint.DBTraceObjectBreakpointLocation;
|
import ghidra.trace.database.breakpoint.DBTraceObjectBreakpointLocation;
|
||||||
|
@ -728,47 +727,6 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
|
||||||
return manager.doCreateValue(lifespan, this, key, value);
|
return manager.doCreateValue(lifespan, this, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: Because breakpoint uses address,length instead of range. FIXME!
|
|
||||||
protected void applyBreakpointRangeHack(Range<Long> lifespan, String key, Object value,
|
|
||||||
ConflictResolution resolution) {
|
|
||||||
/**
|
|
||||||
* NOTE: This should only be happening in Target/TraceBreakpointLocation, but I suppose
|
|
||||||
* anything using this scheme should be hacked.
|
|
||||||
*/
|
|
||||||
Address address;
|
|
||||||
int length;
|
|
||||||
if (key == TargetBreakpointLocation.ADDRESS_ATTRIBUTE_NAME &&
|
|
||||||
value instanceof Address) {
|
|
||||||
address = (Address) value;
|
|
||||||
InternalTraceObjectValue lengthObj = getValue(DBTraceUtils.lowerEndpoint(lifespan),
|
|
||||||
TargetBreakpointLocation.LENGTH_ATTRIBUTE_NAME);
|
|
||||||
if (lengthObj == null || !(lengthObj.getValue() instanceof Integer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
length = (Integer) lengthObj.getValue();
|
|
||||||
}
|
|
||||||
else if (key == TargetBreakpointLocation.LENGTH_ATTRIBUTE_NAME &&
|
|
||||||
value instanceof Integer) {
|
|
||||||
length = (Integer) value;
|
|
||||||
InternalTraceObjectValue addressObj = getValue(DBTraceUtils.lowerEndpoint(lifespan),
|
|
||||||
TargetBreakpointLocation.ADDRESS_ATTRIBUTE_NAME);
|
|
||||||
if (addressObj == null || !(addressObj.getValue() instanceof Address)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
address = (Address) addressObj.getValue();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
setValue(lifespan, TraceObjectBreakpointLocation.KEY_RANGE,
|
|
||||||
new AddressRangeImpl(address, length), resolution);
|
|
||||||
}
|
|
||||||
catch (AddressOverflowException e) {
|
|
||||||
Msg.warn(this, "Could not set range: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InternalTraceObjectValue setValue(Range<Long> lifespan, String key, Object value,
|
public InternalTraceObjectValue setValue(Range<Long> lifespan, String key, Object value,
|
||||||
ConflictResolution resolution) {
|
ConflictResolution resolution) {
|
||||||
|
@ -812,8 +770,6 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
|
||||||
};
|
};
|
||||||
InternalTraceObjectValue result = setter.set(lifespan, value);
|
InternalTraceObjectValue result = setter.set(lifespan, value);
|
||||||
|
|
||||||
// NB. This hack will cause more value events. good.
|
|
||||||
applyBreakpointRangeHack(lifespan, key, value, resolution);
|
|
||||||
DBTraceObject child = setter.canonicalLifeChanged;
|
DBTraceObject child = setter.canonicalLifeChanged;
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
child.emitEvents(
|
child.emitEvents(
|
||||||
|
|
|
@ -31,14 +31,11 @@ import ghidra.util.exception.DuplicateNameException;
|
||||||
shortName = "breakpoint location",
|
shortName = "breakpoint location",
|
||||||
fixedKeys = {
|
fixedKeys = {
|
||||||
TargetObject.DISPLAY_ATTRIBUTE_NAME,
|
TargetObject.DISPLAY_ATTRIBUTE_NAME,
|
||||||
TargetBreakpointLocation.ADDRESS_ATTRIBUTE_NAME,
|
TargetBreakpointLocation.RANGE_ATTRIBUTE_NAME,
|
||||||
TargetBreakpointLocation.LENGTH_ATTRIBUTE_NAME,
|
|
||||||
TraceObjectBreakpointLocation.KEY_COMMENT,
|
TraceObjectBreakpointLocation.KEY_COMMENT,
|
||||||
TraceObjectBreakpointLocation.KEY_RANGE,
|
|
||||||
})
|
})
|
||||||
public interface TraceObjectBreakpointLocation extends TraceBreakpoint, TraceObjectInterface {
|
public interface TraceObjectBreakpointLocation extends TraceBreakpoint, TraceObjectInterface {
|
||||||
String KEY_COMMENT = "_comment";
|
String KEY_COMMENT = "_comment";
|
||||||
String KEY_RANGE = "_range"; // Duplicates address,length
|
|
||||||
|
|
||||||
TraceObjectBreakpointSpec getSpecification();
|
TraceObjectBreakpointSpec getSpecification();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue