mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +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");
|
||||
* 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) {
|
||||
|
|
|
@ -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,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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -31,12 +31,9 @@ import java.io.IOException;
|
|||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
||||
|
||||
|
@ -69,16 +66,12 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
|
|||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -31,11 +31,9 @@ import java.io.IOException;
|
|||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class CreateExampleGDTArchiveScript extends GhidraScript {
|
||||
|
||||
|
@ -69,13 +67,9 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
|
|||
|
||||
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));
|
||||
FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames,
|
||||
includePaths, args, f.getAbsolutePath(), languageID, compiler, monitor);
|
||||
|
||||
dtMgr.save();
|
||||
dtMgr.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,18 +16,14 @@
|
|||
package ghidra.app.plugin.core.cparser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.dialogs.MultiLineMessageDialog;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
|
@ -40,7 +36,8 @@ import ghidra.framework.plugintool.PluginInfo;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
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.listing.Program;
|
||||
import ghidra.util.*;
|
||||
|
@ -168,9 +165,9 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
/*
|
||||
* Parse C-source into a data type manager
|
||||
*/
|
||||
protected void parse(String[] filenames, String includePaths[], String options,
|
||||
String languageIDString, String compilerSpecID, DataTypeManager dtMgr,
|
||||
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
protected CParseResults parse(String[] filenames, String includePaths[], String options,
|
||||
DataTypeManager dtMgr, TaskMonitor monitor)
|
||||
throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException {
|
||||
|
||||
results = null;
|
||||
|
@ -181,43 +178,26 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
try {
|
||||
openDTmanagers = getOpenDTMgrs();
|
||||
} catch (CancelledException exc) {
|
||||
return; // parse canceled
|
||||
return null; // parse canceled
|
||||
}
|
||||
|
||||
try {
|
||||
results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
|
||||
args, dtMgr, languageIDString, compilerSpecID, monitor);
|
||||
|
||||
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager);
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
// CParserTask will show any errors
|
||||
if (!results.successful()) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
|
||||
args, dtMgr, monitor);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
boolean isOpenInTool(DataTypeManager dtm) {
|
||||
DataTypeManagerService dtService = tool.getService(DataTypeManagerService.class);
|
||||
if (dtService == null) {
|
||||
return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
// ignore
|
||||
for (DataTypeManager openDtm : dtService.getDataTypeManagers()) {
|
||||
if (dtm == openDtm) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -327,11 +307,9 @@ public class CParserPlugin extends ProgramPlugin {
|
|||
|
||||
CParserTask parseTask =
|
||||
new CParserTask(this, currentProgram.getDataTypeManager())
|
||||
.setFileNames(filenames)
|
||||
.setIncludePaths(includePaths)
|
||||
.setOptions(options)
|
||||
.setLanguageID(procID)
|
||||
.setCompilerID(compilerID);
|
||||
.setFileNames(filenames)
|
||||
.setIncludePaths(includePaths)
|
||||
.setOptions(options);
|
||||
|
||||
tool.execute(parseTask);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,11 +16,16 @@
|
|||
package ghidra.app.plugin.core.cparser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
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.exception.DuplicateFileException;
|
||||
import ghidra.util.task.Task;
|
||||
|
@ -34,18 +39,19 @@ import ghidra.util.task.TaskMonitor;
|
|||
class CParserTask extends Task {
|
||||
|
||||
private CParserPlugin plugin;
|
||||
private String dataFileName;
|
||||
|
||||
private String[] filenames;
|
||||
private String[] includePaths;
|
||||
|
||||
private String options;
|
||||
|
||||
private String languageString;
|
||||
private String compilerString;
|
||||
// Language and Compiler Spec IDs valid only for new dataFileName use
|
||||
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
|
||||
|
@ -55,44 +61,64 @@ class CParserTask extends Task {
|
|||
*/
|
||||
CParserTask(CParserPlugin plugin, String dataFileName) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
|
||||
dataTypeManager = null;
|
||||
this.plugin = plugin;
|
||||
this.dataFileName = dataFileName;
|
||||
this.dataFile = new File(dataFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create task to parse to a dataTypeManager
|
||||
*
|
||||
* @param plugin
|
||||
* @param dataTypeManager
|
||||
* NOTE: The Language ID and Compiler Spec ID must not be set since the dataTypeManager's
|
||||
* 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) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
|
||||
dataFile = null;
|
||||
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
|
||||
* @param dataTypeManager
|
||||
* NOTE: The compiler spec ID must also be set, see {@code #setCompilerID(String)}.
|
||||
* 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) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.dtMgr = dataTypeManager;
|
||||
}
|
||||
|
||||
public CParserTask setLanguageID(String languageID) {
|
||||
this.languageString = languageID;
|
||||
public CParserTask setLanguageID(String languageId) {
|
||||
if (dataTypeManager != null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"setLanguageID not supported when constructed with DataTypeManager");
|
||||
}
|
||||
this.languageId = languageId;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -120,96 +146,142 @@ class CParserTask extends Task {
|
|||
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
|
||||
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);
|
||||
if (dataFileName != null) {
|
||||
// TODO: does not consider existing datatypes
|
||||
if (dtMgr.getDataTypeCount(true) != 0) {
|
||||
try {
|
||||
((FileDataTypeManager) dtMgr).save();
|
||||
dtMgr.close();
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
FileDataTypeManager fileDtMgr = null;
|
||||
if (dataFile != null) {
|
||||
try {
|
||||
if ((languageId != null) != (compilerSpecId != null)) {
|
||||
Msg.showError(this, plugin.getDialog().getComponent(), "Archive Failure",
|
||||
"Language/CompilerSpec improperly specified: " + languageId + "/" +
|
||||
compilerSpecId);
|
||||
return;
|
||||
}
|
||||
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();
|
||||
System.err.println(errMsg);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String msg = getFirstMessageLine(errMsg);
|
||||
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
|
||||
"Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
|
||||
DataTypeManager dtMgr = fileDtMgr != null ? fileDtMgr : dataTypeManager;
|
||||
|
||||
int initialDtCount = dtMgr.getDataTypeCount(true);
|
||||
|
||||
try {
|
||||
|
||||
CParseResults results = plugin.parse(filenames, includePaths, options, dtMgr, monitor);
|
||||
if (results == null) {
|
||||
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) {
|
||||
final String errMsg = e.getMessage();
|
||||
System.err.println(errMsg);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String msg = getFirstMessageLine(errMsg);
|
||||
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
|
||||
"PreProcessor Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
}
|
||||
final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||
"C-PreProcessor Parse Failed",
|
||||
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||
plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
final String errMsg = e.getMessage();
|
||||
String msg = getFirstMessageLine(errMsg);
|
||||
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Parse",
|
||||
final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
|
||||
Msg.showError(this, plugin.getDialog().getComponent(), "Error During C-Parse",
|
||||
"Parse header files failed" + "\n\nParser Messages:\n" + plugin.getParseMessage(),
|
||||
e);
|
||||
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
|
||||
"Error During Parse", msg, plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||
"Error During C-Parse",
|
||||
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||
plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
});
|
||||
}
|
||||
finally {
|
||||
if (fileDtMgr != null) {
|
||||
boolean deleteFile = fileDtMgr.getDataTypeCount(true) == 0;
|
||||
fileDtMgr.close();
|
||||
if (deleteFile) {
|
||||
dataFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,32 +18,26 @@ package ghidra.app.util.cparser.C;
|
|||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.cparser.CPP.PreProcessor;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.framework.store.LockException;
|
||||
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.util.DefaultLanguageService;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CParserUtils {
|
||||
|
||||
|
||||
private CParserUtils() {
|
||||
// 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) {
|
||||
String message = "";
|
||||
|
||||
|
@ -62,7 +56,7 @@ public class CParserUtils {
|
|||
}
|
||||
|
||||
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
|
||||
* with in the provided dataFileName.
|
||||
* Parse a set of C Header files and associated parsing arguments, returning a new 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:
|
||||
* - a dependence on the other archive
|
||||
|
@ -273,17 +269,20 @@ public class CParserUtils {
|
|||
* @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,
|
||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
|
||||
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
|
||||
* with in the provided dataFileName.
|
||||
* Parse a set of C Header files and associated parsing arguments, returning a new
|
||||
* 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:
|
||||
* - a dependence on the other archive
|
||||
|
@ -312,19 +311,22 @@ public class CParserUtils {
|
|||
* @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,
|
||||
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
|
||||
* with in the provided dataFileName.
|
||||
*
|
||||
* When parsing is complete any parser messages will be logged.
|
||||
*
|
||||
* 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
|
||||
|
@ -333,7 +335,7 @@ public class CParserUtils {
|
|||
*
|
||||
* 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
|
||||
*
|
||||
|
@ -349,32 +351,43 @@ public class CParserUtils {
|
|||
*
|
||||
* @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.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
||||
* @throws IOException if there io are errors saving the archive
|
||||
*
|
||||
*/
|
||||
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
|
||||
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
public static FileDataTypeManager parseHeaderFiles(DataTypeManager[] openDTMgrs,
|
||||
String[] filenames, String[] includePaths, String[] args, String dataFileName,
|
||||
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);
|
||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
|
||||
|
||||
CParseResults results;
|
||||
results = parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, languageId, compileSpecId, monitor);
|
||||
|
||||
String messages = results.getFormattedParseMessage(null);
|
||||
Msg.info(CParserUtils.class, messages);
|
||||
|
||||
dtMgr.save();
|
||||
|
||||
return dtMgr;
|
||||
}
|
||||
File file = new File(dataFileName);
|
||||
FileDataTypeManager dtMgr =
|
||||
FileDataTypeManager.createFileArchive(file, languageId, compileSpecId);
|
||||
boolean success = false;
|
||||
try {
|
||||
CParseResults results =
|
||||
parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, monitor);
|
||||
|
||||
String messages = results.getFormattedParseMessage(null);
|
||||
Msg.info(CParserUtils.class, messages);
|
||||
|
||||
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
|
||||
* DTMgr.
|
||||
|
@ -387,7 +400,6 @@ public class CParserUtils {
|
|||
*
|
||||
* 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
|
||||
|
@ -395,10 +407,7 @@ public class CParserUtils {
|
|||
* @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 dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
|
||||
*
|
||||
* @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
|
||||
*
|
||||
*/
|
||||
public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
|
||||
String languageId, String compileSpecId, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTMgrs, String[] filenames,
|
||||
String[] args, DataTypeManager dtMgr,
|
||||
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
return parseHeaderFiles(openDTMgrs, filenames, null, args, dtMgr, monitor);
|
||||
}
|
||||
|
||||
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
|
||||
* 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.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
|
||||
*/
|
||||
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, String[] includePaths,
|
||||
String args[], DataTypeManager dtMgr, TaskMonitor monitor)
|
||||
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers,
|
||||
String[] filenames, String[] includePaths,
|
||||
String[] args, DataTypeManager dtMgr, TaskMonitor monitor)
|
||||
throws ghidra.app.util.cparser.C.ParseException,
|
||||
ghidra.app.util.cparser.CPP.ParseException {
|
||||
|
||||
|
@ -534,9 +472,9 @@ public class CParserUtils {
|
|||
cpp.addIncludePaths(includePaths);
|
||||
|
||||
PrintStream os = System.out;
|
||||
|
||||
|
||||
String fName = dtMgr.getName();
|
||||
|
||||
|
||||
// make a path to tmpdir with name of data type manager
|
||||
String path = new File(Application.getUserTempDirectory(), fName).getAbsolutePath();
|
||||
// if file data type manager, use path to .gdt file
|
||||
|
@ -544,10 +482,11 @@ public class CParserUtils {
|
|||
path = ((FileDataTypeManager) dtMgr).getPath();
|
||||
}
|
||||
path = path + "_CParser.out";
|
||||
|
||||
|
||||
try {
|
||||
os = new PrintStream(new FileOutputStream(path));
|
||||
} catch (FileNotFoundException e2) {
|
||||
}
|
||||
catch (FileNotFoundException e2) {
|
||||
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
|
||||
}
|
||||
// cpp.setOutputStream(os);
|
||||
|
@ -580,26 +519,29 @@ public class CParserUtils {
|
|||
parseFile(child.getAbsolutePath(), monitor, cpp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
parseFile(filename, monitor, cpp);
|
||||
}
|
||||
}
|
||||
parseSucceeded = true;
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.info(cpp, cpp.getParseMessages());
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
System.out.println(bos);
|
||||
os.flush();
|
||||
os.close();
|
||||
System.setOut(old);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
cppMessages = cpp.getParseMessages();
|
||||
if (!parseSucceeded) {
|
||||
return new CParseResults(cpp, "", cppMessages, false);
|
||||
}
|
||||
|
||||
|
||||
// process all the defines and add any that are integer values into
|
||||
// the Equates table
|
||||
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
|
||||
|
@ -608,7 +550,7 @@ public class CParserUtils {
|
|||
boolean cparseSucceeded = false;
|
||||
if (!monitor.isCancelled()) {
|
||||
monitor.setMessage("Parsing C");
|
||||
|
||||
|
||||
CParser cParser = new CParser(dtMgr, true, openDTmanagers);
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
try {
|
||||
|
@ -617,16 +559,18 @@ public class CParserUtils {
|
|||
cParser.setMonitor(monitor);
|
||||
cParser.parse(bis);
|
||||
cparseSucceeded = cParser.didParseSucceed();
|
||||
} catch (RuntimeException re) {
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
Msg.info(cpp, cpp.getParseMessages());
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
parserMessages = cParser.getParseMessages();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
|
||||
}
|
||||
|
||||
|
||||
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
|
||||
throws ghidra.app.util.cparser.CPP.ParseException {
|
||||
monitor.setMessage("PreProcessing " + filename);
|
||||
|
@ -640,10 +584,10 @@ public class CParserUtils {
|
|||
|
||||
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
return cpp.getParseMessages();
|
||||
}
|
||||
|
||||
|
||||
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
|
||||
|
||||
if (service == null) {
|
||||
|
@ -782,54 +726,52 @@ public class CParserUtils {
|
|||
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) {
|
||||
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;
|
||||
}
|
||||
private static File findFile(String parent, String filename) {
|
||||
File iFile = null;
|
||||
|
||||
private static File findFile(String parent, String filename) {
|
||||
File iFile = null;
|
||||
iFile = new File(parent + File.separator + filename);
|
||||
if (iFile.exists())
|
||||
return iFile;
|
||||
|
||||
iFile = new File(parent + File.separator + filename);
|
||||
if (iFile.exists())
|
||||
return iFile;
|
||||
// try just in this directory
|
||||
File sameiFile = new File(parent + File.separator + (new File(filename)).getName());
|
||||
if (sameiFile.exists())
|
||||
return sameiFile;
|
||||
|
||||
// try just in this directory
|
||||
File sameiFile = new File(parent + File.separator
|
||||
+ (new File(filename)).getName());
|
||||
if (sameiFile.exists())
|
||||
return sameiFile;
|
||||
// try all files in this directory doing to-lower on both input file and output file
|
||||
// if match return it
|
||||
File folder = new File(parent);
|
||||
if (folder.isDirectory()) {
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
|
||||
// try all files in this directory doing to-lower on both input file and output file
|
||||
// if match return it
|
||||
File folder = new File(parent);
|
||||
if (folder.isDirectory()) {
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
|
||||
if (listOfFiles != null) {
|
||||
for (File file : listOfFiles) {
|
||||
if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (listOfFiles != null) {
|
||||
for (File file : listOfFiles) {
|
||||
if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,16 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.framework.data.OpenMode;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.framework.store.db.PackedDBHandle;
|
||||
import ghidra.framework.store.db.PackedDatabase;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.IncompatibleLanguageException;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.UniversalID;
|
||||
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.
|
||||
* <p>
|
||||
|
@ -161,7 +235,6 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
|
|||
public void saveAs(File saveFile, UniversalID newUniversalId)
|
||||
throws DuplicateFileException, IOException {
|
||||
ResourceFile resourceSaveFile = new ResourceFile(saveFile);
|
||||
// TODO: this should really be a package method and not public!
|
||||
validateFilename(resourceSaveFile);
|
||||
try {
|
||||
universalID = newUniversalId;
|
||||
|
@ -333,3 +406,4 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
|
|||
return getClass().getSimpleName() + " - " + getName();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -32,9 +32,7 @@ import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
|||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.app.util.cparser.CPP.DefineTable;
|
||||
import ghidra.app.util.cparser.CPP.ParseException;
|
||||
import ghidra.app.util.cparser.CPP.PreProcessor;
|
||||
import ghidra.app.util.cparser.CPP.*;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.util.AddressEvaluator;
|
||||
|
@ -127,7 +125,8 @@ public class CreateAVR8GDTArchiveScript extends GhidraScript {
|
|||
|
||||
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
|
||||
// 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 + "__");
|
||||
|
||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr,
|
||||
"avr8:LE:16:atmega256", "gcc", monitor);
|
||||
monitor);
|
||||
|
||||
Msg.info(this, results.getFormattedParseMessage(null));
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -33,11 +33,9 @@ import generic.jar.ResourceFile;
|
|||
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class CreateJNIGDTArchivesScript extends GhidraScript {
|
||||
|
||||
|
@ -63,13 +61,9 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
|
|||
|
||||
File f = getArchiveFile(dataTypeFile);
|
||||
|
||||
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
|
||||
|
||||
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, monitor);
|
||||
FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames, null, args,
|
||||
f.getAbsolutePath(), languageID, compiler, monitor);
|
||||
|
||||
Msg.info(this, results.getFormattedParseMessage(null));
|
||||
|
||||
dtMgr.save();
|
||||
dtMgr.close();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue