mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-2581: Allow dynamic listing and memory view to follow the adress of a watch.
This commit is contained in:
parent
dc76aa811e
commit
958afa58cc
60 changed files with 1632 additions and 552 deletions
|
@ -0,0 +1,114 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pcode.exec.trace;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.trace.data.PcodeTraceDataAccess;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
||||
/**
|
||||
* An auxilliary state piece that reports the (trace) address ranges
|
||||
*
|
||||
* <p>
|
||||
* Except for unique spaces, sets are ignored, and gets simply echo back the range of addresses of
|
||||
* the requested read. In unique spaces, the "addresses read" is treated as the value, so that
|
||||
* values transiting unique space can correct have their source address ranges reported. Use this
|
||||
* with {@link AddressesReadPcodeArithmetic} to compute the union of these ranges during Sleigh
|
||||
* expression evaluation. The ranges are translated from the guest platform, if applicable, to the
|
||||
* trace address. In the case of registers, the addresses are also translated to the appropriate
|
||||
* overlay space, if applicable.
|
||||
*/
|
||||
public class AddressesReadTracePcodeExecutorStatePiece
|
||||
extends AbstractLongOffsetPcodeExecutorStatePiece<byte[], AddressSetView, AddressSpace>
|
||||
implements TracePcodeExecutorStatePiece<byte[], AddressSetView> {
|
||||
|
||||
protected final PcodeTraceDataAccess data;
|
||||
private final Map<Long, AddressSetView> unique = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Construct the state piece
|
||||
*
|
||||
* @param data the trace data access shim
|
||||
*/
|
||||
public AddressesReadTracePcodeExecutorStatePiece(PcodeTraceDataAccess data) {
|
||||
super(data.getLanguage(), BytesPcodeArithmetic.forLanguage(data.getLanguage()),
|
||||
AddressesReadPcodeArithmetic.INSTANCE);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemBuffer getConcreteBuffer(Address address, Purpose purpose) {
|
||||
throw new ConcretionError("Cannot make 'addresses read' concrete buffers", purpose);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PcodeTraceDataAccess getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDown(PcodeTraceDataAccess into) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddressSpace getForSpace(AddressSpace space, boolean toWrite) {
|
||||
return space;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setInSpace(AddressSpace space, long offset, int size, AddressSetView val) {
|
||||
if (!space.isUniqueSpace()) {
|
||||
return;
|
||||
}
|
||||
// TODO: size is not considered
|
||||
unique.put(offset, val);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddressSetView getFromSpace(AddressSpace space, long offset, int size,
|
||||
Reason reason) {
|
||||
if (space.isUniqueSpace()) {
|
||||
AddressSetView result = unique.get(offset);
|
||||
if (result == null) {
|
||||
return new AddressSet();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Address start = data.translate(space.getAddress(offset));
|
||||
if (start == null) {
|
||||
return new AddressSet();
|
||||
}
|
||||
try {
|
||||
return new AddressSet(new AddressRangeImpl(start, size));
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
unique.clear();
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ public class DirectBytesTracePcodeExecutorStatePiece
|
|||
*
|
||||
* @param data the trace-data access shim
|
||||
*/
|
||||
protected DirectBytesTracePcodeExecutorStatePiece(PcodeTraceDataAccess data) {
|
||||
public DirectBytesTracePcodeExecutorStatePiece(PcodeTraceDataAccess data) {
|
||||
this(BytesPcodeArithmetic.forLanguage(data.getLanguage()), data);
|
||||
}
|
||||
|
||||
|
@ -138,4 +138,9 @@ public class DirectBytesTracePcodeExecutorStatePiece
|
|||
public void writeDown(PcodeTraceDataAccess into) {
|
||||
// Writes directly, so just ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
unique.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,4 +120,9 @@ public class TraceMemoryStatePcodeExecutorStatePiece extends
|
|||
public MemBuffer getConcreteBuffer(Address address, Purpose purpose) {
|
||||
throw new ConcretionError("Cannot make TraceMemoryState into a concrete buffer", purpose);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
unique.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,11 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
|
|||
this.mm = platform.getTrace().getMemoryManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceTimeViewport getViewport() {
|
||||
return viewport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Language getLanguage() {
|
||||
return platform.getLanguage();
|
||||
|
@ -186,6 +191,15 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
|
|||
return ops.getViewBytes(snap, toOverlay(hostStart), buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address translate(Address address) {
|
||||
Address host = platform.mapGuestToHost(address);
|
||||
if (host == null) {
|
||||
return null;
|
||||
}
|
||||
return toOverlay(host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> PcodeTracePropertyAccess<T> getPropertyAccess(String name, Class<T> type) {
|
||||
return new DefaultPcodeTracePropertyAccess<>(this, name, type);
|
||||
|
|
|
@ -46,12 +46,12 @@ public class DefaultPcodeTraceAccess extends AbstractPcodeTraceAccess //
|
|||
}
|
||||
|
||||
@Override
|
||||
public DefaultPcodeTraceMemoryAccess newDataForSharedState() {
|
||||
protected DefaultPcodeTraceMemoryAccess newDataForSharedState() {
|
||||
return new DefaultPcodeTraceMemoryAccess(platform, snap, viewport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultPcodeTraceRegistersAccess newDataForLocalState(TraceThread thread, int frame) {
|
||||
protected DefaultPcodeTraceRegistersAccess newDataForLocalState(TraceThread thread, int frame) {
|
||||
return new DefaultPcodeTraceRegistersAccess(platform, snap, thread, frame, viewport);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,6 +101,14 @@ public class DefaultPcodeTraceThreadAccess
|
|||
return memory.getBytes(start, buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address translate(Address address) {
|
||||
if (address.isRegisterAddress()) {
|
||||
return registers.translate(address);
|
||||
}
|
||||
return memory.translate(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> PcodeTracePropertyAccess<T> getPropertyAccess(String name, Class<T> type) {
|
||||
throw new UnsupportedOperationException("This is meant for p-code executor use");
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.pcode.exec.trace.data;
|
||||
|
||||
import ghidra.lifecycle.Internal;
|
||||
import ghidra.trace.model.TraceTimeViewport;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.property.TracePropertyMapOperations;
|
||||
|
||||
|
@ -27,4 +28,6 @@ public interface InternalPcodeTraceDataAccess extends PcodeTraceDataAccess {
|
|||
|
||||
<T> TracePropertyMapOperations<T> getPropertyOps(String name, Class<T> type,
|
||||
boolean createIfAbsent);
|
||||
|
||||
TraceTimeViewport getViewport();
|
||||
}
|
||||
|
|
|
@ -106,6 +106,18 @@ public interface PcodeTraceAccess {
|
|||
*/
|
||||
PcodeTraceRegistersAccess getDataForLocalState(TraceThread thread, int frame);
|
||||
|
||||
/**
|
||||
* Construct a new trace thread data-access shim
|
||||
*
|
||||
* @param shared the shared (memory) state
|
||||
* @param local the local (register) state
|
||||
* @return the thread data-access shim
|
||||
*/
|
||||
default PcodeTraceDataAccess newPcodeTraceThreadAccess(PcodeTraceMemoryAccess shared,
|
||||
PcodeTraceRegistersAccess local) {
|
||||
return new DefaultPcodeTraceThreadAccess(shared, local);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data-access shim for use in an executor having thread context
|
||||
*
|
||||
|
@ -123,7 +135,7 @@ public interface PcodeTraceAccess {
|
|||
if (thread == null) {
|
||||
return getDataForSharedState();
|
||||
}
|
||||
return new DefaultPcodeTraceThreadAccess(getDataForSharedState(),
|
||||
return newPcodeTraceThreadAccess(getDataForSharedState(),
|
||||
getDataForLocalState(thread, frame));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,14 @@ public interface PcodeTraceDataAccess {
|
|||
*/
|
||||
int getBytes(Address start, ByteBuffer buf);
|
||||
|
||||
/**
|
||||
* Translate the given emulator address to a host/overlay address
|
||||
*
|
||||
* @param address the emulator address
|
||||
* @return the host/overlay address
|
||||
*/
|
||||
Address translate(Address address);
|
||||
|
||||
/**
|
||||
* Get a property-access shim for the named property
|
||||
*
|
||||
|
|
|
@ -291,6 +291,7 @@ public class DBTraceTimeViewport implements TraceTimeViewport {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Range<Long>> getOrderedSpans() {
|
||||
try (LockHold hold = trace.lockRead()) {
|
||||
synchronized (ordered) {
|
||||
|
|
|
@ -173,6 +173,9 @@ public interface TraceTimeViewport {
|
|||
<T> AddressSet computeVisibleParts(AddressSetView set, Range<Long> lifespan, T object,
|
||||
Occlusion<T> occlusion);
|
||||
|
||||
|
||||
List<Range<Long>> getOrderedSpans();
|
||||
|
||||
/**
|
||||
* Get the snaps involved in the view in most-recent-first order
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue