Skip to content

Commit 034bad9

Browse files
committed
Merge remote-tracking branch 'origin/GP-7170_ghidra_red_timeless_byte_search--SQUASHED'
2 parents 95b3286 + 71e6068 commit 034bad9

6 files changed

Lines changed: 556 additions & 11 deletions

File tree

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/* ###
2+
* IP: GHIDRA
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
// Search the entire trace, across all time, for a user-specified byte pattern.
17+
//@category Debugger
18+
19+
import javax.swing.*;
20+
import java.awt.*;
21+
import java.awt.event.MouseAdapter;
22+
import java.awt.event.MouseEvent;
23+
import java.util.ArrayList;
24+
import java.util.List;
25+
26+
import docking.ComponentProvider;
27+
import docking.widgets.table.*;
28+
import ghidra.app.script.GhidraScript;
29+
import ghidra.app.services.DebuggerListingService;
30+
import ghidra.app.services.DebuggerTraceManagerService;
31+
import ghidra.app.services.DebuggerTraceManagerService.ActivationCause;
32+
import ghidra.async.AsyncUtils;
33+
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
34+
import ghidra.framework.plugintool.PluginTool;
35+
import ghidra.program.model.address.*;
36+
import ghidra.trace.model.*;
37+
import ghidra.trace.model.memory.TraceMemoryManager;
38+
39+
public class SearchBytesAcrossTime extends GhidraScript {
40+
public record Row(Address address, long startSnap, long endSnap) {
41+
Row(TraceAddressSnapRange match) {
42+
this(match.getRange().getMinAddress(), match.getLifespan().lmin(),
43+
match.getLifespan().lmax());
44+
}
45+
}
46+
47+
private static class ResultsProvider extends ComponentProvider {
48+
private final JComponent component;
49+
50+
ResultsProvider(PluginTool tool, String title, List<Row> rows) {
51+
super(tool, title, ResultsProvider.class.getSimpleName());
52+
53+
AnyObjectTableModel<Row> model =
54+
new AnyObjectTableModel<>("Matches", Row.class, "startSnap", "endSnap",
55+
"address");
56+
model.setModelData(rows);
57+
GTable table = new GTable(model);
58+
59+
table.addMouseListener(new MouseAdapter() {
60+
@Override
61+
public void mouseClicked(MouseEvent e) {
62+
if (e.getClickCount() != 2) {
63+
return;
64+
}
65+
int viewRow = table.getSelectedRow();
66+
if (viewRow == -1) {
67+
return;
68+
}
69+
int modelRow = table.convertRowIndexToModel(viewRow);
70+
Row row = rows.get(modelRow);
71+
navigateTo(tool, row.startSnap, row.address);
72+
}
73+
});
74+
75+
GTableFilterPanel<Row> filterPanel = new GTableFilterPanel<>(table, model);
76+
77+
final JPanel panel = new JPanel(new BorderLayout());
78+
panel.add(new JScrollPane(table));
79+
panel.add(filterPanel, BorderLayout.SOUTH);
80+
81+
component = panel;
82+
setTransient();
83+
setVisible(true);
84+
}
85+
86+
private void navigateTo(PluginTool tool, long snap, Address address) {
87+
DebuggerTraceManagerService traceManager =
88+
tool.getService(DebuggerTraceManagerService.class);
89+
DebuggerListingService listingService = tool.getService(DebuggerListingService.class);
90+
91+
DebuggerCoordinates coords = traceManager.getCurrent().snap(snap);
92+
93+
traceManager.activateAndNotify(coords, ActivationCause.USER)
94+
.thenRunAsync(() -> listingService.goTo(address, true),
95+
AsyncUtils.SWING_EXECUTOR);
96+
}
97+
98+
@Override
99+
public JComponent getComponent() {
100+
return component;
101+
}
102+
}
103+
104+
@Override
105+
protected void run() throws Exception {
106+
DebuggerTraceManagerService traceManager =
107+
state.getTool().getService(DebuggerTraceManagerService.class);
108+
Trace trace = traceManager.getCurrentTrace();
109+
if (trace == null) {
110+
printerr("No trace is active");
111+
return;
112+
}
113+
114+
byte[] pattern = askBytes("Search Across Time", "Enter byte pattern to search for:");
115+
if (pattern == null || pattern.length == 0) {
116+
printerr("No pattern given");
117+
return;
118+
}
119+
120+
TraceMemoryManager mem = trace.getMemoryManager();
121+
122+
List<Row> rows = new ArrayList<>();
123+
124+
// This searches the default address space, if your architecture uses other address spaces
125+
// this needs to be updated.
126+
AddressRange fullRange = new AddressRangeImpl(toAddr(0L), toAddr(0xFFFF_FFFF_FFFF_FFFFL));
127+
List<TraceAddressSnapRange> bytesAcrossLifespan =
128+
mem.findBytesAcrossLifespan(Lifespan.ALL, fullRange, pattern, monitor);
129+
130+
for (TraceAddressSnapRange traceAddressSnapRange : bytesAcrossLifespan) {
131+
rows.add(new Row(traceAddressSnapRange));
132+
}
133+
134+
println("Found " + rows.size() + " match(es)");
135+
new ResultsProvider(state.getTool(), "Search Across Time Results MEMORY_BLOCKS", rows);
136+
}
137+
}

Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapTree.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ public static TraceAddressSnapRangeQuery intersectingMinWithin(AddressRange rang
516516
new ImmutableTraceAddressSnapRange(space.getMinAddress(), range.getMaxAddress(),
517517
span),
518518
new ImmutableTraceAddressSnapRange(range.getMinAddress(), space.getMaxAddress(),
519-
Lifespan.nowOnMaybeScratch(span.lmax())),
519+
Lifespan.nowOnMaybeScratch(span.lmin())),
520520
null);
521521
}
522522

Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,22 @@ public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(long
268268
Collections.emptyList());
269269
}
270270

271+
@Override
272+
public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(Lifespan span,
273+
AddressRange range) {
274+
return delegateReadOr(range.getAddressSpace(), m -> m.getStates(span, range),
275+
() -> List.of(
276+
Map.entry(new ImmutableTraceAddressSnapRange(range, span),
277+
TraceMemoryState.UNKNOWN)));
278+
}
279+
280+
@Override
281+
public List<TraceAddressSnapRange> findBytesAcrossLifespan(Lifespan span, AddressRange range, byte[] pattern,
282+
TaskMonitor monitor) {
283+
return delegateReadOr(range.getAddressSpace(),
284+
m -> m.findBytesAcrossLifespan(span, range, pattern, monitor), List::of);
285+
}
286+
271287
@Override
272288
public Iterable<Entry<TraceAddressSnapRange, TraceMemoryState>> getMostRecentStates(
273289
TraceAddressSnapRange within) {

0 commit comments

Comments
 (0)