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

This commit is contained in:
Ryan Kurtz 2023-01-27 07:54:56 -05:00
commit d8a144eeee
3 changed files with 103 additions and 88 deletions

View file

@ -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<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 J computeFromJoinKey(F from);
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) {
double bestScore = -1;
MP bestMap = null;
@ -99,10 +114,7 @@ public enum DebuggerStaticMappingProposals {
Map<F, MP> result = new LinkedHashMap<>();
for (F f : froms) {
J joinKey = computeFromJoinKey(f);
Set<T> joined = tos.stream()
.filter(t -> isJoined(joinKey, t))
// Need to preserve order here
.collect(Collectors.toCollection(LinkedHashSet::new));
Collection<T> 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<TraceModule, Program, String, ModuleMapProposal> {
implements ProposalGenerator<TraceModule, Program, ModuleMapProposal> {
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<? 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
protected boolean isJoined(String key, Program to) {
return namesContain(to, key);
public Map<TraceModule, ModuleMapProposal> proposeBestMaps(
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
extends ProposalGenerator<TraceModule, Program, String, SectionMapProposal> {
extends AbstractProposalGenerator<TraceModule, Program, String, SectionMapProposal> {
@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<? 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
ProposalGenerator<Collection<TraceMemoryRegion>, Program, Set<String>, //
AbstractProposalGenerator<Collection<TraceMemoryRegion>, Program, Set<String>, //
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<? extends TraceMemoryRegion> regions,
Program program) {
return REGIONS.proposeMap(Collections.unmodifiableCollection(regions), program);
}
public static RegionMapProposal proposeRegionMap(
Collection<? extends TraceMemoryRegion> regions,
Collection<? extends Program> programs) {
@ -277,11 +265,4 @@ public enum DebuggerStaticMappingProposals {
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);
}
}

View file

@ -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<Program> 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<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeModuleMap(module, orderCurrentFirst(programs));
return moduleMapProposalGenerator.proposeBestMap(module, orderCurrentFirst(programs));
}
@Override
public Map<TraceModule, ModuleMapProposal> proposeModuleMaps(
Collection<? extends TraceModule> modules, Collection<? extends Program> 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<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeSectionMap(module,
return DebuggerStaticMappingProposals.SECTIONS.proposeBestMap(module,
orderCurrentFirst(programs));
}
@Override
public Map<TraceModule, SectionMapProposal> proposeSectionMaps(
Collection<? extends TraceModule> modules, Collection<? extends Program> 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<? extends TraceMemoryRegion> regions,
Program program) {
return DebuggerStaticMappingProposals.proposeRegionMap(regions, program);
return DebuggerStaticMappingProposals.REGIONS
.proposeMap(Collections.unmodifiableCollection(regions), program);
}
@Override
public Map<Collection<TraceMemoryRegion>, RegionMapProposal> proposeRegionMaps(
Collection<? extends TraceMemoryRegion> regions,
Collection<? extends Program> programs) {
return DebuggerStaticMappingProposals.proposeRegionMaps(regions, programs);
Set<Set<TraceMemoryRegion>> groups =
DebuggerStaticMappingProposals.groupRegionsByLikelyModule(regions);
return DebuggerStaticMappingProposals.REGIONS.proposeBestMaps(groups, programs);
}
}

View file

@ -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) {
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<IndexEntry> entries) {
if (entries.isEmpty()) {
return null;
}
Map<DomainFolder, Integer> folderUses = new HashMap<>();
Set<DomainFile> 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<IndexEntry> entries) {
return getBestMatch(module.getBase().getAddressSpace(), module, currentProgram, entries);
}
public List<IndexEntry> getBestEntries(TraceModule module) {
String modulePathName = module.getName().toLowerCase();
List<IndexEntry> 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<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;
}
}