GP-1979_emteere better error reporting and handling of newer cspec idioms NoReturn, anonymous function arrays and parameters, #pragma use, Thread_local, Alignas, allow '#' comment out filename, added parsing scripts

This commit is contained in:
emteere 2022-10-12 21:50:02 -04:00
parent 35b58b3105
commit ffae7232cb
25 changed files with 5367 additions and 2072 deletions

View File

@ -20,9 +20,9 @@ data/file_extension_icons.xml||GHIDRA||||END|
data/functionTags.xml||GHIDRA||||END|
data/ms_pe_rich_products.xml||GHIDRA||||END|
data/noReturnFunctionConstraints.xml||GHIDRA||||END|
data/parserprofiles/MacOSX_10.5.prf||GHIDRA||reviewed||END|
data/parserprofiles/MacOSX_10.5.prf||GHIDRA||||END|
data/parserprofiles/MacOSX_10.9.prf||GHIDRA||||END|
data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||reviewed||END|
data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio12_32.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio12_64.prf||GHIDRA||||END|
data/parserprofiles/VisualStudio9.prf||GHIDRA||reviewed||END|
@ -31,7 +31,7 @@ data/parserprofiles/generic_clib_32.prf||GHIDRA||||END|
data/parserprofiles/generic_clib_64.prf||GHIDRA||||END|
data/parserprofiles/linux_32.prf||GHIDRA||||END|
data/parserprofiles/linux_64.prf||GHIDRA||||END|
data/parserprofiles/objc_mac_carbon.prf||GHIDRA||reviewed||END|
data/parserprofiles/objc_mac_carbon.prf||GHIDRA||||END|
data/parserprofiles/vs12Local.prf||GHIDRA||||END|
data/pcodetest/EmuTesting.gdt||GHIDRA||||END|
data/stringngrams/StringModel.sng||GHIDRA||reviewed||END|

View File

@ -207,7 +207,6 @@ zlib.h
-DTARGET_API_MAC_OSX
-DTARGET_COCOA
-DHANDLE="unsigned long"
-D_Bool="BOOL"
-D_WCHAR_T
-D_Complex
-Drestrict

View File

@ -323,7 +323,6 @@ zlib.h
-D_MAC_
-DTARGET_API_MAC_OSX
-DHANDLE="unsigned long"
-D_Bool="BOOL"
-D_WCHAR_T
-D_Complex
-Drestrict

View File

@ -28,7 +28,6 @@ Cocoa\Cocoa.h
-D_MAC_
-DTARGET_API_MAC_OSX=1
-DHANDLE="unsigned long"
-D_Bool="BOOL"
-D_WCHAR_T
-D_Complex
-Drestrict

View File

@ -236,6 +236,5 @@ arpa/tftp.h
-D__NO_LONG_DOUBLE_MATH
-D__signed__
-D__extension__=""
-D_Bool="bool"
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t

View File

@ -235,7 +235,6 @@ arpa/tftp.h
-D__NO_STRING_INLINES
-D__signed__
-D__extension__=""
-D_Bool="bool"
-D__GLIBC_HAVE_LONG_LONG=1
-D__need_sigset_t
-Daligned_u64=uint64_t

View File

@ -533,6 +533,5 @@ auth_gssapi.h
-D__NO_LONG_DOUBLE_MATH
-D__signed__
-D__extension__=""
-D_Bool="bool"
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t

View File

@ -532,6 +532,5 @@ auth_gssapi.h
-D__NO_STRING_INLINES
-D__signed__
-D__extension__=""
-D_Bool="bool"
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t

View File

@ -380,4 +380,3 @@ WSTypes.h
-DTARGET_API_MAC_OSX
-DTARGET_CARBON
-DHANDLE="unsigned long"
-D_Bool="BOOL"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,499 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Parses preview of VS22 and DirectX to .gdt archive files
//
// To replace existing header files and have the data type ID's synchronized
//
// Must run SynchronizeGDTCategoryPaths.java script with old and replacement GDT
// archive to synchronize upper/lower case paths
/// (only on windows archives)
//
// Then Run DataTypeArchiveTransformer in eclipse to synchronize old data types ID's
//
//@category Data Types
import java.io.File;
import java.io.IOException;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg;
public class CreateExampleGDTArchiveScript extends GhidraScript {
private File outputDirectory;
// location of header files base directory
private static String headerFilePath = "/data/HeaderFiles";
@Override
protected void run() throws Exception {
outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir");
parseGDT_DirectX();
parseGDT_WinVS22();
}
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
DataTypeManager openTypes[] = null;
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args);
}
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
Msg.info(this, messages);
dtMgr.save();
dtMgr.close();
}
/**
* Turn string into a file, delete old archive if it exists
*
* @param dataTypeFile
*
* @return file
*/
private File getArchiveFile(String dataTypeFile) {
File f = new File(dataTypeFile);
if (f.exists()) {
f.delete();
}
String lockFile = dataTypeFile + ".ulock";
File lf = new File(lockFile);
if (lf.exists()) {
lf.delete();
}
return f;
}
public void parseGDT_DirectX() throws Exception {
String filenames[] = {
"SDKDDKVer.h",
"Windows.h",
"winnt.h",
"windowsx.h",
"ddraw.h",
"d3d.h",
"dinput.h",
"mmreg.h",
"dsound.h",
};
String args[] = {
"-I"+headerFilePath+"/VC/VS22/10.0.190141.0",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
"-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
"-D_AMD64_",
"-D_M_AMD64",
"-D_M_X64",
"-D_WIN64",
"-D_WIN32",
"-v0",
};
parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, args);
}
public void parseGDT_WinVS22() throws Exception {
String filenames[] = {
"# Core necessary files",
"winapifamily.h",
"winpackagefamily.h",
"sdkddkver.h",
"sal.h",
"no_sal2.h",
"corecrt.h",
"wtypes.h",
"winnt.h",
"winternl.h",
"#ntdef.h",
"# Common headers ",
"dos.h",
"errno.h",
"malloc.h",
"signal.h",
"stdalign.h",
"stddef.h",
"stdio.h",
"stdlib.h",
"assert.h",
"crtdbg.h",
"ctype.h",
"conio.h",
"direct.h",
"fcntl.h",
"float.h",
"fpieee.h",
"inttypes.h",
"io.h",
"locale.h",
"complex.h",
"math.h",
"mbctype.h",
"mbstring.hs",
"memory.h",
"minmax.h",
"new.h",
"process.h",
"search.h",
"share.h",
"winbase.h",
"winuser.h",
"Windows.h",
"# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)",
"accctrl.h",
"aclapi.h",
"aclui.h",
"advapi32.h",
"adtgen.h",
"authz.h",
"azroles.h",
"bcrypt.h",
"casetup.h",
"ccgplugins.h",
"celib.h",
"ntlsa.h",
"sspi.h",
"ntsecapi.h",
"ntsecpkg.h",
"schannel.h",
"certadm.h",
"certbcli.h",
"certcli.h",
"certenroll.h",
"certexit.h",
"certif.h",
"certmod.h",
"certpol.h",
"certpoleng.h ",
"certsrv.h",
"certview.h",
"credssp.h",
"cryptdlg.h",
"cryptuiapi.h",
"cryptxml.h",
"diagnosticdataquery.h",
"diagnosticdataquerytypes.h",
"dpapi.h",
"dssec.h",
"iads.h",
"identitycommon.h",
"identityproviders.h",
"identitystore.h",
"keycredmgr.h",
"lmaccess.h",
"lsalookup.h",
"mmcobj.h",
"mscat.h",
"mssip.h",
"namedpipeapi.h",
"ncrypt.h",
"ncryptprotect.h",
"npapi.h",
"processthreadsapi.h",
"sas.h",
"scesvc.h",
"sddl.h",
"securityappcontainer.h",
"securitybaseapi.h",
"slpublic.h",
"subauth.h",
"tokenbinding.h",
"tpmsvcmgr.h",
"wincred.h",
"wincrypt.h",
"winnetwk.h",
"winreg.h",
"winsafer.h",
"winscard.h",
"winsvc.h",
"wintrust.h",
"winwlx.h",
"xenroll.h",
"# Windows sockets",
"af_irda.h",
"in6addr.h",
"mstcpip.h",
"ws2def.h",
"winsock.h",
"winsock2.h",
"nsemail.h",
"nspapi.h",
"socketapi.h",
"# Nothing includes this; is it necessary?",
"#sporder.h",
"transportsettingcommon.h",
"ws2atm.h",
"ws2spi.h",
"mswsock.h",
"ws2tcpip.h",
"wsipv6ok.h",
"wslwlink.h",
"wsrm.h",
"mswsockdef.h",
"# Remote Procedure Call (RPC)",
"midles.h",
"midlbase.h",
"rpc.h",
"rpcndr.h",
"rpcasync.h",
"rpcdcep.h",
"rpcnsi.h",
"rpcproxy.h",
"rpcssl.h",
"# COM",
"accctrl.h",
"callobj.h",
"combaseapi.h",
"comcat.h",
"ctxtcall.h",
"dmerror.h",
"docobj.h",
"eventsys.h",
"guiddef.h",
"iaccess.h",
"hstring.h",
"imessagedispatcher.h",
"messagedispatherapi.h",
"objbase.h",
"objidlbase.h",
"objidl.h",
"ocidl.h",
"ole.h",
"ole2.h",
"oledlg.h",
"oleidl.h",
"roapi.h",
"rpcdce.h",
"servprov.h",
"shobjidl.h",
"txlogpub.h",
"unknwnbase.h",
"unknwn.h",
"urlmon.h",
"vbinterf.h",
"winddi.h",
"winerror.h",
"wtypesbase.h",
"# COM+",
"comadmin.h",
"mtxdm.h",
"# More",
"inspectable.h",
"# Windows Internet",
"proofofpossessioncookieinfo.h",
"wininet.h",
"winineti.h",
"# Windows HTTP Services",
"winhttp.h",
"# Compression",
"compressapi.h",
"# TraceLogging",
"#traceloggingactivity.h",
"#traceloggingprovider.h",
"# Windows Error Reporting",
"errorrep.h",
"werapi.h",
"# Windows and MEssages",
"olectl.h",
"windef.h",
"windowsx.h",
"# Shell",
"appmgmt.h",
"appnotify.h",
"cpl.h",
"credentialprovider.h",
"dimm.h",
"imagetranscode.h",
"inputpanelconfiguration.h",
"intsafe.h",
"intshcut.h",
"mobsync.h",
"objectarray.h",
"pathcch.h",
"profinfo.h",
"propkeydef.h",
"scrnsave.h",
"shappmgr.h",
"shdeprecated.h",
"shidfact.h",
"shimgdata.h",
"shlwapi.h",
"shtypes.h",
"storageprovider.h",
"syncmgr.h",
"thumbcache.h",
"thumbnailstreamcache.h",
"tlogstg.h",
"usereng.h",
"# Windows Controls",
"commctrl.h",
"commoncontrols.h",
"dpa_dsa.h",
"prsht.h",
"richedit.h",
"richole.h",
"shlobj_core.h",
"shlobj.h",
"#textserv.h", // C++
"tom.h",
"uxtheme.h",
"# Menus and other resources",
"resourceindexer.h",
"strsafe.h",
"verrsrc.h",
"winver.h",
"# Windows Accessibility Features",
"oleacc.h",
"uiautomationcore.h",
"uiautomationclient.h",
"uiautomationcoreapi.h",
"# Internationalization",
"datetimeapi.h",
"elscore.h",
"gb18030.h",
"imepad.h",
"imm.h",
"immdev.h",
"msime.h",
"msimeapi.h",
"muiload.h",
"spellcheck.h",
"spellcheckprovider.h",
"stringapiset.h",
"usp10.h",
"winnls.h",
"# HTTP Server API",
"#http.h", // included by something else
"# IP Helper",
"#icmpapi.h", // Something wrong with IP_ADDR
"ifdef.h",
"inaddr.h",
"ip2string.h",
"ipexport.h",
"iphlpapi.h",
"iprtrmib.h",
"iptypes.h",
"netioapi.h",
"nldef.h",
"tcpestats.h",
"ws2ipdef.h",
"# Network Management",
"atacct.h",
"lmalert.h",
"lmapibuf.h",
"lmat.h",
"lmaudit.h",
"lmconfig.h",
"lmerrlog.h",
"lmjoin.h",
"lmmsg.h",
"lmremutl.h",
"lmserver.h",
"lmsvc.h",
"lmuse.h",
"lmwksta.h"
};
String args[] = {
"-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um",
"-I"+headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
"-D_MSC_VER=1924",
"-D_INTEGRAL_MAX_BITS=64",
"-DWINVER=0x0a00",
"-D_WIN32_WINNT=0x0a00",
"-D_AMD64_",
"-D_M_AMD64",
"-D_M_X64",
"-D_WIN64",
"-D_WIN32",
"-D_USE_ATTRIBUTES_FOR_SAL",
"-D_CRTBLD",
"-D_OPENMP_NOFORCE_MANIFEST",
"-DSTRSAFE_LIB",
"-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM",
"-D_WCHAR_T_DEFINED",
"-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS",
"-D_CRT_NONSTDC_NO_DEPRECATE",
"-D_CRT_NONSTDC_NO_WARNINGS",
"-D_CRT_OBSOLETE_NO_DEPRECATE",
"-D_ALLOW_KEYWORD_MACROS",
"-D_ASSERT_OK",
"-DSTRSAFE_NO_DEPRECATE",
"-D__possibly_notnullterminated",
"-Dtype_info=\"void *\"",
"-D_ThrowInfo=ThrowInfo",
"-D__unaligned=",
"-v0",
"-D__inner_checkReturn=",
"-DWINAPI_PARTITION_APP=1",
"-DWINAPI_PARTITION_SYSTEM=1",
"-DWINAPI_PARTITION_GAMES=1",
"-DSECURITY_WIN32",
};
parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, args);
}
}

View File

@ -15,33 +15,45 @@
*/
package ghidra.app.plugin.core.cparser;
import java.io.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.StringTokenizer;
import javax.swing.SwingUtilities;
import org.apache.commons.io.DirectoryWalker.CancelException;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import docking.widgets.OptionDialog;
import docking.widgets.dialogs.MultiLineMessageDialog;
import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.C.CParser;
import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.app.util.xml.DataTypesXmlMgr;
import ghidra.framework.Application;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.data.*;
import ghidra.program.model.data.BuiltInDataTypeManager;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.model.listing.Program;
import ghidra.util.*;
import ghidra.util.HTMLUtilities;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
//@formatter:off
@ -62,9 +74,14 @@ public class CParserPlugin extends ProgramPlugin {
private ParseDialog parseDialog;
private File userProfileDir;
private String parserMessages;
private String cppMessages;
final static String DESCRIPTION =
"Parse C and C Header files, extracting data definitions and function signatures.";
private static final String PARSER_DEBUG_OUTFILE = "CParserPlugin.out";
public CParserPlugin(PluginTool plugintool) {
super(plugintool, false, false);
createActions();
@ -144,134 +161,6 @@ public class CParserPlugin extends ProgramPlugin {
tool.showDialog(parseDialog);
}
public void doCParser() {
try {
// PreProcessor cpp = new PreProcessor("c:/Program Files/Microsoft
// Visual Studio/VC98/Include/stdio.h");
String filename1 = "c:/Program Files/Microsoft Visual Studio/VC98/Include/windows.h";
// String filename1 = "c:/Program Files/Microsoft Visual
// Studio/VC98/Include/stdio.h";
// String filename1 = "c:/dummy.h";
// String filename2 = "c:/Program Files/Microsoft Visual
// Studio/VC98/Include/winnt.h";
String[] args = { "-Ic:/Program Files/Microsoft Visual Studio/VC98/Include/",
// "-D_DLL",
"-D_M_IX86=500", "-D_MSC_VER=9090", "-D_WIN32_WINNT=0x0400",
"-D_WIN32_WINDOWS=0x400", "-D_INTEGRAL_MAX_BITS=32", "-D_X86_", "-D_WIN32" };
PreProcessor cpp = new PreProcessor();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setArgs(args);
OutputStream os = null;
try {
os = new FileOutputStream("c:/tmpwindows.h.out");
}
catch (FileNotFoundException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
PrintStream ps = new PrintStream(os);
System.setErr(ps);
System.setOut(ps);
cpp.setOutputStream(bos);
try {
cpp.parse(filename1);
}
catch (RuntimeException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
System.out.println(bos);
FileDataTypeManager dtMgr =
FileDataTypeManager.createFileArchive(new File("c:/parse.gdt"));
CParser cParser = new CParser(dtMgr, true, null);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
cParser.parse(bis);
try {
DataTypesXmlMgr.writeAsXMLForDebug(dtMgr, "c:/parse.xml");
dtMgr.save();
dtMgr.close();
}
catch (IOException e3) {
Msg.error(this, "Unexpected Exception: " + e3.getMessage(), e3);
}
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
}
// // Prints out all the types used in parsing the c source
// private DataTypeManager populateTypes(CParser parser) {
// DataTypeManager dtMgr = new DataTypeManagerImpl("parsed");
//
// addTypes(dtMgr, parser.getFunctions());
// addTypes(dtMgr, parser.getDeclarations());
// addTypes(dtMgr, parser.getEnums());
// addTypes(dtMgr, parser.getStructs());
// addTypes(dtMgr, parser.getTypes());
//
// moveTypes("Functions", dtMgr, parser.getFunctions());
// moveTypes("Declarations", dtMgr, parser.getDeclarations());
// moveTypes("Enums", dtMgr, parser.getEnums());
// moveTypes("Structs", dtMgr, parser.getStructs());
// moveTypes("Types", dtMgr, parser.getTypes());
//
// return dtMgr;
// }
//
// private void addTypes(DataTypeManager dtMgr, Hashtable table) {
// Category rootCat = dtMgr.getRootCategory();
//
// Enumeration enum = table.keys();
// while (enum.hasMoreElements()) {
// String name = (String) enum.nextElement();
// DataType dt = null;
// Object obj = table.get(name);
// if (obj instanceof DataType) {
// dt = (DataType) obj;
// }
// if (dt instanceof TypedefDataType) {
// TypedefDataType tdt = (TypedefDataType) dt;
// if (tdt instanceof Composite) {
// if (tdt.getName().equals(tdt.getBaseDataType().getName())) {
// continue;
// }
// }
// }
// if (dt != null) {
// dumpDT(name, dt);
// dt = rootCat.addDataType(dt);
// dumpDT(name, dt);
// table.put(name, dt);
// }
// }
// }
//
// private void dumpDT(String name, DataType dt) {
// if (dt instanceof StructureDataType) {
// StructureDataType sdt = (StructureDataType) dt;
// Err.debug(this, "struct " + sdt.getName() + " "
// + sdt.getNumComponents());
// CategoryPath cat = sdt.getCategoryPath();
// Err.debug(this, " "
// + (cat != null ? cat.getName() : " -nocat-"));
// for (int i = 0; i < sdt.getNumComponents(); i++) {
// DataTypeComponent ndt = sdt.getComponent(i);
// Err.debug(this, " " + ndt.getFieldName() + " "
// + ndt.getLength() + " " + ndt.getOffset());
// }
// } else if (dt instanceof TypedefDataType) {
// TypedefDataType tdt = (TypedefDataType) dt;
// Err.debug(this, "typedef " + tdt.getBaseDataType().getName()
// + " " + dt.getName());
// } else {
// Err.debug(this, " " + dt.getName());
// }
// }
/*
* Parse into a saved data type data base file
*/
@ -289,52 +178,31 @@ public class CParserPlugin extends ProgramPlugin {
String[] args = parseOptions(options);
DataTypeManager openDTmanagers[] = null;
DataTypeManagerService dtService = tool.getService(DataTypeManagerService.class);
if (dtService != null) {
openDTmanagers = dtService.getDataTypeManagers();
ArrayList<DataTypeManager> list = new ArrayList<>();
String htmlNamesList = "";
for (int i = 0; i < openDTmanagers.length; i++) {
if (openDTmanagers[i] instanceof ProgramDataTypeManager) {
continue;
}
list.add(openDTmanagers[i]);
if (!(openDTmanagers[i] instanceof BuiltInDataTypeManager)) {
htmlNamesList += "<li><b>" +
HTMLUtilities.escapeHTML(openDTmanagers[i].getName()) + "</b></li>";
}
}
openDTmanagers = list.toArray(new DataTypeManager[0]);
if (openDTmanagers.length > 1 && OptionDialog.showOptionDialog(
this.parseDialog.getComponent(), "Use Open Archives?",
"<html>The following archives are currently open: " + "<ul>" + htmlNamesList +
"</ul>" + "<p><b>The new archive will become dependent on these archives<br>" +
"for any datatypes already defined in them </b>(only unique <br>" +
"data types will be added to the new archive).",
"Continue?", OptionDialog.QUESTION_MESSAGE) != OptionDialog.OPTION_ONE) {
return;
}
try {
openDTmanagers = getOpenDTMgrs();
} catch (CancelledException exc) {
return; // parse canceled
}
cppMessages = "";
PreProcessor cpp = new PreProcessor();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setArgs(args);
PrintStream os = System.out;
String homeDir = System.getProperty("user.home");
String fName = homeDir + File.separator + "CParserPlugin.out";
try {
String homeDir = System.getProperty("user.home");
String fName = homeDir + File.separator + "CParserPlugin.out";
os = new PrintStream(new FileOutputStream(fName));
}
catch (FileNotFoundException e2) {
Msg.error(this, "Unexpected Exception: " + e2.getMessage(), e2);
}
// cpp.setOutputStream(os);
PrintStream old = System.out;
System.setOut(os);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setOutputStream(bos);
try {
@ -342,9 +210,14 @@ public class CParserPlugin extends ProgramPlugin {
if (monitor.isCancelled()) {
break;
}
// any file beginning with a "#" is assumed to be a comment
if (filename.trim().startsWith("#")) {
continue;
}
File file = new File(filename);
// process each header file in the directory
if (file.isDirectory()) {
// process each header file in the directory
String[] children = file.list();
if (children == null) {
continue;
@ -362,16 +235,15 @@ public class CParserPlugin extends ProgramPlugin {
}
}
catch (RuntimeException re) {
Msg.error(this, re.getMessage());
os.close();
return;
throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
}
// process all the defines and add any that are integer values into
// the Equates table
cpp.getDefinitions().populateDefineEquates(dtMgr);
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
System.out.println(bos);
System.out.println(bos.toString());
System.setOut(old);
os.close();
@ -380,26 +252,134 @@ public class CParserPlugin extends ProgramPlugin {
monitor.setMessage("Parsing C");
CParser cParser = new CParser(dtMgr, true, openDTmanagers);
cParser.setParseFileName(PARSER_DEBUG_OUTFILE);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
cParser.parse(bis);
try {
parserMessages = "";
cParser.setParseFileName(fName);
cParser.parse(bis);
}
finally {
parserMessages = cParser.getParseMessages();
}
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager);
SwingUtilities.invokeLater(() -> {
// CParserTask will show any errors
if (!cParser.didParseSucceed()) {
return;
}
if (isProgramDtMgr) {
Msg.showInfo(getClass(), parseDialog.getComponent(),
"Parse Header Files Completed", "Successfully parsed header file(s).\n" +
"Check the Manage Data Types window for added data types.");
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 {
parseDialog.setDialogText("Successfully parsed header file(s).");
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);
}
});
}
}
private void parseFile(String filename, TaskMonitor monitor, PreProcessor cpp) {
/**
* Get open data type managers.
* User can Use Open managers, Select not to use, or Cancel
*
* @param openDTmanagers open mgrs, null if don't use
* @return array of open data type managers
*
* @throws CancelledException if user cancels
*/
private DataTypeManager[] getOpenDTMgrs() throws CancelledException {
DataTypeManager[] openDTmanagers = null;
DataTypeManagerService dtService = tool.getService(DataTypeManagerService.class);
if (dtService == null) {
return openDTmanagers;
}
openDTmanagers = dtService.getDataTypeManagers();
ArrayList<DataTypeManager> list = new ArrayList<>();
String htmlNamesList = "";
for (DataTypeManager openDTmanager : openDTmanagers) {
if (openDTmanager instanceof ProgramDataTypeManager) {
continue;
}
list.add(openDTmanager);
if (!(openDTmanager instanceof BuiltInDataTypeManager)) {
htmlNamesList +=
"<li><b>" + HTMLUtilities.escapeHTML(openDTmanager.getName()) + "</b></li>";
}
}
openDTmanagers = list.toArray(new DataTypeManager[0]);
if (openDTmanagers.length > 1) {
int result = OptionDialog.showOptionDialog(
this.parseDialog.getComponent(), "Use Open Archives?",
"<html>The following archives are currently open: " + "<ul>" + htmlNamesList +
"</ul>" + "<p><b>The new archive will become dependent on these archives<br>" +
"for any datatypes already defined in them </b>(only unique <br>" +
"data types will be added to the new archive).",
"Use Open Archives?", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
if (result == OptionDialog.CANCEL_OPTION) {
throw new CancelledException("User Cancelled");
}
if (result == OptionDialog.OPTION_TWO) {
return null;
}
}
return openDTmanagers;
}
public String getFormattedParseMessage(String errMsg) {
String message = "";
if (errMsg != null) {
message += errMsg + "\n\n";
}
String msg = getParseMessage();
if (msg != null && msg.length() != 0) {
message += "CParser Messages:\n" + msg + "\n\n";
}
msg = getPreProcessorMessage();
if (msg != null && msg.length() != 0) {
message += "PreProcessor Messages:\n" + getPreProcessorMessage();
}
return message;
}
/**
* Get any parse messages produced by parsing good, or informational
*
* @return messages from parser
*/
public String getParseMessage() {
return parserMessages;
}
public String getPreProcessorMessage() {
return cppMessages;
}
private void parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
throws ghidra.app.util.cparser.CPP.ParseException {
monitor.setMessage("PreProcessing " + filename);
try {
Msg.info(this, "parse " + filename);
@ -408,6 +388,11 @@ public class CParserPlugin extends ProgramPlugin {
catch (Throwable e) {
Msg.error(this, "Parsing file :" + filename);
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
}
finally {
cppMessages += cpp.getParseMessages();
}
}

View File

@ -19,6 +19,7 @@ import java.io.File;
import javax.swing.SwingUtilities;
import docking.widgets.dialogs.MultiLineMessageDialog;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg;
@ -57,6 +58,15 @@ class CParserTask extends Task {
this.dtMgr = dataTypeManager;
}
private String getFirstMessageLine(final String errMsg) {
int indexOf = errMsg.indexOf('\n');
String msg = errMsg;
if (indexOf > 0) {
msg = msg.substring(0, indexOf);
}
return msg;
}
@Override
public void run(TaskMonitor monitor) {
DataTypeManager fileDtMgr = null;
@ -73,16 +83,6 @@ class CParserTask extends Task {
try {
((FileDataTypeManager) dtMgr).save();
dtMgr.close();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Msg.showInfo(
getClass(), plugin.getDialog().getComponent(),
"Created Archive File", "Successfully created archive file\n" +
((FileDataTypeManager) dtMgr).getFilename());
}
});
}
catch (DuplicateFileException e) {
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save",
@ -102,8 +102,12 @@ class CParserTask extends Task {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Msg.showInfo(getClass(),
plugin.getDialog().getComponent(), "Parse Errors", "File was not created due to parse errors.");
MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(), "Parse Errors",
"File was not created due to parse errors: " +
((FileDataTypeManager) dtMgr).getFilename(),
plugin.getFormattedParseMessage(null),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
});
}
@ -115,8 +119,10 @@ class CParserTask extends Task {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Msg.showInfo(getClass(),
plugin.getDialog().getComponent(), "Parse Errors", errMsg);
String msg = getFirstMessageLine(errMsg);
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
"Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE);
}
});
}
@ -126,14 +132,22 @@ class CParserTask extends Task {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Msg.showInfo(getClass(),
plugin.getDialog().getComponent(), "Parse Errors", errMsg);
String msg = getFirstMessageLine(errMsg);
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
"PreProcessor Parse Errors", msg, plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE);
}
});
}
catch (Exception e) {
final String errMsg = e.getMessage();
String msg = getFirstMessageLine(errMsg);
Msg.showError(this, plugin.getDialog().getComponent(), "Error During Parse",
"Parse header files failed", e);
"Parse header files failed" + "\n\nParser Messages:\n" + plugin.getParseMessage(),
e);
MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(),
"Error During Parse", msg, plugin.getFormattedParseMessage(errMsg),
MultiLineMessageDialog.ERROR_MESSAGE);
}
finally {
if (fileDtMgr != null) {

View File

@ -15,14 +15,35 @@
*/
package ghidra.app.util.cparser.C;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Iterator;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.data.*;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.model.data.FunctionDefinitionDataType;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.CompilerSpecID;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.listing.Program;
import ghidra.util.*;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.HTMLUtilities;
import ghidra.util.InvalidNameException;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
public class CParserUtils {
@ -171,6 +192,7 @@ public class CParserUtils {
DataType dt = null;
try {
// parse the signature
parser.setParseFileName("input line");
dt = parser.parse(replacedText + ";");
if (!(dt instanceof FunctionDefinitionDataType)) {
@ -207,6 +229,330 @@ public class CParserUtils {
return null;
}
/**
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
* with in the provided dataFileName.
*
* 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.
*
* @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 args arguments for parsing, "-D<defn>=", "-I<includepath>"
*
* @param dataFileName name of data type archive file (include the .gdt extension)
*
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
*
* @param monitor used to cancel or provide results
*
* @return the data types in the ghidra .gdt archive file
*
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
* @throws IOException if there io are errors saving the archive
*
*/
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
File file = new File(dataFileName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, cpp, monitor);
dtMgr.save();
return dtMgr;
}
/**
* Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
* with in the provided dataFileName.
*
* 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 args arguments for parsing, "-D<defn>=", "-I<includepath>"
*
* @param dataFileName name of data type archive file (include the .gdt extension)
*
* @param languageId language identication to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing
*
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing
*
* @param monitor used to cancel or provide results
*
* @return the data types in the ghidra .gdt archive file
*
* @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 DataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
File file = new File(dataFileName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
String messages = parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, languageId, compileSpecId, cpp, monitor);
Msg.info(CParserUtils.class, messages);
dtMgr.save();
return dtMgr;
}
/**
* 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 args arguments for parsing, "-D<defn>=", "-I<includepath>"
*
* @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
*
* @param languageId language identication to use for data type organization definitions (int, long, ptr size)
* @param compileSpecId compiler specification to use for parsing
*
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after 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 String parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
String languageId, String compileSpecId, PreProcessor cpp, 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));
String dtmgrName = existingDTMgr.getName();
if (existingDTMgr instanceof FileDataTypeManager) {
dtmgrName = ((FileDataTypeManager) existingDTMgr).getPath();
}
ProgramDB program = new ProgramDB(dtmgrName, language, compilerSpec, CParserUtils.class);
try {
DataTypeManager programDtm = program.getDataTypeManager();
String messages = parseHeaderFiles(openDTMgrs, filenames, args, programDtm, cpp, monitor);
int txId = existingDTMgr.startTransaction("Add Types");
try {
Iterator<DataType> allDataTypes = programDtm.getAllDataTypes();
while (allDataTypes.hasNext()) {
existingDTMgr.resolve(allDataTypes.next(), null);
}
}
finally {
existingDTMgr.endTransaction(txId, true);
}
return messages;
}
finally {
program.release(CParserUtils.class);
}
}
/**
* 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: The DTMgr should have been created with the correct data type organization from a language/compilerspec
* if there could be variants in datatype defintions when using the generic data type manager data organization
* for example in a generic FileDataTypeManager int and long are size 4. This will change in the future,
* but with the current implementation, beware!
*
* @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 args arguments for parsing, "-D<defn>=", "-I<includepath>"
*
* @param dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr
*
* @param cpp provided PreProcessor, useful if parsed Define's need to be examined after 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 String parseHeaderFiles(DataTypeManager openDTmanagers[], String[] filenames, String args[],
DataTypeManager dtMgr, PreProcessor cpp, TaskMonitor monitor)
throws ghidra.app.util.cparser.C.ParseException, ghidra.app.util.cparser.CPP.ParseException {
String cppMessages = "";
if (cpp == null) {
cpp = new PreProcessor();
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setArgs(args);
PrintStream os = System.out;
String fName = dtMgr.getName().replace(".gdt","")+"_CParser.out";
try {
os = new PrintStream(new FileOutputStream(fName));
} catch (FileNotFoundException e2) {
Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2);
}
// cpp.setOutputStream(os);
PrintStream old = System.out;
System.setOut(os);
cpp.setOutputStream(bos);
try {
for (String filename : filenames) {
if (monitor.isCancelled()) {
break;
}
if (filename.trim().startsWith("#")) {
continue;
}
File file = new File(filename);
// process each header file in the directory
if (file.isDirectory()) {
String[] children = file.list();
if (children == null) {
continue;
}
for (String element : children) {
File child = new File(file.getAbsolutePath() + "/" + element);
if (child.getName().endsWith(".h")) {
parseFile(child.getAbsolutePath(), monitor, cpp);
}
}
} else {
parseFile(filename, monitor, cpp);
}
}
} catch (RuntimeException re) {
Msg.info(cpp, cpp.getParseMessages());
throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
} finally {
System.out.println(bos);
os.flush();
os.close();
System.setOut(old);
}
cppMessages = cpp.getParseMessages();
// process all the defines and add any that are integer values into
// the Equates table
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
String parserMessages = "";
if (!monitor.isCancelled()) {
monitor.setMessage("Parsing C");
CParser cParser = new CParser(dtMgr, true, openDTmanagers);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
try {
parserMessages = "";
cParser.setParseFileName(fName);
cParser.parse(bis);
} finally {
parserMessages = cParser.getParseMessages();
}
}
return getFormattedParseMessage(parserMessages, cppMessages, null);
}
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
throws ghidra.app.util.cparser.CPP.ParseException {
monitor.setMessage("PreProcessing " + filename);
try {
Msg.info(CParserUtils.class, "parse " + filename);
cpp.parse(filename);
}
catch (Throwable e) {
Msg.error(CParserUtils.class, "Parsing file :" + filename);
Msg.error(CParserUtils.class, "Unexpected Exception: " + e.getMessage(), e);
throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage());
}
return cpp.getParseMessages();
}
private static String getFormattedParseMessage(String parseMessage, String cppMessage, String errMsg) {
String message = "";
if (errMsg != null) {
message += errMsg + "\n\n";
}
String msg = parseMessage;
if (msg != null && msg.length() != 0) {
message += "CParser Messages:\n" + msg + "\n\n";
}
msg = cppMessage;
if (msg != null && msg.length() != 0) {
message += "PreProcessor Messages:\n" + msg;
}
return message;
}
private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) {
if (service == null) {

View File

@ -16,13 +16,18 @@
*/
package ghidra.app.util.cparser.C;
import ghidra.program.model.data.*;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.data.AbstractIntegerDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.PointerDataType;
/**
* Container for information about a Declaration that is accumulated during parsing.
*/
public class Declaration {
private int qualifier;
private ArrayList<Integer> qualifierList;
private DataType dt;
private String name;
private String comment;
@ -35,6 +40,9 @@ public class Declaration {
public Declaration(Declaration dec) {
this();
this.dt = dec.getDataType();
if (dec.qualifierList != null) {
this.qualifierList = new ArrayList<Integer>(dec.qualifierList);
}
}
public Declaration(Declaration dec, String name) throws ParseException {
@ -65,6 +73,9 @@ public class Declaration {
}
this.name = subDecl.name;
this.comment = subDecl.comment;
if (subDecl.qualifierList != null) {
this.qualifierList = new ArrayList<Integer>(subDecl.qualifierList);
}
}
public Declaration(DataType dt, String name) {
@ -84,8 +95,11 @@ public class Declaration {
return comment;
}
public int getQualifier() {
return qualifier;
public List<Integer> getQualifiers() {
if (qualifierList == null) {
return List.of();
}
return qualifierList;
}
public DataType getDataType() {
@ -103,8 +117,21 @@ public class Declaration {
comment = string;
}
public void setQualifier(int qualifier) {
this.qualifier = qualifier;
public void addQualifier(int qualifier) {
if (qualifierList == null) {
qualifierList = new ArrayList<Integer>();
}
qualifierList.add(qualifier);
}
public void addQualifiers(Declaration dec) {
if (dec.qualifierList == null) {
return;
}
if (qualifierList == null) {
qualifierList = new ArrayList<Integer>();
}
qualifierList.addAll(dec.qualifierList);
}
public void setDataType(DataType type) {

View File

@ -27,6 +27,8 @@ import ghidra.util.Msg;
*
*/
public class DefineTable {
private static final String VARARG_ELLIPSIS = "...";
private static final int ARBITRARY_MAX_REPLACEMENTS = 900000;
// Hastable for storing #defs
@ -35,6 +37,7 @@ public class DefineTable {
// Hastable for storing #define macro args (substitution list)
Hashtable<String, Vector<PPToken>> args = new Hashtable<String, Vector<PPToken>>();
// Multi-level hashtable with different types of keys and values
Hashtable lookupTable = new Hashtable();
private final static String VALUE = "value";
@ -74,7 +77,7 @@ public class DefineTable {
while (findTable != null && pos < buf.length()) {
char ch = buf.charAt(pos++);
Character chObj = new Character(ch);
Character chObj = ch;
findTable = (Hashtable) findTable.get(chObj);
@ -106,7 +109,7 @@ public class DefineTable {
int len = string.length();
while (pos < len) {
char ch = string.charAt(pos++);
chObj = new Character(ch);
chObj = ch;
Hashtable node = (Hashtable) findTable.get(chObj);
@ -168,7 +171,7 @@ public class DefineTable {
int len = string.length();
while (pos < len) {
char ch = string.charAt(pos++);
chObj = new Character(ch);
chObj = Character.valueOf(ch);
findTable = (Hashtable) findTable.get(chObj);
@ -281,13 +284,13 @@ public class DefineTable {
while (pos < buf.length() && replaceCount < ARBITRARY_MAX_REPLACEMENTS) {
// clear list of used macros when move past replacement area
if (pos == lastReplPos) {
sublist = new ArrayList<String> (); // ok to clear list of used macro names
sublist = new ArrayList<String>(); // ok to clear list of used macro names
}
String defName = getDefineAt(buf, pos);
if (shouldReplace(buf, defName, pos)) {
// stop recursion on the same replacement string
int replPos = replace(buf, defName, pos, sublist);
if (replPos == -1) {
// if no replacement string, move on
pos++;
@ -417,12 +420,16 @@ public class DefineTable {
int index = 0;
int pos = 0;
StringBuffer argsfound = new StringBuffer();
boolean isVarArg = false;
boolean hadVarArgs = false;
while (pos < parms.length() || index < argv.size()) {
String argValue = "";
int origPos = pos;
if (pos < parms.length()) {
argValue = getParams(new StringBuffer(parms), pos, ',');
}
pos += argValue.length() + 1;
if (index >= argv.size()) {
Msg.error(this,
"Define parameter mismatch for macro " + defName + "(" + parms + ")" +
@ -430,12 +437,27 @@ public class DefineTable {
argValue + " args processed : " + argsfound);
return replString;
}
// Handle "..." varargs
// if last argument is ellipsis, then is varargs, replace the rest of the params
String curArgName = argv.elementAt(index).image;
if (index == argv.size()-1 && VARARG_ELLIPSIS.equals(curArgName)) {
isVarArg = true;
// Replace __VA_ARGS__ with the rest of params
curArgName = "__VA_ARGS__";
argValue = getParams(new StringBuffer(parms), origPos, '\0');
pos += argValue.length() + 1;
}
index++;
argValue = argValue.trim();
argsfound.append(argValue);
argsfound.append(", ");
// isVarArg, and had variable arguments
if (isVarArg && argValue.length() != 0) {
hadVarArgs = true;
}
int curpos = -1;
// find argname in substString
// note begin and end position
@ -461,7 +483,7 @@ public class DefineTable {
continue;
}
Integer begin = new Integer(curpos);
Integer begin = Integer.valueOf(curpos);
int insertLoc = 0;
for (; insertLoc < beginPos.size(); insertLoc++) {
Integer loc = beginPos.get(insertLoc);
@ -471,7 +493,7 @@ public class DefineTable {
}
beginPos.add(insertLoc, begin);
endPos.add(insertLoc, new Integer(curpos + curArgName.length()));
endPos.add(insertLoc, Integer.valueOf(curpos + curArgName.length()));
subValue.add(insertLoc, argValue);
}
while (curpos >= 0);
@ -490,10 +512,49 @@ public class DefineTable {
startpos = end;
}
buf.append(substString.substring(startpos));
// Handle __VA_OPT__(<repl>)
// if varargs and no more params, replace with ""
// if varargs and has vararg params, replace with <repl>
if (isVarArg) {
replace_VaOpt(buf, hadVarArgs);
}
substString = buf.toString();
return substString;
}
/**
* Replace __VA_OPT__(arg) in buf with either the arg to __VA_OPT__
* if there were any VARARGS, otherwise with ""
* @param buf string buffer to replace __VA_OPT__(value) within
* @param hadVarArgs
*/
private void replace_VaOpt(StringBuffer buf, boolean hadVarArgs) {
int optIdx = buf.indexOf("__VA_OPT__");
if (optIdx < 0) {
return;
}
int lparen = buf.indexOf("(", optIdx+1);
if (lparen < 0) {
return;
}
int rparen = buf.indexOf(")",lparen+1);
if (rparen < 0) {
return;
}
// get in between string.
String replarg = buf.substring(lparen+1, rparen);
if (hadVarArgs) {
buf.replace(optIdx, rparen+1, replarg);
} else {
buf.replace(optIdx, rparen+1, "");
}
}
/**
* @param buf the buffer containing the parameters
* @param start the starting index of the parameters in the buffer
@ -507,7 +568,7 @@ public class DefineTable {
if (pos >= len) {
return "";
}
char ch = buf.charAt(pos);
char lastChar = 0;
boolean hitQuote = false;
@ -521,11 +582,11 @@ public class DefineTable {
if (ch == '\'' && lastChar != '\\') {
hitTick = !hitTick;
}
if (!(hitQuote||hitTick) && ch == endChar && depth == 0) {
if (!(hitQuote || hitTick) && ch == endChar && depth == 0) {
pos--;
break;
}
if (!(hitQuote||hitTick) && ch == ')') {
if (!(hitQuote || hitTick) && ch == ')') {
depth--;
if (depth == 0 && endChar == 0) {
break;
@ -536,7 +597,7 @@ public class DefineTable {
break;
}
}
if (!(hitQuote||hitTick) && ch == '(') {
if (!(hitQuote || hitTick) && ch == '(') {
depth++;
}
lastChar = ch;
@ -611,24 +672,19 @@ public class DefineTable {
*
*/
public void populateDefineEquates(DataTypeManager dtMgr) {
public void populateDefineEquates(DataTypeManager openDTMgrs[], DataTypeManager dtMgr) {
int transactionID = dtMgr.startTransaction("Add Equates");
Iterator<String> iter = getDefineNames();
while (iter.hasNext()) {
String defName = iter.next();
// don't worry about macros
if (isArg(defName)) {
//System.err.println(defName + " = " + getValue(defName));
String strValue = expandDefine(defName);
if (strValue == null) {
// couldn't expand, must have been a macro
continue;
}
// check if this is a numeric expression that could be simplified
//
String strValue = getValue(defName);
String strExpanded = expand(strValue, true);
strValue = strExpanded;
// strip off any casting/parentheses
strValue = stripCast(strValue);
@ -649,30 +705,74 @@ public class DefineTable {
value = lvalue.longValue();
String enumName = "define_" + defName;
EnumDataType enuum = new EnumDataType(enumName, 8);
enuum.add(defName, value);
String defPath = getDefinitionPath(defName);
String currentCategoryName = getFileName(defPath);
CategoryPath path = getCategory(currentCategoryName);
path = new CategoryPath(path, "defines");
enuum.setCategoryPath(path);
dtMgr.addDataType(enuum, DataTypeConflictHandler.DEFAULT_HANDLER);
populateDefineEquate(openDTMgrs, dtMgr, "defines", "define_", defName, value);
}
dtMgr.endTransaction(transactionID, true);
}
public void populateDefineEquate(DataTypeManager openDTMgrs[], DataTypeManager dtMgr, String category, String prefix, String defName, long value) {
String enumName = prefix + defName;
EnumDataType enuum = new EnumDataType(enumName, 8);
enuum.add(defName, value);
String defPath = getDefinitionPath(defName);
String currentCategoryName = getFileName(defPath);
CategoryPath path = getCategory(currentCategoryName);
path = new CategoryPath(path, category);
enuum.setCategoryPath(path);
DataType dt = resolveDataType(openDTMgrs, path, enuum);
dtMgr.addDataType(dt, DataTypeConflictHandler.DEFAULT_HANDLER);
}
private DataType resolveDataType(DataTypeManager openDTMgrs[], CategoryPath path, DataType dt) {
if (openDTMgrs == null) {
return dt;
}
// If the exact data type exists in any open DTMgr, use the open DTmgr type
// instead
for (int i = 0; i < openDTMgrs.length; i++) {
// look for the data type by name
// equivalent, return it
// look for the data type by category
// equivalent, return it
DataType candidateDT = openDTMgrs[i].getDataType(dt.getCategoryPath(), dt.getName());
if (candidateDT != null && candidateDT.isEquivalent(candidateDT)) {
return candidateDT;
}
}
return dt;
}
public String expandDefine(String defName) {
// don't worry about macros
if (isArg(defName)) {
//System.err.println(defName + " = " + getValue(defName));
return null;
}
// check if this is a numeric expression that could be simplified
//
String strValue = getValue(defName);
String strExpanded = expand(strValue, true);
strValue = strExpanded;
return strValue;
}
/**
* Parse a C format integer value
*
* @param strValue value to parse
* @return long value if parsable as an integer, null otherwise
*/
private static Long getCValue(String strValue) {
public static Long getCValue(String strValue) {
try {
int start = 0;
int radix = 10;
@ -719,6 +819,9 @@ public class DefineTable {
* Get the filename portion of a path
*/
private static String getFileName(String path) {
if (path == null) {
return null;
}
int slashpos = path.lastIndexOf('/');
if (slashpos < 0) {
slashpos = path.lastIndexOf('\\');

View File

@ -167,37 +167,37 @@ public class PreProcessor {
boolean emitExecSave;
int comparison;
ArrayList <String> appendList = new ArrayList();
ArrayList <StringBuffer> appendList = new ArrayList();
ArrayList <Boolean> expandList = new ArrayList();
void append(String str, boolean expand) {
if (image != null & image.length()>0) {
appendList.add(image);
appendList.add(new StringBuffer(image));
expandList.add(true);
image = null;
}
int endIndex = appendList.size() - 1;
if (endIndex >= 0 && (str.strip().length()==0 || expand == expandList.get(endIndex)) ) {
// just add to the last image so it can expand properly
String lastStr = appendList.remove(endIndex);
expand = expandList.remove(endIndex);
str = lastStr + str;
StringBuffer lastStr = appendList.get(endIndex);
lastStr.append(str);
return;
}
appendList.add(str);
appendList.add(new StringBuffer(str));
expandList.add(expand);
}
void append(PPToken tok, boolean expand) {
if (tok.image != null && tok.image.length() > 0) {
append(tok.image, expand);
return;
}
int cnt = 0;
for (String string : appendList) {
append(string, expandList.get(cnt));
}
}
// void append(PPToken tok, boolean expand) {
// if (tok.image != null && tok.image.length() > 0) {
// append(tok.image, expand);
// return;
// }
// int cnt = 0;
// for (String string : appendList) {
// append(string, expandList.get(cnt));
// }
// }
void setTruth(boolean truth) {
this.truth = truth;
@ -241,7 +241,7 @@ public class PreProcessor {
return this.image.equals((String) t);
}
} catch (ClassNotFoundException e) {
Msg.error(this, "PPToken.equals: " + e.getMessage());
addParseMessage(null, "PPToken.equals: " + e.getMessage());
}
return false;
}
@ -288,12 +288,12 @@ public class PreProcessor {
}
break;
default:
Msg.error(this, "Cannot compareToZero Token: " + image + " kind " + kind);
addParseMessage(null, "Cannot compareToZero Token: " + image + " kind " + kind);
break;
}
}
catch (Exception e) {
Msg.error(this, "CMP2Zero:Numeric Conversion Error: " + e.getMessage());
addParseMessage(null, "CMP2Zero:Numeric Conversion Error: " + e.getMessage());
}
return comparison;
}
@ -317,7 +317,7 @@ public class PreProcessor {
PPToken replVal = (PPToken) getDef(this); // not a PPToken
if (replVal == null) {
replVal = new PPToken(this);
// Msg.error(this,
// addParseMessage(null,
// "Missing numeric value for: "+image+" at "
// +curFileStackTop
// ()+"'"+beginLine+". PreProcessor expects one.");
@ -332,7 +332,7 @@ public class PreProcessor {
}
catch (Exception e) {
thisFP = null;
// Msg.error(this, "Numeric Conversion Error for '" + this.image
// addParseMessage(null, "Numeric Conversion Error for '" + this.image
// + "' in " + curFileStackTop() + " line " + that.beginLine +
// " : "+e.getMessage());
}
@ -350,7 +350,7 @@ public class PreProcessor {
PPToken replVal = (PPToken) getDef(that); // not a PPToken
if (replVal == null) {
replVal = new PPToken(that);
// Msg.error(this,
// addParseMessage(null,
// "Missing numeric value for: "+image+" at "
// +curFileStackTop
// ()+"'"+beginLine+". PreProcessor expects one.");
@ -365,7 +365,7 @@ public class PreProcessor {
}
catch (Exception e) {
thatFP = null;
// Msg.error(this, "Numeric Conversion Error in " +
// addParseMessage(null, "Numeric Conversion Error in " +
// curFileStackTop() + " line " + that.beginLine +
// " : "+e.getMessage());
}
@ -499,9 +499,9 @@ public class PreProcessor {
image = defs.expand(image, true);
} else {
int cnt = 0;
for (String string : appendList) {
for (StringBuffer string : appendList) {
if (expand && expandList.get(cnt++)) {
image += defs.expand(string, true);
image += defs.expand(string.toString(), true);
} else {
image += string;
}
@ -522,7 +522,7 @@ public class PreProcessor {
boolean emitExecSwitch = true;
// Hastable for storing #include file names
Hashtable<String, Boolean> files = new Hashtable<String, Boolean>();
HashSet<String> files = new HashSet<String>();
// Stack for keeping shadowed (include) files
Stack<String> fileStack = new Stack<String>();
@ -545,6 +545,11 @@ public class PreProcessor {
// times they have been parsed
private HashMap<String, Integer> alreadyDone;
private StringBuilder parseMessages = new StringBuilder();
// true if parse was successful
private boolean parseSuccess = false;
// Toggle printing
private int verboseLevel = 0;
@ -700,10 +705,10 @@ public class PreProcessor {
}
}
} catch (FileNotFoundException fene) {
Msg.error(this, fene.getMessage() + " " + incFile);
addParseMessage(incFile.getName(), fene.getMessage());
}
if (fis == null) {
// Msg.error(this,
// addParseMessage(null,
// "Warning: No relative path to #include \""+def+"\"\nThis is a design/configuration flaw. Trying the standard places...");
standardPlace(inc, xsym);
} else {
@ -715,7 +720,7 @@ public class PreProcessor {
}
}
private void swapFileStreams(File incFile, FileInputStream fis) {
private void swapFileStreams(File incFile, FileInputStream fis) throws ParseException {
if (verboseLevel == 2)
print(incFile.getAbsolutePath() + "\n");
else if (verboseLevel == 1)
@ -733,10 +738,8 @@ public class PreProcessor {
count++;
}
if (count > 5) {
Msg.error(this,
"Error: Possible infinite inclusion recursion detected: "
+ incFile.getAbsolutePath());
Msg.error(this, fileStack);
addParseMessage(incFile.getAbsolutePath(),
"Error: Possible infinite inclusion recursion detected: \n" + fileStack);
return;
}
} while (pos != -1);
@ -757,14 +760,13 @@ public class PreProcessor {
parser.ReInit(fis);
parser.Input();
fileStack.pop();
} catch (ParseException e) {
Msg.error(this,
"PERROR parsing Included File: In " + incFile.getName()
+ ": " + e.getMessage());
Msg.error(this, "PreProcessor Parse Error: " + e.getMessage());
} catch (TokenMgrError e) {
Msg.error(this, "ERROR parsing Included File: " + incFile.getName());
Msg.error(this, "PreProcessor Token Error: " + e.getMessage());
} catch (ParseException e) {
addParseMessage(incFile.getName(), "ERROR parsing Included File: " + e.getMessage());
throw e;
}
catch (TokenMgrError e) {
addParseMessage(incFile.getName(), "ERROR parsing Included File: " + e.getMessage());
throw e;
}
}
@ -834,7 +836,8 @@ public class PreProcessor {
FileInputStream fis = null;
File iFile = null;
int i;
addFile(fn);
boolean alreadyIncluded = addFile(fn);
for (i = 0; i < pathList.size(); i++) {
iFile = getFile(pathList.elementAt(i), fn, xsym);
// don't include the same file name
@ -853,26 +856,26 @@ public class PreProcessor {
fis = getFIS(iFile);
}
if (fis == null) {
Msg.error(this, "No path to #include " + ft + "\nUse -I option");
Msg.error(this, " Current Include Path: ");
for (int pi = 0; pi < fileStack.size(); pi++) {
Msg.error(this, " : " + fileStack.get(pi));
addParseMessage(null, "WARNING: No path to #include " + ft +
" Assuming not needed!" + "\u005cnUse -I option");
addParseMessage(null, " Current Include Path: ");
for (String element : fileStack) {
addParseMessage(null, " : " + element);
}
Msg.error(this, " Assuming not needed");
// throw new ParseException("No path to #include " + ft
// + "\nUse -I option");
} else {
if (verboseLevel == 2) {
print("Line " + inc.beginLine + ": " + curFileStackTop()
+ " => ");
print("Line " + inc.beginLine + ": " + curFileStackTop() + " => ");
}
StringBuffer pad = new StringBuffer();
for (int padInd = 0; padInd < fileStack.size(); padInd++)
for (String element : fileStack) {
pad.append(" ");
Msg.info(this, " " + pad + iFile);
}
if (!alreadyIncluded) {
addParseMessage(null, " " + pad + iFile);
}
swapFileStreams(iFile, fis);
if (verboseLevel == 1) {
Msg.info(this, "Include depth " + fileStack.size() + ": Done!");
addParseMessage(null, "Include depth " + fileStack.size() + ": Done!");
}
}
}
@ -1018,14 +1021,18 @@ public class PreProcessor {
fis = new java.io.FileInputStream(lowerFile);
}
} catch (FileNotFoundException fene) {
Msg.error(this, fene.getMessage() + " " + iFile);
addParseMessage(null, fene.getMessage() + " " + iFile);
}
return fis;
}
// Add an include file to those already included
private void addFile(String file) {
files.put(file, Boolean.TRUE);
// Add an include file to those already included, return true if already included
private boolean addFile(String file) {
if (files.contains(file)) {
return true;
}
files.add(file);
return false;
}
private void printCommentedLines(boolean emitSwitch, String line, String state) {
@ -1053,10 +1060,10 @@ public class PreProcessor {
// Prints out all the files used in parsing the source
private void printFiles() {
Enumeration<String> eFiles = files.keys();
Iterator<String> eFiles = files.iterator();
while (eFiles.hasMoreElements()) {
Msg.info(this, "PreProcessor: " + eFiles.nextElement());
while (eFiles.hasNext()) {
addParseMessage(null, "PreProcessor: " + eFiles.next());
}
}
@ -1089,8 +1096,7 @@ public class PreProcessor {
val = "";
}
if (verboseLevel == 3 || verboseLevel == 6) {
System.out.print("Predefining " + key + " to "
+ val);
addParseMessage(null, "Predefining " + key + " to " + val);
}
Token k, v;
k = new Token();
@ -1103,12 +1109,12 @@ public class PreProcessor {
PPToken ppv = new PPToken(v);
setDef(ppk, ppv);
if (verboseLevel == 3 || verboseLevel == 6) {
Msg.info(this, "Defs: containsKey: " + key + " = "
+ defs.containsKey(key) + " " + defs.size());
addParseMessage(null, "Defs: containsKey: " + key + " = " +
defs.containsKey(key) + " " + defs.size());
}
} else {
if (verboseLevel == 3 || verboseLevel == 6) {
System.out.print("Predefining " + optValue);
addParseMessage(null, "Predefining " + optValue);
}
Token k = new Token();
k.image = argString.substring(2);
@ -1126,23 +1132,20 @@ public class PreProcessor {
try {
verboseLevel = Integer.parseInt(optValue, 10);
} catch (NumberFormatException nfe) {
Msg.error(this,
"Verbose Level Error: " + nfe.getMessage());
throw new ParseException("Bad verbosity level "
+ optValue);
addParseMessage(null, "Verbose Level Error: " + nfe.getMessage());
throw new ParseException("Bad verbosity level " + optValue);
}
continue; // continue loop
case 'O':
try {
setOutputStream(new java.io.FileOutputStream(optValue));
} catch (FileNotFoundException exc) {
Msg.error(this, "Couldn't create file " + optValue);
throw new ParseException("Couldn't create file "
+ optValue);
addParseMessage(null, "Couldn't create file " + optValue);
throw new ParseException("Couldn't create file " + optValue);
}
continue;
default:
Msg.error(this, "Unknown option: " + argString);
addParseMessage(null, "Unknown option: " + argString);
throw new ParseException("Unknown option: " + argString);
}
default:
@ -1207,6 +1210,21 @@ public class PreProcessor {
throw new NumberFormatException("Couldn't parse number: \'" + str + "\'");
}
private void addParseMessage(String filename, String message) {
if (filename != null) {
parseMessages.append(" In file " + filename + "\n");
}
parseMessages.append(message + "\n");
}
public String getParseMessages() {
return parseMessages.toString();
}
public boolean didParseSucceed() {
return parseSuccess;
}
public void setArgs(String[] args) throws ParseException {
shift = getopt(args);
}
@ -1215,10 +1233,10 @@ public class PreProcessor {
outputStream = new PrintStream(fos);
}
public void parse(String filename) {
public void parse(String filename) throws ParseException {
if (verboseLevel == 1) {
Msg.info(this, "PreProcessor Version 0.0: Reading from file "
+ filename + " . . .");
addParseMessage(null,
"PreProcessor: Reading from file " + filename + " . . .");
}
FileInputStream fis = null;
@ -1237,8 +1255,7 @@ public class PreProcessor {
}
}
if (fis == null) {
Msg.error(this, "PreProcessor Version 0.0: File " + filename
+ " not found.");
addParseMessage(null, "PreProcessor: File " + filename + " not found.");
return;
}
fileStack.push(filename);
@ -1249,16 +1266,16 @@ public class PreProcessor {
fileStack.pop();
if (fileStack.size() == 0) {
if (verboseLevel == 1) {
Msg.info(this,
"PreProcessor Version 0.0: Java program parsed successfully.");
addParseMessage(null,
"PreProcessor: Java program parsed successfully.");
}
}
} catch (ParseException e) {
Msg.error(this, "ERROR parsing: " + filename);
Msg.error(this, "PreProcessor Parse Error: " + e.getMessage());
addParseMessage(filename, "PreProcessor Parse Error: " + e.getMessage());
throw e;
} catch (TokenMgrError e) {
Msg.error(this, "ERROR parsing: " + filename);
Msg.error(this, "PreProcessor Token Error: " + e.getMessage());
addParseMessage(filename, "PreProcessor Token Error: " + e.getMessage());
throw e;
}
}
@ -1284,8 +1301,8 @@ public class PreProcessor {
if (args.length - shift == 0) {
if (verboseLevel == 1) {
Msg.info(this,
"PreProcessor Version 0.0: Reading from standard input . . .");
addParseMessage(null,
"PreProcessor: Reading from standard input . . .");
}
fileStack.push("stdin");
} else
@ -1302,12 +1319,12 @@ public class PreProcessor {
FileInputStream fis = new java.io.FileInputStream(filename);
ReInit(fis);
} catch (java.io.FileNotFoundException e) {
Msg.error(this, "PreProcessor Version 0.0: File " + filename
addParseMessage(null, "PreProcessor: File " + filename
+ " not found.");
Msg.error(this, "Usage is one of:");
Msg.error(this, " java PreProcessor < inputfile ...");
Msg.error(this, "OR");
Msg.error(this, " java PreProcessor inputfile ...");
addParseMessage(null, "Usage is one of:");
addParseMessage(null, " java PreProcessor < inputfile ...");
addParseMessage(null, "OR");
addParseMessage(null, " java PreProcessor inputfile ...");
return;
}
}
@ -1321,8 +1338,7 @@ public class PreProcessor {
try {
PreProcessor parser = new PreProcessor(args);
} catch (ParseException e) {
System.out
.println("PreProcessor Version 0.0: Encountered errors during parse.");
System.out.println("PreProcessor: Encountered errors during parse.");
System.out.println("PreProcessor: " + e.getMessage());
}
}
@ -1344,8 +1360,8 @@ void Input() :
( b=TranslationUnit(){if (b.getTruth()==false) break;})*
{
if (conditionDepth!=execStack.size()) {
Msg.error(this, "Imbalance in sequence/nesting of compile-time conditions/logic in input file "+curFileStackTop());
Msg.error(this, " " + execStack);
addParseMessage(null, "Imbalance in sequence/nesting of compile-time conditions/logic in input file "+curFileStackTop());
addParseMessage(null, " " + execStack);
// pop off conditionals, so we can get back on track
while (conditionDepth != execStack.size() && execStack.size() > 0) {
PPToken olde = execStack.pop();;
@ -1439,8 +1455,8 @@ PPToken IFGroup() : { PPToken t, e, olde; }
e=ElIf() t=ElseIfCondition(){
e.setTruth(t.getTruth());
if (execStack.size()==0) {
Msg.error(this, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
throw new ParseException(curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
addParseMessage(null,curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
throw new ParseException(curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
}
olde = (PPToken) execStack.pop();
emitExecSwitch = olde.getEmitSave();
@ -1476,7 +1492,7 @@ PPToken IFGroup() : { PPToken t, e, olde; }
} |
t=Else(){
if (execStack.size()==0) {
Msg.error(this, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
addParseMessage(null, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
throw new ParseException (curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
}
olde = (PPToken) execStack.pop();
@ -1491,7 +1507,7 @@ PPToken IFGroup() : { PPToken t, e, olde; }
} |
t=EndIf(){
if (execStack.size()==0) {
Msg.error(this, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
addParseMessage(null, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
throw new ParseException(curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected");
}
olde = (PPToken) execStack.pop();
@ -1550,8 +1566,8 @@ PPToken Include() : {Token t;PPToken pt;int conditionDepth=execStack.size();}
}
){
if (conditionDepth!=execStack.size()) {
Msg.error(this, "Imbalance in sequence/nesting of compile-time conditions/logic in included file "+t.image);
Msg.error(this, " " + execStack);
addParseMessage(null, "Imbalance in sequence/nesting of compile-time conditions/logic in included file "+t.image);
addParseMessage(null, " " + execStack);
// pop off conditionals, so we can get back on track
while (conditionDepth != execStack.size() && execStack.size() > 0) {
PPToken olde = execStack.pop();
@ -1650,17 +1666,18 @@ PPToken UnDef() : {Token t;}
PPToken MacroArgs() : {Token t,u=null;}
{
t=<MACROMV>{return new PPToken(t);}
(
t=<MACROMV> |
t=<MACROMVTAG >
)
{return new PPToken(t);}
}
PPToken MacroVals() : {Token s,t,u=new Token();u.image="";}
{
(u=Values() |
(LOOKAHEAD(2)(t=<MACRORV>{u.image+=t.image;} | t=<MQUOTED_VALUE> { u.image+="\""+t.image+"\"";}))+
(LOOKAHEAD(2)(t=<MACRORV> {u.image+=t.image;} | t=<MACRORVCMT> { t.image="/"; } | t=<MQUOTED_VALUE> { u.image+="\""+t.image+"\"";}))+
[LOOKAHEAD(2) (LOOKAHEAD(2)t=Values(){u.image+=t.image;})+ ]
// |
// t=<NOTCMTRV>{u.image+=t.image;}
// [LOOKAHEAD(2) (LOOKAHEAD(2)t=Values(){u.image+=t.image;})+ ]
) {return new PPToken(u);}
}
@ -1719,8 +1736,8 @@ PPToken Error() :
{Token t;}
{ t=<ERROR_EXPRN>{
if (emitExecSwitch==true) {
Msg.error(this, curFileStackTop()+"'"+t.beginLine+" Compiler Error:");
Msg.error(this, t.image);
addParseMessage(null, curFileStackTop()+"'"+t.beginLine+" Compiler Error:");
addParseMessage(null, t.image);
}
return new PPToken(t);
}
@ -1730,8 +1747,8 @@ PPToken Warning() :
{Token t;}
{ t=<WARNING_EXPRN>{
if (emitExecSwitch==true) {
Msg.error(this, curFileStackTop()+"'"+t.beginLine+" Warning: ");
Msg.error(this, t.image);
addParseMessage(null, curFileStackTop()+"'"+t.beginLine+" Warning: ");
addParseMessage(null, t.image);
}
return new PPToken(t);
}
@ -1788,7 +1805,9 @@ PPToken Values() :
t.kind = getNumericType(t.image);
}|
t=QuotedValue() |
// t=<CMTVAL> |
t=<VALUESCMT> {
t.image = "/";
} |
t=<MOREVAL>
){
PPToken pt=new PPToken(t);
@ -1808,22 +1827,22 @@ PPToken Text() :
{
( LOOKAHEAD(3)
(LOOKAHEAD(2)(u=<OUTER_TEXT>{ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }
(LOOKAHEAD(2)nl=NewLines(){if (emitExecSwitch==true) buf.append(nl.image,false); else buf.append((u.image.length() == 0 ? "//// " : "") + nl.image, false); } )*|
(LOOKAHEAD(2)nl=NewLines(){if (emitExecSwitch==true) buf.append(nl.image,true); else buf.append((u.image.length() == 0 ? "//// " : "") + nl.image, false); } )* |
u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image,true);} )
[LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }]
[LOOKAHEAD(2)u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true);}]
[LOOKAHEAD(2)u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image, true); }
(LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image, false);})*])+|
u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); } )
[LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }]
[LOOKAHEAD(2)u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false);}]
[LOOKAHEAD(2)u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image, true); else buf.append("//// " + u.image, false); }
(LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image, true); else buf.append("//// " + u.image, false);})*])+|
(LOOKAHEAD(2)(u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true);}
[LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }]|
u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image,true);})
[LOOKAHEAD(2)t=NewLines(){ if (emitExecSwitch==true) buf.append(t.image,false); }]
[LOOKAHEAD(2)u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image,true);}]
[LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }])+ |
(LOOKAHEAD(2)(u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }
[LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }]|
u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); })
[LOOKAHEAD(2)t=NewLines(){ if (emitExecSwitch==true) buf.append(t.image,true); else buf.append("//// " + u.image, false); }]
[LOOKAHEAD(2)u=<OTHER_TEXT>{if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }]
[LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }])+ |
u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }
u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }
) { return buf;}
}
@ -1938,23 +1957,6 @@ PPToken LogicalAndExpression() :
){return t;}
}
/***
PPToken EqualityExpression() :
{PPToken t,u,v;}
{
(t=RelationalExpression()
( LOOKAHEAD(2)
u=EqualTo(){
if (verboseLevel()==7) print(u.image);
}
v=RelationalExpression(){
t.setTruth(t.compareTo(v)==0);
if (verboseLevel()==7) print(": ");
})*
){return t;}
}
***/
PPToken EqualityExpression() :
{PPToken t,u,v;}
{
@ -2377,7 +2379,7 @@ SKIP:
//MORE:
SKIP:
{
<_LCMT: "//" > : SpecialEOLComment |
<_LCMT: "/" "/" > : SpecialEOLComment |
<_CMT: <CMT>(<ECMT>) > : SpecialBlockComment
}
@ -2631,7 +2633,7 @@ TOKEN : {
<PRAGMA>
TOKEN : {
<PRAGMA_EXPRN: <NOTWS> (<NOTENDL>)+ > : DEFAULT |
<PRAGMA_EXPRN: <NOTWS> (<NOTENDL>)* > : DEFAULT |
<PRGLINE: <ENDL> > : DEFAULT
}
@ -2643,7 +2645,7 @@ SKIP : {
<IFDEF>
TOKEN : {
<IFDEF_EXPRN: <NOTWS> (<NOTENDLC> | ( "/" <NOTENDLC>) )+ > : DEFAULT |
<IFDEF_EXPRN: <NOTWS> (<NOTENDLC> | ( "/" <NOTENDLC>) )* > : DEFAULT |
<IFDLINE: <ENDL> > : DEFAULT
}
@ -2655,7 +2657,7 @@ SKIP : {
<IFNDEF>
TOKEN : {
<IFNDEF_EXPRN: <NOTWS> (<NOTENDLC> | ( "/" <NOTENDLC>) )+ > : DEFAULT |
<IFNDEF_EXPRN: <NOTWS> (<NOTENDLC> | ( "/" <NOTENDLC>) )* > : DEFAULT |
<IFNDLINE: <ENDL> > : DEFAULT
}
@ -2679,7 +2681,7 @@ SKIP : {
<WARNING>
TOKEN : {
<WARNING_EXPRN: <NOTWS> (<NOTENDL>)+ > : DEFAULT |
<WARNING_EXPRN: <NOTWS> (<NOTENDL>)* > : DEFAULT |
<WARNLINE: <ENDL> > : DEFAULT
}
@ -2690,7 +2692,7 @@ SKIP : {
<INFO>
TOKEN : {
<INFO_EXPRN: <NOTWS> (<NOTENDL>)+ > : DEFAULT |
<INFO_EXPRN: <NOTWS> (<NOTENDL>)* > : DEFAULT |
<INFOLINE: <ENDL> > : DEFAULT
}
@ -2765,13 +2767,19 @@ SKIP : {
<RVALUES>
TOKEN : {
<VALUES: (<NOTVALCMT> | <NOTCMTCOD> | (<CMT><NOTENDLSTAR>) | (["\\"] ~[" ","\n","\r"]) )+ > : RVALUES |
<VALUES: (<NOTVALCMT> |
<NOTCMTCOD> |
(<CMT><NOTENDLSTAR>) |
("'" ((~["\n","\r","\\"]) | ("\\" ~["\n","\r"] ) ) "'") |
(["\\"] ~[" ","\n","\r"])
)+ > : RVALUES |
<VALUESCMT: <CMT><ENDL> > : DEFAULT |
<MOREVAL: <MANIFEST> >
}
<RVALUES_COMMENT>
SKIP : {
<_ECMT7: (~["*"] | "*" ~["/"])* > : RVALUES_COMMENT |
<_ECMT7: ~["*"] | "*" ~["/"] > : RVALUES_COMMENT |
<_EECMT7: <ENDCMT> > : RVALUES
}
@ -2784,13 +2792,13 @@ SKIP:
<QUOTED_VAL>
TOKEN:
{
<QUOTED_VALUE: ( ~["\"","\\"] | "\\" ~["\n", "\r"] )* > : QUOTED_VAL
<QUOTED_VALUE: ( ~["\"","\\"] | "\\" ~["\n", "\r"] )+ > : QUOTED_VAL
}
<MACROARGS>
TOKEN : {
<MACROMV: <MANIFEST> >
// <MACROMV: <MANIFEST> >
<MACROMV: <MANIFEST> > |
<MACROMVTAG: "[" <MANIFEST > "]" >
}
<MACROARGS>
@ -2816,7 +2824,8 @@ TOKEN : {
<MACROVALS>
TOKEN : {
<MACRORV: ( <NOTCMTCOD> | <CMT><NOTENDLSTAR> | ("\\" ~[" ","\t","\\","\n","\r"]))+ > : MACROVALS
<MACRORV: ( <NOTCMTCOD> | <CMT><NOTENDLSTAR> | ("\\" ~[" ","\t","\\","\n","\r"]))+ > : MACROVALS |
<MACRORVCMT: <CMT><ENDL> > : DEFAULT
}
<MACROVALS>
@ -2844,7 +2853,7 @@ TOKEN:
<MACROVALS_COMMENT>
SKIP : {
<_ECMT9: (~["*"] | "*" ~["/"])* > : MACROVALS_COMMENT |
<_ECMT9: ~["*"] | "*" ~["/"] > : MACROVALS_COMMENT |
<_EEECMT9: <ENDCMT> > : MACROVALS |
<_EECMT9: <ENDCMT> (<WSP>)* <ENDL> > : DEFAULT
}

View File

@ -17,6 +17,7 @@ package ghidra.app.util.cparser;
import static org.junit.Assert.*;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
@ -126,26 +127,43 @@ public class CParserTest extends AbstractGenericTest {
@Test
public void testHeaderParsing() throws Exception {
DataTypeManager dtMgr;
CParser parser;
parser = new CParser();
// Uncomment to save the parse results to a GDT file to check out
//
// File fgdt = new File("/tmp/CParserTest.gdt");
// fgdt.delete();
// FileDataTypeManager fdt = FileDataTypeManager.createFileArchive(fgdt);
// CParser parser = new CParser(fdt, true, null);
// DataTypeManager dtMgr = fdt;
CParser parser = new CParser();
// FileDataTypeManager fdt = FileDataTypeManager.createFileArchive(fgdt);
// parser = new CParser(fdt, true, null);
String resourceName;
resourceName = "CParserTest.h";
InputStream is = CParserTest.class.getResourceAsStream(resourceName);
// resourceName = "/home/mjtiern/CParserPlugin.out.sav";
// is = new FileInputStream(new File(resourceName));
parser.setParseFileName("CParserTest.h");
parser.parse(is);
DataTypeManager dtMgr = parser.getDataTypeManager();
dtMgr = parser.getDataTypeManager();
// Uncomment to save the parse results to a GDT file to check out
//
// fdt.save();
// fdt.close();
String parseMessages = parser.getParseMessages();
System.out.println(parseMessages);
assertTrue("Duplicate ENUM message", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16"));
assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\""));
assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
DataType dt;
DataType pointedToDT;
ParameterDefinition[] funcArgs;
FunctionDefinition funcDef;
String str;
dt = dtMgr.getDataType(new CategoryPath("/"), "_IO_FILE_complete");
@ -153,12 +171,67 @@ public class CParserTest extends AbstractGenericTest {
DataTypeComponent data3 = sldt.getComponent(2);
assertEquals("Computed Array correct", 40, data3.getLength());
dt = dtMgr.getDataType(new CategoryPath("/"), "fnptr"); // typedef int (*fnptr)(struct fstruct);
// "fnptr" named typedef of pointer to "int fnptr(fstruct )" --- should an anonymous function name be used?
assertTrue("typedefed fnptr", dt instanceof TypeDef);
dt = ((TypeDef) dt).getDataType();
assertTrue("typedef fnptr *", dt instanceof Pointer);
dt = ((Pointer) dt).getDataType();
assertTrue("typedef fnptr *", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt;
funcArgs = funcDef.getArguments();
assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Structure);
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "int fnptr(fstruct )", replaceAnonFuncName(str));
// Test
dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Once"); // void __cdecl _Once(_Once_t *, void (__cdecl *)(void));
// void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymouse function * --> void (__cdecl *)(void)
// void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymous function * --> void (__cdecl *)(void)
assertTrue("_Once function definition", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _Once(_Once_t * , _func_anon_ * )", replaceAnonFuncName(str));
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
funcArgs = funcDef.getArguments();
assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Pointer);
assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer);
pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT;
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Twice"); // void __cdecl _Once(_Once_t *, void (__cdecl *)(void));
// void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymous function * --> void (__cdecl *)(void)
assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString();
assertEquals("calling convention _Twice", "__stdcall", funcDef.getGenericCallingConvention().getDeclarationName());
funcArgs = funcDef.getArguments();
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT;
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Thrice"); // void __cdecl _Once(_Once_t *, void (__cdecl *)(void));
// void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymous function * --> void (__cdecl *)(void)
assertTrue("_Twice function definition", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt;
str = funcDef.getPrototypeString();
assertEquals("calling convention _Thrice", "", funcDef.getGenericCallingConvention().getDeclarationName());
funcArgs = funcDef.getArguments();
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
funcDef = (FunctionDefinition) pointedToDT;
assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName());
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
dt = dtMgr.getDataType(new CategoryPath("/"), "UShortInt");
assertTrue(dt instanceof TypeDef);
assertTrue("signature not correct",
@ -320,14 +393,125 @@ public class CParserTest extends AbstractGenericTest {
assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
assertEquals("signature not correct", "int fputs(char * , void * )", str);
dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParam");
assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
assertEquals("signature not correct", "void funcParam(_func_anon_ * )", replaceAnonFuncName(str));
funcDef = (FunctionDefinition) dt;
funcArgs = funcDef.getArguments();
assertTrue("ptr", funcArgs[0].getDataType() instanceof Pointer);
pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
str = ((FunctionDefinition) pointedToDT).getPrototypeString();
assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str));
for (int i=1; i < 11; i++) {
dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParam"+i);
assertTrue("not a function" + dt.getName(), dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
funcDef = (FunctionDefinition) dt;
funcArgs = funcDef.getArguments();
assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer);
pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType();
assertTrue("ptr not to a function " + dt.getName(), pointedToDT instanceof FunctionDefinition);
funcArgs = ((FunctionDefinition) pointedToDT).getArguments();
assertEquals("function args != 1 " + pointedToDT, 1, funcArgs.length);
assertEquals("double", funcArgs[0].getDataType().getName());
}
dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParamNoPtr");
assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
assertEquals("signature not correct", "double funcParamNoPtr(double x, func * func)", str);
funcDef = (FunctionDefinition) dt;
funcArgs = funcDef.getArguments();
assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer);
pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
str = ((FunctionDefinition) pointedToDT).getPrototypeString();
assertEquals("signature not correct", "double func(double , void * )", str);
dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParmWithName");
assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
assertEquals("signature not correct", "void funcParmWithName(_func_arg * _func_arg)", str);
dt = dtMgr.getDataType(new CategoryPath("/functions"), "__mem_func");
assertTrue("not a function", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
assertEquals("signature not correct", "void __mem_func("
+ "void * ,"
+ " char * * ,"
+ " int * * * ,"
+ " _func_anon_ * ,"
+ " _func_anon_1 * ,"
+ " _func_anon_2 * )", replaceAnonFuncName(str));
funcDef = (FunctionDefinition) dt;
funcArgs = funcDef.getArguments();
assertTrue("ptr", funcArgs[5].getDataType() instanceof Pointer);
pointedToDT = ((Pointer) funcArgs[5].getDataType()).getDataType();
assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition);
str = ((FunctionDefinition) pointedToDT).getPrototypeString();
assertEquals("signature not correct", "void * _func_anon_(void * , size_t )", replaceAnonFuncName(str));
// ensure that temporary anonymous function definition names did not get retained
ArrayList<DataType> list = new ArrayList<>();
dtMgr.findDataTypes("_func_", list);
assertTrue(list.isEmpty());
dtMgr.findDataTypes("_func_1", list);
assertTrue(list.isEmpty());
assertTrue(
"Expected anonymous function replaced (is blarg first function in CParserTest.h file?):" +
list,
list.isEmpty());
dt = dtMgr.getDataType(new CategoryPath("/functions"), "blarg");
assertTrue("named function blarg", dt instanceof FunctionDefinition);
str = ((FunctionDefinition) dt).getPrototypeString();
assertEquals("signature not correct", "void blarg(int * , long[0][0] * )", replaceAnonFuncName(str));
// Structure extension
dt = dtMgr.getDataType(new CategoryPath("/"), "System_System_SystemException_Fields");
assertTrue (dt instanceof Structure);
sdt = (Structure) dt;
comp = sdt.getComponent(1);
assertEquals("foo", comp.getFieldName());
comp = sdt.getComponent(2);
assertEquals("bar", comp.getFieldName());
assertEquals("short", comp.getDataType().getName());
comp = sdt.getComponent(0);
assertTrue (comp.getDataType() instanceof Structure);
assertEquals ("extended parent ", "System_SystemException_Fields", comp.getDataType().getName());
sdt = (Structure) comp.getDataType();
comp = sdt.getComponent(0);
assertTrue (comp.getDataType() instanceof Structure);
assertEquals ("extended parent ", "System_Exception_Fields", comp.getDataType().getName());
// Check arrays of functions in structures
dt = dtMgr.getDataType(new CategoryPath("/"), "SomeStruct");
assertTrue (dt instanceof Structure);
sdt = (Structure) dt;
int numComponents = sdt.getNumComponents();
assertEquals("Number of components in struct arrays of function pointer + \n" + sdt.toString(),
8, numComponents);
DataTypeComponent component = sdt.getComponent(2);
assertEquals("procArray1", component.getFieldName());
dt = component.getDataType();
assertTrue("procArray1 member is a an array", dt instanceof Array);
assertEquals("ProcArray1 member bad size", 2, ((Array) dt).getNumElements());
dt = ((Array) dt).getDataType();
assertTrue("ProcArray1 is not an Array of pointers", dt instanceof Pointer);
dt = ((Pointer) dt).getDataType();
assertTrue("procArray1 member is Array of function pointers", dt instanceof FunctionDefinition);
funcDef = (FunctionDefinition) dt;
funcArgs = funcDef.getArguments();
str = funcDef.getPrototypeString();
assertEquals("signature not correct", "char _func_anon_(int * , short * )", replaceAnonFuncName(str));
dt = dtMgr.getDataType(new CategoryPath("/"), "EmptyBuffer");
assertTrue(dt instanceof Structure);
sdt = (Structure) dt;
@ -389,7 +573,6 @@ public class CParserTest extends AbstractGenericTest {
assertTrue(dt instanceof Structure);
sdt = (Structure) dt;
assertEquals("Default packing", false, sdt.hasExplicitPackingValue());
assertEquals("Default packing", true, sdt.hasDefaultPacking());
// data type after #pragma got parsed
dt = dtMgr.getDataType("/functions/dtAfterPragma"); // typedef int (*fnptr)(struct fstruct);
@ -445,6 +628,19 @@ public class CParserTest extends AbstractGenericTest {
cdt = sdt.getComponent(1);
assertTrue(cdt.getDataType() instanceof Array);
assertEquals("Array field defined with sizeof typedef", 2084, cdt.getLength());
}
private String replaceAnonFuncName(String str) {
int num = 0;
String replStr = str;
String origStr = null;
while (!replStr.equals(origStr)) {
origStr = replStr;
replStr = replStr.replaceFirst("_func_([0-9])+", "_func_anon_" + (num == 0 ? "" : num));
num++;
}
return replStr;
}
}

View File

@ -30,13 +30,14 @@ import ghidra.program.model.data.Enum;
public class PreProcessorTest extends AbstractGenericTest {
private static String resourceName = "PreProcessorTest.h";
private static CategoryPath path = new CategoryPath(new CategoryPath("/PreProcessorTest.h"), "defines");
private static CategoryPath path =
new CategoryPath(new CategoryPath("/PreProcessorTest.h"), "defines");
// must get rid of after all tests
private static StandAloneDataTypeManager dtMgr;
private static ByteArrayOutputStream baos = new ByteArrayOutputStream();
private static PreProcessor parser;
long value;
String defname;
@ -47,8 +48,9 @@ public class PreProcessorTest extends AbstractGenericTest {
@BeforeClass
public static void init() {
URL url = PreProcessorTest.class.getResource(resourceName);
String[] args = new String[] {"-I"+url.getPath()+"/..","-DFROM_ARG_VALUE=300", "-DFROM_ARG_DEF", "-DFROM_ARG_EMPTY=\"\""};
String[] args = new String[] { "-I" + url.getPath() + "/..", "-DFROM_ARG_VALUE=300",
"-DFROM_ARG_DEF", "-DFROM_ARG_EMPTY=\"\"" };
parser = null;
try {
parser = new PreProcessor(args);
@ -73,34 +75,39 @@ public class PreProcessorTest extends AbstractGenericTest {
//// fullName = "adoguids.h";
//// parser.parse(fullName);
parser.parse(url.getFile());
try {
parser.parse(url.getFile());
}
catch (ParseException e) {
e.printStackTrace();
}
// Uncomment to print out parse results
// System.err.println(baos.toString());
dtMgr = new StandAloneDataTypeManager("parsed");
parser.getDefinitions().populateDefineEquates(dtMgr);
parser.getDefinitions().populateDefineEquates(null, dtMgr);
}
@AfterClass
public static void destroy() {
dtMgr = null;
baos = null;
parser = null;
}
@Test
public void testHeaderParsed() throws Exception {
String results = baos.toString("ASCII");
int end = results.lastIndexOf(";") + 1;
String endStr = results.substring(end - 9, end);
assertEquals("theEnd();", endStr);
assertTrue("macro expansion _fpl(bob) failed ", results
.indexOf("extern int __declspec(\"fp(\\\"l\\\", \" #bob \")\") __ifplbob;") != -1);
}
@Test
public void testDefines() throws Exception {
long value;
@ -160,7 +167,7 @@ public class PreProcessorTest extends AbstractGenericTest {
defname = "isDefineOnValue";
value = 1;
checkDefine(dtMgr, path, value, defname);
defname = "DID_EXPANSION";
value = 1;
checkDefine(dtMgr, path, value, defname);
@ -168,33 +175,32 @@ public class PreProcessorTest extends AbstractGenericTest {
defname = "BIGNUM";
value = 64 * 16 + 16;
checkDefine(dtMgr, path, value, defname);
defname = "NEWLINETEST1";
value = 1;
checkDefine(dtMgr, path, value, defname);
defname = "NEWLINETEST2";
value = 2;
checkDefine(dtMgr, path, value, defname);
defname = "NEWLINETEST3";
value = 3;
checkDefine(dtMgr, path, value, defname);
defname = "SEPERATORC";
String defval = parser.getDef(defname);
assertEquals(defval, "','");
}
@Test
public void testDefinesArgValue() {
defname = "DID_ARG_VALUE";
value = 1;
checkDefine(dtMgr, path, value, defname);
// This is from a -D arg define, not from a file
CategoryPath argCategoryPath = new CategoryPath(CategoryPath.ROOT, "defines");
CategoryPath argCategoryPath = new CategoryPath(CategoryPath.ROOT, "defines");
defname = "FROM_ARG_VALUE";
value = 300;
checkDefine(dtMgr, argCategoryPath, value, defname);
@ -207,6 +213,13 @@ public class PreProcessorTest extends AbstractGenericTest {
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testQuotedQuote() {
defname = "TEST_QUOTED_QUOTE";
String defval = parser.getDef(defname);
assertEquals(defval, "QUOTED('\"')");
}
@Test
public void testDefinesArgDef() {
defname = "DID_ARG_DEF";
@ -276,30 +289,45 @@ public class PreProcessorTest extends AbstractGenericTest {
value = 1;
checkDefine(dtMgr, path, value, defname);
}
@Test
public void testMultipleInclude() {
defname = "INCLUDE1";
String defval = parser.getDef(defname);
assertNotNull("Had 1 duplicate include", defval);
defname = "INCLUDE2";
defval = parser.getDef(defname);
assertNotNull("Had 2 duplicate include", defval);
defname = "INCLUDE3";
defval = parser.getDef(defname);
assertNotNull("Had 3 duplicate include", defval);
defname = "INCLUDE4";
defval = parser.getDef(defname);
assertNotNull("Had 4 duplicate include", defval);
defname = "INCLUDE5";
defval = parser.getDef(defname);
// if a define is not defined, getDef() returns name of define as value
assertEquals("No INCLUDE5 define", "INCLUDE5", defval);
}
@Test
public void testVarags() {
defname = "EPRINTF_VARARGS";
String defval = parser.getDef(defname);
assertEquals("fprintf (stderr, \"%s:%d: \", input_file, lineno)", defval);
defname = "VPRINTF_NO_ARGS";
defval = parser.getDef(defname);
assertEquals("fprintf (stderr, \"no args!\\n\" )", defval);
defname = "VPRINTF_ARGS";
defval = parser.getDef(defname);
assertEquals("fprintf (stderr, \"%s!\\n\" , \"I have args\")", defval);
}
private void checkDefine(StandAloneDataTypeManager dtMgr, CategoryPath path, long value,
String defname) {

View File

@ -58,6 +58,7 @@ abstract class AbstractCompositeTest extends AbstractGTest {
throw new FileNotFoundException("Resource not found: " + headerResourcePath);
}
// Msg.debug(this, "Parsing C headers from " + headerResourcePath);
parser.setParseFileName(headerResourcePath);
parser.parse(is);
}

View File

@ -17,8 +17,78 @@
/** Test parsing header file for CParser. Most of the file is just checked to make sure it gets through parsing.
** Some data types are checked. More checking of the parsed information would be beneficial at some point.
**/
/**
* Check initial anonymous __func_1, is give an name blarg
* Note: This must be first function for junit tests to pass
**/
void blarg(int *, long[][][]);
void blarg(int *);
/**
* Test arrays of anonymous functions in a structure
**/
typedef struct SomeStruct {
int first_member;
int *second_member[3];
char (*procArray1[2])(int *, short *);
int anotherMember;
int (*procArray2[2])(int *, int *);
int (*LoneProc1)(char, int);
int (*LoneProc2)(char, int);
int finalMember;
} SomeStruct;
/**
* Anonymous function parameter definitions
**/
void funcParam(void (*)(void));
void funcParmWithName(void (*_func_arg)(void));
double funcParamNoPtr(double x, double func(double, void *));
double funcParam1( double, double (*)( double ) );
double funcParam2( double, double( double ) ); // this guy _func_
double funcParam3( const double, double (*)( double ) );
double funcParam4( const double, double( double ) ); // this guy _func_
double funcParam5( double, double (*)( const double ) );
double funcParam6( double, double( const double ) ); // this guy _func_
double funcParam7( const double, double (*)( const double ) );
double funcParam8( const double, double( const double ) ); // this guy _func_
double funcParam9(double, double (* const)(double ) );
double funcParam10(double, double (__cdecl *)(double ) );
typedef unsigned int size_t;
typedef unsigned long size_t;
void* __cdecl memset(
void* _Dst,
int _Val,
size_t _Size
);
typedef size_t rsize_t;
static __inline int __cdecl memcpy_s(
void* const _Destination,
rsize_t const _DestinationSize,
void const* const _Source,
rsize_t const _SourceSize
) {
if (_SourceSize == 0)
{
return 0;
}
memset(_Destination, 0, _DestinationSize);
}
void __mem_func (void *, char **, int ***, long (*) (size_t),
short *(*) (size_t),
void *(*) (void *, size_t));
void * foo;
@ -28,6 +98,12 @@
typedef int pid_t;
typedef long _Once_t;
void __cdecl _Once(_Once_t *, void (__cdecl *)(void));
void __stdcall _Twice(void (__cdecl *)(void));
void _Thrice(void (__cdecl *)(void));
/**
** use of long as an attribute
@ -51,6 +127,7 @@ int (__stdcall * GetSectionBlock) (
long align=1,
void **ppBytes=0) ;
#pragma region Input compatibility macros
#pragma warning(disable)
@ -59,6 +136,9 @@ int (__stdcall * GetSectionBlock) (
#pragma section(".CRTMP$XCA",long,read)
#pragma GCC poison (*(volatile uint8_t *)(0xB3))
#pragma our macros nachos (for use only within FileProvider.h)
/**
** Packing tests
@ -231,8 +311,32 @@ int fputs( char * , void * ) __asm("_" "fputs" "$FPOOTS");
void _exit(int) __attribute__((noreturn));
// C11 noreturn
void _Noreturn _Noreturn_exit(int);
// C23 Attributes
int [[deprecated]] imDeprecated(int);
int [[gnu::deprecated]] imDeprecatedToo(int) ;
int [[deprecated("bad design")]] imDeprecatedToo(int) ;
int [[deprecated("bad design")]] imDeprecatedToo(int) ;
[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
int f(void); // declare f with four attributes
[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(void); // same as above, but uses a single attr specifier that contains four attributes
// __attribute__
int abs(int) __attribute__((bob));
enum __attribute__((enum_extensibility(open))) OpenEnum {
B0, B1
};
typedef int (__cdecl * _onexit_t)(void);
typedef int int32_t;
@ -249,6 +353,23 @@ __checkint(int val, int* err) {
return (int32_t) val;
}
/**
** Structure extension
**/
struct __declspec(align(8)) System_Exception_Fields {
int _HResult;
};
struct System_SystemException_Fields : System_Exception_Fields {
int foo;
};
struct System_System_SystemException_Fields : System_SystemException_Fields {
int foo;
short bar;
};
typedef enum {} EmptyEnum;
@ -284,11 +405,17 @@ struct fowstruct {
fstruct *next;
};
@protocol Bubba
bob
marley
@end
@protocol SwiftProtocol
@required
- (void) method;
@end
typedef struct __attribute__ ((packed))
{
int test1;
@ -477,6 +604,8 @@ typedef union __declspec(intrin_type) __declspec(align(8)) __m64
unsigned __int32 m64_u32[2];
} __m64;
extern __m64 _mm_loadh_pi1(__m64, const __m64 *);
extern __m64 _mm_loadh_pi2(__m64, __m64 const *);
@ -679,6 +808,10 @@ enum options_enum {
ONE_UP,
PLUS_SET = 4 + 12,
PLUS_SET = 4 + 12,
#pragma endit
MINUS_SET = 12 - 1,
@ -744,6 +877,28 @@ struct s fs_pi = (struct s){ .z = "Pi", .x = 3, .y = 3.1415 };
struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2 };
/**
** _Alignas
**/
// every object of type struct data will be aligned to 128-byte boundary
struct data {
char x;
_Alignas(128) char cacheline[128]; // over-aligned array of char,
// not array of over-aligned chars
};
int aligning(void)
{
int sof = sizeof(struct data);
int aof = _Alignof(struct data);
printf("sizeof(data) = %zu \n", sizeof(struct data));
printf("alignment of data = %zu\n", _Alignof(struct data));
_Alignas(2048) struct data d; // this instance of data is aligned even stricter
}
typedef long long LRESULT;
@ -923,6 +1078,7 @@ char lineInFunc(int i) {
/**
** Check _Static_assert support
**/
#line 1 "static_assert.h"
int check_assert(void)
{
// test with message
@ -933,4 +1089,16 @@ int check_assert(void)
_Static_assert(sizeof(int) < sizeof(char));
static_assert(sizeof(int) < sizeof(char));
int x;
static_assert(sizeof(int) > sizeof(char));
}
struct statcheck {
int a;
static_assert(1 + 1 == 3, "1 + 1 == 3, fail!");
int b;
};
typedef int test_before;
static_assert(1 + 1 == 2, "That's true!");
typedef int test_after;

View File

@ -13,6 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* test define symbols of length 1 */
#ifdef a
#undef a
#endif
/* definition coming from -D, should evaluate to true */
#if FROM_ARG_VALUE
@ -183,6 +188,12 @@ int TEST_FAILED;
#define O_M 0xffff0000 // test commment
#define N_V 0x60010001 // test comment
#if 0 /* comment
*/
# define DefineNameSlash ?? * /
# define DefineMacroSlash(aba) aba ?? * /
#endif
#define K 0x06010000
/**
@ -381,6 +392,22 @@ ldp LDP((
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wmismatched-tags\"")
/**
** Vararg defined
**/
# define SETIT(value, [attributes])
#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)
#define EPRINTF_VARARGS eprintf ("%s:%d: ", input_file, lineno)
#define vprintf(format, ...) \
fprintf (stderr, format __VA_OPT__(,) __VA_ARGS__)
#define VPRINTF_NO_ARGS vprintf ("no args!\n")
#define VPRINTF_ARGS vprintf ("%s!\n", "I have args")
#if defined(__has_include)
#if __has_include(<gethostuuid_private.h>)
@ -419,4 +446,9 @@ int does_not_has_include();
#endif
// 5 blank lines above
// test single quoted qoutes
#define BEGINC QUOTED('"')
#define TEST_QUOTED_QUOTE QUOTED('"')
theEnd();

View File

@ -0,0 +1,462 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Parses AVR8 header files and extracts special memory definitions for each processor variant
//
// Defined enums can be applied to the program and the enum value is interpreted as an address, and the
// name of the enum the label at that addres.
//
//@category Data Types
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import org.bouncycastle.util.Arrays;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.CPP.DefineTable;
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.FileDataTypeManager;
import ghidra.program.util.AddressEvaluator;
import ghidra.util.Msg;
public class CreateAVR8GDTArchiveScript extends GhidraScript {
private File outputDirectory;
private static String headerFilePath = "/data/HeaderFiles";
private static String filenames[] = {
"stdint.h",
"avr/io.h",
};
private static String orig_args[] = {
"-I"+headerFilePath+"/avr/include",
"-I"+headerFilePath+"/avr/include/avr",
"-D__STDC",
"-D_GNU_SOURCE",
"-D__GLIBC_HAVE_LONG_LONG=1",
"-D__DOXYGEN__=true", // header files have special __attributes__ if not defined
};
private static String processorVariants[] = {
"AT94K",
"AT43USB320",
"AT43USB355",
"AT76C711",
"AT86RF401",
"AT90PWM1",
"AT90PWM2",
"AT90PWM2B",
"AT90PWM3",
"AT90PWM3B",
"AT90PWM216",
"AT90PWM316",
"AT90PWM161",
"AT90PWM81",
"ATmega8U2",
"ATmega16M1",
"ATmega16U2",
"ATmega16U4",
"ATmega32C1",
"ATmega32M1",
"ATmega32U2",
"ATmega32U4",
"ATmega32U6",
"ATmega64C1",
"ATmega64M1",
"ATmega128",
"ATmega128A",
"ATmega1280",
"ATmega1281",
"ATmega1284",
"ATmega1284P",
"ATmega128RFA1",
"ATmega1284RFR2",
"ATmega128RFR2",
"ATmega2564RFR2",
"ATmega256RFR2",
"ATmega2560",
"ATmega2561",
"AT90CAN32",
"AT90CAN64",
"AT90CAN128",
"AT90USB82",
"AT90USB162",
"AT90USB646",
"AT90USB647",
"AT90USB1286",
"AT90USB1287",
"ATmega644RFR2",
"ATmega64RFR2",
"ATmega64",
"ATmega64A",
"ATmega640",
"ATmega644",
"ATmega644A",
"ATmega644P",
"ATmega644PA",
"ATmega645",
"ATmega645A",
"ATmega645P",
"ATmega6450",
"ATmega6450A",
"ATmega6450P",
"ATmega649",
"ATmega649A",
"ATmega6490",
"ATmega6490A",
"ATmega6490P",
"ATmega649P",
"ATmega64HVE",
"ATmega64HVE2",
"ATmega103",
"ATmega32",
"ATmega32A",
"ATmega323",
"ATmega324P",
"ATmega324A",
"ATmega324PA",
"ATmega325",
"ATmega325A",
"ATmega325P",
"ATmega325PA",
"ATmega3250",
"ATmega3250A",
"ATmega3250P",
"ATmega3250PA",
"ATmega328P",
"ATmega328",
"ATmega329",
"ATmega329A",
"ATmega329P",
"ATmega329PA",
"ATmega3290PA",
"ATmega3290",
"ATmega3290A",
"ATmega3290P",
"ATmega32HVB",
"ATmega32HVBREVB",
"ATmega406",
"ATmega16",
"ATmega16A",
"ATmega161",
"ATmega162",
"ATmega163",
"ATmega164P",
"ATmega164A",
"ATmega164PA",
"ATmega165",
"ATmega165A",
"ATmega165P",
"ATmega165PA",
"ATmega168",
"ATmega168A",
"ATmega168P",
"ATmega168PA",
"ATmega168PB",
"ATmega169",
"ATmega169A",
"ATmega169P",
"ATmega169PA",
"ATmega8HVA",
"ATmega16HVA",
"ATmega16HVA2",
"ATmega16HVB",
"ATmega16HVBREVB",
"ATmega8",
"ATmega8A",
"ATmega48",
"ATmega48A",
"ATmega48PA",
"ATmega48PB",
"ATmega48P",
"ATmega88",
"ATmega88A",
"ATmega88P",
"ATmega88PA",
"ATmega88PB",
"ATmega8515",
"ATmega8535",
"AT90S8535",
"AT90C8534",
"AT90S8515",
"AT90S4434",
"AT90S4433",
"AT90S4414",
"ATtiny22",
"ATtiny26",
"AT90S2343",
"AT90S2333",
"AT90S2323",
"AT90S2313",
"ATtiny4",
"ATtiny5",
"ATtiny9",
"ATtiny10",
"ATtiny20",
"ATtiny40",
"ATtiny2313",
"ATtiny2313A",
"ATtiny13",
"ATtiny13A",
"ATtiny25",
"ATtiny4313",
"ATtiny45",
"ATtiny85",
"ATtiny24",
"ATtiny24A",
"ATtiny44",
"ATtiny44A",
"ATtiny441",
"ATtiny84",
"ATtiny84A",
"ATtiny841",
"ATtiny261",
"ATtiny261A",
"ATtiny461",
"ATtiny461A",
"ATtiny861",
"ATtiny861A",
"ATtiny43U",
"ATtiny48",
"ATtiny88",
"ATtiny828",
"ATtiny87",
"ATtiny167",
"ATtiny1634",
"AT90SCR100",
"ATxmega8E5",
"ATxmega16A4",
"ATxmega16A4U",
"ATxmega16C4",
"ATxmega16D4",
"ATxmega16E5",
"ATxmega32A4",
"ATxmega32A4U",
"ATxmega32C3",
"ATxmega32C4",
"ATxmega32D3",
"ATxmega32D4",
"ATxmega32E5",
"ATxmega64A1",
"ATxmega64A1U",
"ATxmega64A3",
"ATxmega64A3U",
"ATxmega64A4U",
"ATxmega64B1",
"ATxmega64B3",
"ATxmega64C3",
"ATxmega64D3",
"ATxmega64D4",
"ATxmega128A1",
"ATxmega128A1U",
"ATxmega128A4U",
"ATxmega128A3",
"ATxmega128A3U",
"ATxmega128B1",
"ATxmega128B3",
"ATxmega128C3",
"ATxmega128D3",
"ATxmega128D4",
"ATxmega192A3",
"ATxmega192A3U",
"ATxmega192C3",
"ATxmega192D3",
"ATxmega256A3",
"ATxmega256A3U",
"ATxmega256A3B",
"ATxmega256A3BU",
"ATxmega256C3",
"ATxmega256D3",
"ATxmega384C3",
"ATxmega384D3",
"ATA5702M322",
"ATA5782",
"ATA5790",
"ATA5790N",
"ATA5791",
"ATA5831",
"ATA5272",
"ATA5505",
"ATA5795",
"ATA6285",
"ATA6286",
"ATA6289",
"ATA6612C",
"ATA6613C",
"ATA6614Q",
"ATA6616C",
"ATA6617C",
"ATA664251",
"ATA8210",
"ATA8510",
"ATtiny28",
"AT90S1200",
"ATtiny15",
"ATtiny12",
"ATtiny11",
"M3000",
};
@Override
protected void run() throws Exception {
outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir");
parseGDT_AVR8();
}
public void parseGDT_AVR8() throws Exception {
// If need data types from other archives can add other archives
// Using another archive while parsing will cause:
// - a dependence on the other archive
// - any missing data types while parsing are supplied if present from existingDTMgr
// - after parsing all data types parsed that have an equivalent data type will be
// replaced by the data type from the existingDTMgr
//
// NOTE: This will only occur if the data type from the exisitngDTMgr is equivalent.
//
ResourceFile clib64ArchiveFile = DataTypeArchiveUtility.findArchiveFile("generic_clib.gdt");
File file = new File(clib64ArchiveFile.getAbsolutePath());
DataTypeManager vsDTMgr = FileDataTypeManager.openFileArchive(file, false);
DataTypeManager openTypes[] = { vsDTMgr };
// by defaults, don't want to be dependent on other archives if have all necessary definitions
// comment out if missing data types
openTypes = null;
String dataTypeFile = outputDirectory + File.separator + "avr8.gdt";
File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
// 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
// macro definitions that will cause the parse to fail.
//
for (String variantName : processorVariants) {
parseProcessorDefs(variantName, dtMgr, openTypes);
}
dtMgr.save();
dtMgr.close();
}
/**
* Turn string into a file, delete old archive if it exists
*
* @param dataTypeFile
*
* @return file
*/
private File getArchiveFile(String dataTypeFile) {
File f = new File(dataTypeFile);
if (f.exists()) {
f.delete();
}
String lockFile = dataTypeFile + ".ulock";
File lf = new File(lockFile);
if (lf.exists()) {
lf.delete();
}
return f;
}
/**
* parse a single AVR8 variant
*
* @param procName name of processor
* @param dtMgr open data type manager to add types to
* @param openTypes any open archives for missing data types
* @throws ParseException something happened
* @throws ghidra.app.util.cparser.C.ParseException
* @throws IOException io exception
*/
private void parseProcessorDefs(String procName, FileDataTypeManager dtMgr, DataTypeManager[] openTypes)
throws ParseException, ghidra.app.util.cparser.C.ParseException, IOException {
PreProcessor cpp;
String args[] = Arrays.append(orig_args, "-D__AVR_"+procName+"__");
cpp = new PreProcessor();
String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, "avr8:LE:16:atmega256", "gcc", cpp, monitor);
Msg.info(this, messages);
storeExtraDefinitions(procName, dtMgr, openTypes, cpp);
}
/**
* get extra defines special for the AVR8 that describe memory locations per variant
*
* @param procName processor variant
* @param dtMgr add data types to dtMgr
* @param cpp pre-processor holds macros/defines from parsing
*/
private void storeExtraDefinitions(String procName, FileDataTypeManager dtMgr, DataTypeManager[] openTypes, PreProcessor cpp) {
int transactionID = dtMgr.startTransaction("Add Extra Equates");
DefineTable definitions = cpp.getDefinitions();
Iterator<String> defineNames = definitions.getDefineNames();
while (defineNames.hasNext()) {
String defName = defineNames.next();
String rawDefValue = definitions.getValue(defName);
String expandValue = definitions.expandDefine(defName);
if (expandValue == null || expandValue.length()==0) {
// can't expand, must be a macro
continue;
}
// look at string and see if if the definition of an SFR, register
String PTR_PREFIX_16 = "(*(volatile uint16_t *)";
String PTR_PREFIX_8 = "(*(volatile uint8_t *)";
Long lvalue = null;
if (expandValue.startsWith(PTR_PREFIX_16)) {
// ptr to 16 bit address in SFR
expandValue = expandValue.replace(PTR_PREFIX_16, "");
expandValue = expandValue.substring(0,expandValue.lastIndexOf(')'));
} else if (expandValue.startsWith(PTR_PREFIX_8) ) {
// ptr to 8 bit address in SFR
expandValue = expandValue.replace(PTR_PREFIX_8, "");
expandValue = expandValue.substring(0,expandValue.lastIndexOf(')'));
} else {
continue;
}
if (expandValue == null || expandValue.length() == 0) {
continue;
}
lvalue = AddressEvaluator.evaluateToLong(expandValue);
if (lvalue == null) {
continue;
}
definitions.populateDefineEquate(openTypes, dtMgr, "memory", "", defName, lvalue);
}
dtMgr.endTransaction(transactionID, true);
}
}

View File

@ -0,0 +1,186 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Parses sample linux and windows JNI header files into .gdt data type archive.
//
// To replace existing header files and have the data type ID's synchronized
//
// Must run SynchronizeGDTCategoryPaths.java script with old and replacement GDT
// archive to synchronize upper/lower case paths
/// (only on windows archives)
//
// Then Run DataTypeArchiveTransformer in eclipse to synchronize old data types ID's
//
//@category Data Types
import java.io.File;
import java.io.IOException;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.util.Msg;
public class CreateJNIGDTArchivesScript extends GhidraScript {
private File outputDirectory;
// location of header files base directory
private static String headerFilePath = "/data/HeaderFiles";
@Override
protected void run() throws Exception {
outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir");
parseGDT_Linux_JNI();
parseGDT_Windows_JNI();
}
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
File f = getArchiveFile(dataTypeFile);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
Msg.info(this, messages);
dtMgr.save();
dtMgr.close();
}
/**
* Turn string into a file, delete old archive/lock file if it exists
*
* @param dataTypeFile
*
* @return file
*/
private File getArchiveFile(String dataTypeFile) {
File f = new File(dataTypeFile);
if (f.exists()) {
f.delete();
}
String lockFile = dataTypeFile + ".ulock";
File lf = new File(lockFile);
if (lf.exists()) {
lf.delete();
}
return f;
}
public void parseGDT_Linux_JNI() throws Exception {
String filenames[] = {
"jni.h",
"jawt.h",
"jdwpTransport.h",
"jvmti.h",
"jvmticmlr.h",
"classfile_constants.h",
};
String args[] = {
"-I"+headerFilePath+"/jni/linux",
"-I"+headerFilePath+"/jni/linux/linux",
"-D_X86_",
"-D__STDC__",
"-D_GNU_SOURCE",
"-D__WORDSIZE=64",
"-D__builtin_va_list=void *",
"-D__DO_NOT_DEFINE_COMPILE",
"-D_Complex",
"-D_WCHAR_T",
"-D__NO_STRING_INLINES",
"-D__signed__",
"-D__extension__=",
"-D__GLIBC_HAVE_LONG_LONG=1",
"-D__need_sigset_t",
"-Daligned_u64=uint64_t",
};
// Using another archive while parsing will cause:
// - a dependence on the other archive
// - any missing data types while parsing are supplied if present from existingDTMgr
// - after parsing all data types parsed that have an equivalent data type will be
// replaced by the data type from the existingDTMgr
//
// NOTE: This will only occur if the data type from the exisitngDTMgr is equivalent.
//
ResourceFile clib64ArchiveFile = DataTypeArchiveUtility.findArchiveFile("generic_clib_64.gdt");
File file = new File(clib64ArchiveFile.getAbsolutePath());
DataTypeManager existingDTMgr = FileDataTypeManager.openFileArchive(file, false);
DataTypeManager openTypes[] = { existingDTMgr };
parseHeaderFilesToGDT(openTypes, outputDirectory, "jni_linux", "x86:LE:64:default", "gcc", filenames, args);
}
public void parseGDT_Windows_JNI() throws Exception {
String filenames[] = {
"jni.h",
"jawt.h",
"jdwpTransport.h",
"jvmti.h",
"jvmticmlr.h",
"classfile_constants.h",
};
String args[] = {
"-I"+headerFilePath+"/jni/win32",
"-I"+headerFilePath+"/jni/win32/win32",
"-D_X86_",
"-D__STDC__",
"-D_GNU_SOURCE",
"-D__WORDSIZE=64",
"-D__builtin_va_list=void *",
"-D__DO_NOT_DEFINE_COMPILE",
"-D_Complex",
"-D_WCHAR_T",
"-D__NO_STRING_INLINES",
"-D__signed__",
"-D__extension__=",
"-D__GLIBC_HAVE_LONG_LONG=1",
"-D__need_sigset_t",
"-Daligned_u64=uint64_t",
};
// Using another archive while parsing will cause:
// - a dependence on the other archive
// - any missing data types while parsing are supplied if present from existingDTMgr
// - after parsing all data types parsed that have an equivalent data type will be
// replaced by the data type from the existingDTMgr
//
// NOTE: This will only occur if the data type from the exisitngDTMgr is equivalent.
//
ResourceFile clib64ArchiveFile = DataTypeArchiveUtility.findArchiveFile("windows_vs12_64.gdt");
File file = new File(clib64ArchiveFile.getAbsolutePath());
DataTypeManager existingDTMgr = FileDataTypeManager.openFileArchive(file, false);
DataTypeManager openTypes[] = { existingDTMgr };
parseHeaderFilesToGDT(openTypes, outputDirectory, "jni_windows", "x86:LE:64:default", "windows", filenames, args);
}
}