mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Merge remote-tracking branch 'origin/GP-3031_Dan_fixMemorizedModuleMapping'
This commit is contained in:
commit
d8a144eeee
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.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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue