From 08b20d5d21981b1080882514410c076701473d1b Mon Sep 17 00:00:00 2001
From: emteere <47253321+emteere@users.noreply.github.com>
Date: Tue, 11 Apr 2023 19:48:36 +0000
Subject: [PATCH] GP-2308 Refactored parsing dialog adding includepaths and
Achitecture, handle noreturn tags
---
Ghidra/Features/Base/certification.manifest | 5 +-
.../Base/data/parserprofiles/MacOSX_10.5.prf | 1 -
.../Base/data/parserprofiles/MacOSX_10.9.prf | 1 -
.../Base/data/parserprofiles/MacOSX_Cocoa.prf | 1 -
.../data/parserprofiles/VisualStudio12_32.prf | 16 +-
.../data/parserprofiles/VisualStudio12_64.prf | 13 +-
.../data/parserprofiles/VisualStudio22_64.prf | 341 ++++++++++
.../data/parserprofiles/VisualStudio9.prf | 13 +-
.../Base/data/parserprofiles/clib.prf | 12 +-
.../data/parserprofiles/generic_clib_32.prf | 16 +-
.../data/parserprofiles/generic_clib_64.prf | 16 +-
.../Base/data/parserprofiles/linux_32.prf | 16 +-
.../Base/data/parserprofiles/linux_64.prf | 16 +-
.../Base/data/parserprofiles/vs12Local.prf | 13 +-
.../CreateDefaultGDTArchivesScript.java | 71 ++-
.../CreateExampleGDTArchiveScript.java | 56 +-
.../plugin/core/cparser/CParserPlugin.java | 212 ++-----
.../app/plugin/core/cparser/CParserTask.java | 83 ++-
.../app/plugin/core/cparser/ParseDialog.java | 485 +++++++++++---
.../app/util/cparser/C/CParserUtils.java | 299 ++++++---
.../javacc/ghidra/app/util/cparser/C/C.jj | 79 ++-
.../javacc/ghidra/app/util/cparser/CPP/CPP.jj | 15 +-
.../ParseDialogParsingAndPromptsTest.java | 596 ++++++++++++++++++
.../plugin/core/cparser/ParseDialogTest.java | 22 +-
.../ghidra/app/util/cparser/CParserTest.java | 16 +-
.../ghidra/app/util/cparser/CParserTest.h | 10 +-
.../CreateAVR8GDTArchiveScript.java | 10 +-
.../CreateJNIGDTArchivesScript.java | 7 +-
28 files changed, 1948 insertions(+), 493 deletions(-)
create mode 100644 Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf
create mode 100644 Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogParsingAndPromptsTest.java
diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest
index ce192cb3ef..1c4ad4dfee 100644
--- a/Ghidra/Features/Base/certification.manifest
+++ b/Ghidra/Features/Base/certification.manifest
@@ -29,8 +29,9 @@ data/parserprofiles/MacOSX_10.9.prf||GHIDRA||||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|
-data/parserprofiles/clib.prf||GHIDRA||reviewed||END|
+data/parserprofiles/VisualStudio22_64.prf||GHIDRA||||END|
+data/parserprofiles/VisualStudio9.prf||GHIDRA||||END|
+data/parserprofiles/clib.prf||GHIDRA||||END|
data/parserprofiles/generic_clib_32.prf||GHIDRA||||END|
data/parserprofiles/generic_clib_64.prf||GHIDRA||||END|
data/parserprofiles/linux_32.prf||GHIDRA||||END|
diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf
index d6d7265a87..929ce4271e 100644
--- a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf
@@ -207,7 +207,6 @@ zlib.h
-DTARGET_API_MAC_OSX
-DTARGET_COCOA
-DHANDLE="unsigned long"
--D_WCHAR_T
-D_Complex
-Drestrict
-D__restrict
diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf
index d084caa7ba..ef2649046e 100644
--- a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf
@@ -323,7 +323,6 @@ zlib.h
-D_MAC_
-DTARGET_API_MAC_OSX
-DHANDLE="unsigned long"
--D_WCHAR_T
-D_Complex
-Drestrict
-D__restrict
diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf
index ad295be77e..8daa8f9d32 100644
--- a/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf
@@ -28,7 +28,6 @@ Cocoa\Cocoa.h
-D_MAC_
-DTARGET_API_MAC_OSX=1
-DHANDLE="unsigned long"
--D_WCHAR_T
-D_Complex
-Drestrict
-D__restrict
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf
index b65e318471..2dd5df02d2 100644
--- a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_32.prf
@@ -172,12 +172,8 @@ wpcapi.h
wscapi.h
wsdapi.h
wspiapi.h
-
rpcproxy.h
--I/VC/VS12/src
--I/VC/VS12/include
--I/VC/SDK/v7.1A/Include
-D_M_IX86=300
-D_MSC_VER=1200
-D_INTEGRAL_MAX_BITS=32
@@ -191,7 +187,6 @@ rpcproxy.h
-DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
--D_WCHAR_T_DEFINED
-DCONST=const
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE
@@ -205,3 +200,14 @@ rpcproxy.h
-D_ThrowInfo=ThrowInfo
-v0
-D__inner_checkReturn=""
+
+/data/HeaderFiles/VC/VS12/src
+/data/HeaderFiles/VC/VS12/include
+/data/HeaderFiles/VC/SDK/v7.1A/Include
+
+x86:LE:32:default
+
+windows
+
+
+
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf
index aa7101f648..b30064ecc3 100644
--- a/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio12_64.prf
@@ -172,12 +172,8 @@ wpcapi.h
wscapi.h
wsdapi.h
wspiapi.h
-
rpcproxy.h
--I/VC/VS12/src
--I/VC/VS12/include
--I/VC/SDK/v7.1A/Include
-D_M_IX86=300
-D_MSC_VER=1200
-D_INTEGRAL_MAX_BITS=64
@@ -193,7 +189,6 @@ rpcproxy.h
-DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
--D_WCHAR_T_DEFINED
-DCONST=const
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE
@@ -208,3 +203,11 @@ rpcproxy.h
-D__unaligned=""
-v0
-D__inner_checkReturn=""
+
+/data/HeaderFiles/VC/VS12/include
+/data/HeaderFiles/VC/VS12/src
+/data/HeaderFiles/VC/SDK/v7.1A/Include
+
+
+
+
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf
new file mode 100644
index 0000000000..88d953a047
--- /dev/null
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio22_64.prf
@@ -0,0 +1,341 @@
+# 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.h
+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
+identityprovider.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
+tpmvscmgr.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
+wsnwlink.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
+messagedispatcherapi.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
+userenv.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
+ifdef.h
+inaddr.h
+ip2string.h
+ipexport.h
+iphlpapi.h
+icmpapi.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
+
+-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
+-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
+
+/data/HeaderFiles/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include
+/data/HeaderFiles/VC/VS22/10.0.19041.0/shared
+/data/HeaderFiles/VC/VS22/10.0.19041.0/ucrt
+/data/HeaderFiles/VC/VS22/10.0.19041.0/um
+/data/HeaderFiles/VC/VS22/10.0.19041.0/winrt
+
+x86:LE:64:default
+
+windows
diff --git a/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf b/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf
index 3a4b3376b8..d96adeb393 100644
--- a/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/VisualStudio9.prf
@@ -58,13 +58,10 @@ yvals.h
CommDlg.h
WinUser.h
WinNls.h
-C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src\internal.h
+internal.h
strsafe.h
penwin.h
--IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
--IC:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
--IC:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
-D_M_IX86=500
-D_MSC_VER=9090
-D_MSC_EXTENSIONS
@@ -85,5 +82,11 @@ penwin.h
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
-D_PHNDLR=void *
--D_WCHAR_T_DEFINED
-DCONST=const
+
+C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Include
+C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include
+C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
+
+x86:LE:64:default
+
diff --git a/Ghidra/Features/Base/data/parserprofiles/clib.prf b/Ghidra/Features/Base/data/parserprofiles/clib.prf
index 6cbd35baac..04fa31722d 100644
--- a/Ghidra/Features/Base/data/parserprofiles/clib.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/clib.prf
@@ -78,13 +78,17 @@ wchar.h
wctype.h
wordexp.h
--IU:\linux_include\include
--IU:\linux_include\include\sys
--IU:\linux_include\i386-redhat-linux\4.1.2\include
-D_X86_
-D__STDC__
-D__WORDSIZE=32
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
+
+U:\linux_include\include
+U:\linux_include\include\sys
+U:\linux_include\i386-redhat-linux\4.1.2\include
+
+x86:LE:32:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf b/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf
index 3d331f0ffd..188be92604 100644
--- a/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf
@@ -219,11 +219,6 @@ arpa/nameser_compat.h
arpa/telnet.h
arpa/tftp.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_GNU_SOURCE
@@ -231,10 +226,19 @@ arpa/tftp.h
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
-D__NO_STRING_INLINES
-D__NO_LONG_DOUBLE_MATH
-D__signed__
-D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:32:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf b/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf
index 0c76e8d1aa..af46b60039 100644
--- a/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf
@@ -219,11 +219,6 @@ arpa/nameser_compat.h
arpa/telnet.h
arpa/tftp.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_GNU_SOURCE
@@ -231,10 +226,19 @@ arpa/tftp.h
-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
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:64:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/linux_32.prf b/Ghidra/Features/Base/data/parserprofiles/linux_32.prf
index 5235499a8a..2c8fe49cf8 100644
--- a/Ghidra/Features/Base/data/parserprofiles/linux_32.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/linux_32.prf
@@ -515,11 +515,6 @@ mechglue.h
auth_gss.h
auth_gssapi.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_POSIX_C_SOURCE
@@ -528,10 +523,19 @@ auth_gssapi.h
-D__builtin_va_list=void *
-D__DO_NOT_DEFINE_COMPILE
-D_Complex
--D_WCHAR_T
-D__NO_STRING_INLINES
-D__NO_LONG_DOUBLE_MATH
-D__signed__
-D__extension__=""
-D__GLIBC_HAVE_LONG_LONG=1
-Daligned_u64=uint64_t
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:32:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/linux_64.prf b/Ghidra/Features/Base/data/parserprofiles/linux_64.prf
index f3c783c33b..2d714aef72 100644
--- a/Ghidra/Features/Base/data/parserprofiles/linux_64.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/linux_64.prf
@@ -515,11 +515,6 @@ mechglue.h
auth_gss.h
auth_gssapi.h
--I/linux/include
--I/linux/include/sys
--I/linux/gcc/include
--I/linux/x86_64-redhat-linux5E/include
--I/linux/x86_64-redhat-linux5E/include/sys
-D_X86_
-D__STDC__
-D_POSIX_C_SOURCE
@@ -528,9 +523,18 @@ auth_gssapi.h
-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
-Daligned_u64=uint64_t
+
+/data/HeaderFiles/linux/include
+/data/HeaderFiles/linux/include/sys
+/data/HeaderFiles/linux/gcc/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include
+/data/HeaderFiles/linux/x86_64-redhat-linux5E/include/sys
+
+x86:LE:64:default
+
+gcc
diff --git a/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf b/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf
index 7427750503..cdf7b4b8bd 100644
--- a/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf
+++ b/Ghidra/Features/Base/data/parserprofiles/vs12Local.prf
@@ -222,9 +222,6 @@ wscapi.h
wsdapi.h
wspiapi.h
--I/VisualStudio/VS12/include
--I/VisualStudio/Windows/v7.0a/Include
--I/VisualStudio/VS12/src
-D_M_IX86
-D_MSC_VER=9090
-D_INTEGRAL_MAX_BITS=32
@@ -239,7 +236,6 @@ wspiapi.h
-DSTRSAFE_LIB
-DSTRSAFE_LIB_IMPL
-DLPSKBINFO=LPARAM
--D_WCHAR_T_DEFINED
-DCONST=const
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_DEPRECATE
@@ -250,3 +246,12 @@ wspiapi.h
-D__possibly_notnullterminated
-Dtype_info="void *"
-v0
+
+/data/HeaderFiles/VC/VS12/include
+/data/HeaderFiles/VC/Windows/v7.0a/Include
+/data/HeaderFiles/VC/VS12/src
+
+x86:LE:32:default
+
+windows
+
diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
index d84e1341c5..894068140e 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
@@ -31,6 +31,7 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
@@ -55,14 +56,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
}
- private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String includePaths[], String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
DataTypeManager openTypes[] = null;
- parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args);
+ parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
}
- private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String[] includePaths, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
@@ -71,9 +74,9 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
- String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close();
@@ -276,14 +279,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"wscapi.h",
"wsdapi.h",
"wspiapi.h",
-
"rpcproxy.h",
};
+ String includePaths[] = {
+ headerFilePath+"/VC/VS12/src",
+ headerFilePath+"/VC/VS12/include",
+ headerFilePath+"/VC/SDK/v7.1A/Include",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/VC/VS12/src",
- "-I"+headerFilePath+"/VC/VS12/include",
- "-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
"-D_M_IX86=300",
"-D_MSC_VER=1200",
"-D_INTEGRAL_MAX_BITS=32",
@@ -294,8 +299,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D_USE_ATTRIBUTES_FOR_SAL",
"-D_CRTBLD",
"-D_OPENMP_NOFORCE_MANIFEST",
- "-DSTRSAFE_LIB",
- "-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM",
"-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS",
@@ -312,7 +315,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D__inner_checkReturn=",
};
- parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, includePaths, args);
}
@@ -494,14 +497,16 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"wscapi.h",
"wsdapi.h",
"wspiapi.h",
-
"rpcproxy.h",
};
+ String includePaths[] = {
+ headerFilePath+"/VC/VS12/src",
+ headerFilePath+"/VC/VS12/include",
+ headerFilePath+"/VC/SDK/v7.1A/Include",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/VC/VS12/src",
- "-I"+headerFilePath+"/VC/VS12/include",
- "-I"+headerFilePath+"/VC/SDK/v7.1A/Include",
"-D_MSC_VER=1200",
"-D_INTEGRAL_MAX_BITS=64",
"-DWINVER=0x0900",
@@ -513,8 +518,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D_USE_ATTRIBUTES_FOR_SAL",
"-D_CRTBLD",
"-D_OPENMP_NOFORCE_MANIFEST",
- "-DSTRSAFE_LIB",
- "-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM",
"-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS",
@@ -532,7 +535,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-D__inner_checkReturn=",
};
- parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, includePaths, args);
}
@@ -761,12 +764,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"arpa/tftp.h",
};
+ String includePaths[] = {
+ headerFilePath+"/linux/include",
+ headerFilePath+"/linux/include/sys",
+ headerFilePath+"/linux/gcc/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/linux/include",
- "-I"+headerFilePath+"/linux/include/sys",
- "-I"+headerFilePath+"/linux/gcc/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
"-D_X86_",
"-D__STDC__",
"-D_GNU_SOURCE",
@@ -782,7 +788,7 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-Daligned_u64=uint64_t",
};
- parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, includePaths, args);
}
@@ -1011,12 +1017,15 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"arpa/tftp.h",
};
+ String includePaths[] = {
+ headerFilePath+"/linux/include",
+ headerFilePath+"/linux/include/sys",
+ headerFilePath+"/linux/gcc/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include",
+ headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
+ };
+
String args[] = {
- "-I"+headerFilePath+"/linux/include",
- "-I"+headerFilePath+"/linux/include/sys",
- "-I"+headerFilePath+"/linux/gcc/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include",
- "-I"+headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
"-D_X86_",
"-D__STDC__",
"-D_GNU_SOURCE",
@@ -1032,6 +1041,6 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"-Daligned_u64=uint64_t",
};
- parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, includePaths, args);
}
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
index 3b9397a386..bab606bb29 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
@@ -31,6 +31,7 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
@@ -52,14 +53,16 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
parseGDT_WinVS22();
}
- private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String includePaths[], String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
DataTypeManager openTypes[] = null;
- parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args);
+ parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
}
- private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args)
+ private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
+ String[] filenames, String[] includePaths, String[] args)
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
@@ -68,9 +71,9 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
- String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, includePaths, args, dtMgr, languageID, compiler, monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close();
@@ -79,7 +82,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
/**
* Turn string into a file, delete old archive if it exists
*
- * @param dataTypeFile
+ * @param dataTypeFile name of archive file
*
* @return file
*/
@@ -112,12 +115,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"dsound.h",
};
+ String includeFiles[] = {
+ headerFilePath+"/VC/VS22/10.0.190141.0",
+ headerFilePath+"/VC/VS22/10.0.19041.0/um",
+ headerFilePath+"/VC/VS22/10.0.19041.0/shared",
+ headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include",
+ };
+
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",
@@ -126,7 +132,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-v0",
};
- parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, includeFiles, args);
}
public void parseGDT_WinVS22() throws Exception {
@@ -167,7 +173,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"complex.h",
"math.h",
"mbctype.h",
- "mbstring.hs",
+ "mbstring.h",
"memory.h",
"minmax.h",
"new.h",
@@ -216,7 +222,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"dssec.h",
"iads.h",
"identitycommon.h",
- "identityproviders.h",
+ "identityprovider.h",
"identitystore.h",
"keycredmgr.h",
"lmaccess.h",
@@ -237,7 +243,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"slpublic.h",
"subauth.h",
"tokenbinding.h",
- "tpmsvcmgr.h",
+ "tpmvscmgr.h",
"wincred.h",
"wincrypt.h",
"winnetwk.h",
@@ -267,7 +273,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"mswsock.h",
"ws2tcpip.h",
"wsipv6ok.h",
- "wslwlink.h",
+ "wsnwlink.h",
"wsrm.h",
"mswsockdef.h",
@@ -375,7 +381,7 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"thumbcache.h",
"thumbnailstreamcache.h",
"tlogstg.h",
- "usereng.h",
+ "userenv.h",
"# Windows Controls",
"commctrl.h",
@@ -452,12 +458,15 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"lmwksta.h"
};
+ String includeFiles[] = {
+ headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
+ headerFilePath+"/VC/VS22/10.0.19041.0/shared",
+ headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath+"/VC/VS22/10.0.19041.0/um",
+ headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
+ };
+
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",
@@ -473,7 +482,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-DSTRSAFE_LIB",
"-DSTRSAFE_LIB_IMPL",
"-DLPSKBINFO=LPARAM",
- "-D_WCHAR_T_DEFINED",
"-DCONST=const",
"-D_CRT_SECURE_NO_WARNINGS",
"-D_CRT_NONSTDC_NO_DEPRECATE",
@@ -494,6 +502,6 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
"-DSECURITY_WIN32",
};
- parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, args);
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, includeFiles, args);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java
index 22f96f2627..bf55b2c8a1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserPlugin.java
@@ -15,7 +15,8 @@
*/
package ghidra.app.plugin.core.cparser;
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
@@ -31,9 +32,8 @@ 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.ParseException;
-import ghidra.app.util.cparser.CPP.PreProcessor;
+import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.framework.Application;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginInfo;
@@ -56,22 +56,20 @@ import ghidra.util.task.TaskMonitor;
)
//@formatter:on
public class CParserPlugin extends ProgramPlugin {
- final static String PARSE_ACTION_NAME = "Import C DataTypes";
+ public final static String PARSE_ACTION_NAME = "Import C DataTypes";
final static String USER_PROFILES_DIR =
Application.getUserSettingsDirectory().getAbsolutePath() + File.separatorChar +
"parserprofiles";
+
private ParseDialog parseDialog;
private File userProfileDir;
- private String parserMessages;
- private String cppMessages;
+ private CParseResults results;
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);
createActions();
@@ -145,26 +143,37 @@ public class CParserPlugin extends ProgramPlugin {
if (parseDialog == null) {
parseDialog = new ParseDialog(this);
}
- else {
- parseDialog.toFront();
- }
+ parseDialog.setupForDisplay();
tool.showDialog(parseDialog);
}
/*
* Parse into a saved data type data base file
*/
- protected void parse(String[] filenames, String options, String dataFilename) {
- CParserTask parseTask = new CParserTask(this, filenames, options, dataFilename);
+ protected void parse(String[] filenames, String includePaths[], String options,
+ String languageIDString, String compilerSpecID, String dataFilename) {
+
+ CParserTask parseTask = new CParserTask(this, dataFilename)
+ .setFileNames(filenames)
+ .setIncludePaths(includePaths)
+ .setOptions(options)
+ .setLanguageID(languageIDString)
+ .setCompilerID(compilerSpecID);
+
this.getTool().execute(parseTask, 500);
}
+
/*
* Parse C-source into a data type manager
*/
- protected void parse(String[] filenames, String options, DataTypeManager dtMgr,
+ protected void parse(String[] filenames, String includePaths[], String options,
+ String languageIDString, String compilerSpecID, DataTypeManager dtMgr,
TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException {
+
+ results = null;
+
String[] args = parseOptions(options);
DataTypeManager openDTmanagers[] = null;
@@ -174,113 +183,22 @@ public class CParserPlugin extends ProgramPlugin {
return; // parse canceled
}
- cppMessages = "";
- PreProcessor cpp = new PreProcessor();
-
- cpp.setArgs(args);
-
- PrintStream os = System.out;
- String homeDir = System.getProperty("user.home");
- String fName = homeDir + File.separator + "CParserPlugin.out";
try {
- os = new PrintStream(new FileOutputStream(fName));
- }
- catch (FileNotFoundException e2) {
- Msg.error(this, "Unexpected Exception: " + e2.getMessage(), e2);
- }
-
- PrintStream old = System.out;
- System.setOut(os);
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- cpp.setOutputStream(bos);
- cpp.setMonitor(monitor);
-
- int fileCount = 0;
- try {
- for (String filename : filenames) {
- 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);
-
- if (file.isDirectory()) {
- // process each header file in the directory
- 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 if (file.exists()) {
- ++fileCount;
- parseFile(filename, monitor, cpp);
- }
- else {
- Msg.error(this, "Skipping file not found:" + filename);
- }
- }
- }
- catch (RuntimeException re) {
- os.close();
- throw new ParseException(re.getMessage());
- }
-
- if (fileCount == 0) {
- throw new ParseException("Failed to find any header files to parse!");
- }
- else if (fileCount != filenames.length) {
- Msg.warn(this,
- "Only found " + fileCount + " of " + filenames.length + " specified header files");
- }
-
- // process all the defines and add any that are integer values into
- // the Equates table
- cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
-
- System.out.println(bos.toString());
-
- System.setOut(old);
- os.close();
-
- if (!monitor.isCancelled()) {
- monitor.setMessage("Parsing C");
-
- CParser cParser = new CParser(dtMgr, true, openDTmanagers);
- cParser.setParseFileName(PARSER_DEBUG_OUTFILE);
- ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
- try {
- parserMessages = "";
- cParser.setParseFileName(fName);
- cParser.setMonitor(monitor);
- cParser.parse(bis);
- }
- finally {
- parserMessages = cParser.getParseMessages();
- }
-
+ results = CParserUtils.parseHeaderFiles(openDTmanagers, filenames, includePaths,
+ args, dtMgr, languageIDString, compilerSpecID, monitor);
+
final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager);
-
+
SwingUtilities.invokeLater(() -> {
// CParserTask will show any errors
- if (!cParser.didParseSucceed()) {
+ if (!results.successful()) {
return;
}
if (isProgramDtMgr) {
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
"C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Program.",
- getFormattedParseMessage(
- "Check the Manage Data Types window for added data types."),
+ getFormattedParseMessage("Check the Manage Data Types window for added data types."),
MultiLineMessageDialog.INFORMATION_MESSAGE);
}
else {
@@ -289,20 +207,22 @@ public class CParserPlugin extends ProgramPlugin {
archiveName = ((FileDataTypeManager) dtMgr).getFilename();
}
MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(),
- "C-Parse of Header Files Complete. ",
+ "C-Parse of Header Files Complete",
"Successfully parsed header file(s) to Archive File: " + archiveName,
- getFormattedParseMessage(null), MultiLineMessageDialog.INFORMATION_MESSAGE);
+ getFormattedParseMessage(null),
+ MultiLineMessageDialog.INFORMATION_MESSAGE);
}
});
}
-
+ catch (IOException e) {
+ // ignore
+ }
}
/**
* 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
@@ -338,7 +258,7 @@ public class CParserPlugin extends ProgramPlugin {
"" + "
The new archive will become dependent on these archives
" +
"for any datatypes already defined in them (only unique
" +
"data types will be added to the new archive).",
- "Use Open Archives?", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
+ "Use Open Archives", "Don't Use Open Archives", OptionDialog.QUESTION_MESSAGE);
if (result == OptionDialog.CANCEL_OPTION) {
throw new CancelledException("User Cancelled");
}
@@ -349,62 +269,40 @@ public class CParserPlugin extends ProgramPlugin {
return openDTmanagers;
}
+
+ public CParseResults getParseResults() {
+ return results;
+ }
+
+ public String getParseMessage() {
+ return (results != null ? results.cParseMessages() : "");
+ }
- public String getFormattedParseMessage(String errMsg) {
+ protected String getFormattedParseMessage(String errMsg) {
String message = "";
if (errMsg != null) {
message += errMsg + "\n\n";
}
- String msg = getParseMessage();
+ String msg = (results == null ? null : results.cParseMessages());
if (msg != null && msg.length() != 0) {
message += "CParser Messages:\n" + msg + "\n\n";
}
- msg = getPreProcessorMessage();
+ msg = (results == null ? null : results.cppParseMessages());
if (msg != null && msg.length() != 0) {
- message += "PreProcessor Messages:\n" + getPreProcessorMessage();
+ message += "PreProcessor Messages:\n" + msg;
}
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);
- cpp.parse(filename);
- }
- 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();
- }
- }
-
/*
* Parse into the current programs data type manager
*/
- protected void parse(String[] filenames, String options) {
+ protected void parse(String[] filenames, String[] includePaths, String options,
+ String languageIDString, String compilerIDString) {
if (currentProgram == null) {
Msg.showInfo(getClass(), parseDialog.getComponent(), "No Open Program",
"A program must be open to \"Parse to Program\"");
@@ -416,8 +314,14 @@ public class CParserPlugin extends ProgramPlugin {
if (result == OptionDialog.CANCEL_OPTION) {
return;
}
+
CParserTask parseTask =
- new CParserTask(this, filenames, options, currentProgram.getDataTypeManager());
+ new CParserTask(this, currentProgram.getDataTypeManager())
+ .setFileNames(filenames)
+ .setIncludePaths(includePaths)
+ .setOptions(options)
+ .setLanguageID(languageIDString)
+ .setCompilerID(compilerIDString);
tool.execute(parseTask);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
index b02ba60e0a..68ae94864a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
@@ -20,44 +20,97 @@ 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.program.model.data.*;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateFileException;
import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor;
/**
- * This is called by the dialog box.
+ * Background task to parse files for cparser plugin
*
*
*/
class CParserTask extends Task {
- private String[] filenames;
- private String options;
+
private CParserPlugin plugin;
private String dataFileName;
+
+ private String[] filenames;
+ private String[] includePaths;
+
+ private String options;
+
+ private String languageString;
+ private String compilerString;
+
private DataTypeManager dtMgr;
- CParserTask(CParserPlugin plugin, String[] filenames, String options, String dataFileName) {
+
+ /**
+ * Create task to parse to a dataFile
+ *
+ * @param plugin CParserPlugin that will do the work
+ * @param dataFileName name of the file to parse to
+ */
+ CParserTask(CParserPlugin plugin, String dataFileName) {
super("Parsing C Files", true, false, false);
this.plugin = plugin;
- this.filenames = filenames;
- this.options = options;
this.dataFileName = dataFileName;
}
- public CParserTask(CParserPlugin plugin, String[] filenames, String options,
- DataTypeManager dataTypeManager) {
+ /**
+ * Create task to parse to a dataTypeManager
+ *
+ * @param plugin
+ * @param dataTypeManager
+ */
+ public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
super("Parsing C Files", true, false, false);
this.plugin = plugin;
- this.filenames = filenames;
- this.options = options;
this.dtMgr = dataTypeManager;
}
+ /**
+ * Create task to parse to a ProgramDataTypeManager
+ *
+ * @param plugin
+ * @param dataTypeManager
+ */
+ public CParserTask(CParserPlugin plugin, ProgramBasedDataTypeManager dataTypeManager) {
+ super("Parsing C Files", true, false, false);
+
+ this.plugin = plugin;
+ this.dtMgr = dataTypeManager;
+ }
+
+ public CParserTask setLanguageID(String languageID) {
+ this.languageString = languageID;
+ return this;
+ }
+
+ public CParserTask setCompilerID(String compilerID) {
+ this.compilerString = compilerID;
+ return this;
+ }
+
+ public CParserTask setIncludePaths(String includePaths[]) {
+ this.includePaths = includePaths.clone();
+ return this;
+ }
+
+ public CParserTask setFileNames(String names[]) {
+ this.filenames = names.clone();
+ return this;
+ }
+
+ public CParserTask setOptions(String options) {
+ this.options = options;
+ return this;
+ }
+
private String getFirstMessageLine(final String errMsg) {
int indexOf = errMsg.indexOf('\n');
String msg = errMsg;
@@ -77,7 +130,7 @@ class CParserTask extends Task {
fileDtMgr = dtMgr;
}
- plugin.parse(filenames, options, dtMgr, monitor);
+ plugin.parse(filenames, includePaths, options, languageString, compilerString, dtMgr, monitor);
if (dataFileName != null) {
// TODO: does not consider existing datatypes
if (dtMgr.getDataTypeCount(true) != 0) {
@@ -103,6 +156,10 @@ class CParserTask extends Task {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
+ // no results, was canceled
+ if (plugin.getParseResults() == null) {
+ return;
+ }
MultiLineMessageDialog.showModalMessageDialog(
plugin.getDialog().getComponent(), "Parse Errors",
"File was not created due to parse errors: " +
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
index 70d64ef2fc..3b13c69e75 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
@@ -15,31 +15,44 @@
*/
package ghidra.app.plugin.core.cparser;
-import java.awt.BorderLayout;
-import java.awt.Dimension;
+import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.*;
import java.util.*;
+import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.TableModel;
+import org.apache.commons.lang3.ObjectUtils;
+
import docking.*;
import docking.action.*;
import docking.widgets.OptionDialog;
+import docking.widgets.button.BrowseButton;
import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.dialogs.InputDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode;
+import docking.widgets.label.GLabel;
import docking.widgets.pathmanager.PathnameTablePanel;
+import docking.widgets.table.GTableCellRenderer;
+import docking.widgets.table.GTableCellRenderingData;
import generic.jar.ResourceFile;
+import generic.theme.GThemeDefaults.Colors.Tables;
+import ghidra.app.plugin.core.processors.SetLanguageDialog;
+import ghidra.app.util.Option;
+import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.exporter.Exporter;
import ghidra.framework.Application;
import ghidra.framework.options.SaveState;
import ghidra.framework.preferences.Preferences;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.program.model.data.FileDataTypeManager;
+import ghidra.program.model.lang.CompilerSpecID;
+import ghidra.program.model.lang.LanguageID;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.filechooser.ExtensionFileFilter;
@@ -75,6 +88,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
private PathnameTablePanel pathPanel;
private JTextArea parseOptionsField;
+
+ protected JComponent languagePanel;
+ protected JTextField languageTextField;
+ protected JButton languageButton;
+ protected String languageIDString = null;
+ protected String compilerIDString = null;
+
private GhidraComboBox comboBox;
private DefaultComboBoxModel comboModel;
private DockingAction saveAction;
@@ -86,44 +106,75 @@ class ParseDialog extends ReusableDialogComponentProvider {
private TableModelListener tableListener;
private ItemListener comboItemListener;
private TableModel tableModel;
+
+ private PathnameTablePanel includePathPanel;
+ private TableModel parsePathTableModel;
+ private TableModelListener parsePathTableListener;
+
private ArrayList itemList;
private ComboBoxItemComparator comparator;
private ResourceFile parentUserFile;
private boolean saveAsInProgress;
+ private boolean initialBuild = true;
+
+ private boolean userDefined = false;
+ private String currentProfileName = null;
ParseDialog(CParserPlugin plugin) {
super("Parse C Source", false, true, true, false);
this.plugin = plugin;
- itemList = new ArrayList<>();
- comparator = new ComboBoxItemComparator();
- addWorkPanel(buildMainPanel());
- addDismissButton();
- createActions();
- setActionsEnabled();
}
+ public void setupForDisplay() {
+ if (initialBuild) {
+ itemList = new ArrayList<>();
+ comparator = new ComboBoxItemComparator();
+ addWorkPanel(buildMainPanel());
+ addDismissButton();
+ createActions();
+ setActionsEnabled();
+
+ // setup based on save state
+ if (currentProfileName != null) {
+ for (int i = 0; i < itemList.size(); i++) {
+ ComboBoxItem item = itemList.get(i);
+ if (userDefined == item.isUserDefined && currentProfileName.equals(item.file.getName())) {
+ comboBox.setSelectedIndex(i);
+ break;
+ }
+ }
+ }
+ } else {
+ toFront();
+ }
+ }
+
void writeState(SaveState saveState) {
- ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
- saveState.putString(CURRENT_PROFILE, item.file.getName());
- saveState.putBoolean(USER_DEFINED, item.isUserDefined);
+ // Get the current state if the dialog has been displayed
+ if (!initialBuild) {
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+
+ currentProfileName = item.file.getName();
+ userDefined = item.isUserDefined;
+
+ }
+ saveState.putString(CURRENT_PROFILE, currentProfileName);
+ saveState.putBoolean(USER_DEFINED, userDefined);
}
void readState(SaveState saveState) {
- String name = saveState.getString(CURRENT_PROFILE, null);
- if (name != null) {
- boolean userDefined = saveState.getBoolean(USER_DEFINED, true);
- for (int i = 0; i < itemList.size(); i++) {
- ComboBoxItem item = itemList.get(i);
- if (userDefined == item.isUserDefined && name.equals(item.file.getName())) {
- comboBox.setSelectedIndex(i);
- break;
- }
- }
+ currentProfileName = saveState.getString(CURRENT_PROFILE, null);
+ if (currentProfileName != null) {
+ userDefined = saveState.getBoolean(USER_DEFINED, true);
}
}
void closeProfile() {
+ // dialog not built yet
+ if (initialBuild) {
+ return;
+ }
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
if (item.isChanged) {
processItemChanged(item);
@@ -136,6 +187,8 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
protected JPanel buildMainPanel() {
+ initialBuild = true;
+
mainPanel = new JPanel(new BorderLayout(10, 5));
comboModel = new DefaultComboBoxModel<>();
@@ -164,14 +217,64 @@ class ParseDialog extends ReusableDialogComponentProvider {
pathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
+
+ // Set default render to display red if file would not we found
+ // Using include paths
+ pathPanel.getTable().setDefaultRenderer(String.class, new GTableCellRenderer() {
+ @Override
+ public Component getTableCellRendererComponent(GTableCellRenderingData data) {
+ JLabel label = (JLabel) super.getTableCellRendererComponent(data);
+ Object value = data.getValue();
+
+ String pathName = (String) value;
+ pathName = (pathName == null ? "" : pathName.trim());
+
+ if (pathName.length() == 0 || pathName.startsWith("#")) {
+ return label;
+ }
+
+ boolean fileExists = true;
+ File file = new File(pathName);
+ fileExists = file.exists();
+
+ // file not found directly, see if one of the include paths will find the file
+ if (!fileExists) {
+ fileExists = doesFileExist(pathName, fileExists);
+ }
+
+ label.setText(pathName.toString());
+ if (!fileExists) {
+ label.setForeground(data.isSelected() ? Tables.FG_ERROR_SELECTED
+ : Tables.FG_ERROR_UNSELECTED);
+ }
+
+ return label;
+ }
+ });
+
tableListener = e -> {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
- item.isChanged = true;
+ item.isChanged = !initialBuild;
setActionsEnabled();
};
tableModel = pathPanel.getTable().getModel();
tableModel.addTableModelListener(tableListener);
+
+ includePathPanel = new PathnameTablePanel(null, true, false);
+ includePathPanel.setBorder(BorderFactory.createTitledBorder("Include paths"));
+ includePathPanel.setFileChooserProperties("Choose Source Files", LAST_IMPORT_C_DIRECTORY,
+ GhidraFileChooserMode.FILES_AND_DIRECTORIES, true,
+ new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
+
+ parsePathTableListener = e -> {
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+ item.isChanged = !initialBuild;
+ setActionsEnabled();
+ pathPanel.getTable().repaint();
+ };
+ parsePathTableModel = includePathPanel.getTable().getModel();
+ parsePathTableModel.addTableModelListener(parsePathTableListener);
JPanel optionsPanel = new JPanel(new BorderLayout());
optionsPanel.setBorder(BorderFactory.createTitledBorder("Parse Options"));
@@ -182,7 +285,13 @@ class ParseDialog extends ReusableDialogComponentProvider {
JScrollPane pane = new JScrollPane(parseOptionsField);
pane.getViewport().setPreferredSize(new Dimension(300, 200));
optionsPanel.add(pane, BorderLayout.CENTER);
-
+
+ JPanel archPanel = new JPanel(new BorderLayout());
+ archPanel.setBorder(BorderFactory.createTitledBorder("Program Architecture:"));
+ archPanel.add(new GLabel(" ", SwingConstants.RIGHT));
+ languagePanel = buildLanguagePanel();
+ archPanel.add(languagePanel);
+
// create Parse Button
parseButton = new JButton("Parse to Program");
@@ -195,23 +304,103 @@ class ParseDialog extends ReusableDialogComponentProvider {
parseToFileButton.setToolTipText("Parse files and output to archive file");
addButton(parseToFileButton);
- pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
- JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPanel);
- splitPane.setResizeWeight(0.50);
+
mainPanel.add(comboPanel, BorderLayout.NORTH);
- mainPanel.add(splitPane, BorderLayout.CENTER);
+
+ includePathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
+ JSplitPane optionsPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, includePathPanel, optionsPanel);
+ optionsPane.setResizeWeight(0.50);
+
+ pathPanel.setPreferredSize(new Dimension(pathPanel.getPreferredSize().width, 200));
+ JSplitPane outerPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pathPanel, optionsPane);
+ outerPane.setResizeWeight(0.50);
+
+ mainPanel.add(outerPane, BorderLayout.CENTER);
+
+ mainPanel.add(archPanel, BorderLayout.SOUTH);
setHelpLocation(new HelpLocation(plugin.getName(), "Parse_C_Source"));
loadProfile();
+ initialBuild = false;
return mainPanel;
}
+ private boolean doesFileExist(String pathName, boolean fileExists) {
+ String[] includePaths = includePathPanel.getPaths();
+ for (String path : includePaths) {
+ File file = CParserUtils.getFile(path, pathName);
+ if (file == null) {
+ continue;
+ }
+ fileExists = file.exists();
+ if (fileExists) {
+ break;
+ }
+ }
+ return fileExists;
+ }
+
+ private JComponent buildLanguagePanel() {
+ languageTextField = new JTextField();
+ languageTextField.setEditable(false);
+ languageTextField.setFocusable(false);
+
+ languageButton = new BrowseButton();
+ languageButton.addActionListener(e -> {
+ SetLanguageDialog dialog = new SetLanguageDialog(plugin.getTool(), languageIDString, compilerIDString,
+ "Select Program Architecture for File DataType Archive");
+ LanguageID languageId = dialog.getLanguageDescriptionID();
+ CompilerSpecID compilerSpecId = dialog.getCompilerSpecDescriptionID();
+ if ((languageId == null) || (compilerSpecId == null)) {
+ return;
+ }
+
+ String newLanguageIDString = languageId.getIdAsString();
+ String newCompilerIDString = compilerSpecId.getIdAsString();
+
+ if (!Objects.equals(newLanguageIDString, languageIDString) ||
+ !Objects.equals(newCompilerIDString, compilerIDString)) {
+ itemChanged();
+ }
+
+ languageIDString = newLanguageIDString;
+ compilerIDString = newCompilerIDString;
+
+ updateArchitectureDescription();
+ });
+
+ updateArchitectureDescription();
+
+ languageButton.setName("Set Processor Architecture");
+ Font font = languageButton.getFont();
+ languageButton.setFont(font.deriveFont(Font.BOLD));
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(languageTextField, BorderLayout.CENTER);
+ panel.add(languageButton, BorderLayout.EAST);
+ return panel;
+ }
+
+ private void updateArchitectureDescription() {
+ String newProgramArchitectureSummary = "64/32 (primarily for backward compatibility)";
+
+ if (languageIDString != null) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(languageIDString);
+ buf.append(" / ");
+ buf.append(compilerIDString != null ? compilerIDString : "none");
+ newProgramArchitectureSummary = buf.toString();
+ }
+
+ languageTextField.setText(newProgramArchitectureSummary);
+ }
+
private void selectionChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED) {
ComboBoxItem item = (ComboBoxItem) e.getItem();
- if (item.isChanged && !saveAsInProgress) {
+ if (item.isChanged && !saveAsInProgress && !initialBuild) {
if (item.isUserDefined) {
if (OptionDialog.showOptionDialog(rootPanel, "Save Changes to Profile?",
"Profile " + item.file.getName() +
@@ -256,53 +445,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
}
- private void loadProfile() {
- if (docListener != null) {
- parseOptionsField.getDocument().removeDocumentListener(docListener);
- }
- tableModel.removeTableModelListener(tableListener);
- ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
-
- StringBuffer sb = new StringBuffer();
- ArrayList pathList = new ArrayList<>();
- try {
- BufferedReader br =
- new BufferedReader(new InputStreamReader(item.file.getInputStream()));
- String line = null;
- while ((line = br.readLine()) != null) {
- line = line.trim();
- if (line.startsWith("-") || (line.length() == 0 && sb.length() > 0)) {
- // this is a compiler directive
- sb.append(line + "\n");
- }
- else if (line.length() > 0) {
- File f = new File(line);
- pathList.add(f.getPath());
- }
- }
- String[] paths = new String[pathList.size()];
- paths = pathList.toArray(paths);
- pathPanel.setPaths(paths);
- parseOptionsField.setText(sb.toString());
-
- br.close();
- }
- catch (FileNotFoundException e) {
- Msg.showInfo(getClass(), getComponent(), "File Not Found",
- "Could not find file\n" + item.file.getAbsolutePath());
- }
- catch (IOException e) {
- Msg.showError(this, getComponent(), "Error Loading Profile",
- "Exception occurred while reading file\n" + item.file.getAbsolutePath() + ": " + e);
- }
- finally {
- // add a document listener to the options field
- addDocumentListener();
- tableModel.addTableModelListener(tableListener);
- setActionsEnabled();
- }
- }
-
private void addDocumentListener() {
if (docListener == null) {
docListener = new DocumentListener() {
@@ -327,6 +469,9 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void itemChanged() {
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+ if (item == null) {
+ return;
+ }
item.isChanged = true;
setActionsEnabled();
}
@@ -466,6 +611,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
file.delete();
}
+ saveAsInProgress = true;
ComboBoxItem newItem = new ComboBoxItem(file, true);
if (itemList.contains(newItem)) {
itemList.remove(newItem);
@@ -476,7 +622,6 @@ class ParseDialog extends ReusableDialogComponentProvider {
index = -index - 1;
}
itemList.add(index, newItem);
- saveAsInProgress = true;
writeProfile(newItem.file);
newItem.isChanged = false;
item.isChanged = false;
@@ -491,6 +636,97 @@ class ParseDialog extends ReusableDialogComponentProvider {
}
}
+ private void loadProfile() {
+ if (docListener != null) {
+ parseOptionsField.getDocument().removeDocumentListener(docListener);
+ }
+ tableModel.removeTableModelListener(tableListener);
+ parsePathTableModel.removeTableModelListener(parsePathTableListener);
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+ item.isChanged = false;
+
+ StringBuffer sb = new StringBuffer();
+ ArrayList pathList = new ArrayList<>();
+ ArrayList includeList = new ArrayList<>();
+ String langString = null;
+ String compileString = null;
+ try {
+ BufferedReader br =
+ new BufferedReader(new InputStreamReader(item.file.getInputStream()));
+ String line = null;
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ pathList.add(line);
+ }
+
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ sb.append(line + "\n");
+ }
+
+ // get paths
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ includeList.add(line);
+ }
+
+ // get language
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.length() > 0) {
+ langString = (line.length() == 0 ? null : line);
+ break;
+ }
+ }
+
+ // get compiler spec
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.length() > 0) {
+ compileString = (line.length() == 0 ? null : line);
+ break;
+ }
+ }
+
+
+ String[] paths = new String[pathList.size()];
+ paths = pathList.toArray(paths);
+ pathPanel.setPaths(paths);
+
+ String[] incpaths = new String[includeList.size()];
+ incpaths = includeList.toArray(incpaths);
+ includePathPanel.setPaths(incpaths);
+
+ parseOptionsField.setText(sb.toString());
+
+ languageIDString = langString;
+
+ compilerIDString = compileString;
+
+ updateArchitectureDescription();
+
+ br.close();
+ }
+ catch (FileNotFoundException e) {
+ Msg.showInfo(getClass(), getComponent(), "File Not Found",
+ "Could not find file\n" + item.file.getAbsolutePath());
+ }
+ catch (IOException e) {
+ Msg.showError(this, getComponent(), "Error Loading Profile",
+ "Exception occurred while reading file\n" + item.file.getAbsolutePath() + ": " + e);
+ }
+ finally {
+ // add a document listener to the options field
+ addDocumentListener();
+ tableModel.addTableModelListener(tableListener);
+ parsePathTableModel.addTableModelListener(parsePathTableListener);
+ setActionsEnabled();
+ }
+ }
+
private void writeProfile(ResourceFile outputFile) {
// write the pathnames
try {
@@ -498,7 +734,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
new BufferedWriter(new OutputStreamWriter(outputFile.getOutputStream()));
String[] paths = pathPanel.getPaths();
for (String path : paths) {
- writer.write(path);
+ writer.write(path.trim());
writer.newLine();
}
writer.newLine();
@@ -510,6 +746,30 @@ class ParseDialog extends ReusableDialogComponentProvider {
writer.write(tok);
writer.newLine();
}
+ writer.newLine();
+
+ // Write paths
+ String [] includePaths = includePathPanel.getPaths();
+ for (String path : includePaths) {
+ writer.write(path.trim());
+ writer.newLine();
+ }
+ writer.newLine();
+
+ // Write Language ID Spec
+ if (languageIDString != null) {
+ writer.write(languageIDString);
+ }
+ writer.newLine();
+ writer.newLine();
+
+ // Write Compiler ID Spec
+ if (compilerIDString != null) {
+ writer.write(compilerIDString);
+ }
+ writer.newLine();
+ writer.newLine();
+
writer.close();
}
catch (IOException e) {
@@ -537,6 +797,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void doParse(boolean parseToFile) {
clearStatusText();
String options = getParseOptions();
+ String[] includePaths = includePathPanel.getPaths();
String[] paths = pathPanel.getPaths();
if (paths.length == 0) {
@@ -547,15 +808,21 @@ class ParseDialog extends ReusableDialogComponentProvider {
paths = expandPaths(paths);
pathPanel.setPaths(paths);
+
+ if (languageIDString == null || compilerIDString == null ) {
+ Msg.showWarn(getClass(), rootPanel, "Program Architecture not Specified",
+ "A Program Architecture must be specified in order to parse to a file.");
+ return;
+ }
if (parseToFile) {
File file = getSaveFile();
if (file != null) {
- plugin.parse(paths, options, file.getAbsolutePath());
+ plugin.parse(paths, includePaths, options, languageIDString, compilerIDString, file.getAbsolutePath());
}
}
else {
- plugin.parse(paths, options);
+ plugin.parse(paths, includePaths, options, languageIDString, compilerIDString);
}
}
@@ -605,7 +872,12 @@ class ParseDialog extends ReusableDialogComponentProvider {
private void addToComboModel(ResourceFile parent, boolean isUserDefined) {
ResourceFile[] children = parent.listFiles();
- for (ResourceFile resourceFile : children) {
+ List sorted = Arrays.asList(children);
+ // sort each set of files, system will go first
+ // User local files second
+ // new files at the end
+ Collections.sort(sorted);
+ for (ResourceFile resourceFile : sorted) {
if (resourceFile.getName().startsWith(".")) {
continue;
}
@@ -687,7 +959,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
return parseOptionsField.getText();
}
- private class ComboBoxItem {
+ class ComboBoxItem {
private ResourceFile file;
private boolean isUserDefined;
private boolean isChanged;
@@ -745,4 +1017,55 @@ class ParseDialog extends ReusableDialogComponentProvider {
return 1;
}
}
+
+ //==================================================================================================
+ // Methods for Testing
+ //==================================================================================================
+
+
+ GhidraComboBox getParseComboBox() {
+ return comboBox;
+ }
+
+ PathnameTablePanel getSourceFiles() {
+ return this.pathPanel;
+ }
+
+ PathnameTablePanel getIncludePaths() {
+ return this.includePathPanel;
+ }
+
+ JTextArea getParseOptionsTextField() {
+ return this.parseOptionsField;
+ }
+
+ JButton getLanguageButton() {
+ return this.languageButton;
+ }
+
+ JTextField getLanguageText() {
+ return this.languageTextField;
+ }
+
+ JButton getParseButton() {
+ return this.parseButton;
+ }
+
+ JButton getParseToFileButton() {
+ return this.parseToFileButton;
+ }
+
+ ArrayList getProfiles() {
+ return this.itemList;
+ }
+
+ ComboBoxItem getCurrentItem() {
+ ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
+
+ return item;
+ }
+
+ ResourceFile getUserProfileParent() {
+ return parentUserFile;
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java
index ff8dffb1f1..076df67d9d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java
@@ -17,27 +17,52 @@ package ghidra.app.util.cparser.C;
import java.io.*;
import java.util.Arrays;
-import java.util.Iterator;
+
+import javax.help.UnsupportedOperationException;
import generic.theme.GThemeDefaults.Colors;
import generic.theme.GThemeDefaults.Colors.Messages;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.CPP.PreProcessor;
import ghidra.framework.plugintool.ServiceProvider;
-import ghidra.program.database.ProgramDB;
+import ghidra.framework.store.LockException;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.model.listing.Program;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.*;
+import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
public class CParserUtils {
-
+
private CParserUtils() {
// utils class
}
+
+ public record CParseResults(PreProcessor preProcessor, String cppParseMessages, String cParseMessages, boolean successful) {
+ public String getFormattedParseMessage(String errMsg) {
+ String message = "";
+
+ if (errMsg != null) {
+ message += errMsg + "\n\n";
+ }
+
+ String msg = cppParseMessages;
+ if (msg != null && msg.length() != 0) {
+ message += "CParser Messages:\n" + msg + "\n\n";
+ }
+
+ msg = cppParseMessages;
+ if (msg != null && msg.length() != 0) {
+ message += "PreProcessor Messages:\n" + msg;
+ }
+
+ return message;
+ }
+ }
/**
* Parse the given function signature text. Any exceptions will be handled herein
@@ -88,7 +113,7 @@ public class CParserUtils {
* [0]= part before function name
* [1]= function name
* [2]= parameter body after function name
- * @param signature
+ * @param signature function signature string to split
* @return parts array or null if split failed
*/
private static String[] splitFunctionSignature(String signature) {
@@ -136,7 +161,7 @@ public class CParserUtils {
/**
* Get a temporary name of a specified length (tttt....)
- * @param length
+ * @param length of temporary string
* @return temporary name string
*/
private static String getTempName(int length) {
@@ -158,6 +183,7 @@ public class CParserUtils {
* parsing exceptions. This allows clients to perform exception handling that
* better matches their workflow.
* @return the data type that is created as a result of parsing; null if there was a problem
+ * @throws ParseException for catastrophic errors in C parsing
*/
public static FunctionDefinitionDataType parseSignature(DataTypeManagerService service,
Program program, String signatureText, boolean handleExceptions) throws ParseException {
@@ -237,8 +263,6 @@ public class CParserUtils {
*
* @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
@@ -250,15 +274,48 @@ public class CParserUtils {
*/
public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName,
- PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
- File file = new File(dataFileName);
- FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
- parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, cpp, monitor);
+ return parseHeaderFiles(openDTMgrs, filenames, null, args, dataFileName, monitor);
+ }
+
+ /**
+ * Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager
+ * 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 includePaths paths to include files, instead of using "-I" in args
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
+ *
+ * @param dataFileName name of data type archive file (include the .gdt extension)
+ *
+ * @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 includePaths[], String args[], String dataFileName,
+ TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ ghidra.app.util.cparser.CPP.ParseException, IOException {
- dtMgr.save();
- return dtMgr;
+ return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dataFileName, null, null, monitor);
}
@@ -280,6 +337,7 @@ public class CParserUtils {
*
* @param filenames names of files in order to parse, could include strings with
* "#" at start, which are ignored as comments
+ * @param includePaths path to include files, could also be in args with "-I"
* @param args arguments for parsing, "-D=", "-I"
*
* @param dataFileName name of data type archive file (include the .gdt extension)
@@ -287,8 +345,6 @@ public class CParserUtils {
* @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
@@ -298,14 +354,17 @@ public class CParserUtils {
* @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,
+ public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], String dataFileName,
+ String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
File file = new File(dataFileName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file);
- String messages = parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, languageId, compileSpecId, cpp, monitor);
+ CParseResults results;
+ results = parseHeaderFiles(openDTMgrs, filenames, includePaths, args, dtMgr, languageId, compileSpecId, monitor);
+
+ String messages = results.getFormattedParseMessage(null);
Msg.info(CParserUtils.class, messages);
dtMgr.save();
@@ -331,15 +390,13 @@ public class CParserUtils {
*
* @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=", "-I"
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
*
* @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
@@ -349,39 +406,84 @@ public class CParserUtils {
* @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,
+ public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr,
+ String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
+ ghidra.app.util.cparser.CPP.ParseException, IOException {
+
+ return parseHeaderFiles(openDTMgrs, filenames, null, args, existingDTMgr, languageId, compileSpecId, monitor);
+ }
+
+ /**
+ * Parse a set of C Header files and associated parsing arguments, data types are added to the provided
+ * DTMgr.
+ *
+ * Note: Using another open archive while parsing will cause:
+ * - a dependence on the other archive
+ * - any missing data types while parsing are supplied if present from an openDTMgr
+ * - after parsing all data types parsed with an equivalent data type in any openDTMgr
+ * replaced by the data type from the openDTMgr
+ *
+ * NOTE: This will only occur if the data type from the openDTMgr's is equivalent.
+ *
+ * NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof()
+ * @param openDTMgrs array of datatypes managers to use for undefined data types
+ *
+ * @param filenames names of files in order to parse, could include strings with
+ * "#" at start, which are ignored as comments
+ * @param includePaths paths to include files, instead of using "-I" in args
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
+ *
+ * @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 monitor used to cancel or provide results
+ *
+ * @return a formatted string of any output from pre processor parsing or C parsing
+ *
+ * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
+ * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
+ * @throws IOException if there io are errors saving the archive
+ *
+ */
+ public static CParseResults parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String includePaths[], String args[], DataTypeManager existingDTMgr,
+ String languageId, String compileSpecId, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException, IOException {
Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId));
CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId));
-
- 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 allDataTypes = programDtm.getAllDataTypes();
- while (allDataTypes.hasNext()) {
- existingDTMgr.resolve(allDataTypes.next(), null);
- }
- }
- finally {
- existingDTMgr.endTransaction(txId, true);
- }
- return messages;
- }
- finally {
- program.release(CParserUtils.class);
+ if (existingDTMgr instanceof StandAloneDataTypeManager) {
+ try {
+ ((StandAloneDataTypeManager) existingDTMgr).setProgramArchitecture(language, compilerSpec.getCompilerSpecID(),
+ StandAloneDataTypeManager.LanguageUpdateOption.UNCHANGED, monitor);
+ }
+ catch (CompilerSpecNotFoundException e) {
+ e.printStackTrace();
+ }
+ catch (LanguageNotFoundException e) {
+ e.printStackTrace();
+ }
+ catch (CancelledException e) {
+ // ignore
+ }
+ catch (LockException e) {
+ e.printStackTrace();
+ }
+ catch (UnsupportedOperationException e) {
+ e.printStackTrace();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ catch (IncompatibleLanguageException e) {
+ // Shouldn't happen, unless already had a language
+ e.printStackTrace();
+ }
}
+
+ return parseHeaderFiles(openDTMgrs, filenames, includePaths, args, existingDTMgr, monitor);
}
/**
@@ -405,12 +507,11 @@ public class CParserUtils {
*
* @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=", "-I"
+ * @param includePaths paths to include files, instead of using "-I" in args
+ * @param args arguments for parsing, "-D=", ( "-I" use includePaths parm instead)
*
* @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
@@ -418,17 +519,16 @@ public class CParserUtils {
* @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing
* @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing
*/
- public static String parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames,
- String args[], DataTypeManager dtMgr, PreProcessor cpp, TaskMonitor monitor)
+ public static CParseResults parseHeaderFiles(DataTypeManager[] openDTmanagers, String[] filenames, String[] includePaths,
+ String args[], DataTypeManager dtMgr, TaskMonitor monitor)
throws ghidra.app.util.cparser.C.ParseException,
ghidra.app.util.cparser.CPP.ParseException {
String cppMessages = "";
- if (cpp == null) {
- cpp = new PreProcessor();
- }
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ PreProcessor cpp = new PreProcessor();
+
cpp.setArgs(args);
+ cpp.addIncludePaths(includePaths);
PrintStream os = System.out;
String fName = dtMgr.getName().replace(".gdt","")+"_CParser.out";
@@ -442,8 +542,10 @@ public class CParserUtils {
System.setOut(os);
cpp.setMonitor(monitor);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
cpp.setOutputStream(bos);
+ boolean parseSucceeded = false;
try {
for (String filename : filenames) {
if (monitor.isCancelled()) {
@@ -469,9 +571,9 @@ public class CParserUtils {
parseFile(filename, monitor, cpp);
}
}
- } catch (RuntimeException re) {
+ parseSucceeded = true;
+ } catch (Throwable e) {
Msg.info(cpp, cpp.getParseMessages());
- throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage());
} finally {
System.out.println(bos);
os.flush();
@@ -481,12 +583,16 @@ public class CParserUtils {
}
cppMessages = cpp.getParseMessages();
+ if (!parseSucceeded) {
+ return new CParseResults(cpp, "", cppMessages, false);
+ }
// process all the defines and add any that are integer values into
// the Equates table
cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr);
String parserMessages = "";
+ boolean cparseSucceeded = false;
if (!monitor.isCancelled()) {
monitor.setMessage("Parsing C");
@@ -497,12 +603,15 @@ public class CParserUtils {
cParser.setParseFileName(fName);
cParser.setMonitor(monitor);
cParser.parse(bis);
+ cparseSucceeded = cParser.didParseSucceed();
+ } catch (RuntimeException re) {
+ Msg.info(cpp, cpp.getParseMessages());
} finally {
parserMessages = cParser.getParseMessages();
}
}
- return getFormattedParseMessage(parserMessages, cppMessages, null);
+ return new CParseResults(cpp, parserMessages, cppMessages, cparseSucceeded);
}
private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp)
@@ -522,26 +631,6 @@ public class CParserUtils {
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) {
@@ -680,4 +769,54 @@ public class CParserUtils {
errorIndex + "
" + successFailureBuffer;
}
+
+ public static File getFile(String parent, String filename) {
+ File file = findFile(parent, filename);
+ if (file != null) {
+ return file;
+ }
+ // filename lower
+ file = findFile(parent, filename.toLowerCase());
+ if (file != null) {
+ return file;
+ }
+ // parent and filename lower
+ file = findFile(parent.toLowerCase(), filename.toLowerCase());
+ if (file != null) {
+ return file;
+ }
+ // parent and filename upper
+ file = findFile(parent.toUpperCase(), filename.toUpperCase());
+ return file;
+ }
+
+ private static File findFile(String parent, String filename) {
+ File iFile = null;
+
+ iFile = new File(parent + File.separator + filename);
+ if (iFile.exists())
+ return iFile;
+
+ // try just in this directory
+ File sameiFile = new File(parent + File.separator
+ + (new File(filename)).getName());
+ if (sameiFile.exists())
+ return sameiFile;
+
+ // try all files in this directory doing to-lower on both input file and output file
+ // if match return it
+ File folder = new File(parent);
+ if (folder.isDirectory()) {
+ File[] listOfFiles = folder.listFiles();
+
+ if (listOfFiles != null) {
+ for (File file : listOfFiles) {
+ if (file.isFile() && filename.compareToIgnoreCase(file.getName()) == 0) {
+ return file;
+ }
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
index 84628aee6b..c6e6d59c74 100644
--- a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
+++ b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
@@ -622,7 +622,7 @@ public class CParser {
* @param dec Declaration
* @param funcDT function data type to qualify
*/
- private void applyFunctionQualifiers(Declaration dec, FunctionDefinitionDataType funcDT) {
+ private void applyFunctionQualifiers(Declaration dec, FunctionDefinition funcDT) {
List qualifierList = dec.getQualifiers();
if (qualifierList.contains(NORETURN) ) {
funcDT.setNoReturn(true);
@@ -1773,18 +1773,18 @@ Declaration TypeQualifier(Declaration dec) : {}
|
|
|
- ( DeclSpec() )
+ ( DeclSpec(dec) )
)
{
return dec;
}
}
-void AttributeSpec() : {}
+void AttributeSpec(Declaration dec) : {}
{
- ( ("(") SubIdent() (")") ) |
+ ( ("(") SubIdent(dec) (")") ) |
AsmStatement() |
- ( "[" "[" AttributeList() "]" "]" ) |
+ ( "[" "[" AttributeList(dec) "]" "]" ) |
AlignmentSpecifier()
}
@@ -1794,48 +1794,59 @@ void AlignmentSpecifier() : { Declaration dt = new Declaration(); }
< ALIGNAS > "(" ( TypeQualifier(dt) | AssignmentExpression() ) ")"
}
-void AttributeList() : { }
+void AttributeList(Declaration dec) : { }
{
- AttributeToken() [ ("," AttributeToken())+ ]
+ AttributeToken(dec) [ ("," AttributeToken(dec))+ ]
}
-void AttributeToken() : { Declaration dt = new Declaration(); }
+void AttributeToken(Declaration dec) : { }
{
- ( < IDENTIFIER > | TypeQualifier(dt) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dt) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ]
+ ( < IDENTIFIER > | TypeQualifier(dec) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dec) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ]
}
-void AttributeSpecList() : {}
+void AttributeSpecList(Declaration dec) : {}
{
- ( AttributeSpec() )+
+ ( AttributeSpec(dec) )+
}
-void SubIdent() : { Declaration dt = new Declaration(); }
+void SubIdent(Declaration dec) : {
+ Token id = null;
+ Declaration dt = new Declaration();
+}
{
- ( ( "(" [SubIdent()] ")" ) |
- ( | TypeQualifier(dt)) [ ( "(" [SubIdent()] ")") | ("=" SubIdent()) ]
+ ( ( "(" [SubIdent(dec)] ")" ) |
+ (id= | TypeQualifier(dec)) [ ( "(" [SubIdent(dt)] ")") | ("=" SubIdent(dt)) ]
[ ","
- SubIdent()
+ SubIdent(dt)
] |
Constant() [ ","
- SubIdent()
+ SubIdent(dt)
]
)
+ {
+ if (id != null && "noreturn".equals(id.image.replace("_", ""))) {
+ dec.addQualifier(NORETURN);
+ if (dec.getDataType() instanceof FunctionDefinition) {
+ applyFunctionQualifiers(dec, (FunctionDefinition) dec.getDataType());
+ }
+ }
+ }
}
-void DeclSpec() : {
+void DeclSpec(Declaration dec) : {
}
{
- ( ( | ) "(" DeclSpecifier() ")" ) |
- AttributeSpecList()
+ ( ( | ) "(" DeclSpecifier(dec) ")" ) |
+ AttributeSpecList(dec)
}
-void DeclSpecifier() : {
+void DeclSpecifier(Declaration dec) : {
+ Token id = null;
}
{
- "(" DeclSpecifier() ")" |
- ()+ [ "("
- DeclConstant() ( DeclConstant() )*
- ")" ]
+ "(" DeclSpecifier(dec) ")" |
+ (id= { if (id != null && "noreturn".equals(id.image)) dec.addQualifier(NORETURN); } )+
+ [ "(" DeclConstant() ( DeclConstant() )* ")" ]
}
void DeclConstant() : {}
@@ -1971,6 +1982,7 @@ DataType StructOrUnionSpecifier() : {
Token parent;
Token sname;
Composite comp;
+ Declaration dec = new Declaration();
}
{
{
@@ -1983,7 +1995,7 @@ DataType StructOrUnionSpecifier() : {
LOOKAHEAD(3)
[ t= [ ":" parent=]
{ comp=defineNamedComposite(t, null, comp); } // no parent yet, since there are no guts
- ] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList() ]
+ ] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList(dec) ]
|
sname=
)
@@ -1998,10 +2010,13 @@ DataType StructOrUnionSpecifier() : {
}
}
-Composite StructOrUnion() : {Composite comp;}
+Composite StructOrUnion() : {
+ Composite comp;
+ Declaration dec = new Declaration();
+}
{
(
- ( DeclSpec() | PragmaSpec() )*
+ ( DeclSpec(dec) | PragmaSpec() )*
{
comp = new StructureDataType(getCurrentCategoryPath(), ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr);
@@ -2015,7 +2030,7 @@ Composite StructOrUnion() : {Composite comp;}
}
|
- ( DeclSpec() )* {
+ ( DeclSpec(dec) )* {
comp = new UnionDataType(getCurrentCategoryPath(), ANONYMOUS_UNION_PREFIX + cnt++, dtMgr);
// Always set the packing, because by default structures should be aligned
@@ -2068,6 +2083,7 @@ void InitDeclarator(Declaration dt) : { Declaration dec; }
void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
Declaration dt = null;
+ Declaration dec = new Declaration();
}
{
LineDef() |
@@ -2078,7 +2094,7 @@ void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : {
[
StructDeclaratorList(dt, comp, compositeHandler) { dt= null; }
]
- [ AttributeSpecList() ]
+ [ AttributeSpecList(dec) ]
";"
)
{
@@ -2174,12 +2190,13 @@ DataType EnumSpecifier() : {
Token t= null;
DataType dt;
ArrayList list;
+ Declaration dec = new Declaration();
}
{
(
LOOKAHEAD(3)
- [AttributeSpecList()] [ t= ] "{" list= EnumeratorList() "}"
+ [AttributeSpecList(dec)] [ t= ] "{" list= EnumeratorList() "}"
{
String enumName= (t != null ? t.image : ("enum_" + cnt++));
EnumDataType enuum= new EnumDataType(getCurrentCategoryPath(), enumName, 4, dtMgr);
@@ -2248,7 +2265,7 @@ Declaration Declarator(Declaration dt, DataType container) : {
}
{
(
- [ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList() ]
+ [ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList(dec) ]
)
{
return dec;
diff --git a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj
index 4db24f649d..4725c46480 100644
--- a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj
+++ b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj
@@ -1164,6 +1164,16 @@ public class PreProcessor {
public void addIncludePath(String path) {
pathList.addElement(path);
}
+
+ public void addIncludePaths(String[] paths) {
+ if (paths == null || paths.length < 1) {
+ return;
+ }
+
+ for (String path : paths) {
+ addIncludePath(path);
+ }
+ }
public int getNumericType(String val) {
try {
@@ -1238,7 +1248,7 @@ public class PreProcessor {
outputStream = new PrintStream(fos);
}
- public void parse(String filename) throws ParseException {
+ public boolean parse(String filename) throws ParseException {
if (verboseLevel == 1) {
addParseMessage(null,
"PreProcessor: Reading from file " + filename + " . . .");
@@ -1261,7 +1271,7 @@ public class PreProcessor {
}
if (fis == null) {
addParseMessage(null, "PreProcessor: File " + filename + " not found.");
- return;
+ return false;
}
fileStack.push(filename);
alreadyDone = new HashMap();
@@ -1282,6 +1292,7 @@ public class PreProcessor {
addParseMessage(filename, "PreProcessor Token Error: " + e.getMessage());
throw e;
}
+ return true;
}
PreProcessor(PreProcessor parent) {
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogParsingAndPromptsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogParsingAndPromptsTest.java
new file mode 100644
index 0000000000..c4bddf24c1
--- /dev/null
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogParsingAndPromptsTest.java
@@ -0,0 +1,596 @@
+/* ###
+ * 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.
+ */
+package ghidra.app.plugin.core.cparser;
+
+import static org.junit.Assert.*;
+
+import java.awt.Window;
+import java.io.File;
+import java.util.ArrayList;
+
+import javax.swing.JTextArea;
+
+import org.junit.*;
+
+import docking.action.DockingActionIf;
+import docking.widgets.combobox.GhidraComboBox;
+import docking.widgets.dialogs.InputDialog;
+import docking.widgets.filechooser.GhidraFileChooser;
+import docking.widgets.pathmanager.PathnameTablePanel;
+import generic.jar.ResourceFile;
+import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
+import ghidra.app.plugin.core.cparser.ParseDialog.ComboBoxItem;
+import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
+import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
+import ghidra.app.plugin.core.processors.SetLanguageDialog;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.plugin.importer.NewLanguagePanel;
+import ghidra.program.model.data.*;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.Program;
+import ghidra.test.*;
+import utilities.util.FileUtilities;
+
+public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegrationTest {
+
+ private static final String TITLE = "CParser Results Summary";
+
+ private TestEnv env;
+ private PluginTool tool;
+
+ private Program program;
+ private CParserPlugin plugin;
+
+ private DockingActionIf cparserAction;
+
+ private DataTypeManagerPlugin dtmPlugin;
+
+
+ @Before
+ public void setUp() throws Exception {
+ program = getNotepad();
+
+ env = new TestEnv();
+ }
+
+ private Program getNotepad() throws Exception {
+ ClassicSampleX86ProgramBuilder builder =
+ new ClassicSampleX86ProgramBuilder("notepad", false, this);
+ return builder.getProgram();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ env.dispose();
+ }
+
+ private void initTool(Program prog) throws Exception {
+ if (prog != null) {
+ tool = env.showTool(prog);
+ } else {
+ tool = env.showTool();
+ }
+
+ tool.addPlugin(CodeBrowserPlugin.class.getName());
+ tool.addPlugin(GoToAddressLabelPlugin.class.getName());
+ tool.addPlugin(CParserPlugin.class.getName());
+ tool.addPlugin(DataTypeManagerPlugin.class.getName());
+ plugin = getPlugin(tool, CParserPlugin.class);
+
+ cparserAction = getAction(plugin, CParserPlugin.PARSE_ACTION_NAME);
+ dtmPlugin = getPlugin(tool, DataTypeManagerPlugin.class);
+ }
+
+ @Test
+ public void testImportToProgramNoneOpen() throws Exception {
+ initTool(null);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("No Open Program"), "OK", false);
+
+ }
+
+ @Test
+ public void testImportToProgramNoArch() throws Exception {
+ program = getNotepad();
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "MacOSX_10.5.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ String langText = parseDialog.getLanguageText().getText();
+ assertEquals("64/32 (primarily for backward compatibility)", langText);
+
+ pressButtonByText(waitForDialogComponent("Program Architecture not Specified"), "OK", false);
+ }
+
+ @Test
+ public void testImportToProgramConfirm() throws Exception {
+ program = getNotepad();
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Cancel", false);
+ }
+
+ @Test
+ public void testImportToProgram() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getPath()};
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ // dummy file empty, error
+ pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
+
+ assertNotNull("mystruct parsed into program", dataType);
+ }
+
+ @Test
+ public void testImportToProgramWithIncludePaths() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getName()};
+
+ this.setFiles(parseDialog, files);
+
+ String includePath[] = {dummyHeader.getParent()};
+
+ this.setIncludePaths(parseDialog, includePath);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ // dummy file empty, error
+ pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
+
+ assertNotNull("mystruct parsed into program", dataType);
+ }
+
+ @Test
+ public void testImportToProgramOpenArchives() throws Exception {
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ // open an archive
+ dtmPlugin.openDataTypeArchive("windows_vs12_64");
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ pressButtonByText(parseDialog, "Parse to Program", false);
+
+ pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
+
+ pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Don't Use Open Archives", false);
+ }
+
+ // switch between two
+ // change, test ask save if change
+ @Test
+ public void testSetLanguage() throws Exception {
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ //
+ // test switch to new profile after changes, NO to save changes
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
+ }, false);
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "No", false);
+
+
+ assertEquals("VisualStudio12_64.prf",parseDialog.getCurrentItem().getName());
+
+ //
+ // test forced save as new profile, doesn't exist
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+ }, false);
+
+ // make sure profile is gone
+ ResourceFile userProfileParent = parseDialog.getUserProfileParent();
+ File f = new File(userProfileParent.getAbsolutePath(),"MyTestProfile.prf");
+ f.delete();
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
+
+ InputDialog dialog = waitForDialogComponent(InputDialog.class);
+
+ dialog.setValue("MyTestProfile");
+ pressButtonByText(dialog, "OK");
+ waitForSwing();
+
+ assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
+
+ // test save as forced to an existing profile
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
+ }, false);
+
+ setLanguage(parseDialog, "x86:LE:64:default", "gcc");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+ }, false);
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
+
+ dialog = waitForDialogComponent(InputDialog.class);
+
+ dialog.setValue("MyTestProfile");
+ pressButtonByText(dialog, "OK");
+ waitForSwing();
+
+ pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
+
+ waitForSwing();
+
+ assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
+
+ // test save the current USER profile when switching
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "MyTestProfile.prf");
+ }, false);
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ runSwing(() -> {
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+ }, false);
+
+ pressButtonByText(waitForDialogComponent("Save Changes to Profile?"), "Yes", false);
+
+ assertEquals("VisualStudio12_32.prf",parseDialog.getCurrentItem().getName());
+
+ }
+
+ private void setLanguage(ParseDialog parseDialog, String langID, String compID) {
+ runSwing(() -> {
+ pressButton(parseDialog.getLanguageButton());
+ }, false);
+
+ SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
+ assertNotNull(dlg);
+ NewLanguagePanel languagePanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ assertNotNull(languagePanel);
+
+ waitForSwing();
+
+ runSwing(() -> {
+ NewLanguagePanel selectLangPanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ selectLangPanel.setSelectedLcsPair(
+ new LanguageCompilerSpecPair(new LanguageID(langID), new CompilerSpecID(compID)));
+ }, true);
+
+ waitForSwing();
+
+ pressButtonByText(dlg, "OK");
+ }
+
+ // test parse to file, choose file
+ @Test
+ public void testImportToFile() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ final File tmpDir = createTempDirectory("GDT");
+ FileUtilities.checkedMkdir(tmpDir);
+
+ // open an archive
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getName()};
+
+ this.setFiles(parseDialog, files);
+
+ String includePath[] = {dummyHeader.getParent()};
+
+ this.setIncludePaths(parseDialog, includePath);
+
+ pressButtonByText(parseDialog, "Parse to File...", false);
+
+ final GhidraFileChooser fileChooser = waitForDialogComponent(GhidraFileChooser.class);
+
+ runSwing(() -> fileChooser.setSelectedFile(new File(tmpDir, "dummy")));
+
+ waitForUpdateOnChooser(fileChooser);
+
+ pressButtonByName(fileChooser.getComponent(), "OK");
+
+ // dummy file empty, error
+ pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to File...", false);
+
+ final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
+
+ final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
+
+ runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
+
+ waitForUpdateOnChooser(existsChooser);
+
+ pressButtonByName(existsChooser.getComponent(), "OK");
+
+ pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ // open the file archive
+ FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
+
+ DataType dataType = fileArchive.getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
+
+ assertNotNull("mystruct parsed into program", dataType);
+ }
+
+ // test parse to file, choose file
+ @Test
+ public void testImportToFileUseArchive() throws Exception {
+
+ initTool(program);
+
+ ParseDialog parseDialog = showParseDialog();
+
+ // open an archive
+ dtmPlugin.openDataTypeArchive("windows_vs12_64");
+
+ this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
+
+ setLanguage(parseDialog, "8051:BE:16:default", "default");
+
+ final File tmpDir = createTempDirectory("GDT");
+ FileUtilities.checkedMkdir(tmpDir);
+
+ // open an archive
+ // write out a dummy header file to read
+ File dummyHeader = this.createTempFile("dummy.h");
+
+ FileUtilities.deleteDir(dummyHeader);
+
+ String files[] = {dummyHeader.getName()};
+
+ String includePath[] = {dummyHeader.getParent()};
+
+ this.setIncludePaths(parseDialog, includePath);
+
+ // dummy file full, OK
+ FileUtilities.writeStringToFile(dummyHeader,
+ "typedef int wchar_t;\n" +
+ "struct mystruct {\n" +
+ " wchar_t defined_wchar_t;\n" +
+ " wint_t defined_from_windows;\n" +
+ "};\n");
+
+ this.setFiles(parseDialog, files);
+
+ pressButtonByText(parseDialog, "Parse to File...", false);
+
+ final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
+
+ final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
+
+ runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
+
+ waitForUpdateOnChooser(existsChooser);
+
+ pressButtonByName(existsChooser.getComponent(), "OK");
+
+ pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Use Open Archives", false);
+
+ pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
+
+ // open the file archive
+ FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
+
+ DataType dataType = fileArchive.getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
+
+ assertNotNull("mystruct parsed into program", dataType);
+
+ Structure struct = (Structure) dataType;
+
+ DataTypeComponent component = struct.getComponent(1);
+ assertEquals (component.getDataType().getName(), "wint_t");
+ }
+
+
+ private void startSetLanguage(LanguageID languageID, CompilerSpecID compilerSpecID) throws Exception {
+ if (languageID == null) {
+ throw new RuntimeException("languageID == null not allowed");
+ }
+ if (compilerSpecID == null) {
+ throw new RuntimeException("compilerSpecID == null not allowed");
+ }
+
+ SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
+ assertNotNull(dlg);
+ NewLanguagePanel languagePanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ assertNotNull(languagePanel);
+
+ waitForSwing();
+
+ runSwing(() -> {
+ NewLanguagePanel selectLangPanel =
+ (NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
+ selectLangPanel.setSelectedLcsPair(
+ new LanguageCompilerSpecPair(languageID, compilerSpecID));
+ }, true);
+
+ waitForSwing();
+
+ pressButtonByText(dlg, "OK");
+ }
+
+ private void assertResultDialog() {
+ Window aboutDialog = waitForWindow(TITLE);
+ assertNotNull(aboutDialog);
+ pressButtonByText(aboutDialog, "OK");
+ }
+
+ private ParseDialog showParseDialog() {
+
+ //ActionContext actionContext = cbPlugin.getProvider().getActionContext(null);
+ performAction(cparserAction, false);
+ ParseDialog parseDialog = waitForDialogComponent(ParseDialog.class);
+ assertNotNull(parseDialog);
+ return parseDialog;
+ }
+
+ private void setOption(ParseDialog dialog, String options) {
+ runSwing(() -> {
+ JTextArea parseOptionsTextField = dialog.getParseOptionsTextField();
+ parseOptionsTextField.setText(options);
+ });
+ }
+
+ private void setIncludePaths(ParseDialog dialog, String paths[]) {
+ runSwing(() -> {
+ PathnameTablePanel incPaths = dialog.getIncludePaths();
+ incPaths.setPaths(paths);
+ });
+ }
+
+ private void setFiles(ParseDialog dialog, String files[]) {
+ runSwing(() -> {
+ PathnameTablePanel sourceFiles = dialog.getSourceFiles();
+ sourceFiles.setPaths(files);
+ });
+ }
+
+ private void setSelectedParseProfile(ParseDialog dialog, String profileName) {
+ runSwing(() -> {
+ GhidraComboBox parseComboBox = dialog.getParseComboBox();
+ ArrayList profiles = dialog.getProfiles();
+ int index = 0;
+ for (ComboBoxItem comboBoxItem : profiles) {
+ if (profileName.equals(comboBoxItem.getName())) {
+ parseComboBox.setSelectedIndex(index);
+ break;
+ }
+ index++;
+ }
+ });
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java
index f2d0ff3844..e3d14c13e5 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/cparser/ParseDialogTest.java
@@ -352,17 +352,21 @@ public class ParseDialogTest extends AbstractGhidraHeadedIntegrationTest {
BufferedReader br = new BufferedReader(new InputStreamReader(profileFile.getInputStream()));
String line = null;
- while ((line = br.readLine()) != null) {
+
+ // read paths
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
line = line.trim();
- if (line.startsWith("-") || (line.length() == 0 && buffy.length() > 0)) {
- // this is a compiler directive
- buffy.append(line + "\n");
- }
- else if (line.length() > 0) {
- File f = new File(line);
- pathList.add(f.getPath());
- }
+
+ pathList.add(line);
}
+
+ // read options
+ while ((line = br.readLine()) != null && line.trim().length() > 0) {
+ line = line.trim();
+
+ buffy.append(line + "\n");
+ }
+
paths = pathList;
defaultPrfOptions = buffy.toString();
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
index a06e8235d6..52282a5823 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java
@@ -222,11 +222,11 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
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 missing", 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 missing", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\""));
- assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
+ assertTrue("Duplicate ENUM message missing", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\""));
DataType dt;
DataType pointedToDT;
@@ -362,8 +362,16 @@ public class CParserTest extends AbstractGhidraHeadlessIntegrationTest {
dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Noreturn_exit");
assertTrue("not a function", dt instanceof FunctionDefinition);
- assertTrue("Caller should purge", ((FunctionDefinition) dt).hasNoReturn());
+ assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
+ dt = dtMgr.getDataType(new CategoryPath("/functions"), "win_exit");
+ assertTrue("not a function", dt instanceof FunctionDefinition);
+ assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
+
+ dt = dtMgr.getDataType(new CategoryPath("/functions"), "gcc_exit");
+ assertTrue("not a function", dt instanceof FunctionDefinition);
+ assertTrue("Caller should noreturn", ((FunctionDefinition) dt).hasNoReturn());
+
dt = dtMgr.getDataType(new CategoryPath("/"), "UINT2");
assertTrue(dt instanceof TypeDef);
assertEquals("ushort", ((TypeDef) dt).getBaseDataType().getName());
diff --git a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
index c26101d2d1..6dd802956c 100644
--- a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
+++ b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
@@ -378,12 +378,18 @@ int fputs( char * , void * ) __asm("_" "fputs" "$FPOOTS");
void _exit(int) __attribute__((noreturn));
+// NoReturn
+
+extern void gcc_exit (int __status) __attribute__ ((__noreturn__));
+
+__declspec(noreturn) void __cdecl win_exit(int _Code);
+
+void _exit(int) __attribute__((noreturn));
+
// C11 noreturn
void _Noreturn _Noreturn_exit(int);
-
-
// C23 Attributes
int [[deprecated]] imDeprecated(int);
int [[gnu::deprecated]] imDeprecatedToo(int) ;
diff --git a/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java b/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java
index 121d95c7dd..4682daca4a 100644
--- a/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java
+++ b/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java
@@ -31,6 +31,7 @@ import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.CPP.DefineTable;
import ghidra.app.util.cparser.CPP.ParseException;
import ghidra.app.util.cparser.CPP.PreProcessor;
@@ -395,17 +396,14 @@ public class CreateAVR8GDTArchiveScript extends GhidraScript {
*/
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);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, "avr8:LE:16:atmega256", "gcc", monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
- storeExtraDefinitions(procName, dtMgr, openTypes, cpp);
+ storeExtraDefinitions(procName, dtMgr, openTypes, results.preProcessor());
}
/**
diff --git a/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java b/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java
index 9d55d457d1..4091798a8f 100644
--- a/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java
+++ b/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java
@@ -33,6 +33,7 @@ import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
@@ -64,9 +65,9 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f);
- String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor);
+ CParseResults results = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, monitor);
- Msg.info(this, messages);
+ Msg.info(this, results.getFormattedParseMessage(null));
dtMgr.save();
dtMgr.close();
@@ -113,7 +114,6 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
"-D__builtin_va_list=void *",
"-D__DO_NOT_DEFINE_COMPILE",
"-D_Complex",
- "-D_WCHAR_T",
"-D__NO_STRING_INLINES",
"-D__signed__",
"-D__extension__=",
@@ -159,7 +159,6 @@ public class CreateJNIGDTArchivesScript extends GhidraScript {
"-D__builtin_va_list=void *",
"-D__DO_NOT_DEFINE_COMPILE",
"-D_Complex",
- "-D_WCHAR_T",
"-D__NO_STRING_INLINES",
"-D__signed__",
"-D__extension__=",