GP-3625 Added simplified FileDataTypeManager factory methods and cleanup of CParser utilities.

This commit is contained in:
ghidra1 2024-12-03 09:43:24 -05:00
parent 81c687d06b
commit c23354b78d
8 changed files with 428 additions and 382 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -31,12 +31,9 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils; import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
public class CreateDefaultGDTArchivesScript extends GhidraScript { public class CreateDefaultGDTArchivesScript extends GhidraScript {
@ -69,16 +66,12 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt"; String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save(); File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames,
includePaths, args, f.getAbsolutePath(), languageID, compiler, monitor);
dtMgr.close(); dtMgr.close();
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -31,11 +31,9 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils; import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg;
public class CreateExampleGDTArchiveScript extends GhidraScript { public class CreateExampleGDTArchiveScript extends GhidraScript {
@ -69,13 +67,9 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
File f = getArchiveFile(dataTypeFile); File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames,
includePaths, args, f.getAbsolutePath(), languageID, compiler, monitor);
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close(); dtMgr.close();
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -16,18 +16,14 @@
package ghidra.app.plugin.core.cparser; package ghidra.app.plugin.core.cparser;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import javax.swing.SwingUtilities;
import docking.ActionContext; import docking.ActionContext;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.action.MenuData; import docking.action.MenuData;
import docking.tool.ToolConstants; import docking.tool.ToolConstants;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.dialogs.MultiLineMessageDialog;
import ghidra.app.CorePluginPackage; import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin; import ghidra.app.plugin.ProgramPlugin;
@ -40,7 +36,8 @@ import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.database.data.ProgramDataTypeManager; import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.data.*; import ghidra.program.model.data.BuiltInDataTypeManager;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.lang.LanguageCompilerSpecPair; import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.*; import ghidra.util.*;
@ -168,9 +165,9 @@ public class CParserPlugin extends ProgramPlugin {
/* /*
* Parse C-source into a data type manager * Parse C-source into a data type manager
*/ */
protected void parse(String[] filenames, String includePaths[], String options, protected CParseResults parse(String[] filenames, String includePaths[], String options,
String languageIDString, String compilerSpecID, DataTypeManager dtMgr, DataTypeManager dtMgr, TaskMonitor monitor)
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException { ghidra.app.util.cparser.CPP.ParseException {
results = null; results = null;
@ -181,43 +178,26 @@ public class CParserPlugin extends ProgramPlugin {
try { try {
openDTmanagers = getOpenDTMgrs(); openDTmanagers = getOpenDTMgrs();
} catch (CancelledException exc) { } catch (CancelledException exc) {
return; // parse canceled return null; // parse canceled
} }
try { results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths, args, dtMgr, monitor);
args, dtMgr, languageIDString, compilerSpecID, monitor);
return results;
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager); }
SwingUtilities.invokeLater(() -> { boolean isOpenInTool(DataTypeManager dtm) {
// CParserTask will show any errors DataTypeManagerService dtService = tool.getService(DataTypeManagerService.class);
if (!results.successful()) { if (dtService == null) {
return; return false;
}
if (isProgramDtMgr) {
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
"C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Program.",
getFormattedParseMessage("Check the Manage Data Types window for added data types."),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
else {
String archiveName = dtMgr.getName();
if (dtMgr instanceof FileDataTypeManager) {
archiveName = ((FileDataTypeManager) dtMgr).getFilename();
}
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
"C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Archive File: " + archiveName,
getFormattedParseMessage(null),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
});
} }
catch (IOException e) { for (DataTypeManager openDtm : dtService.getDataTypeManagers()) {
// ignore if (dtm == openDtm) {
return true;
}
} }
return false;
} }
/** /**
@ -327,11 +307,9 @@ public class CParserPlugin extends ProgramPlugin {
CParserTask parseTask = CParserTask parseTask =
new CParserTask(this, currentProgram.getDataTypeManager()) new CParserTask(this, currentProgram.getDataTypeManager())
.setFileNames(filenames) .setFileNames(filenames)
.setIncludePaths(includePaths) .setIncludePaths(includePaths)
.setOptions(options) .setOptions(options);
.setLanguageID(procID)
.setCompilerID(compilerID);
tool.execute(parseTask); tool.execute(parseTask);
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -16,11 +16,16 @@
package ghidra.app.plugin.core.cparser; package ghidra.app.plugin.core.cparser;
import java.io.File; import java.io.File;
import java.io.IOException;
import javax.help.UnsupportedOperationException;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import docking.widgets.dialogs.MultiLineMessageDialog; import docking.widgets.dialogs.MultiLineMessageDialog;
import ghidra.program.model.data.*; import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.DuplicateFileException; import ghidra.util.exception.DuplicateFileException;
import ghidra.util.task.Task; import ghidra.util.task.Task;
@ -34,18 +39,19 @@ import ghidra.util.task.TaskMonitor;
class CParserTask extends Task { class CParserTask extends Task {
private CParserPlugin plugin; private CParserPlugin plugin;
private String dataFileName;
private String[] filenames; private String[] filenames;
private String[] includePaths; private String[] includePaths;
private String options; private String options;
private String languageString; // Language and Compiler Spec IDs valid only for new dataFileName use
private String compilerString; private String languageId;
private String compilerSpecId;
private DataTypeManager dtMgr; // Either dataTypeManager or dataFileName must be set, but not both
private final DataTypeManager dataTypeManager; // specified for an existing DataTypeManager
private final File dataFile; // specified for a new file
/** /**
* Create task to parse to a dataFile * Create task to parse to a dataFile
@ -55,44 +61,64 @@ class CParserTask extends Task {
*/ */
CParserTask(CParserPlugin plugin, String dataFileName) { CParserTask(CParserPlugin plugin, String dataFileName) {
super("Parsing C Files", true, false, false); super("Parsing C Files", true, false, false);
dataTypeManager = null;
this.plugin = plugin; this.plugin = plugin;
this.dataFileName = dataFileName; this.dataFile = new File(dataFileName);
} }
/** /**
* Create task to parse to a dataTypeManager * Create task to parse to a dataTypeManager
* *
* @param plugin * NOTE: The Language ID and Compiler Spec ID must not be set since the dataTypeManager's
* @param dataTypeManager * current architecture will be used.
*
* @param plugin CParserPlugin that will do the work
* @param dataTypeManager target data type manager
*/ */
public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) { public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
super("Parsing C Files", true, false, false); super("Parsing C Files", true, false, false);
dataFile = null;
this.plugin = plugin; this.plugin = plugin;
this.dtMgr = dataTypeManager; this.dataTypeManager = dataTypeManager;
} }
/** /**
* Create task to parse to a ProgramDataTypeManager * Set the language ID to be used.
* *
* @param plugin * NOTE: The compiler spec ID must also be set, see {@code #setCompilerID(String)}.
* @param dataTypeManager * See language *.ldefs file for defined compiler spec IDs or existing Program info.
*
* @param languageId language ID
* @return this task
* @throws UnsupportedOperationException if task was constructed with a DataTypeManager whose
* existing architecture will be used.
*/ */
public CParserTask(CParserPlugin plugin, ProgramBasedDataTypeManager dataTypeManager) { public CParserTask setLanguageID(String languageId) {
super("Parsing C Files", true, false, false); if (dataTypeManager != null) {
throw new UnsupportedOperationException(
this.plugin = plugin; "setLanguageID not supported when constructed with DataTypeManager");
this.dtMgr = dataTypeManager; }
} this.languageId = languageId;
public CParserTask setLanguageID(String languageID) {
this.languageString = languageID;
return this; return this;
} }
public CParserTask setCompilerID(String compilerID) { /**
this.compilerString = compilerID; * Set the compiler spec ID to be used. This ID must be defined for the specified language.
*
* NOTE: The language ID must also be set, see {@code #setLanguageID(String)}.
* See language *.ldefs file for defined compiler spec IDs or existing Program info.
*
* @param compilerSpecId compiler spec ID
* @return this task
* @throws UnsupportedOperationException if task was constructed with a DataTypeManager whose
* existing architecture will be used.
*/
public CParserTask setCompilerID(String compilerSpecId) {
if (dataTypeManager != null) {
throw new UnsupportedOperationException(
"setLanguageID not supported when constructed with DataTypeManager");
}
this.compilerSpecId = compilerSpecId;
return this; return this;
} }
@ -120,96 +146,142 @@ class CParserTask extends Task {
return msg; return msg;
} }
private String getResultMessage(DataTypeManager dtMgr, int initialDtCount) {
int finalDtCount = dtMgr.getDataTypeCount(true) - initialDtCount;
String msg = (finalDtCount == 0 ? "No" : Integer.toString(finalDtCount)) +
" Data Types added.";
if (finalDtCount != 0 && plugin.isOpenInTool(dtMgr)) {
msg += "\nCheck the Data Type Manager window for added data types.";
}
return msg;
}
private String getParseDestination(DataTypeManager dtMgr) {
String parseDest = "";
if (dtMgr instanceof ProgramDataTypeManager) {
parseDest = "Program " + dtMgr.getName();
}
else if (dtMgr instanceof FileDataTypeManager fileDtm) {
parseDest = "Archive File: " + fileDtm.getFilename();
}
else {
parseDest = dtMgr.getName();
}
return parseDest;
}
@Override @Override
public void run(TaskMonitor monitor) { public void run(TaskMonitor monitor) {
DataTypeManager fileDtMgr = null;
try {
if (dtMgr == null) {
File file = new File(dataFileName);
dtMgr = FileDataTypeManager.createFileArchive(file);
fileDtMgr = dtMgr;
}
plugin.parse(filenames, includePaths, options, languageString, compilerString, dtMgr, monitor); FileDataTypeManager fileDtMgr = null;
if (dataFileName != null) { if (dataFile != null) {
// TODO: does not consider existing datatypes try {
if (dtMgr.getDataTypeCount(true) != 0) { if ((languageId != null) != (compilerSpecId != null)) {
try { Msg.showError(this, plugin.getDialog().getComponent(), "Archive Failure",
((FileDataTypeManager) dtMgr).save(); "Language/CompilerSpec improperly specified: " + languageId + "/" +
dtMgr.close(); compilerSpecId);
} return;
catch (DuplicateFileException e) {
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save",
e.getMessage());
}
catch (Exception e) {
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save",
"Could not save to file " + dataFileName, e);
}
finally {
if (dtMgr instanceof FileDataTypeManager) {
dtMgr.close();
}
}
}
else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// no results, was canceled
if (plugin.getParseResults() == null) {
return;
}
MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(), "Parse Errors",
"File was not created due to parse errors: " +
((FileDataTypeManager) dtMgr).getFilename(),
plugin.getFormattedParseMessage(null),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
});
} }
fileDtMgr =
FileDataTypeManager.createFileArchive(dataFile, languageId, compilerSpecId);
}
catch (IOException e) {
Msg.showError(this, plugin.getDialog().getComponent(), "Archive Failure",
"Failed to create archive datatype manager: " + e.getMessage());
return;
} }
} }
catch (ghidra.app.util.cparser.C.ParseException e) {
final String errMsg = e.getMessage(); DataTypeManager dtMgr = fileDtMgr != null ? fileDtMgr : dataTypeManager;
System.err.println(errMsg);
SwingUtilities.invokeLater(new Runnable() { int initialDtCount = dtMgr.getDataTypeCount(true);
@Override
public void run() { try {
String msg = getFirstMessageLine(errMsg);
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(), CParseResults results = plugin.parse(filenames, includePaths, options, dtMgr, monitor);
"Parse Errors", msg, plugin.getFormattedParseMessage(errMsg), if (results == null) {
MultiLineMessageDialog.ERROR_MESSAGE); return; // cancelled
}
if (fileDtMgr != null && dtMgr.getDataTypeCount(true) != 0) {
// If archive created - save to file
try {
fileDtMgr.save();
} }
catch (DuplicateFileException e) {
Msg.showError(this, plugin.getDialog().getComponent(),
"C-Parse Error During Save",
e.getMessage());
}
catch (Exception e) {
Msg.showError(this, plugin.getDialog().getComponent(),
"C-Parse Error During Save",
"Could not save to file " + dataFile.getPath(), e);
}
}
String msg = getResultMessage(dtMgr, initialDtCount);
SwingUtilities.invokeLater(() -> {
if (!results.successful()) {
MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(), "C-Parse Failed",
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
plugin.getFormattedParseMessage(msg),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
else {
MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(),
"C-Parse Completed",
"Successfully parsed header file(s) to " + getParseDestination(dtMgr),
plugin.getFormattedParseMessage(msg),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
});
}
catch (ghidra.app.util.cparser.C.ParseException e) {
final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
SwingUtilities.invokeLater(() -> {
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
"C-Parse Failed",
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE);
}); });
} }
catch (ghidra.app.util.cparser.CPP.ParseException e) { catch (ghidra.app.util.cparser.CPP.ParseException e) {
final String errMsg = e.getMessage(); final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
System.err.println(errMsg); SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(new Runnable() { MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
@Override "C-PreProcessor Parse Failed",
public void run() { "Failed to parse header file(s) to " + getParseDestination(dtMgr),
String msg = getFirstMessageLine(errMsg); plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(), MultiLineMessageDialog.ERROR_MESSAGE);
"PreProcessor Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE);
}
}); });
} }
catch (Exception e) { catch (Exception e) {
final String errMsg = e.getMessage(); final String errMsg = getResultMessage(dtMgr, initialDtCount) + "\n\n" + e.getMessage();
String msg = getFirstMessageLine(errMsg); Msg.showError(this, plugin.getDialog().getComponent(), "Error During C-Parse",
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Parse",
"Parse header files failed" + "\n\nParser Messages:\n" + plugin.getParseMessage(), "Parse header files failed" + "\n\nParser Messages:\n" + plugin.getParseMessage(),
e); e);
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(), SwingUtilities.invokeLater(() -> {
"Error During Parse", msg, plugin.getFormattedParseMessage(errMsg), MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
MultiLineMessageDialog.ERROR_MESSAGE); "Error During C-Parse",
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE);
});
} }
finally { finally {
if (fileDtMgr != null) { if (fileDtMgr != null) {
boolean deleteFile = fileDtMgr.getDataTypeCount(true) == 0;
fileDtMgr.close(); fileDtMgr.close();
if (deleteFile) {
dataFile.delete();
}
} }
} }
} }

View file

@ -18,32 +18,26 @@ package ghidra.app.util.cparser.C;
import java.io.*; import java.io.*;
import java.util.Arrays; import java.util.Arrays;
import javax.help.UnsupportedOperationException;
import generic.theme.GThemeDefaults.Colors; import generic.theme.GThemeDefaults.Colors;
import generic.theme.GThemeDefaults.Colors.Messages; import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.services.DataTypeManagerService; import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.CPP.PreProcessor; import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.plugintool.ServiceProvider; import ghidra.framework.plugintool.ServiceProvider;
import ghidra.framework.store.LockException;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class CParserUtils { public class CParserUtils {
private CParserUtils() { private CParserUtils() {
// utils class // utils class
} }
public record CParseResults(PreProcessor preProcessor, String cppParseMessages, String cParseMessages, boolean successful) { public record CParseResults(PreProcessor preProcessor, String cppParseMessages,
String cParseMessages, boolean successful) {
public String getFormattedParseMessage(String errMsg) { public String getFormattedParseMessage(String errMsg) {
String message = ""; String message = "";
@ -62,7 +56,7 @@ public class CParserUtils {
} }
return message; return message;
} }
} }
/** /**
@ -245,8 +239,10 @@ public class CParserUtils {
} }
/** /**
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager * Parse a set of C Header files and associated parsing arguments, returning a new File
* with in the provided dataFileName. * Data TypeManager with in the provided dataFileName. The resulting archive
* will not be associated with a specific language/compiler and will use the default
* data organization.
* *
* Note: Using another open archive while parsing will cause: * Note: Using another open archive while parsing will cause:
* - a dependence on the other archive * - a dependence on the other archive
@ -273,17 +269,20 @@ public class CParserUtils {
* @throws IOException if there io are errors saving the archive * @throws IOException if there io are errors saving the archive
* *
*/ */
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName, public static FileDataTypeManager parseHeaderFiles(DataTypeManager[] openDTMgrs,
String[] filenames, String[] args, String dataFileName,
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException { ghidra.app.util.cparser.CPP.ParseException, IOException {
return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor); return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor);
} }
/** /**
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager * Parse a set of C Header files and associated parsing arguments, returning a new
* with in the provided dataFileName. * File Data TypeManager with in the provided dataFileName. The resulting archive
* will not be associated with a specific language/compiler and will use the default
* data organization.
* *
* Note: Using another open archive while parsing will cause: * Note: Using another open archive while parsing will cause:
* - a dependence on the other archive * - a dependence on the other archive
@ -312,19 +311,22 @@ public class CParserUtils {
* @throws IOException if there io are errors saving the archive * @throws IOException if there io are errors saving the archive
* *
*/ */
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName, public static FileDataTypeManager parseHeaderFiles(DataTypeManager[] openDTMgrs,
String[] filenames, String[] includePaths, String[] args, String dataFileName,
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException { ghidra.app.util.cparser.CPP.ParseException, IOException {
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null, monitor); return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null,
monitor);
} }
/** /**
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager * Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
* with in the provided dataFileName. * with in the provided dataFileName.
* *
* When parsing is complete any parser messages will be logged.
*
* Note: Using another open archive while parsing will cause: * Note: Using another open archive while parsing will cause:
* - a dependence on the other archive * - a dependence on the other archive
* - any missing data types while parsing are supplied if present from an openDTMgr * - any missing data types while parsing are supplied if present from an openDTMgr
@ -333,7 +335,7 @@ public class CParserUtils {
* *
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent. * NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
* *
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof() * NOTE: Providing the correct languageId and compileSpecId is very important for header files that might use sizeof()
* *
* @param openDTMgrs array of datatypes managers to use for undefined data types * @param openDTMgrs array of datatypes managers to use for undefined data types
* *
@ -349,32 +351,43 @@ public class CParserUtils {
* *
* @param monitor used to cancel or provide results * @param monitor used to cancel or provide results
* *
* @return the data types in the ghidra .gdt archive file * @return the FileDataTypeManager corresponding to the Ghidra .gdt archive file.
* The caller is responsible for closing the instance.
* *
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
* @throws IOException if there io are errors saving the archive * @throws IOException if there io are errors saving the archive
* *
*/ */
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName, public static FileDataTypeManager parseHeaderFiles(DataTypeManager[] openDTMgrs,
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, String[] filenames, String[] includePaths, String[] args, String dataFileName,
ghidra.app.util.cparser.CPP.ParseException, IOException { String languageId, String compileSpecId, TaskMonitor monitor)
throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
File file = new File(dataFileName); File file = new File(dataFileName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file); FileDataTypeManager dtMgr =
FileDataTypeManager.createFileArchive(file, languageId, compileSpecId);
CParseResults results; boolean success = false;
results = parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, languageId, compileSpecId, monitor); try {
CParseResults results =
String messages = results.getFormattedParseMessage(null); parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, monitor);
Msg.info(CParserUtils.class, messages);
String messages = results.getFormattedParseMessage(null);
dtMgr.save(); Msg.info(CParserUtils.class, messages);
return dtMgr; dtMgr.save();
}
success = true;
return dtMgr;
}
finally {
if (!success) {
dtMgr.close();
}
}
}
/** /**
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided * Parse a set of C Header files and associated parsing arguments, data types are added to the provided
* DTMgr. * DTMgr.
@ -387,7 +400,6 @@ public class CParserUtils {
* *
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent. * NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
* *
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
* @param openDTMgrs array of datatypes managers to use for undefined data types * @param openDTMgrs array of datatypes managers to use for undefined data types
* *
* @param filenames names of files in order to parse, could include strings with * @param filenames names of files in order to parse, could include strings with
@ -395,10 +407,7 @@ public class CParserUtils {
* @param args arguments for parsing, {@code -D<defn>=}, ({@code -I<includepath>} use * @param args arguments for parsing, {@code -D<defn>=}, ({@code -I<includepath>} use
* includePaths parm instead) * includePaths parm instead)
* *
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr * @param dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
*
* @param languageId language identification to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing
* *
* @param monitor used to cancel or provide results * @param monitor used to cancel or provide results
* *
@ -409,86 +418,14 @@ public class CParserUtils {
* @throws IOException if there io are errors saving the archive * @throws IOException if there io are errors saving the archive
* *
*/ */
public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr, public static CParseResults parseHeaderFiles(DataTypeManager[] openDTMgrs, String[] filenames,
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, String[] args, DataTypeManager dtMgr,
ghidra.app.util.cparser.CPP.ParseException, IOException { TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
return parseHeaderFiles(openDTMgrs, filenames, null, args, existingDTMgr, languageId, compileSpecId, monitor);
} return parseHeaderFiles(openDTMgrs, filenames, null, args, dtMgr, monitor);
}
/**
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided
* DTMgr.
*
* Note: Using another open archive while parsing will cause:
* - a dependence on the other archive
* - any missing data types while parsing are supplied if present from an openDTMgr
* - after parsing all data types parsed with an equivalent data type in any openDTMgr
* replaced by the data type from the openDTMgr
*
* NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
*
* NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
* @param openDTMgrs array of datatypes managers to use for undefined data types
*
* @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments
* @param includePaths paths to include files, instead of using {@code -I<includepath>} in args
* @param args arguments for parsing, {@code -D<defn>=}, ( {@code -I<includepath>} use includePaths parm instead)
*
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
*
* @param languageId language identification to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing
*
* @param monitor used to cancel or provide results
*
* @return a formatted string of any output from pre processor parsing or C parsing
*
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
* @throws IOException if there io are errors saving the archive
*
*/
public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], DataTypeManager existingDTMgr,
String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId));
CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId));
if (existingDTMgr instanceof StandAloneDataTypeManager) {
try {
((StandAloneDataTypeManager) existingDTMgr).setProgramArchitecture(language, compilerSpec.getCompilerSpecID(),
StandAloneDataTypeManager.LanguageUpdateOption.UNCHANGED, monitor);
}
catch (CompilerSpecNotFoundException e) {
e.printStackTrace();
}
catch (LanguageNotFoundException e) {
e.printStackTrace();
}
catch (CancelledException e) {
// ignore
}
catch (LockException e) {
e.printStackTrace();
}
catch (UnsupportedOperationException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (IncompatibleLanguageException e) {
// Shouldn't happen, unless already had a language
e.printStackTrace();
}
}
return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, existingDTMgr, monitor);
}
/** /**
* Parse a set of C Header files and associated parsing arguments, data types are added to the provided * Parse a set of C Header files and associated parsing arguments, data types are added to the provided
* DTMgr. * DTMgr.
@ -522,8 +459,9 @@ public class CParserUtils {
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
*/ */
public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, String[] includePaths, public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers,
String args[], DataTypeManager dtMgr, TaskMonitor monitor) String[] filenames, String[] includePaths,
String[] args, DataTypeManager dtMgr, TaskMonitor monitor)
throws ghidra.app.util.cparser.C.ParseException, throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException { ghidra.app.util.cparser.CPP.ParseException {
@ -534,9 +472,9 @@ public class CParserUtils {
cpp.addIncludePaths(includePaths); cpp.addIncludePaths(includePaths);
PrintStream os = System.out; PrintStream os = System.out;
String fName = dtMgr.getName(); String fName = dtMgr.getName();
// make a path to tmpdir with name of data type manager // make a path to tmpdir with name of data type manager
String path = new File(Application.getUserTempDirectory(), fName).getAbsolutePath(); String path = new File(Application.getUserTempDirectory(), fName).getAbsolutePath();
// if file data type manager, use path to .gdt file // if file data type manager, use path to .gdt file
@ -544,10 +482,11 @@ public class CParserUtils {
path = ((FileDataTypeManager) dtMgr).getPath(); path = ((FileDataTypeManager) dtMgr).getPath();
} }
path = path + "_CParser.out"; path = path + "_CParser.out";
try { try {
os = new PrintStream(new FileOutputStream(path)); os = new PrintStream(new FileOutputStream(path));
} catch (FileNotFoundException e2) { }
catch (FileNotFoundException e2) {
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2); Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
} }
// cpp.setOutputStream(os); // cpp.setOutputStream(os);
@ -580,26 +519,29 @@ public class CParserUtils {
parseFile(child.getAbsolutePath(), monitor, cpp); parseFile(child.getAbsolutePath(), monitor, cpp);
} }
} }
} else { }
else {
parseFile(filename, monitor, cpp); parseFile(filename, monitor, cpp);
} }
} }
parseSucceeded = true; parseSucceeded = true;
} catch (Throwable e) { }
catch (Throwable e) {
Msg.info(cpp, cpp.getParseMessages()); Msg.info(cpp, cpp.getParseMessages());
} finally { }
finally {
System.out.println(bos); System.out.println(bos);
os.flush(); os.flush();
os.close(); os.close();
System.setOut(old); System.setOut(old);
} }
cppMessages = cpp.getParseMessages(); cppMessages = cpp.getParseMessages();
if (!parseSucceeded) { if (!parseSucceeded) {
return new CParseResults(cpp, "", cppMessages, false); return new CParseResults(cpp, "", cppMessages, false);
} }
// process all the defines and add any that are integer values into // process all the defines and add any that are integer values into
// the Equates table // the Equates table
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr); cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
@ -608,7 +550,7 @@ public class CParserUtils {
boolean cparseSucceeded = false; boolean cparseSucceeded = false;
if (!monitor.isCancelled()) { if (!monitor.isCancelled()) {
monitor.setMessage("Parsing C"); monitor.setMessage("Parsing C");
CParser cParser = new CParser(dtMgr, true, openDTmanagers); CParser cParser = new CParser(dtMgr, true, openDTmanagers);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
try { try {
@ -617,16 +559,18 @@ public class CParserUtils {
cParser.setMonitor(monitor); cParser.setMonitor(monitor);
cParser.parse(bis); cParser.parse(bis);
cparseSucceeded = cParser.didParseSucceed(); cparseSucceeded = cParser.didParseSucceed();
} catch (RuntimeException re) { }
catch (RuntimeException re) {
Msg.info(cpp, cpp.getParseMessages()); Msg.info(cpp, cpp.getParseMessages());
} finally { }
finally {
parserMessages = cParser.getParseMessages(); parserMessages = cParser.getParseMessages();
} }
} }
return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded); return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
} }
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp) private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
throws ghidra.app.util.cparser.CPP.ParseException { throws ghidra.app.util.cparser.CPP.ParseException {
monitor.setMessage("PreProcessing " + filename); monitor.setMessage("PreProcessing " + filename);
@ -640,10 +584,10 @@ public class CParserUtils {
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage()); throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
} }
return cpp.getParseMessages(); return cpp.getParseMessages();
} }
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) { private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
if (service == null) { if (service == null) {
@ -782,54 +726,52 @@ public class CParserUtils {
errorIndex + "<br>" + successFailureBuffer; errorIndex + "<br>" + successFailureBuffer;
} }
public static File getFile(String parent, String filename) {
File file = findFile(parent, filename);
if (file != null) {
return file;
}
// filename lower
file = findFile(parent, filename.toLowerCase());
if (file != null) {
return file;
}
// parent and filename lower
file = findFile(parent.toLowerCase(), filename.toLowerCase());
if (file != null) {
return file;
}
// parent and filename upper
file = findFile(parent.toUpperCase(), filename.toUpperCase());
return file;
}
public static File getFile(String parent, String filename) { private static File findFile(String parent, String filename) {
File file = findFile(parent, filename); File iFile = null;
if (file != null) {
return file;
}
// filename lower
file = findFile(parent, filename.toLowerCase());
if (file != null) {
return file;
}
// parent and filename lower
file = findFile(parent.toLowerCase(), filename.toLowerCase());
if (file != null) {
return file;
}
// parent and filename upper
file = findFile(parent.toUpperCase(), filename.toUpperCase());
return file;
}
private static File findFile(String parent, String filename) { iFile = new File(parent + File.separator + filename);
File iFile = null; if (iFile.exists())
return iFile;
iFile = new File(parent + File.separator + filename); // try just in this directory
if (iFile.exists()) File sameiFile = new File(parent + File.separator + (new File(filename)).getName());
return iFile; if (sameiFile.exists())
return sameiFile;
// try just in this directory // try all files in this directory doing to-lower on both input file and output file
File sameiFile = new File(parent + File.separator // if match return it
+ (new File(filename)).getName()); File folder = new File(parent);
if (sameiFile.exists()) if (folder.isDirectory()) {
return sameiFile; File[] listOfFiles = folder.listFiles();
// try all files in this directory doing to-lower on both input file and output file if (listOfFiles != null) {
// if match return it for (File file : listOfFiles) {
File folder = new File(parent); if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
if (folder.isDirectory()) { return file;
File[] listOfFiles = folder.listFiles(); }
}
if (listOfFiles != null) { }
for (File file : listOfFiles) { }
if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) { return null;
return file; }
}
}
}
}
return null;
}
} }

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

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -32,9 +32,7 @@ import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils; import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.CParserUtils.CParseResults; import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.CPP.DefineTable; import ghidra.app.util.cparser.CPP.*;
import ghidra.app.util.cparser.CPP.ParseException;
import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.util.AddressEvaluator; import ghidra.program.util.AddressEvaluator;
@ -127,7 +125,8 @@ public class CreateAVR8GDTArchiveScript extends GhidraScript {
File f = getArchiveFile(dataTypeFile); File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); FileDataTypeManager dtMgr =
FileDataTypeManager.createFileArchive(f, "avr8:LE:16:atmega256", "gcc");
// Parse each processor variant as an individual parse that gets added to the data // Parse each processor variant as an individual parse that gets added to the data
// type manager. If all header files were parsed at once, there are conflicting // type manager. If all header files were parsed at once, there are conflicting
@ -178,7 +177,7 @@ public class CreateAVR8GDTArchiveScript extends GhidraScript {
String args[] = Arrays.append(orig_args, "-D__AVR_" + procName + "__"); String args[] = Arrays.append(orig_args, "-D__AVR_" + procName + "__");
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr,
"avr8:LE:16:atmega256", "gcc", monitor); monitor);
Msg.info(this, results.getFormattedParseMessage(null)); Msg.info(this, results.getFormattedParseMessage(null));

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -33,11 +33,9 @@ import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility; import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils; import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg;
public class CreateJNIGDTArchivesScript extends GhidraScript { public class CreateJNIGDTArchivesScript extends GhidraScript {
@ -63,13 +61,9 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
File f = getArchiveFile(dataTypeFile); File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames, null, args,
f.getAbsolutePath(), languageID, compiler, monitor);
CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, monitor);
Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close(); dtMgr.close();
} }