mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 12:11:55 +00:00
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:
parent
35b58b3105
commit
ffae7232cb
@ -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|
|
||||
|
@ -207,7 +207,6 @@ zlib.h
|
||||
-DTARGET_API_MAC_OSX
|
||||
-DTARGET_COCOA
|
||||
-DHANDLE="unsigned long"
|
||||
-D_Bool="BOOL"
|
||||
-D_WCHAR_T
|
||||
-D_Complex
|
||||
-Drestrict
|
||||
|
@ -323,7 +323,6 @@ zlib.h
|
||||
-D_MAC_
|
||||
-DTARGET_API_MAC_OSX
|
||||
-DHANDLE="unsigned long"
|
||||
-D_Bool="BOOL"
|
||||
-D_WCHAR_T
|
||||
-D_Complex
|
||||
-Drestrict
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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('\\');
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user