mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch 'origin/GP-1232_Dan_map1to1' into patch
This commit is contained in:
commit
dc8c5f5a47
8 changed files with 161 additions and 13 deletions
|
@ -96,6 +96,13 @@
|
|||
selected modules to Ghidra data types in the trace. These are often the same types that Ghidra
|
||||
imports from the static image, anyway.</P>
|
||||
|
||||
<H3><A name="map_identically"></A>Map Identically</H3>
|
||||
|
||||
<P>This action is available when both a trace and a program are opened. It maps the current
|
||||
trace to the current program using identical addresses. This action ignores the module list. It
|
||||
is a suitable mapping when the current program is loaded in the trace <EM>without
|
||||
relocation</EM>. It is also a fallback worth trying in the absence of a module list.</P>
|
||||
|
||||
<H3><A name="map_modules"></A>Map Modules</H3>
|
||||
|
||||
<P>This action is available from the modules' or sections' pop-up menu. It searches the tool's
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
automation, e.g., the <A href="help/topics/DebuggerBots/DebuggerBots.html#map_modules">Map
|
||||
Modules</A> bot, or by higher-level user actions, e.g., the <A href=
|
||||
"help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html#map_modules">Map Modules</A>
|
||||
action. This under-the-hood static mapping window displays the mappings table, allowing users or
|
||||
developers to diagnose image mapping issues and manually add mappings, regardless of reported
|
||||
modules and/or sections. For most users, there is no reason to access this window.</P>
|
||||
action. This under-the-hood static mapping window displays the mappings table, allowing users
|
||||
or developers to diagnose image mapping issues and manually add mappings, regardless of
|
||||
reported modules and/or sections. For most users, there is no reason to access this window.</P>
|
||||
|
||||
<H2>Table Columns</H2>
|
||||
|
||||
|
|
|
@ -50,10 +50,10 @@
|
|||
|
||||
<H2>Navigating Threads</H2>
|
||||
|
||||
<P>Selecting a thread in the table will navigate to (or "activate" or "focus")
|
||||
that thread. Windows which are sensitive to the current thread will update. Notably, the <A
|
||||
href="help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html">Registers</A> window
|
||||
will display the activated thread's register values. <A href=
|
||||
<P>Selecting a thread in the table will navigate to (or "activate" or "focus") that thread.
|
||||
Windows which are sensitive to the current thread will update. Notably, the <A href=
|
||||
"help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html">Registers</A> window will
|
||||
display the activated thread's register values. <A href=
|
||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Listing</A> windows with
|
||||
configured location tracking will re-compute that location with the thread's context and
|
||||
navigate to it. The thread timeline plots all recorded threads. Threads which are alive will
|
||||
|
@ -77,16 +77,17 @@
|
|||
The state always reflects the present, or latest known, state.</LI>
|
||||
|
||||
<LI>Comment - a user-modifiable comment about the thread.</LI>
|
||||
|
||||
<LI>Plot - a graphical representation of the thread's lifespan. Unlike other column headers, clicking and dragging
|
||||
in this one will navigate through time. To rearrange this column, hold SHIFT while dragging.</LI>
|
||||
|
||||
<LI>Plot - a graphical representation of the thread's lifespan. Unlike other column headers,
|
||||
clicking and dragging in this one will navigate through time. To rearrange this column, hold
|
||||
SHIFT while dragging.</LI>
|
||||
</UL>
|
||||
|
||||
<H2>Navigating Time</H2>
|
||||
|
||||
<P>The user can navigate through time within the current trace by using the caret in the plot
|
||||
column header. There are also actions for "stepping the trace" forward and backward. See the
|
||||
<A href="help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html">Time</A> window for a way to
|
||||
column header. There are also actions for "stepping the trace" forward and backward. See the <A
|
||||
href="help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html">Time</A> window for a way to
|
||||
display and navigate to specific events in the trace's timeline. Note that stepping away from
|
||||
the present will prevent most windows from interacting with the live target. While some
|
||||
components and scripts may interact with the target and record things "into the present," such
|
||||
|
|
|
@ -146,6 +146,7 @@ public interface DebuggerResources {
|
|||
//ResourceManager.loadImage("images/capture-memory.png");
|
||||
|
||||
// TODO: Draw an icon
|
||||
ImageIcon ICON_MAP_IDENTICALLY = ResourceManager.loadImage("images/doubleArrow.png");
|
||||
ImageIcon ICON_MAP_MODULES = ResourceManager.loadImage("images/modules.png");
|
||||
ImageIcon ICON_MAP_SECTIONS = ICON_MAP_MODULES; // TODO
|
||||
ImageIcon ICON_BLOCK = ICON_MAP_SECTIONS; // TODO
|
||||
|
@ -1209,6 +1210,23 @@ public interface DebuggerResources {
|
|||
}
|
||||
}
|
||||
|
||||
interface MapIdenticallyAction {
|
||||
String NAME = "Map Identically";
|
||||
String DESCRIPTION =
|
||||
"Map the current trace to the current program using identical addresses";
|
||||
Icon ICON = ICON_MAP_IDENTICALLY;
|
||||
String GROUP = GROUP_MAPPING;
|
||||
String HELP_ANCHOR = "map_identically";
|
||||
|
||||
static ActionBuilder builder(Plugin owner) {
|
||||
String ownerName = owner.getName();
|
||||
return new ActionBuilder(NAME, ownerName).description(DESCRIPTION)
|
||||
.toolBarIcon(ICON)
|
||||
.toolBarGroup(GROUP)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
interface MapModulesAction {
|
||||
String NAME = "Map Modules";
|
||||
String DESCRIPTION = "Map selected modules to program images";
|
||||
|
|
|
@ -539,6 +539,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
private Program currentProgram;
|
||||
private ProgramLocation currentLocation;
|
||||
|
||||
DockingAction actionMapIdentically;
|
||||
DockingAction actionMapModules;
|
||||
DockingAction actionMapModuleTo;
|
||||
DockingAction actionMapSections;
|
||||
|
@ -747,6 +748,10 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
|
||||
protected void createActions() {
|
||||
actionMapIdentically = MapIdenticallyAction.builder(plugin)
|
||||
.enabledWhen(ctx -> currentProgram != null && currentTrace != null)
|
||||
.onAction(this::activatedMapIdentically)
|
||||
.buildAndInstallLocal(this);
|
||||
actionMapModules = MapModulesAction.builder(plugin)
|
||||
.enabledWhen(this::isContextNonEmpty)
|
||||
.popupWhen(this::isContextNonEmpty)
|
||||
|
@ -822,6 +827,14 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
return sel.stream().map(TraceSection::getModule).distinct().count() == 1;
|
||||
}
|
||||
|
||||
private void activatedMapIdentically(ActionContext ignored) {
|
||||
if (currentProgram == null || currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
staticMappingService.addIdentityMapping(currentTrace, currentProgram,
|
||||
Range.atLeast(traceManager.getCurrentSnap()), true);
|
||||
}
|
||||
|
||||
private void activatedMapModules(ActionContext ignored) {
|
||||
Set<TraceModule> sel = getSelectedModules(myActionContext);
|
||||
if (sel == null || sel.isEmpty()) {
|
||||
|
|
|
@ -980,6 +980,69 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
|||
manager.add(range, fromLifespan, toURL, toAddress.toString(true));
|
||||
}
|
||||
|
||||
static protected AddressRange clippedRange(Trace trace, String spaceName, long min,
|
||||
long max) {
|
||||
AddressSpace space = trace.getBaseAddressFactory().getAddressSpace(spaceName);
|
||||
if (space == null) {
|
||||
return null;
|
||||
}
|
||||
Address spaceMax = space.getMaxAddress();
|
||||
if (Long.compareUnsigned(min, spaceMax.getOffset()) > 0) {
|
||||
return null;
|
||||
}
|
||||
if (Long.compareUnsigned(max, spaceMax.getOffset()) > 0) {
|
||||
return new AddressRangeImpl(space.getAddress(min), spaceMax);
|
||||
}
|
||||
return new AddressRangeImpl(space.getAddress(min), space.getAddress(max));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIdentityMapping(Trace from, Program toProgram, Range<Long> lifespan,
|
||||
boolean truncateExisting) {
|
||||
try (UndoableTransaction tid =
|
||||
UndoableTransaction.start(from, "Add identity mappings", false)) {
|
||||
doAddIdentityMapping(from, toProgram, lifespan, truncateExisting);
|
||||
tid.commit();
|
||||
}
|
||||
}
|
||||
|
||||
protected void doAddIdentityMapping(Trace from, Program toProgram, Range<Long> lifespan,
|
||||
boolean truncateExisting) {
|
||||
Map<String, Address> mins = new HashMap<>();
|
||||
Map<String, Address> maxs = new HashMap<>();
|
||||
for (AddressRange range : toProgram.getMemory().getAddressRanges()) {
|
||||
mins.compute(range.getAddressSpace().getName(), (n, min) -> {
|
||||
Address can = range.getMinAddress();
|
||||
if (min == null || can.compareTo(min) < 0) {
|
||||
return can;
|
||||
}
|
||||
return min;
|
||||
});
|
||||
maxs.compute(range.getAddressSpace().getName(), (n, max) -> {
|
||||
Address can = range.getMaxAddress();
|
||||
if (max == null || can.compareTo(max) > 0) {
|
||||
return can;
|
||||
}
|
||||
return max;
|
||||
});
|
||||
}
|
||||
for (String name : mins.keySet()) {
|
||||
AddressRange range = clippedRange(from, name, mins.get(name).getOffset(),
|
||||
maxs.get(name).getOffset());
|
||||
if (range == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
addMapping(new DefaultTraceLocation(from, null, lifespan, range.getMinAddress()),
|
||||
new ProgramLocation(toProgram, mins.get(name)), range.getLength(),
|
||||
truncateExisting);
|
||||
}
|
||||
catch (TraceConflictedMappingException e) {
|
||||
Msg.error(this, "Could not add identity mapping " + range + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addModuleMapping(TraceModule from, long length, Program toProgram,
|
||||
boolean truncateExisting) throws TraceConflictedMappingException {
|
||||
|
|
|
@ -532,7 +532,6 @@ public interface DebuggerStaticMappingService {
|
|||
* Note if the trace is backed by a Ghidra database, the caller must already have started a
|
||||
* transaction on the relevant domain object.
|
||||
*
|
||||
*
|
||||
* @param from the source trace location, including lifespan
|
||||
* @param to the destination program location
|
||||
* @param length the length of the mapped region, where 0 indicates {@code 1 << 64}.
|
||||
|
@ -543,6 +542,18 @@ public interface DebuggerStaticMappingService {
|
|||
void addMapping(TraceLocation from, ProgramLocation to, long length, boolean truncateExisting)
|
||||
throws TraceConflictedMappingException;
|
||||
|
||||
/**
|
||||
* Add a static mapping from the given trace to the given program, using identical addresses
|
||||
*
|
||||
* @param from the source trace
|
||||
* @param toProgram the destination program
|
||||
* @param lifespan the lifespan of the mapping
|
||||
* @param truncateExisting true to delete or truncate the lifespan of overlapping entries. If
|
||||
* false, overlapping entries are omitted.
|
||||
*/
|
||||
void addIdentityMapping(Trace from, Program toProgram, Range<Long> lifespan,
|
||||
boolean truncateExisting);
|
||||
|
||||
/**
|
||||
* Add a static mapping (relocation) from the given module to the given program
|
||||
*
|
||||
|
|
|
@ -327,6 +327,41 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
assertProviderEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionMapIdentically() throws Exception {
|
||||
assertFalse(modulesProvider.actionMapIdentically.isEnabled());
|
||||
|
||||
createAndOpenTrace();
|
||||
createAndOpenProgramFromTrace();
|
||||
intoProject(tb.trace);
|
||||
intoProject(program);
|
||||
|
||||
// No modules necessary
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(modulesProvider.actionMapIdentically.isEnabled());
|
||||
|
||||
// Need some substance in the program
|
||||
try (UndoableTransaction tid = UndoableTransaction.start(program, "Populate", true)) {
|
||||
addBlock();
|
||||
}
|
||||
waitForDomainObject(program);
|
||||
|
||||
performAction(modulesProvider.actionMapIdentically);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
||||
Collection<? extends TraceStaticMapping> mappings =
|
||||
tb.trace.getStaticMappingManager().getAllEntries();
|
||||
assertEquals(1, mappings.size());
|
||||
|
||||
TraceStaticMapping sm = mappings.iterator().next();
|
||||
assertEquals(Range.atLeast(0L), sm.getLifespan());
|
||||
assertEquals("ram:00400000", sm.getStaticAddress());
|
||||
assertEquals(0x1000, sm.getLength()); // Block is 0x1000 in length
|
||||
assertEquals(tb.addr(0x00400000), sm.getMinTraceAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionMapModules() throws Exception {
|
||||
assertFalse(modulesProvider.actionMapModules.isEnabled());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue