mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 12:00:04 +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
|
selected modules to Ghidra data types in the trace. These are often the same types that Ghidra
|
||||||
imports from the static image, anyway.</P>
|
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>
|
<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
|
<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
|
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=
|
Modules</A> bot, or by higher-level user actions, e.g., the <A href=
|
||||||
"help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html#map_modules">Map Modules</A>
|
"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
|
action. This under-the-hood static mapping window displays the mappings table, allowing users
|
||||||
developers to diagnose image mapping issues and manually add mappings, regardless of reported
|
or developers to diagnose image mapping issues and manually add mappings, regardless of
|
||||||
modules and/or sections. For most users, there is no reason to access this window.</P>
|
reported modules and/or sections. For most users, there is no reason to access this window.</P>
|
||||||
|
|
||||||
<H2>Table Columns</H2>
|
<H2>Table Columns</H2>
|
||||||
|
|
||||||
|
|
|
@ -50,10 +50,10 @@
|
||||||
|
|
||||||
<H2>Navigating Threads</H2>
|
<H2>Navigating Threads</H2>
|
||||||
|
|
||||||
<P>Selecting a thread in the table will navigate to (or "activate" or "focus")
|
<P>Selecting a thread in the table will navigate to (or "activate" or "focus") that thread.
|
||||||
that thread. Windows which are sensitive to the current thread will update. Notably, the <A
|
Windows which are sensitive to the current thread will update. Notably, the <A href=
|
||||||
href="help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html">Registers</A> window
|
"help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html">Registers</A> window will
|
||||||
will display the activated thread's register values. <A href=
|
display the activated thread's register values. <A href=
|
||||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Listing</A> windows with
|
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Listing</A> windows with
|
||||||
configured location tracking will re-compute that location with the thread's context and
|
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
|
navigate to it. The thread timeline plots all recorded threads. Threads which are alive will
|
||||||
|
@ -78,15 +78,16 @@
|
||||||
|
|
||||||
<LI>Comment - a user-modifiable comment about the thread.</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
|
<LI>Plot - a graphical representation of the thread's lifespan. Unlike other column headers,
|
||||||
in this one will navigate through time. To rearrange this column, hold SHIFT while dragging.</LI>
|
clicking and dragging in this one will navigate through time. To rearrange this column, hold
|
||||||
|
SHIFT while dragging.</LI>
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
<H2>Navigating Time</H2>
|
<H2>Navigating Time</H2>
|
||||||
|
|
||||||
<P>The user can navigate through time within the current trace by using the caret in the plot
|
<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
|
column header. There are also actions for "stepping the trace" forward and backward. See the <A
|
||||||
<A href="help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html">Time</A> window for a way to
|
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
|
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
|
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
|
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");
|
//ResourceManager.loadImage("images/capture-memory.png");
|
||||||
|
|
||||||
// TODO: Draw an icon
|
// 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_MODULES = ResourceManager.loadImage("images/modules.png");
|
||||||
ImageIcon ICON_MAP_SECTIONS = ICON_MAP_MODULES; // TODO
|
ImageIcon ICON_MAP_SECTIONS = ICON_MAP_MODULES; // TODO
|
||||||
ImageIcon ICON_BLOCK = ICON_MAP_SECTIONS; // 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 {
|
interface MapModulesAction {
|
||||||
String NAME = "Map Modules";
|
String NAME = "Map Modules";
|
||||||
String DESCRIPTION = "Map selected modules to program images";
|
String DESCRIPTION = "Map selected modules to program images";
|
||||||
|
|
|
@ -539,6 +539,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
private Program currentProgram;
|
private Program currentProgram;
|
||||||
private ProgramLocation currentLocation;
|
private ProgramLocation currentLocation;
|
||||||
|
|
||||||
|
DockingAction actionMapIdentically;
|
||||||
DockingAction actionMapModules;
|
DockingAction actionMapModules;
|
||||||
DockingAction actionMapModuleTo;
|
DockingAction actionMapModuleTo;
|
||||||
DockingAction actionMapSections;
|
DockingAction actionMapSections;
|
||||||
|
@ -747,6 +748,10 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createActions() {
|
protected void createActions() {
|
||||||
|
actionMapIdentically = MapIdenticallyAction.builder(plugin)
|
||||||
|
.enabledWhen(ctx -> currentProgram != null && currentTrace != null)
|
||||||
|
.onAction(this::activatedMapIdentically)
|
||||||
|
.buildAndInstallLocal(this);
|
||||||
actionMapModules = MapModulesAction.builder(plugin)
|
actionMapModules = MapModulesAction.builder(plugin)
|
||||||
.enabledWhen(this::isContextNonEmpty)
|
.enabledWhen(this::isContextNonEmpty)
|
||||||
.popupWhen(this::isContextNonEmpty)
|
.popupWhen(this::isContextNonEmpty)
|
||||||
|
@ -822,6 +827,14 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
return sel.stream().map(TraceSection::getModule).distinct().count() == 1;
|
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) {
|
private void activatedMapModules(ActionContext ignored) {
|
||||||
Set<TraceModule> sel = getSelectedModules(myActionContext);
|
Set<TraceModule> sel = getSelectedModules(myActionContext);
|
||||||
if (sel == null || sel.isEmpty()) {
|
if (sel == null || sel.isEmpty()) {
|
||||||
|
|
|
@ -980,6 +980,69 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
||||||
manager.add(range, fromLifespan, toURL, toAddress.toString(true));
|
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
|
@Override
|
||||||
public void addModuleMapping(TraceModule from, long length, Program toProgram,
|
public void addModuleMapping(TraceModule from, long length, Program toProgram,
|
||||||
boolean truncateExisting) throws TraceConflictedMappingException {
|
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
|
* Note if the trace is backed by a Ghidra database, the caller must already have started a
|
||||||
* transaction on the relevant domain object.
|
* transaction on the relevant domain object.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @param from the source trace location, including lifespan
|
* @param from the source trace location, including lifespan
|
||||||
* @param to the destination program location
|
* @param to the destination program location
|
||||||
* @param length the length of the mapped region, where 0 indicates {@code 1 << 64}.
|
* @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)
|
void addMapping(TraceLocation from, ProgramLocation to, long length, boolean truncateExisting)
|
||||||
throws TraceConflictedMappingException;
|
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
|
* Add a static mapping (relocation) from the given module to the given program
|
||||||
*
|
*
|
||||||
|
|
|
@ -327,6 +327,41 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||||
assertProviderEmpty();
|
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
|
@Test
|
||||||
public void testActionMapModules() throws Exception {
|
public void testActionMapModules() throws Exception {
|
||||||
assertFalse(modulesProvider.actionMapModules.isEnabled());
|
assertFalse(modulesProvider.actionMapModules.isEnabled());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue