mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-14 16:12:14 +00:00
Merge remote-tracking branch 'origin/GP-3436_Dan_moduleMappingColumn'
into patch (#5330)
This commit is contained in:
commit
00894f0ab1
@ -93,6 +93,7 @@ public class DebuggerLegacyModulesPanel extends JPanel {
|
||||
MAX("Max Address", Address.class, ModuleRow::getMaxAddress),
|
||||
SHORT_NAME("Name", String.class, ModuleRow::getShortName),
|
||||
NAME("Module Name", String.class, ModuleRow::getName, ModuleRow::setName),
|
||||
MAPPING("Mapping", String.class, ModuleRow::getMapping),
|
||||
LIFESPAN("Lifespan", Lifespan.class, ModuleRow::getLifespan),
|
||||
LENGTH("Length", Long.class, ModuleRow::getLength);
|
||||
|
||||
@ -144,9 +145,9 @@ public class DebuggerLegacyModulesPanel extends JPanel {
|
||||
extends DebouncedRowWrappedEnumeratedColumnTableModel< //
|
||||
ModuleTableColumns, ObjectKey, ModuleRow, TraceModule> {
|
||||
|
||||
public ModuleTableModel(PluginTool tool) {
|
||||
public ModuleTableModel(PluginTool tool, DebuggerModulesProvider provider) {
|
||||
super(tool, "Modules", ModuleTableColumns.class, TraceModule::getObjectKey,
|
||||
ModuleRow::new, ModuleRow::getModule);
|
||||
mod -> new ModuleRow(provider, mod), ModuleRow::getModule);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -197,7 +198,7 @@ public class DebuggerLegacyModulesPanel extends JPanel {
|
||||
super(new BorderLayout());
|
||||
this.provider = provider;
|
||||
|
||||
moduleTableModel = new ModuleTableModel(provider.getTool());
|
||||
moduleTableModel = new ModuleTableModel(provider.getTool(), provider);
|
||||
moduleTable = new GhidraTable(moduleTableModel);
|
||||
moduleTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
add(new JScrollPane(moduleTable));
|
||||
|
@ -21,8 +21,10 @@ import javax.swing.event.ListSelectionEvent;
|
||||
|
||||
import docking.widgets.table.TableColumnDescriptor;
|
||||
import ghidra.app.plugin.core.debug.gui.model.*;
|
||||
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueAttribute;
|
||||
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
|
||||
import ghidra.app.plugin.core.debug.gui.model.columns.*;
|
||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
|
||||
import ghidra.dbg.target.TargetModule;
|
||||
import ghidra.dbg.target.TargetProcess;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
@ -81,6 +83,31 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModuleMappingColumn extends TraceValueKeyColumn {
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Mapping";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(ValueRow rowObject, Settings settings, Trace data,
|
||||
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||
ValueAttribute<AddressRange> attr =
|
||||
rowObject.getAttribute(TargetModule.RANGE_ATTRIBUTE_NAME, AddressRange.class);
|
||||
if (attr == null) {
|
||||
return "";
|
||||
}
|
||||
AddressRange range = attr.getValue();
|
||||
|
||||
// TODO: Cache this? Would flush on:
|
||||
// 1. Mapping changes
|
||||
// 2. Range/Life changes to this module
|
||||
// 3. Snapshot navigation
|
||||
return DebuggerStaticMappingUtils.computeMappedFiles(data, rowObject.currentSnap(),
|
||||
range);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModulePathColumn extends TraceValueKeyColumn {
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
@ -117,6 +144,7 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
||||
descriptor.addVisibleColumn(new ModuleBaseColumn(), 1, true);
|
||||
descriptor.addVisibleColumn(new ModuleMaxColumn());
|
||||
descriptor.addVisibleColumn(new ModuleNameColumn());
|
||||
descriptor.addVisibleColumn(new ModuleMappingColumn());
|
||||
descriptor.addVisibleColumn(new ModuleLengthColumn());
|
||||
return descriptor;
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||
private final DebuggerModuleMapProposalDialog moduleProposalDialog;
|
||||
private final DebuggerSectionMapProposalDialog sectionProposalDialog;
|
||||
|
||||
private DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
||||
DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
||||
private Program currentProgram;
|
||||
private ProgramLocation currentLocation;
|
||||
|
||||
|
@ -16,14 +16,17 @@
|
||||
package ghidra.app.plugin.core.debug.gui.modules;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
|
||||
public class ModuleRow {
|
||||
private final DebuggerModulesProvider provider;
|
||||
private final TraceModule module;
|
||||
|
||||
public ModuleRow(TraceModule module) {
|
||||
public ModuleRow(DebuggerModulesProvider provider, TraceModule module) {
|
||||
this.provider = provider;
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
@ -54,6 +57,15 @@ public class ModuleRow {
|
||||
return module.getName();
|
||||
}
|
||||
|
||||
public String getMapping() {
|
||||
// TODO: Cache this? Would flush on:
|
||||
// 1. Mapping changes
|
||||
// 2. Range/Life changes to this module
|
||||
// 3. Snapshot navigation
|
||||
return DebuggerStaticMappingUtils.computeMappedFiles(module.getTrace(),
|
||||
provider.current.getSnap(), module.getRange());
|
||||
}
|
||||
|
||||
public Address getBase() {
|
||||
return module.getBase();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package ghidra.app.plugin.core.debug.service.modules;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
|
||||
import ghidra.app.services.MapEntry;
|
||||
@ -238,4 +239,66 @@ public enum DebuggerStaticMappingUtils {
|
||||
}
|
||||
return new AddressRangeImpl(space.getAddress(min), space.getAddress(max));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the final file name from the given URL.
|
||||
*
|
||||
* <p>
|
||||
* This is used when listing the "image" name for mappings, since displaying a full URL would
|
||||
* probably clutter the table. This generally matches the "program name," but in certain cases
|
||||
* may not.
|
||||
*
|
||||
* @param staticProgramURL the URL of the static program image
|
||||
* @return the piece after the final "/"
|
||||
*/
|
||||
public static String getImageName(URL staticProgramURL) {
|
||||
String[] parts = staticProgramURL.toExternalForm().split("/");
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a string suitable for displaying the mapped module names for a given range
|
||||
*
|
||||
* <p>
|
||||
* Ideally, the entire range is covered by a single mapping entry. In that case, the "image
|
||||
* name" (see {@link #getImageName(URL)}) for that one mapping is returned. If a single mapping
|
||||
* is found, but it only partially covers the given range, an asterisk is appended. If no
|
||||
* mappings are found, the empty string is returned. If multiple mappings are found, they are
|
||||
* each listed alphabetically. No asterisk is displayed in the case of multiple images, since
|
||||
* it's implied that none cover the entire range.
|
||||
*
|
||||
* @param trace the trace whose mappings to query
|
||||
* @param snap the relevant snapshot
|
||||
* @param range the address range to consider
|
||||
* @return the names of any mapped images
|
||||
*/
|
||||
public static String computeMappedFiles(Trace trace, long snap, AddressRange range) {
|
||||
List<TraceStaticMapping> mappings = List.copyOf(
|
||||
trace.getStaticMappingManager().findAllOverlapping(range, Lifespan.at(snap)));
|
||||
if (mappings.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
if (mappings.size() == 1) {
|
||||
TraceStaticMapping single = mappings.get(0);
|
||||
AddressRange mappedRange = single.getTraceAddressRange();
|
||||
if (mappedRange.contains(range.getMinAddress()) &&
|
||||
mappedRange.contains(range.getMaxAddress())) {
|
||||
return getImageName(single.getStaticProgramURL());
|
||||
}
|
||||
return getImageName(single.getStaticProgramURL()) + "*";
|
||||
}
|
||||
/**
|
||||
* Its possible multiple mappings to the same image are at play. This would happen if the
|
||||
* user is mapping by sections instead of modules.
|
||||
*/
|
||||
List<String> names = mappings.stream()
|
||||
.map(m -> getImageName(m.getStaticProgramURL()))
|
||||
.sorted()
|
||||
.distinct()
|
||||
.toList();
|
||||
if (names.size() == 1) {
|
||||
return names.get(0) + "*";
|
||||
}
|
||||
return names.stream().collect(Collectors.joining(","));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user