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 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 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();
TraceRecorder recorder = current.getRecorder();
BackgroundUtils.async(plugin.getTool(), trace, NAME, true, true, false,
(__, monitor) -> recorder
.captureProcessMemory(getListingPanel().getProgramSelection(), monitor));
(__, monitor) -> recorder.captureProcessMemory(
getListingPanel().getProgramSelection(), monitor, false));
}
@Override

View file

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

View file

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

View file

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

View file

@ -61,11 +61,14 @@ public class DefaultMemoryRecorder implements ManagedMemoryRecorder {
}
public CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView set,
TaskMonitor monitor) {
TaskMonitor monitor, boolean toMap) {
// TODO: Figure out how to display/select per-thread memory.
// Probably need a thread parameter passed in then?
// 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;
AddressSetView expSet = expandToBlocks(set)
.intersect(trace.getMemoryManager().getRegionsAddressSet(recorder.getSnap()));
@ -75,22 +78,27 @@ public class DefaultMemoryRecorder implements ManagedMemoryRecorder {
monitor.initialize(total);
monitor.setMessage("Capturing memory");
// 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) -> {
AddressRangeChunker it = new AddressRangeChunker(r, BLOCK_SIZE);
AsyncUtils.each(TypeSpec.VOID, it.iterator(), (vRng, inner) -> {
AddressRangeChunker blocks = new AddressRangeChunker(r, BLOCK_SIZE);
AsyncUtils.each(TypeSpec.VOID, blocks.iterator(), (vBlk, inner) -> {
// The listener in the recorder will copy to the Trace.
monitor.incrementProgress(1);
AddressRange tRng = recorder.getMemoryMapper().traceToTarget(vRng);
AddressRange tBlk = recorder.getMemoryMapper().traceToTarget(vBlk);
recorder.getProcessMemory()
.readMemory(tRng.getMinAddress(), (int) tRng.getLength())
.thenAccept(data -> result.put(tRng.getMinAddress(), data))
.thenApply(__ -> !monitor.isCancelled())
.handle(inner::repeatWhile);
}).exceptionally(e -> {
Msg.error(this, "Error reading range " + r + ": " + e);
.readMemory(tBlk.getMinAddress(), (int) tBlk.getLength())
.thenAccept(data -> {
if (toMap) {
result.put(tBlk.getMinAddress(), data);
}
})
.exceptionally(e -> {
Msg.error(this, "Error reading block " + tBlk + ": " + e);
// NOTE: Above may double log, since recorder listens for errors, too
return null; // Continue looping on errors
})
.thenApply(__ -> !monitor.isCancelled())
.handle(inner::repeatWhile);
}).thenApply(v -> !monitor.isCancelled()).handle(loop::repeatWhile);
}).thenApply(__ -> result);
}

View file

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

View file

@ -321,15 +321,20 @@ public interface TraceRecorder {
* returned future completes.
*
* <p>
* This task is relatively error tolerant. If a region cannot be captured -- a common occurrence
* -- the error is logged, but the future may still complete successfully.
* This task is relatively error tolerant. If a block or region cannot be captured -- a common
* 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 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
*/
CompletableFuture<NavigableMap<Address, byte[]>> captureProcessMemory(AddressSetView selection,
TaskMonitor monitor);
TaskMonitor monitor, boolean toMap);
/**
* 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));
AddressSet set = new AddressSet(addr, space.getAddress(offset + size - 1));
CompletableFuture<NavigableMap<Address, byte[]>> future =
recorder.captureProcessMemory(set, TaskMonitor.DUMMY);
recorder.captureProcessMemory(set, TaskMonitor.DUMMY, true);
return future.thenApply(map -> {
return knitFromResults(map, addr, size);
});

View file

@ -126,6 +126,9 @@ public class DBTraceStack extends DBAnnotatedObject implements TraceStack {
else {
thread = manager.threadManager.getThread(threadSnap.threadKey);
frames.clear();
if (frameKeys == null) {
return;
}
for (long k : frameKeys) {
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.PROGRAM_ARGUMENTS" value="ghidra.GhidraRun"/>
<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>

View file

@ -83,6 +83,7 @@ VMARGS=-Xshare:off
# 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.util=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.base/sun.security.x509=ALL-UNNAMED