diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java index fb9a3ded64..ea80f4e9c8 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java @@ -22,16 +22,15 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import ghidra.app.plugin.core.debug.service.modules.ProgramModuleIndexer.IndexEntry; import ghidra.app.services.*; import ghidra.dbg.util.PathUtils; import ghidra.framework.model.DomainFile; import ghidra.graph.*; import ghidra.graph.jung.JungDirectedGraph; import ghidra.program.model.listing.Program; -import ghidra.program.model.mem.MemoryBlock; import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.modules.TraceModule; -import ghidra.trace.model.modules.TraceSection; import ghidra.util.Msg; public enum DebuggerStaticMappingProposals { @@ -72,13 +71,29 @@ public enum DebuggerStaticMappingProposals { return false; } - protected abstract static class ProposalGenerator> { + protected interface ProposalGenerator> { + MP proposeMap(F from, T to); + + MP proposeBestMap(F from, Collection tos); + + Map proposeBestMaps(Collection froms, Collection tos); + } + + protected abstract static class AbstractProposalGenerator // + > { protected abstract MP proposeMap(F from, T to); protected abstract J computeFromJoinKey(F from); protected abstract boolean isJoined(J key, T to); + protected Collection filterJoined(J key, Collection 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 tos) { double bestScore = -1; MP bestMap = null; @@ -99,10 +114,7 @@ public enum DebuggerStaticMappingProposals { Map result = new LinkedHashMap<>(); for (F f : froms) { J joinKey = computeFromJoinKey(f); - Set joined = tos.stream() - .filter(t -> isJoined(joinKey, t)) - // Need to preserve order here - .collect(Collectors.toCollection(LinkedHashSet::new)); + Collection joined = filterJoined(joinKey, tos); MP map = proposeBestMap(f, joined); if (map != null) { result.put(f, map); @@ -113,41 +125,47 @@ public enum DebuggerStaticMappingProposals { } protected static class ModuleMapProposalGenerator - extends ProposalGenerator { + implements ProposalGenerator { + private final ProgramModuleIndexer indexer; + + public ModuleMapProposalGenerator(ProgramModuleIndexer indexer) { + this.indexer = indexer; + } + @Override - protected ModuleMapProposal proposeMap(TraceModule from, Program to) { + public ModuleMapProposal proposeMap(TraceModule from, Program to) { return new DefaultModuleMapProposal(from, to); } @Override - protected String computeFromJoinKey(TraceModule from) { - return getLastLower(from.getName()); + public ModuleMapProposal proposeBestMap(TraceModule from, + Collection tos) { + Collection 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 - protected boolean isJoined(String key, Program to) { - return namesContain(to, key); + public Map proposeBestMaps( + Collection froms, Collection tos) { + Map 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 programs) { - return MODULES.proposeBestMap(module, programs); - } - - public static Map proposeModuleMaps( - Collection modules, Collection programs) { - return MODULES.proposeBestMaps(modules, programs); - } - protected static class SectionMapProposalGenerator - extends ProposalGenerator { + extends AbstractProposalGenerator { @Override protected SectionMapProposal proposeMap(TraceModule from, Program 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 programs) { - return SECTIONS.proposeBestMap(module, programs); - } - - public static Map proposeSectionMaps( - Collection modules, Collection programs) { - return SECTIONS.proposeBestMaps(modules, programs); - } - protected static class RegionMapProposalGenerator extends - ProposalGenerator, Program, Set, // + AbstractProposalGenerator, Program, Set, // RegionMapProposal> { @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(); - public static RegionMapProposal proposeRegionMap(TraceMemoryRegion region, Program program, - MemoryBlock block) { - return new DefaultRegionMapProposal(region, program, block); - } - - public static RegionMapProposal proposeRegionMap( - Collection regions, - Program program) { - return REGIONS.proposeMap(Collections.unmodifiableCollection(regions), program); - } - public static RegionMapProposal proposeRegionMap( Collection regions, Collection programs) { @@ -277,11 +265,4 @@ public enum DebuggerStaticMappingProposals { return m1.stream().anyMatch(m2::contains); }); } - - public static Map, RegionMapProposal> proposeRegionMaps( - Collection regions, - Collection programs) { - Set> groups = groupRegionsByLikelyModule(regions); - return REGIONS.proposeBestMaps(groups, programs); - } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java index ec4efc591e..b979ad996f 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java @@ -29,7 +29,7 @@ import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent; 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.services.*; import ghidra.app.services.ModuleMapProposal.ModuleMapEntry; @@ -547,11 +547,13 @@ public class DebuggerStaticMappingServicePlugin extends Plugin private Set affectedPrograms = new HashSet<>(); private final ProgramModuleIndexer programModuleIndexer; + private final ModuleMapProposalGenerator moduleMapProposalGenerator; public DebuggerStaticMappingServicePlugin(PluginTool tool) { super(tool); this.autoWiring = AutoService.wireServicesProvidedAndConsumed(this); this.programModuleIndexer = new ProgramModuleIndexer(tool); + this.moduleMapProposalGenerator = new ModuleMapProposalGenerator(programModuleIndexer); changeDebouncer.addListener(this::fireChangeListeners); tool.getProject().getProjectData().addDomainFolderChangeListener(this); @@ -1006,63 +1008,65 @@ public class DebuggerStaticMappingServicePlugin extends Plugin @Override public ModuleMapProposal proposeModuleMap(TraceModule module, Program program) { - return DebuggerStaticMappingProposals.proposeModuleMap(module, program); + return moduleMapProposalGenerator.proposeMap(module, program); } @Override public ModuleMapProposal proposeModuleMap(TraceModule module, Collection programs) { - return DebuggerStaticMappingProposals.proposeModuleMap(module, orderCurrentFirst(programs)); + return moduleMapProposalGenerator.proposeBestMap(module, orderCurrentFirst(programs)); } @Override public Map proposeModuleMaps( Collection modules, Collection programs) { - return DebuggerStaticMappingProposals.proposeModuleMaps(modules, - orderCurrentFirst(programs)); + return moduleMapProposalGenerator.proposeBestMaps(modules, orderCurrentFirst(programs)); } @Override public SectionMapProposal proposeSectionMap(TraceSection section, Program program, MemoryBlock block) { - return DebuggerStaticMappingProposals.proposeSectionMap(section, program, block); + return new DefaultSectionMapProposal(section, program, block); } @Override public SectionMapProposal proposeSectionMap(TraceModule module, Program program) { - return DebuggerStaticMappingProposals.proposeSectionMap(module, program); + return DebuggerStaticMappingProposals.SECTIONS.proposeMap(module, program); } @Override public SectionMapProposal proposeSectionMap(TraceModule module, Collection programs) { - return DebuggerStaticMappingProposals.proposeSectionMap(module, + return DebuggerStaticMappingProposals.SECTIONS.proposeBestMap(module, orderCurrentFirst(programs)); } @Override public Map proposeSectionMaps( Collection modules, Collection programs) { - return DebuggerStaticMappingProposals.proposeSectionMaps(modules, + return DebuggerStaticMappingProposals.SECTIONS.proposeBestMaps(modules, orderCurrentFirst(programs)); } @Override public RegionMapProposal proposeRegionMap(TraceMemoryRegion region, Program program, MemoryBlock block) { - return DebuggerStaticMappingProposals.proposeRegionMap(region, program, block); + return new DefaultRegionMapProposal(region, program, block); } @Override public RegionMapProposal proposeRegionMap(Collection regions, Program program) { - return DebuggerStaticMappingProposals.proposeRegionMap(regions, program); + return DebuggerStaticMappingProposals.REGIONS + .proposeMap(Collections.unmodifiableCollection(regions), program); } @Override public Map, RegionMapProposal> proposeRegionMaps( Collection regions, Collection programs) { - return DebuggerStaticMappingProposals.proposeRegionMaps(regions, programs); + Set> groups = + DebuggerStaticMappingProposals.groupRegionsByLikelyModule(regions); + return DebuggerStaticMappingProposals.REGIONS.proposeBestMaps(groups, programs); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java index 15f59ee71a..d1996c38b8 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java @@ -317,7 +317,7 @@ public class ProgramModuleIndexer implements DomainFolderChangeAdapter { } } - private DomainFile selectBest(List entries, Set libraries, + private DomainFile selectBest(Collection entries, Set libraries, Map folderUses, Program currentProgram) { if (currentProgram != null) { DomainFile currentFile = currentProgram.getDomainFile(); @@ -359,7 +359,11 @@ public class ProgramModuleIndexer implements DomainFolderChangeAdapter { 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 entries) { + if (entries.isEmpty()) { + return null; + } Map folderUses = new HashMap<>(); Set alreadyMapped = module.getTrace() .getStaticMappingManager() @@ -379,17 +383,43 @@ public class ProgramModuleIndexer implements DomainFolderChangeAdapter { folderUses.compute(folder, (f, c) -> c == null ? 1 : (c + 1)); } }); + return selectBest(entries, libraries, folderUses, currentProgram); + } + public DomainFile getBestMatch(TraceModule module, Program currentProgram, + Collection entries) { + return getBestMatch(module.getBase().getAddressSpace(), module, currentProgram, entries); + } + + public List getBestEntries(TraceModule module) { String modulePathName = module.getName().toLowerCase(); List entries = new ArrayList<>(index.getByName(modulePathName)); if (!entries.isEmpty()) { - return selectBest(entries, libraries, folderUses, currentProgram); + return entries; } String moduleFileName = new File(modulePathName).getName(); entries.addAll(index.getByName(moduleFileName)); - if (!entries.isEmpty()) { - return selectBest(entries, libraries, folderUses, currentProgram); + return entries; + } + + public DomainFile getBestMatch(AddressSpace space, TraceModule module, Program currentProgram) { + return getBestMatch(space, module, currentProgram, getBestEntries(module)); + } + + public Collection filter(Collection entries, + Collection programs) { + Collection 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; } }