mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch 'origin/GP-1488_Dan_emuLogging--REBASED-2--SQUASHED' into Ghidra_10.1
This commit is contained in:
commit
c5957bf0d8
11 changed files with 94 additions and 48 deletions
|
@ -17,9 +17,6 @@ package ghidra.app.plugin.core.debug.service.emulation;
|
||||||
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
import com.google.common.collect.Range;
|
|
||||||
import com.google.common.primitives.UnsignedLong;
|
|
||||||
|
|
||||||
import ghidra.app.services.TraceRecorder;
|
import ghidra.app.services.TraceRecorder;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.pcode.exec.AccessPcodeExecutionException;
|
import ghidra.pcode.exec.AccessPcodeExecutionException;
|
||||||
|
@ -56,17 +53,19 @@ public abstract class AbstractReadsTargetPcodeExecutorState
|
||||||
@Override
|
@Override
|
||||||
public byte[] read(long offset, int size) {
|
public byte[] read(long offset, int size) {
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
AddressSet uninitialized = new AddressSet();
|
AddressSet uninitialized =
|
||||||
for (Range<UnsignedLong> rng : cache.getUninitialized(offset, offset + size - 1)
|
addrSet(cache.getUninitialized(offset, offset + size - 1));
|
||||||
.asRanges()) {
|
|
||||||
uninitialized.add(space.getAddress(lower(rng)),
|
|
||||||
space.getAddress(upper(rng)));
|
|
||||||
}
|
|
||||||
if (uninitialized.isEmpty()) {
|
if (uninitialized.isEmpty()) {
|
||||||
return super.read(offset, size);
|
return super.read(offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
fillUninitialized(uninitialized);
|
fillUninitialized(uninitialized);
|
||||||
|
|
||||||
|
AddressSet unknown =
|
||||||
|
computeUnknown(addrSet(cache.getUninitialized(offset, offset + size - 1)));
|
||||||
|
if (!unknown.isEmpty()) {
|
||||||
|
warnUnknown(unknown);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: What to flush when bytes in the trace change?
|
// TODO: What to flush when bytes in the trace change?
|
||||||
|
|
|
@ -62,7 +62,6 @@ public class ReadsTargetMemoryPcodeExecutorState
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg.warn(this, "Emulator read from UNKNOWN state: " + unknown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean fillUnknownWithRecorder(AddressSet unknown) {
|
protected boolean fillUnknownWithRecorder(AddressSet unknown) {
|
||||||
|
@ -92,7 +91,7 @@ public class ReadsTargetMemoryPcodeExecutorState
|
||||||
long shift = mappedRng.getShift();
|
long shift = mappedRng.getShift();
|
||||||
for (AddressRange subsrng : initialized.intersectRange(srng.getMinAddress(),
|
for (AddressRange subsrng : initialized.intersectRange(srng.getMinAddress(),
|
||||||
srng.getMaxAddress())) {
|
srng.getMaxAddress())) {
|
||||||
Msg.warn(this,
|
Msg.debug(this,
|
||||||
"Filling in unknown trace memory in emulator using mapped image: " +
|
"Filling in unknown trace memory in emulator using mapped image: " +
|
||||||
program + ": " + subsrng);
|
program + ": " + subsrng);
|
||||||
long lower = subsrng.getMinAddress().getOffset();
|
long lower = subsrng.getMinAddress().getOffset();
|
||||||
|
@ -107,6 +106,7 @@ public class ReadsTargetMemoryPcodeExecutorState
|
||||||
" Partial read of " + subsrng + ". Got " + read +
|
" Partial read of " + subsrng + ". Got " + read +
|
||||||
" bytes");
|
" bytes");
|
||||||
}
|
}
|
||||||
|
// write(lower - shift, data, 0 ,read);
|
||||||
cache.putData(lower - shift, data, 0, read);
|
cache.putData(lower - shift, data, 0, read);
|
||||||
}
|
}
|
||||||
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.pcode.exec.trace;
|
package ghidra.pcode.exec.trace;
|
||||||
|
|
||||||
import com.google.common.collect.Range;
|
|
||||||
import com.google.common.collect.RangeSet;
|
import com.google.common.collect.RangeSet;
|
||||||
import com.google.common.primitives.UnsignedLong;
|
import com.google.common.primitives.UnsignedLong;
|
||||||
|
|
||||||
|
@ -32,20 +31,6 @@ public abstract class AbstractCheckedTraceCachedWriteBytesPcodeExecutorState
|
||||||
super(space, source, snap);
|
super(space, source, snap);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AddressRange addrRng(Range<UnsignedLong> rng) {
|
|
||||||
Address start = space.getAddress(lower(rng));
|
|
||||||
Address end = space.getAddress(upper(rng));
|
|
||||||
return new AddressRangeImpl(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AddressSet addrSet(RangeSet<UnsignedLong> set) {
|
|
||||||
AddressSet result = new AddressSet();
|
|
||||||
for (Range<UnsignedLong> rng : set.asRanges()) {
|
|
||||||
result.add(addrRng(rng));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] read(long offset, int size) {
|
public byte[] read(long offset, int size) {
|
||||||
RangeSet<UnsignedLong> uninitialized =
|
RangeSet<UnsignedLong> uninitialized =
|
||||||
|
|
|
@ -16,8 +16,7 @@
|
||||||
package ghidra.pcode.exec.trace;
|
package ghidra.pcode.exec.trace;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import com.google.common.primitives.UnsignedLong;
|
import com.google.common.primitives.UnsignedLong;
|
||||||
|
@ -27,8 +26,9 @@ import ghidra.pcode.exec.AbstractLongOffsetPcodeExecutorState;
|
||||||
import ghidra.pcode.exec.BytesPcodeArithmetic;
|
import ghidra.pcode.exec.BytesPcodeArithmetic;
|
||||||
import ghidra.pcode.exec.trace.TraceCachedWriteBytesPcodeExecutorState.CachedSpace;
|
import ghidra.pcode.exec.trace.TraceCachedWriteBytesPcodeExecutorState.CachedSpace;
|
||||||
import ghidra.pcode.utils.Utils;
|
import ghidra.pcode.utils.Utils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.program.model.lang.Language;
|
||||||
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
@ -36,6 +36,7 @@ import ghidra.trace.model.memory.TraceMemorySpace;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.trace.util.MemBufferAdapter;
|
import ghidra.trace.util.MemBufferAdapter;
|
||||||
import ghidra.util.MathUtilities;
|
import ghidra.util.MathUtilities;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A state which reads bytes from a trace, but caches writes internally.
|
* A state which reads bytes from a trace, but caches writes internally.
|
||||||
|
@ -109,10 +110,10 @@ public class TraceCachedWriteBytesPcodeExecutorState
|
||||||
this.snap = snap;
|
this.snap = snap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(long offset, byte[] val) {
|
public void write(long offset, byte[] buffer, int srcOffset, int length) {
|
||||||
cache.putData(offset, val);
|
cache.putData(offset, buffer, srcOffset, length);
|
||||||
UnsignedLong uLoc = UnsignedLong.fromLongBits(offset);
|
UnsignedLong uLoc = UnsignedLong.fromLongBits(offset);
|
||||||
UnsignedLong uEnd = UnsignedLong.fromLongBits(offset + val.length);
|
UnsignedLong uEnd = UnsignedLong.fromLongBits(offset + length);
|
||||||
written.add(Range.closedOpen(uLoc, uEnd));
|
written.add(Range.closedOpen(uLoc, uEnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +151,62 @@ public class TraceCachedWriteBytesPcodeExecutorState
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected AddressRange addrRng(Range<UnsignedLong> rng) {
|
||||||
|
Address start = space.getAddress(lower(rng));
|
||||||
|
Address end = space.getAddress(upper(rng));
|
||||||
|
return new AddressRangeImpl(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AddressSet addrSet(RangeSet<UnsignedLong> set) {
|
||||||
|
AddressSet result = new AddressSet();
|
||||||
|
for (Range<UnsignedLong> rng : set.asRanges()) {
|
||||||
|
result.add(addrRng(rng));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Set<Register> getRegs(AddressSet set) {
|
||||||
|
// TODO: Should pass in language instead?
|
||||||
|
Language language = source.getTrace().getBaseLanguage();
|
||||||
|
Set<Register> regs = new TreeSet<>();
|
||||||
|
for (AddressRange rng : set) {
|
||||||
|
Register r = language.getRegister(rng.getMinAddress(), (int) rng.getLength());
|
||||||
|
if (r != null) {
|
||||||
|
regs.add(r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
regs.addAll(Arrays.asList(language.getRegisters(rng.getMinAddress())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return regs;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void warnState(AddressSet set, String message) {
|
||||||
|
Set<Register> regs = getRegs(set);
|
||||||
|
if (regs.isEmpty()) {
|
||||||
|
Msg.warn(this, message + ": " + set);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.warn(this, message + ": " + set + " (registers " + regs + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void warnUninit(RangeSet<UnsignedLong> uninit) {
|
||||||
|
AddressSet uninitialized = addrSet(uninit);
|
||||||
|
Set<Register> regs = getRegs(uninitialized);
|
||||||
|
if (regs.isEmpty()) {
|
||||||
|
Msg.warn(this, "Emulator read from uninitialized state: " + uninit);
|
||||||
|
}
|
||||||
|
Msg.warn(this, "Emulator read from uninitialized state: " + uninit +
|
||||||
|
" (includes registers: " + regs + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void warnUnknown(AddressSet unknown) {
|
||||||
|
Set<Register> regs = getRegs(unknown);
|
||||||
|
Msg.warn(this, "Emulator state initialized from UNKNOWN: " + unknown +
|
||||||
|
"(includes registers: " + regs + ")");
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] read(long offset, int size) {
|
public byte[] read(long offset, int size) {
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
// TODO: Warn or bail when reading UNKNOWN bytes
|
// TODO: Warn or bail when reading UNKNOWN bytes
|
||||||
|
@ -157,6 +214,10 @@ public class TraceCachedWriteBytesPcodeExecutorState
|
||||||
// NOTE: Cannot write those gaps, though!!!
|
// NOTE: Cannot write those gaps, though!!!
|
||||||
readUninitializedFromSource(cache.getUninitialized(offset, offset + size - 1));
|
readUninitializedFromSource(cache.getUninitialized(offset, offset + size - 1));
|
||||||
}
|
}
|
||||||
|
RangeSet<UnsignedLong> stillUninit = cache.getUninitialized(offset, offset + size - 1);
|
||||||
|
if (!stillUninit.isEmpty()) {
|
||||||
|
warnUninit(stillUninit);
|
||||||
|
}
|
||||||
return readCached(offset, size);
|
return readCached(offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +312,7 @@ public class TraceCachedWriteBytesPcodeExecutorState
|
||||||
@Override
|
@Override
|
||||||
protected void setInSpace(CachedSpace space, long offset, int size, byte[] val) {
|
protected void setInSpace(CachedSpace space, long offset, int size, byte[] val) {
|
||||||
assert size == val.length;
|
assert size == val.length;
|
||||||
space.write(offset, val);
|
space.write(offset, val, 0, val.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,7 +19,6 @@ import java.lang.reflect.Field;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
|
@ -15,16 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.program;
|
package ghidra.trace.database.program;
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.database.mem.ByteMappingScheme;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.model.mem.*;
|
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
|
||||||
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
|
|
||||||
|
|
||||||
public class DBTraceProgramViewMemorySpaceBlock extends AbstractDBTraceProgramViewMemoryBlock {
|
public class DBTraceProgramViewMemorySpaceBlock extends AbstractDBTraceProgramViewMemoryBlock {
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ public class DBTraceProgramViewRootModule implements ProgramModule {
|
||||||
try (LockHold hold = LockHold.lock(program.trace.getReadWriteLock().readLock())) {
|
try (LockHold hold = LockHold.lock(program.trace.getReadWriteLock().readLock())) {
|
||||||
program.memory.forVisibleRegions(region -> names.add(region.getName()));
|
program.memory.forVisibleRegions(region -> names.add(region.getName()));
|
||||||
}
|
}
|
||||||
return names.indexOf(names);
|
return names.indexOf(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.program;
|
package ghidra.trace.database.program;
|
||||||
|
|
||||||
import ghidra.framework.model.DomainObject;
|
|
||||||
import ghidra.framework.model.DomainObjectChangeRecord;
|
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.listing.CodeUnit;
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.util.Objects;
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
import ghidra.lifecycle.Internal;
|
import ghidra.lifecycle.Internal;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
|
||||||
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
||||||
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
|
||||||
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
|
||||||
|
|
|
@ -61,6 +61,7 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
||||||
private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
|
private static final byte SOURCE_CLEAR = ~(SOURCE_MASK << SOURCE_SHIFT);
|
||||||
|
|
||||||
private static final byte PRIMARY_MASK = 0x10;
|
private static final byte PRIMARY_MASK = 0x10;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final int PRIMARY_CLEAR = ~PRIMARY_MASK;
|
private static final int PRIMARY_CLEAR = ~PRIMARY_MASK;
|
||||||
|
|
||||||
static final String NAME_COLUMN_NAME = "Name";
|
static final String NAME_COLUMN_NAME = "Name";
|
||||||
|
|
|
@ -87,6 +87,16 @@ public class SemisparseByteArrayTest {
|
||||||
assertEquals(HELLO_WORLD, new String(data));
|
assertEquals(HELLO_WORLD, new String(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBoundaryAtUnsignedMax() {
|
||||||
|
SemisparseByteArray cache = new SemisparseByteArray();
|
||||||
|
|
||||||
|
cache.putData(-HW.length, HW);
|
||||||
|
byte[] data = new byte[HW.length];
|
||||||
|
cache.getData(-HW.length, data);
|
||||||
|
assertEquals(HELLO_WORLD, new String(data));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLarge() {
|
public void testLarge() {
|
||||||
Random rand = new Random();
|
Random rand = new Random();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue