Merge remote-tracking branch 'origin/GP-3031_Dan_fixMemorizedModuleMapping'

This commit is contained in:
Ryan Kurtz
2023-01-27 07:54:56 -05:00
3 changed files with 103 additions and 88 deletions
@@ -22,16 +22,15 @@ import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import ghidra.app.plugin.core.debug.service.modules.ProgramModuleIndexer.IndexEntry;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
import ghidra.graph.*; import ghidra.graph.*;
import ghidra.graph.jung.JungDirectedGraph; import ghidra.graph.jung.JungDirectedGraph;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.modules.TraceModule; import ghidra.trace.model.modules.TraceModule;
import ghidra.trace.model.modules.TraceSection;
import ghidra.util.Msg; import ghidra.util.Msg;
public enum DebuggerStaticMappingProposals { public enum DebuggerStaticMappingProposals {
@@ -72,13 +71,29 @@ public enum DebuggerStaticMappingProposals {
return false; return false;
} }
protected abstract static class ProposalGenerator<F, T, J, MP extends MapProposal<?, ?, ?>> { protected interface ProposalGenerator<F, T, MP extends MapProposal<?, ?, ?>> {
MP proposeMap(F from, T to);
MP proposeBestMap(F from, Collection<? extends T> tos);
Map<F, MP> proposeBestMaps(Collection<? extends F> froms, Collection<? extends T> tos);
}
protected abstract static class AbstractProposalGenerator //
<F, T, J, MP extends MapProposal<?, ?, ?>> {
protected abstract MP proposeMap(F from, T to); protected abstract MP proposeMap(F from, T to);
protected abstract J computeFromJoinKey(F from); protected abstract J computeFromJoinKey(F from);
protected abstract boolean isJoined(J key, T to); protected abstract boolean isJoined(J key, T to);
protected Collection<T> filterJoined(J key, Collection<? extends T> tos) {
return tos.stream()
.filter(t -> isJoined(key, t))
// Need to preserve order here
.collect(Collectors.toCollection(LinkedHashSet::new));
}
protected MP proposeBestMap(F from, Collection<? extends T> tos) { protected MP proposeBestMap(F from, Collection<? extends T> tos) {
double bestScore = -1; double bestScore = -1;
MP bestMap = null; MP bestMap = null;
@@ -99,10 +114,7 @@ public enum DebuggerStaticMappingProposals {
Map<F, MP> result = new LinkedHashMap<>(); Map<F, MP> result = new LinkedHashMap<>();
for (F f : froms) { for (F f : froms) {
J joinKey = computeFromJoinKey(f); J joinKey = computeFromJoinKey(f);
Set<T> joined = tos.stream() Collection<T> joined = filterJoined(joinKey, tos);
.filter(t -> isJoined(joinKey, t))
// Need to preserve order here
.collect(Collectors.toCollection(LinkedHashSet::new));
MP map = proposeBestMap(f, joined); MP map = proposeBestMap(f, joined);
if (map != null) { if (map != null) {
result.put(f, map); result.put(f, map);
@@ -113,41 +125,47 @@ public enum DebuggerStaticMappingProposals {
} }
protected static class ModuleMapProposalGenerator protected static class ModuleMapProposalGenerator
extends ProposalGenerator<TraceModule, Program, String, ModuleMapProposal> { implements ProposalGenerator<TraceModule, Program, ModuleMapProposal> {
private final ProgramModuleIndexer indexer;
public ModuleMapProposalGenerator(ProgramModuleIndexer indexer) {
this.indexer = indexer;
}
@Override @Override
protected ModuleMapProposal proposeMap(TraceModule from, Program to) { public ModuleMapProposal proposeMap(TraceModule from, Program to) {
return new DefaultModuleMapProposal(from, to); return new DefaultModuleMapProposal(from, to);
} }
@Override @Override
protected String computeFromJoinKey(TraceModule from) { public ModuleMapProposal proposeBestMap(TraceModule from,
return getLastLower(from.getName()); Collection<? extends Program> tos) {
Collection<IndexEntry> entries = indexer.filter(indexer.getBestEntries(from), tos);
DomainFile df = indexer.getBestMatch(from, null, entries);
if (df == null) {
return null;
}
try (PeekOpenedDomainObject peek = new PeekOpenedDomainObject(df)) {
return proposeMap(from, (Program) peek.object);
}
} }
@Override @Override
protected boolean isJoined(String key, Program to) { public Map<TraceModule, ModuleMapProposal> proposeBestMaps(
return namesContain(to, key); Collection<? extends TraceModule> froms, Collection<? extends Program> tos) {
Map<TraceModule, ModuleMapProposal> result = new LinkedHashMap<>();
for (TraceModule f : froms) {
ModuleMapProposal map = proposeBestMap(f, tos);
if (map != null) {
result.put(f, map);
}
}
return result;
} }
} }
protected static final ModuleMapProposalGenerator MODULES = new ModuleMapProposalGenerator();
public static ModuleMapProposal proposeModuleMap(TraceModule module, Program program) {
return MODULES.proposeMap(module, program);
}
public static ModuleMapProposal proposeModuleMap(TraceModule module,
Collection<? extends Program> programs) {
return MODULES.proposeBestMap(module, programs);
}
public static Map<TraceModule, ModuleMapProposal> proposeModuleMaps(
Collection<? extends TraceModule> modules, Collection<? extends Program> programs) {
return MODULES.proposeBestMaps(modules, programs);
}
protected static class SectionMapProposalGenerator protected static class SectionMapProposalGenerator
extends ProposalGenerator<TraceModule, Program, String, SectionMapProposal> { extends AbstractProposalGenerator<TraceModule, Program, String, SectionMapProposal> {
@Override @Override
protected SectionMapProposal proposeMap(TraceModule from, Program to) { protected SectionMapProposal proposeMap(TraceModule from, Program to) {
return new DefaultSectionMapProposal(from, to); return new DefaultSectionMapProposal(from, to);
@@ -164,29 +182,8 @@ public enum DebuggerStaticMappingProposals {
} }
} }
protected static final SectionMapProposalGenerator SECTIONS = new SectionMapProposalGenerator();
public static SectionMapProposal proposeSectionMap(TraceSection section, Program program,
MemoryBlock block) {
return new DefaultSectionMapProposal(section, program, block);
}
public static SectionMapProposal proposeSectionMap(TraceModule module, Program program) {
return SECTIONS.proposeMap(module, program);
}
public static SectionMapProposal proposeSectionMap(TraceModule module,
Collection<? extends Program> programs) {
return SECTIONS.proposeBestMap(module, programs);
}
public static Map<TraceModule, SectionMapProposal> proposeSectionMaps(
Collection<? extends TraceModule> modules, Collection<? extends Program> programs) {
return SECTIONS.proposeBestMaps(modules, programs);
}
protected static class RegionMapProposalGenerator extends protected static class RegionMapProposalGenerator extends
ProposalGenerator<Collection<TraceMemoryRegion>, Program, Set<String>, // AbstractProposalGenerator<Collection<TraceMemoryRegion>, Program, Set<String>, //
RegionMapProposal> { RegionMapProposal> {
@Override @Override
@@ -209,19 +206,10 @@ public enum DebuggerStaticMappingProposals {
} }
} }
// TODO: Should these also take advantage of the program-module index?
protected static final SectionMapProposalGenerator SECTIONS = new SectionMapProposalGenerator();
protected static final RegionMapProposalGenerator REGIONS = new RegionMapProposalGenerator(); protected static final RegionMapProposalGenerator REGIONS = new RegionMapProposalGenerator();
public static RegionMapProposal proposeRegionMap(TraceMemoryRegion region, Program program,
MemoryBlock block) {
return new DefaultRegionMapProposal(region, program, block);
}
public static RegionMapProposal proposeRegionMap(
Collection<? extends TraceMemoryRegion> regions,
Program program) {
return REGIONS.proposeMap(Collections.unmodifiableCollection(regions), program);
}
public static RegionMapProposal proposeRegionMap( public static RegionMapProposal proposeRegionMap(
Collection<? extends TraceMemoryRegion> regions, Collection<? extends TraceMemoryRegion> regions,
Collection<? extends Program> programs) { Collection<? extends Program> programs) {
@@ -277,11 +265,4 @@ public enum DebuggerStaticMappingProposals {
return m1.stream().anyMatch(m2::contains); return m1.stream().anyMatch(m2::contains);
}); });
} }
public static Map<Collection<TraceMemoryRegion>, RegionMapProposal> proposeRegionMaps(
Collection<? extends TraceMemoryRegion> regions,
Collection<? extends Program> programs) {
Set<Set<TraceMemoryRegion>> groups = groupRegionsByLikelyModule(regions);
return REGIONS.proposeBestMaps(groups, programs);
}
} }
@@ -29,7 +29,7 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent; import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent;
import ghidra.app.plugin.core.debug.event.TraceOpenedPluginEvent; import ghidra.app.plugin.core.debug.event.TraceOpenedPluginEvent;
import ghidra.app.plugin.core.debug.stack.*; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingProposals.ModuleMapProposalGenerator;
import ghidra.app.plugin.core.debug.utils.*; import ghidra.app.plugin.core.debug.utils.*;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.app.services.ModuleMapProposal.ModuleMapEntry; import ghidra.app.services.ModuleMapProposal.ModuleMapEntry;
@@ -547,11 +547,13 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
private Set<Program> affectedPrograms = new HashSet<>(); private Set<Program> affectedPrograms = new HashSet<>();
private final ProgramModuleIndexer programModuleIndexer; private final ProgramModuleIndexer programModuleIndexer;
private final ModuleMapProposalGenerator moduleMapProposalGenerator;
public DebuggerStaticMappingServicePlugin(PluginTool tool) { public DebuggerStaticMappingServicePlugin(PluginTool tool) {
super(tool); super(tool);
this.autoWiring = AutoService.wireServicesProvidedAndConsumed(this); this.autoWiring = AutoService.wireServicesProvidedAndConsumed(this);
this.programModuleIndexer = new ProgramModuleIndexer(tool); this.programModuleIndexer = new ProgramModuleIndexer(tool);
this.moduleMapProposalGenerator = new ModuleMapProposalGenerator(programModuleIndexer);
changeDebouncer.addListener(this::fireChangeListeners); changeDebouncer.addListener(this::fireChangeListeners);
tool.getProject().getProjectData().addDomainFolderChangeListener(this); tool.getProject().getProjectData().addDomainFolderChangeListener(this);
@@ -1006,63 +1008,65 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
@Override @Override
public ModuleMapProposal proposeModuleMap(TraceModule module, Program program) { public ModuleMapProposal proposeModuleMap(TraceModule module, Program program) {
return DebuggerStaticMappingProposals.proposeModuleMap(module, program); return moduleMapProposalGenerator.proposeMap(module, program);
} }
@Override @Override
public ModuleMapProposal proposeModuleMap(TraceModule module, public ModuleMapProposal proposeModuleMap(TraceModule module,
Collection<? extends Program> programs) { Collection<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeModuleMap(module, orderCurrentFirst(programs)); return moduleMapProposalGenerator.proposeBestMap(module, orderCurrentFirst(programs));
} }
@Override @Override
public Map<TraceModule, ModuleMapProposal> proposeModuleMaps( public Map<TraceModule, ModuleMapProposal> proposeModuleMaps(
Collection<? extends TraceModule> modules, Collection<? extends Program> programs) { Collection<? extends TraceModule> modules, Collection<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeModuleMaps(modules, return moduleMapProposalGenerator.proposeBestMaps(modules, orderCurrentFirst(programs));
orderCurrentFirst(programs));
} }
@Override @Override
public SectionMapProposal proposeSectionMap(TraceSection section, Program program, public SectionMapProposal proposeSectionMap(TraceSection section, Program program,
MemoryBlock block) { MemoryBlock block) {
return DebuggerStaticMappingProposals.proposeSectionMap(section, program, block); return new DefaultSectionMapProposal(section, program, block);
} }
@Override @Override
public SectionMapProposal proposeSectionMap(TraceModule module, Program program) { public SectionMapProposal proposeSectionMap(TraceModule module, Program program) {
return DebuggerStaticMappingProposals.proposeSectionMap(module, program); return DebuggerStaticMappingProposals.SECTIONS.proposeMap(module, program);
} }
@Override @Override
public SectionMapProposal proposeSectionMap(TraceModule module, public SectionMapProposal proposeSectionMap(TraceModule module,
Collection<? extends Program> programs) { Collection<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeSectionMap(module, return DebuggerStaticMappingProposals.SECTIONS.proposeBestMap(module,
orderCurrentFirst(programs)); orderCurrentFirst(programs));
} }
@Override @Override
public Map<TraceModule, SectionMapProposal> proposeSectionMaps( public Map<TraceModule, SectionMapProposal> proposeSectionMaps(
Collection<? extends TraceModule> modules, Collection<? extends Program> programs) { Collection<? extends TraceModule> modules, Collection<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeSectionMaps(modules, return DebuggerStaticMappingProposals.SECTIONS.proposeBestMaps(modules,
orderCurrentFirst(programs)); orderCurrentFirst(programs));
} }
@Override @Override
public RegionMapProposal proposeRegionMap(TraceMemoryRegion region, Program program, public RegionMapProposal proposeRegionMap(TraceMemoryRegion region, Program program,
MemoryBlock block) { MemoryBlock block) {
return DebuggerStaticMappingProposals.proposeRegionMap(region, program, block); return new DefaultRegionMapProposal(region, program, block);
} }
@Override @Override
public RegionMapProposal proposeRegionMap(Collection<? extends TraceMemoryRegion> regions, public RegionMapProposal proposeRegionMap(Collection<? extends TraceMemoryRegion> regions,
Program program) { Program program) {
return DebuggerStaticMappingProposals.proposeRegionMap(regions, program); return DebuggerStaticMappingProposals.REGIONS
.proposeMap(Collections.unmodifiableCollection(regions), program);
} }
@Override @Override
public Map<Collection<TraceMemoryRegion>, RegionMapProposal> proposeRegionMaps( public Map<Collection<TraceMemoryRegion>, RegionMapProposal> proposeRegionMaps(
Collection<? extends TraceMemoryRegion> regions, Collection<? extends TraceMemoryRegion> regions,
Collection<? extends Program> programs) { Collection<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeRegionMaps(regions, programs); Set<Set<TraceMemoryRegion>> groups =
DebuggerStaticMappingProposals.groupRegionsByLikelyModule(regions);
return DebuggerStaticMappingProposals.REGIONS.proposeBestMaps(groups, programs);
} }
} }
@@ -317,7 +317,7 @@ public class ProgramModuleIndexer implements DomainFolderChangeAdapter {
} }
} }
private DomainFile selectBest(List<IndexEntry> entries, Set<DomainFile> libraries, private DomainFile selectBest(Collection<IndexEntry> entries, Set<DomainFile> libraries,
Map<DomainFolder, Integer> folderUses, Program currentProgram) { Map<DomainFolder, Integer> folderUses, Program currentProgram) {
if (currentProgram != null) { if (currentProgram != null) {
DomainFile currentFile = currentProgram.getDomainFile(); DomainFile currentFile = currentProgram.getDomainFile();
@@ -359,7 +359,11 @@ public class ProgramModuleIndexer implements DomainFolderChangeAdapter {
return projectData.getFileByID(entries.stream().max(comparator).get().dfID); return projectData.getFileByID(entries.stream().max(comparator).get().dfID);
} }
public DomainFile getBestMatch(AddressSpace space, TraceModule module, Program currentProgram) { public DomainFile getBestMatch(AddressSpace space, TraceModule module, Program currentProgram,
Collection<IndexEntry> entries) {
if (entries.isEmpty()) {
return null;
}
Map<DomainFolder, Integer> folderUses = new HashMap<>(); Map<DomainFolder, Integer> folderUses = new HashMap<>();
Set<DomainFile> alreadyMapped = module.getTrace() Set<DomainFile> alreadyMapped = module.getTrace()
.getStaticMappingManager() .getStaticMappingManager()
@@ -379,17 +383,43 @@ public class ProgramModuleIndexer implements DomainFolderChangeAdapter {
folderUses.compute(folder, (f, c) -> c == null ? 1 : (c + 1)); folderUses.compute(folder, (f, c) -> c == null ? 1 : (c + 1));
} }
}); });
return selectBest(entries, libraries, folderUses, currentProgram);
}
public DomainFile getBestMatch(TraceModule module, Program currentProgram,
Collection<IndexEntry> entries) {
return getBestMatch(module.getBase().getAddressSpace(), module, currentProgram, entries);
}
public List<IndexEntry> getBestEntries(TraceModule module) {
String modulePathName = module.getName().toLowerCase(); String modulePathName = module.getName().toLowerCase();
List<IndexEntry> entries = new ArrayList<>(index.getByName(modulePathName)); List<IndexEntry> entries = new ArrayList<>(index.getByName(modulePathName));
if (!entries.isEmpty()) { if (!entries.isEmpty()) {
return selectBest(entries, libraries, folderUses, currentProgram); return entries;
} }
String moduleFileName = new File(modulePathName).getName(); String moduleFileName = new File(modulePathName).getName();
entries.addAll(index.getByName(moduleFileName)); entries.addAll(index.getByName(moduleFileName));
if (!entries.isEmpty()) { return entries;
return selectBest(entries, libraries, folderUses, currentProgram); }
public DomainFile getBestMatch(AddressSpace space, TraceModule module, Program currentProgram) {
return getBestMatch(space, module, currentProgram, getBestEntries(module));
}
public Collection<IndexEntry> filter(Collection<IndexEntry> entries,
Collection<? extends Program> programs) {
Collection<IndexEntry> result = new ArrayList<>();
for (IndexEntry e : entries) {
DomainFile df = projectData.getFileByID(e.dfID);
if (df == null) {
continue;
}
try (PeekOpenedDomainObject peek = new PeekOpenedDomainObject(df)) {
if (programs.contains(peek.object)) {
result.add(e);
}
}
} }
return null; return result;
} }
} }