mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
16388dc261
11 changed files with 502 additions and 427 deletions
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.model.*;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.AddressRangeImpl;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.trace.model.modules.TraceModule;
|
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?
|
// TODO: Note language and prefer those from the same processor?
|
||||||
// Will get difficult with new OBTR, since I'd need a platform
|
// Will get difficult with new OBTR, since I'd need a platform
|
||||||
// There's also the WoW64 issue....
|
// 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
|
protected class ModuleChangeListener
|
||||||
implements DomainObjectListener, DomainObjectClosedListener {
|
implements DomainObjectListener, DomainObjectClosedListener {
|
||||||
|
@ -383,7 +381,11 @@ public class ProgramModuleIndexer implements DomainFolderChangeListener {
|
||||||
|
|
||||||
public DomainFile getBestMatch(TraceModule module, Program currentProgram,
|
public DomainFile getBestMatch(TraceModule module, Program currentProgram,
|
||||||
Collection<IndexEntry> entries) {
|
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) {
|
public List<IndexEntry> getBestEntries(TraceModule module) {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -69,6 +69,43 @@ import ghidra.util.table.GhidraTable;
|
||||||
@Category(NightlyCategory.class)
|
@Category(NightlyCategory.class)
|
||||||
public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
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;
|
DebuggerModulesProvider provider;
|
||||||
|
|
||||||
protected TraceObjectModule modExe;
|
protected TraceObjectModule modExe;
|
||||||
|
@ -94,42 +131,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes
|
||||||
|
|
||||||
public void activateObjectsMode() throws Exception {
|
public void activateObjectsMode() throws Exception {
|
||||||
// NOTE the use of index='1' allowing object-based managers to ID unique path
|
// NOTE the use of index='1' allowing object-based managers to ID unique path
|
||||||
ctx = XmlSchemaContext.deserialize("""
|
ctx = XmlSchemaContext.deserialize(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>""");
|
|
||||||
|
|
||||||
try (Transaction tx = tb.startTransaction()) {
|
try (Transaction tx = tb.startTransaction()) {
|
||||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||||
|
|
|
@ -25,18 +25,26 @@ import org.junit.Test;
|
||||||
|
|
||||||
import db.Transaction;
|
import db.Transaction;
|
||||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
|
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;
|
||||||
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
|
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.framework.model.DomainFile;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||||
import ghidra.trace.database.memory.DBTraceMemoryManager;
|
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.*;
|
||||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||||
import ghidra.trace.model.modules.*;
|
import ghidra.trace.model.modules.*;
|
||||||
|
import ghidra.trace.model.target.TraceObject.ConflictResolution;
|
||||||
|
import ghidra.trace.model.target.TraceObjectKeyPath;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
// Not technically a GUI test, but must be carried out in the context of a plugin tool
|
// 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.MAX_VALUE, Long.MAX_VALUE);
|
||||||
assertMapsTwoWay(Long.MIN_VALUE, Long.MIN_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)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -31,12 +31,9 @@ import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils;
|
import ghidra.app.util.cparser.C.CParserUtils;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
|
||||||
import ghidra.app.util.cparser.C.ParseException;
|
import ghidra.app.util.cparser.C.ParseException;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.data.FileDataTypeManager;
|
import ghidra.program.model.data.FileDataTypeManager;
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
||||||
|
|
||||||
|
@ -69,16 +66,12 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
||||||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||||
|
|
||||||
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
|
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
|
||||||
|
|
||||||
File f = getArchiveFile(dataTypeFile);
|
|
||||||
|
|
||||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
|
|
||||||
|
|
||||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
|
|
||||||
|
|
||||||
Msg.info(this, results.getFormattedParseMessage(null));
|
|
||||||
|
|
||||||
dtMgr.save();
|
File f = getArchiveFile(dataTypeFile);
|
||||||
|
|
||||||
|
FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames,
|
||||||
|
includePaths, args, f.getAbsolutePath(), languageID, compiler, monitor);
|
||||||
|
|
||||||
dtMgr.close();
|
dtMgr.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -31,11 +31,9 @@ import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils;
|
import ghidra.app.util.cparser.C.CParserUtils;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
|
||||||
import ghidra.app.util.cparser.C.ParseException;
|
import ghidra.app.util.cparser.C.ParseException;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.data.FileDataTypeManager;
|
import ghidra.program.model.data.FileDataTypeManager;
|
||||||
import ghidra.util.Msg;
|
|
||||||
|
|
||||||
public class CreateExampleGDTArchiveScript extends GhidraScript {
|
public class CreateExampleGDTArchiveScript extends GhidraScript {
|
||||||
|
|
||||||
|
@ -69,13 +67,9 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
||||||
|
|
||||||
File f = getArchiveFile(dataTypeFile);
|
File f = getArchiveFile(dataTypeFile);
|
||||||
|
|
||||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
|
FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames,
|
||||||
|
includePaths, args, f.getAbsolutePath(), languageID, compiler, monitor);
|
||||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
|
|
||||||
|
|
||||||
Msg.info(this, results.getFormattedParseMessage(null));
|
|
||||||
|
|
||||||
dtMgr.save();
|
|
||||||
dtMgr.close();
|
dtMgr.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,18 +16,14 @@
|
||||||
package ghidra.app.plugin.core.cparser;
|
package ghidra.app.plugin.core.cparser;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.dialogs.MultiLineMessageDialog;
|
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.ProgramPlugin;
|
import ghidra.app.plugin.ProgramPlugin;
|
||||||
|
@ -40,7 +36,8 @@ import ghidra.framework.plugintool.PluginInfo;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.BuiltInDataTypeManager;
|
||||||
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.lang.LanguageCompilerSpecPair;
|
import ghidra.program.model.lang.LanguageCompilerSpecPair;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
@ -168,9 +165,9 @@ public class CParserPlugin extends ProgramPlugin {
|
||||||
/*
|
/*
|
||||||
* Parse C-source into a data type manager
|
* Parse C-source into a data type manager
|
||||||
*/
|
*/
|
||||||
protected void parse(String[] filenames, String includePaths[], String options,
|
protected CParseResults parse(String[] filenames, String includePaths[], String options,
|
||||||
String languageIDString, String compilerSpecID, DataTypeManager dtMgr,
|
DataTypeManager dtMgr, TaskMonitor monitor)
|
||||||
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
throws ghidra.app.util.cparser.C.ParseException,
|
||||||
ghidra.app.util.cparser.CPP.ParseException {
|
ghidra.app.util.cparser.CPP.ParseException {
|
||||||
|
|
||||||
results = null;
|
results = null;
|
||||||
|
@ -181,43 +178,26 @@ public class CParserPlugin extends ProgramPlugin {
|
||||||
try {
|
try {
|
||||||
openDTmanagers = getOpenDTMgrs();
|
openDTmanagers = getOpenDTMgrs();
|
||||||
} catch (CancelledException exc) {
|
} catch (CancelledException exc) {
|
||||||
return; // parse canceled
|
return null; // parse canceled
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
|
||||||
results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
|
args, dtMgr, monitor);
|
||||||
args, dtMgr, languageIDString, compilerSpecID, monitor);
|
|
||||||
|
return results;
|
||||||
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager);
|
}
|
||||||
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
boolean isOpenInTool(DataTypeManager dtm) {
|
||||||
// CParserTask will show any errors
|
DataTypeManagerService dtService = tool.getService(DataTypeManagerService.class);
|
||||||
if (!results.successful()) {
|
if (dtService == null) {
|
||||||
return;
|
return false;
|
||||||
}
|
|
||||||
if (isProgramDtMgr) {
|
|
||||||
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
|
|
||||||
"C-Parse of Header Files Complete",
|
|
||||||
"Successfully parsed header file(s) to Program.",
|
|
||||||
getFormattedParseMessage("Check the Manage Data Types window for added data types."),
|
|
||||||
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String archiveName = dtMgr.getName();
|
|
||||||
if (dtMgr instanceof FileDataTypeManager) {
|
|
||||||
archiveName = ((FileDataTypeManager) dtMgr).getFilename();
|
|
||||||
}
|
|
||||||
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
|
|
||||||
"C-Parse of Header Files Complete",
|
|
||||||
"Successfully parsed header file(s) to Archive File: " + archiveName,
|
|
||||||
getFormattedParseMessage(null),
|
|
||||||
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
for (DataTypeManager openDtm : dtService.getDataTypeManagers()) {
|
||||||
// ignore
|
if (dtm == openDtm) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -327,11 +307,9 @@ public class CParserPlugin extends ProgramPlugin {
|
||||||
|
|
||||||
CParserTask parseTask =
|
CParserTask parseTask =
|
||||||
new CParserTask(this, currentProgram.getDataTypeManager())
|
new CParserTask(this, currentProgram.getDataTypeManager())
|
||||||
.setFileNames(filenames)
|
.setFileNames(filenames)
|
||||||
.setIncludePaths(includePaths)
|
.setIncludePaths(includePaths)
|
||||||
.setOptions(options)
|
.setOptions(options);
|
||||||
.setLanguageID(procID)
|
|
||||||
.setCompilerID(compilerID);
|
|
||||||
|
|
||||||
tool.execute(parseTask);
|
tool.execute(parseTask);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,11 +16,16 @@
|
||||||
package ghidra.app.plugin.core.cparser;
|
package ghidra.app.plugin.core.cparser;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.help.UnsupportedOperationException;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import docking.widgets.dialogs.MultiLineMessageDialog;
|
import docking.widgets.dialogs.MultiLineMessageDialog;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||||
|
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||||
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
|
import ghidra.program.model.data.FileDataTypeManager;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.DuplicateFileException;
|
import ghidra.util.exception.DuplicateFileException;
|
||||||
import ghidra.util.task.Task;
|
import ghidra.util.task.Task;
|
||||||
|
@ -34,18 +39,19 @@ import ghidra.util.task.TaskMonitor;
|
||||||
class CParserTask extends Task {
|
class CParserTask extends Task {
|
||||||
|
|
||||||
private CParserPlugin plugin;
|
private CParserPlugin plugin;
|
||||||
private String dataFileName;
|
|
||||||
|
|
||||||
private String[] filenames;
|
private String[] filenames;
|
||||||
private String[] includePaths;
|
private String[] includePaths;
|
||||||
|
|
||||||
private String options;
|
private String options;
|
||||||
|
|
||||||
private String languageString;
|
// Language and Compiler Spec IDs valid only for new dataFileName use
|
||||||
private String compilerString;
|
private String languageId;
|
||||||
|
private String compilerSpecId;
|
||||||
|
|
||||||
private DataTypeManager dtMgr;
|
// Either dataTypeManager or dataFileName must be set, but not both
|
||||||
|
private final DataTypeManager dataTypeManager; // specified for an existing DataTypeManager
|
||||||
|
private final File dataFile; // specified for a new file
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create task to parse to a dataFile
|
* Create task to parse to a dataFile
|
||||||
|
@ -55,44 +61,64 @@ class CParserTask extends Task {
|
||||||
*/
|
*/
|
||||||
CParserTask(CParserPlugin plugin, String dataFileName) {
|
CParserTask(CParserPlugin plugin, String dataFileName) {
|
||||||
super("Parsing C Files", true, false, false);
|
super("Parsing C Files", true, false, false);
|
||||||
|
dataTypeManager = null;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.dataFileName = dataFileName;
|
this.dataFile = new File(dataFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create task to parse to a dataTypeManager
|
* Create task to parse to a dataTypeManager
|
||||||
*
|
*
|
||||||
* @param plugin
|
* NOTE: The Language ID and Compiler Spec ID must not be set since the dataTypeManager's
|
||||||
* @param dataTypeManager
|
* current architecture will be used.
|
||||||
|
*
|
||||||
|
* @param plugin CParserPlugin that will do the work
|
||||||
|
* @param dataTypeManager target data type manager
|
||||||
*/
|
*/
|
||||||
public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
|
public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
|
||||||
super("Parsing C Files", true, false, false);
|
super("Parsing C Files", true, false, false);
|
||||||
|
dataFile = null;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.dtMgr = dataTypeManager;
|
this.dataTypeManager = dataTypeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create task to parse to a ProgramDataTypeManager
|
* Set the language ID to be used.
|
||||||
*
|
*
|
||||||
* @param plugin
|
* NOTE: The compiler spec ID must also be set, see {@code #setCompilerID(String)}.
|
||||||
* @param dataTypeManager
|
* See language *.ldefs file for defined compiler spec IDs or existing Program info.
|
||||||
|
*
|
||||||
|
* @param languageId language ID
|
||||||
|
* @return this task
|
||||||
|
* @throws UnsupportedOperationException if task was constructed with a DataTypeManager whose
|
||||||
|
* existing architecture will be used.
|
||||||
*/
|
*/
|
||||||
public CParserTask(CParserPlugin plugin, ProgramBasedDataTypeManager dataTypeManager) {
|
public CParserTask setLanguageID(String languageId) {
|
||||||
super("Parsing C Files", true, false, false);
|
if (dataTypeManager != null) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
this.plugin = plugin;
|
"setLanguageID not supported when constructed with DataTypeManager");
|
||||||
this.dtMgr = dataTypeManager;
|
}
|
||||||
}
|
this.languageId = languageId;
|
||||||
|
|
||||||
public CParserTask setLanguageID(String languageID) {
|
|
||||||
this.languageString = languageID;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CParserTask setCompilerID(String compilerID) {
|
/**
|
||||||
this.compilerString = compilerID;
|
* Set the compiler spec ID to be used. This ID must be defined for the specified language.
|
||||||
|
*
|
||||||
|
* NOTE: The language ID must also be set, see {@code #setLanguageID(String)}.
|
||||||
|
* See language *.ldefs file for defined compiler spec IDs or existing Program info.
|
||||||
|
*
|
||||||
|
* @param compilerSpecId compiler spec ID
|
||||||
|
* @return this task
|
||||||
|
* @throws UnsupportedOperationException if task was constructed with a DataTypeManager whose
|
||||||
|
* existing architecture will be used.
|
||||||
|
*/
|
||||||
|
public CParserTask setCompilerID(String compilerSpecId) {
|
||||||
|
if (dataTypeManager != null) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"setLanguageID not supported when constructed with DataTypeManager");
|
||||||
|
}
|
||||||
|
this.compilerSpecId = compilerSpecId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,96 +146,142 @@ class CParserTask extends Task {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getResultMessage(DataTypeManager dtMgr, int initialDtCount) {
|
||||||
|
|
||||||
|
int finalDtCount = dtMgr.getDataTypeCount(true) - initialDtCount;
|
||||||
|
|
||||||
|
String msg = (finalDtCount == 0 ? "No" : Integer.toString(finalDtCount)) +
|
||||||
|
" Data Types added.";
|
||||||
|
if (finalDtCount != 0 && plugin.isOpenInTool(dtMgr)) {
|
||||||
|
msg += "\nCheck the Data Type Manager window for added data types.";
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getParseDestination(DataTypeManager dtMgr) {
|
||||||
|
String parseDest = "";
|
||||||
|
if (dtMgr instanceof ProgramDataTypeManager) {
|
||||||
|
parseDest = "Program " + dtMgr.getName();
|
||||||
|
}
|
||||||
|
else if (dtMgr instanceof FileDataTypeManager fileDtm) {
|
||||||
|
parseDest = "Archive File: " + fileDtm.getFilename();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parseDest = dtMgr.getName();
|
||||||
|
}
|
||||||
|
return parseDest;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(TaskMonitor monitor) {
|
public void run(TaskMonitor monitor) {
|
||||||
DataTypeManager fileDtMgr = null;
|
|
||||||
try {
|
|
||||||
if (dtMgr == null) {
|
|
||||||
File file = new File(dataFileName);
|
|
||||||
dtMgr = FileDataTypeManager.createFileArchive(file);
|
|
||||||
fileDtMgr = dtMgr;
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.parse(filenames, includePaths, options, languageString, compilerString, dtMgr, monitor);
|
FileDataTypeManager fileDtMgr = null;
|
||||||
if (dataFileName != null) {
|
if (dataFile != null) {
|
||||||
// TODO: does not consider existing datatypes
|
try {
|
||||||
if (dtMgr.getDataTypeCount(true) != 0) {
|
if ((languageId != null) != (compilerSpecId != null)) {
|
||||||
try {
|
Msg.showError(this, plugin.getDialog().getComponent(), "Archive Failure",
|
||||||
((FileDataTypeManager) dtMgr).save();
|
"Language/CompilerSpec improperly specified: " + languageId + "/" +
|
||||||
dtMgr.close();
|
compilerSpecId);
|
||||||
}
|
return;
|
||||||
catch (DuplicateFileException e) {
|
|
||||||
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save",
|
|
||||||
e.getMessage());
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save",
|
|
||||||
"Could not save to file " + dataFileName, e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (dtMgr instanceof FileDataTypeManager) {
|
|
||||||
dtMgr.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// no results, was canceled
|
|
||||||
if (plugin.getParseResults() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MultiLineMessageDialog.showModalMessageDialog(
|
|
||||||
plugin.getDialog().getComponent(), "Parse Errors",
|
|
||||||
"File was not created due to parse errors: " +
|
|
||||||
((FileDataTypeManager) dtMgr).getFilename(),
|
|
||||||
plugin.getFormattedParseMessage(null),
|
|
||||||
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
fileDtMgr =
|
||||||
|
FileDataTypeManager.createFileArchive(dataFile, languageId, compilerSpecId);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Msg.showError(this, plugin.getDialog().getComponent(), "Archive Failure",
|
||||||
|
"Failed to create archive datatype manager: " + e.getMessage());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ghidra.app.util.cparser.C.ParseException e) {
|
|
||||||
final String errMsg = e.getMessage();
|
DataTypeManager dtMgr = fileDtMgr != null ? fileDtMgr : dataTypeManager;
|
||||||
System.err.println(errMsg);
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
int initialDtCount = dtMgr.getDataTypeCount(true);
|
||||||
@Override
|
|
||||||
public void run() {
|
try {
|
||||||
String msg = getFirstMessageLine(errMsg);
|
|
||||||
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
|
CParseResults results = plugin.parse(filenames, includePaths, options, dtMgr, monitor);
|
||||||
"Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
|
if (results == null) {
|
||||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
return; // cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileDtMgr != null && dtMgr.getDataTypeCount(true) != 0) {
|
||||||
|
// If archive created - save to file
|
||||||
|
try {
|
||||||
|
fileDtMgr.save();
|
||||||
}
|
}
|
||||||
|
catch (DuplicateFileException e) {
|
||||||
|
Msg.showError(this, plugin.getDialog().getComponent(),
|
||||||
|
"C-Parse Error During Save",
|
||||||
|
e.getMessage());
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Msg.showError(this, plugin.getDialog().getComponent(),
|
||||||
|
"C-Parse Error During Save",
|
||||||
|
"Could not save to file " + dataFile.getPath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = getResultMessage(dtMgr, initialDtCount);
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
if (!results.successful()) {
|
||||||
|
MultiLineMessageDialog.showModalMessageDialog(
|
||||||
|
plugin.getDialog().getComponent(), "C-Parse Failed",
|
||||||
|
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||||
|
plugin.getFormattedParseMessage(msg),
|
||||||
|
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MultiLineMessageDialog.showModalMessageDialog(
|
||||||
|
plugin.getDialog().getComponent(),
|
||||||
|
"C-Parse Completed",
|
||||||
|
"Successfully parsed header file(s) to " + getParseDestination(dtMgr),
|
||||||
|
plugin.getFormattedParseMessage(msg),
|
||||||
|
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (ghidra.app.util.cparser.C.ParseException e) {
|
||||||
|
final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||||
|
"C-Parse Failed",
|
||||||
|
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||||
|
plugin.getFormattedParseMessage(errMsg),
|
||||||
|
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (ghidra.app.util.cparser.CPP.ParseException e) {
|
catch (ghidra.app.util.cparser.CPP.ParseException e) {
|
||||||
final String errMsg = e.getMessage();
|
final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
|
||||||
System.err.println(errMsg);
|
SwingUtilities.invokeLater(() -> {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||||
@Override
|
"C-PreProcessor Parse Failed",
|
||||||
public void run() {
|
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||||
String msg = getFirstMessageLine(errMsg);
|
plugin.getFormattedParseMessage(errMsg),
|
||||||
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
|
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||||
"PreProcessor Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
|
|
||||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
final String errMsg = e.getMessage();
|
final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
|
||||||
String msg = getFirstMessageLine(errMsg);
|
Msg.showError(this, plugin.getDialog().getComponent(), "Error During C-Parse",
|
||||||
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Parse",
|
|
||||||
"Parse header files failed" + "\n\nParser Messages:\n" + plugin.getParseMessage(),
|
"Parse header files failed" + "\n\nParser Messages:\n" + plugin.getParseMessage(),
|
||||||
e);
|
e);
|
||||||
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
|
SwingUtilities.invokeLater(() -> {
|
||||||
"Error During Parse", msg, plugin.getFormattedParseMessage(errMsg),
|
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
"Error During C-Parse",
|
||||||
|
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||||
|
plugin.getFormattedParseMessage(errMsg),
|
||||||
|
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (fileDtMgr != null) {
|
if (fileDtMgr != null) {
|
||||||
|
boolean deleteFile = fileDtMgr.getDataTypeCount(true) == 0;
|
||||||
fileDtMgr.close();
|
fileDtMgr.close();
|
||||||
|
if (deleteFile) {
|
||||||
|
dataFile.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,32 +18,26 @@ package ghidra.app.util.cparser.C;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.help.UnsupportedOperationException;
|
|
||||||
|
|
||||||
import generic.theme.GThemeDefaults.Colors;
|
import generic.theme.GThemeDefaults.Colors;
|
||||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
import ghidra.app.util.cparser.CPP.PreProcessor;
|
import ghidra.app.util.cparser.CPP.PreProcessor;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.framework.store.LockException;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.*;
|
|
||||||
import ghidra.program.model.listing.IncompatibleLanguageException;
|
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.DefaultLanguageService;
|
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class CParserUtils {
|
public class CParserUtils {
|
||||||
|
|
||||||
private CParserUtils() {
|
private CParserUtils() {
|
||||||
// utils class
|
// utils class
|
||||||
}
|
}
|
||||||
|
|
||||||
public record CParseResults(PreProcessor preProcessor, String cppParseMessages, String cParseMessages, boolean successful) {
|
public record CParseResults(PreProcessor preProcessor, String cppParseMessages,
|
||||||
|
String cParseMessages, boolean successful) {
|
||||||
public String getFormattedParseMessage(String errMsg) {
|
public String getFormattedParseMessage(String errMsg) {
|
||||||
String message = "";
|
String message = "";
|
||||||
|
|
||||||
|
@ -62,7 +56,7 @@ public class CParserUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -245,8 +239,10 @@ public class CParserUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
|
* Parse a set of C Header files and associated parsing arguments, returning a new File
|
||||||
* with in the provided dataFileName.
|
* Data TypeManager with in the provided dataFileName. The resulting archive
|
||||||
|
* will not be associated with a specific language/compiler and will use the default
|
||||||
|
* data organization.
|
||||||
*
|
*
|
||||||
* Note: Using another open archive while parsing will cause:
|
* Note: Using another open archive while parsing will cause:
|
||||||
* - a dependence on the other archive
|
* - a dependence on the other archive
|
||||||
|
@ -273,17 +269,20 @@ public class CParserUtils {
|
||||||
* @throws IOException if there io are errors saving the archive
|
* @throws IOException if there io are errors saving the archive
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
|
public static FileDataTypeManager parseHeaderFiles(DataTypeManager[] openDTMgrs,
|
||||||
|
String[] filenames, String[] args, String dataFileName,
|
||||||
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||||
|
|
||||||
return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor);
|
return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
|
* Parse a set of C Header files and associated parsing arguments, returning a new
|
||||||
* with in the provided dataFileName.
|
* File Data TypeManager with in the provided dataFileName. The resulting archive
|
||||||
|
* will not be associated with a specific language/compiler and will use the default
|
||||||
|
* data organization.
|
||||||
*
|
*
|
||||||
* Note: Using another open archive while parsing will cause:
|
* Note: Using another open archive while parsing will cause:
|
||||||
* - a dependence on the other archive
|
* - a dependence on the other archive
|
||||||
|
@ -312,19 +311,22 @@ public class CParserUtils {
|
||||||
* @throws IOException if there io are errors saving the archive
|
* @throws IOException if there io are errors saving the archive
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
|
public static FileDataTypeManager parseHeaderFiles(DataTypeManager[] openDTMgrs,
|
||||||
|
String[] filenames, String[] includePaths, String[] args, String dataFileName,
|
||||||
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||||
|
|
||||||
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null, monitor);
|
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null,
|
||||||
|
monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
|
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
|
||||||
* with in the provided dataFileName.
|
* with in the provided dataFileName.
|
||||||
*
|
*
|
||||||
|
* When parsing is complete any parser messages will be logged.
|
||||||
|
*
|
||||||
* Note: Using another open archive while parsing will cause:
|
* Note: Using another open archive while parsing will cause:
|
||||||
* - a dependence on the other archive
|
* - a dependence on the other archive
|
||||||
* - any missing data types while parsing are supplied if present from an openDTMgr
|
* - any missing data types while parsing are supplied if present from an openDTMgr
|
||||||
|
@ -333,7 +335,7 @@ public class CParserUtils {
|
||||||
*
|
*
|
||||||
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
|
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
|
||||||
*
|
*
|
||||||
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
|
* NOTE: Providing the correct languageId and compileSpecId is very important for header files that might use sizeof()
|
||||||
*
|
*
|
||||||
* @param openDTMgrs array of datatypes managers to use for undefined data types
|
* @param openDTMgrs array of datatypes managers to use for undefined data types
|
||||||
*
|
*
|
||||||
|
@ -349,32 +351,43 @@ public class CParserUtils {
|
||||||
*
|
*
|
||||||
* @param monitor used to cancel or provide results
|
* @param monitor used to cancel or provide results
|
||||||
*
|
*
|
||||||
* @return the data types in the ghidra .gdt archive file
|
* @return the FileDataTypeManager corresponding to the Ghidra .gdt archive file.
|
||||||
|
* The caller is responsible for closing the instance.
|
||||||
*
|
*
|
||||||
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
|
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
|
||||||
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
||||||
* @throws IOException if there io are errors saving the archive
|
* @throws IOException if there io are errors saving the archive
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
|
public static FileDataTypeManager parseHeaderFiles(DataTypeManager[] openDTMgrs,
|
||||||
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
String[] filenames, String[] includePaths, String[] args, String dataFileName,
|
||||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
String languageId, String compileSpecId, TaskMonitor monitor)
|
||||||
|
throws ghidra.app.util.cparser.C.ParseException,
|
||||||
|
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||||
|
|
||||||
File file = new File(dataFileName);
|
File file = new File(dataFileName);
|
||||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
|
FileDataTypeManager dtMgr =
|
||||||
|
FileDataTypeManager.createFileArchive(file, languageId, compileSpecId);
|
||||||
CParseResults results;
|
boolean success = false;
|
||||||
results = parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, languageId, compileSpecId, monitor);
|
try {
|
||||||
|
CParseResults results =
|
||||||
String messages = results.getFormattedParseMessage(null);
|
parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, monitor);
|
||||||
Msg.info(CParserUtils.class, messages);
|
|
||||||
|
String messages = results.getFormattedParseMessage(null);
|
||||||
dtMgr.save();
|
Msg.info(CParserUtils.class, messages);
|
||||||
|
|
||||||
return dtMgr;
|
dtMgr.save();
|
||||||
}
|
|
||||||
|
success = true;
|
||||||
|
return dtMgr;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (!success) {
|
||||||
|
dtMgr.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
|
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
|
||||||
* DTMgr.
|
* DTMgr.
|
||||||
|
@ -387,7 +400,6 @@ public class CParserUtils {
|
||||||
*
|
*
|
||||||
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
|
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
|
||||||
*
|
*
|
||||||
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
|
|
||||||
* @param openDTMgrs array of datatypes managers to use for undefined data types
|
* @param openDTMgrs array of datatypes managers to use for undefined data types
|
||||||
*
|
*
|
||||||
* @param filenames names of files in order to parse, could include strings with
|
* @param filenames names of files in order to parse, could include strings with
|
||||||
|
@ -395,10 +407,7 @@ public class CParserUtils {
|
||||||
* @param args arguments for parsing, {@code -D<defn>=}, ({@code -I<includepath>} use
|
* @param args arguments for parsing, {@code -D<defn>=}, ({@code -I<includepath>} use
|
||||||
* includePaths parm instead)
|
* includePaths parm instead)
|
||||||
*
|
*
|
||||||
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
|
* @param dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
|
||||||
*
|
|
||||||
* @param languageId language identification to use for data type organization definitions (int, long, ptr size)
|
|
||||||
* @param compileSpecId compiler specification to use for parsing
|
|
||||||
*
|
*
|
||||||
* @param monitor used to cancel or provide results
|
* @param monitor used to cancel or provide results
|
||||||
*
|
*
|
||||||
|
@ -409,86 +418,14 @@ public class CParserUtils {
|
||||||
* @throws IOException if there io are errors saving the archive
|
* @throws IOException if there io are errors saving the archive
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
|
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTMgrs, String[] filenames,
|
||||||
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
String[] args, DataTypeManager dtMgr,
|
||||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||||
|
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||||
return parseHeaderFiles(openDTMgrs, filenames, null, args, existingDTMgr, languageId, compileSpecId, monitor);
|
|
||||||
}
|
return parseHeaderFiles(openDTMgrs, filenames, null, args, dtMgr, monitor);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
|
|
||||||
* DTMgr.
|
|
||||||
*
|
|
||||||
* Note: Using another open archive while parsing will cause:
|
|
||||||
* - a dependence on the other archive
|
|
||||||
* - any missing data types while parsing are supplied if present from an openDTMgr
|
|
||||||
* - after parsing all data types parsed with an equivalent data type in any openDTMgr
|
|
||||||
* replaced by the data type from the openDTMgr
|
|
||||||
*
|
|
||||||
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
|
|
||||||
*
|
|
||||||
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
|
|
||||||
* @param openDTMgrs array of datatypes managers to use for undefined data types
|
|
||||||
*
|
|
||||||
* @param filenames names of files in order to parse, could include strings with
|
|
||||||
* "#" at start, which are ignored as comments
|
|
||||||
* @param includePaths paths to include files, instead of using {@code -I<includepath>} in args
|
|
||||||
* @param args arguments for parsing, {@code -D<defn>=}, ( {@code -I<includepath>} use includePaths parm instead)
|
|
||||||
*
|
|
||||||
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
|
|
||||||
*
|
|
||||||
* @param languageId language identification to use for data type organization definitions (int, long, ptr size)
|
|
||||||
* @param compileSpecId compiler specification to use for parsing
|
|
||||||
*
|
|
||||||
* @param monitor used to cancel or provide results
|
|
||||||
*
|
|
||||||
* @return a formatted string of any output from pre processor parsing or C parsing
|
|
||||||
*
|
|
||||||
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
|
|
||||||
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
|
||||||
* @throws IOException if there io are errors saving the archive
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], DataTypeManager existingDTMgr,
|
|
||||||
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
|
||||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
|
||||||
|
|
||||||
Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId));
|
|
||||||
CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId));
|
|
||||||
|
|
||||||
if (existingDTMgr instanceof StandAloneDataTypeManager) {
|
|
||||||
try {
|
|
||||||
((StandAloneDataTypeManager) existingDTMgr).setProgramArchitecture(language, compilerSpec.getCompilerSpecID(),
|
|
||||||
StandAloneDataTypeManager.LanguageUpdateOption.UNCHANGED, monitor);
|
|
||||||
}
|
|
||||||
catch (CompilerSpecNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (LanguageNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (CancelledException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
catch (LockException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (UnsupportedOperationException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (IncompatibleLanguageException e) {
|
|
||||||
// Shouldn't happen, unless already had a language
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, existingDTMgr, monitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
|
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
|
||||||
* DTMgr.
|
* DTMgr.
|
||||||
|
@ -522,8 +459,9 @@ public class CParserUtils {
|
||||||
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
|
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
|
||||||
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
||||||
*/
|
*/
|
||||||
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, String[] includePaths,
|
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers,
|
||||||
String args[], DataTypeManager dtMgr, TaskMonitor monitor)
|
String[] filenames, String[] includePaths,
|
||||||
|
String[] args, DataTypeManager dtMgr, TaskMonitor monitor)
|
||||||
throws ghidra.app.util.cparser.C.ParseException,
|
throws ghidra.app.util.cparser.C.ParseException,
|
||||||
ghidra.app.util.cparser.CPP.ParseException {
|
ghidra.app.util.cparser.CPP.ParseException {
|
||||||
|
|
||||||
|
@ -534,9 +472,9 @@ public class CParserUtils {
|
||||||
cpp.addIncludePaths(includePaths);
|
cpp.addIncludePaths(includePaths);
|
||||||
|
|
||||||
PrintStream os = System.out;
|
PrintStream os = System.out;
|
||||||
|
|
||||||
String fName = dtMgr.getName();
|
String fName = dtMgr.getName();
|
||||||
|
|
||||||
// make a path to tmpdir with name of data type manager
|
// make a path to tmpdir with name of data type manager
|
||||||
String path = new File(Application.getUserTempDirectory(), fName).getAbsolutePath();
|
String path = new File(Application.getUserTempDirectory(), fName).getAbsolutePath();
|
||||||
// if file data type manager, use path to .gdt file
|
// if file data type manager, use path to .gdt file
|
||||||
|
@ -544,10 +482,11 @@ public class CParserUtils {
|
||||||
path = ((FileDataTypeManager) dtMgr).getPath();
|
path = ((FileDataTypeManager) dtMgr).getPath();
|
||||||
}
|
}
|
||||||
path = path + "_CParser.out";
|
path = path + "_CParser.out";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
os = new PrintStream(new FileOutputStream(path));
|
os = new PrintStream(new FileOutputStream(path));
|
||||||
} catch (FileNotFoundException e2) {
|
}
|
||||||
|
catch (FileNotFoundException e2) {
|
||||||
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
|
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
|
||||||
}
|
}
|
||||||
// cpp.setOutputStream(os);
|
// cpp.setOutputStream(os);
|
||||||
|
@ -580,26 +519,29 @@ public class CParserUtils {
|
||||||
parseFile(child.getAbsolutePath(), monitor, cpp);
|
parseFile(child.getAbsolutePath(), monitor, cpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
parseFile(filename, monitor, cpp);
|
parseFile(filename, monitor, cpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parseSucceeded = true;
|
parseSucceeded = true;
|
||||||
} catch (Throwable e) {
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
Msg.info(cpp, cpp.getParseMessages());
|
Msg.info(cpp, cpp.getParseMessages());
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
System.out.println(bos);
|
System.out.println(bos);
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
System.setOut(old);
|
System.setOut(old);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cppMessages = cpp.getParseMessages();
|
cppMessages = cpp.getParseMessages();
|
||||||
if (!parseSucceeded) {
|
if (!parseSucceeded) {
|
||||||
return new CParseResults(cpp, "", cppMessages, false);
|
return new CParseResults(cpp, "", cppMessages, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// process all the defines and add any that are integer values into
|
// process all the defines and add any that are integer values into
|
||||||
// the Equates table
|
// the Equates table
|
||||||
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
|
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
|
||||||
|
@ -608,7 +550,7 @@ public class CParserUtils {
|
||||||
boolean cparseSucceeded = false;
|
boolean cparseSucceeded = false;
|
||||||
if (!monitor.isCancelled()) {
|
if (!monitor.isCancelled()) {
|
||||||
monitor.setMessage("Parsing C");
|
monitor.setMessage("Parsing C");
|
||||||
|
|
||||||
CParser cParser = new CParser(dtMgr, true, openDTmanagers);
|
CParser cParser = new CParser(dtMgr, true, openDTmanagers);
|
||||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||||
try {
|
try {
|
||||||
|
@ -617,16 +559,18 @@ public class CParserUtils {
|
||||||
cParser.setMonitor(monitor);
|
cParser.setMonitor(monitor);
|
||||||
cParser.parse(bis);
|
cParser.parse(bis);
|
||||||
cparseSucceeded = cParser.didParseSucceed();
|
cparseSucceeded = cParser.didParseSucceed();
|
||||||
} catch (RuntimeException re) {
|
}
|
||||||
|
catch (RuntimeException re) {
|
||||||
Msg.info(cpp, cpp.getParseMessages());
|
Msg.info(cpp, cpp.getParseMessages());
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
parserMessages = cParser.getParseMessages();
|
parserMessages = cParser.getParseMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
|
return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
|
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
|
||||||
throws ghidra.app.util.cparser.CPP.ParseException {
|
throws ghidra.app.util.cparser.CPP.ParseException {
|
||||||
monitor.setMessage("PreProcessing " + filename);
|
monitor.setMessage("PreProcessing " + filename);
|
||||||
|
@ -640,10 +584,10 @@ public class CParserUtils {
|
||||||
|
|
||||||
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
|
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpp.getParseMessages();
|
return cpp.getParseMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
|
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
|
||||||
|
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
|
@ -782,54 +726,52 @@ public class CParserUtils {
|
||||||
errorIndex + "<br>" + successFailureBuffer;
|
errorIndex + "<br>" + successFailureBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static File getFile(String parent, String filename) {
|
||||||
|
File file = findFile(parent, filename);
|
||||||
|
if (file != null) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
// filename lower
|
||||||
|
file = findFile(parent, filename.toLowerCase());
|
||||||
|
if (file != null) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
// parent and filename lower
|
||||||
|
file = findFile(parent.toLowerCase(), filename.toLowerCase());
|
||||||
|
if (file != null) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
// parent and filename upper
|
||||||
|
file = findFile(parent.toUpperCase(), filename.toUpperCase());
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
public static File getFile(String parent, String filename) {
|
private static File findFile(String parent, String filename) {
|
||||||
File file = findFile(parent, filename);
|
File iFile = null;
|
||||||
if (file != null) {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
// filename lower
|
|
||||||
file = findFile(parent, filename.toLowerCase());
|
|
||||||
if (file != null) {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
// parent and filename lower
|
|
||||||
file = findFile(parent.toLowerCase(), filename.toLowerCase());
|
|
||||||
if (file != null) {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
// parent and filename upper
|
|
||||||
file = findFile(parent.toUpperCase(), filename.toUpperCase());
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File findFile(String parent, String filename) {
|
iFile = new File(parent + File.separator + filename);
|
||||||
File iFile = null;
|
if (iFile.exists())
|
||||||
|
return iFile;
|
||||||
|
|
||||||
iFile = new File(parent + File.separator + filename);
|
// try just in this directory
|
||||||
if (iFile.exists())
|
File sameiFile = new File(parent + File.separator + (new File(filename)).getName());
|
||||||
return iFile;
|
if (sameiFile.exists())
|
||||||
|
return sameiFile;
|
||||||
|
|
||||||
// try just in this directory
|
// try all files in this directory doing to-lower on both input file and output file
|
||||||
File sameiFile = new File(parent + File.separator
|
// if match return it
|
||||||
+ (new File(filename)).getName());
|
File folder = new File(parent);
|
||||||
if (sameiFile.exists())
|
if (folder.isDirectory()) {
|
||||||
return sameiFile;
|
File[] listOfFiles = folder.listFiles();
|
||||||
|
|
||||||
// try all files in this directory doing to-lower on both input file and output file
|
if (listOfFiles != null) {
|
||||||
// if match return it
|
for (File file : listOfFiles) {
|
||||||
File folder = new File(parent);
|
if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
|
||||||
if (folder.isDirectory()) {
|
return file;
|
||||||
File[] listOfFiles = folder.listFiles();
|
}
|
||||||
|
}
|
||||||
if (listOfFiles != null) {
|
}
|
||||||
for (File file : listOfFiles) {
|
}
|
||||||
if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
|
return null;
|
||||||
return file;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,16 @@ package ghidra.program.model.data;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.framework.data.OpenMode;
|
import ghidra.framework.data.OpenMode;
|
||||||
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.framework.store.db.PackedDBHandle;
|
import ghidra.framework.store.db.PackedDBHandle;
|
||||||
import ghidra.framework.store.db.PackedDatabase;
|
import ghidra.framework.store.db.PackedDatabase;
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.listing.IncompatibleLanguageException;
|
||||||
|
import ghidra.program.util.DefaultLanguageService;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
import ghidra.util.UniversalID;
|
import ghidra.util.UniversalID;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
|
@ -101,6 +104,77 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new data-type file archive using the default data organization.
|
||||||
|
* @param packedDbFile archive file (filename must end with DataTypeFileManager.SUFFIX)
|
||||||
|
* @param languageId valid language ID (see appropriate *.ldefs file for defined IDs)
|
||||||
|
* @param compilerSpecId valid compiler spec ID which corresponds to the language ID.
|
||||||
|
* @return data-type manager backed by the specified packedDbFile
|
||||||
|
* @returns DuplicateFileException if {@code packedDbFile} already exists
|
||||||
|
* @throws LanguageNotFoundException if specified {@code languageId} not defined.
|
||||||
|
* @throws CompilerSpecNotFoundException if specified {@code compilerSpecId} is not defined
|
||||||
|
* for the specified language.
|
||||||
|
* @throws IOException if an IO error occurs
|
||||||
|
*/
|
||||||
|
public static FileDataTypeManager createFileArchive(File packedDbFile, LanguageID languageId,
|
||||||
|
CompilerSpecID compilerSpecId)
|
||||||
|
throws LanguageNotFoundException, CompilerSpecNotFoundException, IOException {
|
||||||
|
Objects.requireNonNull(languageId, "missing required languageId");
|
||||||
|
Objects.requireNonNull(compilerSpecId, "missing required compilerSpecId");
|
||||||
|
try {
|
||||||
|
if (packedDbFile.exists()) {
|
||||||
|
throw new DuplicateFileException("File already exists: " + packedDbFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the specified language and compiler spec are valid
|
||||||
|
LanguageService languageService = DefaultLanguageService.getLanguageService();
|
||||||
|
Language language = languageService.getLanguage(languageId);
|
||||||
|
language.getCompilerSpecByID(compilerSpecId);
|
||||||
|
|
||||||
|
FileDataTypeManager dtm =
|
||||||
|
new FileDataTypeManager(new ResourceFile(packedDbFile), OpenMode.CREATE,
|
||||||
|
TaskMonitor.DUMMY);
|
||||||
|
|
||||||
|
dtm.setProgramArchitecture(language, compilerSpecId, LanguageUpdateOption.CLEAR,
|
||||||
|
TaskMonitor.DUMMY);
|
||||||
|
|
||||||
|
return dtm;
|
||||||
|
}
|
||||||
|
catch (CancelledException e) {
|
||||||
|
throw new AssertException(e); // unexpected without task monitor use
|
||||||
|
}
|
||||||
|
catch (LockException | IncompatibleLanguageException | UnsupportedOperationException e) {
|
||||||
|
throw new RuntimeException(e); // unexpected for new archive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new data-type file archive using the default data organization.
|
||||||
|
* @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
|
||||||
|
* @param languageId valid language ID (see appropriate *.ldefs file for defined IDs). If null
|
||||||
|
* invocation will be deferred to {@link #createFileArchive(File)}.
|
||||||
|
* @param compilerSpecId valid compiler spec ID which corresponds to the language ID.
|
||||||
|
* @return data-type manager backed by the specified packedDbFile
|
||||||
|
* @throws LanguageNotFoundException if specified {@code languageId} not defined.
|
||||||
|
* @throws CompilerSpecNotFoundException if specified {@code compilerSpecId} is not defined
|
||||||
|
* for the specified language.
|
||||||
|
* @throws IOException if an IO error occurs
|
||||||
|
*/
|
||||||
|
public static FileDataTypeManager createFileArchive(File packedDbfile, String languageId,
|
||||||
|
String compilerSpecId) throws IOException {
|
||||||
|
if (languageId == null) {
|
||||||
|
if (compilerSpecId != null) {
|
||||||
|
throw new IllegalArgumentException("compilerSpecId specified without languageId");
|
||||||
|
}
|
||||||
|
return createFileArchive(packedDbfile);
|
||||||
|
}
|
||||||
|
if (compilerSpecId == null) {
|
||||||
|
throw new IllegalArgumentException("languageId specified without compilerSpecId");
|
||||||
|
}
|
||||||
|
return createFileArchive(packedDbfile, new LanguageID(languageId),
|
||||||
|
new CompilerSpecID(compilerSpecId));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open an existing data-type file archive using the default data organization.
|
* Open an existing data-type file archive using the default data organization.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -161,7 +235,6 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
|
||||||
public void saveAs(File saveFile, UniversalID newUniversalId)
|
public void saveAs(File saveFile, UniversalID newUniversalId)
|
||||||
throws DuplicateFileException, IOException {
|
throws DuplicateFileException, IOException {
|
||||||
ResourceFile resourceSaveFile = new ResourceFile(saveFile);
|
ResourceFile resourceSaveFile = new ResourceFile(saveFile);
|
||||||
// TODO: this should really be a package method and not public!
|
|
||||||
validateFilename(resourceSaveFile);
|
validateFilename(resourceSaveFile);
|
||||||
try {
|
try {
|
||||||
universalID = newUniversalId;
|
universalID = newUniversalId;
|
||||||
|
@ -333,3 +406,4 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
|
||||||
return getClass().getSimpleName() + " - " + getName();
|
return getClass().getSimpleName() + " - " + getName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -32,9 +32,7 @@ import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils;
|
import ghidra.app.util.cparser.C.CParserUtils;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||||
import ghidra.app.util.cparser.CPP.DefineTable;
|
import ghidra.app.util.cparser.CPP.*;
|
||||||
import ghidra.app.util.cparser.CPP.ParseException;
|
|
||||||
import ghidra.app.util.cparser.CPP.PreProcessor;
|
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.data.FileDataTypeManager;
|
import ghidra.program.model.data.FileDataTypeManager;
|
||||||
import ghidra.program.util.AddressEvaluator;
|
import ghidra.program.util.AddressEvaluator;
|
||||||
|
@ -127,7 +125,8 @@ public class CreateAVR8GDTArchiveScript extends GhidraScript {
|
||||||
|
|
||||||
File f = getArchiveFile(dataTypeFile);
|
File f = getArchiveFile(dataTypeFile);
|
||||||
|
|
||||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
|
FileDataTypeManager dtMgr =
|
||||||
|
FileDataTypeManager.createFileArchive(f, "avr8:LE:16:atmega256", "gcc");
|
||||||
|
|
||||||
// Parse each processor variant as an individual parse that gets added to the data
|
// Parse each processor variant as an individual parse that gets added to the data
|
||||||
// type manager. If all header files were parsed at once, there are conflicting
|
// type manager. If all header files were parsed at once, there are conflicting
|
||||||
|
@ -178,7 +177,7 @@ public class CreateAVR8GDTArchiveScript extends GhidraScript {
|
||||||
String args[] = Arrays.append(orig_args, "-D__AVR_" + procName + "__");
|
String args[] = Arrays.append(orig_args, "-D__AVR_" + procName + "__");
|
||||||
|
|
||||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr,
|
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr,
|
||||||
"avr8:LE:16:atmega256", "gcc", monitor);
|
monitor);
|
||||||
|
|
||||||
Msg.info(this, results.getFormattedParseMessage(null));
|
Msg.info(this, results.getFormattedParseMessage(null));
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -33,11 +33,9 @@ import generic.jar.ResourceFile;
|
||||||
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils;
|
import ghidra.app.util.cparser.C.CParserUtils;
|
||||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
|
||||||
import ghidra.app.util.cparser.C.ParseException;
|
import ghidra.app.util.cparser.C.ParseException;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.data.FileDataTypeManager;
|
import ghidra.program.model.data.FileDataTypeManager;
|
||||||
import ghidra.util.Msg;
|
|
||||||
|
|
||||||
public class CreateJNIGDTArchivesScript extends GhidraScript {
|
public class CreateJNIGDTArchivesScript extends GhidraScript {
|
||||||
|
|
||||||
|
@ -63,13 +61,9 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
|
||||||
|
|
||||||
File f = getArchiveFile(dataTypeFile);
|
File f = getArchiveFile(dataTypeFile);
|
||||||
|
|
||||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
|
FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames, null, args,
|
||||||
|
f.getAbsolutePath(), languageID, compiler, monitor);
|
||||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, monitor);
|
|
||||||
|
|
||||||
Msg.info(this, results.getFormattedParseMessage(null));
|
|
||||||
|
|
||||||
dtMgr.save();
|
|
||||||
dtMgr.close();
|
dtMgr.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue