Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2024-12-03 10:15:21 -05:00
commit 16388dc261
11 changed files with 502 additions and 427 deletions

View file

@ -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) {

View file

@ -69,32 +69,7 @@ import ghidra.util.table.GhidraTable;
@Category(NightlyCategory.class) @Category(NightlyCategory.class)
public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTest { public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTest {
DebuggerModulesProvider provider; public static final String CTX_XML = """
protected TraceObjectModule modExe;
protected TraceObjectSection secExeText;
protected TraceObjectSection secExeData;
protected TraceObjectModule modLib;
protected TraceObjectSection secLibText;
protected TraceObjectSection secLibData;
protected SchemaContext ctx;
@Override
protected void createTrace(String langID) throws IOException {
super.createTrace(langID);
try {
activateObjectsMode();
}
catch (Exception e) {
throw new AssertionError(e);
}
}
public void activateObjectsMode() throws Exception {
// NOTE the use of index='1' allowing object-based managers to ID unique path
ctx = XmlSchemaContext.deserialize("""
<context> <context>
<schema name='Session' elementResync='NEVER' attributeResync='ONCE'> <schema name='Session' elementResync='NEVER' attributeResync='ONCE'>
<attribute name='Processes' schema='ProcessContainer' /> <attribute name='Processes' schema='ProcessContainer' />
@ -129,7 +104,34 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes
<schema name='Section' elementResync='NEVER' attributeResync='NEVER'> <schema name='Section' elementResync='NEVER' attributeResync='NEVER'>
<interface name='Section' /> <interface name='Section' />
</schema> </schema>
</context>"""); </context>""";
DebuggerModulesProvider provider;
protected TraceObjectModule modExe;
protected TraceObjectSection secExeText;
protected TraceObjectSection secExeData;
protected TraceObjectModule modLib;
protected TraceObjectSection secLibText;
protected TraceObjectSection secLibData;
protected SchemaContext ctx;
@Override
protected void createTrace(String langID) throws IOException {
super.createTrace(langID);
try {
activateObjectsMode();
}
catch (Exception e) {
throw new AssertionError(e);
}
}
public void activateObjectsMode() throws Exception {
// NOTE the use of index='1' allowing object-based managers to ID unique path
ctx = XmlSchemaContext.deserialize(CTX_XML);
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")));

View file

@ -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)));
}
} }

View file

@ -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 {
@ -72,13 +69,9 @@ public class CreateDefaultGDTArchivesScript 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();
} }

View file

@ -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();
} }

View file

@ -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, languageIDString, compilerSpecID, monitor); args, dtMgr, monitor);
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager); return results;
}
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) { for (DataTypeManager openDtm : dtService.getDataTypeManagers()) {
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(), if (dtm == openDtm) {
"C-Parse of Header Files Complete", return true;
"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) {
// ignore
} }
return false;
} }
/** /**
@ -329,9 +309,7 @@ public class CParserPlugin extends ProgramPlugin {
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);
} }

View file

@ -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;
} }
@Override private String getResultMessage(DataTypeManager dtMgr, int initialDtCount) {
public void run(TaskMonitor monitor) {
DataTypeManager fileDtMgr = null; int finalDtCount = dtMgr.getDataTypeCount(true) - initialDtCount;
try {
if (dtMgr == null) { String msg = (finalDtCount == 0 ? "No" : Integer.toString(finalDtCount)) +
File file = new File(dataFileName); " Data Types added.";
dtMgr = FileDataTypeManager.createFileArchive(file); if (finalDtCount != 0 && plugin.isOpenInTool(dtMgr)) {
fileDtMgr = dtMgr; msg += "\nCheck the Data Type Manager window for added data types.";
}
return msg;
} }
plugin.parse(filenames, includePaths, options, languageString, compilerString, dtMgr, monitor); private String getParseDestination(DataTypeManager dtMgr) {
if (dataFileName != null) { String parseDest = "";
// TODO: does not consider existing datatypes if (dtMgr instanceof ProgramDataTypeManager) {
if (dtMgr.getDataTypeCount(true) != 0) { 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) {
FileDataTypeManager fileDtMgr = null;
if (dataFile != null) {
try { try {
((FileDataTypeManager) dtMgr).save(); if ((languageId != null) != (compilerSpecId != null)) {
dtMgr.close(); 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;
}
}
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) { catch (DuplicateFileException e) {
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save", Msg.showError(this, plugin.getDialog().getComponent(),
"C-Parse Error During Save",
e.getMessage()); e.getMessage());
} }
catch (Exception e) { catch (Exception e) {
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save", Msg.showError(this, plugin.getDialog().getComponent(),
"Could not save to file " + dataFileName, e); "C-Parse Error During Save",
} "Could not save to file " + dataFile.getPath(), e);
finally {
if (dtMgr instanceof FileDataTypeManager) {
dtMgr.close();
} }
} }
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 { else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// no results, was canceled
if (plugin.getParseResults() == null) {
return;
}
MultiLineMessageDialog.showModalMessageDialog( MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(), "Parse Errors", plugin.getDialog().getComponent(),
"File was not created due to parse errors: " + "C-Parse Completed",
((FileDataTypeManager) dtMgr).getFilename(), "Successfully parsed header file(s) to " + getParseDestination(dtMgr),
plugin.getFormattedParseMessage(null), plugin.getFormattedParseMessage(msg),
MultiLineMessageDialog.INFORMATION_MESSAGE); MultiLineMessageDialog.INFORMATION_MESSAGE);
} }
}); });
} }
}
}
catch (ghidra.app.util.cparser.C.ParseException e) { catch (ghidra.app.util.cparser.C.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-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(),
"Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE); 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(),
"PreProcessor Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE); 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(),
"Error During C-Parse",
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE); 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();
}
} }
} }
} }

View file

@ -18,22 +18,15 @@ 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;
@ -43,7 +36,8 @@ public class 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 = "";
@ -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
@ -274,7 +270,8 @@ public class CParserUtils {
* *
*/ */
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 {
@ -282,8 +279,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
* 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
@ -313,18 +312,21 @@ public class CParserUtils {
* *
*/ */
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,31 +351,42 @@ 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,
String languageId, String compileSpecId, TaskMonitor monitor)
throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException { 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 =
parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, monitor);
String messages = results.getFormattedParseMessage(null); String messages = results.getFormattedParseMessage(null);
Msg.info(CParserUtils.class, messages); Msg.info(CParserUtils.class, messages);
dtMgr.save(); dtMgr.save();
success = true;
return dtMgr; 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
@ -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,84 +418,12 @@ 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,
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, 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);
} }
/** /**
@ -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 {
@ -547,7 +485,8 @@ public class CParserUtils {
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,14 +519,17 @@ 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();
@ -617,9 +559,11 @@ 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();
} }
} }
@ -782,7 +726,6 @@ public class CParserUtils {
errorIndex + "<br>" + successFailureBuffer; errorIndex + "<br>" + successFailureBuffer;
} }
public static File getFile(String parent, String filename) { public static File getFile(String parent, String filename) {
File file = findFile(parent, filename); File file = findFile(parent, filename);
if (file != null) { if (file != null) {
@ -811,8 +754,7 @@ public class CParserUtils {
return iFile; return iFile;
// try just in this directory // try just in this directory
File sameiFile = new File(parent + File.separator File sameiFile = new File(parent + File.separator + (new File(filename)).getName());
+ (new File(filename)).getName());
if (sameiFile.exists()) if (sameiFile.exists())
return sameiFile; return sameiFile;

View file

@ -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();
} }
} }

View file

@ -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));

View file

@ -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();
} }