diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index 292a996e04..614ae99c4f 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -20,9 +20,9 @@ data/file_extension_icons.xml||GHIDRA||||END| data/functionTags.xml||GHIDRA||||END| data/ms_pe_rich_products.xml||GHIDRA||||END| data/noReturnFunctionConstraints.xml||GHIDRA||||END| -data/parserprofiles/MacOSX_10.5.prf||GHIDRA||reviewed||END| +data/parserprofiles/MacOSX_10.5.prf||GHIDRA||||END| data/parserprofiles/MacOSX_10.9.prf||GHIDRA||||END| -data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||reviewed||END| +data/parserprofiles/MacOSX_Cocoa.prf||GHIDRA||||END| data/parserprofiles/VisualStudio12_32.prf||GHIDRA||||END| data/parserprofiles/VisualStudio12_64.prf||GHIDRA||||END| data/parserprofiles/VisualStudio9.prf||GHIDRA||reviewed||END| @@ -31,7 +31,7 @@ data/parserprofiles/generic_clib_32.prf||GHIDRA||||END| data/parserprofiles/generic_clib_64.prf||GHIDRA||||END| data/parserprofiles/linux_32.prf||GHIDRA||||END| data/parserprofiles/linux_64.prf||GHIDRA||||END| -data/parserprofiles/objc_mac_carbon.prf||GHIDRA||reviewed||END| +data/parserprofiles/objc_mac_carbon.prf||GHIDRA||||END| data/parserprofiles/vs12Local.prf||GHIDRA||||END| data/pcodetest/EmuTesting.gdt||GHIDRA||||END| data/stringngrams/StringModel.sng||GHIDRA||reviewed||END| diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.5.prf index 552d090977..d6d7265a87 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_Bool="BOOL" -D_WCHAR_T -D_Complex -Drestrict diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_10.9.prf index 4af5368d23..d084caa7ba 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_Bool="BOOL" -D_WCHAR_T -D_Complex -Drestrict diff --git a/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf b/Ghidra/Features/Base/data/parserprofiles/MacOSX_Cocoa.prf index cab3d5d79c..ad295be77e 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_Bool="BOOL" -D_WCHAR_T -D_Complex -Drestrict diff --git a/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf b/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf index a8ea73edaa..3d331f0ffd 100644 --- a/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf +++ b/Ghidra/Features/Base/data/parserprofiles/generic_clib_32.prf @@ -236,6 +236,5 @@ arpa/tftp.h -D__NO_LONG_DOUBLE_MATH -D__signed__ -D__extension__="" --D_Bool="bool" -D__GLIBC_HAVE_LONG_LONG=1 -Daligned_u64=uint64_t diff --git a/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf b/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf index 434dd3205f..0c76e8d1aa 100644 --- a/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf +++ b/Ghidra/Features/Base/data/parserprofiles/generic_clib_64.prf @@ -235,7 +235,6 @@ arpa/tftp.h -D__NO_STRING_INLINES -D__signed__ -D__extension__="" --D_Bool="bool" -D__GLIBC_HAVE_LONG_LONG=1 -D__need_sigset_t -Daligned_u64=uint64_t diff --git a/Ghidra/Features/Base/data/parserprofiles/linux_32.prf b/Ghidra/Features/Base/data/parserprofiles/linux_32.prf index e20dd209e8..5235499a8a 100644 --- a/Ghidra/Features/Base/data/parserprofiles/linux_32.prf +++ b/Ghidra/Features/Base/data/parserprofiles/linux_32.prf @@ -533,6 +533,5 @@ auth_gssapi.h -D__NO_LONG_DOUBLE_MATH -D__signed__ -D__extension__="" --D_Bool="bool" -D__GLIBC_HAVE_LONG_LONG=1 -Daligned_u64=uint64_t diff --git a/Ghidra/Features/Base/data/parserprofiles/linux_64.prf b/Ghidra/Features/Base/data/parserprofiles/linux_64.prf index 04f8c5252f..f3c783c33b 100644 --- a/Ghidra/Features/Base/data/parserprofiles/linux_64.prf +++ b/Ghidra/Features/Base/data/parserprofiles/linux_64.prf @@ -532,6 +532,5 @@ auth_gssapi.h -D__NO_STRING_INLINES -D__signed__ -D__extension__="" --D_Bool="bool" -D__GLIBC_HAVE_LONG_LONG=1 -Daligned_u64=uint64_t diff --git a/Ghidra/Features/Base/data/parserprofiles/objc_mac_carbon.prf b/Ghidra/Features/Base/data/parserprofiles/objc_mac_carbon.prf index dfed60f93f..7a65c3787d 100644 --- a/Ghidra/Features/Base/data/parserprofiles/objc_mac_carbon.prf +++ b/Ghidra/Features/Base/data/parserprofiles/objc_mac_carbon.prf @@ -380,4 +380,3 @@ WSTypes.h -DTARGET_API_MAC_OSX -DTARGET_CARBON -DHANDLE="unsigned long" --D_Bool="BOOL" diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java new file mode 100644 index 0000000000..fe48e7c568 --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java @@ -0,0 +1,1041 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// +// Parses default header file gdt archives +// +// To replace existing header files and have the data type ID's synchronized +// +// Must run SynchronizeGDTCategoryPaths.java script with old and replacement GDT +// archive to synchronize upper/lower case paths +/// (only on windows archives) +// +// Then Run DataTypeArchiveTransformer in eclipse to synchronize old data types ID's +// +//@category Data Types + +import java.io.File; +import java.io.IOException; + +import ghidra.app.script.GhidraScript; +import ghidra.app.util.cparser.C.CParserUtils; +import ghidra.app.util.cparser.C.ParseException; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.FileDataTypeManager; +import ghidra.util.Msg; +import ghidra.util.task.TaskMonitor; + +public class CreateDefaultGDTArchivesScript extends GhidraScript { + + private File outputDirectory; + + private static String headerFilePath = "/data/HeaderFiles"; + + @Override + protected void run() throws Exception { + outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir"); + + parseGDT_CLIB32(); + parseGDT_CLIB64(); + + parseGDT_VS12_32(); + parseGDT_VS12_64(); + + } + + private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) + throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { + DataTypeManager openTypes[] = null; + + parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args); + } + + private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) + throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { + + String dataTypeFile = outputDir + File.separator + gdtName + ".gdt"; + + File f = getArchiveFile(dataTypeFile); + + FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); + + String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor); + + Msg.info(this, messages); + + dtMgr.save(); + dtMgr.close(); + } + + /** + * Turn string into a file, delete old archive if it exists + * + * @param dataTypeFile + * + * @return file + */ + private File getArchiveFile(String dataTypeFile) { + File f = new File(dataTypeFile); + if (f.exists()) { + f.delete(); + } + String lockFile = dataTypeFile + ".ulock"; + File lf = new File(lockFile); + if (lf.exists()) { + lf.delete(); + } + return f; + } + + public void parseGDT_VS12_32() throws Exception { + + String filenames[] = { + "sdkddkver.h", + "sal.h", + "assert.h", + "conio.h", + "crtdefs.h", + "crtdbg.h", + "crtwrn.h", + "ctype.h", + "basetsd.h", + "WinDef.h", + "WinNT.h", + "delayimp.h", + "direct.h", + "dos.h", + "errno.h", + "excpt.h", + "fcntl.h", + "float.h", + "fpieee.h", + "io.h", + "iso646.h", + "limits.h", + "locale.h", + "malloc.h", + "math.h", + "mbctype.h", + "mbstring.h", + "memory.h", + "minmax.h", + "new.h", + "omp.h", + "pgobootrun.h", + "process.h", + "rtcapi.h", + "search.h", + "setjmp.h", + "setjmpex.h", + "share.h", + "signal.h", + "srv.h", + "stdarg.h", + "stddef.h", + "stdexcpt.h", + "stdio.h", + "stdlib.h", + "string.h", + "tchar.h", + "time.h", + "use_ansi.h", + "vadefs.h", + "varargs.h", + "wchar.h", + "wctype.h", + "xlocinfo.h", + "xmath.h", + "ymath.h", + "yvals.h", + "CommDlg.h", + "WinUser.h", + "WinNls.h", + "internal.h", + "strsafe.h", + "align.h", + "awint.h", + "crtversion.h", + "cruntime.h", + "ctime.h", + "cvt.h", + "dbgint.h", + "ehdata.h", + "emmintrin.h", + "errmsg.h", + "fenv.h", + "file2.h", + "fltintrn.h", + "immintrin.h", + "internal_securecrt.h", + "inttypes.h", + "isa_availability.h", + "mbdata.h", + "msdos.h", + "mtdll.h", + "nlsdownlevel.h", + "nlsint.h", + "nmmintrin.h", + "oscalls.h", + "pmmintrin.h", + "rtcsup.h", + "rterr.h", + "sect_attribs.h", + "setlocal.h", + "smmintrin.h", + "stdbool.h", + "stdint.h", + "syserr.h", + "targetver.h", + "tmmintrin.h", + "winheap.h", + "wmmintrin.h", + "wrapwin.h", + "xkeycheck.h", + "xmmintrin.h", + "xmtx.h", + "xtgmath.h", + "xxcctype.h", + "xxdftype.h", + "xxfftype.h", + "xxlftype.h", + "xxwctype.h", + "xxxprec.h", + "shlobj.h", + "evntprov.h", + "uiautomation.h", + "aclapi.h", + "appcompatapi.h", + "capi.h", + "clusapi.h", + "cryptuiapi.h", + "cscapi.h", + "devpropdef.h", + "dhcpsapi.h", + "dwmapi.h", + "ehstorapi.h", + "functiondiscoveryapi.h", + "ipexport.h", + "icmpapi.h", + "iepmapi.h", + "imapi.h", + "ksopmapi.h", + "locationapi.h", + "lpmapi.h", + "mapi.h", + "mbnapi.h", + "mfapi.h", + "mgmtapi.h", + "mmdeviceapi.h", + "mprapi.h", + "msctfmonitorapi.h", + "ndfapi.h", + "netioapi.h", + "npapi.h", + "nspapi.h", + "ntdsapi.h", + "ntmsapi.h", + "ntsecapi.h", + "patchapi.h", + "portabledeviceapi.h", + "portabledeviceconnectapi.h", + "propapi.h", + "psapi.h", + "rdpencomapi.h", + "resapi.h", + "sapi.h", + "searchapi.h", + "sensapi.h", + "sensorsapi.h", + "setupapi.h", + "shellapi.h", + "shlwapi.h", + "srrestoreptapi.h", + "svrapi.h", + "t2embapi.h", + "tapi.h", + "uiautomationcoreapi.h", + "wcnapi.h", + "wdsclientapi.h", + "werapi.h", + "windowssideshowapi.h", + "wlanapi.h", + "wpapi.h", + "wpcapi.h", + "wscapi.h", + "wsdapi.h", + "wspiapi.h", + + "rpcproxy.h", + }; + + 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", + "-DWINVER=0x0900", + "-D_X86_", + "-D_WIN32", + "-DCRTDLL", + "-D_USE_ATTRIBUTES_FOR_SAL", + "-D_CRTBLD", + "-D_OPENMP_NOFORCE_MANIFEST", + "-DSTRSAFE_LIB", + "-DSTRSAFE_LIB_IMPL", + "-DLPSKBINFO=LPARAM", + "-D_WCHAR_T_DEFINED", + "-DCONST=const", + "-D_CRT_SECURE_NO_WARNINGS", + "-D_CRT_NONSTDC_NO_DEPRECATE", + "-D_CRT_NONSTDC_NO_WARNINGS", + "-D_CRT_OBSOLETE_NO_DEPRECATE", + "-D_ALLOW_KEYWORD_MACROS", + "-D_ASSERT_OK", + "-DSTRSAFE_NO_DEPRECATE", + "-D__possibly_notnullterminated", + "-Dtype_info=\"void *\"", + "-D_ThrowInfo=ThrowInfo", + "-v0", + "-D__inner_checkReturn=", + }; + + parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, args); + } + + + + public void parseGDT_VS12_64() throws Exception { + + String filenames[] = { + "sdkddkver.h", + "sal.h", + "assert.h", + "conio.h", + "crtdefs.h", + "crtdbg.h", + "crtwrn.h", + "ctype.h", + "basetsd.h", + "WinDef.h", + "WinNT.h", + "delayimp.h", + "direct.h", + "dos.h", + "errno.h", + "excpt.h", + "fcntl.h", + "float.h", + "fpieee.h", + "io.h", + "iso646.h", + "limits.h", + "locale.h", + "malloc.h", + "math.h", + "mbctype.h", + "mbstring.h", + "memory.h", + "minmax.h", + "new.h", + "omp.h", + "pgobootrun.h", + "process.h", + "rtcapi.h", + "search.h", + "setjmp.h", + "setjmpex.h", + "share.h", + "signal.h", + "srv.h", + "stdarg.h", + "stddef.h", + "stdexcpt.h", + "stdio.h", + "stdlib.h", + "string.h", + "tchar.h", + "time.h", + "use_ansi.h", + "vadefs.h", + "varargs.h", + "wchar.h", + "wctype.h", + "xlocinfo.h", + "xmath.h", + "ymath.h", + "yvals.h", + "CommDlg.h", + "WinUser.h", + "WinNls.h", + "internal.h", + "strsafe.h", + "align.h", + "awint.h", + "crtversion.h", + "cruntime.h", + "ctime.h", + "cvt.h", + "dbgint.h", + "ehdata.h", + "emmintrin.h", + "errmsg.h", + "fenv.h", + "file2.h", + "fltintrn.h", + "immintrin.h", + "internal_securecrt.h", + "inttypes.h", + "isa_availability.h", + "mbdata.h", + "msdos.h", + "mtdll.h", + "nlsdownlevel.h", + "nlsint.h", + "nmmintrin.h", + "oscalls.h", + "pmmintrin.h", + "rtcsup.h", + "rterr.h", + "sect_attribs.h", + "setlocal.h", + "smmintrin.h", + "stdbool.h", + "stdint.h", + "syserr.h", + "targetver.h", + "tmmintrin.h", + "winheap.h", + "wmmintrin.h", + "wrapwin.h", + "xkeycheck.h", + "xmmintrin.h", + "xmtx.h", + "xtgmath.h", + "xxcctype.h", + "xxdftype.h", + "xxfftype.h", + "xxlftype.h", + "xxwctype.h", + "xxxprec.h", + "shlobj.h", + "evntprov.h", + "uiautomation.h", + "aclapi.h", + "appcompatapi.h", + "capi.h", + "clusapi.h", + "cryptuiapi.h", + "cscapi.h", + "devpropdef.h", + "dhcpsapi.h", + "dwmapi.h", + "ehstorapi.h", + "functiondiscoveryapi.h", + "ipexport.h", + "icmpapi.h", + "iepmapi.h", + "imapi.h", + "ksopmapi.h", + "locationapi.h", + "lpmapi.h", + "mapi.h", + "mbnapi.h", + "mfapi.h", + "mgmtapi.h", + "mmdeviceapi.h", + "mprapi.h", + "msctfmonitorapi.h", + "ndfapi.h", + "netioapi.h", + "npapi.h", + "nspapi.h", + "ntdsapi.h", + "ntmsapi.h", + "ntsecapi.h", + "patchapi.h", + "portabledeviceapi.h", + "portabledeviceconnectapi.h", + "propapi.h", + "psapi.h", + "rdpencomapi.h", + "resapi.h", + "sapi.h", + "searchapi.h", + "sensapi.h", + "sensorsapi.h", + "setupapi.h", + "shellapi.h", + "shlwapi.h", + "srrestoreptapi.h", + "svrapi.h", + "t2embapi.h", + "tapi.h", + "uiautomationcoreapi.h", + "wcnapi.h", + "wdsclientapi.h", + "werapi.h", + "windowssideshowapi.h", + "wlanapi.h", + "wpapi.h", + "wpcapi.h", + "wscapi.h", + "wsdapi.h", + "wspiapi.h", + + "rpcproxy.h", + }; + + 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", + "-D_AMD64_", + "-D_M_AMD64", + "-D_M_X64", + "-D_WIN64", + "-D_WIN32", + "-D_USE_ATTRIBUTES_FOR_SAL", + "-D_CRTBLD", + "-D_OPENMP_NOFORCE_MANIFEST", + "-DSTRSAFE_LIB", + "-DSTRSAFE_LIB_IMPL", + "-DLPSKBINFO=LPARAM", + "-D_WCHAR_T_DEFINED", + "-DCONST=const", + "-D_CRT_SECURE_NO_WARNINGS", + "-D_CRT_NONSTDC_NO_DEPRECATE", + "-D_CRT_NONSTDC_NO_WARNINGS", + "-D_CRT_OBSOLETE_NO_DEPRECATE", + "-D_ALLOW_KEYWORD_MACROS", + "-D_ASSERT_OK", + "-DSTRSAFE_NO_DEPRECATE", + "-D__possibly_notnullterminated", + "-Dtype_info=\"void *\"", + "-D_ThrowInfo=ThrowInfo", + "-D__unaligned=", + "-v0", + "-D__inner_checkReturn=", + }; + + parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, args); + } + + + public void parseGDT_CLIB64() throws Exception { + + String filenames[] = { + "sys/types.h", + "types.h", + "stddef.h", + "stddef.h", + "openssl/opensslconf-x86_64.h", + "openssl/bn.h", + "openssl/ssl.h", + "openssl/asn1_mac.h", + "openssl/asn1t.h", + "openssl/blowfish.h", + "openssl/camellia.h", + "openssl/cast.h", + "openssl/cmac.h", + "openssl/cms.h", + "openssl/conf_api.h", + "openssl/des.h", + "openssl/dso.h", + "openssl/engine.h", + "openssl/fips_rand.h", + "openssl/idea.h", + "openssl/krb5_asn.h", + "openssl/md2.h", + "openssl/md4.h", + "openssl/md5.h", + "openssl/ocsp.h", + "openssl/pkcs12.h", + "openssl/rc2.h", + "openssl/rc4.h", + "openssl/ripemd.h", + "openssl/seed.h", + "openssl/ssl3.h", + "openssl/txt_db.h", + "openssl/whrlpool.h", + "aio.h", + "arpa/inet.h", + "cpio.h", + "dirent.h", + "fcntl.h", + "fmtmsg.h", + "fnmatch.h", + "ftw.h", + "glob.h", + "grp.h", + "iconv.h", + "langinfo.h", + "libgen.h", + "monetary.h", + "mqueue.h", + "ndbm.h", + "net/if.h", + "netdb.h", + "netinet/in.h", + "netinet/tcp.h", + "nl_types.h", + "poll.h", + "pthread.h", + "pwd.h", + "regex.h", + "sched.h", + "search.h", + "semaphore.h", + "spawn.h", + "strings.h", + "stropts.h", + "sys/ipc.h", + "sys/mman.h", + "sys/msg.h", + "sys/resource.h", + "sys/select.h", + "sys/sem.h", + "sys/shm.h", + "sys/socket.h", + "sys/stat.h", + "sys/statvfs.h", + "sys/time.h", + "sys/times.h", + "sys/types.h", + "sys/uio.h", + "sys/un.h", + "sys/utsname.h", + "sys/wait.h", + "syslog.h", + "tar.h", + "termios.h", + "trace.h", + "ulimit.h", + "unistd.h", + "utime.h", + "utmpx.h", + "wordexp.h", + "assert.h", + "complex.h", + "ctype.h", + "fenv.h", + "float.h", + "inttypes.h", + "iso646.h", + "limits.h", + "locale.h", + "math.h", + "setjmp.h", + "signal.h", + "stdarg.h", + "stdbool.h", + "stddef.h", + "stdint.h", + "stdio.h", + "stdlib.h", + "string.h", + "tgmath.h", + "time.h", + "wchar.h", + "wctype.h", + "sys/acct.h", + "sys/debugreg.h", + "sys/epoll.h", + "sys/eventfd.h", + "sys/fcntl.h", + "sys/fsuid.h", + "sys/gmon.h", + "sys/gmon_out.h", + "sys/inotify.h", + "sys/io.h", + "sys/kd.h", + "sys/kdaemon.h", + "sys/klog.h", + "sys/mount.h", + "sys/mtio.h", + "sys/pci.h", + "sys/perm.h", + "sys/personality.h", + "sys/prctl.h", + "sys/profil.h", + "sys/ptrace.h", + "sys/quota.h", + "sys/raw.h", + "sys/reboot.h", + "sys/reg.h", + "sys/sem.h", + "sys/sendfile.h", + "sys/signal.h", + "sys/signalfd.h", + "sys/socketvar.h", + "sys/soundcard.h", + "sys/statvfs.h", + "sys/swap.h", + "sys/sysctl.h", + "sys/sysinfo.h", + "sys/termios.h", + "sys/timerfd.h", + "sys/ttychars.h", + "sys/ultrasound.h", + "sys/unistd.h", + "sys/ustat.h", + "sys/vfs.h", + "sys/vlimit.h", + "sys/vt.h", + "sys/vtimes.h", + "sys/xattr.h", + "errno.h", + "mathcalls.h", + "net/ethernet.h", + "net/if_arp.h", + "net/if_ppp.h", + "net/if_slip.h", + "net/ppp_defs.h", + "net/if.h", + "net/if_packet.h", + "net/if_shaper.h", + "net/ppp-comp.h", + "net/route.h", + "netinet/ether.h", + "netinet/if_fddi.h", + "netinet/in.h ", + "netinet/ip6.h", + "netinet/udp.h", + "netinet/icmp6.h", + "netinet/if_tr.h", + "netinet/in_systm.h", + "netinet/ip_icmp.h", + "netinet/if_ether.h", + "netinet/igmp.h", + "netinet/ip.h", + "netinet/tcp.h", + "rpc/types.h", + "rpc/auth.h", + "rpc/des_crypt.h", + "rpc/pmap_prot.h", + "rpc/rpc_msg.h", + "rpc/xdr.h", + "rpc/auth_des.h", + "rpc/key_prot.h", + "rpc/pmap_rmt.h", + "rpc/svc.h", + "rpc/auth_unix.h", + "rpc/netdb.h", + "rpc/rpc.h", + "rpc/svc_auth.h", + "rpc/clnt.h", + "rpc/pmap_clnt.h", + "rpc/rpc_des.h", + "rpcsvc/bootparam.h", + "rpcsvc/nis_callback.h", + "rpcsvc/yp_prot.h", + "rpcsvc/rstat.h", + "rpcsvc/rusers.h", + "rpcsvc/spray.h", + "rpcsvc/ypupd.h", + "rpcsvc/mount.h", + "rpcsvc/nis.h", + "protocols/routed.h", + "protocols/rwhod.h", + "protocols/talkd.h", + "protocols/timed.h", + "arpa/ftp.h", + "arpa/inet.h", + "arpa/nameser.h", + "arpa/nameser_compat.h", + "arpa/telnet.h", + "arpa/tftp.h", + }; + + 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", + "-D__WORDSIZE=64", + "-D__builtin_va_list=void *", + "-D__DO_NOT_DEFINE_COMPILE", + "-D_Complex", + "-D_WCHAR_T", + "-D__NO_STRING_INLINES", + "-D__signed__", + "-D__extension__=", + "-D__GLIBC_HAVE_LONG_LONG=1", + "-D__need_sigset_t", + "-Daligned_u64=uint64_t", + }; + + parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, args); + } + + + public void parseGDT_CLIB32() throws Exception { + + String filenames[] = { + "sys/types.h", + "types.h", + "stddef.h", + "stddef.h", + "openssl/opensslconf-x86_64.h", + "openssl/des.h", + "openssl/bn.h", + "openssl/ssl.h", + "openssl/asn1_mac.h", + "openssl/asn1t.h", + "openssl/blowfish.h", + "openssl/camellia.h", + "openssl/cast.h", + "openssl/cmac.h", + "openssl/cms.h", + "openssl/conf_api.h", + "openssl/dso.h", + "openssl/engine.h", + "openssl/fips_rand.h", + "openssl/idea.h", + "openssl/krb5_asn.h", + "openssl/md2.h", + "openssl/md4.h", + "openssl/md5.h", + "openssl/ocsp.h", + "openssl/pkcs12.h", + "openssl/rc2.h", + "openssl/rc4.h", + "openssl/ripemd.h", + "openssl/seed.h", + "openssl/ssl3.h", + "openssl/txt_db.h", + "openssl/whrlpool.h", + "aio.h", + "arpa/inet.h", + "cpio.h", + "dirent.h", + "fcntl.h", + "fmtmsg.h", + "fnmatch.h", + "ftw.h", + "glob.h", + "grp.h", + "iconv.h", + "langinfo.h", + "libgen.h", + "monetary.h", + "mqueue.h", + "ndbm.h", + "net/if.h", + "netdb.h", + "netinet/in.h", + "netinet/tcp.h", + "nl_types.h", + "poll.h", + "pthread.h", + "pwd.h", + "regex.h", + "sched.h", + "search.h", + "semaphore.h", + "spawn.h", + "strings.h", + "stropts.h", + "sys/ipc.h", + "sys/mman.h", + "sys/msg.h", + "sys/resource.h", + "sys/select.h", + "sys/sem.h", + "sys/shm.h", + "sys/socket.h", + "sys/stat.h", + "sys/statvfs.h", + "sys/time.h", + "sys/times.h", + "sys/types.h", + "sys/uio.h", + "sys/un.h", + "sys/utsname.h", + "sys/wait.h", + "syslog.h", + "tar.h", + "termios.h", + "trace.h", + "ulimit.h", + "unistd.h", + "utime.h", + "utmpx.h", + "wordexp.h", + "assert.h", + "complex.h", + "ctype.h", + "fenv.h", + "float.h", + "inttypes.h", + "iso646.h", + "limits.h", + "locale.h", + "math.h", + "setjmp.h", + "signal.h", + "stdarg.h", + "stdbool.h", + "stddef.h", + "stdint.h", + "stdio.h", + "stdlib.h", + "string.h", + "tgmath.h", + "time.h", + "wchar.h", + "wctype.h", + "sys/acct.h", + "sys/debugreg.h", + "sys/epoll.h", + "sys/eventfd.h", + "sys/fcntl.h", + "sys/fsuid.h", + "sys/gmon.h", + "sys/gmon_out.h", + "sys/inotify.h", + "sys/io.h", + "sys/kd.h", + "sys/kdaemon.h", + "sys/klog.h", + "sys/mount.h", + "sys/mtio.h", + "sys/pci.h", + "sys/perm.h", + "sys/personality.h", + "sys/prctl.h", + "sys/profil.h", + "sys/ptrace.h", + "sys/quota.h", + "sys/raw.h", + "sys/reboot.h", + "sys/reg.h", + "sys/sem.h", + "sys/sendfile.h", + "sys/signal.h", + "sys/signalfd.h", + "sys/socketvar.h", + "sys/soundcard.h", + "sys/statvfs.h", + "sys/swap.h", + "sys/sysctl.h", + "sys/sysinfo.h", + "sys/termios.h", + "sys/timerfd.h", + "sys/ttychars.h", + "sys/ultrasound.h", + "sys/unistd.h", + "sys/ustat.h", + "sys/vfs.h", + "sys/vlimit.h", + "sys/vt.h", + "sys/vtimes.h", + "sys/xattr.h", + "errno.h", + "mathcalls.h", + "net/ethernet.h", + "net/if_arp.h", + "net/if_ppp.h", + "net/if_slip.h", + "net/ppp_defs.h", + "net/if.h", + "net/if_packet.h", + "net/if_shaper.h", + "net/ppp-comp.h", + "net/route.h", + "netinet/ether.h", + "netinet/if_fddi.h", + "netinet/in.h ", + "netinet/ip6.h", + "netinet/udp.h", + "netinet/icmp6.h", + "netinet/if_tr.h", + "netinet/in_systm.h", + "netinet/ip_icmp.h", + "netinet/if_ether.h", + "netinet/igmp.h", + "netinet/ip.h", + "netinet/tcp.h", + "rpc/types.h", + "rpc/auth.h", + "rpc/des_crypt.h", + "rpc/pmap_prot.h", + "rpc/rpc_msg.h", + "rpc/xdr.h", + "rpc/auth_des.h", + "rpc/key_prot.h", + "rpc/pmap_rmt.h", + "rpc/svc.h", + "rpc/auth_unix.h", + "rpc/netdb.h", + "rpc/rpc.h", + "rpc/svc_auth.h", + "rpc/clnt.h", + "rpc/pmap_clnt.h", + "rpc/rpc_des.h", + "rpcsvc/bootparam.h", + "rpcsvc/nis_callback.h", + "rpcsvc/yp_prot.h", + "rpcsvc/rstat.h", + "rpcsvc/rusers.h", + "rpcsvc/spray.h", + "rpcsvc/ypupd.h", + "rpcsvc/mount.h", + "rpcsvc/nis.h", + "protocols/routed.h", + "protocols/rwhod.h", + "protocols/talkd.h", + "protocols/timed.h", + "arpa/ftp.h", + "arpa/inet.h", + "arpa/nameser.h", + "arpa/nameser_compat.h", + "arpa/telnet.h", + "arpa/tftp.h", + }; + + 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", + "-D__WORDSIZE=32", + "-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", + }; + + parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, args); + } +} diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java new file mode 100644 index 0000000000..08ce2298e6 --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java @@ -0,0 +1,499 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// +// Parses preview of VS22 and DirectX to .gdt archive files +// +// To replace existing header files and have the data type ID's synchronized +// +// Must run SynchronizeGDTCategoryPaths.java script with old and replacement GDT +// archive to synchronize upper/lower case paths +/// (only on windows archives) +// +// Then Run DataTypeArchiveTransformer in eclipse to synchronize old data types ID's +// +//@category Data Types + +import java.io.File; +import java.io.IOException; + +import ghidra.app.script.GhidraScript; +import ghidra.app.util.cparser.C.CParserUtils; +import ghidra.app.util.cparser.C.ParseException; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.FileDataTypeManager; +import ghidra.util.Msg; + +public class CreateExampleGDTArchiveScript extends GhidraScript { + + private File outputDirectory; + + // location of header files base directory + private static String headerFilePath = "/data/HeaderFiles"; + + @Override + protected void run() throws Exception { + outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir"); + + parseGDT_DirectX(); + + parseGDT_WinVS22(); + } + + private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) + throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { + DataTypeManager openTypes[] = null; + + parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, args); + } + + private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) + throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { + + String dataTypeFile = outputDir + File.separator + gdtName + ".gdt"; + + File f = getArchiveFile(dataTypeFile); + + FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); + + String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor); + + Msg.info(this, messages); + + dtMgr.save(); + dtMgr.close(); + } + + /** + * Turn string into a file, delete old archive if it exists + * + * @param dataTypeFile + * + * @return file + */ + private File getArchiveFile(String dataTypeFile) { + File f = new File(dataTypeFile); + if (f.exists()) { + f.delete(); + } + String lockFile = dataTypeFile + ".ulock"; + File lf = new File(lockFile); + if (lf.exists()) { + lf.delete(); + } + return f; + } + + + public void parseGDT_DirectX() throws Exception { + + String filenames[] = { + "SDKDDKVer.h", + "Windows.h", + "winnt.h", + + "windowsx.h", + "ddraw.h", + "d3d.h", + "dinput.h", + "mmreg.h", + "dsound.h", + }; + + String args[] = { + "-I"+headerFilePath+"/VC/VS22/10.0.190141.0", + "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um", + "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared", + "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt", + "-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.30.30705/include", + "-D_AMD64_", + "-D_M_AMD64", + "-D_M_X64", + "-D_WIN64", + "-D_WIN32", + "-v0", + }; + + parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, args); + } + + public void parseGDT_WinVS22() throws Exception { + + String filenames[] = { + "# Core necessary files", + "winapifamily.h", + "winpackagefamily.h", + "sdkddkver.h", + "sal.h", + "no_sal2.h", + "corecrt.h", + "wtypes.h", + "winnt.h", + "winternl.h", + "#ntdef.h", + + "# Common headers ", + "dos.h", + "errno.h", + "malloc.h", + "signal.h", + "stdalign.h", + "stddef.h", + "stdio.h", + "stdlib.h", + "assert.h", + "crtdbg.h", + "ctype.h", + "conio.h", + "direct.h", + "fcntl.h", + "float.h", + "fpieee.h", + "inttypes.h", + "io.h", + "locale.h", + "complex.h", + "math.h", + "mbctype.h", + "mbstring.hs", + "memory.h", + "minmax.h", + "new.h", + "process.h", + "search.h", + "share.h", + "winbase.h", + "winuser.h", + "Windows.h", + + "# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)", + "accctrl.h", + "aclapi.h", + "aclui.h", + "advapi32.h", + "adtgen.h", + "authz.h", + "azroles.h", + "bcrypt.h", + "casetup.h", + "ccgplugins.h", + "celib.h", + "ntlsa.h", + "sspi.h", + "ntsecapi.h", + "ntsecpkg.h", + "schannel.h", + "certadm.h", + "certbcli.h", + "certcli.h", + "certenroll.h", + "certexit.h", + "certif.h", + "certmod.h", + "certpol.h", + "certpoleng.h ", + "certsrv.h", + "certview.h", + "credssp.h", + "cryptdlg.h", + "cryptuiapi.h", + "cryptxml.h", + "diagnosticdataquery.h", + "diagnosticdataquerytypes.h", + "dpapi.h", + "dssec.h", + "iads.h", + "identitycommon.h", + "identityproviders.h", + "identitystore.h", + "keycredmgr.h", + "lmaccess.h", + "lsalookup.h", + "mmcobj.h", + "mscat.h", + "mssip.h", + "namedpipeapi.h", + "ncrypt.h", + "ncryptprotect.h", + "npapi.h", + "processthreadsapi.h", + "sas.h", + "scesvc.h", + "sddl.h", + "securityappcontainer.h", + "securitybaseapi.h", + "slpublic.h", + "subauth.h", + "tokenbinding.h", + "tpmsvcmgr.h", + "wincred.h", + "wincrypt.h", + "winnetwk.h", + "winreg.h", + "winsafer.h", + "winscard.h", + "winsvc.h", + "wintrust.h", + "winwlx.h", + "xenroll.h", + + "# Windows sockets", + "af_irda.h", + "in6addr.h", + "mstcpip.h", + "ws2def.h", + "winsock.h", + "winsock2.h", + "nsemail.h", + "nspapi.h", + "socketapi.h", + "# Nothing includes this; is it necessary?", + "#sporder.h", + "transportsettingcommon.h", + "ws2atm.h", + "ws2spi.h", + "mswsock.h", + "ws2tcpip.h", + "wsipv6ok.h", + "wslwlink.h", + "wsrm.h", + "mswsockdef.h", + + "# Remote Procedure Call (RPC)", + "midles.h", + "midlbase.h", + "rpc.h", + "rpcndr.h", + "rpcasync.h", + "rpcdcep.h", + "rpcnsi.h", + "rpcproxy.h", + "rpcssl.h", + + "# COM", + "accctrl.h", + "callobj.h", + "combaseapi.h", + "comcat.h", + "ctxtcall.h", + "dmerror.h", + "docobj.h", + "eventsys.h", + "guiddef.h", + "iaccess.h", + "hstring.h", + "imessagedispatcher.h", + "messagedispatherapi.h", + "objbase.h", + "objidlbase.h", + "objidl.h", + "ocidl.h", + "ole.h", + "ole2.h", + "oledlg.h", + "oleidl.h", + "roapi.h", + "rpcdce.h", + "servprov.h", + "shobjidl.h", + "txlogpub.h", + "unknwnbase.h", + "unknwn.h", + "urlmon.h", + "vbinterf.h", + "winddi.h", + "winerror.h", + "wtypesbase.h", + + "# COM+", + "comadmin.h", + "mtxdm.h", + + "# More", + "inspectable.h", + + "# Windows Internet", + "proofofpossessioncookieinfo.h", + "wininet.h", + "winineti.h", + + "# Windows HTTP Services", + "winhttp.h", + + "# Compression", + "compressapi.h", + + "# TraceLogging", + "#traceloggingactivity.h", + "#traceloggingprovider.h", + + "# Windows Error Reporting", + "errorrep.h", + "werapi.h", + + "# Windows and MEssages", + "olectl.h", + "windef.h", + "windowsx.h", + + "# Shell", + "appmgmt.h", + "appnotify.h", + "cpl.h", + "credentialprovider.h", + "dimm.h", + "imagetranscode.h", + "inputpanelconfiguration.h", + "intsafe.h", + "intshcut.h", + "mobsync.h", + "objectarray.h", + "pathcch.h", + "profinfo.h", + "propkeydef.h", + "scrnsave.h", + "shappmgr.h", + "shdeprecated.h", + "shidfact.h", + "shimgdata.h", + "shlwapi.h", + "shtypes.h", + "storageprovider.h", + "syncmgr.h", + "thumbcache.h", + "thumbnailstreamcache.h", + "tlogstg.h", + "usereng.h", + + "# Windows Controls", + "commctrl.h", + "commoncontrols.h", + "dpa_dsa.h", + "prsht.h", + "richedit.h", + "richole.h", + "shlobj_core.h", + "shlobj.h", + "#textserv.h", // C++ + "tom.h", + "uxtheme.h", + + "# Menus and other resources", + "resourceindexer.h", + "strsafe.h", + "verrsrc.h", + "winver.h", + + "# Windows Accessibility Features", + "oleacc.h", + "uiautomationcore.h", + "uiautomationclient.h", + "uiautomationcoreapi.h", + + "# Internationalization", + "datetimeapi.h", + "elscore.h", + "gb18030.h", + "imepad.h", + "imm.h", + "immdev.h", + "msime.h", + "msimeapi.h", + "muiload.h", + "spellcheck.h", + "spellcheckprovider.h", + "stringapiset.h", + "usp10.h", + "winnls.h", + + "# HTTP Server API", + "#http.h", // included by something else + + "# IP Helper", + "#icmpapi.h", // Something wrong with IP_ADDR + "ifdef.h", + "inaddr.h", + "ip2string.h", + "ipexport.h", + "iphlpapi.h", + "iprtrmib.h", + "iptypes.h", + "netioapi.h", + "nldef.h", + "tcpestats.h", + "ws2ipdef.h", + + "# Network Management", + "atacct.h", + "lmalert.h", + "lmapibuf.h", + "lmat.h", + "lmaudit.h", + "lmconfig.h", + "lmerrlog.h", + "lmjoin.h", + "lmmsg.h", + "lmremutl.h", + "lmserver.h", + "lmsvc.h", + "lmuse.h", + "lmwksta.h" + }; + + String args[] = { + "-I"+headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include", + "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/shared", + "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/ucrt", + "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/um", + "-I"+headerFilePath+"/VC/VS22/10.0.19041.0/winrt", + "-D_MSC_VER=1924", + "-D_INTEGRAL_MAX_BITS=64", + "-DWINVER=0x0a00", + "-D_WIN32_WINNT=0x0a00", + "-D_AMD64_", + "-D_M_AMD64", + "-D_M_X64", + "-D_WIN64", + "-D_WIN32", + "-D_USE_ATTRIBUTES_FOR_SAL", + "-D_CRTBLD", + "-D_OPENMP_NOFORCE_MANIFEST", + "-DSTRSAFE_LIB", + "-DSTRSAFE_LIB_IMPL", + "-DLPSKBINFO=LPARAM", + "-D_WCHAR_T_DEFINED", + "-DCONST=const", + "-D_CRT_SECURE_NO_WARNINGS", + "-D_CRT_NONSTDC_NO_DEPRECATE", + "-D_CRT_NONSTDC_NO_WARNINGS", + "-D_CRT_OBSOLETE_NO_DEPRECATE", + "-D_ALLOW_KEYWORD_MACROS", + "-D_ASSERT_OK", + "-DSTRSAFE_NO_DEPRECATE", + "-D__possibly_notnullterminated", + "-Dtype_info=\"void *\"", + "-D_ThrowInfo=ThrowInfo", + "-D__unaligned=", + "-v0", + "-D__inner_checkReturn=", + "-DWINAPI_PARTITION_APP=1", + "-DWINAPI_PARTITION_SYSTEM=1", + "-DWINAPI_PARTITION_GAMES=1", + "-DSECURITY_WIN32", + }; + + parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, args); + } +} 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 1130564c6e..a3ad438f84 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,33 +15,45 @@ */ package ghidra.app.plugin.core.cparser; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; import java.util.ArrayList; import java.util.StringTokenizer; import javax.swing.SwingUtilities; +import org.apache.commons.io.DirectoryWalker.CancelException; + import docking.ActionContext; import docking.action.DockingAction; import docking.action.MenuData; import docking.tool.ToolConstants; import docking.widgets.OptionDialog; +import docking.widgets.dialogs.MultiLineMessageDialog; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.ProgramPlugin; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.cparser.C.CParser; import ghidra.app.util.cparser.CPP.PreProcessor; -import ghidra.app.util.xml.DataTypesXmlMgr; import ghidra.framework.Application; import ghidra.framework.options.SaveState; import ghidra.framework.plugintool.PluginInfo; import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.program.database.data.ProgramDataTypeManager; -import ghidra.program.model.data.*; +import ghidra.program.model.data.BuiltInDataTypeManager; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.FileDataTypeManager; import ghidra.program.model.listing.Program; -import ghidra.util.*; +import ghidra.util.HTMLUtilities; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; //@formatter:off @@ -62,9 +74,14 @@ public class CParserPlugin extends ProgramPlugin { private ParseDialog parseDialog; private File userProfileDir; + private String parserMessages; + private String cppMessages; + final static String DESCRIPTION = "Parse C and C Header files, extracting data definitions and function signatures."; + private static final String PARSER_DEBUG_OUTFILE = "CParserPlugin.out"; + public CParserPlugin(PluginTool plugintool) { super(plugintool, false, false); createActions(); @@ -144,134 +161,6 @@ public class CParserPlugin extends ProgramPlugin { tool.showDialog(parseDialog); } - public void doCParser() { - - try { - // PreProcessor cpp = new PreProcessor("c:/Program Files/Microsoft - // Visual Studio/VC98/Include/stdio.h"); - String filename1 = "c:/Program Files/Microsoft Visual Studio/VC98/Include/windows.h"; - // String filename1 = "c:/Program Files/Microsoft Visual - // Studio/VC98/Include/stdio.h"; - // String filename1 = "c:/dummy.h"; - // String filename2 = "c:/Program Files/Microsoft Visual - // Studio/VC98/Include/winnt.h"; - String[] args = { "-Ic:/Program Files/Microsoft Visual Studio/VC98/Include/", - // "-D_DLL", - "-D_M_IX86=500", "-D_MSC_VER=9090", "-D_WIN32_WINNT=0x0400", - "-D_WIN32_WINDOWS=0x400", "-D_INTEGRAL_MAX_BITS=32", "-D_X86_", "-D_WIN32" }; - PreProcessor cpp = new PreProcessor(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - cpp.setArgs(args); - OutputStream os = null; - try { - os = new FileOutputStream("c:/tmpwindows.h.out"); - } - catch (FileNotFoundException e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); - } - PrintStream ps = new PrintStream(os); - System.setErr(ps); - System.setOut(ps); - cpp.setOutputStream(bos); - try { - cpp.parse(filename1); - } - catch (RuntimeException e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); - } - - System.out.println(bos); - - FileDataTypeManager dtMgr = - FileDataTypeManager.createFileArchive(new File("c:/parse.gdt")); - CParser cParser = new CParser(dtMgr, true, null); - ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); - cParser.parse(bis); - - try { - DataTypesXmlMgr.writeAsXMLForDebug(dtMgr, "c:/parse.xml"); - dtMgr.save(); - dtMgr.close(); - } - catch (IOException e3) { - Msg.error(this, "Unexpected Exception: " + e3.getMessage(), e3); - } - } - catch (Exception e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); - } - } - - // // Prints out all the types used in parsing the c source - // private DataTypeManager populateTypes(CParser parser) { - // DataTypeManager dtMgr = new DataTypeManagerImpl("parsed"); - // - // addTypes(dtMgr, parser.getFunctions()); - // addTypes(dtMgr, parser.getDeclarations()); - // addTypes(dtMgr, parser.getEnums()); - // addTypes(dtMgr, parser.getStructs()); - // addTypes(dtMgr, parser.getTypes()); - // - // moveTypes("Functions", dtMgr, parser.getFunctions()); - // moveTypes("Declarations", dtMgr, parser.getDeclarations()); - // moveTypes("Enums", dtMgr, parser.getEnums()); - // moveTypes("Structs", dtMgr, parser.getStructs()); - // moveTypes("Types", dtMgr, parser.getTypes()); - // - // return dtMgr; - // } - // - // private void addTypes(DataTypeManager dtMgr, Hashtable table) { - // Category rootCat = dtMgr.getRootCategory(); - // - // Enumeration enum = table.keys(); - // while (enum.hasMoreElements()) { - // String name = (String) enum.nextElement(); - // DataType dt = null; - // Object obj = table.get(name); - // if (obj instanceof DataType) { - // dt = (DataType) obj; - // } - // if (dt instanceof TypedefDataType) { - // TypedefDataType tdt = (TypedefDataType) dt; - // if (tdt instanceof Composite) { - // if (tdt.getName().equals(tdt.getBaseDataType().getName())) { - // continue; - // } - // } - // } - // if (dt != null) { - // dumpDT(name, dt); - // dt = rootCat.addDataType(dt); - // dumpDT(name, dt); - // table.put(name, dt); - // } - // } - // } - // - -// private void dumpDT(String name, DataType dt) { -// if (dt instanceof StructureDataType) { -// StructureDataType sdt = (StructureDataType) dt; -// Err.debug(this, "struct " + sdt.getName() + " " -// + sdt.getNumComponents()); -// CategoryPath cat = sdt.getCategoryPath(); -// Err.debug(this, " " -// + (cat != null ? cat.getName() : " -nocat-")); -// for (int i = 0; i < sdt.getNumComponents(); i++) { -// DataTypeComponent ndt = sdt.getComponent(i); -// Err.debug(this, " " + ndt.getFieldName() + " " -// + ndt.getLength() + " " + ndt.getOffset()); -// } -// } else if (dt instanceof TypedefDataType) { -// TypedefDataType tdt = (TypedefDataType) dt; -// Err.debug(this, "typedef " + tdt.getBaseDataType().getName() -// + " " + dt.getName()); -// } else { -// Err.debug(this, " " + dt.getName()); -// } -// } - /* * Parse into a saved data type data base file */ @@ -289,52 +178,31 @@ public class CParserPlugin extends ProgramPlugin { String[] args = parseOptions(options); DataTypeManager openDTmanagers[] = null; - DataTypeManagerService dtService = tool.getService(DataTypeManagerService.class); - if (dtService != null) { - openDTmanagers = dtService.getDataTypeManagers(); - - ArrayList list = new ArrayList<>(); - String htmlNamesList = ""; - for (int i = 0; i < openDTmanagers.length; i++) { - if (openDTmanagers[i] instanceof ProgramDataTypeManager) { - continue; - } - list.add(openDTmanagers[i]); - if (!(openDTmanagers[i] instanceof BuiltInDataTypeManager)) { - htmlNamesList += "
  • " + - HTMLUtilities.escapeHTML(openDTmanagers[i].getName()) + "
  • "; - } - } - openDTmanagers = list.toArray(new DataTypeManager[0]); - - if (openDTmanagers.length > 1 && OptionDialog.showOptionDialog( - this.parseDialog.getComponent(), "Use Open Archives?", - "The following archives are currently open: " + "" + "

    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).", - "Continue?", OptionDialog.QUESTION_MESSAGE) != OptionDialog.OPTION_ONE) { - return; - } + try { + openDTmanagers = getOpenDTMgrs(); + } catch (CancelledException exc) { + return; // parse canceled } + cppMessages = ""; PreProcessor cpp = new PreProcessor(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); + cpp.setArgs(args); PrintStream os = System.out; + String homeDir = System.getProperty("user.home"); + String fName = homeDir + File.separator + "CParserPlugin.out"; try { - String homeDir = System.getProperty("user.home"); - String fName = homeDir + File.separator + "CParserPlugin.out"; os = new PrintStream(new FileOutputStream(fName)); } catch (FileNotFoundException e2) { Msg.error(this, "Unexpected Exception: " + e2.getMessage(), e2); } - // cpp.setOutputStream(os); + PrintStream old = System.out; System.setOut(os); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); cpp.setOutputStream(bos); try { @@ -342,9 +210,14 @@ public class CParserPlugin extends ProgramPlugin { if (monitor.isCancelled()) { break; } + // any file beginning with a "#" is assumed to be a comment + if (filename.trim().startsWith("#")) { + continue; + } File file = new File(filename); - // process each header file in the directory + if (file.isDirectory()) { + // process each header file in the directory String[] children = file.list(); if (children == null) { continue; @@ -362,16 +235,15 @@ public class CParserPlugin extends ProgramPlugin { } } catch (RuntimeException re) { - Msg.error(this, re.getMessage()); os.close(); - return; + throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage()); } // process all the defines and add any that are integer values into // the Equates table - cpp.getDefinitions().populateDefineEquates(dtMgr); + cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr); - System.out.println(bos); + System.out.println(bos.toString()); System.setOut(old); os.close(); @@ -380,26 +252,134 @@ public class CParserPlugin extends ProgramPlugin { monitor.setMessage("Parsing C"); CParser cParser = new CParser(dtMgr, true, openDTmanagers); + cParser.setParseFileName(PARSER_DEBUG_OUTFILE); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); - cParser.parse(bis); + try { + parserMessages = ""; + cParser.setParseFileName(fName); + cParser.parse(bis); + } + finally { + parserMessages = cParser.getParseMessages(); + } final boolean isProgramDtMgr = (dtMgr instanceof ProgramDataTypeManager); SwingUtilities.invokeLater(() -> { + // CParserTask will show any errors + if (!cParser.didParseSucceed()) { + return; + } if (isProgramDtMgr) { - Msg.showInfo(getClass(), parseDialog.getComponent(), - "Parse Header Files Completed", "Successfully parsed header file(s).\n" + - "Check the Manage Data Types window for added data types."); + MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(), + "C-Parse of Header Files Complete", + "Successfully parsed header file(s) to Program.", + getFormattedParseMessage( + "Check the Manage Data Types window for added data types."), + MultiLineMessageDialog.INFORMATION_MESSAGE); } else { - parseDialog.setDialogText("Successfully parsed header file(s)."); + String archiveName = dtMgr.getName(); + if (dtMgr instanceof FileDataTypeManager) { + archiveName = ((FileDataTypeManager) dtMgr).getFilename(); + } + MultiLineMessageDialog.showModalMessageDialog(parseDialog.getComponent(), + "C-Parse of Header Files Complete. ", + "Successfully parsed header file(s) to Archive File: " + archiveName, + getFormattedParseMessage(null), MultiLineMessageDialog.INFORMATION_MESSAGE); } }); } } - private void parseFile(String filename, TaskMonitor monitor, PreProcessor cpp) { + /** + * Get open data type managers. + * User can Use Open managers, Select not to use, or Cancel + * + * @param openDTmanagers open mgrs, null if don't use + * @return array of open data type managers + * + * @throws CancelledException if user cancels + */ + private DataTypeManager[] getOpenDTMgrs() throws CancelledException { + DataTypeManager[] openDTmanagers = null; + + DataTypeManagerService dtService = tool.getService(DataTypeManagerService.class); + if (dtService == null) { + return openDTmanagers; + } + + openDTmanagers = dtService.getDataTypeManagers(); + + ArrayList list = new ArrayList<>(); + String htmlNamesList = ""; + for (DataTypeManager openDTmanager : openDTmanagers) { + if (openDTmanager instanceof ProgramDataTypeManager) { + continue; + } + list.add(openDTmanager); + if (!(openDTmanager instanceof BuiltInDataTypeManager)) { + htmlNamesList += + "

  • " + HTMLUtilities.escapeHTML(openDTmanager.getName()) + "
  • "; + } + } + openDTmanagers = list.toArray(new DataTypeManager[0]); + + if (openDTmanagers.length > 1) { + int result = OptionDialog.showOptionDialog( + this.parseDialog.getComponent(), "Use Open Archives?", + "The following archives are currently open: " + "" + "

    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); + if (result == OptionDialog.CANCEL_OPTION) { + throw new CancelledException("User Cancelled"); + } + if (result == OptionDialog.OPTION_TWO) { + return null; + } + } + + return openDTmanagers; + } + + public String getFormattedParseMessage(String errMsg) { + String message = ""; + + if (errMsg != null) { + message += errMsg + "\n\n"; + } + + String msg = getParseMessage(); + if (msg != null && msg.length() != 0) { + message += "CParser Messages:\n" + msg + "\n\n"; + } + + msg = getPreProcessorMessage(); + if (msg != null && msg.length() != 0) { + message += "PreProcessor Messages:\n" + getPreProcessorMessage(); + } + + return message; + } + + /** + * Get any parse messages produced by parsing good, or informational + * + * @return messages from parser + */ + public String getParseMessage() { + return parserMessages; + } + + public String getPreProcessorMessage() { + return cppMessages; + } + + private void parseFile(String filename, TaskMonitor monitor, PreProcessor cpp) + throws ghidra.app.util.cparser.CPP.ParseException { monitor.setMessage("PreProcessing " + filename); try { Msg.info(this, "parse " + filename); @@ -408,6 +388,11 @@ public class CParserPlugin extends ProgramPlugin { catch (Throwable e) { Msg.error(this, "Parsing file :" + filename); Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); + + throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage()); + } + finally { + cppMessages += cpp.getParseMessages(); } } 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 f7fdc10f9b..c5a2f720e6 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 @@ -19,6 +19,7 @@ import java.io.File; import javax.swing.SwingUtilities; +import docking.widgets.dialogs.MultiLineMessageDialog; import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.FileDataTypeManager; import ghidra.util.Msg; @@ -57,6 +58,15 @@ class CParserTask extends Task { this.dtMgr = dataTypeManager; } + private String getFirstMessageLine(final String errMsg) { + int indexOf = errMsg.indexOf('\n'); + String msg = errMsg; + if (indexOf > 0) { + msg = msg.substring(0, indexOf); + } + return msg; + } + @Override public void run(TaskMonitor monitor) { DataTypeManager fileDtMgr = null; @@ -73,16 +83,6 @@ class CParserTask extends Task { try { ((FileDataTypeManager) dtMgr).save(); dtMgr.close(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - Msg.showInfo( - getClass(), plugin.getDialog().getComponent(), - "Created Archive File", "Successfully created archive file\n" + - ((FileDataTypeManager) dtMgr).getFilename()); - } - - }); } catch (DuplicateFileException e) { Msg.showError(this, plugin.getDialog().getComponent(), "Error During Save", @@ -102,8 +102,12 @@ class CParserTask extends Task { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - Msg.showInfo(getClass(), - plugin.getDialog().getComponent(), "Parse Errors", "File was not created due to parse errors."); + MultiLineMessageDialog.showModalMessageDialog( + plugin.getDialog().getComponent(), "Parse Errors", + "File was not created due to parse errors: " + + ((FileDataTypeManager) dtMgr).getFilename(), + plugin.getFormattedParseMessage(null), + MultiLineMessageDialog.INFORMATION_MESSAGE); } }); } @@ -115,8 +119,10 @@ class CParserTask extends Task { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - Msg.showInfo(getClass(), - plugin.getDialog().getComponent(), "Parse Errors", errMsg); + String msg = getFirstMessageLine(errMsg); + MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(), + "Parse Errors", msg, plugin.getFormattedParseMessage(errMsg), + MultiLineMessageDialog.ERROR_MESSAGE); } }); } @@ -126,14 +132,22 @@ class CParserTask extends Task { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - Msg.showInfo(getClass(), - plugin.getDialog().getComponent(), "Parse Errors", errMsg); + String msg = getFirstMessageLine(errMsg); + MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(), + "PreProcessor Parse Errors", msg, plugin.getFormattedParseMessage(errMsg), + MultiLineMessageDialog.ERROR_MESSAGE); } }); } catch (Exception e) { + final String errMsg = e.getMessage(); + String msg = getFirstMessageLine(errMsg); Msg.showError(this, plugin.getDialog().getComponent(), "Error During Parse", - "Parse header files failed", e); + "Parse header files failed" + "\n\nParser Messages:\n" + plugin.getParseMessage(), + e); + MultiLineMessageDialog.showModalMessageDialog(plugin.getDialog().getComponent(), + "Error During Parse", msg, plugin.getFormattedParseMessage(errMsg), + MultiLineMessageDialog.ERROR_MESSAGE); } finally { if (fileDtMgr != null) { 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 0354cad3e8..fbfbe7f3f7 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 @@ -15,14 +15,35 @@ */ package ghidra.app.util.cparser.C; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; import java.util.Arrays; +import java.util.Iterator; import ghidra.app.services.DataTypeManagerService; +import ghidra.app.util.cparser.CPP.PreProcessor; import ghidra.framework.plugintool.ServiceProvider; -import ghidra.program.model.data.*; +import ghidra.program.database.ProgramDB; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.FileDataTypeManager; +import ghidra.program.model.data.FunctionDefinitionDataType; +import ghidra.program.model.lang.CompilerSpec; +import ghidra.program.model.lang.CompilerSpecID; +import ghidra.program.model.lang.Language; +import ghidra.program.model.lang.LanguageID; import ghidra.program.model.listing.Program; -import ghidra.util.*; +import ghidra.program.util.DefaultLanguageService; +import ghidra.util.HTMLUtilities; +import ghidra.util.InvalidNameException; +import ghidra.util.Msg; import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; public class CParserUtils { @@ -171,6 +192,7 @@ public class CParserUtils { DataType dt = null; try { // parse the signature + parser.setParseFileName("input line"); dt = parser.parse(replacedText + ";"); if (!(dt instanceof FunctionDefinitionDataType)) { @@ -207,6 +229,330 @@ public class CParserUtils { return null; } + /** + * Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager + * with in the provided dataFileName. + * + * Note: Using another open archive while parsing will cause: + * - a dependence on the other archive + * - any missing data types while parsing are supplied if present from an openDTMgr + * - after parsing all data types parsed with an equivalent data type in any openDTMgr + * replaced by the data type from the openDTMgr + * + * NOTE: This will only occur if the data type from the openDTMgr's is equivalent. + * + * @param openDTMgrs array of datatypes managers to use for undefined data types + * + * @param filenames names of files in order to parse, could include strings with + * "#" at start, which are ignored as comments + * @param args arguments for parsing, "-D=", "-I" + * + * @param dataFileName name of data type archive file (include the .gdt extension) + * + * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing + * + * @param monitor used to cancel or provide results + * + * @return the data types in the ghidra .gdt archive file + * + * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing + * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing + * @throws IOException if there io are errors saving the archive + * + */ + + public static FileDataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName, + PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, + ghidra.app.util.cparser.CPP.ParseException, IOException { + File file = new File(dataFileName); + FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file); + + parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, cpp, monitor); + + dtMgr.save(); + return dtMgr; + } + + + /** + * Parse a set of C Header files and associated parsing arguments, returning a new File Data TypeManager + * with in the provided dataFileName. + * + * Note: Using another open archive while parsing will cause: + * - a dependence on the other archive + * - any missing data types while parsing are supplied if present from an openDTMgr + * - after parsing all data types parsed with an equivalent data type in any openDTMgr + * replaced by the data type from the openDTMgr + * + * NOTE: This will only occur if the data type from the openDTMgr's is equivalent. + * + * NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof() + * + * @param openDTMgrs array of datatypes managers to use for undefined data types + * + * @param filenames names of files in order to parse, could include strings with + * "#" at start, which are ignored as comments + * @param args arguments for parsing, "-D=", "-I" + * + * @param dataFileName name of data type archive file (include the .gdt extension) + * + * @param languageId language identication to use for data type organization definitions (int, long, ptr size) + * @param compileSpecId compiler specification to use for parsing + * + * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing + * + * @param monitor used to cancel or provide results + * + * @return the data types in the ghidra .gdt archive file + * + * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing + * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing + * @throws IOException if there io are errors saving the archive + * + */ + public static DataTypeManager parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], String dataFileName, + String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, + ghidra.app.util.cparser.CPP.ParseException, IOException { + + File file = new File(dataFileName); + FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(file); + + String messages = parseHeaderFiles(openDTMgrs, filenames, args, dtMgr, languageId, compileSpecId, cpp, monitor); + Msg.info(CParserUtils.class, messages); + + dtMgr.save(); + + return dtMgr; + } + + + /** + * Parse a set of C Header files and associated parsing arguments, data types are added to the provided + * DTMgr. + * + * Note: Using another open archive while parsing will cause: + * - a dependence on the other archive + * - any missing data types while parsing are supplied if present from an openDTMgr + * - after parsing all data types parsed with an equivalent data type in any openDTMgr + * replaced by the data type from the openDTMgr + * + * NOTE: This will only occur if the data type from the openDTMgr's is equivalent. + * + * NOTE: Providing the correct languageID and compilerSpec is very important for header files that might use sizeof() + * @param openDTMgrs array of datatypes managers to use for undefined data types + * + * @param filenames names of files in order to parse, could include strings with + * "#" at start, which are ignored as comments + * @param args arguments for parsing, "-D=", "-I" + * + * @param existingDTMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr + * + * @param languageId language identication to use for data type organization definitions (int, long, ptr size) + * @param compileSpecId compiler specification to use for parsing + * + * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing + * + * @param monitor used to cancel or provide results + * + * @return a formatted string of any output from pre processor parsing or C parsing + * + * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing + * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing + * @throws IOException if there io are errors saving the archive + * + */ + public static String parseHeaderFiles(DataTypeManager openDTMgrs[], String[] filenames, String args[], DataTypeManager existingDTMgr, + String languageId, String compileSpecId, PreProcessor cpp, TaskMonitor monitor) throws ghidra.app.util.cparser.C.ParseException, + ghidra.app.util.cparser.CPP.ParseException, IOException { + + Language language = DefaultLanguageService.getLanguageService().getLanguage(new LanguageID(languageId)); + CompilerSpec compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compileSpecId)); + + String dtmgrName = existingDTMgr.getName(); + if (existingDTMgr instanceof FileDataTypeManager) { + dtmgrName = ((FileDataTypeManager) existingDTMgr).getPath(); + } + + ProgramDB program = new ProgramDB(dtmgrName, language, compilerSpec, CParserUtils.class); + try { + DataTypeManager programDtm = program.getDataTypeManager(); + String messages = parseHeaderFiles(openDTMgrs, filenames, args, programDtm, cpp, monitor); + + int txId = existingDTMgr.startTransaction("Add Types"); + try { + Iterator allDataTypes = programDtm.getAllDataTypes(); + while (allDataTypes.hasNext()) { + existingDTMgr.resolve(allDataTypes.next(), null); + } + } + finally { + existingDTMgr.endTransaction(txId, true); + } + + return messages; + } + finally { + program.release(CParserUtils.class); + } + } + + /** + * Parse a set of C Header files and associated parsing arguments, data types are added to the provided + * DTMgr. + * + * Note: Using another open archive while parsing will cause: + * - a dependence on the other archive + * - any missing data types while parsing are supplied if present from an openDTMgr + * - after parsing all data types parsed with an equivalent data type in any openDTMgr + * replaced by the data type from the openDTMgr + * + * NOTE: This will only occur if the data type from the openDTMgr's is equivalent. + * + * NOTE: The DTMgr should have been created with the correct data type organization from a language/compilerspec + * if there could be variants in datatype defintions when using the generic data type manager data organization + * for example in a generic FileDataTypeManager int and long are size 4. This will change in the future, + * but with the current implementation, beware! + * + * @param openDTMgrs array of datatypes managers to use for undefined data types + * + * @param filenames names of files in order to parse, could include strings with + * "#" at start, which are ignored as comments + * @param args arguments for parsing, "-D=", "-I" + * + * @param dtMgr datatypes will be populated into this provided DTMgr, can pass Program or File DTMgr + * + * @param cpp provided PreProcessor, useful if parsed Define's need to be examined after parsing + * + * @param monitor used to cancel or provide results + * + * @return a formatted string of any output from pre processor parsing or C parsing + * + * @throws ghidra.app.util.cparser.C.ParseException for catastrophic errors in C parsing + * @throws ghidra.app.util.cparser.CPP.ParseException for catastrophic errors in Preprocessor macro parsing + * @throws IOException if there io are errors saving the archive + + */ + public static String parseHeaderFiles(DataTypeManager openDTmanagers[], String[] filenames, String args[], + DataTypeManager dtMgr, PreProcessor cpp, TaskMonitor monitor) + throws ghidra.app.util.cparser.C.ParseException, ghidra.app.util.cparser.CPP.ParseException { + + String cppMessages = ""; + if (cpp == null) { + cpp = new PreProcessor(); + } + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + cpp.setArgs(args); + + PrintStream os = System.out; + String fName = dtMgr.getName().replace(".gdt","")+"_CParser.out"; + try { + os = new PrintStream(new FileOutputStream(fName)); + } catch (FileNotFoundException e2) { + Msg.error(CParserUtils.class, "Unexpected Exception: " + e2.getMessage(), e2); + } + // cpp.setOutputStream(os); + PrintStream old = System.out; + System.setOut(os); + + cpp.setOutputStream(bos); + + try { + for (String filename : filenames) { + if (monitor.isCancelled()) { + break; + } + if (filename.trim().startsWith("#")) { + continue; + } + File file = new File(filename); + // process each header file in the directory + if (file.isDirectory()) { + String[] children = file.list(); + if (children == null) { + continue; + } + for (String element : children) { + File child = new File(file.getAbsolutePath() + "/" + element); + if (child.getName().endsWith(".h")) { + parseFile(child.getAbsolutePath(), monitor, cpp); + } + } + } else { + parseFile(filename, monitor, cpp); + } + } + } catch (RuntimeException re) { + Msg.info(cpp, cpp.getParseMessages()); + throw new ghidra.app.util.cparser.CPP.ParseException(re.getMessage()); + } finally { + System.out.println(bos); + os.flush(); + os.close(); + System.setOut(old); + + } + + cppMessages = cpp.getParseMessages(); + + // process all the defines and add any that are integer values into + // the Equates table + cpp.getDefinitions().populateDefineEquates(openDTmanagers, dtMgr); + + String parserMessages = ""; + if (!monitor.isCancelled()) { + monitor.setMessage("Parsing C"); + + CParser cParser = new CParser(dtMgr, true, openDTmanagers); + ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); + try { + parserMessages = ""; + cParser.setParseFileName(fName); + cParser.parse(bis); + } finally { + parserMessages = cParser.getParseMessages(); + } + } + + return getFormattedParseMessage(parserMessages, cppMessages, null); + } + + private static String parseFile(String filename, TaskMonitor monitor, PreProcessor cpp) + throws ghidra.app.util.cparser.CPP.ParseException { + monitor.setMessage("PreProcessing " + filename); + try { + Msg.info(CParserUtils.class, "parse " + filename); + cpp.parse(filename); + } + catch (Throwable e) { + Msg.error(CParserUtils.class, "Parsing file :" + filename); + Msg.error(CParserUtils.class, "Unexpected Exception: " + e.getMessage(), e); + + throw new ghidra.app.util.cparser.CPP.ParseException(e.getMessage()); + } + + return cpp.getParseMessages(); + } + + private static String getFormattedParseMessage(String parseMessage, String cppMessage, String errMsg) { + String message = ""; + + if (errMsg != null) { + message += errMsg + "\n\n"; + } + + String msg = parseMessage; + if (msg != null && msg.length() != 0) { + message += "CParser Messages:\n" + msg + "\n\n"; + } + + msg = cppMessage; + if (msg != null && msg.length() != 0) { + message += "PreProcessor Messages:\n" + msg; + } + + return message; + } + private static DataTypeManager[] getDataTypeManagers(DataTypeManagerService service) { if (service == null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/Declaration.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/Declaration.java index bbd3979ca4..a93b06e43b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/Declaration.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/Declaration.java @@ -16,13 +16,18 @@ */ package ghidra.app.util.cparser.C; -import ghidra.program.model.data.*; +import java.util.ArrayList; +import java.util.List; + +import ghidra.program.model.data.AbstractIntegerDataType; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.PointerDataType; /** * Container for information about a Declaration that is accumulated during parsing. */ public class Declaration { - private int qualifier; + private ArrayList qualifierList; private DataType dt; private String name; private String comment; @@ -35,6 +40,9 @@ public class Declaration { public Declaration(Declaration dec) { this(); this.dt = dec.getDataType(); + if (dec.qualifierList != null) { + this.qualifierList = new ArrayList(dec.qualifierList); + } } public Declaration(Declaration dec, String name) throws ParseException { @@ -65,6 +73,9 @@ public class Declaration { } this.name = subDecl.name; this.comment = subDecl.comment; + if (subDecl.qualifierList != null) { + this.qualifierList = new ArrayList(subDecl.qualifierList); + } } public Declaration(DataType dt, String name) { @@ -84,8 +95,11 @@ public class Declaration { return comment; } - public int getQualifier() { - return qualifier; + public List getQualifiers() { + if (qualifierList == null) { + return List.of(); + } + return qualifierList; } public DataType getDataType() { @@ -103,8 +117,21 @@ public class Declaration { comment = string; } - public void setQualifier(int qualifier) { - this.qualifier = qualifier; + public void addQualifier(int qualifier) { + if (qualifierList == null) { + qualifierList = new ArrayList(); + } + qualifierList.add(qualifier); + } + + public void addQualifiers(Declaration dec) { + if (dec.qualifierList == null) { + return; + } + if (qualifierList == null) { + qualifierList = new ArrayList(); + } + qualifierList.addAll(dec.qualifierList); } public void setDataType(DataType type) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java index 83b0573965..d7dbf630b3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java @@ -27,6 +27,8 @@ import ghidra.util.Msg; * */ public class DefineTable { + private static final String VARARG_ELLIPSIS = "..."; + private static final int ARBITRARY_MAX_REPLACEMENTS = 900000; // Hastable for storing #defs @@ -35,6 +37,7 @@ public class DefineTable { // Hastable for storing #define macro args (substitution list) Hashtable> args = new Hashtable>(); + // Multi-level hashtable with different types of keys and values Hashtable lookupTable = new Hashtable(); private final static String VALUE = "value"; @@ -74,7 +77,7 @@ public class DefineTable { while (findTable != null && pos < buf.length()) { char ch = buf.charAt(pos++); - Character chObj = new Character(ch); + Character chObj = ch; findTable = (Hashtable) findTable.get(chObj); @@ -106,7 +109,7 @@ public class DefineTable { int len = string.length(); while (pos < len) { char ch = string.charAt(pos++); - chObj = new Character(ch); + chObj = ch; Hashtable node = (Hashtable) findTable.get(chObj); @@ -168,7 +171,7 @@ public class DefineTable { int len = string.length(); while (pos < len) { char ch = string.charAt(pos++); - chObj = new Character(ch); + chObj = Character.valueOf(ch); findTable = (Hashtable) findTable.get(chObj); @@ -281,13 +284,13 @@ public class DefineTable { while (pos < buf.length() && replaceCount < ARBITRARY_MAX_REPLACEMENTS) { // clear list of used macros when move past replacement area if (pos == lastReplPos) { - sublist = new ArrayList (); // ok to clear list of used macro names + sublist = new ArrayList(); // ok to clear list of used macro names } String defName = getDefineAt(buf, pos); if (shouldReplace(buf, defName, pos)) { // stop recursion on the same replacement string int replPos = replace(buf, defName, pos, sublist); - + if (replPos == -1) { // if no replacement string, move on pos++; @@ -417,12 +420,16 @@ public class DefineTable { int index = 0; int pos = 0; StringBuffer argsfound = new StringBuffer(); + boolean isVarArg = false; + boolean hadVarArgs = false; while (pos < parms.length() || index < argv.size()) { String argValue = ""; + int origPos = pos; if (pos < parms.length()) { argValue = getParams(new StringBuffer(parms), pos, ','); } pos += argValue.length() + 1; + if (index >= argv.size()) { Msg.error(this, "Define parameter mismatch for macro " + defName + "(" + parms + ")" + @@ -430,12 +437,27 @@ public class DefineTable { argValue + " args processed : " + argsfound); return replString; } + + // Handle "..." varargs + // if last argument is ellipsis, then is varargs, replace the rest of the params String curArgName = argv.elementAt(index).image; + if (index == argv.size()-1 && VARARG_ELLIPSIS.equals(curArgName)) { + isVarArg = true; + // Replace __VA_ARGS__ with the rest of params + curArgName = "__VA_ARGS__"; + argValue = getParams(new StringBuffer(parms), origPos, '\0'); + pos += argValue.length() + 1; + } index++; argValue = argValue.trim(); argsfound.append(argValue); argsfound.append(", "); + // isVarArg, and had variable arguments + if (isVarArg && argValue.length() != 0) { + hadVarArgs = true; + } + int curpos = -1; // find argname in substString // note begin and end position @@ -461,7 +483,7 @@ public class DefineTable { continue; } - Integer begin = new Integer(curpos); + Integer begin = Integer.valueOf(curpos); int insertLoc = 0; for (; insertLoc < beginPos.size(); insertLoc++) { Integer loc = beginPos.get(insertLoc); @@ -471,7 +493,7 @@ public class DefineTable { } beginPos.add(insertLoc, begin); - endPos.add(insertLoc, new Integer(curpos + curArgName.length())); + endPos.add(insertLoc, Integer.valueOf(curpos + curArgName.length())); subValue.add(insertLoc, argValue); } while (curpos >= 0); @@ -490,10 +512,49 @@ public class DefineTable { startpos = end; } buf.append(substString.substring(startpos)); + + // Handle __VA_OPT__() + // if varargs and no more params, replace with "" + // if varargs and has vararg params, replace with + if (isVarArg) { + replace_VaOpt(buf, hadVarArgs); + } + substString = buf.toString(); return substString; } + /** + * Replace __VA_OPT__(arg) in buf with either the arg to __VA_OPT__ + * if there were any VARARGS, otherwise with "" + * @param buf string buffer to replace __VA_OPT__(value) within + * @param hadVarArgs + */ + private void replace_VaOpt(StringBuffer buf, boolean hadVarArgs) { + int optIdx = buf.indexOf("__VA_OPT__"); + if (optIdx < 0) { + return; + } + + int lparen = buf.indexOf("(", optIdx+1); + if (lparen < 0) { + return; + } + + int rparen = buf.indexOf(")",lparen+1); + if (rparen < 0) { + return; + } + + // get in between string. + String replarg = buf.substring(lparen+1, rparen); + if (hadVarArgs) { + buf.replace(optIdx, rparen+1, replarg); + } else { + buf.replace(optIdx, rparen+1, ""); + } + } + /** * @param buf the buffer containing the parameters * @param start the starting index of the parameters in the buffer @@ -507,7 +568,7 @@ public class DefineTable { if (pos >= len) { return ""; } - + char ch = buf.charAt(pos); char lastChar = 0; boolean hitQuote = false; @@ -521,11 +582,11 @@ public class DefineTable { if (ch == '\'' && lastChar != '\\') { hitTick = !hitTick; } - if (!(hitQuote||hitTick) && ch == endChar && depth == 0) { + if (!(hitQuote || hitTick) && ch == endChar && depth == 0) { pos--; break; } - if (!(hitQuote||hitTick) && ch == ')') { + if (!(hitQuote || hitTick) && ch == ')') { depth--; if (depth == 0 && endChar == 0) { break; @@ -536,7 +597,7 @@ public class DefineTable { break; } } - if (!(hitQuote||hitTick) && ch == '(') { + if (!(hitQuote || hitTick) && ch == '(') { depth++; } lastChar = ch; @@ -611,24 +672,19 @@ public class DefineTable { * */ - public void populateDefineEquates(DataTypeManager dtMgr) { + public void populateDefineEquates(DataTypeManager openDTMgrs[], DataTypeManager dtMgr) { int transactionID = dtMgr.startTransaction("Add Equates"); Iterator iter = getDefineNames(); while (iter.hasNext()) { String defName = iter.next(); - // don't worry about macros - if (isArg(defName)) { - //System.err.println(defName + " = " + getValue(defName)); + + String strValue = expandDefine(defName); + if (strValue == null) { + // couldn't expand, must have been a macro continue; } - - // check if this is a numeric expression that could be simplified - // - String strValue = getValue(defName); - String strExpanded = expand(strValue, true); - strValue = strExpanded; - + // strip off any casting/parentheses strValue = stripCast(strValue); @@ -649,30 +705,74 @@ public class DefineTable { value = lvalue.longValue(); - String enumName = "define_" + defName; - - EnumDataType enuum = new EnumDataType(enumName, 8); - enuum.add(defName, value); - - String defPath = getDefinitionPath(defName); - String currentCategoryName = getFileName(defPath); - CategoryPath path = getCategory(currentCategoryName); - path = new CategoryPath(path, "defines"); - enuum.setCategoryPath(path); - - dtMgr.addDataType(enuum, DataTypeConflictHandler.DEFAULT_HANDLER); + populateDefineEquate(openDTMgrs, dtMgr, "defines", "define_", defName, value); } dtMgr.endTransaction(transactionID, true); } + public void populateDefineEquate(DataTypeManager openDTMgrs[], DataTypeManager dtMgr, String category, String prefix, String defName, long value) { + String enumName = prefix + defName; + + EnumDataType enuum = new EnumDataType(enumName, 8); + enuum.add(defName, value); + + String defPath = getDefinitionPath(defName); + String currentCategoryName = getFileName(defPath); + CategoryPath path = getCategory(currentCategoryName); + path = new CategoryPath(path, category); + enuum.setCategoryPath(path); + + DataType dt = resolveDataType(openDTMgrs, path, enuum); + + dtMgr.addDataType(dt, DataTypeConflictHandler.DEFAULT_HANDLER); + } + + private DataType resolveDataType(DataTypeManager openDTMgrs[], CategoryPath path, DataType dt) { + if (openDTMgrs == null) { + return dt; + } + // If the exact data type exists in any open DTMgr, use the open DTmgr type + // instead + + for (int i = 0; i < openDTMgrs.length; i++) { + // look for the data type by name + // equivalent, return it + // look for the data type by category + // equivalent, return it + DataType candidateDT = openDTMgrs[i].getDataType(dt.getCategoryPath(), dt.getName()); + + if (candidateDT != null && candidateDT.isEquivalent(candidateDT)) { + return candidateDT; + } + } + + return dt; + } + + public String expandDefine(String defName) { + // don't worry about macros + if (isArg(defName)) { + //System.err.println(defName + " = " + getValue(defName)); + return null; + } + + // check if this is a numeric expression that could be simplified + // + String strValue = getValue(defName); + String strExpanded = expand(strValue, true); + strValue = strExpanded; + + return strValue; + } + /** * Parse a C format integer value * * @param strValue value to parse * @return long value if parsable as an integer, null otherwise */ - private static Long getCValue(String strValue) { + public static Long getCValue(String strValue) { try { int start = 0; int radix = 10; @@ -719,6 +819,9 @@ public class DefineTable { * Get the filename portion of a path */ private static String getFileName(String path) { + if (path == null) { + return null; + } int slashpos = path.lastIndexOf('/'); if (slashpos < 0) { slashpos = path.lastIndexOf('\\'); 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 6023243bbc..9fe9ad8993 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 @@ -57,13 +57,13 @@ options { // Methods and class variables should not be static to allow multiple parsers to be in use. // This is at the expense of some speed. - STATIC= false; - - // Don't interpret unicode escape sequences, they can appear in embedded text in macros and strings, + STATIC= false; + + // Don't interpret unicode escape sequences, they can appear in embedded text in macros and strings, // which if interpreted can mess up parsing if they are pre-interpreted by the input stream. - JAVA_UNICODE_ESCAPE = false; - - // However, if the file has real embedded unicode characters, such as some microsoft header files, + JAVA_UNICODE_ESCAPE = false; + + // However, if the file has real embedded unicode characters, such as some microsoft header files, // they need to be read correctly by the parser. An example is the embedded code at the beginning // of a file that states that it is in unicode. The characters might be all ascii, which for parsing // purposes is most likely the case. @@ -96,9 +96,11 @@ import java.util.*; @SuppressWarnings("all") // ignore warnings from generated code public class CParser { + private static String DEFAULT_PARSER_OUTPUT_FILENAME = "CParser.out"; + // Map for storing typedef types private Map types = new HashMap(); - private Map structs = new HashMap(); + private Map composites = new HashMap(); private Map functions = new HashMap(); private Map enums = new HashMap(); @@ -106,7 +108,7 @@ public class CParser { private Map internalTypes = new HashMap(); - private DataType lastDataType = null; + private DataType lastDataType = DefaultDataType.dataType; private boolean storeNewDT = true; private String possiblyUndefinedType = null; @@ -119,7 +121,7 @@ public class CParser { private String headerFileName= null; // Current header file from #line token private int headerFileLine = 1; // Current line number from #line token private int headerFileLineOffset= 0; // offset into parse stream of last #line token - private String currentCategoryName = ""; // Current category + private String currentCategoryName = ""; // Current category, ROOT category private final static String ANONYMOUS_STRUCT_PREFIX = "_struct_"; private final static String ANONYMOUS_UNION_PREFIX = "_union_"; @@ -130,15 +132,30 @@ public class CParser { // Stack for putting defined data types on private Stack dataTypeStack = new Stack(); + + private StringBuilder parseMessages = new StringBuilder(); + + // true if parse was successful + private boolean parseSuccess = false; // packing size for structures private int packSize = 0; Stack packStack = new Stack(); Stack packStackID = new Stack(); + String parseFileName = DEFAULT_PARSER_OUTPUT_FILENAME; + + public void setParseFileName(String fName) { + parseFileName = fName; + } + private CategoryPath getCurrentCategoryPath() { return getCategory(currentCategoryName); } + + private CategoryPath getCurrentCategoryPath(String subCatName) { + return getCategory(currentCategoryName).extend(subCatName); + } private CategoryPath getCategory(String catName) { CategoryPath rootCat = CategoryPath.ROOT; @@ -173,39 +190,45 @@ public class CParser { private DataType addTypedef(String type, DataType dt) { if (type == null || dt == null) { - System.err.println("Problem with type " + type + " : " + dt); + addNearParseMessage("Problem with type " + type + " : " + dt); return dt; } + if (type.equals(dt.getName())) { - if (dt instanceof Composite || dt instanceof Enum) { // || dt instanceof FunctionDefinitionDataType - return dt; + // these already get a typedef elsewhere + if (dt instanceof Composite) { + return addDef(composites,type,dt); + } + if (dt instanceof Enum) { + return addDef(enums,type,dt); } } - // if typedefing an anonymous structure, rename structure/union + // if typedef-ing an anonymous structure, rename structure/union if (dt instanceof Composite) { if (dt.getName().startsWith(ANONYMOUS_STRUCT_PREFIX) || dt.getName().startsWith(ANONYMOUS_UNION_PREFIX)) { - try { - dt = renameDef(structs, dt, type); - addDef(structs, type, dt); - return dt; - } catch (InvalidNameException e) { - // handled below - } catch (DuplicateNameException e) { - // handled below - } - } + try { + composites.remove(dt.getName()); + dt.setName(type); + dt = addDef(composites, type, dt); + return dt; + } catch (InvalidNameException e) { + // handled below + } catch (DuplicateNameException e) { + // handled below + } + } } - dt = new TypedefDataType(CategoryPath.ROOT, type, dt, dtMgr); + dt = new TypedefDataType(getCurrentCategoryPath(), type, dt, dtMgr); dt = addDef(types, type, dt); return dt; } private DataType getType(String type) { Object obj; - obj = structs.get(type); + obj = composites.get(type); if (obj instanceof DataType) { return (DataType) obj; } @@ -219,26 +242,27 @@ public class CParser { } // only return a function as a type IF we are defining a typedef - if (typedefParsingStack.size() > 0) { + boolean functionsOK = typedefParsingStack.size() > 0; + + if (functionsOK) { obj = functions.get(type); if (obj instanceof DataType) { return (DataType) obj; } } - if (!storeNewDT) { - - DataType dt = findDataType(type); - if (dt != null) { - return dt; - } - } + + DataType dt = findDataType(type); + if (dt != null && (functionsOK || !(dt instanceof FunctionDefinition))) { + return dt; + } // check the BuiltinTypeManager - BuiltInDataTypeManager builtInMgr = BuiltInDataTypeManager.getDataTypeManager(); - DataType dt = findDataType(builtInMgr, type); - if (dt != null) { - return dt; - } + // Don't check, left in in case basic types like uint64_t are in builtins + // BuiltInDataTypeManager builtInMgr = BuiltInDataTypeManager.getDataTypeManager(); + // DataType bdt = findDataType(builtInMgr, type); + // if (bdt != null) { + // return bdt; + // } possiblyUndefinedType = type; return null; @@ -276,117 +300,163 @@ public class CParser { List list = new ArrayList(); dtMgr.findDataTypes(dataTypeString, list); - for (int i = 0; i < subDTMgrs.length; i++) { - DataTypeManager dtm = subDTMgrs[i]; - dtm.findDataTypes(dataTypeString, list); - } return list; } // Add a typedef type to those already defined private DataType addDef(Map table, String name, DataType dt) { - CategoryPath cat = getCurrentCategoryPath(); - try { - dt.setCategoryPath(cat); - } catch (DuplicateNameException e) { - DataType existing = this.dtMgr.getDataType(cat, name); - if (!dt.isEquivalent(existing)) { - e.printStackTrace(); - } + // System.out.println("** addDef " + name + " = " + (dt != null ? dt.getName() : " - no type -") ); + + DataType existingDT = table.get(name); + if (existingDT != null && dt.isEquivalent(existingDT)) { + return existingDT; } - dt = resolveDataType(table, name, dt); - lastDataType = dt; + // If the exact data type exists in any open DTMgr, use the open DTmgr type + // instead + dt = findEquivalentInOpenDTMgrs(name, dt); + + if (storeNewDT) { + try { + dt = dtMgr.addDataType(dt, DataTypeConflictHandler.REPLACE_HANDLER); + } catch (Exception e) { + addNearParseMessage("Problem adding DataType " + dt.getDisplayName() + "\u005cn" + " " + e.getMessage()); + } + } else { + dt = dt.clone(dtMgr); + } + + table.put(name, dt); + lastDataType = dt; + return dt; } - private DataType resolveDataType(Map table, String name, DataType dt) { - DataType existingDT = table.get(name); - if (existingDT!=null && existingDT != dt && dt.isEquivalent(existingDT)) { - //Msg.info(this, "TYPE " + name + " ALREADY IN THERE"); - return existingDT; - } - + /** + * Try to find this named data type in any open data type managers. + * + * @param name name of datatype + * @param dt datatype to find + * @return Original dt if none found, dt in other archive if found and equivalent + */ + private DataType findEquivalentInOpenDTMgrs(String name, DataType dt) { ArrayList list = new ArrayList(); - for (int i = 0; i < subDTMgrs.length; i++) { + boolean foundDT = false; + for (int i = 0; !foundDT && i < subDTMgrs.length; i++) { // look for the data type by name // equivalent, return it // look for the data type by category // equivalent, return it subDTMgrs[i].findDataTypes(name, list); - + Iterator iter = list.iterator(); while (iter.hasNext()) { DataType dataType = iter.next(); if (dataType.isEquivalent(dt)) { - table.put(name, dataType); return dataType; } } } - - if (storeNewDT) { - try { - dt = dtMgr.addDataType(dt, DataTypeConflictHandler.REPLACE_HANDLER); - } catch (Exception e) { - System.err.println("Problem adding DataType " + dt.getDisplayName()); - System.err.println(" " + e.getMessage()); - } - } - - table.put(name, dt); return dt; } // resolve data types using data type manager so that data organization is considered // private DataType resolveInternal(DataType datatype) { - DataType existingDT = internalTypes.get(datatype.getName()); - if (existingDT != null) { - return existingDT; - } - existingDT = datatype.copy(dtMgr); - - internalTypes.put(datatype.getName(), existingDT); - - return existingDT; - } - - - // rename a data type in the given table - private DataType renameDef(Map table, DataType dt, String newName) throws InvalidNameException, DuplicateNameException { - table.remove(dt.getName()); - dt.setName(newName); - table.put(newName, dt); - - return dt; - } - - - // Add a typedef type to those already defined - private DataType addDef(String subCategory, Map table, String name, DataType dt) { - // System.out.println("** addDef " + name + " = " + (dt != null ? dt.getName() : " - no type -") ); - - CategoryPath subCat = getCurrentCategoryPath(); - subCat = new CategoryPath(subCat, subCategory); - try { - dt.setCategoryPath(subCat); - } catch (DuplicateNameException e) { - DataType existing = this.dtMgr.getDataType(subCat, name); - if (!dt.isEquivalent(existing)) { - e.printStackTrace(); - } + DataType existingDT = internalTypes.get(datatype.getName()); + if (existingDT != null) { + return existingDT; } + existingDT = datatype.clone(dtMgr); - dt = resolveDataType(table, name, dt); - lastDataType = dt; - - return dt; + internalTypes.put(datatype.getName(), existingDT); + + return existingDT; } - private DataType getStructDef(String name) { - DataType dt = getDef(structs, name); + + /** + * Define a forward declared composite + * + * @param name name of composite + * @param comp composite most likely empty + * @return composite with a name, possibly already declared + * + * @throws InvalidNameException bad name + * @throws DuplicateNameException duplicate name + */ + private Composite defineForwardDeclaredComposite(Token symName, Composite comp) + throws InvalidNameException, DuplicateNameException { + DataType dt = findAnyComposite(symName.image); + if (dt instanceof Composite) { + comp = (Composite) dt; + } + if (dt == null) { + comp.setName(symName.image); + comp = (Composite) addDef(composites, symName.image, comp); + } + return comp; + } + + /** + * Define a named composite + * + * @param name name of the composite + * @param parentName possible parent name + * @param comp the composite components + * @return a new composite with the correct name and components + * + * @throws InvalidNameException invalid name + * @throws DuplicateNameException duplicate name + */ + private Composite defineNamedComposite(Token name, Token parentName, Composite comp) + throws InvalidNameException, DuplicateNameException { + + String nameStr = name.image; + + DataType dt = findAnyComposite(nameStr); + + // if existing composite is found + boolean hasNoComponents = false; + boolean hasSameSourceArchive = true; + if (dt != null) { + Composite dtComp = (Composite) dt; + + hasNoComponents = (dtComp.getNumDefinedComponents() == 0 ? true : false); + + hasSameSourceArchive = dt.getSourceArchive().equals(dtMgr.getLocalSourceArchive()); + } + + // make sure comp is a Composite, if existing dt is empty, in same category and archive + if (comp instanceof Composite && hasNoComponents && hasSameSourceArchive) { + // existing composite was an empty placeholder + // replace the internals of the exisint datatype with the composite components + Composite dtcomp = (Composite) dt; + dtcomp.replaceWith(comp); + comp = dtcomp; + } else { + + // check if a parent name was specified, and if so insert it + // only single parent supported currently + if (parentName != null) { + DataType superDt = findAnyComposite(parentName.image); + if (superDt == null) { + addNearParseMessage("Parent structure " + parentName.image + " for " + nameStr + " undefined "); + } else { + // surgically add parent to top of structure + comp.insert(0, superDt); + } + } + comp.setName(nameStr); + comp = (Composite) addDef(composites, nameStr, comp); + } + + return comp; + } + + private DataType findAnyComposite(String name) { + DataType dt = getDef(composites, name); if (dt != null) { return dt; } @@ -402,17 +472,6 @@ public class CParser { } } - // check the BuiltinTypeManager - BuiltInDataTypeManager builtInMgr = BuiltInDataTypeManager.getDataTypeManager(); - ArrayList list = new ArrayList(); - builtInMgr.findDataTypes(name, list); - for (int i = 0; i < list.size(); i++) { - dt = list.get(i); - if (dt instanceof Composite) { - return dt; - } - } - return null; } @@ -431,26 +490,12 @@ public class CParser { } } } - - // check the BuiltinTypeManager - BuiltInDataTypeManager builtInMgr = BuiltInDataTypeManager.getDataTypeManager(); - ArrayList list = new ArrayList(); - builtInMgr.findDataTypes(name, list); - for (int i = 0; i < list.size(); i++) { - dt = list.get(i); - if (dt instanceof Enum) { - return dt; - } - } + return null; } private DataType getDef(Map table, String name) { - Object obj = table.get(name); - if (!(obj instanceof DataType)) { - return null; - } - return (DataType) obj; + return table.get(name); } // Prints out all the types used in parsing the c source @@ -465,14 +510,36 @@ public class CParser { System.out.println("************** ENUMS *****************"); printTable(enums); System.out.println("************** STRUCTS *****************"); - printTable(structs); + printTable(composites); + } + + private void addNearParseMessage(String message) { + parseMessages.append(message + "\n"); + parseMessages.append(" In file " + this.headerFileName + "\n"); + parseMessages.append( + " Near datatype: " + (lastDataType == null ? "- none -" : lastDataType.getName()) + "\n"); + + int endLine = token_source.input_stream.line; + long subLinenum = ((endLine - headerFileLineOffset) + headerFileLine); + + if (headerFileName != null) { + parseMessages.append(" in " + headerFileName + " near line " + subLinenum + "\n"); + } + } + + public String getParseMessages() { + return parseMessages.toString(); + } + + public boolean didParseSucceed() { + return parseSuccess; } private FunctionDefinitionDataType newAnonymousFunction(FunctionDefinitionDataType currentFuncDT) { if (currentFuncDT != null) { return currentFuncDT; } - return new FunctionDefinitionDataType(CategoryPath.ROOT, ANONYMOUS_FUNC_PREFIX+func_cnt++, dtMgr); + return new FunctionDefinitionDataType(getCurrentCategoryPath("functions"), ANONYMOUS_FUNC_PREFIX+func_cnt++, dtMgr); } private void checkReturnDataType(DataType retDT) throws ParseException { @@ -488,55 +555,116 @@ public class CParser { throw new ParseException("'"+retDT.getName()+"'" + " is not fixed length. Function return must be fixed length data type or void."); } } - - private int getConstantValue (Object obj, int defaultValue) { - int value = defaultValue; - - if (obj == null) { - return defaultValue; - } - - if (obj instanceof Integer) { - value = ((Integer)obj).intValue(); - } - else if (obj instanceof Long) { - value = (int) ((Long) obj).longValue(); - } - else if (obj instanceof Character) { - value = ((Character) obj).charValue(); + + /** + * Add a definition to the correct category for funcDT, and replace any use of funcDT in Declaration + * + * @param dec Declaration data type change to replace any use of funcDT with new addDef + * @param funcDT function to put in the correct category + */ + private void defineAndReplaceFunction(Declaration dec, FunctionDefinitionDataType funcDT) { + DataType newDT = addDef(functions, dec.getName(), funcDT); + DataType newDecDT = newDT; + DataType repDT = dec.getDataType(); + DataType origDT = repDT; + // shove the data type into any pointer definition. + while (repDT != null) { + if (repDT instanceof Pointer) { + PointerDataType ptDT = (PointerDataType) repDT; + if (ptDT.getDataType() instanceof FunctionDefinition) { + ptDT.dataTypeReplaced(ptDT.getDataType(), newDT); + newDecDT = origDT; + break; + } + repDT = ptDT.getDataType(); + } else if (repDT instanceof Array) { + ArrayDataType arrDT = (ArrayDataType) repDT; + if (arrDT.getDataType() instanceof FunctionDefinition) { + arrDT.dataTypeReplaced(arrDT.getDataType(), newDT); + newDecDT = origDT; + break; + } + repDT = arrDT.getDataType(); + } else { + break; + } + } + dec.setDataType(newDecDT); + } + + /** + * Apply any accumulated function Qualifiers to functionDT from Declaration + * @param dec Declaration + * @param funcDT function data type to qualify + */ + private void applyFunctionQualifiers(Declaration dec, FunctionDefinitionDataType funcDT) { + List qualifierList = dec.getQualifiers(); + if (qualifierList.contains(NORETURN) ) { + // TODO: set no return on function + } + for (Integer qualifier : qualifierList) { + switch (qualifier) { + case CDECL: + funcDT.setGenericCallingConvention(GenericCallingConvention.cdecl); + break; + case STDCALL: + funcDT.setGenericCallingConvention(GenericCallingConvention.stdcall); + break; + case FASTCALL: + funcDT.setGenericCallingConvention(GenericCallingConvention.fastcall); + break; + } } - return value; } - private void pushPack(Token iD, int packingSize) { - packStack.push(packingSize); - String name = ""; - if (iD != null) { - name = iD.image; - } - packStackID.push(name); - } + private Integer getConstantValue (Object obj, int defaultValue) { + int value = defaultValue; + + if (obj == null) { + return defaultValue; + } + + if (obj instanceof Integer) { + value = ((Integer)obj).intValue(); + } + else if (obj instanceof Long) { + value = (int) ((Long) obj).longValue(); + } + else if (obj instanceof Character) { + value = ((Character) obj).charValue(); + } + return value; + } + + private void pushPack(Token iD, int packingSize) { + packStack.push(packingSize); + String name = ""; + if (iD != null) { + name = iD.image; + } + packStackID.push(name); + } - private int popPack(Token iD) { - if (packStack.size() == 0) { - return packSize; - } - String name = ""; - if (iD != null) { - name = iD.image; - } - - // keep poping looking for ID, stop when find it - int popVal = packSize; - do { - String ID = packStackID.pop(); - popVal = packStack.pop(); - if (name.equals(ID)) { - break; - } - } while (packStack.size() > 0); - return popVal; - } + private int popPack(Token iD) { + if (packStack.size() == 0) { + return packSize; + } + String name = ""; + if (iD != null) { + name = iD.image; + } + + // keep poping looking for ID, stop when find it + int popVal = packSize; + do { + String ID = packStackID.pop(); + popVal = packStack.pop(); + if (name.equals(ID)) { + break; + } + } while (packStack.size() > 0); + return popVal; + } private void printTable(Map table) { @@ -553,79 +681,79 @@ public class CParser { } Object computeBinaryValue(Object obj1, Token operation, Object obj2) { - if (!(obj1 instanceof Long && obj2 instanceof Long)) { - return null; - } - Long val1 = (Long) obj1; - Long val2 = (Long) obj2; - - switch(operation.image) { - case "<<": - return val1 << val2; - case ">>": - return val1 >> val2; - case "+": - return val1 + val2; - case "-": - return val1 - val2; - case "*": - return val1 * val2; - case "/": - return val1 / val2; - case "%": - return val1 % val2; - case "|": - return val1 | val2; - case "&": - return val1 & val2; - case "^": - return val1 ^ val2; - case "==": - return (val1 == val2 ? 1 : 0); - case "!=": - return (val1 != val2 ? 1 : 0); - case "<": - return (val1 < val2 ? 1 : 0); - case ">": - return (val1 > val2 ? 1 : 0); - case "<=": - return (val1 <= val2 ? 1 : 0); - case ">=": - return (val1 >= val2 ? 1 : 0); - case "&&": - return ((val1 != 0 && val2 != 0) ? 1 : 0); - case "||": - return ((val1 != 0 || val2 != 0) ? 1 : 0); - } - return null; + if (!(obj1 instanceof Long && obj2 instanceof Long)) { + return null; + } + Long val1 = (Long) obj1; + Long val2 = (Long) obj2; + + switch(operation.image) { + case "<<": + return val1 << val2; + case ">>": + return val1 >> val2; + case "+": + return val1 + val2; + case "-": + return val1 - val2; + case "*": + return val1 * val2; + case "/": + return val1 / val2; + case "%": + return val1 % val2; + case "|": + return val1 | val2; + case "&": + return val1 & val2; + case "^": + return val1 ^ val2; + case "==": + return (val1 == val2 ? 1 : 0); + case "!=": + return (val1 != val2 ? 1 : 0); + case "<": + return (val1 < val2 ? 1 : 0); + case ">": + return (val1 > val2 ? 1 : 0); + case "<=": + return (val1 <= val2 ? 1 : 0); + case ">=": + return (val1 >= val2 ? 1 : 0); + case "&&": + return ((val1 != 0 && val2 != 0) ? 1 : 0); + case "||": + return ((val1 != 0 || val2 != 0) ? 1 : 0); + } + return null; } Object computeUnaryValue(Object obj, Token operation) { - if (!(obj instanceof Long)) { - return null; - } - Long val = (Long) obj; - - switch(operation.image) { - case "+": - return val; - case "-": - return -val; - case "~": - return ~val; - case "!": - return (val != 0 ? 0 : 1); - } - return null; + if (!(obj instanceof Long)) { + return null; + } + Long val = (Long) obj; + + switch(operation.image) { + case "+": + return val; + case "-": + return -val; + case "~": + return ~val; + case "!": + return (val != 0 ? 0 : 1); + } + return null; } Object computeTernaryValue(Object objTest, Object objTrue, Object objFalse) { - if (!(objTest instanceof Long)) { - return null; - } + if (!(objTest instanceof Long)) { + return null; + } - Long testValue = (Long) objTest; - return (testValue != 0 ? objTrue : objFalse); + Long testValue = (Long) objTest; + return (testValue != 0 ? objTrue : objFalse); } @@ -673,12 +801,12 @@ public class CParser { } /** - * Get structure definitions + * Get composite definitions * - * @return Structure definitions + * @return Composite (structure/union) definitions */ - public Map getStructs() { - return structs; + public Map getComposites() { + return composites; } /** @@ -705,9 +833,12 @@ public class CParser { ReInit(fis); int transactionID = -1; String parseMessage; + + parseSuccess = false; try { transactionID = dtMgr.startTransaction("Parsing"); TranslationUnit(); + parseSuccess = true; } catch (ParseException e) { if (headerFileName == null) { throw e; @@ -725,7 +856,7 @@ public class CParser { parseMessage += "Possibly Undefined : " + possiblyUndefinedType + "\n"; parseMessage += " Last Valid Datatype: " + (lastDataType == null ? "- none -" : lastDataType.getDisplayName()) + "\n"; - parseMessage += " Check around CParserPlugin.out around line: " + parseMessage += " Check around " + parseFileName + " around line: " + this.jj_input_stream.getBeginLine() + "\n"; ParseException parseException = new ParseException(parseMessage); parseException.currentToken = e.currentToken; @@ -741,7 +872,7 @@ public class CParser { } parseMessage += " Last Valid Datatype: " + (lastDataType == null ? "- none -" : lastDataType.getDisplayName()) + "\n"; - parseMessage += " Check around CParserPlugin.out around line: " + parseMessage += " Check around " + parseFileName + " around line: " + this.jj_input_stream.getBeginLine() + "\n"; Msg.warn(this, e, e); ParseException parseException = new ParseException(parseMessage); @@ -756,7 +887,7 @@ public class CParser { } parseMessage += " Last Valid Datatype: " + (lastDataType == null ? "- none -" : lastDataType.getDisplayName()) + "\n"; - parseMessage += " Check around CParserPlugin.out around line: " + parseMessage += " Check around " + parseFileName + " around line: " + this.jj_input_stream.getBeginLine() + "\n"; Msg.warn(this, e, e); throw new ParseException(parseMessage); @@ -836,583 +967,606 @@ SKIP : { "\ufeff" // BOM character at beginning of file | - " " - | - "\f" - | - "\t" - | - "\n" - | - "\r" - | - "\\" - | - < - "//" - ( ~[ "\n", "\r" ] )* - ( "\n" | "\r" | "\r\n" ) - > - | - < - "/*" - ( ~[ "*" ] )* - "*" - ( - "*" - | - ~[ "*", "/" ] ( ~[ "*" ] )* "*" - )* - "/" - > + " " + | + "\f" + | + "\t" + | + "\n" + | + "\r" + | + "\\" + | + < + "//" + ( ~[ "\n", "\r" ] )* + ( "\n" | "\r" | "\r\n" ) + > + | + < + "/*" + ( ~[ "*" ] )* + "*" + ( + "*" + | + ~[ "*", "/" ] ( ~[ "*" ] )* "*" + )* + "/" + > } TOKEN : { - ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? - | - ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? - | - ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? - > - | - <#DECIMAL_LITERAL : [ "1"-"9" ] ( [ "0"-"9" ] )*> - | - <#HEX_LITERAL : "0" [ "x", "X" ] ( [ "0"-"9", "a"-"f", "A"-"F" ] )+> - | - <#OCTAL_LITERAL : "0" ( [ "0"-"7" ] )*> - | - )? ( [ "f", "F", "d", "D" ] )? - | - "." ( [ "0"-"9" ] )+ ( )? ( [ "f", "F", "d", "D" ] )? - | - ( [ "0"-"9" ] )+ ( [ "f", "F", "d", "D" ] )? - | - ( [ "0"-"9" ] )+ ( )? [ "f", "F", "d", "D" ] - > - | - <#EXPONENT : [ "e", "E" ] ( [ "+", "-" ] )? ( [ "0"-"9" ] )+> - | - - | - + ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? ("i")? ( ["0"-"9"] )* + | + ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? ("i")? ( ["0"-"9"] )* + | + ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? ("i")? ( ["0"-"9"] )* + > + | + <#DECIMAL_LITERAL : [ "1"-"9" ] ( [ "0"-"9" ] )*> + | + <#HEX_LITERAL : "0" [ "x", "X" ] ( [ "0"-"9", "a"-"f", "A"-"F" ] )+> + | + <#OCTAL_LITERAL : "0" ( [ "0"-"7" ] )*> + | + )? ( [ "f", "F", "d", "D" ] )? + | + "." ( [ "0"-"9" ] )+ ( )? ( [ "f", "F", "d", "D" ] )? + | + ( [ "0"-"9" ] )+ ( [ "f", "F", "d", "D" ] )? + | + ( [ "0"-"9" ] )+ ( )? [ "f", "F", "d", "D" ] + > + | + <#EXPONENT : [ "e", "E" ] ( [ "+", "-" ] )? ( [ "0"-"9" ] )+> + | + + | + } TOKEN : { - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - : PRAGMALINE - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - - | - : OBJC - | - : OBJC - | - : LINEBLOCK - | - : LINEBLOCK + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + : PRAGMALINE + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + + | + : OBJC + | + : OBJC + | + : LINEBLOCK + | + : LINEBLOCK } TOKEN : { - ( | )*> - | - <#LETTER : [ "$", "A"-"Z", "_", "a"-"z" ]> - | - <#DIGIT : [ "0"-"9" ]> + ( | )*> + | + <#LETTER : [ "$", "A"-"Z", "_", "a"-"z" ]> + | + <#DIGIT : [ "0"-"9" ]> } SKIP: { - " " - | - "\t" + " " + | + "\t" } TOKEN : { - : ASMBLOCK - | - : ASMBLOCK - | - : DEFAULT + : ASMBLOCK + | + : ASMBLOCK + | + : DEFAULT } SKIP: { - " " - | - "\f" - | - "\t" - | - ":" + " " + | + "\f" + | + "\t" + | + ":" } TOKEN: { - :DEFAULT - | - :LINEBLOCK + :DEFAULT + | + :LINEBLOCK } SKIP: { - " " - | - "\f" - | - "\t" - | - "\n" : DEFAULT - | - "\r" : DEFAULT - | - ";" : DEFAULT - | - < - "//" - ( ~[ "\n", "\r" ] )* - > - | - < - "/*" - ( ~[ "*" ] )* - "*" - ( - "*" - | - ~[ "*", "/" ] ( ~[ "*" ] )* "*" - )* - "/" - > + " " + | + "\f" + | + "\t" + | + "\n" : DEFAULT + | + "\r" : DEFAULT + | + ";" : DEFAULT + | + < + "//" + ( ~[ "\n", "\r" ] )* + > + | + < + "/*" + ( ~[ "*" ] )* + "*" + ( + "*" + | + ~[ "*", "/" ] ( ~[ "*" ] )* "*" + )* + "/" + > } TOKEN: { - ( | )*> - | - <#PLETTER : [ "$", "A"-"Z", "_", "a"-"z" ]> - | - <#PDIGIT : [ "0"-"9" ]> - | - { parenNesting++; } - | - { parenNesting--; if (parenNesting == 0) SwitchTo(DEFAULT); } - | - - | - - | - - | - ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? - | - ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? - | - ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? - > - | - <#PDECIMAL_LITERAL : [ "1"-"9" ] ( [ "0"-"9" ] )*> - | - <#PHEX_LITERAL : "0" [ "x", "X" ] ( [ "0"-"9", "a"-"f", "A"-"F" ] )+> - | - <#POCTAL_LITERAL : "0" ( [ "0"-"7" ] )*> - | - + ( | )*> + | + <#PLETTER : [ "$", "A"-"Z", "_", "a"-"z", ".", "#" ]> + | + <#PDIGIT : [ "0"-"9" ]> + | + { parenNesting++; } + | + { parenNesting--; if (parenNesting == 0) SwitchTo(DEFAULT); } + | + + | + + | + + | + + | + + | + ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? + | + ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? + | + ( "ull" | "ULL" | "ul" | "UL" | "ll" | "LL" | "l" | "L" | "U" | "u")? + > + | + <#PDECIMAL_LITERAL : [ "1"-"9" ] ( [ "0"-"9" ] )*> + | + <#PHEX_LITERAL : "0" [ "x", "X" ] ( [ "0"-"9", "a"-"f", "A"-"F" ] )+> + | + <#POCTAL_LITERAL : "0" ( [ "0"-"7" ] )*> + | + } SKIP: { - " " - | - "\f" - | - "\t" - | - "\n" : OBJC2 - | - "\r" : OBJC2 + " " + | + "\f" + | + "\t" + | + "\n" : OBJC2 + | + "\r" : OBJC2 } TOKEN: { - : OBJC - | - | )+> : OBJC - | - <#OBJC_LETTER : [ "$", "A"-"Z", "_", "a"-"z" ]> - | - <#OBJC_DIGIT : [ "0"-"9" ]> - | - :DEFAULT + : OBJC + | + | )+> : OBJC + | + <#OBJC_LETTER : [ "$", "A"-"Z", "_", "a"-"z" ]> + | + <#OBJC_DIGIT : [ "0"-"9" ]> + | + :DEFAULT } SKIP: { - " " - | - "\f" - | - "\t" - | - "\n" - | - "\r" - | - "@private" - | - "@protected" - | - "@property" - | - "@optional" - | - "@required" + " " + | + "\f" + | + "\t" + | + "\n" + | + "\r" + | + "@private" + | + "@protected" + | + "@property" + | + "@optional" + | + "@required" } TOKEN: { - : OBJC2 - | - :DEFAULT + : OBJC2 + | + :DEFAULT } //jjt SimpleNode TranslationUnit() #TranslationUnit : {} void TranslationUnit() : {} { - ( ExternalDeclaration() )+ - { - //jjt return jjtThis; - } + ( ExternalDeclaration() )+ + { + //jjt return jjtThis; + } } void ExternalDeclaration() : {} { - ( - LOOKAHEAD(FunctionDefinition() ) - FunctionDefinition() - | -// FunctionDefinition() -// | - Declaration() - | - PragmaSpec() - | - LineDef() - | - ";" - ) - { - typedefParsingStack.clear(); - } + ( + LOOKAHEAD(FunctionDefinition() ) + FunctionDefinition() + | +// FunctionDefinition() +// | + Declaration() + | + PragmaSpec() + | + StaticAssert() + | + LineDef() + | + ";" + ) + { + typedefParsingStack.clear(); + } } void LineDef() : { - Token lineTok, fileTok; + Token lineTok, fileTok; } { - ( | ) ( lineTok= ) ( fileTok= ) [ ()+ ] - { - headerFileName= fileTok.image.substring(1, fileTok.image.length() - 1); - headerFileLine= Integer.parseInt(lineTok.image); - headerFileLineOffset= lineTok.beginLine; - currentCategoryName = getFileName(headerFileName); - } + ( | ) ( lineTok= ) ( fileTok= ) [ ()+ ] + { + headerFileName= fileTok.image.substring(1, fileTok.image.length() - 1); + headerFileLine= Integer.parseInt(lineTok.image); + headerFileLineOffset= lineTok.beginLine; + currentCategoryName = getFileName(headerFileName); + } } DataType ObjcDef() : { - Token nameTok; + Token nameTok; } { - ( nameTok= ) ( | | )* ( | ) - { - return addTypedef(nameTok.image, resolveInternal(VoidDataType.dataType)); - } + ( nameTok= ) ( | | )* ( | ) + { + return addTypedef(nameTok.image, resolveInternal(VoidDataType.dataType)); + } } void FunctionDefinition() : { - Declaration retDT = new Declaration(); - Declaration dec = null; + Declaration retDT = new Declaration(); + Declaration dec = null; } { - [ - LOOKAHEAD(DeclarationSpecifiers(retDT)) - retDT = DeclarationSpecifiers(retDT) - ] - {typedefParsingStack.push(Boolean.FALSE);} - dec= Declarator(retDT, null) [ DeclarationList() ] {typedefParsingStack.pop();} CompoundStatement() - { - if (dec.getDataType() instanceof FunctionDefinition) { - addDef("functions", functions, dec.getName(), dec.getDataType()); - } - } + [ + LOOKAHEAD(DeclarationSpecifiers(retDT)) + retDT = DeclarationSpecifiers(retDT) + ] + {typedefParsingStack.push(Boolean.FALSE);} + dec= Declarator(retDT, null) [ DeclarationList() ] {typedefParsingStack.pop();} CompoundStatement() + { + if (dec.getDataType() instanceof FunctionDefinition) { + addDef(functions, dec.getName(), dec.getDataType()); + } + } } Declaration Declaration() : { - Declaration dec = new Declaration(); - DataType dt = null; + Declaration dec = new Declaration(); + DataType dt = null; } { ( - dec = DeclarationSpecifiers(dec) [ InitDeclaratorList(dec) ] ";" - | - ( | ) ( dt = ObjcDef() ) { - dec.setDataType(dt); - } - ) - { - return dec; - } + dec = DeclarationSpecifiers(dec) [ InitDeclaratorList(dec) ] ";" + | + ( | ) ( dt = ObjcDef() ) { + dec.setDataType(dt); + } + ) + { + return dec; + } } void DeclarationList() : {} { - ( - LOOKAHEAD(Declaration()) - Declaration() - )+ + ( + LOOKAHEAD(Declaration()) + Declaration() + )+ } Declaration DeclarationSpecifiers(Declaration specDT) : { - Declaration typeDT= null; + Declaration typeDT= null; } { - ( - specDT = StorageClassSpecifier(specDT) - [ -// LOOKAHEAD(DeclarationSpecifiers(specDT)) - specDT= DeclarationSpecifiers(specDT) - ] - | - specDT = BuiltInDeclarationSpecifier(specDT) - [ - LOOKAHEAD(TypeQualifierList(specDT)) - specDT = TypeQualifierList(specDT) - ] - | - specDT = TypeSpecifier(specDT) - [ + ( + specDT = StorageClassSpecifier(specDT) + [ +// LOOKAHEAD(DeclarationSpecifiers(specDT)) + specDT= DeclarationSpecifiers(specDT) + ] + | + specDT = BuiltInDeclarationSpecifier(specDT) + [ + LOOKAHEAD(TypeQualifierList(specDT)) + specDT = TypeQualifierList(specDT) + ] + | + specDT = TypeSpecifier(specDT) + [ // I don't think this does anything useful. Look into removing it. - LOOKAHEAD(DeclarationSpecifiers(specDT) , { specDT.getDataType() == null } ) -// LOOKAHEAD(DeclarationSpecifiers() -// , { (typeDT == null || -// (!typeDT.getName().equals(getToken(1).image) && !isType(getToken(1).image))) } + LOOKAHEAD(DeclarationSpecifiers(specDT) , { specDT.getDataType() == null } ) +// LOOKAHEAD(DeclarationSpecifiers() +// , { (typeDT == null || +// (!typeDT.getName().equals(getToken(1).image) && !isType(getToken(1).image))) } // ) - specDT = DeclarationSpecifiers(specDT) - ] - | - specDT = TypeQualifier(specDT) - [ - LOOKAHEAD(DeclarationSpecifiers(specDT)) - specDT = DeclarationSpecifiers(specDT) - ] - ) - [ specDT = TypeQualifier(specDT) ] - { - if (specDT == null) { - specDT = new Declaration(typeDT); - } - return specDT; - } + specDT = DeclarationSpecifiers(specDT) + ] + | + specDT = TypeQualifier(specDT) + [ + LOOKAHEAD(DeclarationSpecifiers(specDT)) + specDT = DeclarationSpecifiers(specDT) + ] + ) + [ LOOKAHEAD(TypeQualifier(specDT)) + specDT = TypeQualifier(specDT) ] + { + if (specDT == null) { + specDT = new Declaration(typeDT); + } + return specDT; + } } Declaration StorageClassSpecifier(Declaration specDT) : {} { // TODO: might want to set a storage classifier on DECL - ( - - | - - | - - | - [ ] - | - - { - // System.out.println("TYPEDEF! " + typedefParsingStack.size()); - typedefParsingStack.push(Boolean.TRUE); - } - ) - { - return specDT; - } + ( + + | + + | + + | + + | + + | + [ ] + | + + { + // System.out.println("TYPEDEF! " + typedefParsingStack.size()); + typedefParsingStack.push(Boolean.TRUE); + } + ) + { + return specDT; + } } @@ -1420,200 +1574,220 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : { DataType dt; } { - ( - { dec.setDataType(resolveInternal(VoidDataType.dataType)); } - | - { dt = dec.getDataType(); - if (dt != null) { - if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) { - dt = resolveInternal(UnsignedCharDataType.dataType); - } else if (dt == resolveInternal(IntegerDataType.dataType)) { - dt = resolveInternal(CharDataType.dataType); - } else { - throw new ParseException("Bad datatype " + dt + " char"); - } - } - else { - dt = resolveInternal(CharDataType.dataType); - } - dec.setDataType(dt); - } - | - { dec.setDataType(resolveInternal(WideCharDataType.dataType)); } - | - { dt = dec.getDataType(); - if (dt == null) { - dt = resolveInternal(ShortDataType.dataType); - } else if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) { - dt = resolveInternal(UnsignedShortDataType.dataType); - } else if (dt == resolveInternal(IntegerDataType.dataType)) { - dt = resolveInternal(ShortDataType.dataType); - } else { - throw new ParseException("Bad datatype " + dt + " short"); - } - dec.setDataType(dt); - } - [ - LOOKAHEAD(BuiltInDeclarationSpecifier(dec)) - dec = BuiltInDeclarationSpecifier(dec) - ] - | - { dt = dec.getDataType(); - if (dt == null ) { - dec.setDataType(resolveInternal(IntegerDataType.dataType)); - } - } - | - { dt = dec.getDataType(); - if ( dt == null) { - dt = resolveInternal(LongDataType.dataType); - } else if ( dt == resolveInternal(UnsignedIntegerDataType.dataType)) { - dt = resolveInternal(UnsignedLongDataType.dataType); - } else if (dt == resolveInternal(IntegerDataType.dataType)) { - dt = resolveInternal(LongDataType.dataType); - } else if (dt == resolveInternal(LongDataType.dataType)) { - dt = resolveInternal(LongLongDataType.dataType); - } else if (dt == resolveInternal(UnsignedLongDataType.dataType)) { - dt = resolveInternal(UnsignedLongLongDataType.dataType); - } else { - throw new ParseException("Bad datatype " + dt + " long"); - } - dec.setDataType(dt); - } - [ - LOOKAHEAD(BuiltInDeclarationSpecifier(dec)) - dec = BuiltInDeclarationSpecifier(dec) - ] - | - { dt = dec.getDataType(); - if ( dt == null) { - dt = resolveInternal(FloatDataType.dataType); - } else if ( dt == resolveInternal(LongDataType.dataType)) { - dt = resolveInternal(DoubleDataType.dataType); - } else { - throw new ParseException("Bad datatype " + dt + " long"); - } - dec.setDataType(dt); - } - | - { dec.setDataType(resolveInternal(DoubleDataType.dataType)); } - | - { dt = dec.getDataType(); - if ( dt == null) { - dt = resolveInternal(IntegerDataType.dataType); - } else { - // data type already set, don't do anything? - dt = dt; - } - dec.setDataType(dt); - } - - [ - LOOKAHEAD(BuiltInDeclarationSpecifier()) - dec = BuiltInDeclarationSpecifier(dec) - ] - | - { dt = dec.getDataType(); - if ( dt == null) { - dt = resolveInternal(UnsignedIntegerDataType.dataType); - } else if (dt == resolveInternal(ShortDataType.dataType)) { - dt = resolveInternal(UnsignedShortDataType.dataType); - } else if (dt == resolveInternal(LongDataType.dataType)) { - dt = resolveInternal(UnsignedLongDataType.dataType); - } else if (dt == resolveInternal(LongLongDataType.dataType)) { - dt = resolveInternal(UnsignedLongLongDataType.dataType); - } else { - throw new ParseException("Bad datatype " + dt + " unsigned"); - } - dec.setDataType(dt); - } - [ - LOOKAHEAD(BuiltInDeclarationSpecifier()) - dec = BuiltInDeclarationSpecifier(dec) - ] - | - { dec.setDataType(resolveInternal(SignedByteDataType.dataType)); } - | - { dec.setDataType(resolveInternal(ShortDataType.dataType)); } - | - { dec.setDataType(resolveInternal(IntegerDataType.dataType)); } - | - { dec.setDataType(resolveInternal(LongLongDataType.dataType)); } - ) - { - return dec; - } + ( + { dec.setDataType(resolveInternal(VoidDataType.dataType)); } + | + { dt = dec.getDataType(); + if (dt != null) { + if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) { + dt = resolveInternal(UnsignedCharDataType.dataType); + } else if (dt == resolveInternal(IntegerDataType.dataType)) { + dt = resolveInternal(CharDataType.dataType); + } else { + throw new ParseException("Bad datatype " + dt + " char"); + } + } + else { + dt = resolveInternal(CharDataType.dataType); + } + dec.setDataType(dt); + } + | + { dec.setDataType(resolveInternal(WideCharDataType.dataType)); } + | + { dt = dec.getDataType(); + if (dt == null) { + dt = resolveInternal(ShortDataType.dataType); + } else if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) { + dt = resolveInternal(UnsignedShortDataType.dataType); + } else if (dt == resolveInternal(IntegerDataType.dataType)) { + dt = resolveInternal(ShortDataType.dataType); + } else { + throw new ParseException("Bad datatype " + dt + " short"); + } + dec.setDataType(dt); + } + [ + LOOKAHEAD(BuiltInDeclarationSpecifier(dec)) + dec = BuiltInDeclarationSpecifier(dec) + ] + | + { dt = dec.getDataType(); + if (dt == null ) { + dec.setDataType(resolveInternal(IntegerDataType.dataType)); + } + } + | + { dt = dec.getDataType(); + if ( dt == null) { + dt = resolveInternal(LongDataType.dataType); + } else if ( dt == resolveInternal(UnsignedIntegerDataType.dataType)) { + dt = resolveInternal(UnsignedLongDataType.dataType); + } else if (dt == resolveInternal(IntegerDataType.dataType)) { + dt = resolveInternal(LongDataType.dataType); + } else if (dt == resolveInternal(LongDataType.dataType)) { + dt = resolveInternal(LongLongDataType.dataType); + } else if (dt == resolveInternal(UnsignedLongDataType.dataType)) { + dt = resolveInternal(UnsignedLongLongDataType.dataType); + } else { + throw new ParseException("Bad datatype " + dt + " long"); + } + dec.setDataType(dt); + } + [ + LOOKAHEAD(BuiltInDeclarationSpecifier(dec)) + dec = BuiltInDeclarationSpecifier(dec) + ] + | + { dt = dec.getDataType(); + if ( dt == null) { + dt = resolveInternal(FloatDataType.dataType); + } else if ( dt == resolveInternal(LongDataType.dataType)) { + dt = resolveInternal(DoubleDataType.dataType); + } else { + throw new ParseException("Bad datatype " + dt + " long"); + } + dec.setDataType(dt); + } + | + { dec.setDataType(resolveInternal(DoubleDataType.dataType)); } + | + { dt = dec.getDataType(); + if ( dt == null) { + dt = resolveInternal(IntegerDataType.dataType); + } else { + // data type already set, don't do anything? + dt = dt; + } + dec.setDataType(dt); + } + + [ + LOOKAHEAD(BuiltInDeclarationSpecifier()) + dec = BuiltInDeclarationSpecifier(dec) + ] + | + { dt = dec.getDataType(); + if ( dt == null) { + dt = resolveInternal(UnsignedIntegerDataType.dataType); + } else if (dt == resolveInternal(ShortDataType.dataType)) { + dt = resolveInternal(UnsignedShortDataType.dataType); + } else if (dt == resolveInternal(LongDataType.dataType)) { + dt = resolveInternal(UnsignedLongDataType.dataType); + } else if (dt == resolveInternal(LongLongDataType.dataType)) { + dt = resolveInternal(UnsignedLongLongDataType.dataType); + } else { + throw new ParseException("Bad datatype " + dt + " unsigned"); + } + dec.setDataType(dt); + } + [ + LOOKAHEAD(BuiltInDeclarationSpecifier()) + dec = BuiltInDeclarationSpecifier(dec) + ] + | + { dec.setDataType(resolveInternal(SignedByteDataType.dataType)); } + | + { dec.setDataType(resolveInternal(ShortDataType.dataType)); } + | + { dec.setDataType(resolveInternal(IntegerDataType.dataType)); } + | + { dec.setDataType(resolveInternal(LongLongDataType.dataType)); } + | + { dec.setDataType(resolveInternal(BooleanDataType.dataType)); } + ) + { + return dec; + } } Declaration BuiltInDeclarationSpecifier(Declaration dec) : { - DataType dt= null; + DataType dt= null; } { - dec = BuiltInTypeSpecifier(dec) - { - return dec; - } + dec = BuiltInTypeSpecifier(dec) + { + return dec; + } } Declaration TypeSpecifier(Declaration dec) : { DataType dt = null; } { - ( - dt= StructOrUnionSpecifier() - | - dt= EnumSpecifier() - | - LOOKAHEAD( { isType(getToken(1).image) } ) - dt= TypedefName() - ) - { - dec.setDataType(dt); - return dec; - } + ( + dt= StructOrUnionSpecifier() + | + dt= EnumSpecifier() + | + LOOKAHEAD( { isType(getToken(1).image) } ) + dt= TypedefName() + ) + { + dec.setDataType(dt); + return dec; + } } Declaration TypeQualifier(Declaration dec) : {} { - ( - { dec.setQualifier(CONST); } | - | - { dec.setQualifier(CDECL); } | - | - | - { dec.setQualifier(STDCALL); } | - { dec.setQualifier(FASTCALL); } | - | - | - | - | - | - | - | - | - ( DeclSpec() ) - ) - { - return dec; - } + ( + { dec.addQualifier(CONST); } | + | + { dec.addQualifier(CDECL); } | + | + | + { dec.addQualifier(STDCALL); } | + { dec.addQualifier(FASTCALL); } | + { dec.addQualifier(NORETURN); } | + | + | + | + | + | + | + | + | + | + ( DeclSpec() ) + ) + { + return dec; + } } void AttributeSpec() : {} { ( ("(") SubIdent() (")") ) | - AsmStatement() + AsmStatement() | + ( "[" "[" AttributeList() "]" "]" ) | + AlignmentSpecifier() + +} + +void AlignmentSpecifier() : { Declaration dt = new Declaration(); } +{ + < ALIGNAS > "(" ( TypeQualifier(dt) | AssignmentExpression() ) ")" +} + +void AttributeList() : { } +{ + AttributeToken() [ ("," AttributeToken())+ ] +} + +void AttributeToken() : { Declaration dt = new Declaration(); } +{ + ( < IDENTIFIER > | TypeQualifier(dt) ) [ ":" ":" ( < IDENTIFIER > | TypeQualifier(dt) ) ] [ "(" ( < IDENTIFIER > | Constant() ) [ ( "," (< IDENTIFIER > | Constant()) )+ ] ")" ] } void AttributeSpecList() : {} { - ( AttributeSpec() )+ + ( AttributeSpec() )+ } void SubIdent() : { Declaration dt = new Declaration(); } { ( ( "(" [SubIdent()] ")" ) | - ( | TypeQualifier(dt)) [ "(" - [SubIdent()] - ")" ] + ( | TypeQualifier(dt)) [ ( "(" [SubIdent()] ")") | ("=" SubIdent()) ] [ "," SubIdent() ] | @@ -1634,7 +1808,7 @@ void DeclSpecifier() : { } { "(" DeclSpecifier() ")" | - [ "(" + ()+ [ "(" DeclConstant() ( DeclConstant() )* ")" ] } @@ -1643,7 +1817,7 @@ void DeclConstant() : {} { | [ ":" ] | - ( "#" ["(" ")"] )* + ( "#" | ":" | | "(" ")" | ) } void PragmaSpec() : { @@ -1662,47 +1836,47 @@ void PragmaSpecifier() : { LOOKAHEAD(3) PragmaSpecifier() | id= ( | | )* - [ [ ds1=PragmaConstant() [ ( ds2=PragmaConstant() ) [ ( ds3=PragmaConstant() ) [ ( PragmaConstant() )+ ] ] ] ] ] + ([ [ (ds1=PragmaConstant())+ [ ( ds2=PragmaConstant() ) [ ( ds3=PragmaConstant() ) [ ( PragmaConstant() )+ ] ] ] ] ] ) { - if (id.image.equals("pack") && ds1 != null) { - Token newPackVal = ds1; - Token ID = ds2; - if (ds1.image.equals("pop")) { - // pop and set current value - packSize = popPack(ID); - newPackVal = null; - } - else if (ds1.image.equals("push") && ds2 != null) { - try { - // check if second arg is an integer - int ival = Integer.parseInt(ds2.image); - // if it is, the ID is default - newPackVal = ds2; - ID = null; - } - catch (NumberFormatException exc) { - // if it is not, then second arg is an ID - // and third arg is potentially a pack value - newPackVal = ds3; - ID = ds2; - } - pushPack(ID, packSize); - } - // set current pack value - if (newPackVal != null) { - int ival = packSize; - try { - // second arg may be an integer - ival = Integer.parseInt(newPackVal.image); - } - catch (NumberFormatException exc) { - // bad parse of number, just keep current pack size - } - packSize = ival; - } - } else if (id.image.equals("pack")) { - packSize = 0; - } + if (id.image.equals("pack") && ds1 != null) { + Token newPackVal = ds1; + Token ID = ds2; + if (ds1.image.equals("pop")) { + // pop and set current value + packSize = popPack(ID); + newPackVal = null; + } + else if (ds1.image.equals("push") && ds2 != null) { + try { + // check if second arg is an integer + int ival = Integer.parseInt(ds2.image); + // if it is, the ID is default + newPackVal = ds2; + ID = null; + } + catch (NumberFormatException exc) { + // if it is not, then second arg is an ID + // and third arg is potentially a pack value + newPackVal = ds3; + ID = ds2; + } + pushPack(ID, packSize); + } + // set current pack value + if (newPackVal != null) { + int ival = packSize; + try { + // second arg may be an integer + ival = Integer.parseInt(newPackVal.image); + } + catch (NumberFormatException exc) { + // bad parse of number, just keep current pack size + } + packSize = ival; + } + } else if (id.image.equals("pack")) { + packSize = 0; + } } // ignore to EOL now. } @@ -1712,12 +1886,18 @@ Token PragmaConstant() : { } { ( - val= | + val= + | + ( | | ) (PragmaConstant())* + | + ( (PragmaConstant())* )+ + | ( - (val=) [ ( ( | )+ ) ] - ) | + (val=) [ | ( ( | )+ ) ] + ) + | ( - val= ( [ ] )* + val= ( [ ] )* ) ) { @@ -1726,569 +1906,534 @@ Token PragmaConstant() : { } void StaticAssert() : { + Object expr = null; + Token t, message=null; } { - ( ( ) "(" ConstantExpression() [ "," ] ")" ) + ( ( t= ) "(" expr=ConstantExpression() [ "," message= ] ")" ) + { + if (expr != null) { + Integer evalue = getConstantValue(expr,1); + if (evalue == 0) { + String smessage = (message == null ? "" : message.image); + addNearParseMessage("Static_Asssert has failed " + " \"" + smessage + "\""); + } + } + } } DataType StructOrUnionSpecifier() : { - Token t; - Token sname; - Composite comp; + Token t; + Token parent; + Token sname; + Composite comp; } { - { - typedefParsingStack.push(Boolean.FALSE); - t= sname= null; - } - comp= StructOrUnion() - ( - LOOKAHEAD(3) - [ t= ] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList() ] - | - sname= - ) - { - try { + { + typedefParsingStack.push(Boolean.FALSE); + t= sname= null; + parent = null; + } + comp= StructOrUnion() + ( + LOOKAHEAD(3) + [ t= [ ":" parent=] ] "{" [StructDeclarationList(comp)] "}" [ AttributeSpecList() ] + | + sname= + ) + { + try { if (t != null) { - DataType dt= getStructDef(t.image); - if (dt != null && dt instanceof Structure && comp instanceof Structure && - dt.getDataTypeManager()==this.getDataTypeManager()) { - Structure dtcomp= (Structure) dt; - dtcomp.replaceWith(comp); - comp= dtcomp; - } else { - comp.setName(t.image); - comp= (Composite) addDef(structs, t.image, comp); - } + comp = defineNamedComposite(t, parent, comp); } else if (sname != null) { - DataType dt= getStructDef(sname.image); - if (dt instanceof Composite) { - comp= (Composite) dt; - } - if (dt == null) { - comp.setName(sname.image); - comp= (Composite) addDef(structs, sname.image, comp); - // System.out.println("COULDN'T FIND STRUCT DEFN " + sname); - } + comp = defineForwardDeclaredComposite(sname, comp); } - //System.out.println(" " + comp.getName()); - //for (int i = 0; i < comp.getNumComponents(); i++) { - // DataTypeComponent c = comp.getComponent(i); - // if (c == null) { - // System.out.println(" no comp " + i); - // } - // System.out.println(" " + c.getFieldName() + " off " + c.getOffset() + " len " + c.getLength()); - //} - } catch (InvalidNameException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (DuplicateNameException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - typedefParsingStack.pop(); - return comp; - } + } catch (InvalidNameException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (DuplicateNameException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + typedefParsingStack.pop(); + return comp; + } } Composite StructOrUnion() : {Composite comp;} { - ( - ( DeclSpec() | PragmaSpec() )* { comp = new StructureDataType(CategoryPath.ROOT, ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr); + ( + ( DeclSpec() | PragmaSpec() )* + { + comp = new StructureDataType(getCurrentCategoryPath(), ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr); - // Always set the packing, because by default structures should be aligned - if (packSize > 0) { - comp.setExplicitPackingValue(packSize); - } - else { - comp.setPackingEnabled(true); // ensure default packing enabled - } - - } - | - ( DeclSpec() )* { comp = new UnionDataType(CategoryPath.ROOT, ANONYMOUS_UNION_PREFIX + cnt++, dtMgr); - - // Always set the packing, because by default structures should be aligned - if (packSize > 0) { - comp.setExplicitPackingValue(packSize); - } - else { - comp.setPackingEnabled(true); // ensure default packing enabled - } - } - ) - { - try { - comp.setCategoryPath(getCurrentCategoryPath()); - } catch (DuplicateNameException e) {} - return comp; - } + // Always set the packing, because by default structures should be aligned + if (packSize > 0) { + comp.setExplicitPackingValue(packSize); + } + else { + comp.setPackingEnabled(true); // ensure default packing enabled + } + + } + | + ( DeclSpec() )* { + comp = new UnionDataType(getCurrentCategoryPath(), ANONYMOUS_UNION_PREFIX + cnt++, dtMgr); + + // Always set the packing, because by default structures should be aligned + if (packSize > 0) { + comp.setExplicitPackingValue(packSize); + } else { + comp.setPackingEnabled(true); // ensure default packing enabled + } + } + ) + { + return comp; + } } void StructDeclarationList(Composite comp) : { CompositeHandler compositeHandler = new CompositeHandler(comp); } { - ( StructDeclaration(comp, compositeHandler) )+ + ( StructDeclaration(comp, compositeHandler) )+ } void InitDeclaratorList(Declaration dt) : { - Declaration initialDT = new Declaration(dt); + Declaration initialDT = new Declaration(dt); } { - InitDeclarator(dt) - ( "," { dt = new Declaration(initialDT); } InitDeclarator(dt) )* - { - // Finished with a typedefDeclaration?? - if (!(typedefParsingStack.empty()) && (typedefParsingStack.peek()).booleanValue()) { - typedefParsingStack.pop(); - } - } + InitDeclarator(dt) + ( "," { dt = new Declaration(initialDT); } InitDeclarator(dt) )* + { + // Finished with a typedefDeclaration?? + if (!(typedefParsingStack.empty()) && (typedefParsingStack.peek()).booleanValue()) { + typedefParsingStack.pop(); + } + } } void InitDeclarator(Declaration dt) : { Declaration dec; } { - dec = Declarator(dt, null) [ "=" Initializer() ] - { - if (!(typedefParsingStack.empty()) && (typedefParsingStack.peek()).booleanValue()) { - addTypedef(dec.getName(), dec.getDataType()); - } else { - if (dt.getDataType() instanceof FunctionDefinition) { - addDef("functions", functions, dec.getName(), dec.getDataType()); - } - } - } + dec = Declarator(dt, null) [ "=" Initializer() ] + { + if (!(typedefParsingStack.empty()) && (typedefParsingStack.peek()).booleanValue()) { + addTypedef(dec.getName(), dec.getDataType()); + } else { + if (dt.getDataType() instanceof FunctionDefinition) { + addDef(functions, dec.getName(), dec.getDataType()); + } + } + } } void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : { - Declaration dt = null; + Declaration dt = null; } { LineDef() | + StaticAssert() | PragmaSpec() | - ( - [ dt = SpecifierQualifierList() ] - [ - StructDeclaratorList(dt, comp, compositeHandler) { dt= null; } - ] - [ AttributeSpecList() ] - ";" - ) - { - if (dt != null) { // dt was not used up - if (dt.getDataType().getLength() > 0) { - comp.add(dt.getDataType(), "", null); - } else { - System.err.println("BAD data type struct size " + dt); - } - } - } + ( + [ dt = SpecifierQualifierList() ] + [ + StructDeclaratorList(dt, comp, compositeHandler) { dt= null; } + ] + [ AttributeSpecList() ] + ";" + ) + { + if (dt != null) { // dt was not used up + if (dt.getDataType().getLength() > 0) { + comp.add(dt.getDataType(), "", null); + } else { + addNearParseMessage("BAD data type struct size " + dt); + } + } + } } Declaration SpecifierQualifierList() : { - Declaration dt = new Declaration(); - Declaration sdt= null; + Declaration dt = new Declaration(); + Declaration sdt= null; } { - ( - ( - dt = BuiltInDeclarationSpecifier(dt) - [ - LOOKAHEAD(TypeQualifierList(dt)) - dt = TypeQualifierList(dt) - ] - ) - | - ( - dt = TypeSpecifier(dt) - [ - LOOKAHEAD(SpecifierQualifierList() , { dt == null } ) - sdt = SpecifierQualifierList() - ] - ) - | - ( - dt = TypeQualifier(dt) - [ - LOOKAHEAD(SpecifierQualifierList()) - sdt = SpecifierQualifierList() - ] - ) - ) - { - if (sdt == null) { - dataTypeStack.push(dt.getDataType()); - return dt; - } - return sdt; - } + ( + ( + dt = BuiltInDeclarationSpecifier(dt) + [ + LOOKAHEAD(TypeQualifierList(dt)) + dt = TypeQualifierList(dt) + ] + ) + | + ( + dt = TypeSpecifier(dt) + [ + LOOKAHEAD(SpecifierQualifierList() , { dt == null } ) + sdt = SpecifierQualifierList() + ] + ) + | + ( + dt = TypeQualifier(dt) + [ + LOOKAHEAD(SpecifierQualifierList()) + sdt = SpecifierQualifierList() + ] + ) + ) + { + if (sdt == null) { + dataTypeStack.push(dt.getDataType()); + return dt; + } + return sdt; + } } void StructDeclaratorList(Declaration dt, Composite comp, CompositeHandler compositeHandler) : { } { - StructDeclarator(dt, comp, compositeHandler) ( "," StructDeclarator(dt, comp, compositeHandler) )* + StructDeclarator(dt, comp, compositeHandler) ( "," StructDeclarator(dt, comp, compositeHandler) )* } void StructDeclarator(Declaration dt, Composite comp, CompositeHandler compositeHandler) : { - Declaration dec= null; - Object bitSizeObj; + Declaration dec= null; + Object bitSizeObj; } { LineDef() | - ( - LOOKAHEAD(3) - dec= Declarator(dt, comp) [ ":" bitSizeObj = ConstantExpression() { - Integer bitSize = getConstantValue(bitSizeObj,-1); - dec.setBitFieldSize(bitSize); - }] - | - ":" bitSizeObj = ConstantExpression() { - Integer bitSize = getConstantValue(bitSizeObj,-1); - dec = new Declaration(dt); - dec.setBitFieldSize(bitSize); - } - ) - { + StaticAssert() | + ( + LOOKAHEAD(3) + dec= Declarator(dt, comp) [ ":" bitSizeObj = ConstantExpression() { + Integer bitSize = getConstantValue(bitSizeObj,-1); + dec.setBitFieldSize(bitSize); + }] + | + ":" bitSizeObj = ConstantExpression() { + Integer bitSize = getConstantValue(bitSizeObj,-1); + dec = new Declaration(dt); + dec.setBitFieldSize(bitSize); + } + ) + { try { compositeHandler.add(dec); - } catch (IllegalArgumentException e) { - System.err.println("Bad structure size " + dec.getName() + " length=" + dec.getDataType().getLength()); - System.err.println(" In file " + this.headerFileName); - System.err.println(" Near " + lastDataType.getName()); - } - } + } catch (IllegalArgumentException e) { + addNearParseMessage("Bad structure size " + dec.getName() + " length=" + dec.getDataType().getLength()); + } + } } DataType EnumSpecifier() : { - Token t= null; - DataType dt; - ArrayList list; + Token t= null; + DataType dt; + ArrayList list; } { - - ( - LOOKAHEAD(3) - [ t= ] "{" list= EnumeratorList() "}" - { - String enumName= (t != null ? t.image : ("enum_" + cnt++)); - EnumDataType enuum= new EnumDataType(CategoryPath.ROOT, enumName, 4, dtMgr); - for (EnumMember member : list) { - try { - enuum.add(member.name, member.value); + + ( + LOOKAHEAD(3) + [AttributeSpecList()] [ t= ] "{" list= EnumeratorList() "}" + { + String enumName= (t != null ? t.image : ("enum_" + cnt++)); + EnumDataType enuum= new EnumDataType(getCurrentCategoryPath(), enumName, 4, dtMgr); + for (EnumMember member : list) { + try { + enuum.add(member.name, member.value); } catch (IllegalArgumentException exc) { - System.err.println("duplicate enum value: " + enumName + " : " + member.name + " : " + member.value); - System.err.println(" In file " + this.headerFileName); - System.err.println(" Near " + lastDataType.getName()); + addNearParseMessage("duplicate enum value: " + enumName + " : " + member.name + " : " + member.value); } - } - dt= enuum; - dt= addDef(enums, enumName, enuum); - } - | - t= { dt= getEnumDef(t.image); } - ) - { - return dt; - } + } + dt= enuum; + dt= addDef(enums, enumName, enuum); + } + | + t= { dt= getEnumDef(t.image); } + ) + { + return dt; + } } ArrayList EnumeratorList() : { - int value= 0; - ArrayList list= new ArrayList(); + int value= 0; + ArrayList list= new ArrayList(); } { - ( - LineDef() | - value= Enumerator(list, value) [ "," ] { value++; } - )* - { - return list; - } + ( + LineDef() | + PragmaSpec() | + StaticAssert() | + value= Enumerator(list, value) [ "," ] { value++; } + )* + { + return list; + } } int Enumerator(ArrayList list, int value) : { - Token t = null; - Object obj = null; - Integer evalue; + Token t = null; + Object obj = null; + Integer evalue; } { - t = [ "=" obj = ConstantExpression() ] - { - evalue = getConstantValue(obj,value); + t = [ "=" obj = ConstantExpression() ] + { + evalue = getConstantValue(obj,value); if (evalue != null) { - value = evalue; - } - list.add(new EnumMember(t.image, value)); - return value; - } - | - t = [ "=" obj = ConstantExpression() ] - { - evalue = getConstantValue(obj,value); + value = evalue; + } + list.add(new EnumMember(t.image, value)); + return value; + } + | + t = [ "=" obj = ConstantExpression() ] + { + evalue = getConstantValue(obj,value); if (evalue != null) { - value = evalue; - } - return value; - } + value = evalue; + } + return value; + } } Declaration Declarator(Declaration dt, DataType container) : { - Declaration dec= null; + Declaration dec= null; } { - ( - [ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList() ] - ) - { - return dec; - } + ( + [ dt = TypeQualifierList(dt) ] [ dt = Pointer(dt) ] dec= DirectDeclarator(dt, container) [ AttributeSpecList() ] + ) + { + return dec; + } } Declaration DirectDeclarator(Declaration dt, DataType container) : { - Token t; - Declaration dec= null; - Declaration funcDec= null; + Token t; + Declaration dec= null; + Declaration funcDec= null; FunctionDefinitionDataType funcDT= null; - Object obj = null; - ArrayList list = new ArrayList(); + Object obj = null; + ArrayList list = new ArrayList(); } { - ( - ( - t= { dec= new Declaration(dt, t.image); } - //****** working here Looks like should define a function here. - // if the data type in dec is a pointer, it should be a pointer. - // The function should be set locally so the param list can be applied. - // The function pointer should be returned. - // Also, the pointer data type should probably have the TypeQualifier before the "*"????? - | - "(" dec= Declarator(new Declaration(funcDT=newAnonymousFunction(funcDT)), null) ")" - { - // System.out.println(" ( func dec ) " + dec.getName() + " " + dec.getDataType()); - } - // | "(" [ decDT = DeclarationSpecifiers() ] - // { - // if (decDT != null) { - // dt = decDT; - // } - // } - // dec = Declarator(dt, null) ")" - ) - { lastDataType = dec.getDataType(); } - ( - "[" [ obj = ConditionalExpression() ] "]" - { - // make a new array given value on constant expression - Integer size = getConstantValue(obj, 0); - if (size == null) { - System.out.println("BAD ARRAY SIZE! " + obj); - size = 0; - } - list.add(0,size); - dec.setDataType(dt.getDataType()); - for (Iterator iterator = list.iterator(); iterator.hasNext();) { - Integer iSize = (Integer) iterator.next(); - DataType decDt = dec.getDataType(); - dec.setDataType(new ArrayDataType(decDt, iSize, decDt.getLength())); - } - //System.out.println("Array expr: for " + dec.getName() + " make an array " + dt.getName() + "["+size+"]"); - } - )* - - ( - LOOKAHEAD(3) - "(" funcDec= ParameterTypeList(funcDT=newAnonymousFunction(funcDT), dt.getDataType()) ")" - { - //System.out.println( - // "Param list: for " + dec.getName() + " make a function " + dt.getName()); - } - | - "(" [ IdentifierList(funcDT=newAnonymousFunction(funcDT), dt.getDataType()) ] ")" - { - //System.out.println( - // "ID List: for " + dec.getName() + " make a function " + dt.getName()); - funcDec= new Declaration(funcDT=newAnonymousFunction(funcDT), "__paramIDList__"); - } - )* - ) - { - if (funcDec != null) { - try { - // functions in containers stay anonymous - if (container == null) { - funcDT.setName(dec.getName()); - } - funcDec.setName(dec.getName()); - if (dec.getDataType() != null) { - funcDec.setDataType(dec.getDataType()); - } - } catch (InvalidNameException e) { - throw new ParseException("duplicate name " + dec.getName()); - } - DataType retDT = dt.getDataType(); - checkReturnDataType(retDT); - funcDT.setReturnType(retDT); - switch (dt.getQualifier()) { - case CDECL: - funcDT.setGenericCallingConvention(GenericCallingConvention.cdecl); - break; - case STDCALL: - funcDT.setGenericCallingConvention(GenericCallingConvention.stdcall); - break; - case FASTCALL: - funcDT.setGenericCallingConvention(GenericCallingConvention.fastcall); - break; + [ PragmaSpec() ] + ( + ( + t= { dec= new Declaration(dt, t.image); } + | + "(" dec= Declarator(new Declaration(funcDT=newAnonymousFunction(funcDT)), null) ")" + { + // System.out.println(" ( func dec ) " + dec.getName() + " " + dec.getDataType()); } - dec= funcDec; - DataType newDT = addDef("functions", functions, dec.getName(), funcDT); - DataType repDT= dec.getDataType(); - // shove the data type into any pointer definition. - while (repDT != null) { - if (repDT instanceof Pointer) { - PointerDataType ptDT= (PointerDataType) repDT; - if (ptDT.getDataType() instanceof FunctionDefinition) { - ptDT.dataTypeReplaced(ptDT.getDataType(), newDT); - newDT = repDT; - break; - } - repDT= ptDT.getDataType(); - } else { - break; - } - } - dec.setDataType(newDT); - } + ) + { lastDataType = dec.getDataType(); } + ( + ( + "[" [ obj = ConditionalExpression() ] "]" + { + // make a new array given value on constant expression + Integer size = getConstantValue(obj, 0); + if (size == null) { + System.out.println("BAD ARRAY SIZE! " + obj); + size = 0; + } + list.add(0,size); + } + )* + ) + { + if (list.size() > 0) { + dec.setDataType(dt.getDataType()); + for (Iterator iterator = list.iterator(); iterator.hasNext();) { + Integer iSize = (Integer) iterator.next(); + DataType decDt = dec.getDataType(); + dec.setDataType(new ArrayDataType(decDt, iSize, decDt.getLength())); + } + //System.out.println("Array expr: for " + dec.getName() + " make an array " + dt.getName() + "["+size+"]"); + } + } + + ( + LOOKAHEAD(3) + "(" funcDec= ParameterTypeList(funcDT=newAnonymousFunction(funcDT), dt.getDataType()) ")" + { + //System.out.println( + // "Param list: for " + dec.getName() + " make a function " + dt.getName()); + } + | + "(" [ IdentifierList(funcDT=newAnonymousFunction(funcDT), dt.getDataType()) ] ")" + { + //System.out.println( + // "ID List: for " + dec.getName() + " make a function " + dt.getName()); + funcDec= new Declaration(funcDT=newAnonymousFunction(funcDT), "__paramIDList__"); + } + )* + ) + { + if (funcDec != null) { + try { + // functions in containers stay anonymous + if (container == null) { + funcDT.setName(dec.getName()); + } + funcDec.setName(dec.getName()); + if (dec.getDataType() != null) { + funcDec.setDataType(dec.getDataType()); + } + } catch (InvalidNameException e) { + throw new ParseException("duplicate name " + dec.getName()); + } + DataType retDT = dt.getDataType(); + checkReturnDataType(retDT); + funcDT.setReturnType(retDT); + // get qualifiers and apply them + applyFunctionQualifiers(dt, funcDT); + dec= funcDec; + defineAndReplaceFunction(dec, funcDT); + } - return dec; - } + return dec; + } } Declaration Pointer(Declaration dec) : {} { - ("*" | "&") [ dec = TypeQualifierList(dec) ] [ dec = Pointer(dec) ] - { - // TODO: is this right? - dec.setDataType(dtMgr.getPointer(dec.getDataType())); - return dec; - } + ("*" | "&") [ dec = TypeQualifierList(dec) ] [ dec = Pointer(dec) ] + { + // TODO: is this right? + dec.setDataType(dtMgr.getPointer(dec.getDataType())); + return dec; + } } Declaration TypeQualifierList(Declaration dec) : {} { - ( dec = TypeQualifier(dec) )+ - { - return dec; - } + ( dec = TypeQualifier(dec) )+ + { + return dec; + } } Declaration ParameterTypeList(FunctionDefinitionDataType funcDT, DataType retDT) : { - ArrayList list; - Token varargs= null; + ArrayList list; + Token varargs= null; } { - list= ParameterList() [ "," varargs = "..." ] - { - checkReturnDataType(retDT); - if (funcDT == null) { - funcDT= new FunctionDefinitionDataType(CategoryPath.ROOT, ANONYMOUS_FUNC_PREFIX, dtMgr); - } - funcDT.setVarArgs(varargs!=null); - ParameterDefinition[] variables= new ParameterDefinition[list.size()]; - for (int i= 0; i < variables.length; i++) { - Declaration dec= list.get(i); + list= ParameterList() [ "," varargs = "..." ] + { + checkReturnDataType(retDT); + if (funcDT == null) { + funcDT= new FunctionDefinitionDataType(getCurrentCategoryPath("functions"), ANONYMOUS_FUNC_PREFIX, dtMgr); + } + funcDT.setVarArgs(varargs!=null); + Declaration firstDeclaration = null; + ParameterDefinition[] variables= new ParameterDefinition[list.size()]; + if (variables.length == 1) { + firstDeclaration = list.get(0); + } + for (int i= 0; i < variables.length; i++) { + Declaration dec= list.get(i); DataType varDT = dec.getDataType(); - // if this is a single void parameter, empty the parameter variable list + // if this is a single void parameter, empty the parameter variable list // if (variables.length == 1 && varDT instanceof VoidDataType) { - variables = new ParameterDefinition[0]; - break; + variables = new ParameterDefinition[0]; + break; } variables[i] = new ParameterDefinitionImpl(dec.getName(), dec.getDataType(), null); - } - funcDT.setReturnType(retDT); - funcDT.setArguments(variables); - return new Declaration(funcDT); - } + } + funcDT.setReturnType(retDT); + funcDT.setArguments(variables); + Declaration dec = new Declaration(funcDT); + if (firstDeclaration != null) { + dec.addQualifiers(firstDeclaration); + } + return dec; + } } ArrayList ParameterList() : { - ArrayList list= new ArrayList(); + ArrayList list= new ArrayList(); } { - ParameterDeclaration(list) - ( - LOOKAHEAD(2) - "," ParameterDeclaration(list) - )* - { - return list; - } + ParameterDeclaration(list) + ( + LOOKAHEAD(2) + "," ParameterDeclaration(list) + )* + { + return list; + } } void ParameterDeclaration(ArrayList list) : { - Declaration dt = new Declaration(); - Declaration dec= new Declaration(); + Declaration dt = new Declaration(); + Declaration dec= new Declaration(); } { - dt = DeclarationSpecifiers(dec) - ( - LOOKAHEAD(Declarator(dt)) - dec= Declarator(dt, null) - | - [ dec = AbstractDeclarator(dt) ] - ) [ "=" ] - { - if (dec == null) { - dec = new Declaration(dt); - } - DataType decDT = dec.getDataType(); + dt = DeclarationSpecifiers(dec) + ( + LOOKAHEAD(Declarator(dt)) + dec= Declarator(dt, null) + | + [ dec = AbstractDeclarator(dt) ] + ) [ "=" ] + { + if (dec == null) { + dec = new Declaration(dt); + } + DataType decDT = dec.getDataType(); if (decDT != null) { if (decDT.getLength() < 0 && !((decDT instanceof FunctionDefinition) || (decDT instanceof TypeDef && (((TypeDef) decDT).getDataType() instanceof FunctionDefinition)))) { - // if (decDT.getLength() < 0 && !(decDT instanceof FunctionDefinitionDataType)) { - throw new ParseException("'"+decDT.getName()+"'" + " is not fixed length. Function parameters must use fixed length data type."); + // if (decDT.getLength() < 0 && !(decDT instanceof FunctionDefinitionDataType)) { + throw new ParseException("'"+decDT.getName()+"'" + " is not fixed length. Function parameters must use fixed length data type."); } else { list.add(dec); } } - } + } } void IdentifierList(FunctionDefinitionDataType funcDT, DataType retDT) : { - Token t; + Token t; } { - { - ArrayList list= new ArrayList(); - } - t= { list.add(t.image); } - ( - "," t= { list.add(t.image); } - )* - { - checkReturnDataType(retDT); - ParameterDefinition[] variables= new ParameterDefinition[list.size()]; - for (int i= 0; i < variables.length; i++) { - // TODO need a data type - variables[i] = new ParameterDefinitionImpl(list.get(i), null, null); - } - funcDT.setReturnType(retDT); - funcDT.setArguments(variables); - } + { + ArrayList list= new ArrayList(); + } + t= { list.add(t.image); } + ( + "," t= { list.add(t.image); } + )* + { + checkReturnDataType(retDT); + ParameterDefinition[] variables= new ParameterDefinition[list.size()]; + for (int i= 0; i < variables.length; i++) { + // TODO need a data type + variables[i] = new ParameterDefinitionImpl(list.get(i), null, null); + } + funcDT.setReturnType(retDT); + funcDT.setArguments(variables); + } } void Initializer() : {} { - ( AssignmentExpression() | "{" InitializerList() [ "," ] "}" ) + ( AssignmentExpression() | "{" InitializerList() [ "," ] "}" ) } void InitializerList() : {} { - [ Designation() ] Initializer() [ "," InitializerList() ] + [ Designation() ] Initializer() [ "," InitializerList() ] } void Designation() : { } @@ -2311,113 +2456,153 @@ Declaration TypeName() : { Declaration dec = null; } { - dec = SpecifierQualifierList() [ dec = AbstractDeclarator(new Declaration(dec)) ] - { - return dec; - } + dec = SpecifierQualifierList() [ dec = AbstractDeclarator(new Declaration(dec)) ] + { + return dec; + } } Declaration AbstractDeclarator(Declaration dt) : { - Declaration dec= null; + Declaration dec= null; } { - ( - LOOKAHEAD(3) - dec= DirectAbstractDeclarator(dt) { return new Declaration(dec, dt.getDataType()); } | - dt= Pointer(dt) [dec= DirectAbstractDeclarator(dt) { return new Declaration(dec, dt.getDataType()); }] - ) - { return new Declaration(dt); } + ( + LOOKAHEAD(3) + dec = DirectAbstractDeclarator(dt) { return dec; } | + dt = Pointer(dt) [dec= DirectAbstractDeclarator(dt) { return dec; }] + ) + { return new Declaration(dt); } } Declaration DirectAbstractDeclarator(Declaration dt) : { - Declaration dec= null; + Declaration dec= dt; + Declaration paramDec= null; + FunctionDefinitionDataType funcDT = null; + Object constObj = null; + ArrayList list = new ArrayList(); } { - ( - LOOKAHEAD(2) - "(" [TypeQualifier(dt)] dec= AbstractDeclarator(dt) ")" - | - "[" [ ConstantExpression() ] "]" - | - "(" [ dec= ParameterTypeList(null, dt.getDataType()) ] ")" - ) - + ( + LOOKAHEAD(2) + "(" { funcDT = newAnonymousFunction(null); dec = new Declaration(funcDT); } dec = AbstractDeclarator(dec) ")" + | + "[" [ constObj = ConstantExpression() ] "]" + { + // TODO: create an array + Integer size = getConstantValue(constObj, 0); + list.add(0,size); + } + | + "(" [ { funcDT = newAnonymousFunction(null); } dec= ParameterTypeList(funcDT, dt.getDataType()) ] ")" + { + funcDT = (FunctionDefinitionDataType) dec.getDataType(); + dec.setDataType(dtMgr.getPointer(funcDT)); + } + ) - - - - ( - "[" [ ConstantExpression() ] "]" | "(" [ dec= ParameterTypeList(null, dec.getDataType()) ] ")" - )* - { - return dec; - } + ( + ( + "[" [ constObj = ConstantExpression() ] "]" + { + // TODO: create an array + Integer size = getConstantValue(constObj, 0); + list.add(0,size); + } + ) * + ) + { + if (list.size() > 0) { + for (Iterator iterator = list.iterator(); iterator.hasNext();) { + Integer iSize = (Integer) iterator.next(); + DataType decDt = dec.getDataType(); + dec.setDataType(new ArrayDataType(decDt, iSize, decDt.getLength())); + } + } + } + + ( "(" [ paramDec = ParameterTypeList(funcDT, dt.getDataType()) ] ")" + { + dec = (funcDT != null ? dec : paramDec); + } + )* + { + if (funcDT != null) { + // get qualifiers and apply them + List dtQualifiers = dt.getQualifiers(); + if (dtQualifiers == null || dtQualifiers.isEmpty()) { + dt = dec; + } + applyFunctionQualifiers(dt, funcDT); + defineAndReplaceFunction(dec, funcDT); + } + return dec; + } } DataType TypedefName() : { - Token t; + Token t; } { - t= - { - return getType(t.image); - } + t= + { + return getType(t.image); + } } void Statement() : {} { - ( - LOOKAHEAD(2) - AsmStatement() - | - LOOKAHEAD(3) - DeclarationList() - | - LOOKAHEAD(2) - LabeledStatement() - | - ExpressionStatement() - | - CompoundStatement() - | - SelectionStatement() - | - IterationStatement() - | - JumpStatement() - | - AsmStatement() - | - PragmaSpec() - | - StaticAssert() - ) + ( + LOOKAHEAD(2) + AsmStatement() + | + LOOKAHEAD(3) + DeclarationList() + | + LOOKAHEAD(2) + LabeledStatement() + | + ExpressionStatement() + | + CompoundStatement() + | + SelectionStatement() + | + IterationStatement() + | + JumpStatement() + | + AsmStatement() + | + PragmaSpec() + | + StaticAssert() + ) } void LabeledStatement() : {} { - ( ":" Statement() | ConstantExpression() ":" Statement() | ":" Statement() ) + ( ":" Statement() | ConstantExpression() ":" Statement() | ":" Statement() ) } void ExpressionStatement() : {} { - [ Expression() ] ";" + [ Expression() ] ";" } void CompoundStatement() : {} { - "{" -// [ -// LOOKAHEAD(DeclarationList()) -// DeclarationList() -// ] - [ StatementList() ] "}" + "{" +// [ +// LOOKAHEAD(DeclarationList()) +// DeclarationList() +// ] + [ StatementList() ] "}" } void StatementList() : {} { - ( LineDef() | - Statement() )+ + ( LineDef() | + Statement() )+ } @@ -2436,7 +2621,7 @@ void AsmStatement() : void AsmLine() : { - Declaration dec = new Declaration(); + Declaration dec = new Declaration(); } { ( | | | | BuiltInTypeSpecifier(dec) | "#" | "+" | "-" | "," | ":" | "*" | ("[" AsmLine() "]") | ( "(" AsmLine() ")" ) | ( "{" AsmLine() "}" ) )+ @@ -2445,61 +2630,61 @@ void AsmLine() : void SelectionStatement() : {} { - ( - "(" Expression() ")" Statement() - [ - LOOKAHEAD(2) - Statement() - ] - | - "(" Expression() ")" Statement() - ) + ( + "(" Expression() ")" Statement() + [ + LOOKAHEAD(2) + Statement() + ] + | + "(" Expression() ")" Statement() + ) } void IterationStatement() : {} { - ( - "(" Expression() ")" Statement() - | - Statement() "(" Expression() ")" ";" - | - "(" [ Expression() ] ";" [ Expression() ] ";" [ Expression() ] ")" Statement() - ) + ( + "(" Expression() ")" Statement() + | + Statement() "(" Expression() ")" ";" + | + "(" [ Expression() ] ";" [ Expression() ] ";" [ Expression() ] ")" Statement() + ) } void JumpStatement() : {} { - ( ";" | ";" | ";" | [ Expression() ] ";" ) + ( ";" | ";" | ";" | [ Expression() ] ";" ) } Object Expression() : { Object obj = null; } { - obj = AssignmentExpression() ( "," obj = AssignmentExpression() )* - { - return obj; - } + obj = AssignmentExpression() ( "," obj = AssignmentExpression() )* + { + return obj; + } } Object AssignmentExpression() : { Object obj = null; } { - ( LOOKAHEAD(UnaryExpression() AssignmentOperator()) - UnaryExpression() AssignmentOperator() obj=AssignmentExpression() - | - LOOKAHEAD(3) - obj = ConditionalExpression() - ) - { - return obj; - } + ( LOOKAHEAD(UnaryExpression() AssignmentOperator()) + UnaryExpression() AssignmentOperator() obj=AssignmentExpression() + | + LOOKAHEAD(3) + obj = ConditionalExpression() + ) + { + return obj; + } } void AssignmentOperator() : {} { - ( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" ) + ( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" ) } Object ConditionalExpression() : { @@ -2507,9 +2692,9 @@ Object ConditionalExpression() : { Object objTrue = null, objFalse = null; } { - obj = LogicalORExpression() [ "?" objTrue=Expression() ":" objFalse=ConditionalExpression() { obj = computeTernaryValue(obj, objTrue, objFalse); } ] - { - return obj; + obj = LogicalORExpression() [ "?" objTrue=Expression() ":" objFalse=ConditionalExpression() { obj = computeTernaryValue(obj, objTrue, objFalse); } ] + { + return obj; } } @@ -2517,9 +2702,9 @@ Object ConstantExpression() : { Object obj = null; } { - obj = ConditionalExpression() - { - return obj; + obj = ConditionalExpression() + { + return obj; } } @@ -2527,9 +2712,9 @@ Object LogicalORExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = LogicalANDExpression() ( op="||" obj2 = LogicalANDExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + obj = LogicalANDExpression() ( op="||" obj2 = LogicalANDExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * + { + return obj; } } @@ -2537,9 +2722,9 @@ Object LogicalANDExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = InclusiveORExpression() ( op="&&" obj2=InclusiveORExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + obj = InclusiveORExpression() ( op="&&" obj2=InclusiveORExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * + { + return obj; } } @@ -2547,9 +2732,9 @@ Object InclusiveORExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = ExclusiveORExpression() ( op="|" obj2=ExclusiveORExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + obj = ExclusiveORExpression() ( op="|" obj2=ExclusiveORExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * + { + return obj; } } @@ -2557,9 +2742,9 @@ Object ExclusiveORExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = ANDExpression() ( op="^" obj2=ANDExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + obj = ANDExpression() ( op="^" obj2=ANDExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * + { + return obj; } } @@ -2567,9 +2752,9 @@ Object ANDExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = EqualityExpression() ( op="&" obj2=EqualityExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + obj = EqualityExpression() ( op="&" obj2=EqualityExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * + { + return obj; } } @@ -2577,11 +2762,11 @@ Object EqualityExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = RelationalExpression() - ( - (op="==" | op="!=") obj2 = RelationalExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + obj = RelationalExpression() + ( + (op="==" | op="!=") obj2 = RelationalExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * + { + return obj; } } @@ -2589,12 +2774,12 @@ Object RelationalExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = ShiftExpression() - ( - (op="<" | op=">" | op="<=" | op=">=") obj2=ShiftExpression() { obj = computeBinaryValue(obj, op, obj2); } - ) * - { - return obj; + obj = ShiftExpression() + ( + (op="<" | op=">" | op="<=" | op=">=") obj2=ShiftExpression() { obj = computeBinaryValue(obj, op, obj2); } + ) * + { + return obj; } } @@ -2602,13 +2787,13 @@ Object ShiftExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = AdditiveExpression() - ( - ( op="<<" | op=">>" ) obj2 = AdditiveExpression() - { obj = computeBinaryValue(obj, op, obj2); } - ) * - { - return obj; + obj = AdditiveExpression() + ( + ( op="<<" | op=">>" ) obj2 = AdditiveExpression() + { obj = computeBinaryValue(obj, op, obj2); } + ) * + { + return obj; } } @@ -2616,12 +2801,12 @@ Object AdditiveExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = MultiplicativeExpression() - ( ( op="+" | op="-" ) obj2 = MultiplicativeExpression() - { obj = computeBinaryValue(obj, op, obj2); } + obj = MultiplicativeExpression() + ( ( op="+" | op="-" ) obj2 = MultiplicativeExpression() + { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + { + return obj; } } @@ -2629,12 +2814,12 @@ Object MultiplicativeExpression() : { Object obj = null, obj2 = null; Token op=null; } { - obj = CastExpression() - ( ( op="*" | op="/" | op="%" ) obj2 = CastExpression() - { obj = computeBinaryValue(obj, op, obj2); } + obj = CastExpression() + ( ( op="*" | op="/" | op="%" ) obj2 = CastExpression() + { obj = computeBinaryValue(obj, op, obj2); } ) * - { - return obj; + { + return obj; } } @@ -2642,101 +2827,109 @@ Object CastExpression() : { Object obj = null; } { - ( - LOOKAHEAD("(" TypeName() ")") - ( - "(" TypeName() ")" ( obj = CastExpression() | - ( "{" InitializerList() [ "," ] "}" ) ) - ) - | - obj = UnaryExpression() - ) - { - return obj; + ( + LOOKAHEAD("(" TypeName() ")") + ( + "(" TypeName() ")" ( obj = CastExpression() | + ( "{" InitializerList() [ "," ] "}" ) ) + ) + | + obj = UnaryExpression() + ) + { + return obj; } } Object UnaryExpression() : { Object obj = null; Token op = null; - Declaration dec = null; + Declaration dec = null; } { - ( - LOOKAHEAD(3) - obj = PostfixExpression() - | - UnaryOperator() CastExpression() - | - "++" UnaryExpression() - | - "--" UnaryExpression() - | - "+" obj=CastExpression() - | - op="-" obj=CastExpression() { obj = computeUnaryValue(obj, op); } - | - op="~" obj=CastExpression() { obj = computeUnaryValue(obj, op); } - | - op="!" obj=CastExpression() { obj = computeUnaryValue(obj, op); } - | - - ( - "(" ( dec = TypeName() | obj = UnaryExpression() ) ")" - { - if (obj != null && obj instanceof String) { - obj = Long.valueOf(((String) obj).length() - 1); // will include "" plus \0 - } - else if (dec != null) { - obj = Long.valueOf(dec.getDataType().getLength()); - } - else if (obj != null) { - // TODO: try to look up the type of the identifier - // TODO: Throw error if identifier is not defined - // may need to actually track declarations! - } - } - ) - ) - { - return obj; + ( + LOOKAHEAD(3) + obj = PostfixExpression() + | + UnaryOperator() CastExpression() + | + "++" UnaryExpression() + | + "--" UnaryExpression() + | + "+" obj=CastExpression() + | + op="-" obj=CastExpression() { obj = computeUnaryValue(obj, op); } + | + op="~" obj=CastExpression() { obj = computeUnaryValue(obj, op); } + | + op="!" obj=CastExpression() { obj = computeUnaryValue(obj, op); } + | + + ( + "(" ( dec = TypeName() | obj = UnaryExpression() ) ")" + { + if (obj != null && obj instanceof String) { + obj = Long.valueOf(((String) obj).length() - 1); // will include "" plus \0 + } + else if (dec != null) { + obj = Long.valueOf(dec.getDataType().clone(dtMgr).getLength()); + } + else if (obj != null) { + // TODO: try to look up the type of the identifier + // TODO: Throw error if identifier is not defined + // may need to actually track declarations! + } + } + ) + | + + ( + "(" ( dec = TypeName() ) ")" + { + // TODO: if data types can have alignment, replace with alignment of the data type + } + ) + ) + { + return obj; } } void UnaryOperator() : { } { - ( - "&" - | - "*" - ) + ( + "&" + | + "*" + ) } Object PostfixExpression() : { Object obj = null; } { - obj = PrimaryExpression() - ( - ( "[" Expression() "]" ) - | - "(" - [ - LOOKAHEAD(ArgumentExpressionList() ) - ArgumentExpressionList() - ] - ")" - | - "." - | - "->" - | - "++" - | - "--" - )* - { - return obj; + obj = PrimaryExpression() + ( + ( "[" Expression() "]" ) + | + "(" + [ + LOOKAHEAD(ArgumentExpressionList() ) + ArgumentExpressionList() + ] + ")" + | + "." + | + "->" + | + "++" + | + "--" + )* + { + return obj; } } @@ -2744,28 +2937,41 @@ Object PrimaryExpression() : { Object obj = null; } { - ( obj = | - obj = Constant() | - "(" obj = Expression() ")" ) - { - return obj; + ( obj = | + obj = Constant() | + "(" obj = Expression() ")" ) + { + return obj; } } void ArgumentExpressionList() : {} { - AssignmentExpression() ( "," AssignmentExpression() )* + AssignmentExpression() ( "," AssignmentExpression() )* } Object Constant() : { Token t; - Object obj= null; + Object obj= null; } { ( - t = - { - String sval = t.image; + t = + { + String sval = t.image; + if (sval.endsWith("i8") || sval.endsWith("I8")) { + sval = sval.substring(0,sval.length()-2); + } + else if (sval.endsWith("i16") || sval.endsWith("I16")) { + sval = sval.substring(0,sval.length()-3); + } + else if (sval.endsWith("i32") || sval.endsWith("I32")) { + sval = sval.substring(0,sval.length()-3); + } + else if (sval.endsWith("i64") || sval.endsWith("I64")) { + sval = sval.substring(0,sval.length()-3); + } + if (sval.endsWith("ull") || sval.endsWith("ULL")) { sval = sval.substring(0,sval.length()-3); } @@ -2782,36 +2988,36 @@ Object Constant() : { sval = sval.substring(0,sval.length()-1); } if (sval.startsWith("0x") || sval.startsWith("0X")) { - BigInteger bigConst = new BigInteger(sval.substring(2), 16); + BigInteger bigConst = new BigInteger(sval.substring(2), 16); obj = Long.valueOf(bigConst.longValue()); } else { - BigInteger bigConst = new BigInteger(sval); + BigInteger bigConst = new BigInteger(sval); obj = Long.valueOf(bigConst.longValue()); } - } - | - t = - { - obj = new Double(t.image); - } - | - t = - { + } + | + t = + { + obj = new Double(t.image); + } + | + t = + { if (t.image.length() == 1) { obj = new Character(t.image.charAt(0)); } else if (t.image.length() == 4) { long cval = ((long)t.image.charAt(0) << 24) + ((long)t.image.charAt(1) << 16) + ((long)t.image.charAt(2) << 8) + ((long) t.image.charAt(3)); obj = Long.valueOf(cval); } - } - | - t = - { - obj = t.image; - } - ) - { - return obj; + } + | + t = + { + obj = t.image; + } + ) + { + return obj; } } 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 3b895cb664..092de2c138 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 @@ -167,37 +167,37 @@ public class PreProcessor { boolean emitExecSave; int comparison; - ArrayList appendList = new ArrayList(); + ArrayList appendList = new ArrayList(); ArrayList expandList = new ArrayList(); void append(String str, boolean expand) { if (image != null & image.length()>0) { - appendList.add(image); + appendList.add(new StringBuffer(image)); expandList.add(true); image = null; } int endIndex = appendList.size() - 1; if (endIndex >= 0 && (str.strip().length()==0 || expand == expandList.get(endIndex)) ) { // just add to the last image so it can expand properly - String lastStr = appendList.remove(endIndex); - expand = expandList.remove(endIndex); - str = lastStr + str; + StringBuffer lastStr = appendList.get(endIndex); + lastStr.append(str); + return; } - appendList.add(str); + appendList.add(new StringBuffer(str)); expandList.add(expand); } - void append(PPToken tok, boolean expand) { - if (tok.image != null && tok.image.length() > 0) { - append(tok.image, expand); - return; - } - int cnt = 0; - for (String string : appendList) { - append(string, expandList.get(cnt)); - } - } +// void append(PPToken tok, boolean expand) { +// if (tok.image != null && tok.image.length() > 0) { +// append(tok.image, expand); +// return; +// } +// int cnt = 0; +// for (String string : appendList) { +// append(string, expandList.get(cnt)); +// } +// } void setTruth(boolean truth) { this.truth = truth; @@ -241,7 +241,7 @@ public class PreProcessor { return this.image.equals((String) t); } } catch (ClassNotFoundException e) { - Msg.error(this, "PPToken.equals: " + e.getMessage()); + addParseMessage(null, "PPToken.equals: " + e.getMessage()); } return false; } @@ -288,12 +288,12 @@ public class PreProcessor { } break; default: - Msg.error(this, "Cannot compareToZero Token: " + image + " kind " + kind); + addParseMessage(null, "Cannot compareToZero Token: " + image + " kind " + kind); break; } } catch (Exception e) { - Msg.error(this, "CMP2Zero:Numeric Conversion Error: " + e.getMessage()); + addParseMessage(null, "CMP2Zero:Numeric Conversion Error: " + e.getMessage()); } return comparison; } @@ -317,7 +317,7 @@ public class PreProcessor { PPToken replVal = (PPToken) getDef(this); // not a PPToken if (replVal == null) { replVal = new PPToken(this); - // Msg.error(this, + // addParseMessage(null, // "Missing numeric value for: "+image+" at " // +curFileStackTop // ()+"'"+beginLine+". PreProcessor expects one."); @@ -332,7 +332,7 @@ public class PreProcessor { } catch (Exception e) { thisFP = null; - // Msg.error(this, "Numeric Conversion Error for '" + this.image + // addParseMessage(null, "Numeric Conversion Error for '" + this.image // + "' in " + curFileStackTop() + " line " + that.beginLine + // " : "+e.getMessage()); } @@ -350,7 +350,7 @@ public class PreProcessor { PPToken replVal = (PPToken) getDef(that); // not a PPToken if (replVal == null) { replVal = new PPToken(that); - // Msg.error(this, + // addParseMessage(null, // "Missing numeric value for: "+image+" at " // +curFileStackTop // ()+"'"+beginLine+". PreProcessor expects one."); @@ -365,7 +365,7 @@ public class PreProcessor { } catch (Exception e) { thatFP = null; - // Msg.error(this, "Numeric Conversion Error in " + + // addParseMessage(null, "Numeric Conversion Error in " + // curFileStackTop() + " line " + that.beginLine + // " : "+e.getMessage()); } @@ -499,9 +499,9 @@ public class PreProcessor { image = defs.expand(image, true); } else { int cnt = 0; - for (String string : appendList) { + for (StringBuffer string : appendList) { if (expand && expandList.get(cnt++)) { - image += defs.expand(string, true); + image += defs.expand(string.toString(), true); } else { image += string; } @@ -522,7 +522,7 @@ public class PreProcessor { boolean emitExecSwitch = true; // Hastable for storing #include file names - Hashtable files = new Hashtable(); + HashSet files = new HashSet(); // Stack for keeping shadowed (include) files Stack fileStack = new Stack(); @@ -545,6 +545,11 @@ public class PreProcessor { // times they have been parsed private HashMap alreadyDone; + private StringBuilder parseMessages = new StringBuilder(); + + // true if parse was successful + private boolean parseSuccess = false; + // Toggle printing private int verboseLevel = 0; @@ -700,10 +705,10 @@ public class PreProcessor { } } } catch (FileNotFoundException fene) { - Msg.error(this, fene.getMessage() + " " + incFile); + addParseMessage(incFile.getName(), fene.getMessage()); } if (fis == null) { - // Msg.error(this, + // addParseMessage(null, // "Warning: No relative path to #include \""+def+"\"\nThis is a design/configuration flaw. Trying the standard places..."); standardPlace(inc, xsym); } else { @@ -715,7 +720,7 @@ public class PreProcessor { } } - private void swapFileStreams(File incFile, FileInputStream fis) { + private void swapFileStreams(File incFile, FileInputStream fis) throws ParseException { if (verboseLevel == 2) print(incFile.getAbsolutePath() + "\n"); else if (verboseLevel == 1) @@ -733,10 +738,8 @@ public class PreProcessor { count++; } if (count > 5) { - Msg.error(this, - "Error: Possible infinite inclusion recursion detected: " - + incFile.getAbsolutePath()); - Msg.error(this, fileStack); + addParseMessage(incFile.getAbsolutePath(), + "Error: Possible infinite inclusion recursion detected: \n" + fileStack); return; } } while (pos != -1); @@ -757,14 +760,13 @@ public class PreProcessor { parser.ReInit(fis); parser.Input(); fileStack.pop(); - } catch (ParseException e) { - Msg.error(this, - "PERROR parsing Included File: In " + incFile.getName() - + ": " + e.getMessage()); - Msg.error(this, "PreProcessor Parse Error: " + e.getMessage()); - } catch (TokenMgrError e) { - Msg.error(this, "ERROR parsing Included File: " + incFile.getName()); - Msg.error(this, "PreProcessor Token Error: " + e.getMessage()); + } catch (ParseException e) { + addParseMessage(incFile.getName(), "ERROR parsing Included File: " + e.getMessage()); + throw e; + } + catch (TokenMgrError e) { + addParseMessage(incFile.getName(), "ERROR parsing Included File: " + e.getMessage()); + throw e; } } @@ -834,7 +836,8 @@ public class PreProcessor { FileInputStream fis = null; File iFile = null; int i; - addFile(fn); + + boolean alreadyIncluded = addFile(fn); for (i = 0; i < pathList.size(); i++) { iFile = getFile(pathList.elementAt(i), fn, xsym); // don't include the same file name @@ -853,26 +856,26 @@ public class PreProcessor { fis = getFIS(iFile); } if (fis == null) { - Msg.error(this, "No path to #include " + ft + "\nUse -I option"); - Msg.error(this, " Current Include Path: "); - for (int pi = 0; pi < fileStack.size(); pi++) { - Msg.error(this, " : " + fileStack.get(pi)); + addParseMessage(null, "WARNING: No path to #include " + ft + + " Assuming not needed!" + "\u005cnUse -I option"); + addParseMessage(null, " Current Include Path: "); + for (String element : fileStack) { + addParseMessage(null, " : " + element); } - Msg.error(this, " Assuming not needed"); - // throw new ParseException("No path to #include " + ft - // + "\nUse -I option"); } else { if (verboseLevel == 2) { - print("Line " + inc.beginLine + ": " + curFileStackTop() - + " => "); + print("Line " + inc.beginLine + ": " + curFileStackTop() + " => "); } StringBuffer pad = new StringBuffer(); - for (int padInd = 0; padInd < fileStack.size(); padInd++) + for (String element : fileStack) { pad.append(" "); - Msg.info(this, " " + pad + iFile); + } + if (!alreadyIncluded) { + addParseMessage(null, " " + pad + iFile); + } swapFileStreams(iFile, fis); if (verboseLevel == 1) { - Msg.info(this, "Include depth " + fileStack.size() + ": Done!"); + addParseMessage(null, "Include depth " + fileStack.size() + ": Done!"); } } } @@ -1018,14 +1021,18 @@ public class PreProcessor { fis = new java.io.FileInputStream(lowerFile); } } catch (FileNotFoundException fene) { - Msg.error(this, fene.getMessage() + " " + iFile); + addParseMessage(null, fene.getMessage() + " " + iFile); } return fis; } - // Add an include file to those already included - private void addFile(String file) { - files.put(file, Boolean.TRUE); + // Add an include file to those already included, return true if already included + private boolean addFile(String file) { + if (files.contains(file)) { + return true; + } + files.add(file); + return false; } private void printCommentedLines(boolean emitSwitch, String line, String state) { @@ -1053,10 +1060,10 @@ public class PreProcessor { // Prints out all the files used in parsing the source private void printFiles() { - Enumeration eFiles = files.keys(); + Iterator eFiles = files.iterator(); - while (eFiles.hasMoreElements()) { - Msg.info(this, "PreProcessor: " + eFiles.nextElement()); + while (eFiles.hasNext()) { + addParseMessage(null, "PreProcessor: " + eFiles.next()); } } @@ -1089,8 +1096,7 @@ public class PreProcessor { val = ""; } if (verboseLevel == 3 || verboseLevel == 6) { - System.out.print("Predefining " + key + " to " - + val); + addParseMessage(null, "Predefining " + key + " to " + val); } Token k, v; k = new Token(); @@ -1103,12 +1109,12 @@ public class PreProcessor { PPToken ppv = new PPToken(v); setDef(ppk, ppv); if (verboseLevel == 3 || verboseLevel == 6) { - Msg.info(this, "Defs: containsKey: " + key + " = " - + defs.containsKey(key) + " " + defs.size()); + addParseMessage(null, "Defs: containsKey: " + key + " = " + + defs.containsKey(key) + " " + defs.size()); } } else { if (verboseLevel == 3 || verboseLevel == 6) { - System.out.print("Predefining " + optValue); + addParseMessage(null, "Predefining " + optValue); } Token k = new Token(); k.image = argString.substring(2); @@ -1126,23 +1132,20 @@ public class PreProcessor { try { verboseLevel = Integer.parseInt(optValue, 10); } catch (NumberFormatException nfe) { - Msg.error(this, - "Verbose Level Error: " + nfe.getMessage()); - throw new ParseException("Bad verbosity level " - + optValue); + addParseMessage(null, "Verbose Level Error: " + nfe.getMessage()); + throw new ParseException("Bad verbosity level " + optValue); } continue; // continue loop case 'O': try { setOutputStream(new java.io.FileOutputStream(optValue)); } catch (FileNotFoundException exc) { - Msg.error(this, "Couldn't create file " + optValue); - throw new ParseException("Couldn't create file " - + optValue); + addParseMessage(null, "Couldn't create file " + optValue); + throw new ParseException("Couldn't create file " + optValue); } continue; default: - Msg.error(this, "Unknown option: " + argString); + addParseMessage(null, "Unknown option: " + argString); throw new ParseException("Unknown option: " + argString); } default: @@ -1207,6 +1210,21 @@ public class PreProcessor { throw new NumberFormatException("Couldn't parse number: \'" + str + "\'"); } + private void addParseMessage(String filename, String message) { + if (filename != null) { + parseMessages.append(" In file " + filename + "\n"); + } + parseMessages.append(message + "\n"); + } + + public String getParseMessages() { + return parseMessages.toString(); + } + + public boolean didParseSucceed() { + return parseSuccess; + } + public void setArgs(String[] args) throws ParseException { shift = getopt(args); } @@ -1215,10 +1233,10 @@ public class PreProcessor { outputStream = new PrintStream(fos); } - public void parse(String filename) { + public void parse(String filename) throws ParseException { if (verboseLevel == 1) { - Msg.info(this, "PreProcessor Version 0.0: Reading from file " - + filename + " . . ."); + addParseMessage(null, + "PreProcessor: Reading from file " + filename + " . . ."); } FileInputStream fis = null; @@ -1237,8 +1255,7 @@ public class PreProcessor { } } if (fis == null) { - Msg.error(this, "PreProcessor Version 0.0: File " + filename - + " not found."); + addParseMessage(null, "PreProcessor: File " + filename + " not found."); return; } fileStack.push(filename); @@ -1249,16 +1266,16 @@ public class PreProcessor { fileStack.pop(); if (fileStack.size() == 0) { if (verboseLevel == 1) { - Msg.info(this, - "PreProcessor Version 0.0: Java program parsed successfully."); + addParseMessage(null, + "PreProcessor: Java program parsed successfully."); } } } catch (ParseException e) { - Msg.error(this, "ERROR parsing: " + filename); - Msg.error(this, "PreProcessor Parse Error: " + e.getMessage()); + addParseMessage(filename, "PreProcessor Parse Error: " + e.getMessage()); + throw e; } catch (TokenMgrError e) { - Msg.error(this, "ERROR parsing: " + filename); - Msg.error(this, "PreProcessor Token Error: " + e.getMessage()); + addParseMessage(filename, "PreProcessor Token Error: " + e.getMessage()); + throw e; } } @@ -1284,8 +1301,8 @@ public class PreProcessor { if (args.length - shift == 0) { if (verboseLevel == 1) { - Msg.info(this, - "PreProcessor Version 0.0: Reading from standard input . . ."); + addParseMessage(null, + "PreProcessor: Reading from standard input . . ."); } fileStack.push("stdin"); } else @@ -1302,12 +1319,12 @@ public class PreProcessor { FileInputStream fis = new java.io.FileInputStream(filename); ReInit(fis); } catch (java.io.FileNotFoundException e) { - Msg.error(this, "PreProcessor Version 0.0: File " + filename + addParseMessage(null, "PreProcessor: File " + filename + " not found."); - Msg.error(this, "Usage is one of:"); - Msg.error(this, " java PreProcessor < inputfile ..."); - Msg.error(this, "OR"); - Msg.error(this, " java PreProcessor inputfile ..."); + addParseMessage(null, "Usage is one of:"); + addParseMessage(null, " java PreProcessor < inputfile ..."); + addParseMessage(null, "OR"); + addParseMessage(null, " java PreProcessor inputfile ..."); return; } } @@ -1321,8 +1338,7 @@ public class PreProcessor { try { PreProcessor parser = new PreProcessor(args); } catch (ParseException e) { - System.out - .println("PreProcessor Version 0.0: Encountered errors during parse."); + System.out.println("PreProcessor: Encountered errors during parse."); System.out.println("PreProcessor: " + e.getMessage()); } } @@ -1344,8 +1360,8 @@ void Input() : ( b=TranslationUnit(){if (b.getTruth()==false) break;})* { if (conditionDepth!=execStack.size()) { - Msg.error(this, "Imbalance in sequence/nesting of compile-time conditions/logic in input file "+curFileStackTop()); - Msg.error(this, " " + execStack); + addParseMessage(null, "Imbalance in sequence/nesting of compile-time conditions/logic in input file "+curFileStackTop()); + addParseMessage(null, " " + execStack); // pop off conditionals, so we can get back on track while (conditionDepth != execStack.size() && execStack.size() > 0) { PPToken olde = execStack.pop();; @@ -1439,8 +1455,8 @@ PPToken IFGroup() : { PPToken t, e, olde; } e=ElIf() t=ElseIfCondition(){ e.setTruth(t.getTruth()); if (execStack.size()==0) { - Msg.error(this, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); - throw new ParseException(curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); + addParseMessage(null,curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); + throw new ParseException(curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); } olde = (PPToken) execStack.pop(); emitExecSwitch = olde.getEmitSave(); @@ -1476,7 +1492,7 @@ PPToken IFGroup() : { PPToken t, e, olde; } } | t=Else(){ if (execStack.size()==0) { - Msg.error(this, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); + addParseMessage(null, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); throw new ParseException (curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); } olde = (PPToken) execStack.pop(); @@ -1491,7 +1507,7 @@ PPToken IFGroup() : { PPToken t, e, olde; } } | t=EndIf(){ if (execStack.size()==0) { - Msg.error(this, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); + addParseMessage(null, curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); throw new ParseException(curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); } olde = (PPToken) execStack.pop(); @@ -1550,8 +1566,8 @@ PPToken Include() : {Token t;PPToken pt;int conditionDepth=execStack.size();} } ){ if (conditionDepth!=execStack.size()) { - Msg.error(this, "Imbalance in sequence/nesting of compile-time conditions/logic in included file "+t.image); - Msg.error(this, " " + execStack); + addParseMessage(null, "Imbalance in sequence/nesting of compile-time conditions/logic in included file "+t.image); + addParseMessage(null, " " + execStack); // pop off conditionals, so we can get back on track while (conditionDepth != execStack.size() && execStack.size() > 0) { PPToken olde = execStack.pop(); @@ -1650,17 +1666,18 @@ PPToken UnDef() : {Token t;} PPToken MacroArgs() : {Token t,u=null;} { - t={return new PPToken(t);} + ( + t= | + t= + ) + {return new PPToken(t);} } PPToken MacroVals() : {Token s,t,u=new Token();u.image="";} { (u=Values() | - (LOOKAHEAD(2)(t={u.image+=t.image;} | t= { u.image+="\""+t.image+"\"";}))+ + (LOOKAHEAD(2)(t= {u.image+=t.image;} | t= { t.image="/"; } | t= { u.image+="\""+t.image+"\"";}))+ [LOOKAHEAD(2) (LOOKAHEAD(2)t=Values(){u.image+=t.image;})+ ] -// | -// t={u.image+=t.image;} -// [LOOKAHEAD(2) (LOOKAHEAD(2)t=Values(){u.image+=t.image;})+ ] ) {return new PPToken(u);} } @@ -1719,8 +1736,8 @@ PPToken Error() : {Token t;} { t={ if (emitExecSwitch==true) { - Msg.error(this, curFileStackTop()+"'"+t.beginLine+" Compiler Error:"); - Msg.error(this, t.image); + addParseMessage(null, curFileStackTop()+"'"+t.beginLine+" Compiler Error:"); + addParseMessage(null, t.image); } return new PPToken(t); } @@ -1730,8 +1747,8 @@ PPToken Warning() : {Token t;} { t={ if (emitExecSwitch==true) { - Msg.error(this, curFileStackTop()+"'"+t.beginLine+" Warning: "); - Msg.error(this, t.image); + addParseMessage(null, curFileStackTop()+"'"+t.beginLine+" Warning: "); + addParseMessage(null, t.image); } return new PPToken(t); } @@ -1788,7 +1805,9 @@ PPToken Values() : t.kind = getNumericType(t.image); }| t=QuotedValue() | -// t= | + t= { + t.image = "/"; + } | t= ){ PPToken pt=new PPToken(t); @@ -1808,22 +1827,22 @@ PPToken Text() : { ( LOOKAHEAD(3) (LOOKAHEAD(2)(u={ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); } - (LOOKAHEAD(2)nl=NewLines(){if (emitExecSwitch==true) buf.append(nl.image,false); else buf.append((u.image.length() == 0 ? "//// " : "") + nl.image, false); } )*| + (LOOKAHEAD(2)nl=NewLines(){if (emitExecSwitch==true) buf.append(nl.image,true); else buf.append((u.image.length() == 0 ? "//// " : "") + nl.image, false); } )* | - u={if (emitExecSwitch==true) buf.append(u.image,true);} ) - [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }] - [LOOKAHEAD(2)u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true);}] - [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image, true); } - (LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image, false);})*])+| + u={if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); } ) + [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }] + [LOOKAHEAD(2)u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false);}] + [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image, true); else buf.append("//// " + u.image, false); } + (LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image, true); else buf.append("//// " + u.image, false);})*])+| - (LOOKAHEAD(2)(u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true);} - [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }]| - u={if (emitExecSwitch==true) buf.append(u.image,true);}) - [LOOKAHEAD(2)t=NewLines(){ if (emitExecSwitch==true) buf.append(t.image,false); }] - [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image,true);}] - [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }])+ | + (LOOKAHEAD(2)(u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); } + [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }]| + u={if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }) + [LOOKAHEAD(2)t=NewLines(){ if (emitExecSwitch==true) buf.append(t.image,true); else buf.append("//// " + u.image, false); }] + [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }] + [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); }])+ | - u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); } + u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); } ) { return buf;} } @@ -1938,23 +1957,6 @@ PPToken LogicalAndExpression() : ){return t;} } -/*** -PPToken EqualityExpression() : -{PPToken t,u,v;} -{ - (t=RelationalExpression() - ( LOOKAHEAD(2) - u=EqualTo(){ - if (verboseLevel()==7) print(u.image); - } - v=RelationalExpression(){ - t.setTruth(t.compareTo(v)==0); - if (verboseLevel()==7) print(": "); - })* - ){return t;} -} -***/ - PPToken EqualityExpression() : {PPToken t,u,v;} { @@ -2377,7 +2379,7 @@ SKIP: //MORE: SKIP: { - <_LCMT: "//" > : SpecialEOLComment | + <_LCMT: "/" "/" > : SpecialEOLComment | <_CMT: () > : SpecialBlockComment } @@ -2631,7 +2633,7 @@ TOKEN : { TOKEN : { - ()+ > : DEFAULT | + ()* > : DEFAULT | > : DEFAULT } @@ -2643,7 +2645,7 @@ SKIP : { TOKEN : { - ( | ( "/" ) )+ > : DEFAULT | + ( | ( "/" ) )* > : DEFAULT | > : DEFAULT } @@ -2655,7 +2657,7 @@ SKIP : { TOKEN : { - ( | ( "/" ) )+ > : DEFAULT | + ( | ( "/" ) )* > : DEFAULT | > : DEFAULT } @@ -2679,7 +2681,7 @@ SKIP : { TOKEN : { - ()+ > : DEFAULT | + ()* > : DEFAULT | > : DEFAULT } @@ -2690,7 +2692,7 @@ SKIP : { TOKEN : { - ()+ > : DEFAULT | + ()* > : DEFAULT | > : DEFAULT } @@ -2765,13 +2767,19 @@ SKIP : { TOKEN : { - | | () | (["\\"] ~[" ","\n","\r"]) )+ > : RVALUES | + | + | + () | + ("'" ((~["\n","\r","\\"]) | ("\\" ~["\n","\r"] ) ) "'") | + (["\\"] ~[" ","\n","\r"]) + )+ > : RVALUES | + > : DEFAULT | > } SKIP : { - <_ECMT7: (~["*"] | "*" ~["/"])* > : RVALUES_COMMENT | + <_ECMT7: ~["*"] | "*" ~["/"] > : RVALUES_COMMENT | <_EECMT7: > : RVALUES } @@ -2784,13 +2792,13 @@ SKIP: TOKEN: { - : QUOTED_VAL + : QUOTED_VAL } TOKEN : { - > - // > + > | + "]" > } @@ -2816,7 +2824,8 @@ TOKEN : { TOKEN : { - | | ("\\" ~[" ","\t","\\","\n","\r"]))+ > : MACROVALS + | | ("\\" ~[" ","\t","\\","\n","\r"]))+ > : MACROVALS | + > : DEFAULT } @@ -2844,7 +2853,7 @@ TOKEN: SKIP : { - <_ECMT9: (~["*"] | "*" ~["/"])* > : MACROVALS_COMMENT | + <_ECMT9: ~["*"] | "*" ~["/"] > : MACROVALS_COMMENT | <_EEECMT9: > : MACROVALS | <_EECMT9: ()* > : DEFAULT } 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 f61baba65c..97a867e30f 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 @@ -17,6 +17,7 @@ package ghidra.app.util.cparser; import static org.junit.Assert.*; +import java.io.File; import java.io.InputStream; import java.util.ArrayList; @@ -126,26 +127,43 @@ public class CParserTest extends AbstractGenericTest { @Test public void testHeaderParsing() throws Exception { + DataTypeManager dtMgr; + CParser parser; + + parser = new CParser(); // Uncomment to save the parse results to a GDT file to check out // // File fgdt = new File("/tmp/CParserTest.gdt"); // fgdt.delete(); -// FileDataTypeManager fdt = FileDataTypeManager.createFileArchive(fgdt); -// CParser parser = new CParser(fdt, true, null); -// DataTypeManager dtMgr = fdt; - - CParser parser = new CParser(); +// FileDataTypeManager fdt = FileDataTypeManager.createFileArchive(fgdt); +// parser = new CParser(fdt, true, null); String resourceName; resourceName = "CParserTest.h"; InputStream is = CParserTest.class.getResourceAsStream(resourceName); - // resourceName = "/home/mjtiern/CParserPlugin.out.sav"; - // is = new FileInputStream(new File(resourceName)); + parser.setParseFileName("CParserTest.h"); parser.parse(is); - DataTypeManager dtMgr = parser.getDataTypeManager(); + dtMgr = parser.getDataTypeManager(); + +// Uncomment to save the parse results to a GDT file to check out +// +// fdt.save(); +// fdt.close(); + + String parseMessages = parser.getParseMessages(); + System.out.println(parseMessages); + + assertTrue("Duplicate ENUM message", parseMessages.contains("duplicate enum value: options_enum : PLUS_SET : 16")); + + assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"math fail!\"\"")); + + assertTrue("Duplicate ENUM message", parseMessages.contains("Static_Asssert has failed \"\"1 + 1 == 3, fail!\"\"")); DataType dt; + DataType pointedToDT; + ParameterDefinition[] funcArgs; + FunctionDefinition funcDef; String str; dt = dtMgr.getDataType(new CategoryPath("/"), "_IO_FILE_complete"); @@ -153,12 +171,67 @@ public class CParserTest extends AbstractGenericTest { DataTypeComponent data3 = sldt.getComponent(2); assertEquals("Computed Array correct", 40, data3.getLength()); + dt = dtMgr.getDataType(new CategoryPath("/"), "fnptr"); // typedef int (*fnptr)(struct fstruct); // "fnptr" named typedef of pointer to "int fnptr(fstruct )" --- should an anonymous function name be used? + assertTrue("typedefed fnptr", dt instanceof TypeDef); + dt = ((TypeDef) dt).getDataType(); + assertTrue("typedef fnptr *", dt instanceof Pointer); + dt = ((Pointer) dt).getDataType(); + assertTrue("typedef fnptr *", dt instanceof FunctionDefinition); + funcDef = (FunctionDefinition) dt; + funcArgs = funcDef.getArguments(); + assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Structure); + str = funcDef.getPrototypeString(); + assertEquals("signature not correct", "int fnptr(fstruct )", replaceAnonFuncName(str)); + + // Test dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Once"); // void __cdecl _Once(_Once_t *, void (__cdecl *)(void)); - // void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymouse function * --> void (__cdecl *)(void) + // void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymous function * --> void (__cdecl *)(void) + assertTrue("_Once function definition", dt instanceof FunctionDefinition); + funcDef = (FunctionDefinition) dt; + str = funcDef.getPrototypeString(); + assertEquals("signature not correct", "void _Once(_Once_t * , _func_anon_ * )", replaceAnonFuncName(str)); + assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName()); + funcArgs = funcDef.getArguments(); + assertTrue("struct fstruct", funcArgs[0].getDataType() instanceof Pointer); + assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer); + pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType(); + assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); + funcDef = (FunctionDefinition) pointedToDT; + assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName()); + str = funcDef.getPrototypeString(); + assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str)); + dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Twice"); // void __cdecl _Once(_Once_t *, void (__cdecl *)(void)); + // void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymous function * --> void (__cdecl *)(void) + assertTrue("_Twice function definition", dt instanceof FunctionDefinition); + funcDef = (FunctionDefinition) dt; + str = funcDef.getPrototypeString(); + assertEquals("calling convention _Twice", "__stdcall", funcDef.getGenericCallingConvention().getDeclarationName()); + funcArgs = funcDef.getArguments(); + pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType(); + assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); + funcDef = (FunctionDefinition) pointedToDT; + assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName()); + str = funcDef.getPrototypeString(); + assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str)); + + dt = dtMgr.getDataType(new CategoryPath("/functions"), "_Thrice"); // void __cdecl _Once(_Once_t *, void (__cdecl *)(void)); + // void _Once(_Once_t * , void * ) ---- 2nd param should be an anonymous function * --> void (__cdecl *)(void) + assertTrue("_Twice function definition", dt instanceof FunctionDefinition); + funcDef = (FunctionDefinition) dt; + str = funcDef.getPrototypeString(); + assertEquals("calling convention _Thrice", "", funcDef.getGenericCallingConvention().getDeclarationName()); + funcArgs = funcDef.getArguments(); + pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType(); + assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); + funcDef = (FunctionDefinition) pointedToDT; + assertEquals("calling convention _Once", "__cdecl", funcDef.getGenericCallingConvention().getDeclarationName()); + str = funcDef.getPrototypeString(); + assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str)); + dt = dtMgr.getDataType(new CategoryPath("/"), "UShortInt"); assertTrue(dt instanceof TypeDef); assertTrue("signature not correct", @@ -320,14 +393,125 @@ public class CParserTest extends AbstractGenericTest { assertTrue("not a function", dt instanceof FunctionDefinition); str = ((FunctionDefinition) dt).getPrototypeString(); assertEquals("signature not correct", "int fputs(char * , void * )", str); + + dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParam"); + assertTrue("not a function", dt instanceof FunctionDefinition); + str = ((FunctionDefinition) dt).getPrototypeString(); + + + assertEquals("signature not correct", "void funcParam(_func_anon_ * )", replaceAnonFuncName(str)); + funcDef = (FunctionDefinition) dt; + funcArgs = funcDef.getArguments(); + assertTrue("ptr", funcArgs[0].getDataType() instanceof Pointer); + pointedToDT = ((Pointer) funcArgs[0].getDataType()).getDataType(); + assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); + str = ((FunctionDefinition) pointedToDT).getPrototypeString(); + assertEquals("signature not correct", "void _func_anon_(void)", replaceAnonFuncName(str)); + for (int i=1; i < 11; i++) { + dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParam"+i); + assertTrue("not a function" + dt.getName(), dt instanceof FunctionDefinition); + str = ((FunctionDefinition) dt).getPrototypeString(); + funcDef = (FunctionDefinition) dt; + funcArgs = funcDef.getArguments(); + assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer); + pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType(); + assertTrue("ptr not to a function " + dt.getName(), pointedToDT instanceof FunctionDefinition); + funcArgs = ((FunctionDefinition) pointedToDT).getArguments(); + assertEquals("function args != 1 " + pointedToDT, 1, funcArgs.length); + assertEquals("double", funcArgs[0].getDataType().getName()); + } + + dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParamNoPtr"); + assertTrue("not a function", dt instanceof FunctionDefinition); + str = ((FunctionDefinition) dt).getPrototypeString(); + assertEquals("signature not correct", "double funcParamNoPtr(double x, func * func)", str); + funcDef = (FunctionDefinition) dt; + funcArgs = funcDef.getArguments(); + assertTrue("ptr", funcArgs[1].getDataType() instanceof Pointer); + pointedToDT = ((Pointer) funcArgs[1].getDataType()).getDataType(); + assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); + str = ((FunctionDefinition) pointedToDT).getPrototypeString(); + assertEquals("signature not correct", "double func(double , void * )", str); + + dt = dtMgr.getDataType(new CategoryPath("/functions"), "funcParmWithName"); + assertTrue("not a function", dt instanceof FunctionDefinition); + str = ((FunctionDefinition) dt).getPrototypeString(); + assertEquals("signature not correct", "void funcParmWithName(_func_arg * _func_arg)", str); + + dt = dtMgr.getDataType(new CategoryPath("/functions"), "__mem_func"); + assertTrue("not a function", dt instanceof FunctionDefinition); + str = ((FunctionDefinition) dt).getPrototypeString(); + assertEquals("signature not correct", "void __mem_func(" + + "void * ," + + " char * * ," + + " int * * * ," + + " _func_anon_ * ," + + " _func_anon_1 * ," + + " _func_anon_2 * )", replaceAnonFuncName(str)); + funcDef = (FunctionDefinition) dt; + funcArgs = funcDef.getArguments(); + assertTrue("ptr", funcArgs[5].getDataType() instanceof Pointer); + pointedToDT = ((Pointer) funcArgs[5].getDataType()).getDataType(); + assertTrue("ptr not to a function", pointedToDT instanceof FunctionDefinition); + str = ((FunctionDefinition) pointedToDT).getPrototypeString(); + assertEquals("signature not correct", "void * _func_anon_(void * , size_t )", replaceAnonFuncName(str)); + // ensure that temporary anonymous function definition names did not get retained ArrayList list = new ArrayList<>(); dtMgr.findDataTypes("_func_", list); assertTrue(list.isEmpty()); dtMgr.findDataTypes("_func_1", list); - assertTrue(list.isEmpty()); + assertTrue( + "Expected anonymous function replaced (is blarg first function in CParserTest.h file?):" + + list, + list.isEmpty()); + dt = dtMgr.getDataType(new CategoryPath("/functions"), "blarg"); + assertTrue("named function blarg", dt instanceof FunctionDefinition); + str = ((FunctionDefinition) dt).getPrototypeString(); + assertEquals("signature not correct", "void blarg(int * , long[0][0] * )", replaceAnonFuncName(str)); + // Structure extension + dt = dtMgr.getDataType(new CategoryPath("/"), "System_System_SystemException_Fields"); + assertTrue (dt instanceof Structure); + sdt = (Structure) dt; + comp = sdt.getComponent(1); + assertEquals("foo", comp.getFieldName()); + comp = sdt.getComponent(2); + assertEquals("bar", comp.getFieldName()); + assertEquals("short", comp.getDataType().getName()); + comp = sdt.getComponent(0); + assertTrue (comp.getDataType() instanceof Structure); + assertEquals ("extended parent ", "System_SystemException_Fields", comp.getDataType().getName()); + sdt = (Structure) comp.getDataType(); + comp = sdt.getComponent(0); + assertTrue (comp.getDataType() instanceof Structure); + assertEquals ("extended parent ", "System_Exception_Fields", comp.getDataType().getName()); + + + // Check arrays of functions in structures + dt = dtMgr.getDataType(new CategoryPath("/"), "SomeStruct"); + assertTrue (dt instanceof Structure); + sdt = (Structure) dt; + + int numComponents = sdt.getNumComponents(); + assertEquals("Number of components in struct arrays of function pointer + \n" + sdt.toString(), + 8, numComponents); + + DataTypeComponent component = sdt.getComponent(2); + assertEquals("procArray1", component.getFieldName()); + dt = component.getDataType(); + assertTrue("procArray1 member is a an array", dt instanceof Array); + assertEquals("ProcArray1 member bad size", 2, ((Array) dt).getNumElements()); + dt = ((Array) dt).getDataType(); + assertTrue("ProcArray1 is not an Array of pointers", dt instanceof Pointer); + dt = ((Pointer) dt).getDataType(); + assertTrue("procArray1 member is Array of function pointers", dt instanceof FunctionDefinition); + funcDef = (FunctionDefinition) dt; + funcArgs = funcDef.getArguments(); + str = funcDef.getPrototypeString(); + assertEquals("signature not correct", "char _func_anon_(int * , short * )", replaceAnonFuncName(str)); + dt = dtMgr.getDataType(new CategoryPath("/"), "EmptyBuffer"); assertTrue(dt instanceof Structure); sdt = (Structure) dt; @@ -389,7 +573,6 @@ public class CParserTest extends AbstractGenericTest { assertTrue(dt instanceof Structure); sdt = (Structure) dt; assertEquals("Default packing", false, sdt.hasExplicitPackingValue()); - assertEquals("Default packing", true, sdt.hasDefaultPacking()); // data type after #pragma got parsed dt = dtMgr.getDataType("/functions/dtAfterPragma"); // typedef int (*fnptr)(struct fstruct); @@ -445,6 +628,19 @@ public class CParserTest extends AbstractGenericTest { cdt = sdt.getComponent(1); assertTrue(cdt.getDataType() instanceof Array); assertEquals("Array field defined with sizeof typedef", 2084, cdt.getLength()); + } + private String replaceAnonFuncName(String str) { + int num = 0; + String replStr = str; + String origStr = null; + + while (!replStr.equals(origStr)) { + origStr = replStr; + replStr = replStr.replaceFirst("_func_([0-9])+", "_func_anon_" + (num == 0 ? "" : num)); + num++; + } + + return replStr; } } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java index 7a29cb859b..326b1f6f50 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java @@ -30,13 +30,14 @@ import ghidra.program.model.data.Enum; public class PreProcessorTest extends AbstractGenericTest { private static String resourceName = "PreProcessorTest.h"; - private static CategoryPath path = new CategoryPath(new CategoryPath("/PreProcessorTest.h"), "defines"); - + private static CategoryPath path = + new CategoryPath(new CategoryPath("/PreProcessorTest.h"), "defines"); + // must get rid of after all tests private static StandAloneDataTypeManager dtMgr; private static ByteArrayOutputStream baos = new ByteArrayOutputStream(); private static PreProcessor parser; - + long value; String defname; @@ -47,8 +48,9 @@ public class PreProcessorTest extends AbstractGenericTest { @BeforeClass public static void init() { URL url = PreProcessorTest.class.getResource(resourceName); - - String[] args = new String[] {"-I"+url.getPath()+"/..","-DFROM_ARG_VALUE=300", "-DFROM_ARG_DEF", "-DFROM_ARG_EMPTY=\"\""}; + + String[] args = new String[] { "-I" + url.getPath() + "/..", "-DFROM_ARG_VALUE=300", + "-DFROM_ARG_DEF", "-DFROM_ARG_EMPTY=\"\"" }; parser = null; try { parser = new PreProcessor(args); @@ -73,34 +75,39 @@ public class PreProcessorTest extends AbstractGenericTest { //// fullName = "adoguids.h"; //// parser.parse(fullName); - parser.parse(url.getFile()); + try { + parser.parse(url.getFile()); + } + catch (ParseException e) { + e.printStackTrace(); + } // Uncomment to print out parse results // System.err.println(baos.toString()); dtMgr = new StandAloneDataTypeManager("parsed"); - parser.getDefinitions().populateDefineEquates(dtMgr); + parser.getDefinitions().populateDefineEquates(null, dtMgr); } - + @AfterClass public static void destroy() { dtMgr = null; baos = null; parser = null; } - + @Test public void testHeaderParsed() throws Exception { - + String results = baos.toString("ASCII"); int end = results.lastIndexOf(";") + 1; String endStr = results.substring(end - 9, end); assertEquals("theEnd();", endStr); - + assertTrue("macro expansion _fpl(bob) failed ", results .indexOf("extern int __declspec(\"fp(\\\"l\\\", \" #bob \")\") __ifplbob;") != -1); } - + @Test public void testDefines() throws Exception { long value; @@ -160,7 +167,7 @@ public class PreProcessorTest extends AbstractGenericTest { defname = "isDefineOnValue"; value = 1; checkDefine(dtMgr, path, value, defname); - + defname = "DID_EXPANSION"; value = 1; checkDefine(dtMgr, path, value, defname); @@ -168,33 +175,32 @@ public class PreProcessorTest extends AbstractGenericTest { defname = "BIGNUM"; value = 64 * 16 + 16; checkDefine(dtMgr, path, value, defname); - + defname = "NEWLINETEST1"; value = 1; checkDefine(dtMgr, path, value, defname); - + defname = "NEWLINETEST2"; value = 2; checkDefine(dtMgr, path, value, defname); - + defname = "NEWLINETEST3"; value = 3; checkDefine(dtMgr, path, value, defname); - - + defname = "SEPERATORC"; String defval = parser.getDef(defname); assertEquals(defval, "','"); } - + @Test public void testDefinesArgValue() { defname = "DID_ARG_VALUE"; value = 1; checkDefine(dtMgr, path, value, defname); - + // This is from a -D arg define, not from a file - CategoryPath argCategoryPath = new CategoryPath(CategoryPath.ROOT, "defines"); + CategoryPath argCategoryPath = new CategoryPath(CategoryPath.ROOT, "defines"); defname = "FROM_ARG_VALUE"; value = 300; checkDefine(dtMgr, argCategoryPath, value, defname); @@ -207,6 +213,13 @@ public class PreProcessorTest extends AbstractGenericTest { checkDefine(dtMgr, path, value, defname); } + @Test + public void testQuotedQuote() { + defname = "TEST_QUOTED_QUOTE"; + String defval = parser.getDef(defname); + assertEquals(defval, "QUOTED('\"')"); + } + @Test public void testDefinesArgDef() { defname = "DID_ARG_DEF"; @@ -276,30 +289,45 @@ public class PreProcessorTest extends AbstractGenericTest { value = 1; checkDefine(dtMgr, path, value, defname); } - + @Test public void testMultipleInclude() { defname = "INCLUDE1"; String defval = parser.getDef(defname); assertNotNull("Had 1 duplicate include", defval); - + defname = "INCLUDE2"; defval = parser.getDef(defname); assertNotNull("Had 2 duplicate include", defval); - + defname = "INCLUDE3"; defval = parser.getDef(defname); assertNotNull("Had 3 duplicate include", defval); - + defname = "INCLUDE4"; defval = parser.getDef(defname); assertNotNull("Had 4 duplicate include", defval); - + defname = "INCLUDE5"; defval = parser.getDef(defname); // if a define is not defined, getDef() returns name of define as value assertEquals("No INCLUDE5 define", "INCLUDE5", defval); } + + @Test + public void testVarags() { + defname = "EPRINTF_VARARGS"; + String defval = parser.getDef(defname); + assertEquals("fprintf (stderr, \"%s:%d: \", input_file, lineno)", defval); + + defname = "VPRINTF_NO_ARGS"; + defval = parser.getDef(defname); + assertEquals("fprintf (stderr, \"no args!\\n\" )", defval); + + defname = "VPRINTF_ARGS"; + defval = parser.getDef(defname); + assertEquals("fprintf (stderr, \"%s!\\n\" , \"I have args\")", defval); + } private void checkDefine(StandAloneDataTypeManager dtMgr, CategoryPath path, long value, String defname) { diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java index dfbc57331e..f203f1e15a 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/AbstractCompositeTest.java @@ -58,6 +58,7 @@ abstract class AbstractCompositeTest extends AbstractGTest { throw new FileNotFoundException("Resource not found: " + headerResourcePath); } // Msg.debug(this, "Parsing C headers from " + headerResourcePath); + parser.setParseFileName(headerResourcePath); parser.parse(is); } 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 0022096044..2af9d8710e 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 @@ -17,8 +17,78 @@ /** Test parsing header file for CParser. Most of the file is just checked to make sure it gets through parsing. ** Some data types are checked. More checking of the parsed information would be beneficial at some point. **/ + +/** + * Check initial anonymous __func_1, is give an name blarg + * Note: This must be first function for junit tests to pass + **/ + +void blarg(int *, long[][][]); - void blarg(int *); + /** + * Test arrays of anonymous functions in a structure + **/ +typedef struct SomeStruct { + int first_member; + int *second_member[3]; + char (*procArray1[2])(int *, short *); + int anotherMember; + int (*procArray2[2])(int *, int *); + int (*LoneProc1)(char, int); + int (*LoneProc2)(char, int); + int finalMember; +} SomeStruct; + + +/** + * Anonymous function parameter definitions + **/ +void funcParam(void (*)(void)); + +void funcParmWithName(void (*_func_arg)(void)); + +double funcParamNoPtr(double x, double func(double, void *)); + +double funcParam1( double, double (*)( double ) ); +double funcParam2( double, double( double ) ); // this guy _func_ +double funcParam3( const double, double (*)( double ) ); +double funcParam4( const double, double( double ) ); // this guy _func_ +double funcParam5( double, double (*)( const double ) ); +double funcParam6( double, double( const double ) ); // this guy _func_ +double funcParam7( const double, double (*)( const double ) ); +double funcParam8( const double, double( const double ) ); // this guy _func_ +double funcParam9(double, double (* const)(double ) ); +double funcParam10(double, double (__cdecl *)(double ) ); + + +typedef unsigned int size_t; + +typedef unsigned long size_t; + +void* __cdecl memset( + void* _Dst, + int _Val, + size_t _Size + ); + +typedef size_t rsize_t; + +static __inline int __cdecl memcpy_s( + void* const _Destination, + rsize_t const _DestinationSize, + void const* const _Source, + rsize_t const _SourceSize + ) { + if (_SourceSize == 0) + { + return 0; + } + memset(_Destination, 0, _DestinationSize); +} + + void __mem_func (void *, char **, int ***, long (*) (size_t), + short *(*) (size_t), + void *(*) (void *, size_t)); void * foo; @@ -28,6 +98,12 @@ typedef int pid_t; +typedef long _Once_t; +void __cdecl _Once(_Once_t *, void (__cdecl *)(void)); + +void __stdcall _Twice(void (__cdecl *)(void)); + +void _Thrice(void (__cdecl *)(void)); /** ** use of long as an attribute @@ -51,6 +127,7 @@ int (__stdcall * GetSectionBlock) ( long align=1, void **ppBytes=0) ; + #pragma region Input compatibility macros #pragma warning(disable) @@ -59,6 +136,9 @@ int (__stdcall * GetSectionBlock) ( #pragma section(".CRTMP$XCA",long,read) +#pragma GCC poison (*(volatile uint8_t *)(0xB3)) + + #pragma our macros nachos (for use only within FileProvider.h) /** ** Packing tests @@ -231,8 +311,32 @@ int fputs( char * , void * ) __asm("_" "fputs" "$FPOOTS"); void _exit(int) __attribute__((noreturn)); +// C11 noreturn +void _Noreturn _Noreturn_exit(int); + + + + +// C23 Attributes +int [[deprecated]] imDeprecated(int); +int [[gnu::deprecated]] imDeprecatedToo(int) ; +int [[deprecated("bad design")]] imDeprecatedToo(int) ; +int [[deprecated("bad design")]] imDeprecatedToo(int) ; + +[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]] +int f(void); // declare f with four attributes + +[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]] +int f(void); // same as above, but uses a single attr specifier that contains four attributes + + +// __attribute__ int abs(int) __attribute__((bob)); +enum __attribute__((enum_extensibility(open))) OpenEnum { + B0, B1 +}; + typedef int (__cdecl * _onexit_t)(void); typedef int int32_t; @@ -249,6 +353,23 @@ __checkint(int val, int* err) { return (int32_t) val; } + +/** + ** Structure extension + **/ +struct __declspec(align(8)) System_Exception_Fields { + int _HResult; +}; + +struct System_SystemException_Fields : System_Exception_Fields { + int foo; +}; + +struct System_System_SystemException_Fields : System_SystemException_Fields { + int foo; + short bar; +}; + typedef enum {} EmptyEnum; @@ -284,11 +405,17 @@ struct fowstruct { fstruct *next; }; + @protocol Bubba bob marley @end +@protocol SwiftProtocol +@required +- (void) method; +@end + typedef struct __attribute__ ((packed)) { int test1; @@ -477,6 +604,8 @@ typedef union __declspec(intrin_type) __declspec(align(8)) __m64 unsigned __int32 m64_u32[2]; } __m64; + + extern __m64 _mm_loadh_pi1(__m64, const __m64 *); extern __m64 _mm_loadh_pi2(__m64, __m64 const *); @@ -679,6 +808,10 @@ enum options_enum { ONE_UP, PLUS_SET = 4 + 12, + + PLUS_SET = 4 + 12, + +#pragma endit MINUS_SET = 12 - 1, @@ -744,6 +877,28 @@ struct s fs_pi = (struct s){ .z = "Pi", .x = 3, .y = 3.1415 }; struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2 }; +/** + ** _Alignas + **/ + + // every object of type struct data will be aligned to 128-byte boundary +struct data { + char x; + _Alignas(128) char cacheline[128]; // over-aligned array of char, + // not array of over-aligned chars +}; + +int aligning(void) +{ + int sof = sizeof(struct data); + int aof = _Alignof(struct data); + + printf("sizeof(data) = %zu \n", sizeof(struct data)); + + printf("alignment of data = %zu\n", _Alignof(struct data)); + + _Alignas(2048) struct data d; // this instance of data is aligned even stricter +} typedef long long LRESULT; @@ -923,6 +1078,7 @@ char lineInFunc(int i) { /** ** Check _Static_assert support **/ +#line 1 "static_assert.h" int check_assert(void) { // test with message @@ -933,4 +1089,16 @@ int check_assert(void) _Static_assert(sizeof(int) < sizeof(char)); static_assert(sizeof(int) < sizeof(char)); + int x; + static_assert(sizeof(int) > sizeof(char)); } + +struct statcheck { + int a; + static_assert(1 + 1 == 3, "1 + 1 == 3, fail!"); + int b; +}; + +typedef int test_before; +static_assert(1 + 1 == 2, "That's true!"); +typedef int test_after; diff --git a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h index 48846d6434..27f2c0819e 100644 --- a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h +++ b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h @@ -13,6 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + + /* test define symbols of length 1 */ + #ifdef a + #undef a + #endif /* definition coming from -D, should evaluate to true */ #if FROM_ARG_VALUE @@ -183,6 +188,12 @@ int TEST_FAILED; #define O_M 0xffff0000 // test commment #define N_V 0x60010001 // test comment +#if 0 /* comment + */ +# define DefineNameSlash ?? * / +# define DefineMacroSlash(aba) aba ?? * / +#endif + #define K 0x06010000 /** @@ -381,6 +392,22 @@ ldp LDP(( _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wmismatched-tags\"") +/** + ** Vararg defined + **/ + # define SETIT(value, [attributes]) + + +#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__) + +#define EPRINTF_VARARGS eprintf ("%s:%d: ", input_file, lineno) + +#define vprintf(format, ...) \ + fprintf (stderr, format __VA_OPT__(,) __VA_ARGS__) + +#define VPRINTF_NO_ARGS vprintf ("no args!\n") +#define VPRINTF_ARGS vprintf ("%s!\n", "I have args") + #if defined(__has_include) #if __has_include() @@ -419,4 +446,9 @@ int does_not_has_include(); #endif // 5 blank lines above +// test single quoted qoutes +#define BEGINC QUOTED('"') +#define TEST_QUOTED_QUOTE QUOTED('"') + + theEnd(); diff --git a/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java b/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java new file mode 100644 index 0000000000..121d95c7dd --- /dev/null +++ b/Ghidra/Processors/Atmel/ghidra_scripts/CreateAVR8GDTArchiveScript.java @@ -0,0 +1,462 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// +// Parses AVR8 header files and extracts special memory definitions for each processor variant +// +// Defined enums can be applied to the program and the enum value is interpreted as an address, and the +// name of the enum the label at that addres. +// +//@category Data Types + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +import org.bouncycastle.util.Arrays; + +import generic.jar.ResourceFile; +import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility; +import ghidra.app.script.GhidraScript; +import ghidra.app.util.cparser.C.CParserUtils; +import ghidra.app.util.cparser.CPP.DefineTable; +import ghidra.app.util.cparser.CPP.ParseException; +import ghidra.app.util.cparser.CPP.PreProcessor; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.FileDataTypeManager; +import ghidra.program.util.AddressEvaluator; +import ghidra.util.Msg; + +public class CreateAVR8GDTArchiveScript extends GhidraScript { + + private File outputDirectory; + + private static String headerFilePath = "/data/HeaderFiles"; + + private static String filenames[] = { + "stdint.h", + "avr/io.h", + }; + + private static String orig_args[] = { + "-I"+headerFilePath+"/avr/include", + "-I"+headerFilePath+"/avr/include/avr", + "-D__STDC", + "-D_GNU_SOURCE", + "-D__GLIBC_HAVE_LONG_LONG=1", + "-D__DOXYGEN__=true", // header files have special __attributes__ if not defined + }; + + private static String processorVariants[] = { + "AT94K", + "AT43USB320", + "AT43USB355", + "AT76C711", + "AT86RF401", + "AT90PWM1", + "AT90PWM2", + "AT90PWM2B", + "AT90PWM3", + "AT90PWM3B", + "AT90PWM216", + "AT90PWM316", + "AT90PWM161", + "AT90PWM81", + "ATmega8U2", + "ATmega16M1", + "ATmega16U2", + "ATmega16U4", + "ATmega32C1", + "ATmega32M1", + "ATmega32U2", + "ATmega32U4", + "ATmega32U6", + "ATmega64C1", + "ATmega64M1", + "ATmega128", + "ATmega128A", + "ATmega1280", + "ATmega1281", + "ATmega1284", + "ATmega1284P", + "ATmega128RFA1", + "ATmega1284RFR2", + "ATmega128RFR2", + "ATmega2564RFR2", + "ATmega256RFR2", + "ATmega2560", + "ATmega2561", + "AT90CAN32", + "AT90CAN64", + "AT90CAN128", + "AT90USB82", + "AT90USB162", + "AT90USB646", + "AT90USB647", + "AT90USB1286", + "AT90USB1287", + "ATmega644RFR2", + "ATmega64RFR2", + "ATmega64", + "ATmega64A", + "ATmega640", + "ATmega644", + "ATmega644A", + "ATmega644P", + "ATmega644PA", + "ATmega645", + "ATmega645A", + "ATmega645P", + "ATmega6450", + "ATmega6450A", + "ATmega6450P", + "ATmega649", + "ATmega649A", + "ATmega6490", + "ATmega6490A", + "ATmega6490P", + "ATmega649P", + "ATmega64HVE", + "ATmega64HVE2", + "ATmega103", + "ATmega32", + "ATmega32A", + "ATmega323", + "ATmega324P", + "ATmega324A", + "ATmega324PA", + "ATmega325", + "ATmega325A", + "ATmega325P", + "ATmega325PA", + "ATmega3250", + "ATmega3250A", + "ATmega3250P", + "ATmega3250PA", + "ATmega328P", + "ATmega328", + "ATmega329", + "ATmega329A", + "ATmega329P", + "ATmega329PA", + "ATmega3290PA", + "ATmega3290", + "ATmega3290A", + "ATmega3290P", + "ATmega32HVB", + "ATmega32HVBREVB", + "ATmega406", + "ATmega16", + "ATmega16A", + "ATmega161", + "ATmega162", + "ATmega163", + "ATmega164P", + "ATmega164A", + "ATmega164PA", + "ATmega165", + "ATmega165A", + "ATmega165P", + "ATmega165PA", + "ATmega168", + "ATmega168A", + "ATmega168P", + "ATmega168PA", + "ATmega168PB", + "ATmega169", + "ATmega169A", + "ATmega169P", + "ATmega169PA", + "ATmega8HVA", + "ATmega16HVA", + "ATmega16HVA2", + "ATmega16HVB", + "ATmega16HVBREVB", + "ATmega8", + "ATmega8A", + "ATmega48", + "ATmega48A", + "ATmega48PA", + "ATmega48PB", + "ATmega48P", + "ATmega88", + "ATmega88A", + "ATmega88P", + "ATmega88PA", + "ATmega88PB", + "ATmega8515", + "ATmega8535", + "AT90S8535", + "AT90C8534", + "AT90S8515", + "AT90S4434", + "AT90S4433", + "AT90S4414", + "ATtiny22", + "ATtiny26", + "AT90S2343", + "AT90S2333", + "AT90S2323", + "AT90S2313", + "ATtiny4", + "ATtiny5", + "ATtiny9", + "ATtiny10", + "ATtiny20", + "ATtiny40", + "ATtiny2313", + "ATtiny2313A", + "ATtiny13", + "ATtiny13A", + "ATtiny25", + "ATtiny4313", + "ATtiny45", + "ATtiny85", + "ATtiny24", + "ATtiny24A", + "ATtiny44", + "ATtiny44A", + "ATtiny441", + "ATtiny84", + "ATtiny84A", + "ATtiny841", + "ATtiny261", + "ATtiny261A", + "ATtiny461", + "ATtiny461A", + "ATtiny861", + "ATtiny861A", + "ATtiny43U", + "ATtiny48", + "ATtiny88", + "ATtiny828", + "ATtiny87", + "ATtiny167", + "ATtiny1634", + "AT90SCR100", + "ATxmega8E5", + "ATxmega16A4", + "ATxmega16A4U", + "ATxmega16C4", + "ATxmega16D4", + "ATxmega16E5", + "ATxmega32A4", + "ATxmega32A4U", + "ATxmega32C3", + "ATxmega32C4", + "ATxmega32D3", + "ATxmega32D4", + "ATxmega32E5", + "ATxmega64A1", + "ATxmega64A1U", + "ATxmega64A3", + "ATxmega64A3U", + "ATxmega64A4U", + "ATxmega64B1", + "ATxmega64B3", + "ATxmega64C3", + "ATxmega64D3", + "ATxmega64D4", + "ATxmega128A1", + "ATxmega128A1U", + "ATxmega128A4U", + "ATxmega128A3", + "ATxmega128A3U", + "ATxmega128B1", + "ATxmega128B3", + "ATxmega128C3", + "ATxmega128D3", + "ATxmega128D4", + "ATxmega192A3", + "ATxmega192A3U", + "ATxmega192C3", + "ATxmega192D3", + "ATxmega256A3", + "ATxmega256A3U", + "ATxmega256A3B", + "ATxmega256A3BU", + "ATxmega256C3", + "ATxmega256D3", + "ATxmega384C3", + "ATxmega384D3", + "ATA5702M322", + "ATA5782", + "ATA5790", + "ATA5790N", + "ATA5791", + "ATA5831", + "ATA5272", + "ATA5505", + "ATA5795", + "ATA6285", + "ATA6286", + "ATA6289", + "ATA6612C", + "ATA6613C", + "ATA6614Q", + "ATA6616C", + "ATA6617C", + "ATA664251", + "ATA8210", + "ATA8510", + "ATtiny28", + "AT90S1200", + "ATtiny15", + "ATtiny12", + "ATtiny11", + "M3000", + }; + + @Override + protected void run() throws Exception { + outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir"); + + parseGDT_AVR8(); + } + + public void parseGDT_AVR8() throws Exception { + // If need data types from other archives can add other archives + + // Using another archive while parsing will cause: + // - a dependence on the other archive + // - any missing data types while parsing are supplied if present from existingDTMgr + // - after parsing all data types parsed that have an equivalent data type will be + // replaced by the data type from the existingDTMgr + // + // NOTE: This will only occur if the data type from the exisitngDTMgr is equivalent. + // + ResourceFile clib64ArchiveFile = DataTypeArchiveUtility.findArchiveFile("generic_clib.gdt"); + File file = new File(clib64ArchiveFile.getAbsolutePath()); + DataTypeManager vsDTMgr = FileDataTypeManager.openFileArchive(file, false); + DataTypeManager openTypes[] = { vsDTMgr }; + // by defaults, don't want to be dependent on other archives if have all necessary definitions + // comment out if missing data types + openTypes = null; + + String dataTypeFile = outputDirectory + File.separator + "avr8.gdt"; + + File f = getArchiveFile(dataTypeFile); + + FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); + + // Parse each processor variant as an individual parse that gets added to the data + // type manager. If all header files were parsed at once, there are conflicting + // macro definitions that will cause the parse to fail. + // + for (String variantName : processorVariants) { + parseProcessorDefs(variantName, dtMgr, openTypes); + } + + dtMgr.save(); + dtMgr.close(); + } + + /** + * Turn string into a file, delete old archive if it exists + * + * @param dataTypeFile + * + * @return file + */ + private File getArchiveFile(String dataTypeFile) { + File f = new File(dataTypeFile); + if (f.exists()) { + f.delete(); + } + String lockFile = dataTypeFile + ".ulock"; + File lf = new File(lockFile); + if (lf.exists()) { + lf.delete(); + } + return f; + } + + /** + * parse a single AVR8 variant + * + * @param procName name of processor + * @param dtMgr open data type manager to add types to + * @param openTypes any open archives for missing data types + * @throws ParseException something happened + * @throws ghidra.app.util.cparser.C.ParseException + * @throws IOException io exception + */ + private void parseProcessorDefs(String procName, FileDataTypeManager dtMgr, DataTypeManager[] openTypes) + throws ParseException, ghidra.app.util.cparser.C.ParseException, IOException { + PreProcessor cpp; + + String args[] = Arrays.append(orig_args, "-D__AVR_"+procName+"__"); + + cpp = new PreProcessor(); + + String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, "avr8:LE:16:atmega256", "gcc", cpp, monitor); + + Msg.info(this, messages); + + storeExtraDefinitions(procName, dtMgr, openTypes, cpp); + } + + /** + * get extra defines special for the AVR8 that describe memory locations per variant + * + * @param procName processor variant + * @param dtMgr add data types to dtMgr + * @param cpp pre-processor holds macros/defines from parsing + */ + private void storeExtraDefinitions(String procName, FileDataTypeManager dtMgr, DataTypeManager[] openTypes, PreProcessor cpp) { + int transactionID = dtMgr.startTransaction("Add Extra Equates"); + + DefineTable definitions = cpp.getDefinitions(); + Iterator defineNames = definitions.getDefineNames(); + while (defineNames.hasNext()) { + String defName = defineNames.next(); + String rawDefValue = definitions.getValue(defName); + String expandValue = definitions.expandDefine(defName); + + if (expandValue == null || expandValue.length()==0) { + // can't expand, must be a macro + continue; + } + + // look at string and see if if the definition of an SFR, register + String PTR_PREFIX_16 = "(*(volatile uint16_t *)"; + String PTR_PREFIX_8 = "(*(volatile uint8_t *)"; + + Long lvalue = null; + if (expandValue.startsWith(PTR_PREFIX_16)) { + // ptr to 16 bit address in SFR + expandValue = expandValue.replace(PTR_PREFIX_16, ""); + expandValue = expandValue.substring(0,expandValue.lastIndexOf(')')); + } else if (expandValue.startsWith(PTR_PREFIX_8) ) { + // ptr to 8 bit address in SFR + expandValue = expandValue.replace(PTR_PREFIX_8, ""); + expandValue = expandValue.substring(0,expandValue.lastIndexOf(')')); + } else { + continue; + } + + if (expandValue == null || expandValue.length() == 0) { + continue; + } + + lvalue = AddressEvaluator.evaluateToLong(expandValue); + if (lvalue == null) { + continue; + } + definitions.populateDefineEquate(openTypes, dtMgr, "memory", "", defName, lvalue); + } + dtMgr.endTransaction(transactionID, true); + } +} diff --git a/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java b/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java new file mode 100644 index 0000000000..9d55d457d1 --- /dev/null +++ b/Ghidra/Processors/JVM/ghidra_scripts/CreateJNIGDTArchivesScript.java @@ -0,0 +1,186 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// +// Parses sample linux and windows JNI header files into .gdt data type archive. +// +// To replace existing header files and have the data type ID's synchronized +// +// Must run SynchronizeGDTCategoryPaths.java script with old and replacement GDT +// archive to synchronize upper/lower case paths +/// (only on windows archives) +// +// Then Run DataTypeArchiveTransformer in eclipse to synchronize old data types ID's +// +//@category Data Types + +import java.io.File; +import java.io.IOException; + +import generic.jar.ResourceFile; +import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility; +import ghidra.app.script.GhidraScript; +import ghidra.app.util.cparser.C.CParserUtils; +import ghidra.app.util.cparser.C.ParseException; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.FileDataTypeManager; +import ghidra.util.Msg; + +public class CreateJNIGDTArchivesScript extends GhidraScript { + + private File outputDirectory; + + // location of header files base directory + private static String headerFilePath = "/data/HeaderFiles"; + + @Override + protected void run() throws Exception { + outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir"); + + parseGDT_Linux_JNI(); + + parseGDT_Windows_JNI(); + + } + + private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler, String[] filenames, String[] args) + throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException { + + String dataTypeFile = outputDir + File.separator + gdtName + ".gdt"; + + File f = getArchiveFile(dataTypeFile); + + FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(f); + + String messages = CParserUtils.parseHeaderFiles(openTypes, filenames, args, dtMgr, languageID, compiler, null, monitor); + + Msg.info(this, messages); + + dtMgr.save(); + dtMgr.close(); + } + + /** + * Turn string into a file, delete old archive/lock file if it exists + * + * @param dataTypeFile + * + * @return file + */ + private File getArchiveFile(String dataTypeFile) { + File f = new File(dataTypeFile); + if (f.exists()) { + f.delete(); + } + String lockFile = dataTypeFile + ".ulock"; + File lf = new File(lockFile); + if (lf.exists()) { + lf.delete(); + } + return f; + } + + + public void parseGDT_Linux_JNI() throws Exception { + String filenames[] = { + "jni.h", + "jawt.h", + "jdwpTransport.h", + "jvmti.h", + "jvmticmlr.h", + "classfile_constants.h", + }; + + String args[] = { + "-I"+headerFilePath+"/jni/linux", + "-I"+headerFilePath+"/jni/linux/linux", + "-D_X86_", + "-D__STDC__", + "-D_GNU_SOURCE", + "-D__WORDSIZE=64", + "-D__builtin_va_list=void *", + "-D__DO_NOT_DEFINE_COMPILE", + "-D_Complex", + "-D_WCHAR_T", + "-D__NO_STRING_INLINES", + "-D__signed__", + "-D__extension__=", + "-D__GLIBC_HAVE_LONG_LONG=1", + "-D__need_sigset_t", + "-Daligned_u64=uint64_t", + }; + + + // Using another archive while parsing will cause: + // - a dependence on the other archive + // - any missing data types while parsing are supplied if present from existingDTMgr + // - after parsing all data types parsed that have an equivalent data type will be + // replaced by the data type from the existingDTMgr + // + // NOTE: This will only occur if the data type from the exisitngDTMgr is equivalent. + // + ResourceFile clib64ArchiveFile = DataTypeArchiveUtility.findArchiveFile("generic_clib_64.gdt"); + File file = new File(clib64ArchiveFile.getAbsolutePath()); + DataTypeManager existingDTMgr = FileDataTypeManager.openFileArchive(file, false); + DataTypeManager openTypes[] = { existingDTMgr }; + + parseHeaderFilesToGDT(openTypes, outputDirectory, "jni_linux", "x86:LE:64:default", "gcc", filenames, args); + } + + public void parseGDT_Windows_JNI() throws Exception { + String filenames[] = { + "jni.h", + "jawt.h", + "jdwpTransport.h", + "jvmti.h", + "jvmticmlr.h", + "classfile_constants.h", + }; + + String args[] = { + "-I"+headerFilePath+"/jni/win32", + "-I"+headerFilePath+"/jni/win32/win32", + "-D_X86_", + "-D__STDC__", + "-D_GNU_SOURCE", + "-D__WORDSIZE=64", + "-D__builtin_va_list=void *", + "-D__DO_NOT_DEFINE_COMPILE", + "-D_Complex", + "-D_WCHAR_T", + "-D__NO_STRING_INLINES", + "-D__signed__", + "-D__extension__=", + "-D__GLIBC_HAVE_LONG_LONG=1", + "-D__need_sigset_t", + "-Daligned_u64=uint64_t", + }; + + // Using another archive while parsing will cause: + // - a dependence on the other archive + // - any missing data types while parsing are supplied if present from existingDTMgr + // - after parsing all data types parsed that have an equivalent data type will be + // replaced by the data type from the existingDTMgr + // + // NOTE: This will only occur if the data type from the exisitngDTMgr is equivalent. + // + ResourceFile clib64ArchiveFile = DataTypeArchiveUtility.findArchiveFile("windows_vs12_64.gdt"); + File file = new File(clib64ArchiveFile.getAbsolutePath()); + DataTypeManager existingDTMgr = FileDataTypeManager.openFileArchive(file, false); + DataTypeManager openTypes[] = { existingDTMgr }; + + parseHeaderFilesToGDT(openTypes, outputDirectory, "jni_windows", "x86:LE:64:default", "windows", filenames, args); + } +}