Merge remote-tracking branch 'origin/patch'

Conflicts:
	Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ReadsTargetMemoryPcodeExecutorState.java
This commit is contained in:
Ryan Kurtz 2021-08-31 12:51:51 -04:00
commit 50b48ae63b
13 changed files with 44 additions and 27 deletions

View file

@ -67,6 +67,6 @@ public class VisibleAutoReadMemorySpec implements AutoReadMemorySpec {
return AsyncUtils.NIL; return AsyncUtils.NIL;
} }
return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY); return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY, false);
} }
} }

View file

@ -92,6 +92,6 @@ public class VisibleROOnceAutoReadMemorySpec implements AutoReadMemorySpec {
return AsyncUtils.NIL; return AsyncUtils.NIL;
} }
return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY); return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY, false);
} }
} }

View file

@ -134,8 +134,8 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
Trace trace = current.getTrace(); Trace trace = current.getTrace();
TraceRecorder recorder = current.getRecorder(); TraceRecorder recorder = current.getRecorder();
BackgroundUtils.async(plugin.getTool(), trace, NAME, true, true, false, BackgroundUtils.async(plugin.getTool(), trace, NAME, true, true, false,
(__, monitor) -> recorder (__, monitor) -> recorder.captureProcessMemory(
.captureProcessMemory(getListingPanel().getProgramSelection(), monitor)); getListingPanel().getProgramSelection(), monitor, false));
} }
@Override @Override

View file

@ -76,11 +76,11 @@ public abstract class ImportExportAsAction extends DockingAction {
chooser.setFileSelectionMode(fileMode); chooser.setFileSelectionMode(fileMode);
chooser.setCurrentDirectory(Application.getUserSettingsDirectory()); chooser.setCurrentDirectory(Application.getUserSettingsDirectory());
if (chooser.wasCancelled()) {
return;
}
File f = chooser.getSelectedFile(); File f = chooser.getSelectedFile();
if (chooser.wasCancelled() || f == null) { // Redundant? Meh, it's cheap.
return;
}
doAction(container, f); doAction(container, f);
} }

View file

@ -97,7 +97,7 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
try { try {
// This is on its own task thread, so whatever. // This is on its own task thread, so whatever.
// Just don't hang it indefinitely. // Just don't hang it indefinitely.
recorder.captureProcessMemory(set, TaskMonitor.DUMMY) recorder.captureProcessMemory(set, TaskMonitor.DUMMY, false)
.get(1000, TimeUnit.MILLISECONDS); .get(1000, TimeUnit.MILLISECONDS);
} }
catch (InterruptedException | ExecutionException | TimeoutException e) { catch (InterruptedException | ExecutionException | TimeoutException e) {

View file

@ -68,7 +68,7 @@ public class ReadsTargetMemoryPcodeExecutorState
if (!isLive()) { if (!isLive()) {
return false; return false;
} }
waitTimeout(recorder.captureProcessMemory(unknown, TaskMonitor.DUMMY)); waitTimeout(recorder.captureProcessMemory(unknown, TaskMonitor.DUMMY, false));
return true; return true;
} }

View file

@ -61,11 +61,14 @@ public class DefaultMemoryRecorder implements ManagedMemoryRecorder {
} }
public CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView set, public CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView set,
TaskMonitor monitor) { TaskMonitor monitor, boolean toMap) {
// TODO: Figure out how to display/select per-thread memory. // TODO: Figure out how to display/select per-thread memory.
// Probably need a thread parameter passed in then? // Probably need a thread parameter passed in then?
// NOTE: That thread memory will already be chained to process memory. Good. // NOTE: That thread memory will already be chained to process memory. Good.
// NOTE: I don't intend to warn about the number of requests.
// They're delivered in serial, and there's a cancel button that works
int total = 0; int total = 0;
AddressSetView expSet = expandToBlocks(set) AddressSetView expSet = expandToBlocks(set)
.intersect(trace.getMemoryManager().getRegionsAddressSet(recorder.getSnap())); .intersect(trace.getMemoryManager().getRegionsAddressSet(recorder.getSnap()));
@ -75,22 +78,27 @@ public class DefaultMemoryRecorder implements ManagedMemoryRecorder {
monitor.initialize(total); monitor.initialize(total);
monitor.setMessage("Capturing memory"); monitor.setMessage("Capturing memory");
// TODO: Read blocks in parallel? Probably NO. Tends to overload the agent. // TODO: Read blocks in parallel? Probably NO. Tends to overload the agent.
NavigableMap<Address, byte[]> result = new TreeMap<>(); NavigableMap<Address, byte[]> result = toMap ? new TreeMap<>() : null;
return AsyncUtils.each(TypeSpec.VOID, expSet.iterator(), (r, loop) -> { return AsyncUtils.each(TypeSpec.VOID, expSet.iterator(), (r, loop) -> {
AddressRangeChunker it = new AddressRangeChunker(r, BLOCK_SIZE); AddressRangeChunker blocks = new AddressRangeChunker(r, BLOCK_SIZE);
AsyncUtils.each(TypeSpec.VOID, it.iterator(), (vRng, inner) -> { AsyncUtils.each(TypeSpec.VOID, blocks.iterator(), (vBlk, inner) -> {
// The listener in the recorder will copy to the Trace. // The listener in the recorder will copy to the Trace.
monitor.incrementProgress(1); monitor.incrementProgress(1);
AddressRange tRng = recorder.getMemoryMapper().traceToTarget(vRng); AddressRange tBlk = recorder.getMemoryMapper().traceToTarget(vBlk);
recorder.getProcessMemory() recorder.getProcessMemory()
.readMemory(tRng.getMinAddress(), (int) tRng.getLength()) .readMemory(tBlk.getMinAddress(), (int) tBlk.getLength())
.thenAccept(data -> result.put(tRng.getMinAddress(), data)) .thenAccept(data -> {
.thenApply(__ -> !monitor.isCancelled()) if (toMap) {
.handle(inner::repeatWhile); result.put(tBlk.getMinAddress(), data);
}).exceptionally(e -> { }
Msg.error(this, "Error reading range " + r + ": " + e); })
.exceptionally(e -> {
Msg.error(this, "Error reading block " + tBlk + ": " + e);
// NOTE: Above may double log, since recorder listens for errors, too // NOTE: Above may double log, since recorder listens for errors, too
return null; // Continue looping on errors return null; // Continue looping on errors
})
.thenApply(__ -> !monitor.isCancelled())
.handle(inner::repeatWhile);
}).thenApply(v -> !monitor.isCancelled()).handle(loop::repeatWhile); }).thenApply(v -> !monitor.isCancelled()).handle(loop::repeatWhile);
}).thenApply(__ -> result); }).thenApply(__ -> result);
} }

View file

@ -269,11 +269,11 @@ public class DefaultTraceRecorder implements TraceRecorder {
@Override @Override
public CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView set, public CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView set,
TaskMonitor monitor) { TaskMonitor monitor, boolean toMap) {
if (set.isEmpty()) { if (set.isEmpty()) {
return CompletableFuture.completedFuture(new TreeMap<>()); return CompletableFuture.completedFuture(new TreeMap<>());
} }
return memoryRecorder.captureProcessMemory(set, monitor); return memoryRecorder.captureProcessMemory(set, monitor, toMap);
} }
@Override @Override

View file

@ -321,15 +321,20 @@ public interface TraceRecorder {
* returned future completes. * returned future completes.
* *
* <p> * <p>
* This task is relatively error tolerant. If a region cannot be captured -- a common occurrence * This task is relatively error tolerant. If a block or region cannot be captured -- a common
* -- the error is logged, but the future may still complete successfully. * occurrence -- the error is logged, but the future may still complete successfully. For large
* captures, it is recommended to set {@code toMap} to false. The recorder will place the bytes
* into the trace where they can be retrieved later. For small captures, and where bypassing the
* database may offer some advantage, set {@code toMap} to true, and the captured bytes will be
* returned in an interval map. Connected intervals may or may not be joined.
* *
* @param selection the addresses to capture, as viewed in the trace * @param selection the addresses to capture, as viewed in the trace
* @param monitor a monitor for displaying task steps * @param monitor a monitor for displaying task steps
* @param toMap true to return results in a map, false to complete with null
* @return a future which completes with the capture results * @return a future which completes with the capture results
*/ */
CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView selection, CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView selection,
TaskMonitor monitor); TaskMonitor monitor, boolean toMap);
/** /**
* Capture the data types of a target's module. * Capture the data types of a target's module.

View file

@ -99,7 +99,7 @@ public class TraceRecorderAsyncPcodeExecutorState
Address addr = space.getAddress(truncateOffset(space, offset)); Address addr = space.getAddress(truncateOffset(space, offset));
AddressSet set = new AddressSet(addr, space.getAddress(offset + size - 1)); AddressSet set = new AddressSet(addr, space.getAddress(offset + size - 1));
CompletableFuture<NavigableMap<Address, byte[]>> future = CompletableFuture<NavigableMap<Address, byte[]>> future =
recorder.captureProcessMemory(set, TaskMonitor.DUMMY); recorder.captureProcessMemory(set, TaskMonitor.DUMMY, true);
return future.thenApply(map -> { return future.thenApply(map -> {
return knitFromResults(map, addr, size); return knitFromResults(map, addr, size);
}); });

View file

@ -126,6 +126,9 @@ public class DBTraceStack extends DBAnnotatedObject implements TraceStack {
else { else {
thread = manager.threadManager.getThread(threadSnap.threadKey); thread = manager.threadManager.getThread(threadSnap.threadKey);
frames.clear(); frames.clear();
if (frameKeys == null) {
return;
}
for (long k : frameKeys) { for (long k : frameKeys) {
frames.add(manager.getFrameByKey(k)); frames.add(manager.getFrameByKey(k));
} }

View file

@ -30,5 +30,5 @@
<stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="Framework Utility"/> <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="Framework Utility"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="ghidra.GhidraRun"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="ghidra.GhidraRun"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Framework Utility"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Framework Utility"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:+IgnoreUnrecognizedVMOptions&#13;&#10;-Djava.system.class.loader=ghidra.GhidraClassLoader&#13;&#10;-Xshare:off&#13;&#10;-Dfile.encoding=UTF8&#13;&#10;-Duser.country=US&#13;&#10;-Duser.language=en&#13;&#10;-Dsun.java2d.pmoffscreen=false&#13;&#10;-Dsun.java2d.xrender=true&#13;&#10;-Dsun.java2d.d3d=false&#13;&#10;-Xdock:name=&quot;Ghidra&quot;&#13;&#10;-Dvisualvm.display.name=Ghidra&#13;&#10;-Dpython.console.encoding=UTF-8&#13;&#10;--add-opens java.base/java.lang=ALL-UNNAMED&#13;&#10;--add-opens java.base/java.net=ALL-UNNAMED&#13;&#10;--add-opens java.desktop/sun.awt.image=ALL-UNNAMED&#13;&#10;--add-opens java.base/sun.security.x509=ALL-UNNAMED&#13;&#10;--add-opens java.base/sun.security.util=ALL-UNNAMED&#13;&#10;--add-opens java.desktop/sun.awt.X11=ALL-UNNAMED"/> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:+IgnoreUnrecognizedVMOptions&#13;&#10;-Djava.system.class.loader=ghidra.GhidraClassLoader&#13;&#10;-Xshare:off&#13;&#10;-Dfile.encoding=UTF8&#13;&#10;-Duser.country=US&#13;&#10;-Duser.language=en&#13;&#10;-Dsun.java2d.pmoffscreen=false&#13;&#10;-Dsun.java2d.xrender=true&#13;&#10;-Dsun.java2d.d3d=false&#13;&#10;-Xdock:name=&quot;Ghidra&quot;&#13;&#10;-Dvisualvm.display.name=Ghidra&#13;&#10;-Dpython.console.encoding=UTF-8&#13;&#10;--add-opens java.base/java.lang=ALL-UNNAMED&#13;&#10;--add-opens java.base/java.util=ALL-UNNAMED&#13;&#10;--add-opens java.base/java.net=ALL-UNNAMED&#13;&#10;--add-opens java.desktop/sun.awt.image=ALL-UNNAMED&#13;&#10;--add-opens java.base/sun.security.x509=ALL-UNNAMED&#13;&#10;--add-opens java.base/sun.security.util=ALL-UNNAMED&#13;&#10;--add-opens java.desktop/sun.awt.X11=ALL-UNNAMED"/>
</launchConfiguration> </launchConfiguration>

View file

@ -83,6 +83,7 @@ VMARGS=-Xshare:off
# Permit "illegal reflective accesses" to enable JDK compatibility with Ghidra and 3rd party jars. # Permit "illegal reflective accesses" to enable JDK compatibility with Ghidra and 3rd party jars.
VMARGS=--add-opens java.base/java.lang=ALL-UNNAMED VMARGS=--add-opens java.base/java.lang=ALL-UNNAMED
VMARGS=--add-opens java.base/java.util=ALL-UNNAMED
VMARGS=--add-opens java.base/java.net=ALL-UNNAMED VMARGS=--add-opens java.base/java.net=ALL-UNNAMED
VMARGS=--add-opens java.desktop/sun.awt.image=ALL-UNNAMED VMARGS=--add-opens java.desktop/sun.awt.image=ALL-UNNAMED
VMARGS=--add-opens java.base/sun.security.x509=ALL-UNNAMED VMARGS=--add-opens java.base/sun.security.x509=ALL-UNNAMED