mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch 'origin/Ghidra_10.2'
This commit is contained in:
commit
12854d1316
6 changed files with 104 additions and 19 deletions
|
@ -149,8 +149,8 @@ public class GdbBreakpointInfo {
|
||||||
else {
|
else {
|
||||||
locs = List.of();
|
locs = List.of();
|
||||||
}
|
}
|
||||||
return new GdbBreakpointInfo(number, type, typeName, GdbBreakpointDisp.KEEP, null, null,
|
return new GdbBreakpointInfo(number, type, typeName, GdbBreakpointDisp.KEEP, null, origLoc,
|
||||||
origLoc, origLoc, null, true, 0, locs);
|
null, origLoc, null, true, 0, locs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,11 +18,13 @@ package agent.gdb.model.impl;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import agent.gdb.manager.breakpoint.GdbBreakpointLocation;
|
import agent.gdb.manager.breakpoint.GdbBreakpointLocation;
|
||||||
import agent.gdb.manager.parsing.GdbCValueParser;
|
import agent.gdb.manager.parsing.GdbCValueParser;
|
||||||
import agent.gdb.manager.parsing.GdbParsingUtils.GdbParseError;
|
import agent.gdb.manager.parsing.GdbParsingUtils.GdbParseError;
|
||||||
import generic.Unique;
|
import generic.Unique;
|
||||||
|
import ghidra.async.AsyncUtils;
|
||||||
import ghidra.dbg.agent.DefaultTargetObject;
|
import ghidra.dbg.agent.DefaultTargetObject;
|
||||||
import ghidra.dbg.target.TargetBreakpointLocation;
|
import ghidra.dbg.target.TargetBreakpointLocation;
|
||||||
import ghidra.dbg.target.TargetObject;
|
import ghidra.dbg.target.TargetObject;
|
||||||
|
@ -98,7 +100,7 @@ public class GdbModelTargetBreakpointLocation
|
||||||
int iid = Unique.assertOne(loc.getInferiorIds());
|
int iid = Unique.assertOne(loc.getInferiorIds());
|
||||||
GdbModelTargetInferior inf = impl.session.inferiors.getTargetInferior(iid);
|
GdbModelTargetInferior inf = impl.session.inferiors.getTargetInferior(iid);
|
||||||
String addrSizeExp = String.format("{(long long)&(%s), (long long)sizeof(%s)}", exp, exp);
|
String addrSizeExp = String.format("{(long long)&(%s), (long long)sizeof(%s)}", exp, exp);
|
||||||
return inf.inferior.evaluate(addrSizeExp).thenAccept(result -> {
|
return inf.inferior.evaluate(addrSizeExp).thenApply(result -> {
|
||||||
List<Long> vals;
|
List<Long> vals;
|
||||||
try {
|
try {
|
||||||
vals = GdbCValueParser.parseArray(result).expectLongs();
|
vals = GdbCValueParser.parseArray(result).expectLongs();
|
||||||
|
@ -112,13 +114,29 @@ public class GdbModelTargetBreakpointLocation
|
||||||
|
|
||||||
range = makeRange(impl.space.getAddress(vals.get(0)), vals.get(1).intValue());
|
range = makeRange(impl.space.getAddress(vals.get(0)), vals.get(1).intValue());
|
||||||
doChangeAttributes("Initialized");
|
doChangeAttributes("Initialized");
|
||||||
|
return AsyncUtils.NIL;
|
||||||
}).exceptionally(ex -> {
|
}).exceptionally(ex -> {
|
||||||
Msg.warn(this, "Could not evaluated breakpoint location and/or size: " + ex);
|
CompletableFuture<String> secondTry =
|
||||||
Address addr = impl.space.getAddress(0);
|
inf.inferior.evaluate(String.format("(long long)&(%s)", exp));
|
||||||
range = new AddressRangeImpl(addr, addr);
|
return secondTry.thenAccept(result -> {
|
||||||
doChangeAttributes("Defaulted for eval/parse error");
|
long addr;
|
||||||
return null;
|
try {
|
||||||
});
|
addr = GdbCValueParser.parseValue(result).expectLong();
|
||||||
|
}
|
||||||
|
catch (GdbParseError e) {
|
||||||
|
throw new AssertionError("Unexpected result type: " + result, e);
|
||||||
|
}
|
||||||
|
range = makeRange(impl.space.getAddress(addr), 1);
|
||||||
|
doChangeAttributes("Initialized, but defaulted length=1");
|
||||||
|
}).exceptionally(ex2 -> {
|
||||||
|
Msg.warn(this,
|
||||||
|
"Could not evaluated breakpoint location and/or size: " + ex2);
|
||||||
|
Address addr = impl.space.getAddress(0);
|
||||||
|
range = new AddressRangeImpl(addr, addr);
|
||||||
|
doChangeAttributes("Defaulted for eval/parse error");
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}).thenCompose(Function.identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String computeDisplay() {
|
protected String computeDisplay() {
|
||||||
|
|
|
@ -349,7 +349,7 @@ public class DebuggerCoordinates {
|
||||||
throw new IllegalArgumentException("Cannot change trace");
|
throw new IllegalArgumentException("Cannot change trace");
|
||||||
}
|
}
|
||||||
if (newThread == null) {
|
if (newThread == null) {
|
||||||
newThread = resolveThread(recorder, getTime());
|
newThread = resolveThread(trace, recorder, getTime());
|
||||||
}
|
}
|
||||||
Trace newTrace = trace != null ? trace : newThread.getTrace();
|
Trace newTrace = trace != null ? trace : newThread.getTrace();
|
||||||
TracePlatform newPlatform = platform != null ? platform : resolvePlatform(newTrace);
|
TracePlatform newPlatform = platform != null ? platform : resolvePlatform(newTrace);
|
||||||
|
@ -405,6 +405,13 @@ public class DebuggerCoordinates {
|
||||||
newObject);
|
newObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DebuggerCoordinates frame(Integer newFrame) {
|
||||||
|
if (newFrame == null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return frame(newFrame.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
private DebuggerCoordinates replaceView(TraceProgramView newView) {
|
private DebuggerCoordinates replaceView(TraceProgramView newView) {
|
||||||
return new DebuggerCoordinates(trace, platform, recorder, thread, newView, time, frame,
|
return new DebuggerCoordinates(trace, platform, recorder, thread, newView, time, frame,
|
||||||
object);
|
object);
|
||||||
|
|
|
@ -22,6 +22,8 @@ import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
import docking.DialogComponentProvider;
|
import docking.DialogComponentProvider;
|
||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractSetBreakpointAction;
|
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractSetBreakpointAction;
|
||||||
|
@ -29,6 +31,7 @@ import ghidra.app.services.DebuggerLogicalBreakpointService;
|
||||||
import ghidra.async.AsyncUtils;
|
import ghidra.async.AsyncUtils;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Instruction;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
||||||
|
@ -56,6 +59,22 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
|
||||||
populateComponents();
|
populateComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean validateAddress() {
|
||||||
|
address = program.getAddressFactory().getAddress(fieldAddress.getText());
|
||||||
|
if (address == null) {
|
||||||
|
setStatusText("Invalid address: " + fieldAddress.getText());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Instruction instruction = program.getListing().getInstructionContaining(address);
|
||||||
|
if (instruction != null && !address.equals(instruction.getAddress())) {
|
||||||
|
setStatusText("Warning: breakpoint is offset within an instruction.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clearStatusText();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected void populateComponents() {
|
protected void populateComponents() {
|
||||||
JPanel panel = new JPanel(new PairLayout(5, 5));
|
JPanel panel = new JPanel(new PairLayout(5, 5));
|
||||||
|
|
||||||
|
@ -66,6 +85,29 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
|
||||||
panel.add(labelAddress);
|
panel.add(labelAddress);
|
||||||
panel.add(fieldAddress);
|
panel.add(fieldAddress);
|
||||||
|
|
||||||
|
fieldAddress.setInputVerifier(new InputVerifier() {
|
||||||
|
@Override
|
||||||
|
public boolean verify(JComponent input) {
|
||||||
|
return validateAddress();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fieldAddress.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
validateAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
validateAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
validateAddress();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
JLabel labelLength = new JLabel("Length");
|
JLabel labelLength = new JLabel("Length");
|
||||||
fieldLength = new JTextField();
|
fieldLength = new JTextField();
|
||||||
panel.add(labelLength);
|
panel.add(labelLength);
|
||||||
|
@ -99,7 +141,7 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
|
||||||
ProgramLocation loc, long length, Collection<TraceBreakpointKind> kinds, String name) {
|
ProgramLocation loc, long length, Collection<TraceBreakpointKind> kinds, String name) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.program = loc.getProgram();
|
this.program = loc.getProgram();
|
||||||
this.address = loc.getAddress(); // byte address can be confusing here.
|
this.address = DebuggerLogicalBreakpointService.addressFromLocation(loc);
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.kinds = Set.copyOf(kinds);
|
this.kinds = Set.copyOf(kinds);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -109,7 +151,7 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
|
||||||
this.fieldKinds.setSelectedItem(TraceBreakpointKindSet.encode(kinds));
|
this.fieldKinds.setSelectedItem(TraceBreakpointKindSet.encode(kinds));
|
||||||
this.fieldName.setText("");
|
this.fieldName.setText("");
|
||||||
|
|
||||||
clearStatusText();
|
validateAddress();
|
||||||
|
|
||||||
setTitle(title);
|
setTitle(title);
|
||||||
tool.showDialog(this);
|
tool.showDialog(this);
|
||||||
|
@ -117,9 +159,7 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void okCallback() {
|
protected void okCallback() {
|
||||||
address = program.getAddressFactory().getAddress(fieldAddress.getText());
|
if (!validateAddress()) {
|
||||||
if (address == null) {
|
|
||||||
setStatusText("Invalid address: " + fieldAddress.getText());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1110,7 +1110,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
MappedLogicalBreakpoint lb = new MappedLogicalBreakpoint(staticLocation.getProgram(),
|
MappedLogicalBreakpoint lb = new MappedLogicalBreakpoint(staticLocation.getProgram(),
|
||||||
staticLocation.getAddress(), length, kinds);
|
staticLocation.getByteAddress(), length, kinds);
|
||||||
lb.setTraceAddress(recorder, address);
|
lb.setTraceAddress(recorder, address);
|
||||||
lb.enableForProgramWithName(name);
|
lb.enableForProgramWithName(name);
|
||||||
return lb.enableForTrace(trace);
|
return lb.enableForTrace(trace);
|
||||||
|
|
|
@ -25,7 +25,7 @@ import ghidra.app.services.LogicalBreakpoint.State;
|
||||||
import ghidra.framework.plugintool.ServiceInfo;
|
import ghidra.framework.plugintool.ServiceInfo;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.*;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
||||||
|
@ -158,15 +158,35 @@ public interface DebuggerLogicalBreakpointService {
|
||||||
*/
|
*/
|
||||||
CompletableFuture<Void> changesSettled();
|
CompletableFuture<Void> changesSettled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the address most likely intended by the user for a given location
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Program locations always have addresses at the start of a code unit, no matter how the
|
||||||
|
* location was produced. This attempts to interpret the context a bit deeper to discern the
|
||||||
|
* user's intent. At the moment, it seems reasonable to check if the location includes a code
|
||||||
|
* unit. If so, take its min address, i.e., the location's address. If not, take the location's
|
||||||
|
* byte address.
|
||||||
|
*
|
||||||
|
* @param loc the location
|
||||||
|
* @return the address
|
||||||
|
*/
|
||||||
|
static Address addressFromLocation(ProgramLocation loc) {
|
||||||
|
if (loc instanceof CodeUnitLocation) {
|
||||||
|
return loc.getAddress();
|
||||||
|
}
|
||||||
|
return loc.getByteAddress();
|
||||||
|
}
|
||||||
|
|
||||||
static <T> T programOrTrace(ProgramLocation loc,
|
static <T> T programOrTrace(ProgramLocation loc,
|
||||||
BiFunction<? super Program, ? super Address, ? extends T> progFunc,
|
BiFunction<? super Program, ? super Address, ? extends T> progFunc,
|
||||||
BiFunction<? super Trace, ? super Address, ? extends T> traceFunc) {
|
BiFunction<? super Trace, ? super Address, ? extends T> traceFunc) {
|
||||||
Program progOrView = loc.getProgram();
|
Program progOrView = loc.getProgram();
|
||||||
if (progOrView instanceof TraceProgramView) {
|
if (progOrView instanceof TraceProgramView) {
|
||||||
TraceProgramView view = (TraceProgramView) progOrView;
|
TraceProgramView view = (TraceProgramView) progOrView;
|
||||||
return traceFunc.apply(view.getTrace(), loc.getByteAddress());
|
return traceFunc.apply(view.getTrace(), addressFromLocation(loc));
|
||||||
}
|
}
|
||||||
return progFunc.apply(progOrView, loc.getByteAddress());
|
return progFunc.apply(progOrView, addressFromLocation(loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
default State computeState(Collection<LogicalBreakpoint> col) {
|
default State computeState(Collection<LogicalBreakpoint> col) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue