mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-24 00:55:08 +08:00
GP-5102: Fix NPE when TraceModule.getBase() is null during mapping.
This commit is contained in:
+9
-7
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -26,8 +26,7 @@ import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressRangeImpl;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
|
||||
@@ -73,8 +72,7 @@ public class ProgramModuleIndexer implements DomainFolderChangeListener {
|
||||
// TODO: Note language and prefer those from the same processor?
|
||||
// Will get difficult with new OBTR, since I'd need a platform
|
||||
// There's also the WoW64 issue....
|
||||
protected record IndexEntry(String name, String dfID, NameSource source) {
|
||||
}
|
||||
protected record IndexEntry(String name, String dfID, NameSource source) {}
|
||||
|
||||
protected class ModuleChangeListener
|
||||
implements DomainObjectListener, DomainObjectClosedListener {
|
||||
@@ -383,7 +381,11 @@ public class ProgramModuleIndexer implements DomainFolderChangeListener {
|
||||
|
||||
public DomainFile getBestMatch(TraceModule module, Program currentProgram,
|
||||
Collection<IndexEntry> entries) {
|
||||
return getBestMatch(module.getBase().getAddressSpace(), module, currentProgram, entries);
|
||||
Address base = module.getBase();
|
||||
AddressSpace space = base == null
|
||||
? module.getTrace().getBaseAddressFactory().getDefaultAddressSpace()
|
||||
: base.getAddressSpace();
|
||||
return getBestMatch(space, module, currentProgram, entries);
|
||||
}
|
||||
|
||||
public List<IndexEntry> getBestEntries(TraceModule module) {
|
||||
|
||||
+40
-38
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -69,6 +69,43 @@ import ghidra.util.table.GhidraTable;
|
||||
@Category(NightlyCategory.class)
|
||||
public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
|
||||
public static final String CTX_XML = """
|
||||
<context>
|
||||
<schema name='Session' elementResync='NEVER' attributeResync='ONCE'>
|
||||
<attribute name='Processes' schema='ProcessContainer' />
|
||||
</schema>
|
||||
<schema name='ProcessContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element index='1' schema='Process' />
|
||||
</schema>
|
||||
<schema name='Process' elementResync='NEVER' attributeResync='ONCE'>
|
||||
<attribute name='Modules' schema='ModuleContainer' />
|
||||
<attribute name='Memory' schema='RegionContainer' />
|
||||
</schema>
|
||||
<schema name='RegionContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element schema='Region' />
|
||||
</schema>
|
||||
<schema name='Region' elementResync='NEVER' attributeResync='NEVER'>
|
||||
<interface name='MemoryRegion' />
|
||||
</schema>
|
||||
<schema name='ModuleContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element schema='Module' />
|
||||
</schema>
|
||||
<schema name='Module' elementResync='NEVER' attributeResync='NEVER'>
|
||||
<interface name='Module' />
|
||||
<attribute name='Sections' schema='SectionContainer' />
|
||||
</schema>
|
||||
<schema name='SectionContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element schema='Section' />
|
||||
</schema>
|
||||
<schema name='Section' elementResync='NEVER' attributeResync='NEVER'>
|
||||
<interface name='Section' />
|
||||
</schema>
|
||||
</context>""";
|
||||
|
||||
DebuggerModulesProvider provider;
|
||||
|
||||
protected TraceObjectModule modExe;
|
||||
@@ -94,42 +131,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes
|
||||
|
||||
public void activateObjectsMode() throws Exception {
|
||||
// NOTE the use of index='1' allowing object-based managers to ID unique path
|
||||
ctx = XmlSchemaContext.deserialize("""
|
||||
<context>
|
||||
<schema name='Session' elementResync='NEVER' attributeResync='ONCE'>
|
||||
<attribute name='Processes' schema='ProcessContainer' />
|
||||
</schema>
|
||||
<schema name='ProcessContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element index='1' schema='Process' />
|
||||
</schema>
|
||||
<schema name='Process' elementResync='NEVER' attributeResync='ONCE'>
|
||||
<attribute name='Modules' schema='ModuleContainer' />
|
||||
<attribute name='Memory' schema='RegionContainer' />
|
||||
</schema>
|
||||
<schema name='RegionContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element schema='Region' />
|
||||
</schema>
|
||||
<schema name='Region' elementResync='NEVER' attributeResync='NEVER'>
|
||||
<interface name='MemoryRegion' />
|
||||
</schema>
|
||||
<schema name='ModuleContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element schema='Module' />
|
||||
</schema>
|
||||
<schema name='Module' elementResync='NEVER' attributeResync='NEVER'>
|
||||
<interface name='Module' />
|
||||
<attribute name='Sections' schema='SectionContainer' />
|
||||
</schema>
|
||||
<schema name='SectionContainer' canonical='yes' elementResync='NEVER'
|
||||
attributeResync='ONCE'>
|
||||
<element schema='Section' />
|
||||
</schema>
|
||||
<schema name='Section' elementResync='NEVER' attributeResync='NEVER'>
|
||||
<interface name='Section' />
|
||||
</schema>
|
||||
</context>""");
|
||||
ctx = XmlSchemaContext.deserialize(CTX_XML);
|
||||
|
||||
try (Transaction tx = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
|
||||
+25
@@ -25,18 +25,26 @@ import org.junit.Test;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesProviderTest;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||
import ghidra.trace.database.target.DBTraceObject;
|
||||
import ghidra.trace.database.target.DBTraceObjectManager;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.modules.*;
|
||||
import ghidra.trace.model.target.TraceObject.ConflictResolution;
|
||||
import ghidra.trace.model.target.TraceObjectKeyPath;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
// Not technically a GUI test, but must be carried out in the context of a plugin tool
|
||||
@@ -667,4 +675,21 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||
assertMapsTwoWay(Long.MAX_VALUE, Long.MAX_VALUE);
|
||||
assertMapsTwoWay(Long.MIN_VALUE, Long.MIN_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProposeModuleMappingNullBase() throws Throwable {
|
||||
DBTraceObject objModBash;
|
||||
try (Transaction tx = tb.startTransaction()) {
|
||||
SchemaContext ctx = XmlSchemaContext.deserialize(DebuggerModulesProviderTest.CTX_XML);
|
||||
DBTraceObjectManager objects = tb.trace.getObjectManager();
|
||||
objects.createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
objModBash =
|
||||
objects.createObject(TraceObjectKeyPath.parse("Processes[1].Modules[/bin/bash]"));
|
||||
objModBash.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
|
||||
}
|
||||
|
||||
TraceModule modBash = objModBash.queryInterface(TraceObjectModule.class);
|
||||
assertEquals(Map.of(),
|
||||
mappingService.proposeModuleMaps(List.of(modBash), List.of(program)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user