Linkloader improvement: mclinker.
Change-Id: I8805e39ccbc2ee204234fb3e71c70c906f3990bb
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d970594
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+*.o
+*.swp
+Makefile.in
+VERSION
+aclocal.m4
+autom4te.cache
+config.guess
+config.sub
+configure
+depcomp
+install-sh
+ltmain.sh
+missing
+libtool.m4
+ltoptions.m
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
+ltoptions.m4
+test/*
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..6210620
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH := $(call my-dir)
+MCLD_ROOT_PATH := $(LOCAL_PATH)
+# For mcld.mk
+LLVM_ROOT_PATH := external/llvm
+MCLD_ENABLE_ASSERTION := true
+
+include $(CLEAR_VARS)
+
+# MCLinker Libraries
+subdirs := \
+ lib/CodeGen \
+ lib/LD \
+ lib/MC \
+ lib/Support \
+ lib/Target
+
+# ARM Code Generation Libraries
+subdirs += \
+ lib/Target/ARM \
+ lib/Target/ARM/TargetInfo
+
+# MIPS Code Generation Libraries
+subdirs += \
+ lib/Target/Mips \
+ lib/Target/Mips/TargetInfo
+
+# X86 Code Generation Libraries
+subdirs += \
+ lib/Target/X86 \
+ lib/Target/X86/TargetInfo
+
+include $(MCLD_ROOT_PATH)/mcld.mk
+include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, $(subdirs)))
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..3dcd781
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,9 @@
+
+================================================
+Copyrights and Licenses for Third Party Software
+Distributed with MCLinker Project
+================================================
+Program Directory
+------- ---------
+Google Test ${MCLinker}/utils/gtest
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..d2ddba3
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,112 @@
+2012-03-14 Luba Tang <lubatang@gmail.com>
+ * Migrate on LLVM@r152063
+ * Migrate on clang@r152062
+
+ * LD/LDSection, LD/ELFFileFormat, LD/ELFDynObjFileFormat,
+ LD/ELFExecFileFormat:
+ Support setting alignment constraint in section header.
+ * LD/Layout:
+ Update sections' alignment constraints during section merging.
+
+ * Support/MemoryArea, Support/MemoryRegion:
+ Enhance memory utilities.
+
+ * Target/ARMLDBackend:
+ 1. work around ARM.exidx and ARM.extab.
+ 2. add relocation supports - R_ARM_TARGET1, R_ARM_TARGET2, R_ARM_ABS32,
+ R_ARM_BASE_PREL, and R_ARM_GOT_PREL
+
+ * Target/MipsLDBackend:
+ 1. Android bitmap, native Plasma and Quake1 is examined successfully.
+
+ * Target/GNULDBackend, LD/ELFSegmentFactory:
+ Move segment-related implemenation out of GNULDBackend.
+
+ * Support/ScopedWriter:
+ Obsolete, removed.
+
+ * MC/SymbolCategory:
+ add random accessing functions
+
+2012-03-01 Luba Tang <lubatang@gmail.com>
+ * add test/ARM/Relocation:
+ * add test/ARM/GOTPLT:
+ Simple regression testcases. Each case is used for testing a single
+ relocation or GOTPLT entry.
+
+ * add test/Android/Plasma/ARM, X86, MIPS:
+ * add test/Android/Quake/ARM, X86:
+ * add test/Android/Quake2/ARM, X86:
+ Basic regression testcases for Android platform. The system libraries
+ for each platform are under test/libs/ARM, X86, MIPS.
+
+ * Target/TargetLDBackend:
+ separate readSections() into readRegularSection() and
+ readTargetSection().
+
+ * Target/GNULDBackend:
+ Move hash_bucket_count() and isDynamicSymbol() on successors.
+
+ * Target/MipsLDBackend: Eable to link trivial cases and Android Plasma.
+ * Target/X86LDBackend: Eable to link all Android JNI cases with CRT.
+
+ * CodeGen/SectLinkerOption, llvm-mcld.cpp:
+ get rid of -dB option. MCLinker does not need to ask users for -dB
+ option.
+
+ * MC/MCLinker, LD/ELFObjectReader, LD/ELFObjectWriter:
+ Support symbol visibility.
+
+ * LD/LDSection: Separate LinkInfo into Link and Info.
+
+ * LD/Relocation:
+ In order to enhance memory footprints:
+ 1. Remove Relocation::m_Parent.
+ 2. Let target data be a copy, not a pointer.
+
+ * LD/ELFReader, LD/ObjectReader, LD/ELFObjectReader, LD/Layout:
+ Support GROUPT section.
+
+ * LD/LDFileFormat:
+ Support all special sections listed in Linux Standard Base
+ (ISO/IEC 23360).
+
+ * Support/GCFactoryListTraits:
+ Provides GCFactory's trait for llvm::iplist.
+
+ * Support/LEB128: Add LEB128 utilities.
+
+ * Support/HashTable:
+ Identify ambiguous constructors by adding an anonyous parameter.
+
+ * Suppot/MemoryRegion, Support/MemoryArea:
+ 1. remove pIsWrite parameter in MemoryArea::request(). MemoryArea knows
+ the file is readable or writable when map() the file.
+ 2. MemoryArea allows to request a zero size MemoryRegion.
+
+ * patch/LLVM.patch: complement llvm/Support/ELF.h.
+ Add SHT_GNU_ATTRIBUTES, SHT_GNU_HASH, SHT_GNU_verdef, SHT_GNU_verneed,
+ and SHT_GNU_versym.
+
+ * LD/Layout:
+ 1. Work around LDFileFormat::Exception and LDFileFormat::Version.
+ 2. appendFragment(): Support merging sections with different alignment
+ constraints.
+
+2012-02-03 Luba Tang <lubatang@gmail.com>
+ * allocate common symbols in BSS section
+ * add ThreadLocal type in ResolveInfo::Type
+ * Quake2 can be linked on ARM Android.
+
+2012-02-02 Luba Tang <lubatang@gmail.com>
+ * Quake can be linked on x86 Android.
+
+2012-01-17 Luba Tang <lubatang@gmail.com>
+ * Quake can be linked on ARM Android.
+ * All APIs for backends is ready.
+
+2012-01-12 Jush Lu <Jush.Lu@mediatek.com>
+ * Trivial cases have worked on ARM.
+
+2011-05-23 Luba Tang <lubatang@gmail.com>
+ * create all basic files and directories.
diff --git a/ChangeLog.txt b/ChangeLog.txt
new file mode 100644
index 0000000..719a25e
--- /dev/null
+++ b/ChangeLog.txt
@@ -0,0 +1,11615 @@
+Linkloader improvement: mclinker.
+
+commit c58eed892e965064c66841b99a7492b155bee456
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Thu Mar 15 09:07:33 2012 +0800
+
+ Add Android makefiles for MCLinker.
+
+commit 2fafd87a75fb85f77453cbec31403a2df47a284f
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Mar 14 14:43:00 2012 +0800
+
+ Remove things under mclinker/test directory.
+
+ It is not required for MCLinker build.
+
+commit 64b43e630548f6ff5e29f67fd50fdfa1627cdd03
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Mar 14 18:54:32 2012 +0800
+
+ Increase version number to 2.10.1-18peaks.
+
+commit 2670f6eb7355fac11eeb1e9b4b7cbad2cdcc8b96
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Mar 14 18:53:27 2012 +0800
+
+ Update golden model of ARM Quake
+
+commit bbe26afd1ea952e3d35ef4b7cb62ba4a88fa31c7
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Mar 14 18:43:58 2012 +0800
+
+ Fixes issue 21 comment 1.
+
+ crtbegin.o should precede all input files and crtend.o should be the
+ last. Golden model files for ARM are also updated to reflect such
+ changes.
+
+commit 99a16a23c03e34e50537efe5337fc2b00444edce
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Mar 14 17:44:15 2012 +0800
+
+ Update golden model files for X86.
+
+commit 9bd9575c2676f7b409e18c021c73264a9cfbb705
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Mar 14 15:46:50 2012 +0800
+
+ Add error message when scan relcoation R_ARM_BASE_PREL
+
+ Currently we handle R_ARM_BASE_PREL only if its target
+ symbol is _GLOBAL_OFFSET_TABEL_
+
+ R_ARM_BASE_PREL only against symbol defined by linker,
+ for example, section or segment symbols. Now we support
+ only got section symbol _GLOBAL_OFFSET_TABLE_
+
+commit fb2c70a1b22c594b256c1726cc7eff03a98065a5
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Mar 14 15:39:43 2012 +0800
+
+ Fix a bug - region should not released before creating symbol.
+
+ Because we use llvm::StringRef to pass symbol name, and llvm::StringRef
+ has no copy of the string. So, we must remain the region until we
+ finish creating symbol.
+
+commit ac12e4f59fe222245f1cb924b760b932644c096e
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Mar 14 14:26:46 2012 +0800
+
+ Refine code. let entry size use type size_t, not uint64_t.
+
+commit d904b5a237f7d49450d6569bfbce2d20d63866f3
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Mar 14 14:19:39 2012 +0800
+
+ Refine a bit - to supress the warning messages.
+
+commit 6cd13d38e0fdb37e35fc6e2211d1d566b7609d28
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Mar 14 13:54:06 2012 +0800
+
+ Refine code.
+
+ The size of got entry and fragment is hard to out of the range of size_t.
+ So, I use size_t instead of uint64_t.
+
+commit 7de970aba179e30db7f69486eeac7b3e9f052fb7
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Mar 14 13:46:19 2012 +0800
+
+ Suppress the build warnings in GNUArchiveReader.
+
+ Patch by Ping-Jung Lu <pingjunglu at gmail.com>.
+
+commit f53bf100944d0b15d1d8509e8450ea9cb5863e0c
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Mar 14 11:12:02 2012 +0800
+
+ Rename the function.
+
+commit 363f704321b4a533bd5cc624790749a28509a169
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Mar 13 21:54:25 2012 +0800
+
+ Refactor pread() out of request() in MemoryArea.
+
+commit 2aac5daab09f381d49a5106b0ec07d6e96680b15
+Author: Luba Tang <lubatang@gmail.com>
+Date: Tue Mar 13 21:34:56 2012 +0800
+
+ Use MemoryArea::release(MemoryRegion*) to reduce the memory footprint.
+
+commit 7f8198e609778300fcd853f388f40b3c9caac6c1
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:49:29 2012 +0800
+
+ For enhance performance, remove MemoryRegion::sync()
+
+commit cccd59a73e6995654815b1c827c80d9867519536
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:45:14 2012 +0800
+
+ Add new functio - RegionFactory::destruct(MemoryRegion*)
+
+commit a9f2046bb3a98105c3ac466823764dd8b0b836bd
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:44:05 2012 +0800
+
+ Add drift and increase/decrease MemoryArea::Space::region_num
+
+commit 203df1dce6f0499288e6da60043243f6c63643da
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:38:45 2012 +0800
+
+ Avoid from allocating big memory space at very first time.
+
+commit 7719d5b9a39baa77c4edfd98d3107013cbac5333
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:37:57 2012 +0800
+
+ remove obsolete ScopedWriter.
+
+commit 46252dc19cccb09dbcff0b28c42075bdbf602d77
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:36:25 2012 +0800
+
+ add a new field of MemoryArea::Space - region_num.
+
+ Let MemoryArea::Space be countable.
+
+commit 7deb4cc8fbd34b96761c5654bd2d59223060799d
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:32:57 2012 +0800
+
+ Refine code. Change the type of parameter of PLT::reserveEntry from int to size_t.
+
+commit a32b0633a1cb899563aceced1901801587d56b52
+Author: luba <lubatang@gmail.com>
+Date: Tue Mar 13 20:31:01 2012 +0800
+
+ Remove obsolete ScopedWriter.
+
+commit 3f1657871789c2e10597fb814a8976a287e8b1a9
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Mar 13 20:20:54 2012 +0800
+
+ Set real relocation type to R_ARM_TARGET1 and R_ARM_TARGET2
+
+commit 7ee57163fb4274e29fc2004524847d0f7d1cc2c4
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Mar 13 19:59:11 2012 +0800
+
+ Update golden model files for ARM.
+
+commit 5460ca01dbf89e72f47ef936f923e28a32b925cb
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Mar 13 14:06:44 2012 +0800
+
+ Add ARM relcoation function for R_ARM_TARGET1
+
+ Refer to GNU gold, treat R_ARM_TARGET1 as R_ARM_ABS32
+
+commit 222cbd1efa892d48aa47d6de195778b51293dc2a
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Mar 13 12:00:35 2012 +0800
+
+ Set section .ARM.exidx and .ARM.extab to 'Exception.'
+
+ Currently we emit these two sections directly from inputs.
+
+commit 84bec2b1a2d6a6d3612b1b691d1130395d1ebbfa
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Mar 12 21:47:19 2012 +0800
+
+ Add ARM relocation support
+
+ R_ARM_BASE_PREL, R_ARM_TARGET2 and R_ARM_GOT_PREL
+ Refer to GNU gold, we treat R_ARM_TARGET2 as R_ARM_GOT_PREL here
+
+commit 7209c752ab4e6e0e26d51261260fbee51fb8752e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Mar 12 21:23:02 2012 +0800
+
+ Suppress more warning messages.
+
+commit 726dd63cd894c08336f8bd96dd9fe5d80d9d77ee
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Mar 12 20:33:27 2012 +0800
+
+ Suppress the warning message about enumeral and non-enumeral type in conditional expression
+
+commit 0814259a29b34222959eb8e49fb2e2ff5aa3c7e6
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Mar 12 20:16:54 2012 +0800
+
+ Remove some unused code and variables.
+
+commit e20dc4fd1122ebdd5e0b33f7b7c04b59067762f3
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Mar 12 19:12:12 2012 +0800
+
+ Suppress the warning messages about order of initialization.
+
+ No functionality was expected to change.
+
+ Initialze the member variables in the order they are declared.
+
+commit 3ef7531e9e700666a9fdb5ff9a5ac7abab422a92
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Mar 12 19:07:33 2012 +0800
+
+ Rename m_ELFSegmentFactory as m_ELFSegmentTable in GNULDBackend.
+
+commit afba4bc78d33a361e32f926e7a272898800dab01
+Author: Luba Tang <lubatang@gmail.com>
+Date: Mon Mar 12 18:39:13 2012 +0800
+
+ Fix a bug - SymbolCategory::arrange upward does not change the category.begin/end correctly.
+
+commit 843d7c0e8c4831362439d349dd71c9412e44067f
+Author: Luba Tang <lubatang@gmail.com>
+Date: Mon Mar 12 18:33:46 2012 +0800
+
+ Add access functions of SymbolCategory.
+
+commit 05bdee9db90fbffa6088be80e99b9d0acf553907
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Mar 12 16:48:16 2012 +0800
+
+ add ELFSegmentFactory class.
+
+commit dad3cbf8460739d2a709224c7f101e66336837b0
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Mon Mar 12 15:56:10 2012 +0800
+
+ eliminate clang++ warnings
+
+commit 9bf8e7d52e08420b0ef4d35f7cf90207731cb628
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Mar 12 15:21:56 2012 +0800
+
+ Migrate to LLVM upstream r152063.
+
+commit 32f23312756038f853d959613721f6df83e0a16f
+Author: luba <lubatang@gmail.com>
+Date: Mon Mar 12 15:08:39 2012 +0800
+
+ remove sed -i option for all platforms.
+
+commit 74bbca62e25f04adfdbb3f7d6ad29c4b00635c3b
+Author: Luba Tang <lubatang@Scarecrow.local>
+Date: Mon Mar 12 14:59:25 2012 +0800
+
+ Conforming to Mac iOS 10.7.
+
+ Using sed -i "" -e instead of sed -i
+
+commit 30c4c4a9abf655fb30817846c0fa71ad3cf49aa3
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Mar 12 14:57:03 2012 +0800
+
+ Update golden model files for ARM.
+
+commit 8be0c24c9cbeea14fdefb06bee5f3172a2b2466f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Mar 12 14:12:32 2012 +0800
+
+ Fix a bug - If not building a PIC object, no relocation type is invalid
+
+commit bab512b3b7c1f15a578666bf0cf3c8e807588381
+Author: luba <lubatang@gmail.com>
+Date: Mon Mar 12 09:47:41 2012 +0800
+
+ Revert "Fix a bug - No matter the old symbol exists or not, StrSymPool should"
+
+ This reverts commit ae5f00574654c98426f95bc0e062ce0e5727ad25.
+
+ The bug is in SymbolCategory, not StrSymPool.
+
+commit 517d91be79c2e5bf8e3e9d0c34adbd6d09c70a75
+Author: luba <lubatang@gmail.com>
+Date: Mon Mar 12 09:47:14 2012 +0800
+
+ Revert "Conforming to FreeBSD's sed."
+
+ This reverts commit d5decba261d3ad72d0bb978a805e3269a79bd014.
+
+commit ae5f00574654c98426f95bc0e062ce0e5727ad25
+Author: Luba Tang <lubatang@gmail.com>
+Date: Sun Mar 11 16:16:08 2012 +0800
+
+ Fix a bug - No matter the old symbol exists or not, StrSymPool should
+ set pOldInfo if it isn't NULL.
+
+commit d5decba261d3ad72d0bb978a805e3269a79bd014
+Author: Luba Tang <lubatang@gmail.com>
+Date: Sun Mar 11 16:00:05 2012 +0800
+
+ Conforming to FreeBSD's sed.
+
+commit 092c60351451c2e34ab22970ed78a4adefa05ec8
+Author: Luba Tang <lubatang@gmail.com>
+Date: Sun Mar 11 15:58:16 2012 +0800
+
+ Add Mips backend.
+
+commit e09e8f332dab61b7f74ea684fb44928b16344415
+Author: Luba Tang <lubatang@gmail.com>
+Date: Sun Mar 11 02:52:46 2012 +0800
+
+ Refine format.
+
+commit 1f5e424dc99c7d103044e1623fe47b819b0137bb
+Author: Luba Tang <lubatang@gmail.com>
+Date: Sat Mar 10 03:50:00 2012 +0800
+
+ Fix a bug - when a entry does not exist in a hash table, the parameter
+ bool & pExist should set false.
+
+commit b6a144426f7c819ef60b05f1717a5e7bfd4bf6fa
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Mar 9 11:48:48 2012 +0800
+
+ Fix a bug - When applying ABS32 relocation in X86 and ARM, check if
+ symbol is not local (external) instead of checking if it's global
+
+commit 7362d1e643756893d4b8e9eec0f0f22f89082a2d
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Fri Mar 9 09:28:56 2012 +0800
+
+ Fix arithmetic error in MIPS helper_CalcAHL.
+
+ Fix helper_CalcAHL section offset added to avoid arithmetic error by
+ the comment http://code.google.com/p/mclinker/issues/detail?id=20#c24
+
+commit feaf13d60030aaf1ec4a719b53c5a7670f8fa436
+Author: luba <lubatang@gmail.com>
+Date: Thu Mar 8 17:36:49 2012 +0800
+
+ clean up code.
+
+commit 29ba42e4513ee8e9ff9317cdca359d96c449f12c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Mar 8 17:28:37 2012 +0800
+
+ Fix a bug - In OutputRelocSection, not to use iterator as a boolean
+
+commit c3a62be7ffce3f652bab64785b5462c05276d135
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Mar 8 11:09:24 2012 +0800
+
+ Fix a bug - Modify X86RelocationFactory
+
+ The dynamic relocations which relocating GOT entry,
+ their type may be R_386_RELATIVE or R_386_GLOB_DAT
+
+commit ea5c2032f569376f8d927cfe10ad0eb9119831f7
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Thu Mar 8 00:44:41 2012 +0800
+
+ Fix AHL HI-part value in MIPS AHL calculation.
+
+commit efd979162595780f5f1d15bd071ae8b715c5c68a
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Mar 7 22:10:21 2012 +0800
+
+ Fix a bug where applying wrong value to PLT entries.
+
+commit 9d38ed3a0b946a3d100edf4206c71db5528fc92e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Mar 7 20:33:56 2012 +0800
+
+ Fix a bug - The dynamic relocations which relocating GOT entry,
+ their type may be R_ARM_RELATIVE or R_ARM_GLOB_DAT
+
+commit af4263eff50dc4fc0185f9bd3cbea7ededc72425
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Mar 7 07:42:17 2012 +0400
+
+ Cleanup the code. Remove obsoleted FIXME notes.
+
+commit a15ce7547bf10d2d36efbac0d7b1f732531b0532
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Mar 5 14:18:33 2012 +0400
+
+ Remove redundant code. MIPS local GOT entries cannot be dynamic. MIPS
+ global GOT entries are always dynamic.
+
+commit 2d66da2594d9c0d7a9039199855a89f6df7b2594
+Merge: 7945be9 bd8e77f
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sun Mar 4 17:52:00 2012 +0400
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 7945be9fa81db1bc83e36cfd9a48a2a743b4ef4b
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sun Mar 4 17:26:15 2012 +0400
+
+ Fix a bug in the R_MIPS_GPREL32 relocation handling.
+
+commit bd8e77f50d2366289d72531453bb4b3d82eff7ac
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Mar 2 13:50:07 2012 +0800
+
+ Refine code. Pass more specific GNULDBackend to ELFFileFormat instead.
+
+commit 21d1e845be3d83f22c9b0795bcbe76a7e7b9b08b
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Mar 2 11:17:17 2012 +0800
+
+ Return the number of bytes being written in leb128::encode().
+
+commit 46a42e8f46a4153294ddc19afa45e212599e5193
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Thu Mar 1 15:39:11 2012 +0400
+
+ Emit MIPS .rel.dyn entries for local symbols.
+
+commit 692a9dbea99d575a61d9f8dc96813de91702eed5
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Thu Mar 1 14:52:47 2012 +0400
+
+ Use target() and addend() uniformly in all MIPS relocation handles.
+
+commit 01cb37e11941d5cad49843872d2fdae51cf11075
+Author: Luba Tang <lubatang@gmail.com>
+Date: Fri Mar 2 01:34:37 2012 +0800
+
+ Fix a typo in README
+
+commit 6a5e7296d267366f0a738aab2d3bd39919ef68fd
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Mar 1 21:14:36 2012 +0800
+
+ Set the align field in output LDSection.
+
+ For output LDSection,
+ 1. the alignment is initialized in the initialization function of
+ "FilfFormat" or Target Section
+ 2. the alignment is also updated when merging sections if needed
+ Then we can use its alignment constraint in Layout::layout() directly.
+
+commit d2f094c84b419254f163c63d53346245d47ccc6a
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Thu Mar 1 21:26:10 2012 +0800
+
+ Fix a bug - use the value from -mtriple when possible.
+
+commit 9413eacd135be46d5d43cb7a42fff3b1bab33ef6
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Mar 1 17:35:51 2012 +0800
+
+ Update optimized/Makefile.am
+
+commit f75e059b3bf05a2bc5f3832a83e54f261d06d17e
+Author: luba <lubatang@gmail.com>
+Date: Thu Mar 1 16:17:27 2012 +0800
+
+ Refine README - add the steps to download and compile clang.
+
+commit 6c0fcd2e7aadddeaa856994897a9e5a5ffc36345
+Author: luba <lubatang@gmail.com>
+Date: Thu Mar 1 11:59:13 2012 +0800
+
+ Increase version number. Sorry for the long and large release.
+ In this version, both ARM and X86 Android cases (with CRT) are examinated.
+
+commit 2ffae8a472b1f6f526a5cb8e8245e51a5d618558
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 29 23:57:41 2012 +0400
+
+ Add missed files for MIPS target testing.
+
+commit 79f618678fcc25884359cef66ce5e6b41df60636
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Mar 1 10:37:46 2012 +0800
+
+ Fix a bug - update addend of the relocation against a section symbol
+
+ Add updateAddend into ARM/X86/MipsLDBackend.
+
+ For the relocation which againsts a section symbol, its addend
+ is supposed to be the offset in the section. This offset should
+ be updated after section merged.
+
+commit ee10db85d63962f08152a5c89a94a54a74a302ed
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Mar 1 10:37:17 2012 +0800
+
+ Update golden model files for ARM and X86.
+
+commit 9a3e5b180107e7a8ca3eb2c21da6d766dd50b851
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 29 06:55:41 2012 +0400
+
+ Add Plasma test case for MIPS target platform.
+
+commit db2dc667e6e07e3f41be496f1653e249f75dba47
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 29 18:17:49 2012 +0800
+
+ Refine format.
+
+commit 5b8ca2e10aeb5f1bf609ebdedc372db09a97a3ee
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Feb 29 13:50:08 2012 +0800
+
+ Handle the alignment of common symbols in X86GNULDBackend
+
+commit 47a6a79752d9cf061757f5e05dc2da3de97f294f
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Feb 29 11:36:23 2012 +0800
+
+ Fix the value applied to PLT1 entries.
+
+ According to the order of .got and .plt,
+ we should use different ways to calculate the values of PLT1 entries.
+
+commit b49129b899bcf88c8d76f35aaeb3805a44b6c7eb
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sun Feb 26 17:22:09 2012 +0400
+
+ Fix R_MIPS_HI16 / R_MIPS_LO16 relocation calculation bug.
+
+commit 2551281f30c53db037b628b128bc887ea053bc36
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Feb 24 19:49:41 2012 +0800
+
+ Update golden model files for ARM.
+
+commit ba2dff7c335ac23eaaf0f70fe999f14275c0de94
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 24 19:13:00 2012 +0800
+
+ Fix a bug - use virtual fillment fragment to represent zero sections.
+
+commit 7f0459ab6c403775fafb11f95c17e6b42eb08147
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 24 19:11:52 2012 +0800
+
+ Refactoring - remove pIsWrite parameter in MemoryArea::request.
+
+commit d22cfbc0a372a748990aee94b432d8ca3a6a5e72
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 24 19:09:33 2012 +0800
+
+ Refine code.
+
+commit 309a3094cf4098cd0ce59f431f8a5752c8a9ddf0
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 24 19:08:39 2012 +0800
+
+ Refine code.
+
+commit dfea6c724986980f0b47878eb73c6deee0654c1e
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 24 19:07:19 2012 +0800
+
+ Allow MemoryRegion is a virtual, zero memory address space.
+
+commit e90c7108897d441912a0ba648511c199f3da51ec
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 24 12:10:45 2012 +0800
+
+ Read exception and version sections.
+
+commit b36d04682eee8e4f5891d8141b2b8963efe52fc4
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Thu Feb 23 16:09:22 2012 +0400
+
+ Configure .rel.dyn entries.
+
+commit 67f1ffd187742c6ca7827a1bb62866d0570abc3d
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Feb 20 16:05:10 2012 +0400
+
+ Process R_MIPS_GOT16 for local symbols.
+
+commit 775875f83689bdf45f18cb0836e1fa25fb7cf315
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Feb 20 15:56:13 2012 +0400
+
+ Allow to call helper_CalcAHL() for R_MIPS_GOT16 relocation.
+
+commit 97da85f1fcb643f97e14c1bc0ddfe00bf4b5c227
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Thu Feb 16 10:41:12 2012 +0400
+
+ Emit local GOT entries before global ones.
+
+commit cfc393a694d9107d1c3a9fe18a856521115ac13f
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 21:07:12 2012 +0800
+
+ Fix a bug. Fix the typo for DT_INIT_ARRAYSZ and DT_FINI_ARRAYSZ in ELFDynamic.
+
+commit 95d864a8e4d928dde6d2490827694558c6249358
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 21:05:14 2012 +0800
+
+ Fix a bug. Correct the section kind and output section order of .eh_frame
+
+commit d0d46c5618a397154ae87bfc4f6b572e194b0133
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 23 18:18:12 2012 +0800
+
+ Fix a bug - ELFObjectReader should read Exception and Version sections.
+
+commit 6f0cfd0ee056b8ffdb39f98630e072a44530de38
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 17:44:23 2012 +0800
+
+ Initiate MCAlignFragment emmision support in ELFWriter::emitSectionData()
+
+commit 4bcb041764e509af45b0fab47c5e0d0fc931f1f7
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 16:34:54 2012 +0800
+
+ Handle alignment issue as finding FragmentRef and deciding section offset.
+
+commit 310c12126e9ac5e3ff9bb642729e1fe041ec4cd2
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 16:12:23 2012 +0800
+
+ Use Layout::appendFragment() for mergeable sections.
+
+ Currently we changed to use new API as
+ 1. reading Regular sections and BSS sections from input objects.
+ 2. allocating common symbols in BSS sections
+
+commit 3739e4217e45fbb6781c184e1b90d240c7b8133f
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 16:06:01 2012 +0800
+
+ Add API Layout::appendFragment().
+
+ To handle alignment in section merging correctly, we need to preserve input
+ alignment constraint. For mergeable sections (e.g., .text, .data, and .bss, ...)
+ from input objects, we should use this new API to append the fragment to the
+ associated MCSectionData.
+
+ As for the backend part, there is no need to change the used API.
+
+commit ade62d0450729561944699f599b22e64f6756626
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 16:03:17 2012 +0800
+
+ Set up the alignment constraint of input section in ELFReader.
+
+commit d797fa0a4a09cc5ae4689e2c592ccc5758235b6e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 16:02:45 2012 +0800
+
+ Add a field in LDSection for alignment constraint
+
+commit cd346eff71145785b1fb96363756452b6edf79c5
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Thu Feb 23 17:27:18 2012 +0800
+
+ Remove the const-ness from ELFReaderIF::readTargetSection.
+
+ Target-specific section is usually associated with a specialized
+ object which is managed by the target backend. And during the
+ read, it processes the bits from the input and may changes the
+ state of the associated object in the target backend.
+
+commit d423039e0a1bdf05425a1d236ed96d24414cbbd8
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 23 16:49:05 2012 +0800
+
+ Fix a bug - exception section should be able to be relocated.
+
+commit e565d30787176f67a1cfaeb35a85000c982a65bc
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 23 13:44:43 2012 +0800
+
+ Enhance warning messages.
+
+commit 8b9fbaf526e2edcbd59da1a483181979ac6ae5da
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 10:13:37 2012 +0800
+
+ Code refinement.
+
+commit dd3c5ab939a607c5fc538a6875f3a7f2d52a9e1b
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 09:51:31 2012 +0800
+
+ Fix a bug. Correct the way to calculate the file size of a ELF segment.
+
+commit 71d1bf7ae0dad888885bd46113e3c61f4d186436
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 09:42:52 2012 +0800
+
+ Fix a bug. Correct the offset of a section which is right after BSS section.
+
+commit 776eba0e3317ff4b29b91d04c19dd21b2a89db4d
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 09:39:12 2012 +0800
+
+ Remove sect_iterator in mcld::Layout
+
+commit 65371459a7251f00361cb31aa655d43511432b5b
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 23 09:35:34 2012 +0800
+
+ Refine code and comment.
+
+ It should be more clear to set output section indices after sorting section order.
+
+commit 90ceb06ca53afda34504e048f10b9be50ff0ace3
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Feb 22 18:42:36 2012 +0800
+
+ Thumb relocation note.
+
+commit 4681126a39cdfe435b6f2767a8fad98fbee57d35
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 22 15:06:49 2012 +0800
+
+ Remove handling 64bit backend in MipsGNULDBackend::emitDynNamePools
+
+commit 4ca129cb8ac7fdbfe71a72d3cfe2e19fc524273f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 22 14:30:59 2012 +0800
+
+ Add a HashMap into GNULDBackend to map symbols to their ouput symtab index
+
+ 1. Add a HashMap m_pSymIndexMap, maintain the map when emitDynNamePools
+ and emitRegNamePools
+ 2. Add an API GNULDBackend::getSymbolIdx to get symbol's index. This
+ API is used when emitRelocation. This API takes the place of
+ original LDContext::getSymbolIdx.
+
+ Now only the input symbols will push into LDContex's symTab, the
+ output symbols and the index maintained in m_pSymIndexMap of GNULDBackend.
+
+ When emitRelocation, we get the symbol's index in ouput symbol table
+ by asking the HashTable, this can reduce time on searching from the
+ vector and avoid string comparison.
+
+commit fca4108f643edeb74d163d9b7ddb2871b3a3dc1f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 22 14:21:17 2012 +0800
+
+ Add API - LDContext::addSymbol
+
+ Add input symbols into SymTab in LDContext by this API instead of
+ pushing into the SymTab directly.
+
+commit 1ff48e8f60c04334c284bd76dff99ce02bb1de20
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Feb 22 12:16:38 2012 +0800
+
+ Separate the implementation of LEB128 from header.
+
+ No functionality or API changed.
+
+ Fully specialized template functions are just like the normal
+ functions. It doesn't depend on the template parameters any more.
+ Therefore, you should declare them as inline functions in header
+ or define them in a .cpp in order to not violating the ODR. And
+ we choose the later.
+
+commit 12732aea6e1844c07bc066681bfde8792bf4f56f
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 22 12:02:05 2012 +0800
+
+ Refine warning information.
+
+commit ab8b32751554b817d3920375557c06106b505fc2
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Feb 22 09:30:47 2012 +0800
+
+ Allow signed char stream to be passed to LEB128 APIs.
+
+commit b03e65f660416f0d34ec3770b34fcf057a294e27
+Author: luba <lubatang@gmail.com>
+Date: Tue Feb 21 23:01:36 2012 +0800
+
+ Add special section support in ELFFileFormat
+
+ @ref "Additional Special Sections," ch. 10.3.1.2, ISO/IEC 23360 Part 1:2010(E)
+
+commit 6f429e27a868513bab6164d85f3e2af181c1857d
+Author: luba <lubatang@gmail.com>
+Date: Tue Feb 21 23:00:26 2012 +0800
+
+ Fix a bug - MCLinker should not set the index of output LDSection.
+ Instead, Layout should set up the index of output LDSection.
+
+commit 18cb084376bbe4589e0457265913821aa140400f
+Author: luba <lubatang@gmail.com>
+Date: Tue Feb 21 22:59:39 2012 +0800
+
+ Handle Exception and Version section kind.
+
+commit 455bc970e42ff12b3ed9dc0aed05d8489bbd0d1f
+Author: luba <lubatang@gmail.com>
+Date: Tue Feb 21 22:58:51 2012 +0800
+
+ Fix a bug - initialize LDSection::m_Index.
+
+commit 0c51de0dedac8f0f37f6e406255284a375b3e2a8
+Author: luba <lubatang@gmail.com>
+Date: Tue Feb 21 22:57:34 2012 +0800
+
+ Add new LDFileFormat::Kinds - Exception and Version.
+
+ Exception is used to identify a section for exception handling.
+ Version is used to identify a section for symbolic versioning.
+
+commit 8f0ae100a435e4b53943dbe2636a43e9e7fd80b6
+Author: luba <lubatang@gmail.com>
+Date: Tue Feb 21 22:55:54 2012 +0800
+
+ Complement lost ELF definitions in LLVM/include/llvm/Support/ELF.h
+
+commit c2754ddbdea85ad0460dd6e67e5d8d6ff549a1de
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Feb 21 19:58:24 2012 +0800
+
+ Fix typo.
+
+commit e1454f9d24b40e0784ef603bf844d87bad465054
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Feb 21 19:54:48 2012 +0800
+
+ Rearrange files for regression test.
+
+commit e4f8b8bf06c56d012146c363bed24f7125c3d032
+Author: luba <lubatang@gmail.com>
+Date: Tue Feb 21 17:01:56 2012 +0800
+
+ Add ISO/IEC 23360, LSB support.
+
+commit 4b58952253ff5b980c61837fe4f97217ae5b09ca
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Feb 21 15:06:10 2012 +0800
+
+ Change the decoding function APIs of LEB128.
+
+ Original: IntType decode(ByteType *pBuf, size_t *pSize);
+
+ Revised: IntType decode(const ByteType *pBuf, size_t &pSize);
+ IntType decode(const ByteType *&pBuf);
+
+ Also fix bugs in encode<uint32_t> (wrong mask.)
+
+commit f00151375dd50bcbe34ab6971933e8a932e76914
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Feb 21 13:49:31 2012 +0800
+
+ Load the input file content into memory after open.
+
+ Almost every byte in the input file (e.g., input object file) will
+ be examined during processing. Enforcing kernel to load the entire
+ file into memory right after open could generally reduce the
+ number of page fault generated.
+
+commit 7835521c2893df4650c46263f8ad8aa047d0a396
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Feb 21 12:11:19 2012 +0800
+
+ Fix HashTable - Identify ambiguous methods by adding an anonymous parameter
+
+commit a1b98456c9978f4b47842ac91912a9131db4fa0c
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Feb 21 11:56:03 2012 +0800
+
+ Use more correct type in template class SizeTraits.
+
+commit 706e8c41dfeab68417fb7f90e7815ea7e053e935
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Feb 21 11:44:51 2012 +0800
+
+ Add utility functions to support LEB128 encoding.
+
+commit 94b6e95182389993c807cb473b9ca2de7556cb7d
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 17 18:14:04 2012 +0800
+
+ Add unit test for GCFactoryListTraits.
+
+commit 2a19a2a89b60d18cc63e31cfe98ed41079105b92
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 17 17:31:37 2012 +0800
+
+ Format tabs with some typos fixed in Makefiles.
+
+ No functionality changed.
+
+commit 1b7be3e5098d852dc726f6d41a887c13ed9b9593
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 17 10:18:54 2012 +0800
+
+ Use LinearAllocator for input Relocation.
+
+commit 8eb7dc5a8f50b6826de4cd3172bc4973ccbfd672
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 17 10:13:37 2012 +0800
+
+ Add GCFactoryListTraits.
+
+ GCFactoryListTraits provides trait class for llvm::iplist when
+ the nodes in the list is produced by GCFactory.
+
+commit ec8c9322c12cb68aeb5c84bd7b77214c1544e7e4
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 17 13:47:13 2012 +0800
+
+ TargetLDBacked should have longer lifetime.
+
+ TargetLDBacked contains target RelocationFactory which holds the
+ allocation of the Relocation entries a target uses during linking
+ (i.e., MCLinker::m_RelocationList.) If the TargetLDBacked object
+ was destroy first, it will cause the relocation list in a valid
+ object however its allocation has been corrupted.
+
+commit cba8168c37579a45322bd1b99c3e574d77763118
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 17 10:06:39 2012 +0800
+
+ Let RelocationFactory inherit GCFactory again.
+
+ This reverts commit 6ffb8df05e1c0859fd2e74217b645ec3466e457f
+ "Change Relocation member variable m_pTargetData type from DWord* to DWord"
+
+ and commit f2e77a332a448cb1ac0ac2f30c599c7f4987814b.
+ "Let RelocationFactory not to inherit to GCFactory"
+
+commit 84634224e89ab32ec1c482de943359ce0f31cd5e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Feb 16 13:56:35 2012 +0800
+
+ Use llvm::ELF to specify the namespace of ELF
+
+ for building MCLinker on FreeBSD machine.
+
+commit f5543c18085dcafc8740473bf2bce9bc107f3ed0
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 15 17:26:41 2012 +0400
+
+ Do not reserve GOT entry twice.
+
+commit 7d5e0e96d6687522fd57c06584d119c3d2948f62
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 15 17:09:52 2012 +0400
+
+ Save calculated AHL value between R_MIPS_HI16/R_MIPS_LO16 relocations.
+
+commit 4602029c2f9b0992f7ed5391ab7f43f289f13fca
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 15 17:04:48 2012 +0400
+
+ Replace duplicated code in the MipsGNULDBackend::emitDynNamePools() routine
+ by getOutputFormat() call.
+
+commit 1263f542c4afa34986c5c44e88800856309719a7
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 15 16:59:51 2012 +0400
+
+ Emit dynamic symbols referenced by GOT at the end of .dynsym section.
+
+commit 312d21fe5664cae5d7abd2a677683d547f0ab791
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 15 16:54:01 2012 +0400
+
+ Save local/global symbols referenced by GOT in the m_LocalGOTSyms/m_GlobalGOTSyms arrays.
+
+commit ebc1e5c938c5e3f6497c70f9f165063c3f2d0981
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 15 16:45:41 2012 +0400
+
+ Make hash_bucket_count() and isDynamicSymbol() the GNULDBackend class memebers
+ to reuse in the GNULDBackend successors.
+
+commit 7933aef3fc78c35a1cbf9dd98d55605bf874a8d7
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Feb 15 18:02:19 2012 +0800
+
+ Fix bugs in group section handling.
+
+ 1. set up the link section of group sections as symtab section
+ 2. correct the code to check if discarding a relocation section
+
+commit 05deb106a3b706c74e3f11cc64e815f7f40beb06
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 15 14:06:46 2012 +0800
+
+ Refine optimized compilation options.
+
+commit 2b75acf4db917ed853cee8457d2c8618c6719daa
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 15 14:05:59 2012 +0800
+
+ Enhance performance. Eliminate the number of MemoryArea::request.
+
+commit 227e94232b776ce9b5e5d550900fce46b140a6b3
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 15 14:03:59 2012 +0800
+
+ Refine group section code.
+
+commit e0e0dee53da2c3bbd4cf1fe80e10012b565ddffa
+Author: luba <lubatang@gmail.com>
+Date: Mon Feb 13 14:08:26 2012 +0800
+
+ Refined optimized compilation options.
+
+commit 127607018a29c29cd4ae7649015852d53382f777
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Feb 15 14:03:14 2012 +0800
+
+ We can use diff only.(Return value.)
+
+commit 5a2927a9a63d088ebde7b13a01d0f83a319d06a2
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Feb 15 13:41:54 2012 +0800
+
+ Copy bitcode to individual folder.
+
+ Copy to same file will cause error when multithread.
+ E.g. When A thread is running plasma_arm and reading the bc, another
+ thread is running plasma_x86 and copying the bc, plasma_arm will fail.
+
+commit f702adaffc4649915e7c3bc3684d1ac1780ebc33
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Feb 15 13:37:53 2012 +0800
+
+ Fix typo. Remove unused file.
+
+commit e066a3c508d2ef6ab408a7845f403d97d4754cda
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Feb 14 16:45:55 2012 +0800
+
+ Fix a bug - When scanRelocation, Weak and Common symbol should do
+ scanGlobalReloc. While scanGlobalReloc handles all the external
+ symbols but not only for symbols with Global binding.
+
+commit ad6732f718a0b21f53d338e24f0fcacf467f9898
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Feb 13 21:06:13 2012 +0800
+
+ Add group section support.
+
+ The shared objects of Quake Android w/ ELF group section are verified on both
+ x86 and arm target.
+
+commit 8a4d59bc9c591d8eaf8a6b6b96a47c2e73a79dcf
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Feb 13 20:50:06 2012 +0800
+
+ Remove Relocation member variable m_Parent
+
+commit 6ffb8df05e1c0859fd2e74217b645ec3466e457f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Feb 13 20:20:31 2012 +0800
+
+ Change Relocation member variable m_pTargetData type from DWord* to DWord
+
+ To reduce memory footprint, let Relocation entry holds the TargetData
+ itself instead of using GCFactory to allocate a memory space for TargetData.
+
+commit f2e77a332a448cb1ac0ac2f30c599c7f4987814b
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Feb 13 20:14:03 2012 +0800
+
+ Let RelocationFactory not to inherit to GCFactory
+
+commit 758c2c1c49fcf0678c0720ecd58119d2b236106e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Feb 13 19:08:31 2012 +0800
+
+ Separate Link and Info from LinkInfo in LDSection
+
+commit 2e34545e28918e18383061f2d5352b57d526f3b0
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 13 14:30:00 2012 +0800
+
+ Add regression tests for the Android examples on X86.
+
+ Running the regression tests for X86 by binary file comparison.
+ Remove them when MCLinker has more test cases for X86.
+
+commit a80b5d3532770202298b2eadec4d417a5586310d
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sat Feb 11 07:57:40 2012 +0400
+
+ Move the const GOT offset to the helper functions.
+
+commit 13addedc0afe67f89ec677219098705ec4390bfa
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Fri Feb 10 03:31:13 2012 +0400
+
+ Adjust G value using _gp_disp offset.
+
+commit aa41a8c624b9f5ce936555b15940e37d524bef19
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 10 17:47:05 2012 +0800
+
+ Add support for target-dependent section.
+
+commit 76e0a0c7cbd6edc5c2e399e4320b3372f3a1debf
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 10 10:47:39 2012 +0800
+
+ No need to specify -dB for linking native files.
+
+commit 74deea14a47458276f5e8d6ca465170f480e7575
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 10 09:08:34 2012 +0800
+
+ Drop the dependency of llvm::Module in SectLinker.
+
+ Change the API of the constructor of SectLinkerOption. We now read
+ the library dependency from command line. Also modify the test such
+ that `make check' still works after this commit.
+
+ MCLinker requires both native input and its associated bitcode (
+ via -dB option) for linking. MCLinker treats the input bitcode as
+ linker script.
+
+ More specifically, given a bitcode module, MCLinker only need the
+ dependent library information within the module which can be
+ assigned via command line option "-l." Moreover, MCLinker spends
+ 90%+ time on decoding the bitcode when performs linking.
+
+ This and subsequent commits relax this requirement.
+
+commit 5df66059bdfc6124454269148a755e953380b833
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 10 10:54:01 2012 +0800
+
+ Fix logic bug.
+
+commit 1a835f684ea2e8cd3a6093452c2e4df83098c6c8
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 10 03:29:03 2012 +0800
+
+ Fix build on Mac.
+
+commit ec6e41d254b2075e4c77e9ddae0887ad18a2ee36
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Thu Feb 9 20:24:10 2012 +0800
+
+ Use the proper variable.
+
+commit 7973e64e61ee5726585b47317b965f2e705d2cdb
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 9 17:43:02 2012 +0800
+
+ Fix a bug - user, OS, and processor specific section types should be LDFileFormat::Target sections.
+
+commit 6b6cc27f922bb29d97067050af67a81949eb832e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Feb 9 13:55:15 2012 +0800
+
+ Refactoring - Add getOutputFormat to ARM and X86LDBackend
+
+commit 6d22b22a75a27d042598c0fd20e19744e0c0ce86
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Thu Feb 9 13:38:24 2012 +0800
+
+ Refine the code.
+
+ Reduce the calls to map insertion in MemoryAreaFactory when an
+ entry already exists in the map.
+
+commit e9c111d26aa52658c1631aaff527657310b0c9ea
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Feb 9 11:27:23 2012 +0800
+
+ Refine error message in ARMRelocationFactory
+
+commit 3700ecf0983d2b33d7ea215df3c7e52ae7b0e155
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Feb 9 10:01:08 2012 +0800
+
+ Add a regression test for Quake2 on ARM.
+
+ Currently running the regression test for Quake2 by binary file comparison.
+ Remove it when MCLinker has more test cases to ensure that Quake2 will work.
+
+commit d745e9af87248e14734e8e7755c9002d7dd045af
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Feb 8 11:41:59 2012 -0800
+
+ Allow R_386_PC32 in scanGlobalReloc if not preemptible
+
+ We allow R_386_PC32 only if it isn't preemptible. Otherwise we will
+ generate writable text section in output.
+
+commit 8a165afd2271b9ccd362bfa6895265d38ba6a121
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 9 02:37:45 2012 +0800
+
+ Fix a bug - we should check visibility and change symbol's binding during writing.
+
+commit a154003e4e366ec86f0d316fc0b7094983bcfb5f
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 9 02:31:23 2012 +0800
+
+ Refine code.
+
+commit d3a172595bd3bea111ca8e41e7bbbee872a73035
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 9 02:30:43 2012 +0800
+
+ Fix a bug - We should not change the binding at reading.
+
+commit 3011c9bb0b22ab09bba0d436daba715c3f2232de
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 9 02:29:33 2012 +0800
+
+ Fix a bug - When the symbol is old, and its category is changed, MCLinker should
+ arrange the symbol.
+
+commit 9b6e3c2eda00db383efb2dc80230d3e23d77d50a
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 9 02:13:29 2012 +0800
+
+ Fix a bug - when a symbol is forcefully added into local category, all other categories' begin and end should be increased.
+
+commit f0ef47e8d43bdcf3547288e7352121f9a5a90deb
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:08:12 2012 +0400
+
+ Check _gp_disp symbol existence before access it.
+
+commit daca6babfab7111e5fd8b764ae4ced79d5f8205c
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Fix MIPS_GOTSYM value.
+
+commit 9f220590f3de9cab18805e074c7f541c1face81d
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Fix bug in the NipsGOT iterator.
+
+commit ee7ce7727d57b5cd5d884b8e487be66a88a027ad
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Fix a bug in the MipsGOT::reserveEntry() code.
+
+commit 1414dcde776932e2def6422a316d1d22b7043afb
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Refine MipsGNULDBackend::scanGlobalReloc() code.
+
+commit 4ff71f8439e66c25230c6828381be3945b5f1249
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Reserve GOT entry for non-local R_MIPS_GOT16 and R_MIPS_GOT16 relocations.
+
+commit a06fdce36088665988f233b238e593f0b4db3783
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Reserve GOT entry for R_MIPS_GOT16 and R_MIPS_GOT16 relocations.
+
+commit df254304c75b183565e3ac7adc7feb452241d46f
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Implement R_MIPS_GOT16 relocation for non-local symbols.
+
+commit 52f1720b66f8fb743ad3a1101f382044f14aea99
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Implement R_MIPS_CALL16 relocation.
+
+commit 7a2378c847fbccc17ec7818113de36232e4ead9f
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Fix a typo in the function return type name.
+
+commit a1a47fd7486ee6f19c724c3757d139f8a142d415
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Implement R_MIPS_GPREL32 relocation.
+
+commit 883ea5441cc05e1787fbae17a9e6d78f59d347f1
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Implement R_MIPS_HI16/R_MIPS_LO16 relocations for the _gp_disp.
+
+commit 28a23a68d5a6c386d754e0bffab966fb27567bca
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Implement R_MIPS_HI16/R_MIPS_LO16 relocations (except _gp_disp).
+
+commit 0e1c6bcb8469bae9ee88fe2d77b61096080fe9cf
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Fix typo in _gp_disp offset.
+
+commit 62ab473c9f6365ffd9378b3d6d4c6c627a07fbb7
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Refine reservation type constant values.
+
+commit c2ee7d13534683ce18d236172e88d3b0de9a6b4a
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Add helper function to setup .rel.dyn section entry.
+
+commit 84fff7fbc2f453075a769375548c95e49bdc8dc6
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Remove handler for R_MIPS_REL32 relocation.
+
+commit faad90e5fd5ef52bdee5e886ee1e85989e23e3af
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Add flags to mark requests for GOT and .rel.dyn sections entries reservations.
+
+commit 602c0136c61e54723b5fe9ecc3e96eb66fdbe359
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Add methods to access .rel.dyn section representation.
+
+commit 41488b02c69fcbdbb54d6c02afa39c83a8dff87f
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Define _gp_disp symbol.
+
+commit 20b353a6fbaf111c50bdf6719c93204d9d285ad4
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Move calculation of the MIPS specific dynamic section entries to the
+ separate functions.
+
+commit 5d0881a53692a009c4cbcf4e1484a08ebaea632b
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Reserve one entry in the GOT. Do not support gnu extension.
+
+commit 9516ec8e00a1795de88ab5216be83f1a5148d1bd
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Write correct value to the MIPS_SYMTABNO entry.
+
+commit 0d4f4594eba1b4f8d4581366ae8799260e9c75b2
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Pass non-const reference to the MipsRelocationFactory to relocation
+ processing functions.
+
+commit d187eb62e4a279ade7e5c0f35ca250018d2aabfa
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Create reserved entries in the GOT head.
+
+commit 471b08d6347342c7bbce57a896cc260e13ad12c2
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Synchronize code with ARM implementation.
+
+commit 40ef97d600f82d95726a2b75855bfdfbef1a4e33
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Do not use std::auto_ptr to simplify the code.
+
+commit 2385d784c99a87250beb69a003ae061aa9b6e578
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Rearrange MipsLDBackend class member functions.
+
+commit 9dfd8cc0712d502b90557c1f3a9d30e7a73e2319
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Reserver and apply MIPS specific dynamic section entries.
+
+commit 1a918712e467830dcdc433656964e32305ef5b8d
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Refine local variables names.
+
+commit 1214910f8a141ddac21b9c7a596bc8f47849f56b
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Feb 8 14:00:00 2012 +0400
+
+ Pass reference to the MCLDInfo to the MIPS relocation processing
+ functions.
+
+commit 679c2440ddecb8072276ea2c44a8262d462f6c3a
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 8 17:46:41 2012 +0800
+
+ If a symbol is absolute, it should be a global symbol.
+
+commit 56cd3d6ceefb072cddbed6bf6543ac37a871fb23
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 8 17:46:12 2012 +0800
+
+ Enahnce error message.
+
+commit 8ff5d1cdeed63bb3261c9b83f1535e4ff0577cfb
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Feb 8 17:35:08 2012 +0800
+
+ Add a regression test for Plasma on ARM.
+
+ Currently running the regression test for Plasma by binary file comparison.
+ Remove it when MCLinker has more test cases to ensure that Plasma will work.
+
+commit 31c88c45e05e8a1f8ea1fccd5693e8d573127656
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 8 17:16:19 2012 +0800
+
+ Fix a bug - MCLinker should not forbid defining a section symbol.
+
+commit 771a838be86aeed4534d61ca629cb5b08d33824b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Feb 8 17:01:30 2012 +0800
+
+ Reset errno to zero where the value of errno may has changed.
+
+commit bd72555be4517d60efe2af63d4cae0760cff279e
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 8 15:43:17 2012 +0800
+
+ Fix a bug - we should finalize target symbol first.
+
+commit 68ab790946559f18f70ea508a9833832284d6312
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Tue Feb 7 09:21:00 2012 -0800
+
+ Handle R_386_PC32 in scanLocalReloc
+
+ We don't allow R_386_PC32 in scanGlobalReloc since it results in
+ writable text section in shared library and we don't support executable
+ yet.
+
+commit 834a16a16ba848e40ff68c19de6e7fd85f6ef5aa
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Feb 7 11:07:25 2012 +0800
+
+ No functionality changes.
+
+commit e6cadd10c455ad3e84c76a4bd847dcd6d586d0bc
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Feb 7 09:44:26 2012 +0800
+
+ Change the destination of cp for separate targets to use the same bitcode file.
+
+commit fcbdbad05f6efb2316baaf323468c0fce6d75afd
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Feb 7 09:34:00 2012 +0800
+
+ Fix a bug - In Relocation::symValue, check if symbol has fragmentRef if it's a section symbol.
+
+commit b619f47e3748a7bb374c08ea1797a1195e2d308e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 6 21:12:10 2012 +0800
+
+ Get rid of the use of GNU objdump and strip in regression tests.
+
+commit a780fa6b61a5ee722f5c339736dc15b59a2a6cf1
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 6 16:47:29 2012 +0800
+
+ Strip the source file path from the object file for Quake regression test.
+
+ By default, Object files contain the path of the source file,
+ This will make the comparision of binary files fail.
+
+commit 6a467f73017bc1bb37a7820b14e6b1e182b25459
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 6 16:46:15 2012 +0800
+
+ Add missing files for the regression test of Quake.
+
+commit 011856411f364126dcd06ac0a38d27cdb0a75244
+Author: Duo <pinronglu@gmail.com>
+Date: Mon Feb 6 15:25:44 2012 +0800
+
+ Fix a bug occurring in merge operation of InputTree.
+
+commit 5678e8e436192dcfbdb9225366d46afb56254f14
+Author: Duo <pinronglu@gmail.com>
+Date: Mon Feb 6 15:21:30 2012 +0800
+
+ Fix a trival bug of GNUArchiveReader.
+
+ We use the file name instead the symbol name when opening an external file.
+
+commit 0c1303641bf9a65cc13923fe259a476716626d24
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Jan 31 15:54:33 2012 +0800
+
+ Enable the functionality of reading thin archive.
+
+ Additionally, make the coding style consistent and refine the comment.
+
+commit 4b31b16b29ee16a79057412209e4770b7cb75a8c
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Jan 31 11:26:26 2012 +0800
+
+ Correct the constructor of GNUArchiveReader.
+
+commit 240babefe0ad85f71f0d3a388c72e079438cbc2a
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Jan 31 10:29:25 2012 +0800
+
+ Refine the commit of GNUArchiveReader.
+
+commit a01335007c3aa7298761cfeb3868a8e6047cde84
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 6 14:28:02 2012 +0800
+
+ Add a regression test for Quake on ARM.
+
+ Currently running the regression test for Quake by binary file comparison.
+ Remove it when MCLinker has more separate regression tests.
+
+commit 3b374c6bd177df731a32281a465484c0a33ffaff
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 6 14:17:36 2012 +0800
+
+ Move the regression tests of Relocation to test/ARM/Relocation.
+
+commit 001e7b3d1bf806b36e21ad3a7f4a04e5d703852e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 6 14:12:54 2012 +0800
+
+ Add a regression test for ARM got0.
+
+commit 6d71742e9d57608d247914e74d1304887155e19c
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Feb 6 14:08:17 2012 +0800
+
+ Add a regression test sample to demo how to use variables with FileCheck.
+
+commit 0c134b8d22b6b0bdf187ca42eba4ea7886c5c8cb
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 3 22:44:08 2012 +0800
+
+ Fix a bug in PathCache.
+
+ Missing the assignment of the parent path for the first entry when
+ read it in open_dir().
+
+commit 5345f6c466b7b08c9ebd2ee468cbec82a55d9cc8
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 3 18:07:10 2012 +0800
+
+ Fix a bug - MCLinker should only add new symbols in the output symbol table.
+
+commit e5e842f5ef4120d735682d036b384a6a9fdd7b02
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 3 11:19:23 2012 +0800
+
+ Increase version number - Quake2 Android is linkable on ARM Android.
+
+commit 69f99cb08cd9ab9c711191919f0141390638d913
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Fri Feb 3 12:13:45 2012 +0800
+
+ Refine the comments.
+
+commit 82d5f80792a60746734e81d4190c7ecad9cb4e0f
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 3 02:52:18 2012 +0800
+
+ Enable TargetLDBackend::allocateCommonSymbols()
+
+commit 19bf25970b446b110373a62eb0ee15c85557e274
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 3 02:48:27 2012 +0800
+
+ Add allocateCommonSymbols to TargetLDBackend.
+
+ Although different formats allocate common symbols in different section, but
+ all formats have steps to allocate common symbols. So, we add a new API
+ TargetLDBackend::allocateCommonSymbols() and implement it in different targets.
+
+ Some targets, such as Mips and X86_64, have different need to allocate
+ common symbols. Their LDSection, the definition of common symbols, etc. are
+ very different. So, we leave the implementation of allocateCommonSymbols() to
+ the lowerest target backends.
+
+ In ARM and X86, a basic allocation is implemented. But Mips needs small symbol
+ support.
+
+commit 13b6580af224ec8d33880812e957fb98c8c0094c
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 3 02:47:19 2012 +0800
+
+ Fix a bug - because there are may different BSS section, we should not fix the name as .bss.
+
+commit 81c4562ece94ef540cc67832bdd9300e7cf50f02
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 3 02:44:47 2012 +0800
+
+ After allocation of common symbols, all common symbols must move to Global category.
+ So, we add SymbolCategory::moveCommonsToGlobal() function.
+
+commit 2931aa2f26d38f7c4d9c4673ed614a16db431e77
+Author: luba <lubatang@gmail.com>
+Date: Fri Feb 3 02:44:05 2012 +0800
+
+ Add TLS symbol type
+
+commit 8c337e71d8b6aa7d2791f481296ff6af4fca24a1
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Feb 2 19:37:24 2012 +0800
+
+ Add Group section kind.
+
+ Let ELFReader can recognize group section first.
+ TODO: implement group section support.
+
+commit 5f448bce6fb5c6035d0b3832db9a4c08c2edc3ec
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 2 18:55:15 2012 +0800
+
+ Refactoring - by Simon's suggestion, change the reserve/applyPLTGOT to general reserve/applyTargetEntries
+
+commit cd3459a3959f0a6f22745248436c1b0d16f170bd
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 2 13:59:36 2012 +0800
+
+ Increase the version number - Quake is ready to run on x86 Android.
+
+commit b980efbdd0ce5d45cb64638129f57f829a4d1e2c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Feb 2 10:16:27 2012 +0800
+
+ Refine error message in ARMLDBackend
+
+commit 83d05ff948cfa7ceed5b5fb5f846787bd51dc684
+Author: luba <lubatang@gmail.com>
+Date: Thu Feb 2 01:00:09 2012 +0800
+
+ Fix a bug - if the symbol is in the output symbol table, arrange it. Otherwise, add it.
+
+commit cd028c67baa8d30ca9c9bbbb32c84d240f0c8d13
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 22:44:45 2012 +0800
+
+ Fix a bug - ResolveInfo in the pool does not mean it is already in the output. We should still add it into the output.
+
+commit 11e74bd8ba338ba7a9c8a2511c8acc330e4f704c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 1 20:41:20 2012 +0800
+
+ Refactoring - using comparison of pointer instead of string compare.
+
+commit 9d266c741ff9ea5f5d4e731facaac739ad0bbb24
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 1 20:33:17 2012 +0800
+
+ Reorder pass 7.a - add standard/target symbols before read and
+ scan relocations.
+
+commit 2642f21bbe8578fc1f72f54578fe17e6aa810045
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 19:57:45 2012 +0800
+
+ Add SymbolCategory's unittest.
+
+commit b5dfaa011bddfacc9ebb95e4923a278ec6267e24
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 19:20:36 2012 +0800
+
+ All reasons of force local should be the same.
+
+commit 99c9f72b76b566b6acef86e4aeae63da10068116
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 19:00:05 2012 +0800
+
+ Fix a bug - If a symbol is existent, we should not add it into output again.
+
+commit cc6ffef4605b544581305cacff7bb2771886f05b
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 18:59:17 2012 +0800
+
+ Fix a bug - In Darwin, GCC 4.2 forbit inconsistent template reference.
+
+commit af22c32a6676cd7eb3512a78a6f5cd01dbcc4218
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 17:16:36 2012 +0800
+
+ Change API - MCLinker::defineSymbol<POLICY, RESOLVE>(), add the 2nd template
+ argument.
+
+ Backends request a new defineSymbol() function - the new one can define a
+ symbol, but do not resolve the symbol immediately, just override the existent
+ symbol.
+
+ Therefore, MCLinker add a new template argument - RESOVLE.
+ If RESOLVE is MCLinker::Unresolve, then defineSymbol() defines a symbol and
+ overrides it.
+ Else if RESOLVE is MCLinker::Resolve, then defineSymbol() defines a symbol
+ and resolve it immediately. Just like the old behavior.
+
+commit 572e320a34bdd4603933ae54314b2c121c1d92ab
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 17:14:40 2012 +0800
+
+ Fix a bug - Creating a new symbol should be treated as overriding an old symbol.
+
+commit 1782eb764ac34b8dfb501905a949ddfff6cbedbb
+Author: luba <lubatang@gmail.com>
+Date: Wed Feb 1 17:13:47 2012 +0800
+
+ Refine comments.
+
+commit 5281d5dbb2081c18ffab6aad14b5413c67237824
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 1 16:19:03 2012 +0800
+
+ Modify API - TargetLDBackend::scanRelocation
+
+ Add a parameter pInputSym which is the input LDSymbol of
+ relocation target symbol.
+
+ We need to update value in relocation place (A value) if it's a
+ ABS type relocation and point to a section symbol. This value
+ should be the offset to the output section. We needs the
+ input section symbol to get the correct output offset if several
+ sections are merged to single one.
+
+commit 421b256fa93912dcdadc3cb28ee15a3719e3257e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Feb 1 15:49:46 2012 +0800
+
+ clean up the code in Layout::layout()
+
+commit e8d6546fd6a39f3f7fbaf9d7a209bddf911508ea
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Feb 1 15:43:12 2012 +0800
+
+ Refine the code - add assert to check if segment pointer is NULL
+
+commit f7095c27f9af7545c5e6301a5ca896d952220694
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 1 10:54:02 2012 +0800
+
+ Fix a bug - For R_ARM_ABS32 type relocation, no need to check if
+ it is function or not in helper_use_relative_reloc
+
+commit 82c5d35e1e3ab0c5eb5cf149ecc20a3c6bef41fb
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Feb 1 10:14:30 2012 +0800
+
+ Refine code.
+
+commit d753d4811dd53af51c6b7e39ef4a596fd0af67f8
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 31 16:16:36 2012 +0800
+
+ Fix a bug - MCLinker should not crash when it's a shared library.
+
+ if we build MCLinker as a dynamic shared library, it will crash when we load MCLinker twice.
+ This is because we use a static local variable in a function.
+
+commit cb593166652d96f05f90804b4039e181a711076b
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Jan 31 15:58:32 2012 +0800
+
+ Fix the types.
+
+commit 71242fae4bb7cb25f304ef77e1316ec3b8c842c7
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Jan 31 15:30:50 2012 +0800
+
+ Clean the code.
+
+ Remove unused variables.
+
+commit 94d18868919ffac706abaac2c7c96149154993fa
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 31 15:02:27 2012 +0800
+
+ refine comments.
+
+commit 822525dc3f1c1d9be6f99aed79996f56a969e5a4
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Jan 31 14:26:48 2012 +0800
+
+ Add basic ARM/ABS32 relocation test.
+
+ For verify relocation, we may need some tool to get the instruction of a
+ given address.
+
+commit 594b934cbedce9c16e885658557f83eb8aa2b5e6
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Jan 18 15:33:39 2012 +0800
+
+ Fix TestSample.o.
+
+commit bbcf2855efffd3932e3516bc630af2b77f907c5e
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 31 14:47:31 2012 +0800
+
+ clean up code.
+
+ For clarity, use incremental addition.
+
+commit 2162ef32bdea1484841b14a0455ab0fa5d4e1eb8
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 31 11:41:06 2012 +0800
+
+ Use isPIC to check ouput type during scanRelocation.
+
+commit 59fd2f8b6db678b4200417fe4a714d5a76cf12f2
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jan 31 10:35:45 2012 +0800
+
+ Avoid summing up sizes of .ARM.attributes sections of input files for output.
+
+ MCLinker uses the .ARM.attributes section of the first input file for output.
+ The size of .ARM.attributes in output is same as the one in first input file.
+ there is no need to sum up size for ARM.attributes section.
+
+ MCLinker will emit .ARM.attributes section in correct way in the future.
+
+commit e834ac1392db08ad7b36b26632ea690d2f5ff73f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 31 10:49:33 2012 +0800
+
+ Recover change - using comparison of pointer instead of string compare.
+
+ Because the GOT symbol will be created after creating the GOT section.
+ We won't gete the pointer of GOT symbol until creating GOT section.
+
+commit bd7730cb5f687d15c6c2db14556ef039183fa9e5
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 31 10:05:05 2012 +0800
+
+ Refactoring - using comparison of pointer instead of string compare.
+
+commit 8d797f5fe21047f8bdfbccf517d60d32d9c7058a
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 31 09:51:53 2012 +0800
+
+ Clean up code - move out create GOT from createX86PLTandRelPLT
+
+commit 787c86546655e3683642f8e159490fe3f35ebeb3
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 31 09:26:32 2012 +0800
+
+ Refactoring - For clarity, replace zero magic value by NULL.
+
+commit 27ace9924d4c527b152778651cf6dcdac9a4c6e2
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 16:56:11 2012 +0800
+
+ Refactoring - using comparison of pointer instead of string compare.
+
+commit 9f19f0c3af66bc925e3fda66cf918ee412ed4cd6
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 16:50:15 2012 +0800
+
+ refine comments.
+
+commit 15b9c8ca41cf13230f53353c5ae19bcf138c755c
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 16:46:03 2012 +0800
+
+ clean up the code.
+
+commit 4c7611f090f3baca46568573ed614bfb49b73133
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 16:43:54 2012 +0800
+
+ Refactoring - For clarity, replace zero magic value by NULL.
+
+commit 801d4ec509e24dd819bfb2bcd3bb6647224ca9dc
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 16:27:55 2012 +0800
+
+ Refactoring - Move some trivial functions from ARMLDBackend implementation file to header
+
+commit 37e04b69d3c976175dce2a049158dd6bb6159928
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 16:21:07 2012 +0800
+
+ Refactoring - change the structure of emitSectionData from if/else to ripple if/return.
+
+commit edc03b8cf64f9fb6db777fcf7b5b21fd09f49ddf
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 16:04:56 2012 +0800
+
+ Refactoring - move the details of emission of ARMGOT from ARMLDBackend to ARMGOT itself.
+
+commit fc57a81e73498745db6e9bb1dbfc9a79bb4f89ec
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 15:58:01 2012 +0800
+
+ Refactoring - move the details of emission of ARMPLT from ARMLDBackend to ARMPLT itself.
+
+commit 65b49f4d6e4da078f1e6237dd3e50ce6f0962a28
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 15:44:25 2012 +0800
+
+ Refactoring - auto-variables' names should be lower-case words.
+
+commit cde5fec451a408232244039ead6513d41683ae19
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 15:26:09 2012 +0800
+
+ Refactoring - apply GOT and PLT should be done during doPostLayout(), not during emitSectionData().
+
+commit 6c5b7068bfaf560ef64a255cc0236109e0afc872
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 15:06:35 2012 +0800
+
+ Refactoring - select file format first. This can remove many duplicated code.
+
+commit 33eab96e81b3598c026076cdbf0d300fb7fd2eff
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 30 14:57:44 2012 +0800
+
+ Refactoring - in order to keep encapsulation, we should use Output rather output's type as input arguments.
+
+commit 39e6850693a2960a3dec84f9ce674c21ac429ba9
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 30 14:10:04 2012 +0800
+
+ Avoid const cast in emitProgramHdrs
+
+commit 88e8f4035870f5807a1c62d368274b53e67d5544
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Jan 24 09:16:41 2012 +0400
+
+ Small cleanup of OutputRelocSection class.
+
+commit a1dca7451e684791374fd9dd2dcae196993d75b5
+Author: luba <lubatang@gmail.com>
+Date: Sat Jan 21 22:38:22 2012 +0800
+
+ Refactoring - remove some stupid interfaces.
+
+commit e088bd0415d86efd20d01ca5c43f3e964c4325e8
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Fri Jan 20 09:13:43 2012 -0800
+
+ Properly handle R_386_PLT32 without PLT entry
+
+commit 004516520594d691b776fa7eb1f94efb864fdddd
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 20:44:46 2012 +0800
+
+ Remove unneeded header.
+
+commit a4e931b52d501eb2152723bd79ce5573c88b16d7
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 20:34:00 2012 +0800
+
+ Add class X86GOTPLT.
+
+ X86GOTPLT is simliar to ARMGOT.
+ It is used to emit .got.plt section on X86.
+
+commit bc0fa7d5596471b57e0939fb18de95a7d130c216
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 19:45:11 2012 +0800
+
+ Revise comments, no functionality changes.
+
+commit 6ea1c6822197c98fa968e8dd53504742156c36da
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 18:08:49 2012 +0800
+
+ Reorder function declarations and add comments.
+
+ No functionality changes.
+
+commit d8f0ed69ed5cafc94bac8ba360994d960f99abb2
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 17:24:52 2012 +0800
+
+ Remove friend functions in ARMGOT.
+
+commit d68176ad2fed547ad7f80a9addde572a6fd20d4a
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 16:30:51 2012 +0800
+
+ Refactor some code in applyPLT1() out into applyAllGOTPLT().
+
+commit 4103e6bec356a08aa45b8c8872ba35f0ccbd0576
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 16:19:08 2012 +0800
+
+ Use iterator to process all GOTPLT entries.
+
+commit 0a0f270f89393870a2e9fc2835f920752ba886f7
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 15:16:00 2012 +0800
+
+ Start refactoring ARMGOT and ARMPLT for reusability.
+
+ 1. Rename general got entry to normal got entry.
+ 2. Refactor some code out into reserveGOTPLTEntry().
+
+commit e5160ae90cb87de069f4f8f9de820133c9168276
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 20 18:06:09 2012 +0800
+
+ Avoid string comparison in getSectionOrder functions
+
+ we can get the LDSection from ELFFileFormat and compare it with the given
+ LDSection directly.
+
+ TODO: Review the ELFFileFormat for executable and object files.
+
+commit 76e3041eed22558131dc0f1235168e3338f0bd7f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 20 15:10:31 2012 +0800
+
+ Refactoring - ARM/X86/MipsDynRelSection to general OutputRelocSection
+
+ Because the output relocation is format- and target-independent,
+ we move origin DynRelSection from ARM/X86/Mips to Target.
+ The original ARM/X86/MipsDynRelSection have totally the same
+ functionality. Now they share the same structure.
+
+commit e82a5cbc98a2194ba91d2bc74654dc727259072b
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 20 13:20:34 2012 +0800
+
+ Adjust the section order of .got and .got.plt in X86GNULDBackend
+
+commit a609d1ec135d702ab9369ab94c0a305021af433a
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 20 13:19:37 2012 +0800
+
+ Refine ARMGNULDBackend::getTargetSectionOrder() since ARM has no .got.plt
+
+commit a4379af62da91cc3c948acea49d26beb652648e4
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 20 13:18:07 2012 +0800
+
+ Minor code refinement in GNULDBackend::getSectionOrder()
+
+commit f766140caeed2478e7d99ffbdbae5676b8253d14
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 20 11:33:01 2012 +0800
+
+ Remove obsolete code.
+
+commit 1def14764c99de206929bc599fb949e023588d84
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 20 10:56:33 2012 +0800
+
+ Remove obsolete code.
+
+commit d59be6e9457e93a552b44c9c36e46cd0d129d765
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 20 10:02:17 2012 +0800
+
+ Increment position counters for local symbol and common symbol after insertion.
+
+commit f73f6db8bc672707990a1a735117cd9e5add9d99
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Thu Jan 19 13:14:31 2012 -0800
+
+ Check if the symbol is preemptible on x86
+
+ It is x86 part of commit 8ba9c4b54a360cb3d3253b1b56a8afe0317f53bf
+ for arm.
+
+commit 4a213c598051fc0a53f26edf30b85ffab5883cff
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Thu Jan 19 12:58:09 2012 -0800
+
+ Replace isSymbolPreemtible with isSymbolPreemptible
+
+commit f190b4771a51918d1768c73256cd3f6c30d1e7f2
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Thu Jan 19 12:44:05 2012 -0800
+
+ Implement X86RelocationFactory
+
+ Known limitations:
+
+ 1. Only shared library support is tested.
+ 2. There is no TLS support.
+
+commit 1769226d41b7190b37e2f4193d3757860fb7ef25
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Thu Jan 19 12:35:52 2012 -0800
+
+ Implement shared library support in X86LDBackend
+
+ It shares many codes with ARMLDBackend.
+
+ Known limitations:
+
+ 1. Only shared library is supported.
+ 2. Only PIC input is supported.
+ 3. There is no TLS support.
+ 4. It doesn't use .got.plt section.
+
+commit ed1c3740140cd1f0312becc1104450affb80854b
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Thu Jan 19 12:31:54 2012 -0800
+
+ Add X86DynRelSection
+
+ It is copied from ARMDynRelSection.
+
+commit 13479a0d785747e0f84f18cbeb9416505711b65c
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Thu Jan 19 12:20:15 2012 -0800
+
+ Add x86 GOT and PLT support
+
+ X86 GOT and PLT support is based on arm GOT and PLT support.
+ X86 and arm share many common codes in this area.
+
+commit aa4f6ce3277acfaf24d6a015a4474799556eafc7
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Thu Jan 19 12:04:05 2012 -0800
+
+ Add m_HasGOTPLT to indicate .got.plt support
+
+ We can avoid GOT0 entries with .got.plt section so that we don't create
+ them if PLT isn't used. To support .got.plt section, we must combine
+ .got section and .got.plt section into a single GOT.
+
+ For now, x86 doesn't use .got.plt section. We always have GOT0 entries
+ in at the beginning of .got section even if PLT isn't used.
+
+commit e2f5694303e3c21c44f45f8074521fe7b702e033
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 20 00:55:29 2012 +0800
+
+ Fix a bug - The order of the symbols should be "File" -> "Local" -> "Common" -> "Weak" -> "the rest"
+
+commit 7207ac264dddf47c282062e5c39ef641f3e1d220
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 20 00:53:52 2012 +0800
+
+ ResolveInfo adds a new friend class MCLinker
+
+commit daeb39431219944cd79303c8fa514ead5949efd1
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 20 00:53:19 2012 +0800
+
+ Refine comments.
+
+commit a5e65e7843af4303e8b29aac2926c539661fe003
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 19 22:13:21 2012 +0800
+
+ Use co-variant return type to return target-specific dynamic section.
+
+commit cb86c80b01c35c83dd1da47aa4557acf98a5d7aa
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 19 20:13:27 2012 +0800
+
+ Implement DT_PLTGOT for ARM and X86.
+
+ DT_PLTGOT for Mips is still unsupported.
+ MipsELFDynamic::reservePLTGOT() and
+ MipsELFDynamic::applyPLTGOT() need implementation.
+
+commit 6f4e4a327d278e46ba3d2904ae7a611e2c293906
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 19 16:31:01 2012 +0800
+
+ Add virtual functions for DT_PLTGOT entry on various target.
+
+commit 24164f8c8810fea57e087c4cc939a2f9a060b5ef
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 19 16:14:35 2012 +0800
+
+ Refactoring - let different target backends can implement its own dynamic section.
+
+ If a target backend need its own dynamic section, it can override dynamic() and
+ use co-variant return type to generate its own dynamic section.
+
+commit 8ba9c4b54a360cb3d3253b1b56a8afe0317f53bf
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 19 11:49:27 2012 +0800
+
+ Fix a bug - check the symbol is preemptible
+ when attmpt to generate ouput relocation of R_ARM_RELATIVE type.
+
+commit 53a5a14283d3ea03d5c74607bd2eda7c44105b76
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 19 10:33:49 2012 +0800
+
+ Modify API - Relocation::apply and RelocationFactory::applyRelocation
+
+ Add parameter MCLDInfo for applying relocation.
+
+commit 1a52a94dd9e5858b551d643d5f7ead8fe83b12c9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 19 09:22:42 2012 +0800
+
+ Fix 80-column violations.
+
+commit b85a3dbe8fb1b20f442b8b40de8c87b748902559
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Jan 18 10:39:15 2012 -0800
+
+ Update comments in ELFWriter.cpp
+
+commit d5341a19812027751915a1750c5f25494d1cee9d
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Jan 18 10:36:19 2012 -0800
+
+ Handle SHT_DYNAMIC section in getELF64SectEntrySize
+
+commit 671b356aa5152c00f992e89fd2861818b533716e
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Jan 18 09:44:07 2012 -0800
+
+ Handle SHT_DYNAMIC section in getELF32SectEntrySize
+
+commit 013edf93ccefdba1d9743fd08fc5370d6497f561
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Jan 18 09:39:18 2012 -0800
+
+ Fix another typo in comment
+
+commit c22ce3fd9839b6b809e9728d910fb07dac67eca9
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Jan 18 09:37:24 2012 -0800
+
+ Fix a typo in comment
+
+commit 36f89e2c2659807ae273f6993b85792f678ccced
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Jan 18 14:50:28 2012 +0800
+
+ Fix bug: PLT is not in thumb mode.
+
+commit 8fda3164400240239cbb0f85e0c1fa839db4a5a9
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Jan 18 14:23:03 2012 +0800
+
+ Implement ELFWriter::emitRela
+
+commit 2b23a398b1aa2e97142aba856cc34ef1090f0cb3
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Jan 18 12:09:27 2012 +0800
+
+ Fix typos.
+
+commit b26c74a9a119f38b116c4712cbb2d8509dd11f77
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Jan 18 10:58:08 2012 +0800
+
+ Check if output relocation type is valid during scanRelocation
+
+commit b0e75c73eb2f069f1a4e2ac565996cbe2bbaba8d
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Jan 18 10:46:46 2012 +0800
+
+ Fix typo.
+
+commit 9aea15094a1e69258066fdbf6dbd592178b5c526
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Jan 18 10:37:56 2012 +0800
+
+ Add a sample object file for relocation testing.
+
+commit 748f5c777796f3a49ff20383d5e6cdc95dec2b60
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jan 18 09:50:36 2012 +0800
+
+ Replace delete by free() for the memory space allocated by malloc().
+
+commit 65d345de14f0a19c91c97dbdd45744010f6b7f4f
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Tue Jan 17 10:02:35 2012 -0800
+
+ Emit program headers for x86
+
+commit e741f76fa3177a74c888851c9b494e95b1db50dd
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 17 22:41:01 2012 +0800
+
+ Increase version - 1.6.0-open
+
+ In current version, Quake can be linked on ARM Android.
+
+commit 07040cd7a7fb37ac0e800d83d6f7c77f04c7b89f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 17 21:21:18 2012 +0800
+
+ Fix a bug - Write back relocation target data to correct place
+
+commit 3fd03f0f18d093a241d9b883e7cbe6838e515f6e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jan 17 20:42:00 2012 +0800
+
+ Fix a bug where modifying the last GOT0 entry unexpectedly.
+
+commit 36b0ad0454ca0b0d3a035e7fd5d2d6ce008b190d
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jan 17 20:15:06 2012 +0800
+
+ Fix a bug where the iterator of got.plt will walk through general got entries.
+
+commit 047549ec677b3728ce819fe447d286b9005e934b
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 17 20:01:16 2012 +0800
+
+ Refine code, no functionality changed
+
+commit 97d07ac833ad2cdd4956ddc57900462f024bcd37
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Jan 17 19:00:28 2012 +0800
+
+ Add an sample test.
+
+ This test will generate an ARM ELF object file and a dynamic share
+ object, and check the symbols and sections which are basically required
+ are exist.
+
+commit 3f6e8610dea08566466defdab5c695b1544df44d
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Jan 17 18:46:48 2012 +0800
+
+ .ll treat as test files.
+
+commit 5705123368ea0c47580d6379a5ab22b2865e078a
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 17 17:49:41 2012 +0800
+
+ Fix a bug - if the backend does not recongize the symbol during finalizeSymbols(),
+ MCLinker should take over the symbol.
+
+commit 5b2d726dcf7d7727025381260a110d27727c6c2d
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 17 17:46:12 2012 +0800
+
+ Modify API - TargetLDBackend::finalizeSymbol
+
+ Add return value:
+ return ture - if backend set the symbol value sucessfully
+ return false - if backend do not recognize the symbol
+
+commit ae935e3cf795e1608a0113ce8cec3873bc854d7e
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 17 17:00:43 2012 +0800
+
+ Fix a bug - the scale of relocations is huge, so, we should not sync relocation-by-relocation.
+
+commit f6d22bbc41fe828d0673c1b90ad470895a394379
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 17 17:00:20 2012 +0800
+
+ Add a new function - MemoryArea::sync()
+
+commit 8ba345695fb31a6023e47edeed3f3a3af4ab1b9f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 17 16:21:39 2012 +0800
+
+ Set output relocation symbol index to 0 if it's R_ARM_RELATIVE
+
+commit 400abcaa602b9ee8e49d685d8fb432c8b71e4f54
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 17 16:18:24 2012 +0800
+
+ Modify Relocation::symValue
+
+ If relocation meets a section symbol, set S value to
+ the output section's virtual address
+
+commit 4fd17381cec853596d0824771cdf12eed2b2ddab
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 17 15:51:46 2012 +0800
+
+ Turn off CodeGenPasses if we're performing linking.
+
+commit da9abb62f25779d122c0539e4358e3ffd7ab33d9
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 17 13:44:45 2012 +0800
+
+ refine code - add an assertion to check if a Relocation object has a valid symInfo.
+
+commit e236324e5505674565717ac2e5cc8a4bc9516b08
+Author: luba <lubatang@gmail.com>
+Date: Tue Jan 17 12:15:57 2012 +0800
+
+ Fix a bug and conform to clang++ - we should not refer to a template argument.
+
+commit afeb4519d3429d5359b0f4057c42364350300f1d
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 17 12:11:19 2012 +0800
+
+ Fix a bug - Scan ABS type relocations
+
+commit a83ddc8167383f761cf6b3f66db8bb526bb23fd2
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 17 12:06:01 2012 +0800
+
+ Fix a bug - do not report error unsupport relocation type when
+ applying relocation.
+
+ Because a symbol's reserved won't be 0 if it has relocations with
+ ABS32 and REL32 type point to it. In this case, we should generate
+ dynamic relocation for ABS32 type relocation and perform static
+ relocation on REL32 instead of reporting error.
+
+ TODO: Report this error when scanRelocation
+
+commit 5046913407dbd8d15a11e308e1f1e939ae3fa3e0
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Jan 17 11:03:28 2012 +0800
+
+ Let Output be in build dir.
+
+commit 6addb106e6a7b00ddd877cfe20278776d6f98da9
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 16 23:30:57 2012 +0800
+
+ Increase version - in current version, ARM Android plasma is ready.
+
+commit 8951b13bed44207b4dd6b61afa15bf7ff03edb74
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 16 23:14:16 2012 +0800
+
+ Clean comment in ARMLDBackend::scanRelocation
+
+commit 07189308b1956502ec1ae375218c7aa2cc27f158
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 16 23:07:15 2012 +0800
+
+ Add parameter MCLDInfo to TargetLDBackend::scanRelocation
+
+ In ARM scanRelocation, we need input options to judge the
+ symbol is preemtible or not.
+
+commit f1de3601284cffa67cffc89e24de439b8d2c0874
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Jan 16 22:15:49 2012 +0800
+
+ Don't modify variable within assert() statement.
+
+commit 4c4cdbd3fdc8c08ac86a6ced57b15e5a08d045df
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 16 22:13:13 2012 +0800
+
+ Fix a bug - whether a relocation entry needs a symbol in .dynsym, is not
+ determined by ResolveInfo::reserved(). Relocation entry pushes the symbols
+ into force local by itself.
+
+commit 29c432726133bff7c8f1319690bb98bc551f268c
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 16 20:27:21 2012 +0800
+
+ Refactoring MCLDFile and MCLDOutput - setSOName should be in MCLDFile.
+
+commit 3a975dd5e0fa9b32899f63e5926c8ef337d27318
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 16 20:12:22 2012 +0800
+
+ Fix a bug - do not report error when applying relocation with
+ branch type if its target symbol's reserved() is not 0 or PLT
+
+ Because there might be a symbol with GOT and there is another
+ relocation with branch related relocation type
+ (CALL, PLT32, ...) point to this symbol, and we no need to
+ generate PLT entry for it. In this situation, the symbol's
+ reserved() won't be 0 or PLT, but it's still correct and we
+ should perform static relocation on it.
+
+commit f275631743978a7483a165f49cf1cbf01e6486c2
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 16 18:28:34 2012 +0800
+
+ Fix a bug - Undefined and dynamic symbols should have zero size.
+
+commit 39a3709f54c41b3131c94440e7b1aecad7e658c3
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 16 18:17:03 2012 +0800
+
+ Fix bugs - ARM relocation applying functions
+
+ We may generate a got and a plt entry to the same symbol,
+ so we should take all these situations into consideration
+ when applying relocation.
+
+commit 65e1c0e732509a2ed2603f5cf7196e480b79f120
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 16 17:41:26 2012 +0800
+
+ Fix a bug - if a symbol or a section can not be found, use zero index.
+
+commit d1575fc2169271f9e1a62d14b10a746ae8af0da5
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 16 17:31:21 2012 +0800
+
+ Refine the code to set SONAME
+
+commit 0b354cbf50d949f0871bf03b7e7738da307f3f75
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 16 16:42:37 2012 +0800
+
+ Fix a bug - a undefined symbol meets a dynamic defined symbol, should use the
+ undefined symbol's binding.
+
+commit a472f2a1710a7359c1b761d877ca2caa739ed9bb
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 16 14:45:06 2012 +0800
+
+ Change data to Nop if applying relocation meets a weak undefined symbol
+ and we didn't generate a plt entry for it.
+
+commit fe6bec3c29d0696ffd3cc00029a232bcde78eff9
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 16 14:12:58 2012 +0800
+
+ Fix a bug - section symbol should stay at Input's LDContext, but do not
+ get into Output's LDContext.
+
+commit bea7b1b44f68085b8061e17f5dde244b64190312
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Jan 16 12:11:26 2012 +0800
+
+ Fix a bug for DT_JMPREL and DT_PLTRELSZ.
+
+ Values of DT_JMPREL and DT_PLTRELSZ should be decided by .rel.plt section.
+
+commit f035c318c05d9bffba3f7faadd1da27f652fef59
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 22:27:13 2012 +0800
+
+ Fix a bug - MCLinker should write down the symbol's value no matter if the
+ symbol is absolute or not.
+
+commit 50af09e996bc24b3d747c1abaf1fe71a677e99d4
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 22:10:01 2012 +0800
+
+ Fix a bug - Finalize symbol value should use SymbolCategory, not output's symtab().
+
+commit d162a1222c9b1a7906844a8d63cee07ed155cef5
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 20:38:15 2012 +0800
+
+ Fix a bug - Output's LDContext::symtab should be maintained before emitRelocation
+
+ move emit NamePools before emitRelocation.
+
+commit 164c0a4b5ddde790f2a6c4b4902964fd04b84ec2
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 20:37:27 2012 +0800
+
+ Fix a bug - LDContext::getSymbol by name should skip the first symbol.
+
+commit a6deea7cb4c5c8b4a5cd1de2a855c2697d2de5d7
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 20:37:02 2012 +0800
+
+ Remove redundant creation of first ResloveInfo.
+
+commit a61badd2124703d0dd50f61f1bd096b54a7c45f6
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 19:52:23 2012 +0800
+
+ Fix a bug - the symbol index of the output dynamic relocation should correct.
+
+commit 04b9a93c70987f5156b1c4da3a9e4bfb15698725
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 19:50:39 2012 +0800
+
+ Add iterator for SymbolCategory.
+
+commit 9a6175b5d9c3f34aabae14704fb3181126c2c25d
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 19:49:48 2012 +0800
+
+ Add new ConstIteratorTraits and NonConstIteratorTraits for getting the right iterator.
+
+commit 5fca0980f01296b628eb52d3ef1a86648ef01799
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 19:48:51 2012 +0800
+
+ Summon old SymbolCategory.
+
+commit 5b7a347544a3d96d2a9427f528953f3adece2fc3
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 13 17:10:03 2012 +0800
+
+ Refine MCLinker::syncRelocationResult
+
+commit 4440c9ae6b3ebf94e7a38581d945262e801c9d3e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 13 16:41:47 2012 +0800
+
+ Add function MCLinker::syncRelocationResult
+
+ Move write back relocation target data from applyRelocations
+ to this function. Relocation target data shold write to
+ output region and should write after all section data has
+ been written, so that it will replace the input data to the
+ relocation applying result.
+
+commit 995b415ce3097b8ab6361a12acaf0e60266568d9
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 13 16:39:14 2012 +0800
+
+ Add API - MCLDDriver::postProcessing
+
+ Let MCLinker do any needed modification after all
+ processes.
+
+commit 4b6ef391f36547de5255eb1a00fc8388e701cafb
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 13 14:14:57 2012 +0800
+
+ Refactor ELFWriter::emitRel().
+
+ No functionality changes.
+
+commit c59b007bae34fbd219014bdd16fe64a34b186b53
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 13 11:21:58 2012 +0800
+
+ Split out emitRelocation() into emitRel() and emitRela().
+
+ No functionality changes.
+
+commit 31da795373a3cb7ce2dfa8fcd66b1522545d7ac3
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 13 09:48:50 2012 +0800
+
+ Refine formant
+
+commit b829cf34ecaceeb32384efc9ac2bde7c7c5f369c
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 13 09:45:58 2012 +0800
+
+ Fix a bug in function ARMPLT::applyPLT1.
+
+ Apply right value now.
+
+commit ea018e93504c468c58b200b0cc47c27fb5e87460
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 13 09:01:01 2012 +0800
+
+ Use virtual address to apply PLT[0] and PLT[N]
+
+commit 80e6ec1088f5ebeb21c454e75cd71863f3724692
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 03:16:15 2012 +0800
+
+ Fix a bug - dynamic symbols should have 0x0 value.
+
+commit 4cc20c0afcb8c9ec43aded25a60d7d5cfaf19c6c
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 03:05:11 2012 +0800
+
+ Fix bugs - MCLinker should maintains the output LDContext's symbol table.
+
+commit 839d95a416b3a71fcbe5dfe914a39251b70c28ff
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 03:04:39 2012 +0800
+
+ Add a new function - LDContext::getSymbol by name.
+
+commit 9aa004ae51eb8cfe89b79a4b872a87994575999f
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 01:37:41 2012 +0800
+
+ Fix a bug - dynamic symbol's output section should be undefine.
+
+commit 95e23aeb035a5dacefc3f2e83f534b47b02f280f
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 01:20:09 2012 +0800
+
+ Fix a bug - local symbols should be read but do not resolve them.
+
+commit a3483669541e8def1e7880ac64b161f928a095a4
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 01:19:46 2012 +0800
+
+ Fix a bug - the first symbol need to be inserted.
+
+commit fd906f7b5aa90d156e1279bc9522643b19372ac2
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 13 01:03:36 2012 +0800
+
+ Revert ab3d09e014f6
+
+ revert "reading symbols from the symbol table's first not local symbol."
+ Because relocation entries need local symbols, we read them but do not
+ resolve them.
+
+commit ab3d09e014f651d8b5618ad79d145886ff30d8d4
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 12 20:31:44 2012 +0800
+
+ Fix a bug - the first entry of the symbol table should not be put in LDContext::symtab().
+
+ LDContext::symtab() is used to group symbols into different file. It's not use to maintain
+ the index of input symbols.
+
+commit 1e1e8825efd95b2a9828838d114871ef481e0ace
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 12 20:29:10 2012 +0800
+
+ Fix a bug - the first fragment's offset and order is not set.
+
+commit 8c5bc4a3994cab28939969ade167b145bd9bddf9
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Jan 12 18:29:00 2012 +0800
+
+ Set up input shared objects' SONAME for DT_NEEDED
+
+commit 0aa76f98a3eb0d5f7be17f19869dc2f1ae681b00
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 12 17:49:50 2012 +0800
+
+ Modify ELFWriter::emitRelocation
+
+ Set output relocation r_offset to virtual address
+ when buiding .so or executable, otherwise set to
+ section offset.
+
+commit 528d7f35853befc4a1646081bf339500dd21c37c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 12 17:27:47 2012 +0800
+
+ Set GOT reserved entry value when emit .got section.
+
+commit 9737942ead9c2fb6177cd33e09bc98b64a6ee29c
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 12 16:45:20 2012 +0800
+
+ Refactoring - let TargetLDBackend::initStandardSymbol() become a pure virtual function.
+
+ Because different format-dependent target backend should implement its own initStandardSymbol,
+ I leave it as a pure virtual function.
+
+commit 1ba759878f57b6084e49112bf02b8579ac72cbfe
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 12 16:24:07 2012 +0800
+
+ Prevent relocations from double free.
+
+ Relocations are double free by both iplist and GCFactory.
+ To temporarily solve this problem, we new relocations
+ directly instead of allocating their memory space by
+ GCFactory.
+
+commit 9fe80774372f17b878447e0fa8155290cf7a3f22
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 12 16:13:31 2012 +0800
+
+ Write back Relocation target data to MCFragment
+
+commit 3e42c0eae9264e93fecdebbdece54d67f716f4e5
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Jan 12 15:58:35 2012 +0800
+
+ Fix hash section size calculation.
+
+ The number of symbol table entries should equal to nchain.
+ Therefore the previous fix is wrong, now revert it.
+
+commit 1480a43ccec6ab5f445ac8832c50b177c2b0bf50
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 12 14:11:52 2012 +0800
+
+ For performance, remove redundant malloc().
+
+commit 3b8725ed4dd1e69239cadef98070656b119a31e5
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 12 13:48:58 2012 +0800
+
+ Set up DT_SONAME.
+
+commit d53a0f7f722707476a7b4857dd57968e21565441
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Thu Jan 12 12:59:12 2012 +0800
+
+ Revert "Fix GNULDBackend::emitDynNamePools() to handle hash conflict correctly.", to
+ maintain the same chain order as gold.
+ This reverts commit 605f04d198ed521d9697707aa0d88cfded04da5b.
+
+commit 605f04d198ed521d9697707aa0d88cfded04da5b
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Thu Jan 12 11:56:37 2012 +0800
+
+ Fix GNULDBackend::emitDynNamePools() to handle hash conflict correctly.
+
+commit f65b48e0c7707b8d1f5db89f89713d63171a3e9b
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 12 11:55:03 2012 +0800
+
+ Fix a bug - should not override existing bucket.
+
+commit d9bd4b564e0da97dbb4d3da41c34b73fd88718f7
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Jan 12 11:17:48 2012 +0800
+
+ Fix .hash, .symtab and .strtab size calculation.
+
+ Symbol table already contains NULL entry, no need to write it again.
+ Hash table size calculation should get rid of NULL entry.
+
+commit ceb5a8994c5d8e2a6874eb26b70b4035ac1fc3bc
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 12 10:33:56 2012 +0800
+
+ Update ChangeLog and VERSION.
+
+ Trivial cases generated by llvm-mcld have worked on ARM. For example,
+ the shared library, whose source code only has "int g = 3;", works now.
+
+commit 4d45efa22f97db79decf47b3c2a33a268955d5d5
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Thu Jan 12 09:01:30 2012 +0800
+
+ Include missing header <set> and fix naming.
+
+commit 5347b51798e938af883b52ce591977f2046fc405
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 11 17:57:07 2012 +0800
+
+ Fix a bug - First symbol in both .dynsym and .symtab should be NULL symbol.
+
+commit 2fc92c746ab376a44895b503061d1acd3143d41d
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Jan 11 17:51:30 2012 +0800
+
+ Fix another typo for DT_SYMTAB and DT_STRTAB
+
+commit 5245cca946c4258c5b0eeff923115264b6b35e47
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Jan 11 17:32:37 2012 +0800
+
+ Fix typo for DT_SYMTAB and DT_STRTAB
+
+commit fa6ebb87afcf5bf8b06f7fb05056025e7c26f794
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 11 17:15:04 2012 +0800
+
+ Change the defintion of MCLinker::defineSymbol.
+
+ Because some symbols need to set as a local symbol forcefully, so we
+ should separate MCLinker::defineSymbol() into two functions:
+
+ MCLinker::defineSymbol<AsNeed>() and
+ MCLinker::defineSymbol<Force>()
+
+ There two functions are both inserting symbol into the symbol table and
+ resolve the symbol immediately.
+
+ MCLinker::defineSymbol<AsNeed> is just like Google gold linker's only_if_ref.
+ If there is existing an old symbol, the symbol is not defined until the
+ old symbol is a undefined reference.
+
+ MCLinker::defineSymbol<Force>() defines the symbol and resolves it, no matter
+ if the existing symbol is a undefined reference.
+
+commit cff88c952e1b0806f4f8449cca46b6ff05046b64
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Jan 11 14:43:43 2012 +0800
+
+ Update the output section index as final section ordering is known
+
+commit 5f56778a19faa529a4ee4cb2e939b89a15843a70
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Jan 11 10:39:25 2012 +0800
+
+ Move define symbol _GLOBAL_OFFSET_TABLE_ from
+ ARMLDBackend::initTargetSymbol to ARMLDBackend::createARMGOT
+
+ In scanRelocation, if we meet a relocation with the
+ symbol _GLOBAL_OFFSET_TABLE_, we should define this
+ symbol immediately to let the relocation get the
+ resolved symbol which we defined. And that the correct
+ judgement will be processed for this relocation.
+
+commit 722990656bb7aec860669391a92f9644920962be
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 10 14:36:31 2012 +0800
+
+ Fix a bug - ARMDynRelSection::reserveEntry
+ should reserve number of pNum entries
+
+commit 5093c3bff9b26e199aaa33cf17a6786060b8d18f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 10 14:31:45 2012 +0800
+
+ Modify RelocationFactory::produce
+
+ Check target and host endian to make sure if byte swapping is needed
+ when generate target data for relocation.
+
+commit 40aed57bc0eba6834e13bfd2462c563c4c0f8363
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 10 14:30:00 2012 +0800
+
+ Move byte swapping functions from ELFReader.h to SizeTraits.h
+
+commit 52fa03aa90430d45a6861e32e9164a8451d9ea34
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 10 11:22:37 2012 +0800
+
+ Refine formats
+
+commit ecba32742706bf7369d472a933b0491e27762b6c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 10 10:37:16 2012 +0800
+
+ Fix a bug - RelocationFactory::produce
+
+ No need to shift the target_data after copying because
+ we only copy the needed byte from fragment content.
+
+commit 9d2fc5986573e36949fe6a0694a92068156fd073
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Tue Jan 10 10:21:17 2012 +0800
+
+ Fix ARM PLT32 relocation bug.
+
+ The REL addend of B, BL, BLX should do 2-bit left shift
+ after extracting from instruction.
+
+commit d22942580c47d168c6b44c0d12331c8e110629e3
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 10 09:30:35 2012 +0800
+
+ Emit program headers if output is so or exec
+
+commit e1b21c08eb57828b2f8c4d48d04310790c4c9711
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 19:59:01 2012 +0800
+
+ Minor code refinement. No functionality changed.
+
+commit deacd848bdc8fbfad6331e32fdf34336275f6898
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Jan 9 19:34:10 2012 +0800
+
+ Replace strcmp by address comparison.
+
+commit 70b3e196b104ec518fc6056f7d39eebe69a256db
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 17:42:46 2012 +0800
+
+ Refine the code to calculate mem size of ELF segments
+
+commit f8a85823f66cdc3f76b0fd6816b584cd11041df9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Jan 9 17:25:24 2012 +0800
+
+ Emit the section .ARM.attributes directly from the input file.
+
+commit b070fc27aad35afa8551b665af79a174359303b7
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 17:14:49 2012 +0800
+
+ Refine the code for PT_LOAD segments in GNULDBackend::createProgramHdrs()
+
+commit 934175c2a96571854a0c9df3c79c8c0b67e39f88
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Jan 9 16:09:40 2012 +0800
+
+ Refine the SectLinker's constructor interface.
+
+ Values passed to the constructor of SectLinker (and its derivatives) are now
+ all in SectLinkOption.
+
+commit b4f7b155285b5183a3d7f5627cfa5a4a7c9482f2
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Jan 9 15:33:30 2012 +0800
+
+ Let SectLinkerOption start playing its role -- in that way, we're able to seprate the user input (from command line) processing from SectLinker.
+
+commit 377e533ecc5dde6ab10f714ed19abf2d02059b21
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Jan 9 14:56:54 2012 +0800
+
+ Interface change: SectLinker::addInputsBeforeCMD() and SectLinker::addInputsAfterCMD()
+
+ are suppressed to
+
+ SectLinker::addTargetOptions().
+
+commit 0015c8922cf82d31a279157004167adc1c65ee44
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Jan 9 14:35:50 2012 +0800
+
+ Interface change: pass SectLinkerOption to the constructor of SectLinker instead of MCLDInfo (SectLinkerOption has already contained this.) This invloves the interface change from LLVMTargetMachine to all derived target- specific SectLinker.
+
+commit 1111a1723034142fab1645281e4679ca2b3b0dfb
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Jan 9 14:34:48 2012 +0800
+
+ Introduce class SectLinkerOption. This will be used later to seprate the "data" (i.e., user input from command) from the library (SectLinker itself).
+
+commit 478a5f7e2b90fc5b46819e61e174dcb3e3cf7238
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Mon Jan 9 14:33:23 2012 +0800
+
+ Refactor class PositionDependentOption out from class SectLinker and introduce "derived PositionDependentOption" to handle different kind of options.
+
+commit 1a1f4e448b5f87d9e8f846f8cb56755225cdc6c8
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 16:38:49 2012 +0800
+
+ Not include .bss in output if its size is zero.
+
+commit d960a402d99f6534eca4c5ff72a067b9e2ddae5c
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 16:35:00 2012 +0800
+
+ 1st ELF PT_LOAD segment should include ELF file header and program headers
+
+commit eec23b196dfc13b543c35c9198d2e69434331c91
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 16:16:52 2012 +0800
+
+ Add functions to get the first/last section in ELF segment
+
+commit 3f35b2331065e27df2b4bc6337f7845fc68942b9
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 9 15:49:13 2012 +0800
+
+ Fix a bug - GOTEntry::getSize return correct entry size
+
+commit 69975829d19e4df1b0cf749edd02e2e8a4d10a87
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 9 14:48:18 2012 +0800
+
+ Use virtual address of .got and .plt section when applying relocation
+
+commit 4abd0ac66e9fa9c5a155ffcc7b8a45ec8aee8ee6
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 9 14:38:43 2012 +0800
+
+ Define _GLOBAL_OFFSET_TABLE_ simultaneously when .got created
+ in ARMLDBackend::doPreLayxout
+
+commit 13912532aac8d7ec25fa1b5d791eb7683c512595
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 9 14:20:10 2012 +0800
+
+ Use virtual address as S and P value for applying relocation
+
+ 1. Modify Relocation::place - use LDSection.addr() as base address
+ 2. Modify Relocation::symValue -
+ Symbol's value is set to virtual address before applying
+ relcoation, so we can take this value directly as S value to
+ apply relocation.
+
+commit 3111407b46b766028e3d0665ece0b8ea0b9dedcf
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 14:02:56 2012 +0800
+
+ Correct the alignment to byte alignment
+
+commit b80e0a538cc8a0e4402dd4ccb372a0c9f61f0678
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 9 13:55:57 2012 +0800
+
+ Change the bug reportee from Luba to mclinker@googlegroups.com.
+
+commit 2ced0a42910e2ea516d6249a211fe41f922b997e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 13:30:03 2012 +0800
+
+ Refine the function to get section order
+
+ .dynamic is changed to NamePool
+
+commit 4baefc969db0d7f0c8dd0411359ab0a5fe0673d4
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Mon Jan 9 09:55:35 2012 +0800
+
+ Remove '#include <iostream>' and 'using namespace std'.
+
+commit 9842d170066e6ec6482b3e3e0c99ffaa570d3c9e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 9 09:46:16 2012 +0800
+
+ Correct the segment flag for .dynamic
+
+commit 40924a00ae4f3b984659f4917cfec5f7c86503fe
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 23:03:09 2012 +0800
+
+ The symbol's value should be virtual address. If the symbol is
+ reserved by target backend, call back target backend to finalize
+ the symbol's value.
+
+commit 757b7f29e436b394d746c266727dc43ce399b85d
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 22:26:47 2012 +0800
+
+ Open the getSymbolShndx() - now the symbol's shndx should be right.
+
+commit 52a7cbeea0a7ce37e614d812eca8387905b7e45b
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 22:24:37 2012 +0800
+
+ Fix a bug - because we merge section when reading them, we don't
+ need input's STT_SECTION symbols for relocation. Skip section symbols
+ when reading them.
+
+commit 93094ab3afa4851ce71abb7302fdc4d5a05426e8
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 22:23:24 2012 +0800
+
+ Remove obsolete comments.
+
+commit c766a6b40c849da0d1dc2ff3e0d40f27db13b3cb
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 18:35:16 2012 +0800
+
+ Add a new function - LDSymbol::hasFragRef().
+
+ This function return true if the symbol's fragment is set.
+
+commit 60a6a7679134bbb70db1d2cf40bcdca213cf3b1e
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 18:19:22 2012 +0800
+
+ Fix a bug - Local and absolute symbols' binding should still local.
+
+commit e85a4f3117722767e5048b9ec3b9b1c4e438a5a2
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 17:58:56 2012 +0800
+
+ Refactoring ELFDynamic and GNULDBackend
+
+ 1. Move .dynamic section's initialization from GNULDBackend::prelayout to sizeNamePools
+ 2. Move MCLDDriver::measureNamePool() into MCLDDriver::preLayout()
+
+commit 59fe697fade87471541b1cafe5ef53afdfdbc096
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 17:57:37 2012 +0800
+
+ Refine ELFDynamic Section
+
+ move applyOne and reserveOne to .cpp, and add some parameters for debugging.
+
+commit 47fcaef2d6bd77f21042ba36a6d5fa9dbfbd2733
+Author: luba <lubatang@gmail.com>
+Date: Sun Jan 8 16:31:25 2012 +0800
+
+ Refine rules - if a symbol is reserved or external, add it into dynamic symbol table.
+
+commit f46efc738d24306d50dca76ce7723365e31f4fee
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Sun Jan 8 12:17:43 2012 +0800
+
+ Clean debugging insertion
+
+commit a2e6d1ef62a5ec9dbebdf13e1ea8f99e22986942
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Sun Jan 8 12:14:13 2012 +0800
+
+ Modify Reocation::symValue
+
+ For symbol with no FragmentRef, return its symbol value directly.
+
+commit eb4971267340e343a302970458bd1041fd853eab
+Author: luba <lubatang@gmail.com>
+Date: Sat Jan 7 23:06:29 2012 +0800
+
+ Fix a bug - Any symbol with hidden or internal visibility should be treated as a local symbol
+
+commit 924a15117daeefd4b61ec208299272783e0cb90c
+Author: luba <lubatang@gmail.com>
+Date: Sat Jan 7 22:55:44 2012 +0800
+
+ Fix a bug - A protected symbol coming from a shared object must be treated
+ as a normal symbol
+
+commit ea958dd27e39060da2bb1de1cb4e57996140385f
+Author: luba <lubatang@gmail.com>
+Date: Sat Jan 7 22:43:23 2012 +0800
+
+ Fix a bug - ignore symbols from the shared objects:
+ 1. local binding STB_LOCAL
+ 2. STV_INTERNAL
+ 3. STV_HIDDEN
+
+commit e1e6b960018afbe7e311acffe949f5e2c04fecc2
+Author: luba <lubatang@gmail.com>
+Date: Sat Jan 7 22:21:38 2012 +0800
+
+ Fix a bug - a symbol defined in a section which iwe are not including must be
+ treated as an undefined symbol.
+
+commit 5463c4953fbcb13ecab5c305d60cc9593c7b7cd8
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 23:34:33 2012 +0800
+
+ Apply new ELF .dynamic section on all backends.
+
+commit 258d871b28a35422a28d0a2ab3aced610cfce9c6
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 23:34:11 2012 +0800
+
+ Implement common .dynamic section for all ELF backends.
+
+commit 32c86db8a4edbac688eb834f9329a1ee60d8139e
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 23:33:41 2012 +0800
+
+ Let .dynamic section become a kind of NamePool
+
+commit 91c7317bd0e5f650357e1b41e48c423af7d2ab07
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 23:32:41 2012 +0800
+
+ Implement many hasXXX section checking functions.
+
+commit 8c9e44d5bed5229b9c6ec8c35ae6b995880a56c0
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 6 23:20:54 2012 +0800
+
+ Emit program headers in ARMGNULDBackend::postLayout()
+
+commit 4990a37724326287b637a1421c184e26d807e322
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 6 23:20:24 2012 +0800
+
+ Implement GNULDBackend::emitProgramHdrs()
+
+commit 2ccc45ab9b0a65d8110a17b87021c7ded49221d5
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 6 23:18:14 2012 +0800
+
+ Add pagesize() to define page size of the target machine
+
+commit 7ebcaecff7ed237e7a677083fd14e1c242660adf
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Jan 6 22:45:25 2012 +0800
+
+ Add ELFSegment class.
+
+commit 354fb454a82328e702143402a6e75d35af4d5c7a
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 6 20:02:52 2012 +0800
+
+ Modify symValue() and place() in Relocation
+
+ Use file offset of the symbol and the place being relocated
+ as S and P value for applying relocation.
+
+commit e6595f2dbad20beadd335d9734016fdb5f31e27b
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 6 19:28:35 2012 +0800
+
+ Modify createARMGOT/ARMPLTandRelPLT/ARMRelDyn in ARMLDBackend
+
+ In ARMLDBackend, directly get LDSection from LDFileFormat instead
+ of getting from MCLinker
+
+commit b0f74c4d889d438922a03367e753890ce873a4c3
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 6 15:50:06 2012 +0800
+
+ Do check before generating dynamic section entries.
+
+commit 629b78c40069fedf0c2270170aca853ef35d1e60
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 15:05:01 2012 +0800
+
+ Implement finalize symbol value.
+
+commit 8ce6932dad00ed0a4ab9df56fc321a7d6dfd1474
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 6 14:11:19 2012 +0800
+
+ Fix a bug - fix typo of Rela to Rel
+
+commit cdc28be2dfd86e4c5901d34a4061cfdc91091251
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 13:47:10 2012 +0800
+
+ Fix a typo. MCLinker::finalizeSymbols() should have no parameters.
+
+commit a13bb7e0e666219d668aebddb67aaa721db9a61b
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 13:44:47 2012 +0800
+
+ Refine format.
+
+commit 7fdbf6aa4762ce24cee534ac9bb0753e61fab254
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 13:44:22 2012 +0800
+
+ Enable MCLDDriver::finalizeSymbolValue
+
+commit 903de0b94bdddf262a662c377f7fa0ed246aa237
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 13:36:03 2012 +0800
+
+ Enable TargetLDBackend's preLayout() and postLayout()
+
+commit dc4ceddb70bb11381910cfe4a8f780ae58b6f02b
+Author: luba <lubatang@gmail.com>
+Date: Fri Jan 6 13:19:57 2012 +0800
+
+ Fix a bug - symbol resolution should not override the ResolveInfo's pointer to output's LDSymbol
+
+commit e9124e2f59c421515f43875d089203ee455a9d1a
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 6 12:23:37 2012 +0800
+
+ Enable ARMLDBackend APIs to call the implementation of .dynamic section.
+
+commit 9623085a64401cfecc93fa51796e830fcdb518c9
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Jan 6 11:40:58 2012 +0800
+
+ Fix bugs - Add missing ++it in while loop
+
+commit a197b269f33054978400a996b6565b556ec91a9f
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jan 6 11:02:30 2012 +0800
+
+ Move the implementation of .dynamic section to ARMLDBackend.
+
+commit 00434aeac60ef334e4c2ea84216eae646bb6f673
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 21:14:22 2012 +0800
+
+ Fix a bug where re-pushing MCFragments into MCSectionData.
+
+commit 17a10d49c18bed780d5a6248f4aa2b895b62bbf6
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 21:09:04 2012 +0800
+
+ Fix a bug - MCFragment pushes itself into MCSectionData at constructor.
+ Therefore, any one should not push MCFragment into MCSectionData again.
+
+commit 3993c7dfa8b58d79177af00a5bf60345bb989b4f
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 20:36:28 2012 +0800
+
+ Fix a bug - reader should set up output's LDSection size
+
+commit 8c5946523705c90bbc892b99d7f1ce6659a8e878
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 20:16:42 2012 +0800
+
+ Enable target backend's initTargetSymbol().
+
+commit 207711864c208b4ed977828a35a6d8b16d411126
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 20:14:43 2012 +0800
+
+ Implement GNULDBackend::emitDynNamePool
+
+commit 5e9b12711f9330cc8569b9850038b44eded9ba6e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 5 19:38:33 2012 +0800
+
+ Add APIs - TargetLDBackend::preLayout and postLayout
+
+ create .got section in ARMLDBackend::preLayout while
+ building shared object.
+
+ TODO:
+ 1. create .dynamic section
+ 2. create _GLOBAL_OFFSET_TABLE_ symbol when creating
+ .got section
+
+commit 7e5b753e38ddb50f70ec638a2362156fc7577632
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Jan 5 18:54:32 2012 +0800
+
+ [ARM] Correct the Section flags for .ARM.attributes
+
+commit b21adcf07e8241228c30339cc97a8fb4d09b931e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Jan 5 18:50:35 2012 +0800
+
+ Remove the code to set section size and refine some code in Layout
+
+commit c17a7cb792d53775e84aabe007644d04c0d9a1ad
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 18:02:30 2012 +0800
+
+ Calculate the size of .plt section for LDSection in ARMPLT.
+
+commit 40c92724cb55cdb6bafa311c1e71840e8f7b423b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 17:43:36 2012 +0800
+
+ Calculate the size of .got section for LDSection in ARMGOT.
+
+commit c5ca8210193a6f56529f276fb7926ad35ca79d4a
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 17:15:27 2012 +0800
+
+ Add empty emitting functions for DT_SONAME and DT_NEEDED.
+
+ it has no need to deal with DT_SONAME and DT_NEEDED in emitDynamic(),
+ Using empty emitting functions here are for skipping assert check.
+
+commit d5bf56a171160bb91876e68633127213c364af0b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 17:06:51 2012 +0800
+
+ Change the type of .dynamic section to LDFileFormat::Target.
+
+commit 57fe477031c194b2c0475064821fb6d040f8b8ed
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 17:00:00 2012 +0800
+
+ remove obsolete code.
+
+commit b00a118399e1a2c6756af082c22ed8aa896cabde
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 16:57:44 2012 +0800
+
+ Remove obsolete code.
+
+commit a5ec28fff10512dc3c6f4c2342d404176ef8378e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 16:16:44 2012 +0800
+
+ Fix wrong assert statement.
+
+commit f59f4adda2206a57c15004da974e430d5790a802
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 5 14:02:21 2012 +0800
+
+ Add API - TargetLDBackend::initRelocFactory
+
+ 1. initRelocFactory - create and initialize RelocationFactory
+ 2. Modify getRelocFactory() to only get RelocationFactory but not
+ get or create RelocationFactory
+
+commit 114b828359228ffd7d55ee76835833f1c25cda81
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 12:18:32 2012 +0800
+
+ Fix a bug - Dynamic symbols which do not in the relocatable objects, should not be pushed into dynammic symbol table.
+
+commit a1f691c2db4cde4e31ab9cbb4c1bc164d03b03a0
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 11:49:01 2012 +0800
+
+ Update unittests for the changes of MemoryArea.
+
+commit b24215aae5f56abfa57d80900f46e2d24418ab20
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 11:34:13 2012 +0800
+
+ Fix a bug - ELFObjectReader::readRelocations should check if the
+ LDSection::kind() is LDFileFormat::Relocation.
+
+commit 9e013dce25d8f6ca908bd92ba1474461324b7640
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jan 5 11:23:08 2012 +0800
+
+ Remove Layout from emitDynamic() function prototype.
+
+commit cbc854ffa91959d5e44021a266059b3f68ac4709
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 5 09:59:08 2012 +0800
+
+ Remove debugging insertion
+
+commit a2c2fc755b5499ae1dcea1c9b5adccad1f36317c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Jan 5 09:54:51 2012 +0800
+
+ Fix bugs - create symbol _GLOBAL_OFFSET_TABLE_
+
+ 1. Ask layout to create FragmentRef for this symbol.
+ 2. The size of _GLOBAL_OFFSET_TABLE_ is 0.
+
+commit c04430036f58b5c199377203bb6380348b17e4d6
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 04:19:22 2012 +0800
+
+ Fix a bug - when layout, the fragment list of MCSectionData should not be empty.
+
+commit ed1a19489f3dc1986eb57d6f9159fbae35601e1c
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 04:11:27 2012 +0800
+
+ Fix a bug - In current verion, MCLinker merges sections when reading
+ them. So, the offset of the read fragment should be set.
+
+commit 4a0c98a5e2b572ca57b27599ccc85ab254661641
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 04:09:48 2012 +0800
+
+ Refine the error message.
+
+commit f0a5228dcec061ef8855cdc4acab276c1d0b811c
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 03:22:53 2012 +0800
+
+ Fix a bug - Layout::isEmptyRange() causes segmentation fault when
+ the range is the first element in the range list.
+
+commit 1e5a9a2fb1453045c5e1621c58d973f0b3afdd1b
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 03:03:18 2012 +0800
+
+ Fix a bug - Even dynamic symbols ask Layout to get their FragmentRef.
+ Since dynamic shared objects have no MCSectionData, Layout should
+ return NULL when the symbols's st_shndx points to no MCSectionData,
+ should not report fatal error.
+
+commit c682c31a5fae0760e07cfe291a336e86df8026a4
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 02:49:44 2012 +0800
+
+ refactor the relationship between MCLinker and Relocation
+
+ relocation's fragment reference should be set by format-dependent readers,
+ not MCLinker. Transfer the responsibility from MCLinker to ELFReader
+
+commit 99f069f0b8f37a936bdaedcfc818bec4272aef70
+Author: luba <lubatang@gmail.com>
+Date: Thu Jan 5 01:55:01 2012 +0800
+
+ Set up sh_info and sh_link in input's LDSections.
+
+commit ef9e73ed4cfe3e2701ccc978282dfe2bb35cd3ae
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 4 23:15:03 2012 +0800
+
+ Fix bugs - There are some relocation entries point to the
+ undefined symbol, and undefined symbol has no fragment reference.
+ These undefined fragment references cause segmentation fault when
+ applying relocations.
+
+ The bug source is: in ELF, the relocations' fragment references
+ come from relocation section's sh_info, not from the dynamic
+ symbols' st_shndx. So, ELFReader is responsible for set the
+ LDSection::setInfoLink() when reading relocation sections.
+
+ The same problem is easy in MachO, because MachO's relocation table
+ is within the section. There is no extra effort to get the relocations'
+ fragment references.
+
+commit 9ee8d31b4f39f4dda6d6472b18e50ffb64d52d6b
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Wed Jan 4 19:59:47 2012 +0800
+
+ This patch suppressed the number of warnings when builds the MCLinker under Android compilation flags.
+
+ It includes:
+ 1. Trim spaces.
+ 2. Initialization order.
+ 3. Comparison between signed and unsigned number
+ 4. Uninitialized loop iterator in include/mcld/LD/ELFReader.tcc
+ 5. Move mcld::fs::exists(FileStatus f) and
+ mcld::fs::is_directory(FileStatus f) from Path.cpp to FileSystem.h
+
+commit 079c579fe2f79451c763a4b022a7ff1e193d2664
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jan 4 20:30:26 2012 +0800
+
+ Add the Implementation of emitting .dynamic section.
+
+commit 9ce9285a4a997b33c3ea53e19ed0e43b4cd694b5
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Jan 4 18:02:50 2012 +0800
+
+ Modify ARMLDBackend::isSymbolNeedsDynRel
+
+ Add parameter isAbsReloc to check if symbol needs dynamic
+ relocation when building shared object.
+
+commit a3dbe9ca13b0461731155d9fe97cd61dd6eab3c3
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Jan 4 17:58:14 2012 +0800
+
+ Fix a bug - we can't emit dynamic relocation with type
+ R_ARM_MOVW_PREL_NC and R_ARM_MOVW_ABS_NC
+
+commit b28327cf3385aaeb15556471547f2fe391f2678f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Jan 4 16:34:07 2012 +0800
+
+ Fix comment and refine error message
+
+commit 54f5511857354e612782cfe8df3f44a96062b2d0
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Jan 4 01:31:55 2012 +0400
+
+ Add one reserved entry on Mips GOT initialization.
+
+commit 7a2ee69ef80f5d9a473bedd4daa1998f93cc6f1a
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Jan 4 01:08:13 2012 +0400
+
+ Add a bit more MIPS flags to the ElfXX_Ehdr::e_flags.
+
+commit e347611835616bd346e5609226c054033db80f86
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Jan 4 01:03:33 2012 +0400
+
+ Add namespace qualification to the R_MIPS_HI16 constant name.
+
+commit 3011400c7be9ac02e75c4cf6070b2d1a6a120786
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Jan 3 15:53:53 2012 +0400
+
+ Implement MipsGOT::reserveEntry() and MipsGOT::gotEntry() routines.
+
+commit f4b82d455e287d7797c3deebf9e07ce59423a1e8
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Jan 2 15:21:44 2012 +0400
+
+ Extend the list of Mips relocations processed by the MipsGNULDBackend::scanRelocation() routine.
+
+commit ad6e2eda57c9fe9db930dce4daac725b88161219
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Jan 2 14:24:18 2012 +0400
+
+ Move _GLOBAL_OFFSET_TABLE_ processing to the MipsGNULDBackend::initTargetSymbols() method.
+
+commit 6ceb028677045e69d4c2aa6df50314451dd26163
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Jan 2 14:21:49 2012 +0400
+
+ Add begin()/end() methods to MipsGOT class.
+
+commit a11f8bcd3be88f45629d9ce4b83849de7f086446
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Jan 2 14:02:34 2012 +0400
+
+ Refine MipsGOT code.
+
+commit 93d6e506d075066b83ca2bb8f4030ff5f611f414
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Jan 2 13:23:42 2012 +0400
+
+ Refine MipsGNULDBackend code.
+
+commit 53a8d13f75241e7e94a2b8810a9c762dadafa272
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sat Dec 31 00:34:41 2011 +0400
+
+ Refine MipsRelocationFactory code.
+
+commit 8d9ae90a8bc8f515aa5c14b21f5e5f986c169518
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sat Dec 31 00:14:29 2011 +0400
+
+ Add new entries to the DECL_MIPS_APPLY_RELOC_FUNC_PTRS macro.
+
+commit 15f2df15f4c378509423ccc5f208ba4f45a475d2
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 4 00:30:46 2012 +0800
+
+ Remove rslinker, and use our own readers.
+
+ Sorry for the big patch, but I think this is the last big patch.
+
+commit d42ee92511c1f85308d568d5538d98cec852ef65
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 4 00:29:49 2012 +0800
+
+ Fix a bug - should determine if the fragment is NULL before using it.
+
+commit 8b5c813f53b9dccbf3d86ec80a59013338e0fc49
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 4 00:28:34 2012 +0800
+
+ Fix a bug - the default semantic of Memory::request() should be read-only.
+
+commit a6ca15f9831efb58aac4804d795db27558b8446e
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 4 00:27:13 2012 +0800
+
+ Fix a bug - Layout should return a MCFragmentRef<NULL, 0> when it can not find any fragment.
+
+commit 1b7dffa62857466b6f54d1a6f8b083c49ce9c1fe
+Author: luba <lubatang@gmail.com>
+Date: Wed Jan 4 00:26:30 2012 +0800
+
+ Fix a bug - Add missing llvm::ELF namespace
+
+commit 8a1293d064e9b6c0bc4a92f0e758fca730f5e164
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 3 20:45:44 2012 +0800
+
+ Fix a bug. Refine loop boundary condition in Layout::orderRange()
+
+commit 3c3b5ca1ad50204a20c74a6890c717cdc9346111
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 3 19:58:54 2012 +0800
+
+ Fix typo in ELFDynObjReader::isMyFormat()
+
+commit dc441ccc8ec5acba47820a3edb0c5d38a6338af4
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 3 17:55:07 2012 +0800
+
+ Remove the code to set LDSection address.
+
+ We should base on "Segment" to set section address, and this part will be done
+ in post layout.
+
+commit 8564c3f2e0726d608ef4242f8ee484c0d424d7c4
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Tue Jan 3 19:47:54 2012 +0800
+
+ Use MemoryArea::page_boundary() to find the page-boundary that larger than file-offset.
+
+commit 11661c9b489b7a21c2b0ae3c2ba5517a0bd58109
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 3 19:09:29 2012 +0800
+
+ Fix a bug - ARMDynRelSection::getEntry
+
+commit c721fa8050ab969a7be7f4cd529fd65fb560c01b
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 3 15:26:59 2012 +0800
+
+ Refine comment.
+
+commit 988a531b6b32125128132207f85fbdcc4cb87004
+Author: Zonr Chang <zonr.net@gmail.com>
+Date: Tue Jan 3 16:05:14 2012 +0800
+
+ Fix build when --with-unittest was not given.
+
+commit a4c9f6555118c2cc51f6f51b6bfcf5b41616d3bd
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 3 14:57:47 2012 +0800
+
+ Add mapping rules for .ctors.* and .dtors.* in SectionMap
+
+commit 5f485803471db9be08229da3d6cc1ef105fafd63
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Jan 3 13:49:18 2012 +0800
+
+ Add .init and .fini in ELFFileFormat
+
+commit 39f4cc4245c6fe2b502c49a119f2be507bc3cb45
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 3 11:59:04 2012 +0800
+
+ Refine format
+
+commit b92287ed88cdad5c43946a70cc750b0a3a3b8e3c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Jan 3 08:52:03 2012 +0800
+
+ Fix build failed
+
+commit 47207c00b9f2c41548e836c2006b8974c49a7dfd
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 2 22:08:43 2012 +0800
+
+ Refine format.
+
+commit b869a4e0b42d2d1cbfa70939262c106a064515ee
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 2 22:07:43 2012 +0800
+
+ Refactoring - move TargetLDBackend::machine() to GNULDBackend
+
+commit 5e84179fb316af641a675e718c2b809db89f81cb
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 2 22:05:59 2012 +0800
+
+ Implement byte swaps.
+
+commit 55a981e5a252604981efa07b1c6bda6d2e9ee9be
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 2 20:05:12 2012 +0800
+
+ Add ARMGNULDBackend::getTargetSectionOrder()
+
+commit 470e0593cb2def7e7967d0fe50c7b9b5445485da
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 2 19:59:34 2012 +0800
+
+ Implement GNULDBackend::getSectionOrder()
+
+commit 80aaa308441ff3f89061dca90f48b316161a1ff5
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 2 19:58:34 2012 +0800
+
+ Define the basic section orders for ELF format
+
+commit 34b348d1909089dcb2dd8f134d67c82f5bebdf78
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Jan 2 17:19:30 2012 +0800
+
+ Modify ARM relocation functions
+
+commit 80d202a5358c2ee2636eddf6500de71d5033ed95
+Author: TDYa127 <a127a127@gmail.com>
+Date: Mon Jan 2 15:58:56 2012 +0800
+
+ Enable testing make.(When "make check")
+
+commit 630cc7219c262687e41d32ac6777fd286eb53b75
+Author: TDYa127 <a127a127@gmail.com>
+Date: Mon Jan 2 15:57:25 2012 +0800
+
+ Fix testing config bug.
+
+commit 54b997780caa11cb2b43a018b46a42951b76d784
+Author: TDYa127 <a127a127@gmail.com>
+Date: Mon Jan 2 15:56:48 2012 +0800
+
+ Remove testing temporary files.
+
+commit b7f0f9721ccf21ad13e29c64525000633f635307
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 2 15:55:22 2012 +0800
+
+ Refactoring - collect all MemoryArea::request in ELFObjectReader and ELFDynObjReader.
+
+commit ae0c1babf8bf969f8058178ce24929da976412d2
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 2 15:37:14 2012 +0800
+
+ Refactor ELFReader: eliminate the number of using MemoryArea::request.
+
+commit 5c9b26645d64822d729b867d9a41c6035e930a77
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Jan 2 14:56:06 2012 +0800
+
+ Uncomment emitSectionData() and do little modification.
+
+commit 46b1162de3d85ddd4270e0c809b0fbf951beceef
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 2 14:17:22 2012 +0800
+
+ Refine comments.
+
+commit f7637d41b45dbb63264493b00047a7884f9e78cc
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Jan 2 12:14:11 2012 +0800
+
+ Complete the member function emitRelocation().
+
+commit 80eff6b9386ab4a403f81d23948b5897ba75abe8
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 2 12:07:13 2012 +0800
+
+ enable backend's scanRelocations().
+
+commit 9b2a4151960babbbe0469c480122a61cd6f56e69
+Author: luba <lubatang@gmail.com>
+Date: Mon Jan 2 11:31:39 2012 +0800
+
+ open MCLinker::prelayout() and postlayout() for Backend
+
+commit 559c32fd7c500e5e37821f09f96e24858c35203e
+Author: Duo <pinronglu@gmail.com>
+Date: Mon Jan 2 11:22:41 2012 +0800
+
+ Move m_fileOffset from MCLDFile to MCLDInput.
+
+commit 972d3974e99d12105bf23e69fddcd780d4e4528d
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Jan 2 11:13:58 2012 +0800
+
+ Refine comments.
+
+commit ac57f5127d1c83087b53239882993ab31e886284
+Author: Duo <pinronglu@gmail.com>
+Date: Mon Jan 2 02:04:22 2012 +0800
+
+ Add a varable "fileOffset" for class MCLDFile.
+
+ For a member object file of an archive, we need the start address
+ in the archive. Add an variable for class MCLDFile and set the value
+ in GNUArchiveReader using the member function of MCLDFile ,setFileOffset.
+
+commit 7133194501e161b8dc81da0aa67b1c187f5bf8c1
+Author: Duo <pinronglu@gmail.com>
+Date: Sun Jan 1 09:41:44 2012 +0800
+
+ Complete isolated GNUArchiveReader without thin archive.
+
+ MCLinker can't still work with GNUArchiveReader.
+ We need some unittest to confirm the correctness of MCArchiveReader.
+
+commit 0c722d32b54ef5c2c7e44733f94ce6d4f744e8a2
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 30 17:57:36 2011 +0800
+
+ Add LDContext::getSymbolIdx() for writing out relocation table.
+
+commit 3ea85fd32cc03757cf0e9f9df52ff181d1e31ac5
+Merge: a2c2655 6b5b4fd
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 30 17:47:55 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 6b5b4fde7be7c121b7f59551f30aed104c973c1f
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 17:46:16 2011 +0800
+
+ Fix a bug - produced relocations need to set up input's ResolveInfo.
+
+commit 19e1aa9e96eb921563a7d46044518c847799f515
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Dec 30 17:45:28 2011 +0800
+
+ Implement Layout::getFragmentRef from the big offset
+
+commit a2c265577bc39af4d4fa8857dd0d9f2d1047cf7d
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 30 17:45:59 2011 +0800
+
+ Modify ARM relocation applying functions
+
+ R_ARM_MOVW_PREL_NC and R_ARM_MOVW_ABS_NC
+
+commit e47dbf5641357d4507bb4786e89f9d5a52323e2a
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 30 17:45:11 2011 +0800
+
+ Add assertion if ResolveInfo of relocation not set while scanRelocation
+
+commit 2d38016e4cd23bd518c5dc6dc4e331d50c82ee06
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 30 17:39:58 2011 +0800
+
+ Fix wrong virtual address calculation.
+
+commit 208b75256dc7a75b1829f99d9801147bddc09114
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 30 17:28:10 2011 +0800
+
+ Implement ELFWriter::emitRelocation().
+
+ It is unfinished.
+
+commit 1a0da05a617f89191149b66a826a9a570c67bc01
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 17:23:01 2011 +0800
+
+ Enable `MCLDDriver::relocation()'
+
+ Implement MCLinker::applyRelocations() and related functions.
+
+commit f442311b9f19067fc57d842cecc72a7d406446a2
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Dec 30 17:08:19 2011 +0800
+
+ Modify the return type of Layout::getFragmentRef from the big offset
+
+commit 35bcb06c79acdfb4fae7ccfaed0bb807fa33921e
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 16:57:02 2011 +0800
+
+ Implement MCLinker::addRelocation.
+
+commit 142fd33c403f38e15899c062ecb0427c86a7a1d9
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 16:55:36 2011 +0800
+
+ Open Layout::getFragmentRef from the big offset.
+
+commit 09e22e7c3d506a4f18861570f702551d19322104
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 30 16:43:00 2011 +0800
+
+ Modify ARMRelocationFactory
+
+ 1. Implement relocation function prel31,
+
+ 2. Refine some judgements if got entry is needed
+
+commit 2a13eda6730cb64eccbdc2a67ec80a6a70e1b409
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 15:49:17 2011 +0800
+
+ Implement format reader's readRelocation().
+
+commit 9fd370ba93f84bfc4435dcc249c4c4326b952cdc
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 15:48:04 2011 +0800
+
+ add LDContext::getSymbol()
+
+ Because we may change the definition of LDContext::SymbolTable, LDContext
+ better provides this API.
+
+commit 6b545fe85b908aa333ec5078592d9da6799b57b4
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Dec 30 15:19:11 2011 +0800
+
+ Refine format
+
+commit 0fc01b92e9c82eda9f0d01f983c1cb47283bf605
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 15:11:52 2011 +0800
+
+ Fix a bug - if the section name contains any "debug" sub-string,
+ the section should be a LDFileFormat::Debug section.
+
+commit 9b4233273a69f35e32ecb20c5ff592f23e98293a
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 15:02:49 2011 +0800
+
+ Enable `reading relocation entries'.
+
+commit 98cb9c290428a715bd13bdd38ce2aff65991aef2
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 15:01:19 2011 +0800
+
+ Refine format.
+
+commit dfbabd99b3db7afd45871b6c42bfc3c392dabbc7
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 15:00:15 2011 +0800
+
+ Make a note - we should make a map from section name to section
+ index to speed up the querying.
+
+commit 031a2951ba8879f797be707c3ac98ecdf82ba6a6
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 13:50:26 2011 +0800
+
+ refine comments.
+
+commit ee080734e874ce1898c8545f84a718eb8aad2eda
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 30 14:17:31 2011 +0800
+
+ Modify ARMLDBackend::scanRelocation
+
+ check if relocation target symbol is _GLOBAL_OFFSET_TABLE_
+
+commit 0fcbde36689d60916c76979269c813354b546273
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Dec 30 13:54:00 2011 +0800
+
+ Implement get Input/Output LDSection in Layout
+
+commit e5e02f694f04c4c935945b0d9ea5ac80570bd20b
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 13:45:02 2011 +0800
+
+ Refactoring the architecture - transfer TargetLDBackends from pure-abstract reader interface to format-dependent reader interface.
+
+commit 3c4bc285ac00a9da71b2bbb196f4bbaccc994246
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 30 13:41:34 2011 +0800
+
+ Implement ARM relocation functions: abs32, rel32, gotoff32
+
+commit 45f9be9be83195f01489b96f3ce756cafdfd2ecf
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 30 13:39:16 2011 +0800
+
+ Fix bug - ARMRelocationFactory::ScanRelocation
+
+ A place may still needs a dynamic relocation to relocate itself
+ although it jumps to plt.
+
+commit b193909cd559cc3525400b83c0a0b13c578f0573
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 05:47:00 2011 +0800
+
+ Fix a bug - now can see the symbol name.
+
+commit 81dc1faee5c769f4d6f2511da32f5886ca2e89f8
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 05:01:55 2011 +0800
+
+ Implement emitRegSymTab()
+
+ Some bugs are still remaining.
+
+commit 239c2dca20ab3ecdcf1f3199fee82c8bc237f415
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 05:01:01 2011 +0800
+
+ Fix a bug - when read unsupported symbol, should ignore them.
+
+commit b1ce25b502c8f6fa8cfeff1eb05a3d1e2d2c6a0b
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 04:58:01 2011 +0800
+
+ Fix a bug - when read unsupported symbols, should ignore them.
+
+commit 3bffaf99bea88fe3b737879e5c1723baaa116558
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 04:53:03 2011 +0800
+
+ Add the default NULL symbol when MCLinker is initialized.
+
+commit da75f8ddc0e233134c9368ff8d61a9f1b594340f
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 04:51:30 2011 +0800
+
+ refine typo of comment.
+
+commit 885c6853421646bc2e1144e3b5affc7c7d3f4244
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 04:49:53 2011 +0800
+
+ Add Layout::getOutputLDSection()
+
+ The behavior of this function is similar to getInputLDSection().
+
+commit fb9a3422a6bc8c67e6734cbd2d023c36afcb433e
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 30 04:48:33 2011 +0800
+
+ Add LDSection::setIndex() and index() to remember the input and output
+ section index.
+
+commit 29af7ca5679947e78664aa7427ce15a44901004e
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Fri Dec 30 02:06:39 2011 +0800
+
+ Add missing `static' qualifier.
+
+commit 74104917ecb1dd19f75156203cec87075a761a29
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 23:57:44 2011 +0800
+
+ Implement emitSectionData.
+
+commit 25e2167c9071e3e8a37b789bb6b264ccb6c8b44e
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 23:56:56 2011 +0800
+
+ Fix a bug - the return type of MemoryRegion::getBuffer() should be wrapped by traits.
+
+commit a5a20ca578dad98d4fd00f9ba52da39f01224c2b
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 23:02:18 2011 +0800
+
+ Fix bugs - the start address and size of shstrtab are wrong.
+
+commit 6682993c962600895765db65bf3cf8942b1b77b5
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 22:59:34 2011 +0800
+
+ add template partial specific Align() functions.
+
+commit 04d2cbf6e78844451c581f9017038ff8b54d8c64
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 29 21:13:09 2011 +0800
+
+ Fix a bug. Correct the type of a variable.
+
+ The variable is used to check if out-of-bound and should be signed in this case
+
+commit 5d9d515c96b654b6b975123bae9236f39f4cc4ba
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Thu Dec 29 20:23:35 2011 +0800
+
+ We need to check if PLT of the symbol is exist to determine how to apply while applying relocations.
+
+commit 3da54699c0df014ff7262a6b5f19602386e44fe6
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 29 20:12:00 2011 +0800
+
+ Define target dependent symbol _GLOBAL_OFFSET_TABLE_
+
+commit 6b4dd3d8ba6191f3dbf5cfab8f961217f6fbbe74
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 20:04:58 2011 +0800
+
+ Pass MCSectionData to the constructors of GOT entries and PLT entries.
+
+commit 33d9fafcda5d80777c2a7f9e059d75f5f373904c
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 29 19:04:30 2011 +0800
+
+ Add function Layout::getInputLDSection()
+
+ This may be useful in some scenarios.
+
+commit 9893c832962113d2c16299bfaa86c98b7d1196e9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 19:07:25 2011 +0800
+
+ Rename m_GOTPLT to m_GOT. No functionality changes.
+
+commit 83abffda34e3e677838763b6cab6a6d60e4db667
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 29 18:57:53 2011 +0800
+
+ Refine the function used to align an address
+
+commit 6e9ab5d4b28ce9e3476ec2c2d129d16bc587a194
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 18:02:31 2011 +0800
+
+ Remove redundent ARMGOT::applyGOTPLT() function.
+
+commit 6681d77383bedc6e19f70d0b8d3d9cc9235dfe21
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 29 16:19:09 2011 +0800
+
+ Handle target-dependent fragment in computeFragmentSize()
+
+ As applying relocations, we need to know the fragment offset in GOT/PLT from
+ Layout. Thus we still need to handle target fragments.
+
+commit a7aa9cf925172716c9af35f2ae4db03cee33ef76
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 17:42:14 2011 +0800
+
+ Fix a bug - ResovleInfo.outSymbol() should point to output symbol.
+
+commit b6a45fcfeeb6422bb0faa36d5ff6bbdc33ae2bb4
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 17:36:33 2011 +0800
+
+ Fix some commented code in emitSectionData().
+
+commit c0e795131aa133de61d1b9b73c0b601274977fa4
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 17:19:57 2011 +0800
+
+ Add begin() and end() functions in class ARMGOT.
+
+commit ba4cde9ab4af6e306a5ef1325c2e903519e76574
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 29 17:08:04 2011 +0800
+
+ Sorry to mis-merge the wrong file, ARMRelocationFactory.cpp
+
+commit b3a9172c724cc20263ee8810cc48df4c436dc5e8
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 17:03:32 2011 +0800
+
+ Add the implementation of getGOTPLTEntry.
+
+commit 65e695efbc913f2e3e03c5fd9c354fbb25a8d798
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 29 16:55:31 2011 +0800
+
+ Remove offset() in GOTEntry and PLTEntry
+
+ Now we let Layout to fill up the offset of TargetFragment,
+ so we should ask Layout for the offset to make sure the
+ offset is valid.
+
+commit 8c6e3c68519a51dd66a5a02ce7993bcdb0a633e5
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 29 16:55:16 2011 +0800
+
+ Fix typo.
+
+commit 09d4a89406b5cbaed26c6aa760881cf5a7f9c476
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 16:28:33 2011 +0800
+
+ Implement MCLinker::defineSymbol()
+
+ Because targets and driver may define standard symbols, MCLinker should provide API to do this.
+
+commit 0656aef58bdb634150e17a2e4440af6c7c41c6ab
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 29 16:09:31 2011 +0800
+
+ Enable layout in MCLDDriver
+
+commit fd9e6f7cd04b7250a722f33fca9f9db839bd31eb
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 29 15:59:11 2011 +0800
+
+ Implement Layout::layout()
+
+commit 71fc72a4902204f5f8ba494434a97df772ca5696
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 29 14:37:31 2011 +0800
+
+ Add a helper function to align an address in SizeTraits.h
+
+commit efb966bd7a23c71787ef6e40d0cd902512a801e9
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Thu Dec 29 14:50:40 2011 +0800
+
+ Fix bugs for ARM relocation functions.
+
+ Several minor changes:
+ - Fix some typo
+ - Add overflow checking
+ - Add missing addend if relocation type is RELA
+ - Refine R_ARM_THM_CALL (but still not work)
+
+commit 7e9e873f3ca8d40af3d108b8f2e2a5628d7b41f8
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 14:21:54 2011 +0800
+
+ Add new class MCTargetFragment.
+
+ MCTargetFragment will be inherited by Target-dependent MCFragment.
+
+commit 03fb34aa0cd42a4e438c4b0963302704bb8bd5f8
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 29 13:20:31 2011 +0800
+
+ Remove the class ARMGOTEntries.
+
+ Now using the class GOTEntry to represent all kinds of GOT entries.
+ This is for simplifying the design of GOT.
+
+commit 2f901ad97abfc3473d7da889e6ab2ce55644d5ea
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Dec 29 13:13:06 2011 +0800
+
+ Implement helper_get_PLT_and_init().
+
+commit 339f672b65bbab8a8d39d2eaae44f20dc2a12b55
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 10:29:45 2011 +0800
+
+ Reorder the linking process - move MCLDDriver::readRelocations() before
+ MCLDDriver::add STD/Target Symbols().
+
+ Previously on MCLinker:
+ 1. readRelocations() calls TargetLDBackend::scanRelocations(), and the
+ TargetLDBackend computes the size of target-dependent tables during
+ readRelocations().
+
+ 2. MCLDDriver::addTargetSymbols() calls TargetLDBackend::initTargetSymbols(MCLinker& pLinker)
+
+ 3. TargetLDBackend::initTargetSymbols() calls MCLinker::addGlobalSymbol()
+
+ 4. If user give a non-NULL MCFragmenetRef in MCLinker::addGlobalSymbol(),
+ MCLinker will computes the value of the symbol automatically during
+ MCLDDriver::finalizeSymbolValue().
+
+ Conclusion:
+ It's better to create all fragments before creation of target symbols.
+
+ Because we can not know if the target-dependent tables are existent until
+ MCLDDriver::readRelocations(), so we should move the function before
+ MCLDDriver::add STD/Target Symbols().
+
+commit 8ec35b29b669eaf5c1a3f846fb7d27fbc91d4957
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 29 08:51:23 2011 +0800
+
+ Add API - ARMPLT::getGOTPLTEntry()
+
+ Get an GOT entry in .got.plt
+
+commit fb0b6b11e3eb746ab0fa25794ddb6ac1fab4e530
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 04:13:21 2011 +0800
+
+ Fix a bug - ELF hash entry size should be 4 bytes
+
+commit 45f0bb3b784c206c5bbb6bd5c28320c6579ddd94
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 04:02:16 2011 +0800
+
+ Implement MCLDDriver::measureNamePools.
+
+ Now, the sizes of .symtab, .strtab, .dynsym, .dynstr and .hash should
+ be correct.
+
+commit 92877f4b0e66d3730b0732fe3232986b1afa4c15
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 03:59:26 2011 +0800
+
+ Let the input file remember if she's needed.
+
+ Option --as-needed ask linker to make DT_NEEDED tag only when the
+ shared libraries are needed. We let the input file has a flag to
+ remember if itself is needed.
+
+commit 0a93330e9c1e8a2943d07cdd6faa5adbe331bbb8
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 03:57:44 2011 +0800
+
+ Move all access functions in ELFDynObjFileFormat to ELFFileFormat.
+
+commit 184d13e6d3a63ca70ad0a94d142408ffa29007f6
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Dec 28 11:53:08 2011 -0800
+
+ Issue error in X86RelocationFactory::applyRelocation
+
+ Issue error for now.
+
+commit aae6fac46a042df992db4e19ab5cc185b0922c8e
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Wed Dec 28 11:51:47 2011 -0800
+
+ Issue error in X86GNULDBackend::scanRelocation
+
+ Issue error for now.
+
+commit fac17ed1f3f935ba2e51904e4b40103e8b8b2a95
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 29 00:19:57 2011 +0800
+
+ Add access functions in all kinds of LDFileFormats
+
+commit 6ce4a39443493366eaf45c7cf024efce97278927
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 23:17:18 2011 +0800
+
+ replace \#include<stdint.h> by \#include<llvm/Support/DataTypes.h>
+
+commit 7b443200f6e90b976d55de9ef4fd63080a37eaa7
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 28 22:16:22 2011 +0800
+
+ Initialize standard section map in MCLDDriver directly
+
+commit fb7d9b0151880c358815ac85297c597f2b0fc490
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 21:30:53 2011 +0800
+
+ Refine R_ARM_THM_CALL relocation function.
+
+ Add some helper functions to handle bitwise operations.
+ - helper_thumb32_branch_upper
+ - helper_thumb32_branch_lower
+ - helper_check_signed_overflow
+
+commit 0ab8fd07fd0c6da2fb65fa44542470bbf8081144
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 21:27:35 2011 +0800
+
+ ARMTargetBackend should initialize section by MCLinker::getOrCreateOutputSectHdr() directly.
+
+commit 478ba9a43a99a3cb49d5d2cca6c7960631785200
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 21:16:34 2011 +0800
+
+ Change scanRelocation from trivial virtual function to pure virtual function.
+
+ Because all target backends need to override this function, so it should be
+ a pure virtual function.
+
+commit 2dc7ee8d8dec91347d4aec062947f54563205835
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 20:55:51 2011 +0800
+
+ change the API of TargetLDBackend::computeSectionOrder() and TargetLDBackend::computeTargetSectionOrder().
+
+ Because targets rarely change the default order, so we use trivial virtual function instead of pure virtual function.
+
+ And we also shorten the function name. Use get instead of compute
+ TargetLDBackend::getSectionOrder() and TargetLDBackend::getTargetSectionOrder().
+
+commit 25836ea267fc4c730cab810a6d90022c68d88559
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 20:49:46 2011 +0800
+
+ Refine the input parameter, size, for ARMDynRelSection
+
+commit a9322558e204e54913ca6ad5fdbf12b518668d2f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 20:46:26 2011 +0800
+
+ Set section info of .rel.plt to .plt
+
+commit dfc55f3a445c4d62c48ae9da3292609102626a28
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 20:37:07 2011 +0800
+
+ Give TargetLDBackend::emitSectionData() more parameters.
+
+commit 4c19f36cf2d9585c7333d8d02819bb6558d7d695
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 20:20:58 2011 +0800
+
+ change the name MCLDDriver::computeDynSymTab() to MCLDDriver::measureNamePools().
+
+ This function computes the size of the sections - .hash, .symtab, .strtab, and so on.
+
+commit ac61247f5a65e509f22199d16bc1fe157fb3c8a9
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 19:36:10 2011 +0800
+
+ Get PLT/GOT offset by calling offset()
+
+ For target dependent section, Target is responsible to
+ maintain the MCFragment (Entry) offset. Layout consider
+ only the section size and has no idea about fragment
+ offset.
+
+ So, when applying relocation, instead of asking Layout
+ for the offset of PLT/GOT entry, we extract from the
+ entry directly.
+
+commit ded73047105b31e8bc1d8b9973407b19a574958e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 18:03:14 2011 +0800
+
+ Revert ARMRelocationFunctions.h and ARMRelocationFactory.cpp
+
+commit b2ca6a16105575802642b3da6fc0afc5b0e156f2
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 17:56:50 2011 +0800
+
+ Implement ELFWriter::getSectInfo()
+
+ transfer the responsibility of "set sh_info" from writers to LDSection creators.
+
+commit a0be4a4883e2b03d817b87a48587708ffa7721ee
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 28 17:36:55 2011 +0800
+
+ Reorder if-else statements, no functionality changes. MCLinker should emit PLT SectionData before emitting GOT.
+
+commit bfd99640d46a281fed6e611c539715f295325887
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 17:36:59 2011 +0800
+
+ Implement ELFWriter::setSectLink()
+
+commit d274d7fb9c73a06c0b46f76902e07106af92184a
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 17:28:03 2011 +0800
+
+ Refine ARMRelocationFunctions.h.
+
+ From now on, we need only one modification in ARMRelocationFunctions.h
+ when implementating a new relocation function.
+
+commit 310eefcec21d54ac779dd0fcf873a6f2ae72545a
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 28 17:17:56 2011 +0800
+
+ Perform applyPLT0 and applyPLT1 in emitSectionData.
+
+commit 9c4aa89aa53c1d348229c761fe2ac533fb188a9e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 17:11:31 2011 +0800
+
+ Add member m_EntryBytes into ARM/MipsDynRelSection
+
+ 1. Add entry size as an parameter in constructor of
+ ARM/MipsDynRelSection
+ 2. While reserveEntry, update the section size in LDSection
+
+commit 11fbe3f506158cb8a71d73bd5b0d395c7d686cf3
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 28 17:06:47 2011 +0800
+
+ ARMPLT::applyPLT0 applies a value to PLT0 Entry without parameters.
+
+commit 12b04f8ccc3383f2b2325eaeae583e60dd186b96
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 16:57:54 2011 +0800
+
+ Fix bug: Use bitwise AND, not logical AND.
+
+commit 00a411d4015fa2dc9488c5ebd6f8bea498b14731
+Merge: a9ca660 3da5c7b
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 16:20:15 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 3da5c7bdf32a1cdd99ce5e011ad3dfeb420c1ab5
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 28 16:16:14 2011 +0800
+
+ Implement emitSectionData for ARM GOT and PLT.
+
+ Currently I comment some code.
+ I will uncomment them once the size of MemoryRegion is not zero.
+
+commit a9ca660a50cb6bc688b5f08a3bcf2a86a861c134
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 16:15:34 2011 +0800
+
+ Remove API - TargerLDBackend::getRelocEntrySize
+
+ Relocation entry size is both target and format dependent.
+ Let target handles the size itself.
+
+commit 1da35041319730e81faef6ac2a9a060bf9a5ed64
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 15:53:19 2011 +0800
+
+ Add LDSection::setInfoLink() for conforming to GCC.
+
+commit 7b473df9c46e9d998418f906361b9ea6791b0818
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 28 15:22:49 2011 +0800
+
+ Compute layout order of section in Backend.
+
+ Section order in layout is format-dependent and target-dependent.
+
+commit dc6ca94e472933344c278f97b270e9f19cc0cb0f
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 15:16:47 2011 +0800
+
+ Add API - getRelocEntrySize() in TargetLDBackend
+
+ A format dependent API to get the size of
+ relocation entry.
+
+commit d8f43156bbebc508e1805d3fa5ef1dabd014e83a
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 14:21:15 2011 +0800
+
+ Fix Bug - set pExist in getEntry()
+
+commit cad284cb9ee0267fda05ebe7880bb6f94255d4c5
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 14:10:52 2011 +0800
+
+ Implement ELFWriter::getEntrySize().
+
+commit b9ec46b43454ab7c9693113f723a0071b72e41fa
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 13:59:52 2011 +0800
+
+ Refine the function name.
+
+ Because we have too many getEntry() functions, so I change the
+ ELFWriter::getEntry() to ELFWrite::getnEntryPoint().
+
+commit dc6b852ba058d21b7fe0d62559da8a250d078fca
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 13:49:27 2011 +0800
+
+ Add LDSection pointer into GOT, PLT and ARM/MipsDynRelSection
+
+ For target dependent ouput sections and relocation ouput
+ sections, target should maintain the size of the section
+ by itself.
+
+ While reserveEntry() is called, the size in LDSection has
+ to be updated, so that Layout will get the correct size
+ to decide the section offset.
+
+ Besides, target should maintain the offset of MCFragment
+ (GOT, PLT,...entries) by itself if the offset is needed to
+ apply relocation.
+
+commit 1fe266a3b6f6344e94a3d36d459c3eef838dc45f
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 28 13:42:24 2011 +0800
+
+ Refine the code in Layout::getFragmentRef().
+
+commit f329318e92f6519718f22e0672a54dad6c82835f
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 28 13:18:30 2011 +0800
+
+ Also make sure that fragment is ordered and valid in Layout::getFragmentRefOffset()
+
+commit 102e3e1abe8cee149d23bcea2c02a1980fa5029e
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 13:17:25 2011 +0800
+
+ Short cut for debuging sections.
+
+ On-device linking should not support debug sections. But, in order to
+ speed up the development process, I handle debug sections as regular sections.
+
+commit e167e013b8afa7d91361134f30a5d9af7c93b6a6
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 28 13:10:17 2011 +0800
+
+ Refine the code to set layout order.
+
+commit 7896922ad4d92c18ddfaee1c4ea83ba6a15e32bd
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 28 11:45:08 2011 +0800
+
+ Fix a bug in Layout::getFragmentRef().
+
+ As computing the size of a range (section), need to add the size of last fragment.
+
+commit 7708c0fc24bf143fe68319b8c7fd4ff7ba4e3a24
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 28 11:41:38 2011 +0800
+
+ Add code to order a range of fragments (set their LayoutOrder correctly.)
+
+ The patch for LLVM in commit, 040f5ca0cb95bf2329e1251e9bb28031d335dce7,
+ to initialize LayoutFragment in MCFragment is required.
+
+commit 58e517a42a9d9b6a56c9f6064e9bbb8ad9300e8d
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 10:58:03 2011 +0800
+
+ Unify API - getSectionData() in GOT and PLT
+
+ Both return reference of MCSectionData
+
+commit 70c8782ef9d85aabdce5bca11b7e2eebb03d0022
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 28 10:50:41 2011 +0800
+
+ Modify API - getEntry() in ARMDynRelSection
+
+ Add input parameter "isForGOT" to identify if the relocation
+ entry is used to relocate GOT or normal sections.
+
+commit 040f5ca0cb95bf2329e1251e9bb28031d335dce7
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 28 10:21:45 2011 +0800
+
+ Update patch/LLVM.patch. Initialize LayoutOrder in MCFragment.
+
+commit 477d9de2b9f562ea9178e867d80268c302b28706
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 10:19:16 2011 +0800
+
+ Scaffolding of R_ARM_THM_CALL relocation function.
+
+commit d315bc21208d5621d4d8efca2d708e521eb7c4ca
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 09:30:47 2011 +0800
+
+ Fix bugs of ARM thm_movw, thm_movt relocations.
+
+commit 7fc904d41c54b98470d0dcaeaa7751d706a15fbf
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 10:14:31 2011 +0800
+
+ Add MCFillFragment when meeting a BSS.
+
+commit 21f92079397642341b072ff8f90345332f48f8a7
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 28 09:59:58 2011 +0800
+
+ Move private member data in MCFragment to protected for inheritance.
+
+commit 64e35a9817d664329a5deaaf715d9ab37352fd79
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 28 09:41:53 2011 +0800
+
+ Add new MCFragment type FT_Target for target-dependent MCFragments.
+ Remove FT_GOT and FT_PLT.
+
+commit 744ed8b01a28643ff1da44aa14149ed42ab104ad
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Wed Dec 28 09:19:26 2011 +0800
+
+ pread() returns ssize_t (signed size type),
+
+commit 4b0487ce96bfe0a73421bca2057ca4cee2aab00d
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 05:03:26 2011 +0800
+
+ Refine R_ARM_THM_MOV* relocation functions.
+
+commit 2bb6c4f20e7b9bc6d4c21f3d183cbee9b2398f98
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 04:35:13 2011 +0800
+
+ Extract common helper function for ARM movw, movt relocation.
+
+commit 383363bb1d288bd6b862e09058128d35427d99b2
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 04:22:43 2011 +0800
+
+ Refine R_ARM_MOVW_ABS_NC and R_ARM_MOVW_PREL_NC relocation functions.
+
+commit 3f51c2d057d3d5d7c14dd46ca864d5105d2ebecf
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 03:42:38 2011 +0800
+
+ Fix bugs - ELFObjectReader should put all LDSections into the input's LDContext.
+
+commit 603b0387a42db848b7ebb6e3220fd18fea9c8421
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 03:41:40 2011 +0800
+
+ Fix a bug - ELFReader::getLDSectionKind() should follow this table:
+
+ Regular AW SHT_PREINIT_ARRAY .preinit_array,
+ Regular AW SHT_INIT_ARRAY .init_array,
+ Regular AW SHT_FINI_ARRAY .fini_array,
+ Regular AW PROGBITS .ctors,.dtors, .data,
+ Regular AX PROGBITS .text
+ Regular A PROGBITS .rodata
+ Null 0 NULL ""
+ BSS AW NOBITS .bss
+ Note A PROGBITS .interp
+ Note AW DYNAMIC .dynamic
+ MetaData 0 PROGBITS .comment
+ NamePool A DYNSYM .dynsym,
+ NamePool A STRTAB .dynstr,
+ NamePool A HASH .hash
+ NamePool 0 SYMTAB .symtab,
+ NamePool 0 STRTAB .strtab
+ Relocation A REL/RELA .rela.dyn, .rela.plt, .rel.dyn, .rel.plt
+
+commit ad55c14f39a890182e5702b508e59817dd1fcb0e
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 03:38:50 2011 +0800
+
+ add MCLinker::getOrCreateOutputSectHdr()
+
+ In some cases, it becomes convenient if MCLinker can get or create the output
+ section and return it directly.
+
+commit 3e9875d283ab7366a0e5273338e60fd6d6205ee0
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Dec 28 03:23:58 2011 +0800
+
+ Code cleanup.
+
+commit 194eff80a5bd3f109548f1092904fba335dc39ea
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 02:27:55 2011 +0800
+
+ Implement R_ARM_MOVT* and R_ARM_THM_MOVT* relocation functions.
+
+commit 680035f66033ab667c66102207250e89f7ce64df
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 01:56:47 2011 +0800
+
+ Let writers can emit correct section header and tables.
+
+commit 54541820a23ecebb3be2d73f00ddd62c9e03dbc2
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 01:55:26 2011 +0800
+
+ Add LDSection::setKind(). Writers want to esure LDSection::kind() is also correct.
+
+commit 45433c157107cc762516c6045ae7afe1f96bc8da
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 01:54:37 2011 +0800
+
+ increase the default number of the program header entries.
+
+commit 21817979918904927121a4e86ce3080207bf60d0
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 01:49:44 2011 +0800
+
+ Decrease the warning level. When a weak symbol is marked by a dynamic defined symbol, it won't issue warning.
+
+commit 91331253ad64c0adc2eb2a5712b82fa72facb017
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 28 01:48:58 2011 +0800
+
+ Add a new function LDContext::getSectionIdx - get the section's index by name
+
+commit e3735a39ad183bff6cbcaee31bc0f0f587d27cf8
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 01:50:08 2011 +0800
+
+ Add ARM TLS relocation function which LLVM may generate.
+
+ Though, we don't support it,
+ we still have to show error, rather than keep silent.
+
+commit 095825be0c84e71a142668ec8d802a8ebd01018f
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 01:34:21 2011 +0800
+
+ Coding style: 80-columns.
+
+commit 9445f38aa166c6bfbf88b878ec635d69318a1472
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 01:07:54 2011 +0800
+
+ Implement R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVW_PREL_NC relocation type.
+
+ Besides, merge MOVW unchecked (_NC) relocations into one
+ function, since their behaviors are almost same.
+
+commit 406eda48bf763dccdfe91bdac62af78083b810f2
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 00:55:43 2011 +0800
+
+ Implement R_ARM_MOVW_PREL_NC relocation type.
+
+commit fa8c9091bd937bd8e66721d076981d9994cae743
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 28 00:34:47 2011 +0800
+
+ Implement R_ARM_MOVW_ABS_NC relocation type.
+
+commit 59768ad2fc0980bc532e65e5b034a67620df12fd
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Dec 27 23:19:02 2011 +0800
+
+ Remove unnecessary functions of GNUArchiveReader.
+
+ Refine the code & Remove unnecessary functions.
+
+commit 5b6640ea2a376f99b26c876b8d30d2bfb8714505
+Merge: cde246a 868694a
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Dec 27 23:15:59 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 868694a9bda6f56c15ae0e8791117d86fc1fec78
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Tue Dec 27 23:11:53 2011 +0800
+
+ Revert "Implement R_ARM_PC24 relocation type."
+
+ This reverts commit c87a5f2e7f04d0a055be56c32f8e492913197a06.
+ Sorry that I misunderstood the spec.
+
+commit 5bdec948675c82e62d12c03ae7d48767c1e1ae39
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 27 22:19:33 2011 +0800
+
+ Not compute the size of Reloc, GOT, and PLT fragment.
+
+ Let Backend handle this. Layout and Writer only need to know llvm Fragments,
+ RegionFragment, and total size of Reloc, GOT, and PLT from LDSection.
+
+commit c87a5f2e7f04d0a055be56c32f8e492913197a06
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Tue Dec 27 21:30:09 2011 +0800
+
+ Implement R_ARM_PC24 relocation type.
+
+commit cde246a667964c47ee943d8adcd5be5f43720c0e
+Merge: cc0fbc5 bd84a4d
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Tue Dec 27 18:49:11 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 14d7bf7c90c6aeb2d86fbcae7a6982fdb501fb21
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Dec 27 20:55:54 2011 +0800
+
+ Add R_ARM_CALL and some PLT helper functions.
+
+commit 73295df697a0ef738c828c99fb07edd40198aa7a
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Dec 27 20:54:39 2011 +0800
+
+ Add sign extend helper function.
+
+commit b112fdac7aeddfd1d845ca3949fe685b4b880d93
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 27 19:42:27 2011 +0800
+
+ Implement Layout::getFragmentRef() and Layout::getFragmentRefOffset()
+
+commit a027e466cbe5faf59721b306b0dc0379058466eb
+Merge: cc0fbc5 bd84a4d
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Tue Dec 27 18:49:11 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit cc0fbc5a0eb54e1d3c6ed579054a7a099ad0c92f
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Tue Dec 27 18:46:57 2011 +0800
+
+ std::stringstream needs <sstream>
+
+commit bd84a4dadf172e81ce7da79c0a8651d6d4416a49
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 27 18:46:27 2011 +0800
+
+ Compute the size of MCRegionFragment.
+
+commit aeee708ab045c5c578d94a571c3b62278e1ec3a0
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Dec 27 17:53:59 2011 +0800
+
+ Merge fix for relocation API issue.
+
+commit 386243f21a3e2ac83ad28c07c3e1080bfc59afdf
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Dec 27 17:05:15 2011 +0800
+
+ Rewrite R_ARM_GOT_BREL.
+
+ Apply relocation must focus on apply the "pReloc" relocation. Initialize
+ GOT, PLT, and dynamic relocation can done by helper functions. Because
+ those operation basically is Relocation type independent.
+
+commit 79c8ca3952615702a038b9bc7cc8224cdbd1a755
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Dec 27 15:55:40 2011 +0800
+
+ Fix helper_GOT(section offset+fragment offsest).
+
+commit 94cb09aa2bc372660e2c238e36fc9824ed2c9bb6
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Dec 27 15:44:36 2011 +0800
+
+ Remove rel apply function's pParent constent.
+
+commit d18676dbdb3a398001fba2ed5bf7fd65d93e1e66
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Dec 27 15:34:35 2011 +0800
+
+ Fix typo.
+
+commit 86846f7389eec716042f7caf827e263c06bfd193
+Author: TDYa127 <a127a127@gmail.com>
+Date: Mon Dec 26 22:42:30 2011 +0800
+
+ Implement ARM relocation: R_ARM_GOT_BREL.
+
+commit 8fd4a499866676b85f801205fa5f8a9957e07460
+Author: TDYa127 <a127a127@gmail.com>
+Date: Mon Dec 26 22:34:48 2011 +0800
+
+ Add ARM relocation helper functions.
+
+commit c0f3c5a687adcec37cff147f28b7cd7832a16f20
+Author: TDYa127 <a127a127@gmail.com>
+Date: Mon Dec 26 03:44:18 2011 +0800
+
+ First priority arm relocations.
+
+commit be5a709c5918ee07a76ad847f028b84a9cb8ce05
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 27 17:43:52 2011 +0800
+
+ Fix a bug - Writer should use LDSection::kind(), not LDSection::type(), to determine if the section needs special handling.
+
+commit 9ee0f2379307072fb2dcdfa9d42a297d9ddb64a8
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 27 17:34:57 2011 +0800
+
+ Implement readers -
+ 1. ELFDynObjReader::isMyFormat() and endian()
+ 2. ELFObjectReader::isMyFormat() and endian().
+
+commit d9834d67410416b522cbaacc226978e99bb84751
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 27 17:33:50 2011 +0800
+
+ Fix a bug - ELFReader::fileType() reads the opposite endian.
+
+commit 0864b0c13f96891c2b4dbc0333c77a4d8adbf18c
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 27 16:58:19 2011 +0800
+
+ Implement some functions in ELFReader.
+
+commit e3c302fe3c0e0e82af035641fad3f8ad6a87c74e
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 27 12:47:53 2011 +0400
+
+ Turn on MIPS LDInfo attributes and constraints.
+
+commit ce007f50cb4bdd4bfb91494cecd96b9c1eac1b82
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 27 15:49:07 2011 +0800
+
+ Enhance applyPLT1().
+ applyPLT1() now is able to apply correct values without parameters.
+
+commit eeb44651bedcd420c455c5d889d2de9c1225d76f
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 27 15:33:16 2011 +0800
+
+ Separate ELFReader::createELFObject() into createELF32Object() and createELF64Object().
+
+commit 26160f290eb376486323368c149a18a85b572222
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Dec 27 15:07:16 2011 +0800
+
+ Unify API getEntry()
+
+ Let GOT has the same input parameter type with
+ PLT and ARMDynRelSection.
+
+commit 50dc0f97dd8298d06bbeab193f3accee63cf2f6a
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 27 14:29:13 2011 +0800
+
+ Fix a bug - getLDSectionKind() can not return LDFileFormat::Debug.
+
+ In ELF, debug section is ruled by prefix 'debug', not type.
+
+commit 788fe3a6b7a58f267a055f5dde09c90e1c27e6bf
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Dec 27 13:09:02 2011 +0800
+
+ Fix bug : assert when m_pTargetData is NULL
+
+commit 1ed052e43da5b90a10c9e85a56c759c726f7206d
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Dec 27 13:05:00 2011 +0800
+
+ Add setSymInfo() in Relocation
+
+commit c438c453c3d370a5d847ce30f5a08af7c8f759d0
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 27 11:50:39 2011 +0800
+
+ Fix a bug - MCFragmentRef should have forward declaration of class Layout.
+
+commit d0b1762356e1e1ef3d91b2172a1b0d360be75b71
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 27 10:24:02 2011 +0800
+
+ Add implementation of layout functions to lay out a fragment.
+
+commit dd59a29fcb34ce87d072f1c93dec6fa65de83fe8
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 27 09:54:01 2011 +0800
+
+ Follow llvm::MCAsmLayout to add some layout functions in Layout.
+
+commit edda9ee39c4344fb5c3754434119ad45a9fe3f43
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 27 09:44:08 2011 +0800
+
+ Add mcld::computeFragmentSize for Layout or Writer to compute fragment size.
+
+commit d8bb922d9bfd2cd49210cac36da979b6e6b5f7e6
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 27 02:35:26 2011 +0400
+
+ Replace EF_MIPS_ARCH_32 by EF_MIPS_ARCH_32R2.
+
+commit 2291b81f31b63b8b348bf4a72b98e241d87cd3c6
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 27 02:04:40 2011 +0400
+
+ Add placeholders to .MIPS.stubs and .plt entries reservations.
+
+commit 4997cca774f01db26f8409e3f97a310186f24946
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 27 01:52:37 2011 +0400
+
+ Implement aux functions to create MIPS specific sections.
+
+commit 478439a1992166ddc1874ceaf23dbbe02e27b99e
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 27 01:25:53 2011 +0400
+
+ Implement entry reservation for MIPS .rel.dyn section.
+
+commit 0b960b4748adc67a2571af69ed6bffbc11ebd369
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 27 00:01:28 2011 +0400
+
+ Move GOT section creation to the separate MipsGNULDBackend::createGOTSec() method.
+
+commit 8fd36ac29d938580302a5332ef40bfce3f19d10c
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Dec 26 23:38:42 2011 +0400
+
+ Initial implementation of MipsGNULDBackend::scanRelocation().
+
+commit bc294aa93d072bba5eccbb1ec9c9c42b8f194bbc
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Dec 26 23:27:29 2011 +0400
+
+ Use std::auto_ptr to ensure that an object will be deleted.
+
+commit e2a263e42a309ed7022826406b93ff4f2c067f32
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:27:18 2011 +0800
+
+ implement MCLinker::emitOutput()
+
+commit edc84403dec6d5f906ed502dc1fce16414c8e054
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:25:08 2011 +0800
+
+ Redefine LDFileFormat, and implement the basic shared object writer.
+
+commit 8e4a41c38c083f242aa6e3b3c7fd7dbe860bdfe5
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:23:51 2011 +0800
+
+ Implement -e options.
+
+commit 4f2d8cbc447bef3e2c1bf95e6b6bb29476a593ba
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:22:51 2011 +0800
+
+ Fix a bug - previous commits forget to add GNULDBackend
+
+commit 23ede9002a41baa4f1c1b56d64540deb5f2b1ff2
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:21:15 2011 +0800
+
+ Add some fields for emission of the ELF header.
+
+commit 2518990a1bad651c9c9c59bbfb55782301e89225
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:19:22 2011 +0800
+
+ MCLinker redirects StrSymPool to MCLDInfo
+
+commit b5e2d70aab39eb148b85cb3e366cf988ab5bf7f5
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:18:29 2011 +0800
+
+ Enable -e options in MCLinker.
+
+commit 29c1c4232a0dd9a4273c4f584f861806f1cc61f1
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:17:30 2011 +0800
+
+ Add LDSection::hasSectionData().
+
+commit 2de4610459a3d0ce2c6b374cdc8412faa6044f9d
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:14:39 2011 +0800
+
+ Use only one LDContext::symtab()
+
+ dynsym() is redundant.
+
+commit a3aa37557681f1efec7a96022a972813bf6e09f5
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:10:46 2011 +0800
+
+ Add StrSymPool::addSymbol and addInfo functions.
+
+commit b5947fd364f2cdb9fda2e6b3a5df60b2efebba50
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:09:46 2011 +0800
+
+ Let StrSymPool can get from MCLDInfo.
+
+commit f089c45eb8ec68a317b8bd8552309b9167af6c08
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 26 22:08:36 2011 +0800
+
+ Add some basic functions in Layout.
+
+commit da248b3c9b7a278defce8c6a92d89e8ebaec8988
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 21:10:00 2011 +0800
+
+ Enhance GOTIterator.
+
+commit c34cac884e406a7946242519d1b95f072c504320
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 20:08:33 2011 +0800
+
+ Add a member function getPLT0().
+
+commit 260391b4f21d4ae11787b55321dcff064dbd2d44
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 19:55:09 2011 +0800
+
+ Implement GOTIterator.
+ GOTIterator is used to traverse all kinds of got entries.
+
+commit f50ea946c3740b18be4fd2d0451eaa2164361cb3
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 26 17:54:17 2011 +0800
+
+ Let Relocation be a kind of MCFragment with type FT_Reloc
+
+commit 314174d230658fdd6dfb62436712f5aba4711963
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Dec 26 17:10:57 2011 +0800
+
+ Change the type of Offset in MCFragmentRef to uint64_t.
+
+commit 9d346b4d9295b9e369a7530fad86fa972459307e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Dec 26 17:04:41 2011 +0800
+
+ Implement addInputRange in Layout.
+
+commit 354a447881b4edf663b859518f15c4ed56c0ee58
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Dec 26 15:52:46 2011 +0800
+
+ Refine the structure for input range in Layout.
+
+commit b270dd5d0b06e141ee43fda04c6b4341bbd38690
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 16:27:45 2011 +0800
+
+ Add new MCFragment type FT_Reloc for relocation.
+
+commit 70b7183942d92b6fb93caa6bb4675fe922c07704
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Mon Dec 26 15:52:30 2011 +0800
+
+ Clean up logs
+
+commit aef214663d6584db5b08d6e9bbe9409c34668132
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Mon Dec 26 15:18:39 2011 +0800
+
+ Add program header write out function.
+
+ Program header table sometimes has target-dependent seqment entries
+ for different architectures, currently we use swithes to generate
+ these special segments for now.
+
+commit a9c0210bcdc2ba66b3715261e6f71f15ad100137
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 15:34:08 2011 +0800
+
+ Fix coding style, no functionality change.
+
+commit 056e1aa7f9a303155d3a762e72f3d9a9821ffeb6
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Dec 26 15:32:05 2011 +0800
+
+ Add const version of getSectionData in LDSection.
+
+commit 670f6d30cb243a18b5ac5202df94e692fc4340d9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 15:30:22 2011 +0800
+
+ Update patch/LLVM.patch.
+ Add missing namespace mcld to class Layout.
+
+commit a6cc3d29bf567a42b911ce3759678ab410cd1da2
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 14:45:29 2011 +0800
+
+ Update patch/LLVM.patch.
+ Make Layout be friend class of MCFragment and MCSectionData.
+
+commit 2c6c30e32504e6fc5d98cd134db51d44aac760ee
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 26 13:44:30 2011 +0800
+
+ Add the Implementation of ARMGOT::getEntry, applyGOT0, applyGOTPLT.
+
+commit 4286be84bfadb83c974d71b87327eca6dcfa127b
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 26 13:04:28 2011 +0800
+
+ Implement getPLT(), getRelDyn() and getRelPLT() in ARMLDBackend
+
+commit 295873c9fa6d81adfb438a501f3cd9711dda705d
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 26 11:32:02 2011 +0800
+
+ Add error message in ScanRelocation
+
+commit b4a76b03b70389c37c98f6bc168fdeaee1f89088
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 25 00:43:07 2011 +0800
+
+ Because MCLinker::createSectHdr() and getOrCreateSectionData() always return a valid result, I change their type from pointer to reference.
+
+commit e9be486a629c21e6e3861b21cea901ecf5cbabf4
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 23:23:49 2011 +0800
+
+ Fix a bug - every section header should be added in its LDContext::SectionTable.
+
+commit fa72975274447ca83c1553d078de9d5fc2aee0b2
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 23:23:07 2011 +0800
+
+ ELFReader::getSectionType should return LDFileFormat::Debug type.
+
+commit 889108d49275551a377e3d531fc1fddc587e3517
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 23:21:43 2011 +0800
+
+ remove obsolete getOrCreateSection() in LDContext
+
+commit c64785986f3feffd1aa0995d8292040e67bdf054
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 23:21:00 2011 +0800
+
+ Fix a bug - every pointer should be initialized as zero.
+
+commit 7fb5bd6ccfc84a4088156286d5575bdf020b065e
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 23:05:37 2011 +0800
+
+ Add a new kind - LDFileFormat::Debug
+
+commit fadc31f96b1421789f834cb5a2ce88b0fba3e4f0
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 23:00:18 2011 +0800
+
+ Refine the warning message when read a symbol with unsupported type.
+
+commit b495dc73016cb3648e81ea9f8d37dd8c99fe47f7
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:48:25 2011 +0800
+
+ Fix a bug - add dynamic symbols should enable the `pIsDyn' paramter.
+
+commit 44313e81484300ed0c0a84aa928180a04d196870
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:47:53 2011 +0800
+
+ Fix a bug - dynamic ABS symbol should be handled as dynamic defined symbol.
+
+commit 4a140c1a885ecc12007cfc5acdcf3e9b6a8bd9b4
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:31:46 2011 +0800
+
+ Fig a bug - should let LDSymbol::FragmentRef in ELF shared object empty.
+
+ sh_shndx of symbols in dynamic shared objects will eventually be set to SHN_UNDEF.
+ Therefore, readers do not need to read it.
+
+commit a882ff25989cd64be364b29cfdf70d38c139c556
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:28:38 2011 +0800
+
+ Let the error message of invalid section clearier.
+
+commit 4db79fc61732f32e673818b78bad346699b64657
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:20:02 2011 +0800
+
+ Because we have no RTTI and exception, we should handle the out_of_range by ourselves.
+
+commit 602829648da18410c98e59448b35df863c9af819
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:18:51 2011 +0800
+
+ Refine the symbol-adding functions.
+
+ 1. Add ABS symbol
+ 2. set symbol's fragment reference
+ 3. resolve some conflicting definition between rslinkers and llvm/Support/ELF.h
+
+commit 9f3ccf91ad92cfd5ac04cb18e3076248f183da3b
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:17:34 2011 +0800
+
+ Add LDSymbol::setFragmentRef(const FragmentRef& pRef) for conventient.
+
+commit f9f1d91a209686c994aab1aefff009b9339ae56f
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:16:01 2011 +0800
+
+ fix bug - MCLinker and StrSymPool should provide ResolveInfo::Type as one of the parameters in the adding-symbol functions
+
+commit 841248330380b9c2b1a392e082ef0784a1b83fc9
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:14:37 2011 +0800
+
+ open Layout::getFragmentRef API.
+
+commit 6360a725302d5ec2a496bfbe7855597eec130d74
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:11:57 2011 +0800
+
+ Because in current LLVM, some variables, such as STB_LOOS, etc., are defined,
+ I remove them from rslinker/ELF.h.
+
+ In order to avoid `expected unqualified-id before numeric constant', I define
+ these variables by enum, rather than \#define.
+
+commit eb56740fc14caa95f3ee17a4f7b9d9a19922de5a
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:03:08 2011 +0800
+
+ Fix a but - ResolveInfo::overrideAttribute() should override low_16 bits of bitfield.
+
+commit b9a3414dbf1a33fff097f615245347475486c16c
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 24 22:01:25 2011 +0800
+
+ add MCFragmenrRef::assign(const MCFragmentRef& pCopy) for convenient.
+
+commit a96ea168307fb1551bb0cda8319d668ff325b72b
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 23 21:49:15 2011 +0800
+
+ Create .plt, .got, .rel.plt, .rel.dyn Section and SectionData
+
+commit 1f870f1a4516370021ca1aafe4d8cafc3bffac07
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 23 21:22:47 2011 +0800
+
+ Implement ScanRelocation in ARMLDBackend
+
+commit bfadd67b5dd4adf7c627c5c4ffc7cbda8b8f835c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 23 21:20:14 2011 +0800
+
+ Create ARMDynRelSection
+
+ The dynamic relocation table for .rel.plt and .rel.dyn sectoin
+
+commit 334cd9bbf3580d5496aeafeff633093991c32f02
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Dec 23 21:00:55 2011 +0800
+
+ Add addMapping() in SectionMerger.
+
+ When we need to create a section header for output LDContext, we should add a
+ mapping in the mapping table of SectionMerger.
+
+commit 704c3720fc2d25da8a1fa70eaa82ffa898e25dbf
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 23 20:16:40 2011 +0800
+
+ Remove TODO and fix a bug in ARM::getEntry().
+
+commit db8508c939ea1bf4073fcf7d1c665200d7594701
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Dec 23 20:08:37 2011 +0800
+
+ Add find() in SectionMerger.
+
+commit e7f12246d4b47749b7a2157b8929c8166e367747
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Fri Dec 23 19:55:28 2011 +0800
+
+ malloc() should in stdlib.h, and many BSD systems don't have <malloc.h> now,
+
+commit b6d299d0eab71ab6e44fe820ae8b21409bc5d283
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 23 17:59:22 2011 +0800
+
+ Enhance ARMPLT::reserveEntry().
+
+commit a0df9590e866888238f16f96368992c78f35ef6e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 23 17:34:08 2011 +0800
+
+ Implement several ARMPLT methods.
+ They are applyPLT0, applyPLT1,and getEntry.
+
+commit 67c632f5ef29f7265eef50a6a80c067af7c241c7
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 23 16:27:25 2011 +0800
+
+ Fix a bug -
+ Typo, I should use CommonBlock rather Common for the Type.
+
+commit 8598343dee8f6bcba51cf1fbf105082123620edc
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 23 16:12:22 2011 +0800
+
+ Add ResolveInfo::Common for common block.
+
+commit c8ec48b211ae5411c7a56116a279caff3dbd883d
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Fri Dec 23 10:34:17 2011 +0800
+
+ Write out section data by iterate the section header.
+
+ Assume layout is done correctly, now we can start to write section data.
+ Use LDContext::const_sect_iterator to iterate all LDSection and get
+ its MCSectionData. Currently, we have not really write section data
+ to the output file.
+
+commit 3be6b667c849092fa342a6f297a10d9864db81f2
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 23 15:52:08 2011 +0800
+
+ Open MCLinker API to add relocations.
+
+commit 075fbe5c4cf1dcb0d00cfd1bce647590de751521
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Fri Dec 23 15:02:28 2011 +0800
+
+ Add alignment information in section header table.
+
+commit 8f6382e415272fa13277f1051056545bfd7cadcf
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Fri Dec 23 14:02:13 2011 +0800
+
+ Support read sections from ELF-Object.
+
+commit b6f208cfc7d7bfb74e7e020f25edca4704fd1e89
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Thu Dec 22 20:12:59 2011 +0800
+
+ Support ELF-Relocation in ELF-Object.
+
+commit e813f3423d33f4659352a970a67e2fbb466e3ba8
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Fri Dec 23 14:36:44 2011 +0800
+
+ Refine ELF header write out function.
+
+commit 4ed0c1dd2ae53fde8ea0739bd2edef08a71fcac9
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 23 14:21:35 2011 +0800
+
+ Fix bug -
+ StaticResolver will jump out of the table.
+
+commit 47c946561772f56a91f6b2d0f2462cec26e18054
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 23 14:12:34 2011 +0800
+
+ Add Resolver::Result to member the result of symbol resolution.
+
+commit dff7a00f6c4d9f7bf175ea708f9e8718bc29083f
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 23 13:36:25 2011 +0800
+
+ Make PLT own an MCSectionData pointer as GOT rather than inheriting it.
+
+commit 41d11b46b66ccd21c5aa16e728cb92b43ebd664f
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 23 11:44:03 2011 +0800
+
+ report an internal error when StaticResolver fails.
+
+commit 1d7b2f4aece1ab876f9b9addda822b52f771cd4d
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Fri Dec 23 11:05:36 2011 +0800
+
+ Fix typo.
+
+commit 81eefc392b18ac213d9b6e13c2de095025012bda
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 23 10:47:32 2011 +0800
+
+ Make GOT own an MCSectionData pointer rather than inheriting it.
+
+commit b75c07654bfa79acb34d9e8d74ad56a8ca2b9d02
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Fri Dec 23 09:28:57 2011 +0800
+
+ [Style] Remove 'using namespace std' and #include <iostream>
+
+commit 94b0a18372c1f4f32bcad850959929a4b5e2fe26
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 23 09:39:01 2011 +0800
+
+ Move initPLTEntry to private.
+
+commit 7948f2fbcd77d6ad49903c4ae25d857b377904a5
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Fri Dec 23 09:16:38 2011 +0800
+
+ Refine the code.
+
+commit ff21d7cce6ca4401298dba08e141b8ddd12362f3
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 21:43:06 2011 +0800
+
+ Initialize the pointer to MCSectionData in LDSection as NULL.
+
+commit 563614a22083cb5590a195bb9e1942af773be972
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 21:24:21 2011 +0800
+
+ Implement getOrCreateSectData in MCLinker.
+
+ Any who request a MCSectionData from MCLinker should base on a LDSection first.
+ And SectionMerger in MCLinker will try to find a suitable MCSectionData in return.
+ (see commit, 162fb771a9d9e351a45aeeba2a7c7433863694b5)
+
+ And the pointer to MCSectionData in input LDsection and/or in output LDSection
+ will be set properly also.
+
+commit dcf956efa48e2c4581bf4f3c9ef848f36259eba0
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 21:20:22 2011 +0800
+
+ Add SectionMerger in MCLinker.
+
+commit 162fb771a9d9e351a45aeeba2a7c7433863694b5
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 20:49:54 2011 +0800
+
+ Refine SectionMerger to fit current design.
+
+ SectionMerger would use
+ 1. SectionMap, a "Name-to-Name" map from input substring to output section
+ 2. LDContext of output, who has the output LDSection list
+ to build up another map from input substring to output LDSection.
+
+ And then from the output LDSection itself, an associated output MCSectionData
+ can be gotten. Furthermore, section mergeing is done in this way.
+
+ For example, reader requests one MCSectionData for .text.foo, and another one
+ for .text.bar, and SectionMerger returns the MCSectionData of .text in output
+ directly.
+
+commit bdb417e301a5f7376b09b8502dc648aa3c3e1b9a
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 22 21:28:50 2011 +0800
+
+ A quick patch.
+ Avoid passing instances of derived classes of MCSectionData
+ to MCFragment constructor, this results in segmentation fault.
+
+commit 80dd5b73b833cbca0118d3d2bca79268590133ff
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 22 21:14:57 2011 +0800
+
+ Modify API - TargetLDBackend::scanRelocation
+
+ Add parameters pLinker and pType
+ pLinker - we need MCLinker to create LDSection and MCSectionData
+ pType - the output format type
+
+commit bba7f054c9e0d065796fba853ae04a8459f5b93a
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Dec 22 20:37:55 2011 +0800
+
+ Update .dynsym and .dynstr section header.
+
+ Write the correct sh_offset and sh_addr.
+
+commit 3605d5accef1ed0067d351fe97283478da0d76e5
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 22 20:39:48 2011 +0800
+
+ Add API - produceEmptyEntry() in RelocationFactory
+
+ When ScanRelocation, we need to create empty entry for
+ dynamic relocatoin (ouput relocation).
+ These empty entris occupied memory space but all their
+ contents are set to zero.
+
+commit af4db020d4e4e54b445052c293b2b43b45f197a4
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Thu Dec 22 18:10:16 2011 +0800
+
+ Fix some typo and comments.
+
+commit a94967b9a9989f8dc44c64844d7719c214525192
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Thu Dec 22 17:31:49 2011 +0800
+
+ Fix section header table sh_name index assignment issue.
+
+commit c82184bbb81bb03caf5ade27d508ae2509edd1e6
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 14:52:40 2011 +0800
+
+ Let bitcode is a kind of position-dependent option
+ The embedded libraries also be treated as a kind of namespec.
+
+commit 466b0cdc4a3b225e25c47c6ed3664cadea4fccf7
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 22 14:41:07 2011 +0800
+
+ Implement ARM GOT.
+
+ There are three kinds of got entries in .got section,
+ they are reserved got entries, got.plt entries, general got entries.
+
+ The top of .got section is reserved got entries,
+ and got.plt entries immediately follow behind reserved got entries,
+ the last are general got entries.
+
+ We store got entries in three separate ARMGOTEnties instances, which inherits MCFragment,
+ to avoid sort or rearrangement when writing out by the order.
+
+commit 59b6ca8c30e79e4ab266fc9d24e66b37cd6a6f08
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Dec 22 14:35:27 2011 +0800
+
+ Add sectionStartOffset() to get section's start offset in the output file.
+
+commit 3fb6408e6459c4350f177a6af4a450ff2198a694
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 13:17:34 2011 +0800
+
+ Change the type of first parameter `pInputFilename' from const std::string& to const llvm::cl::opt<std::string>&
+
+ Because the input bitcode should be position-dependent, we let the input bitcode keep its position.
+
+commit a2f95fdceef97f926d2ba0800895dfb15df8ceaf
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 13:14:30 2011 +0800
+
+ Add ARM dependent section mappings in ARM backend.
+
+commit f80e8451062a6d5abc181c06f39ac015247fd87e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 11:48:38 2011 +0800
+
+ Initialize standard section map in MCLinker.
+
+commit f9563793a42417edccdbfbfb98e1483d07159a92
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 11:45:54 2011 +0800
+
+ Refine SectionMap.
+
+commit ea7fa03a1ee865ea96e5a8055a8f1da196d7c34e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 11:25:34 2011 +0800
+
+ Add initializing section map support in MCLDDriver.
+
+ 1. MCLinker will add standard section mapping, e.g., elf
+ 2. Target can also add target dependent mapping
+
+commit b83f5af023bba393b8d32521c353bae3f048ee42
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 10:55:21 2011 +0800
+
+ Refine the warning message in SectionLinker
+
+commit 72d9fe76ade287a3050525b066cb6556c99c1987
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Thu Dec 22 10:39:24 2011 +0800
+
+ Refine mapping rule in SectionMap.
+
+ Add support for
+ 1. wildcard (*) to a user defined output section
+ 2. if still no matching, just let a output section has the same input name
+
+commit 1afc0eed3dfdc2d83accf429675bba1889ff1043
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 10:43:02 2011 +0800
+
+ Refine the warning message of AndroidSectLinker
+
+commit 2d485e6bd0d7e7d4e3fec3a820a3bd1fd765e025
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 10:40:15 2011 +0800
+
+ Decrease the level of warning -
+ If a directory can not open, should not report fatal error immediately.
+ We should open a !isGood() directory.
+
+commit d5f4d60ae3ae23872b2dbb763e5db4f1c4f3918a
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Thu Dec 22 09:30:12 2011 +0800
+
+ Remove function which generates testing information.
+
+commit 75a0870fab5038e8fc48c7791c246de692c14a68
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 02:17:40 2011 +0800
+
+ MemoryArea should open before calling isMyFormat().
+
+commit 023ec211429af0691f35a12cb8d7ead5efa5d73c
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 02:15:41 2011 +0800
+
+ Let AndroidSectLinker to go the normal path.
+
+ Previous AndroidSectLinker use its own doInitialize for rapid prototyping.
+ This patch changes it to the original normalization path.
+
+commit 5487eb6731c23814b23dac000d3ac6945d1e60af
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 02:14:01 2011 +0800
+
+ Fix bugs -
+ MCLDDirectory::iterator should always begin from the cache.
+
+commit 4a1065cec7608c3c5beff5e0b9b46b153920e6e6
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 22 02:10:15 2011 +0800
+
+ Fix a bug -
+ When HashIterator is end(), it should return immediately.
+
+commit 7fefe1136c75dbb0ccc6c10aff3934f819c5a7a4
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Dec 21 19:15:09 2011 +0400
+
+ Check for _gp_disp symbol name in the R_MIPS_LO16 relocation processing function.
+
+commit a17c1f7d1a52f064978c189decc4f2ceb10628de
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Wed Dec 21 22:18:17 2011 +0800
+
+ Add section header table write out functions
+
+commit ec1ee45956d01c70c2bc7d9a185ece6a72f38362
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 22:08:35 2011 +0800
+
+ The function, getOrCreateSectData, should depend on LDSection.
+
+commit ebfe31b80d1342d33f1e9d1362d1a445eef0e7db
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 22:06:41 2011 +0800
+
+ Implement getSection in LDContext.
+
+commit 9d809e93e8d24ff1577aebe90c648dcc9b90e4da
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 21:56:10 2011 +0800
+
+ Changes due to the change of corresponding api name.
+
+ This is based on previous commit, 37c5f6f9e8cf38375b60d2c587b56987d0952dd9
+
+commit 37c5f6f9e8cf38375b60d2c587b56987d0952dd9
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 21:50:20 2011 +0800
+
+ Change getOrCreateSectHdr to createSectHdr in MCLinker.
+
+ Now reader also needs LDSection and all users of LDSection should get it from
+ corresponding LDContext. Thus Change the api name to prevent confusion.
+
+commit 6776482e59b8a845fe607a5362905209a06150ac
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 21:36:34 2011 +0800
+
+ Add SectionMap in MCLDDriver.
+
+commit d7409c8f8fbcc84c4ad1b85c9731e0760d0d045e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 21:28:13 2011 +0800
+
+ Add getOutputSectName api in SectionMap.
+
+ This is for user to find out the associated output section name from the
+ given input section name.
+
+commit c205ff091f4f44ca48762e9ede1b32acea5a031e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 21 21:24:15 2011 +0800
+
+ Create GOT, PLT, .rel.dyn and .rel.plt in ARMLDBackend.
+
+commit 49ffca6e955889e3da28895962fe64acaf2d4f55
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 21 21:09:03 2011 +0800
+
+ Modify Relocation to inherit MCFragment
+
+ The Relocation becomes a kind of MCFragment.
+ and the relocation table will be a MCSectionData.
+
+ Modify applying function lol6 in MipsRelocationFactory
+ to resolve the pReloc.getPrevNode() return type.
+
+commit a10467493cce08fc3c4f32f2784e6e061cfcacf3
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 21 20:34:53 2011 +0800
+
+ Add a missing header file.
+
+commit 4d39006bf5bcb671598f60cc8dff084aff0b6156
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 19:12:55 2011 +0800
+
+ Add pointer back to MCSectionData in LDSection.
+
+commit 0d520ec83c443eb282b57c8df93e499a0603e42b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 21 19:06:46 2011 +0800
+
+ Add a missing header file.
+
+commit 9d76dae305e578f5a5e70bcfe0149ce1e11792db
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 17:40:09 2011 +0800
+
+ Trigger read sections.
+
+commit c0422e9a5498d7d205eedc5a3bbe243bf8cb2ba4
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 17:19:54 2011 +0800
+
+ Change ResolveInfo::value() setValue()
+
+ Because Relocation should use finalized symbol value, so we
+ move the finalized address pointed by the symbol from ResolveInfo::value
+ to LDSymbol::outSymbol().
+
+commit 3b02f5cee5027922e5230b142ac04e9094da17b3
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 16:44:12 2011 +0800
+
+ Add value in LDSymbol.
+
+commit 29ed64610896512023a5a74039d70a1cf84242c3
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 15:05:33 2011 +0800
+
+ open finalizeSymbolValue API.
+
+commit d88adc28c78f94bf49ba4c4d55e5f63b4a3223b8
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 21 14:09:10 2011 +0800
+
+ Add API - TargetLDBackend::scanRelocation(Relocation&)
+
+ Determine the entries such as GOT and PLT are needed or
+ not for the input relocation. If needed, create the
+ empty entries.
+
+ After symbol resolution has been done, MCLinker traveses
+ relocations to generate empty entries. These empty entries
+ are genrtated for Layout to determine the ouput offset.
+
+ For ARM and X86, GOT, PLT and dynamic relocation entries
+ are created if needed.
+
+ For Mips, GOT, dynamic relocation, GP, or other target
+ dependent entrires are created here if needed.
+
+commit 471f65e19434dab1adca03fcde8a9e8bb821db57
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 12:55:14 2011 +0800
+
+ Fix a bug -
+ ResolveInfo.info() is out of the range.
+
+commit 8d236455633bf70a05ef8ca307bf5f2ea481f002
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 21 11:45:38 2011 +0800
+
+ Add virtual function reserveEntry() and getEntry() to GOT.
+
+ void reserveEntry(int pNum) -
+ Before layout, we scan all relocations to determine if GOT entries are
+ needed. If an entry is needed, an empty entry is reserved by calling
+ reserveEntry(), so that Layout has ability to adjust the GOT fragment offset.
+
+ GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist) -
+ After layout is determined, we fill up the GOT entries when applying relocations.
+ getEntry() return the entry we need:
+ - An empty entry or
+ - the filled entry with pSymbol if we've filled a entry for pSymbol before.
+
+commit d01d57067f588de5483f8d24d2a0ae6c1c78a99b
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 11:32:36 2011 +0800
+
+ Create API - MCLDDriver::createDynSymTable().
+
+ Because the hash table and dynamic symbol table are format-dependent,
+ I want to move related functions to TargetLDBackend.
+ Just like GOT, PLT, dynamic symbol table and hash table should be
+ backend special data structures.
+
+commit eb276864b2cbce9bed1c235b7ffa84099f640e8f
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Wed Dec 21 11:15:55 2011 +0800
+
+ Change field filesize from MCLDFile to MemoryArea.
+
+commit 97371c456b285af22905e1e7bae331d2458bea25
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Wed Dec 21 10:36:43 2011 +0800
+
+ Rewrite SectionMap.
+
+ Now SectionMap contains the mapping from input substr to output str and offset
+ for future LD Script support.
+
+commit 47a13edccd75c4930e09555307c12244e142d234
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 21 10:15:02 2011 +0800
+
+ Modify PLT interface
+
+ 1. add reserveEntry() and getEntry()
+ 2. remove virtual funtion getOrCreateGOTPLT()
+ 3. remove parameter GOT section in constructor
+ 4. Refine ARMPLT
+
+commit 5c01b73d614a2a8d70194374a4654f37beac63f8
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 09:57:01 2011 +0800
+
+ remove the 2nd parameter `TargetLDBackend' from RelocationFactory constructor.
+
+ All target backends have their own special data structures. For example,
+ ARM has .got, .plt, X86 has .got.plt, .got and .plt, Mips has .gp, .got.
+ Those special data structures should not dependent on the abstract TargetLDBackend
+ interface. We want that target backends themselves handle the special data
+ structure.
+
+ We want:
+
+ ARMGNUTargetBackend has functions getGOT(), getPLT()
+ X86GNUTargetBackend has functions getGOT, getPLT(), getGOTPLT()
+ MipsGNUTargetBackend has function getGOT(), getGP(), and so on.
+
+ TargetLDBackend or any abstract backend interface should not provide abovementioned
+ functions, instead, the concrete backend should provide.
+
+ In previous architecture, Luba made a mistake to put the abstract TargetLDBackend
+ as one of parameters in the RelocationFactory constructor. This wrong design forcely
+ put all target special data structure in the abstract TargetLDBackend.
+
+ So, we add getTarget() virtual function in the abstract RelocationFactory,
+ and ask all target backends should implement this virtual function by co-variant
+ return type. For example, ARMRelocationFactory::getTarget() should return
+ ARMGNULDBackend& if the relocation factory is created by the ARMGNULDBackend.
+
+ By the new design, all concrete targets can implement their own target special data
+ structure.
+
+commit d0df17e88eae111b9675126d78589f7d83ae5eb5
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 21 08:52:54 2011 +0800
+
+ Fix build fail
+
+ Remove calling hasPLT() in StaticResolverTest
+
+commit 4eafdad8dab88aa02788d40ee0aabe28bdaee522
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 21 02:23:57 2011 +0800
+
+ Remove hasPLT field and add Reserved field in ResolveInfo.
+
+commit f19050d69265cdc726fadddf6ac66c3deada7c22
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Tue Dec 20 22:31:36 2011 +0800
+
+ Convert value between ResolveInfo::Binding and ELF::Binding.
+
+commit c25457c8b8dc6fe9f2d304c722b92c25d245dc73
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Tue Dec 20 22:01:02 2011 +0800
+
+ Revert the change on LDSection.
+
+commit d658c94c07c615db760ebc0c5f3ee458b9af6269
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Tue Dec 20 16:52:02 2011 +0800
+
+ Support Reading Symbols from ELF-Object.
+
+commit e00f8d3a724850132be9bda9ac6da48cd0c8a964
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Tue Dec 20 20:59:49 2011 +0800
+
+ Add sh_link and sh_info member into LDSection.
+
+commit 2b5edd6068532c9f8588d565a54fd0289101b508
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Tue Dec 20 19:26:28 2011 +0800
+
+ Set correct file size in MemoryArea.
+
+commit c0bb3a7cc615b28c71bd9aef0096736b22d936cf
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 20 17:38:14 2011 +0800
+
+ Add a switch case for mcld::CGFT_OBJFile.
+
+commit a5faec9fb63a81b077c53211f1965b3f810c84f0
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Tue Dec 20 15:37:04 2011 +0800
+
+ Write out .dynsym and .dynstr section data.
+
+commit 4b3b8ee4e42a7cf5be9a2d190ac48f45c20c0b06
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 17:08:32 2011 +0800
+
+ Fix typo.
+
+commit cfce8a2a50a1c1fd589d7385fd15a9d1d5076ce3
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 16:35:16 2011 +0800
+
+ Add ARM target-dependent sections in ARMLDBackend.
+
+ add .ARM.exidx, .ARM.extab, and .ARM.attributes sections
+
+commit 8928ce5f6d36641cbde4bcd234a2c650e6878791
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 20 16:38:49 2011 +0800
+
+ Fix bug in StrSymPool and MCLinker -
+ If the symbol is existent, MCLinker should not push the symbol into LDContext.
+
+commit e840ac925a7873df198577514982cb28254cb5aa
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 20 16:18:23 2011 +0800
+
+ Silence warning.
+
+commit c674a30bae7f58a00d2eca02c1d47200aa5c2c7c
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 20 16:00:58 2011 +0800
+
+ Modify building system.
+ Now MCLinker can be built without "source ./scripts/envsetup.sh".
+
+commit bfbc8dd667b0db11e16fe8e03ca2c9510d8dab98
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 20 15:50:02 2011 +0800
+
+ Add a missing header file.
+
+commit 31109fbf57bdb79e5c8c03b523cf564103556f89
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Tue Dec 20 15:21:15 2011 +0800
+
+ Fix MemoryArea write issue.
+
+ if file_offset+length > current file-size, we need to expand the file-size to fit it.
+ Otherwise, it will cause bus error.
+
+commit 44c8d4ed74ca74b937ef50f40b6f96fb929a1508
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 15:03:29 2011 +0800
+
+ Add getOrCreateSectData api in MCLinker for reader to map and perform section merging.
+
+ To prevent confusion, rename getOrCreateSection as getOrCreateSectHdr.
+
+commit 36d36b889b30c4bbbabc30cb70147c4f47e73486
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 14:50:06 2011 +0800
+
+ Rename SectionFactory as LDSectionFactory, and implement getOrCreateSection.
+
+commit a41acb52f445312bd151a6d022000618760e8e63
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 20 14:20:16 2011 +0800
+
+ Add new testcases for our common cases in AndroidSectLinker
+
+commit e7c6ef256623a6d67ad4a599ee0926b91526a1de
+Author: luba <lubatang@gmail.com>
+Date: Tue Dec 20 13:41:14 2011 +0800
+
+ The function of ResolveInfo::setSource return the opposite value.
+
+commit 93ffd84ed3f19a31a9c2d5bf04034c103f49817e
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 10:36:35 2011 +0800
+
+ Use unified getOrCreateSection api instead of knowing SectionFactory.
+
+commit 9d195a1e34d4688c581d4803f4278e8ad9b573d8
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 10:17:27 2011 +0800
+
+ Clean up the code in MCLDDriver and LDBackend related files.
+
+ Remove LDContext since SectionFactor is moved to MCLinker instead.
+
+commit e142d0e6f51618527fa3c0ce80ee47990e130dc0
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 10:16:00 2011 +0800
+
+ Clean up the code in FileFormat related files.
+
+ Remove LDContext since SectionFactory is moved to MCLinker.
+
+commit c0608413669ea3d8bd812b0e04b9abb543e348b2
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Tue Dec 20 10:06:06 2011 +0800
+
+ Move SectionFactory from LDContext to MCLinker.
+
+ We decided to do so due to centralized design in 1st prototype of MCLinker.
+
+commit c77d5161023a74c16e30cd3431cce9965dfd703a
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Tue Dec 20 10:38:02 2011 +0800
+
+ Support Reading Symbols from ELF-DSO.
+
+commit fa6d740cb8d484b2fc94f16e05b95f4ab0a82722
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 20 10:26:49 2011 +0800
+
+ Add missing DSO and EXE switch case.
+
+commit f9ae5ad6ae862ef5caf155f976f82bce1b0d808f
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Tue Dec 20 03:02:13 2011 +0800
+
+ Fix README.
+
+ Use LLVM 3.1svn r146714.
+
+commit 996126a67872ec293371ebb6ff0afcb265fd3a2a
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 20 10:04:07 2011 +0800
+
+ Add a new getOrCreateGOTPLT method.
+
+commit 49f97b746b703313bd466ac84de2e91c51b38c80
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Mon Dec 19 21:33:51 2011 +0800
+
+ Support ELF Reading feature (Simplify from linkloader).
+
+commit b070963fc72b21e725f1ad43f1561a41bbfe32e4
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Mon Dec 19 22:13:54 2011 +0800
+
+ Fix build fail when no --enable-unittest option configured.
+
+commit 2bd5a857d7ca2028af8094da681d388e33922d1e
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 19 21:42:13 2011 +0800
+
+ Implement place() in Relocation
+
+ Add Layout.h and Layout.cpp into Makefile.am
+
+commit 1f0ff309b4d4b1d6f1cb57f2827c392c350c5368
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Mon Dec 19 15:57:40 2011 +0400
+
+ Fix a comment.
+
+commit d898c017e3b588d6f80e7d78d08f4965f5210a97
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 19 19:05:09 2011 +0800
+
+ Make git ignore ltoptions.m4.
+
+commit f3e15d2ae0cb682268de2f15c4f6edc484a96660
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 19 19:00:29 2011 +0800
+
+ Fix patch/LLVM.patch.
+ Silence warning.
+
+commit faee70930939d2c8d0322839af0da5f347f55c42
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 18:55:29 2011 +0800
+
+ Add MCLinker::addGlobalSymbol() and addLocalSymbol()
+
+ Standard symbol, target-depdent symbol and readers can use these functions to insert
+ and resolve symbols.
+
+commit cf36dcd5dd202c934678818811793198ee62efc0
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 18:54:30 2011 +0800
+
+ Resolver should also return the resolved ResolveInfo.
+
+commit a3bbc16ac5147c3108bf282bdba95e7a45c0207e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 19 18:35:52 2011 +0800
+
+ Remove redundent functions in PLT.
+ Use member functions in MCSctionData.
+
+commit 63e692db6a3ac134c265b6a6e0ffb187d31ab7a5
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 19 17:57:37 2011 +0800
+
+ Remove redundent headers.
+
+commit f2ed2b5917116a3d82c7221818a47767fb215550
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 19 17:47:28 2011 +0800
+
+ Add missing options used in LLVM trunk@146714.
+
+commit 4bcd5f4b6c936e1ea3eeae1ac966612fac562ee4
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 19 17:03:47 2011 +0800
+
+ Migrate to LLVM trunk@146714.
+ Build MCLinker with LLVM trunk@146714.
+ Update the web page "Getting Started" as well.
+
+commit f16e41abd14acd1fa324ab497293e174b39a81af
+Merge: d95e32a 2b71280
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Mon Dec 19 16:22:10 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit d95e32a1df3a30c9fa90cec5585386f3d1258880
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Mon Dec 19 16:16:09 2011 +0800
+
+ don't track generated .m4 files
+
+commit 2b7128027392f16909afbc4f5600778d5a6c3878
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 19 16:14:38 2011 +0800
+
+ Modify PLT amd add class ARMPLT
+
+ 1. Let PLT inherit to MCSectionData
+ 2 Initialize PLT by incoming parameter LDSection
+ (Instead of create LDSection itself)
+ 3. Add class ARMPLT which inherits to PLT
+ 4. Add ARMPLT.h and ARMPLT.cpp into Makefile.am
+
+commit 964f9199fa6d287eb9a452894457cc322fa62629
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Mon Dec 19 16:14:04 2011 +0800
+
+ add generated .m4 files
+
+commit ed95bb627f3f519ec3a6c71f41279fb4f0944c50
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Mon Dec 19 16:04:25 2011 +0800
+
+ test
+
+commit b79bd46262d88553ab48f3ea80c7a2a77d0eeafc
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Dec 19 15:15:37 2011 +0800
+
+ Add a series of init/fini sections in ELFDynObjFileFormat.
+
+commit b3be2785a7b892e9b8c3fc42adcc4c856f44dd77
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 14:31:22 2011 +0800
+
+ Move the call of `adding the target-dependent section' from GNULDbackend to MCLDDriver.
+
+commit cce2a8aca3b3dd6ebd4e419b556b7445b5eb938a
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 14:05:37 2011 +0800
+
+ For conforming to gcc on Linux -
+ Add the return type of the template proxy
+
+commit 79a63702d6f79255d3ad5c5702adfb2518417ea0
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 13:52:07 2011 +0800
+
+ Revert "For conforming to clang on BSD -"
+
+ This reverts commit 5829fb9074efcc5a693e788f0c5822082f0d0844.
+
+commit 5829fb9074efcc5a693e788f0c5822082f0d0844
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 13:41:38 2011 +0800
+
+ For conforming to clang on BSD -
+ Remove the return type of the template proxy.
+
+commit f33989cf39002f9f680706b870696f45261dc63f
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Mon Dec 19 11:36:38 2011 +0800
+
+ Fix page-align logic of MemoryArea.
+
+commit f2d10e4796b895a3ba87e9f97ebba7f26b75c25d
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Mon Dec 19 10:20:42 2011 +0800
+
+ Refine the script used by "add_class" to create .h and .cpp files from template
+
+commit 26725499f6104c7ddf1cd78e426c8396809ffddf
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Mon Dec 19 10:25:53 2011 +0800
+
+ Fix build fail.
+
+commit 1d6aeaa24ffb2dc82a8b516efb13dbdbe646b6d9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Dec 19 09:31:44 2011 +0800
+
+ A quick patch for fixing build failure.
+
+commit e3c72cbc2643120ec4b3395fc4530f88547e8fae
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 05:43:52 2011 +0800
+
+ Finish the basic method to create standard sections.
+
+ The approach is very similar to llvm::MCAssembler.
+ - We replace MCObjectFileInfo by LDFileFormat.
+ - We put all LDSections among all inputs and output files.
+ - We use LDFileFormat to create standard sections.
+ - Target uses LDContext.getSectFactory() to create target-dependent section headers.
+ - Target uses MCLinker.createSectionData() to create the section data.
+
+ ------
+ Because we have to create different type of output files.(DSO, EXE, OBJ)
+ So, we need more kinds of LDFileFormat -
+ - ELFObjectFileFormat
+ - ELFDynObjFileFormat
+ - ELFExecFileFormat
+
+ ELFFileFormat is the basic template for all ELFXXXFileFormat.
+
+ ------
+ I put LDSections into LDContext, and put llvm::MCSectionData
+ int MCLinker. Every input file has its own LDSection list. But all
+ (llvm::MCSectionData::Section* Section)s point to the output's LDSections.
+
+ ------
+ GOT should be a kind of MCSectionData and GOT::Entry is a kind of llvm::MCFragment
+
+commit 04f0003bf35756802c4db3f98bbfb97d9872eb3c
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 19 05:33:37 2011 +0800
+
+ change the definition of GOT.
+
+ Let GOT is a kind of MCSectionData, and GOT::Entry is a kind of MCFragment.
+
+commit 0fa8746d3b81aa7581beac7346088595cdb31963
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Sun Dec 18 16:31:01 2011 +0800
+
+ Remove the SectionList reference in SectionMerger.
+
+ Using the section_list_iterator provided by MCLinker is enough.
+
+commit b7d7c1a757de72a7691effe57a3b80f4c85bca28
+Author: Chinyen Chou <petechou@gmail.com>
+Date: Sun Dec 18 16:25:34 2011 +0800
+
+ Add empty class for DynObjFormat and ELFDynObjFormat.
+
+commit 5ef0cba0ffd2c15f15d2db1d9733c7c34aebb46e
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 18 16:07:03 2011 +0800
+
+ add memcpy() in MCFragmentRef.
+
+commit 013eae897c65d387e997ce9cad5a8d89c0985e5f
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 18 16:05:33 2011 +0800
+
+ ABS symbol should be handled as Global, Define symbol.
+
+commit d6a46b0cc622b1dd537cd879a76b5cf06daa73cc
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Sun Dec 18 11:14:32 2011 +0800
+
+ Change type Address from char* to unsigned char*.
+
+commit 6d64dcd4c26c8426d69b61d153e97d3a160d3ffb
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sun Dec 18 01:22:36 2011 +0400
+
+ Fix a comment.
+
+commit 75d643ff0987a675a78ce5fb93ca019fb9915cc9
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sat Dec 17 23:16:40 2011 +0400
+
+ Improve R_MIPS_LO16/R_MIPS_HI16 relocation processing methods.
+
+commit a1a90389549cb7caf517b2343ad4a25529c985f7
+Author: Jush Lu <jush@Jushteki-MacBook-Air.local>
+Date: Sat Dec 17 23:57:40 2011 +0800
+
+ The section name of GOT should be from parameters.
+ The section name may be ".got" or ".got.plt".
+
+commit 3cc417bd06d2155a941ad58cfb15741a1f85ded1
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 17 21:56:55 2011 +0800
+
+ Add ABS in ResolveInfo. The symbol has an absolute value that will not change
+ because of relocation.
+
+commit 32fecd13ecb24eb9938bbf738da211ef32d4aac9
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Fri Dec 16 16:08:59 2011 -0800
+
+ PATCH: include <sys/stat.h> before using stat
+
+ Hi,
+
+ On Fedora 15, I need to include <sys/stat.h> before using stat system
+ call. This patch fixes it.
+
+ --
+ H.J.
+
+commit bc6734b7b32c2b9e34147c27aba9f6f548cd87fb
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date: Fri Dec 16 16:06:25 2011 -0800
+
+ PATCH: Add -Wformat for -Werror=format-security
+
+ Hi,
+
+ GCC on Fedora 15 needs -Wformat for -Werror=format-security. Otherwise,
+ it will give an error. Here is a patch to fix it.
+
+ --
+ H.J.
+
+commit b751ba2c4be668067a4070e6c3cadec9d52c2ee6
+Merge: d0976f3 71cbee1
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Sat Dec 17 17:52:39 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 71cbee1acd81241ee1908b96eb82376719b8e083
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sat Dec 17 11:37:13 2011 +0400
+
+ Add five new placeholders for Mips relocation handlers.
+
+commit 7b2b6957f8021aa7c9a3bf6be8370117109d663c
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Sat Dec 17 11:03:58 2011 +0400
+
+ Single equal sign is a more portable way to compare strings in a shell script.
+
+commit d0976f3fb6c701c4925b7787aa56d75e6e796a88
+Author: Jush Lu <jush@Jushteki-MacBook-Air.local>
+Date: Sat Dec 17 12:39:36 2011 +0800
+
+ Make PLT have a LDSection.
+
+commit 6a04339e16bf68a6af0f4ff6f82d83053218aafa
+Author: Jush Lu <jush@Jushteki-MacBook-Air.local>
+Date: Sat Dec 17 12:11:31 2011 +0800
+
+ Declare LDSection as member data of GOT.
+ Because GOT always has a LDSection,
+ declaring it as member data to avoid new, delete, and possible exception.
+
+commit cb8b34e4e3069323a97fdbcc9fc952baddccf829
+Author: Koan-Sin Tan <koansin.tan@gmail.com>
+Date: Sat Dec 17 10:25:31 2011 +0800
+
+ README: add source ./scripts/envsetup.sh
+ autogen.sh: libtoolize is named glibtoolize on OS X
+
+commit de13226ca6f60248a20458b4347afa040e0cab77
+Author: pete <petechou@gmail.com>
+Date: Fri Dec 16 22:37:32 2011 +0800
+
+ Add SectionMerger class.
+
+commit 3c7adc64543265f66e132997c3da23f682e5dba4
+Author: pete <petechou@gmail.com>
+Date: Fri Dec 16 21:45:41 2011 +0800
+
+ Give SectionMap a default mappings for ELF format based on gold linker.
+
+ As reading object files that are compiled with -ffunction-sections and
+ -fdata-sections options, this will give better performance.
+
+commit ef81a97de44e75f630999d62d2ad5489b440b88a
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Fri Dec 16 16:30:37 2011 +0400
+
+ Add a couple of trivial Mips relocations.
+
+commit a58abd469d9efdb8135e8a49dcda7cf1c41a5f65
+Author: pete <petechou@gmail.com>
+Date: Fri Dec 16 20:00:32 2011 +0800
+
+ Add SectionMap class.
+
+ SectionMap describes the mappings from input section's name (or prefix) to it
+ associated output section's name.
+
+commit 32e7c33fe84f6a2f1d7e9ecd589b121165483ee9
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Fri Dec 16 15:49:59 2011 +0400
+
+ Small set of corrections in the Mips related files: headers,
+ comments etc.
+
+commit 921c4243aebd8a2de573935641589f345060c218
+Author: pete <petechou@gmail.com>
+Date: Fri Dec 16 19:03:23 2011 +0800
+
+ Add SectionFactory class.
+
+commit 40d79dfaf7a917ea07189318885299f1bc702cfa
+Author: pete <petechou@gmail.com>
+Date: Fri Dec 16 19:02:51 2011 +0800
+
+ Add rule to ignore *.o in .gitignore
+
+commit 2b5181f9a8ce07e780a721cd7f47a4c0dcc58437
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Fri Dec 16 17:41:45 2011 +0800
+
+ Add 64bit object file output support
+
+commit 060d3cc2818202c4b9af18ae304fc7921b767263
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 16 17:21:23 2011 +0800
+
+ Move ARMGOT and ARMPLT to separate header files.
+ No funtionality or interface change.
+
+commit 9388bb27659329e44c76e5dba9a77bcd203ebd26
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 16 16:59:18 2011 +0800
+
+ Remove the duplicate member functions in GOTEntry and PLTEntry.
+ Use the member functions inherited from MCFragment instead.
+
+commit 8711bed79380c375975ef467d36f9ce30fe89768
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:30:33 2011 +0800
+
+ Add GOT, RelocationFactorys in the compilation list.
+
+commit f9c9383df1f1abc14e1bd908bc906c06eb76ab88
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:26:55 2011 +0800
+
+ Sorry for the big change. But I think the new architecture is easier
+ to understand. All that targets need to do becomes list all relocation
+ function prototypes in ARMRelocationFunctions.h (C functions) and
+ implement each C function in RelocationFactory.cpp.
+
+commit 575d3feda1e5f308234432bb18617fb6ef037bac
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:24:04 2011 +0800
+
+ Add new GOT class.
+
+commit 0a9435c5a34fa5e74abeb73c60cbbec3ef645086
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:23:20 2011 +0800
+
+ Refine typo and style.
+
+commit 4bdffe67869f16f6372036c8ae54535811157f04
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:20:09 2011 +0800
+
+ 1. The relationship between relocation and relocation factory is fixed. (rarely chang in the future)
+ i. Relocation ask RelocationFactory to apply the relocation.
+ ii. Client only need to know Relocation::apply()
+ iii. Targets need to implement RelocationFactory::applyRelocation()
+
+commit a5391acadf5786272e6d5885529bf65a2db8b889
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:18:43 2011 +0800
+
+ add empty Layout::getFragmentOffset()
+
+commit 12e5edbd37939e9d918b10cc731025f238a5699d
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:17:00 2011 +0800
+
+ make LDSection more loosely-couple with MCSection.
+
+ Do not reuse llvm::SectionKind. Use LDFileFormat::Kind instead.
+
+commit 11f4c1e05468ba91fd7bcc8c61a895e88dc2d5d6
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 16:15:27 2011 +0800
+
+ add GOT kind in LDFileFormat
+
+commit 0fdcb434d63cfc402976e16ec238e0a74503d439
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Fri Dec 16 15:58:24 2011 +0800
+
+ Add ELF header write out function
+
+commit daa6fcf1a064d5fdaf3ee8c6c8115637caa57792
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 16 15:24:50 2011 +0800
+
+ Use angle brackets to include LLVM header files.
+
+commit e26a9a839e9d1fe68d799359494e3c13cd359074
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Fri Dec 16 15:01:15 2011 +0800
+
+ Refine error message. Replace tab by 2 spaces.
+
+commit 3c6be9b1a481fe3b281be441bc58996a54a21cf2
+Merge: 35634c1 3233a0d
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Fri Dec 16 14:54:34 2011 +0800
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 35634c1eb8228ae186d8df4a4fa2fc4edcdcba12
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Fri Dec 16 14:48:23 2011 +0800
+
+ Enhance MCLDFile and MemoryArea handling.
+
+ 1. Add property filesize for MCLDFile.
+ 2. Change MemoryArea.request for read-only and read-write.
+
+commit 3233a0deffb18a4db5a3945dc317d9fc60e77c61
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 16 14:50:11 2011 +0800
+
+ Fix the warning from getcwd.
+
+ Fix the warning:
+ ignoring return value of 'char* getcwd(char*, size_t)'.
+
+commit 669748343ec4ff2286c92b8f96a51de7918a03d7
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 16 09:08:38 2011 +0800
+
+ Use ResolveInfo type definition of symbols
+
+ 1. Use ResolveInfo type definition of symbols instead of llvm::ELF
+ 2. Clean spaces and tabs
+
+commit 07a1c8c177b86e719b0ca5478ecc818558d7b101
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 16 08:59:25 2011 +0800
+
+ Fix build failure.
+ Remove #include MCLDCommand.h.
+
+commit 1e1f1c85c1e4067eb838c6ea7a43eebd2c41f270
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 16 03:55:12 2011 +0800
+
+ Refine ResolveInfo.
+
+ 1. fix many bugs of access the description and type of the symbol
+ 2. change the function name from the original type() to desc()
+ 3. add new function type() as ELF_ST_TYPE
+ 4. add unit-test cases
+
+commit f3941aad56c54aead525cb0a71f546df3e42b85c
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 15 20:06:55 2011 +0800
+
+ remove obsolete code.
+
+commit 83c71bd31e8de366f55b6f1a00e7d946bbb1307c
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Thu Dec 15 23:15:57 2011 +0800
+
+ Move ARM GOT and PLT entries to ARMLDBackend.h.
+
+commit 9ef46fc7152eacdd251fde570b5c336158ce9273
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Thu Dec 15 18:16:55 2011 +0400
+
+ Define virtual function MipsGNULDBackend::machine().
+
+commit f313fbf40bb6bf0eed62cfc15c763d0631e25343
+Author: Jason Lin <sh.lin@mediatek.com>
+Date: Thu Dec 15 21:14:27 2011 +0800
+
+ Force implementation of TargetLDBackend provides machine information.
+
+commit 4e2fb98fa6878095a3fe6f64901a645872b5fd78
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 15 21:03:01 2011 +0800
+
+ Implement GOT and PLT entries for ARM.
+
+commit f99e9e47389a8134cf5aa553be645ff140c8c2e4
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 15 19:37:52 2011 +0800
+
+ Add some common testcases for static symbol resolutions.
+ Also add these testcases in the compilation list.
+
+commit 47373998b2fb96d571782d85dc38c5b7648d02d7
+Merge: 47dcf73 4f50b2b
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Thu Dec 15 14:16:24 2011 +0400
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 4f50b2bf6d025896efed3e90e9a5746f58c89376
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 15 17:58:35 2011 +0800
+
+ Fix bugs
+
+ The StaticResolver uses a table to drive resolution process.
+ The row and the column do not match to ResolveInfo::m_BitField.
+
+commit cda66ba64e9a763bab015ce23d0843e9459b3354
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 15 16:27:11 2011 +0800
+
+ Fix a bug
+
+ ResolveInfoFactory produces the ResolveInfo with wrong types and bindings.
+
+commit 929e39ebb0b8492d298f8e0e5d60ef9cd11520e0
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Dec 15 15:39:32 2011 +0800
+
+ For performance concern, WriteSameuint(8/16/32)_t takes uint32_t.
+
+commit 8c765870568f812c0e3d4ccc9fd6641230a1305b
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 15 14:45:35 2011 +0800
+
+ Fix the bugs in script builders
+
+ Because we change our building system from BOLD (the old project name) to
+ MCLinker (the new project name), so these scripts have to be changed consistently.
+
+commit de74f82f4f04db1af3ed9343dcdd9656a9356b18
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Dec 14 19:47:46 2011 +0400
+
+ Declare ObjectReader::readSections() as an abstract virtual function.
+
+commit caabf5794e85613a1e5938bcc8be4fffdbed94f4
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Dec 15 10:05:41 2011 +0800
+
+ Fix ScopedWriter boundary issue.
+
+ 1. m_Cursor+sizeof(TYPE) <= m_Region->size()
+ 2. Write16 should use uint16_t as argument
+
+commit bdfa73736e01bd02fad99ea54d9fe3112920af94
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Dec 15 10:06:46 2011 +0800
+
+ Add ELFDynObjWriter initial code.
+
+commit 47dcf7300d14a29a7f8270b0cf6e5c76888ea303
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Thu Dec 15 00:15:10 2011 +0400
+
+ Add stub classes to support mipsel target. The classes do nothing yet.
+
+commit 0a257babe6fa86cf8b459a79558bb0367969b41e
+Merge: 4a9b922 07ef497
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Dec 14 19:49:40 2011 +0400
+
+ Merge branch 'master' of https://code.google.com/p/mclinker
+
+commit 4a9b922f1de76dc5ffd1542438d65fc99fec26fa
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Dec 14 19:47:46 2011 +0400
+
+ Declare ObjectReader::readSections() as an abstract virtual function.
+
+commit 07ef4971433ed8a3af54b6b8fc5a20b79ae07552
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 23:27:08 2011 +0800
+
+ add symbol tables in LDContext.
+
+ MCLinker is still responsible for creating LDSymbols. LDContext is just a bookkeeper.
+
+commit 80ad6432f53cfa9d7626eb5504a92718484ad190
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 23:25:35 2011 +0800
+
+ Fix a bug in ResolveInfo
+
+ Bug: Previous patch did not change all TOUCH_OFFSET to PLT_OFFSET
+
+commit 2eb467e858ae0647db14c0bcbb560a9bb5452266
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 22:10:21 2011 +0800
+
+ Add ResolveInfo::hasPLT() and setHasPLT()
+
+ Which comes first? Applying relocations or creating GOT/PLT? This is
+ like checkens and eggs. Without applying relocation, we don't know
+ the number of entries of GOT and PLT. But without GOT and PLT's offset,
+ we can not fix symbol values and applying relocation.
+
+ In order to solve this problem, MCLinker separate the creating GOT/PLT process
+ into two different phases. The first phase is determining if the relocation
+ entry will produce a GOT and a PLT entry, then *create empty* GOT and
+ PLT whose sizes are precisely the same with the final sizes. The second phase
+ is applying the relocation entries, and simultaneously *fill* the GOT and PLT.
+
+ ResolveInfo::hasPLT() and setHasPLT() are functions for the relocation entry which
+ refer to the symbol. If a relocation entry needs to create an empty entry, than
+ the symbol is setHasPLT(true). And when applying the relocation, MCLinker looks
+ up the hasPLT(). If it's true, MCLinker will fill the value of the PLT entry and
+ GOT entry.
+
+ By this two-phase solution, we have no performance lost, and still keep
+ applying relocation and file layout simply.
+
+ Google gold scans relocation entries in file many times to deal with this problem.
+ But we know the scale of the number of relocation entries are huge, and it is
+ performance critical for on-device linking.
+
+commit e843b45c684995afce6ea830d6b4d1228ff64774
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Wed Dec 14 22:09:45 2011 +0800
+
+ Make two typedef(s) public.
+
+commit 6953fab92fef7c55bfb6e0ed83bef3ae16ecc231
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Dec 14 14:42:47 2011 +0400
+
+ Move MCAssembler::setWriter() function definition to the cpp file.
+
+commit eca5451b5d9c6be05977d0924d51a9c980a97bf5
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Dec 14 14:39:06 2011 +0400
+
+ Revert 1fce3a1a1361. The applied patch is obsoleted.
+
+commit 6f829659759631799aa7d5e86257a3c31920c2e0
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Wed Dec 14 20:16:06 2011 +0800
+
+ Initialize GNUArchiveReader in GNULDBackend.
+
+ We need to complete the right ArchiveReader/GNUArchiveReader ctors latter.
+
+commit 7f43c8e73fa01809f5ed56b1184d2aa9ae041300
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 18:08:13 2011 +0800
+
+ Fix a bug - MCLDDriver cat readers and writers before they are intialized.
+
+commit 1fce3a1a1361f690d7e7829267f635649417f7be
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 13 16:31:58 2011 +0400
+
+ The invocation of delete operator for an incomplete type has an undefined behaviour and g++ shows warning on this. To switch off this warning move MCAssembler::setWriter() function definition to the cpp file.
+
+commit 89cbcb97cbfbf280005aea53b94d829e1bbe6c41
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 13 16:09:15 2011 +0400
+
+ Put llvm libraries before the system's ones in the linker commad line. This fix linkage problem when g++ 4.6 is used to build MCLinker.
+
+commit 20403141692eb1174f0521c20c10e5791dbe94b7
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Tue Dec 13 16:08:46 2011 +0400
+
+ Finally fix wrong usage of typedef in MCFragmentRef::deref().
+
+commit 8eb2e5c8105f225941132c9fd51f1a9481cc2c7a
+Author: Simon Atanasyan <simon@atanasyan.com>
+Date: Wed Dec 14 12:16:49 2011 +0400
+
+ The autogen.sh do not use external env variable to get path to "m4" folder. It expects to see "m4" folder in the same directory where the autogen.sh is.
+
+commit 2b982d3654d208b912e834b33d1e7335905cf988
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 17:07:31 2011 +0800
+
+ MCLinker should pass MCLDInfo for readers.
+
+commit 101af4f0b07b9060cc84b7c79fa27a9760aa63cd
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 15:42:56 2011 +0800
+
+ Fix bugs in add_class
+
+ Because we change the building system and some environment parameters are
+ changed, we have to revise add_class script, too.
+
+commit cd088060939c4e1ac75146e21998f26c7e20f6ef
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Dec 14 15:38:26 2011 +0800
+
+ Delete redundant file lib/MC/TargetLDBackend.cpp
+
+commit 955c9893c9e9ff065684c7ae7508d92f40881acc
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 15:30:10 2011 +0800
+
+ class adapter ELFDynObjectReader connects DynObjectReader and ELFReader
+
+commit 986e95ae9f86b95f89b6728ccaca5932b6d957c2
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 15:11:47 2011 +0800
+
+ MCLDDriver checks the result of reading.
+
+commit ad575be2e90ba0bfed99e964c3fc4b460b9fee85
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 15:06:56 2011 +0800
+
+ Let MCLDDriver and MCLinker meet Readers.
+
+ Finish the basic algorithms in MCLDDriver::readSymbols() and mergeSymbolTable().
+
+commit c707ef3a9c538dfcf8263f46e9751cb35f0dce2f
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 14:51:30 2011 +0800
+
+ add DynObjReader::addSymbols interfaces.
+
+commit 92e38888082758b15784da09df2a2399abf1abfb
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 14:49:52 2011 +0800
+
+ Initialize ELFDynObjectReader, ELFDynObjWriter in GNULDBackend.
+
+commit 3742ac2e68cefaeb2c3e637943b34dc0f88d42cb
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 14:01:37 2011 +0800
+
+ Fix a bug in StaticResolver
+
+ Bug: Do not change the row in action_table when get in REFC.
+
+commit ce1f5f24f36cc7a2f9d1f274830dbbceff361e05
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 14 13:57:07 2011 +0800
+
+ Add the missing relocation function.
+
+commit ecc3f20182439be3b496abefb8e62acb64ec5b29
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 14 12:58:38 2011 +0800
+
+ Move relocation function declaration from .h/.cpp to ARMRelocationFunction.def.
+
+ We separate the code flow and the spec to simplify our code.
+ Once we want to implement a relocation function,
+ we need to
+ 1. Modify ARMRelocationFunction.def to add new function name
+ 2. Implement the function in ARMRelocationFactory.cpp
+
+commit 3491cccd6e2e67bd41e880cf7cb9ad1524cdfe62
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 13:53:40 2011 +0800
+
+ Remove author declaration in the header template.
+
+commit 47de2a6346aec8749344ba015f9418f838e1b562
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 13:50:33 2011 +0800
+
+ Add StaticResolver in the compilation list.
+
+commit 4b1a6ad75d0d903b1d8f928b6ac4d35d61e089d1
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 13:49:55 2011 +0800
+
+ MCLinker should have StrSymPool for symbol resolution.
+
+commit 06ef7dc8abfa28cb0efc9e8e818e4a50797ac95e
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 13:46:30 2011 +0800
+
+ 1. Fix bugs in StaticResolver.
+
+ 2. Let Resolver as a clone factory.
+
+ 3.In old ResolveInfo, set functions use ResolveInfo defined enum types as the
+ parameters. For higher performance, change those parameters to uint32_t.
+
+commit 8be180a7c49ff0219886034b32489c3deb2368cc
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 14 13:30:00 2011 +0800
+
+ Use the University of Illinois Open Source License for new files.
+
+commit 8b7e10a93a8accabc74838f64eb2b15dd87bd66e
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Wed Dec 14 13:25:20 2011 +0800
+
+ Fix typo for ScopedWriter.
+
+ Use pRegion to initialize m_Buffer instead of m_Region.
+
+commit 3c51db281e5d65fa31f87279175b0844a15cfd6b
+Author: Anders Cheng <anders.cheng@mediatek.com>
+Date: Wed Dec 14 10:49:26 2011 +0800
+
+ Support Android SectLinker.
+
+commit aa2fe236bc089cb6cd6f02537f8f91f2f56f8e9d
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 11:39:13 2011 +0800
+
+ ResolveInfo::setVisibility should always choose the most strict visibility.
+
+commit b8592f5a219be3cdd9601171091b64a7fabc3765
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 14 11:31:14 2011 +0800
+
+ Use the University of Illinois Open Source License.
+
+commit 221faed40cd9054ebd522f52f3b77e07a8bbb459
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 03:03:37 2011 +0800
+
+ Add ScopedWriter.
+
+ ScopedWriter writes the region and synchronize the region with file at
+ its destructor.
+
+commit 8eb8bcbd158b129d17ad540b0c93327cb184c595
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 02:59:39 2011 +0800
+
+ Finish the static resolver.
+
+ The kernel of symbol resolution - StaticResolver.
+ It can resolve not only the regular symbols, but also indirect symbols.
+ MachO's indirect symbol can directly use the same StaticResolver.
+
+commit 48284527c99bfed258c14ade91402cf178ddd413
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 02:58:43 2011 +0800
+
+ Remove the code in readSymbols(). They can not pass compilation.
+
+commit b460c21691d237d9313028c0f99a3215e6e19a6e
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 02:57:32 2011 +0800
+
+ Symbol resolution changes the original symbol, so Resolver::resolve()
+ must use reference to ResolveInfo instead of constant reference.
+
+commit 3b2c5349998bb780a00ff31e901738c938474a12
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 02:54:45 2011 +0800
+
+ 1. move size and value fields from LDSymbol to ResolveInfo
+ 2. Because indirect symbol use value field as the link to the other
+ ResolveInfo, change the interface of ResolveInfo.
+
+commit 938968f24c9397f1742726527adad32886604c77
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 02:53:28 2011 +0800
+
+ Fix some missing headers in Layout
+
+commit 65f5588158b5d2b5c26e33b5977d1806c440d10f
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 14 10:59:02 2011 +0800
+
+ Fix building system.
+
+ Fix the build failure when building MCLinker in separate building directory.
+
+commit b661426ec46d6bd6f17a5b83520a225bb370efae
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 10:18:34 2011 +0800
+
+ We are currently the external project of LLVM.
+ So, use include `<' `>' instead of `"' `"'
+
+commit 798f14f04306c2d16d015436a9d338f4ea792f0e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Dec 14 10:17:42 2011 +0800
+
+ Add files generated by autogen.sh to .gitignore.
+ Based on a patch by Simon Atanasyan.
+
+commit 0b5b26087708fa0934def8ecff234c581f1510b0
+Author: luba <lubatang@gmail.com>
+Date: Wed Dec 14 10:13:20 2011 +0800
+
+ Change the building system.
+
+ Move the placehold of object files from tools/llvm-mcld to debug and optimized.
+ Change script/envsetup.sh to export environment ${MCLINKERTOP}
+
+commit fe83d4c55fbbfdef3525fca64fc83ae81b78b946
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Wed Dec 14 09:22:38 2011 +0800
+
+ [Patch] llvm::StringRef cannot operator+.
+
+ Use std::string instead.
+
+commit fde52a66fcc382e23bd81a467d192e87b6ddb336
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Tue Dec 13 22:24:07 2011 +0800
+
+ Oops! Method overriding becomes hiding.
+
+ Fix the signature of BSDArchiveReader::isMyFormat().
+
+commit 22a773fb7237dba0200acae47700aca94612269c
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Tue Dec 13 22:20:11 2011 +0800
+
+ Add remaining relocation applying functions.
+
+ In order to meet our 1st milestone, I write the
+ scaffolding of applying functions which can seen
+ in LLVM lib/MC/ELFObjectWriter.cpp.
+
+ There are still some functions not mentioned, and
+ they will be invoked with ARMRelocationFactory::none().
+
+commit f819b7bb2afbede7caa8cda9b7d958f29b6d7c58
+Author: pete <petechou@gmail.com>
+Date: Tue Dec 13 21:15:44 2011 +0800
+
+ Revise the file headers.
+
+commit 1d1e70b22424aba665f58ae9b9b0fb42dd1e5a1d
+Author: Nowar Gu <wenhan.gu@gmail.com>
+Date: Tue Dec 13 20:46:05 2011 +0800
+
+ Add return enum of ARM relocation status;
+
+ Every private relocation function to be applied
+ should return the value of enum ARM_Reloc_Status.
+
+commit 7e33978829dbee73c47af915c3be34b85653abf9
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Dec 13 20:35:30 2011 +0800
+
+ Include llvm/Support/ELF.h as symbol type definition
+
+ Clean space
+
+commit 753dc5889cc09e10fe641c8746edbb6e5664d233
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Tue Dec 13 16:55:18 2011 +0800
+
+ Relocation and RelocationFactory
+
+ 1. Remove destroy() in ARM and X86 RelcoatoinFactory
+ 2. Add APIs to RelocatioFactory
+ 3. Add a few applying functions to ARMRelocatoinFactory
+
+commit 2f3f17784da3c591d7b8a642597539197ffd5878
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 13 16:54:50 2011 +0800
+
+ The development of MCLinker migrates to code.google.com .
+
+commit 5ca1aba0f951f00bcd957c859e0fe55ad2b36c56
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 13 16:25:56 2011 +0800
+
+ Use the University of Illinois Open Source License.
+
+commit c38947f7a889eaeef517a07e057fe2ecfdbab643
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 13 16:19:45 2011 +0800
+
+ Remove redundant "#include <iostream>".
+
+commit 2c3b6bdd90ba5202fcd65c1f90bc24fac340b16b
+Author: pete <petechou@gmail.com>
+Date: Tue Dec 13 14:12:54 2011 +0800
+
+ Fix build break.
+
+commit cd145bcdf7178b4a91a30ebc90579b26787156ff
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 12 21:35:28 2011 +0800
+
+ Layout laid out the sections and fragments
+
+commit 4652987bb676a4e04db7716515a8c414ee3933ef
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 12 21:33:47 2011 +0800
+
+ LDFileFormat describes the common object files.
+
+commit d32477944af36fa03689d0d3762d3c55b361ee84
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 12 14:57:40 2011 +0800
+
+ Fix a bug - set the wrong type of mcld::Input
+
+commit 95586130a0ae4afee1a8b9c2aa41ded57489df75
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Dec 13 15:44:00 2011 +0800
+
+ Merging mainline.
+
+commit 2bf6851902b2f2df82a6abe6eb26b434af43014d
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 11 01:08:51 2011 +0800
+
+ Fix wrong usage of typedef in MCFragmentRef::deref
+
+ Thanks Simon. By his suggestion, I correct the wrong declaration of deref().
+
+commit 70234d9a318e40bc63d60e59d4ee33f63739bbb5
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 11 00:56:14 2011 +0800
+
+ Set new TODO - implement SectionMap and SegmentMap
+
+commit 11b3bd488bad5ea822d5bef55a76ed38c6204a8b
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 11 00:52:10 2011 +0800
+
+ Add LDSection in compilation list.
+
+commit 6c4c3e5c73e752f651a230f0ace48e702081f8a5
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 11 00:40:43 2011 +0800
+
+ LDSection should be a kind of MCSection.
+
+ LDSection has name, type, flags and offset of a section.
+
+ MCLinker reuses llvm::MCSectionData. llvm::MCSectionData only contains
+ partial information of a section, such as real data size and alignment
+ constraint. We complement the rest information by put them in LDSection.
+
+ LDSection is designed for both ELF and MachO. We do not consider about
+ WinPE when we designed it. So, WinPE may not use it.
+
+commit eeb2e9754dc7e301bf66cb1c4a752155eeb3c589
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Sun Dec 11 00:34:54 2011 +0800
+
+ Update patch/LLVM.patch and patch/README.
+ We use LLVM RELEASE_30@145348 now.
+
+ Checkout it by
+ "svn co -r 145348 http://llvm.org/svn/llvm-project/llvm/tags/RELEASE_30/final llvm_30"
+
+commit 3f8342044be5e63e45922943bfb93dc949ec5486
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 10 22:11:36 2011 +0800
+
+ Every debt has it debtor :p
+
+commit 5778cd114cd07e3e1433dac5bdc1afab4d9d3e76
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 10 21:59:07 2011 +0800
+
+ Add 'prepare LLVM' sections in the README
+
+commit 0078964a9df503c358ef5fa2eb23f71cdd50631a
+Author: luba <lubatang@gmail.com>
+Date: Sat Dec 10 21:44:18 2011 +0800
+
+ Add MCSection::SectionVariant a new variety - LD_Context
+
+ Since MCLinker uses LDSection as a common representation of section headers,
+ we need a new variety of section.
+
+commit 3098c5a0851e99fde77f5f2376165ffe42ccf5c9
+Author: pete <petechou@gmail.com>
+Date: Fri Dec 9 14:18:28 2011 +0800
+
+ Add missing MCLinker header in MCLDDriver.
+
+commit eda322c15b5dfd36430be4f7eea70e687aebd71d
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 9 13:47:09 2011 +0800
+
+ Initialize MCLinker
+
+ In MCLDDriver::initMCLinker, MCLinker and all readers and writers are
+ initialized.
+
+ TODO:
+ In the same function MCLDDriver::initMCLinker(), MCLinker should initalize
+ all internal data structures, such as segments, sections, and symbol tables.
+
+commit 22f0fad5630050abf970850bf4ec66d50250daa7
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 8 22:56:35 2011 +0800
+
+ Fix bug - hasContext return opposite value.
+
+ By Simon patch/LLVM.patch
+
+commit 5e56d91d52fceb8cdc7f9ea813cd272c1b710abd
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 8 22:02:06 2011 +0800
+
+ Fix a bug - hasMemArea return opposite value.
+
+ By Simon Atanasyan's patch.
+
+commit 45d47f655e8ffd71e6a7cf42c1ba913f51ce8b87
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 8 21:41:39 2011 +0800
+
+ Add general apply function interface into RelocationFactory
+
+ Remove function pointer in Relocation.
+
+commit b7c194ca85a7f7b8af18173c68bae40e72ffce14
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 8 20:58:09 2011 +0800
+
+ Change type of apply function pointer to pmf
+
+ Apply functions in RelocationFactory should be non-static.
+ Use pmf on Relocation to hold the pointer.
+
+commit 7dc044b48c2ca4a67a76d3d82fef554963225935
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Thu Dec 8 16:39:09 2011 +0800
+
+ Add Relocation and RelocationFactory prototypes
+
+ Remove ARMRelocation and X86Relocation.
+ Define RelocationFactory and apply function prototypes.
+
+commit a2de45a96b5f661b273fc4db2540c22ebd6373e4
+Author: pete <petechou@gmail.com>
+Date: Thu Dec 8 15:00:17 2011 +0800
+
+ Remove mcld::StringMap, its testcase, and related code.
+
+commit ffdc2452a71e8389f2f3d267f54ada53d5029839
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 8 13:34:45 2011 +0800
+
+ Add new MCFragment types FT_GOT and FT_PLT to LLVM 3.0.
+
+commit 633842441e9bc64d69e682070f85ead306ce6749
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 8 10:34:01 2011 +0800
+
+ Add some basic functions in MCLDDriver.
+
+ Because in these early version, algorithms are simple. So I directly write the functions in SectLinker.
+
+commit 9f7c4e27d314bd58bb363335272deaf885732b9a
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 8 03:15:07 2011 +0800
+
+ Add some ARM target backend scaffoldings
+
+ - Relocation Factory
+ - Relocation
+ - Backend
+
+commit 814dd5ead01058162c85017e0fbefdf323b44671
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 8 01:33:32 2011 +0800
+
+ Add some target callback functions for overriding.
+
+commit ec519d96ead369d48c6329c82c8d1b9d4f2f57b9
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 8 01:29:38 2011 +0800
+
+ Add GOT scaffolding
+
+commit dcd1bab5fa09334ad21a8f8e68fb258b483728a4
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 8 01:15:54 2011 +0800
+
+ Add scaffolding of PLT
+
+commit 26b0df4f58214c5769a3b947c93d3ba3f5e87381
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 5 21:23:36 2011 +0800
+
+ Add RelocationFactory interface
+ Add RelocationFactory into Makefile.am
+
+commit 58ad32a8084e64769da2ad871f7ed59cc0061105
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 5 21:21:04 2011 +0800
+
+ Change relocations type to std::vector
+
+commit b68dcea42a93b93f2de690a36352040ae095f7de
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Mon Dec 5 21:19:19 2011 +0800
+
+ Add resolveInfo() into LDSymbol
+
+commit 8ed0f131cbdc717057ebe3fab16bb8c73987148c
+Author: pete <petechou@gmail.com>
+Date: Mon Dec 5 16:25:48 2011 +0800
+
+ Rewrite PathCache of Directory to use mcld::HashTable instead.
+
+commit c222b70e1e6eb7789368002cc5cd850a5db0ac09
+Author: luba <lubatang@gmail.com>
+Date: Mon Dec 5 00:57:49 2011 +0800
+
+ Finish StrSymPool, and define Resolver's API.
+
+ Let resolver has more control for symbol resolution.
+
+ Resolver now can be inherited by static resolver for static linker or by
+ dynamic resolver for dynamic linker.
+
+commit 35dd88a5fdb9b69b65c7d008047cccf36b990593
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 4 14:17:31 2011 +0800
+
+ Change include file - stdint.h to llvm/Support/DataTypes.h
+
+commit 5731c3e1afdb7ec4ee66493ae0b0d5a673c349e2
+Author: luba <lubatang@gmail.com>
+Date: Sun Dec 4 14:17:00 2011 +0800
+
+ Add BranchIsland and Stub
+
+ Not implement yet.
+
+commit 7f3fae69146dc3c05c43a791eead40e70e8eab37
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 2 18:13:31 2011 +0800
+
+ Relocation inherit to ilist_node
+
+commit 87b30c7ec68593f8688426d402303dd8c3c2413d
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 17:44:10 2011 +0800
+
+ Add TargetLDBackend::applyRelocation interface
+
+commit a472c0a9362ec080a26bd8ae04299ccea88f21c5
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 16:39:20 2011 +0800
+
+ Add empty class of Group and Layout
+
+ Group and Layout are two classes used to finalize the layout of regions.
+
+commit 5a546a1459f16d061bc17bd589e7644d88dd5fed
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 16:31:56 2011 +0800
+
+ Add Howto and Relocation into make list
+
+commit c2ebf70bccf6cc890f060e0445029d18b0e01260
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 16:31:12 2011 +0800
+
+ Add Howto
+
+ add Howto as the common information of relocation entries
+
+commit 70dfc86d8dbdf25d7e03b2b05cd7173e6dad1670
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 16:27:39 2011 +0800
+
+ Add MCBitcodeInterceptor
+
+ MCBitcodeInterceptor intercepts data in MCAssembler.
+
+commit f9d450da825e76b8dd2f780a0c334ad3159158b4
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 2 16:18:05 2011 +0800
+
+ Build MCLinker with options which are used in Android.
+
+commit 1c1577cfc9e38edd1964344c39feae7e95575c0e
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 16:08:04 2011 +0800
+
+ Change MCAsmObjectReader to MCBitcodeInterceptor
+
+commit ef7de030bd3381a770ac493e1feb1265d15874d0
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Dec 2 15:46:27 2011 +0800
+
+ Fix build failure when building MCLinker without "--enable-unittest".
+
+commit 19e2d77416d84552f9316b43c7b9cbac7ccdf31e
+Author: pete <petechou@gmail.com>
+Date: Fri Dec 2 15:08:29 2011 +0800
+
+ HashTable
+
+ 1. refine the interface of const interator
+ 2. refine begin iterator (advance if needed)
+ 3. refine the interface of string hash and compare functions
+ 4. enable the unittest of hash table
+
+commit 7ce917c0ec2426096a4bdbe24c8e4e58a696994c
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 14:55:49 2011 +0800
+
+ Remove obsolete code
+
+commit 4bc81fb85bca2b06f4db472532079e0e903a84b4
+Author: luba <lubatang@gmail.com>
+Date: Fri Dec 2 14:46:39 2011 +0800
+
+ remove obsolete codes
+
+commit 63cb8f09d0b36b03eded8a4b097a9109e16f1128
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 2 09:03:51 2011 +0800
+
+ Change type LDRelocation to Relocation
+
+commit 0cebccd14965f785536742b9b7b6a1fce5b17c5c
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Fri Dec 2 08:46:47 2011 +0800
+
+ Remove including file LDRelocation.h from lib/MC/MCAsmObjectReader.cpp
+
+commit 4cac453872b143007c18bea5d55b688866fc2d5b
+Author: ras46 <Robert.Lai@mediatek.com>
+Date: Thu Dec 1 16:36:14 2011 +0800
+
+ STLport needs std::less const version.
+
+commit 814c017983096d3e67df561c18657804fc0371bf
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Dec 1 14:36:59 2011 +0800
+
+ Use ${TOPLEVEL} instead of ".." in Makefile.am.
+
+commit 49814ae1bb6bd86ced88a5edd76ef0def5b8b592
+Author: luba <lubatang@gmail.com>
+Date: Thu Dec 1 14:11:53 2011 +0800
+
+ 1. rename LDRelocation as Relocation
+ 2. change the interface of RelocationFactory
+ 3. refine the API of Relocation.
+
+commit 36dd5efc9e85f180d0636269724099044407f7a4
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Nov 30 21:22:06 2011 +0800
+
+ Fix bug where MCLinker generates empty object files.
+
+commit 12825372ce875ccc72d30bfd4e2f17f3c49d5c31
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Nov 30 18:02:24 2011 +0800
+
+ Add MCDataFragment and MCInstFragment
+
+commit 1b9339ebb1a1baff100c1a82e7af7b05ade4b718
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Nov 30 11:08:21 2011 +0800
+
+ Remove symbols related definition in LDContext
+
+commit 9421ba3955ee189ae9b3b437d10f11b2f2e5a978
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Nov 30 10:29:05 2011 +0800
+
+ Add LDRelocation, LDHowto and LDRelocationFactory
+
+ 1. Remove Relocation.h
+ 2. Change relocation type from Relocation to LDRelocation
+ 3. Remove relocations in LDContext and MCAsmObjectReader
+
+commit 9d385e3683813e24a95731a1dbf0675b15a92dfb
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Nov 30 01:07:02 2011 +0800
+
+ Add an option of golden model linker.
+
+commit aeae012cc95521b03abf812122174564612195d9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 29 16:23:28 2011 +0800
+
+ Move MC/MCLDContext to LD/LDContext.
+
+commit 98975a1aacdd77893a1702cc982ebacbb2e660d4
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 29 15:52:07 2011 +0800
+
+ Revert some changes for building MCLinker with LLVM r142614
+
+commit b0956e0091993c6de228683041e24254c9d21891
+Author: luba <lubatang@gmail.com>
+Date: Tue Nov 29 15:27:11 2011 +0800
+
+ Add StrSymPool
+
+ Use HashTable and ResolveInfo to remember the shared attributes of all symbols.
+
+commit 75c7eefe67b8069c18b5f18db06219a690e9dd7f
+Author: pete <petechou@gmail.com>
+Date: Tue Nov 29 13:52:35 2011 +0800
+
+ LDSymbol: add one missing open brace.
+
+commit 213d67b1693804bc216bef43b7b772cd5f754b94
+Author: luba <lubatang@gmail.com>
+Date: Tue Nov 29 11:51:38 2011 +0800
+
+ Add assert()s in LDSymbol and LDSymbol::setValue()
+
+commit 82732c2a798c034290ea297cbec9e7268ce546da
+Author: luba <lubatang@gmail.com>
+Date: Tue Nov 29 11:43:10 2011 +0800
+
+ Revise ResolveInfo for adapting HashEntry
+
+ add bool compare(llvm::StringRef) and typedef llvm::StringRef key_type
+
+commit d34cdfd3a63cf0afe42d99aa6e0c7dc278bb8b5f
+Author: luba <lubatang@gmail.com>
+Date: Tue Nov 29 10:40:05 2011 +0800
+
+ Remove LDSymbolFactory
+
+commit 419a180a9b65280f0840bd2b56dc9366902c2a6c
+Author: luba <lubatang@gmail.com>
+Date: Tue Nov 29 10:33:21 2011 +0800
+
+ Accommodate new options - -Werror=format-security -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point
+
+commit 75ba993bf689a6c4037539c6a8e0669174bab800
+Author: pete <petechou@gmail.com>
+Date: Tue Nov 29 10:15:04 2011 +0800
+
+ Fix build break.
+
+ 1. add key() api in ResolveInfo
+ 2. modify the makefile
+
+commit 9b8ee64fff298d1d2b05840ce07e0f7c77967161
+Author: luba <lubatang@gmail.com>
+Date: Tue Nov 29 10:11:02 2011 +0800
+
+ Implement MCFragmentRef::assign
+
+commit 3f89a717f38267887cc8ddc10ae1eaf9806ac43d
+Author: luba <lubatang@gmail.com>
+Date: Tue Nov 29 09:49:09 2011 +0800
+
+ Fix typo-error and add some missing header files in LDSymbol
+
+commit af12e0bade43dba059253bdd0977302e9b553669
+Author: pete <petechou@gmail.com>
+Date: Mon Nov 28 21:11:23 2011 +0800
+
+ ResolveInfo implementation and some refinements.
+
+commit 2c585300f58b247a7b4a96ec45196a32f69d4723
+Author: luba <lubatang@gmail.com>
+Date: Mon Nov 28 18:28:40 2011 +0800
+
+ Separate ResolveInfo from LDSymbol
+
+commit bae8cdff60052729d2e7d2d3516cc9776e20bde1
+Author: luba <lubatang@gmail.com>
+Date: Mon Nov 28 17:39:05 2011 +0800
+
+ Follow ResolveInfo, change the RESOLVE_OFFSET to NAME_LENGTH_OFFSET
+
+commit a75d0db412a3ecbf087633e10bcf5bc2b2023d2c
+Author: luba <lubatang@gmail.com>
+Date: Mon Nov 28 17:33:30 2011 +0800
+
+ Add ResolveInfoFactory
+
+ ResolveInfo is a dynamic class whose size is various at run-time.
+ ResolveInfoFactory creates ResolveInfo and make sure such kind of dynamic
+ class is only created in dynamic storage.
+
+commit 518bcd6fa243481d19fd94315cddfaa5833f4d69
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Nov 28 16:46:15 2011 +0800
+
+ Add new MCFragment type FT_Region.
+
+commit 2386bc39771d8d5a3c252f7b5d3fae9e52e96984
+Author: luba <lubatang@gmail.com>
+Date: Mon Nov 28 16:15:17 2011 +0800
+
+ Add ResolveInfo
+
+ ResolveInfo is a common storage for all resolved symbols. It records all
+ information that used during symbol resolution, such as binding, type,
+ isDyn and so on.
+
+commit b49abdefd70309d2c311758dbc916256fc2fd8ec
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Nov 28 14:37:05 2011 +0800
+
+ Remove non-existent files from debug/Makefile.am
+
+commit c37d8a4e32a6177ce38e8af7bff7614d651cc3bd
+Author: luba <lubatang@gmail.com>
+Date: Mon Nov 28 14:18:48 2011 +0800
+
+ Add SizeTraits
+
+ SizeTraits is responsible for defining the numeral system.
+
+commit f88646c19970e5d1839b8d41cd2aabab387cda8b
+Author: luba <lubatang@gmail.com>
+Date: Sun Nov 27 21:53:59 2011 +0800
+
+ Add MCFragmentRef
+
+ MCFragmentRef is a reference to *MCFragments.
+ BTW, in order to compatible to MCInstFragment and MCDataFragment, change FileSystem::Address from unsigned char* to char*.
+
+commit ef4b44d4caa503d5722f253fe92a99ec3b9eafc3
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 24 22:57:48 2011 +0800
+
+ Remove PZString and finish LDSymbols
+
+ Because PZString is impossible to be other classes' member variable, and
+ it is error-prone, remove it.
+
+ Instead, direct add the strings into LDSymbol.
+
+ LDSymbol make sure string and symbol is high-possibly in the same cache line.
+
+commit 40f67efb61335d70e18780303b8a24e2612d09ce
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Nov 24 19:32:25 2011 +0800
+
+ Add a -soname=name option to store soname in class Output
+
+commit 293c6a2da51ffc7d630fa6af5d642ca0a76eaac6
+Author: pete <petechou@gmail.com>
+Date: Thu Nov 24 18:45:02 2011 +0800
+
+ Refine the erase code.
+
+commit 5847a955218fdf4fcb6d1a30770d8d71ce78de4b
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 24 13:44:46 2011 +0800
+
+ add PZString::at() prototypes.
+
+commit 802b1e082c84c9b355be5aa18a3653b86865b4a8
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 24 13:41:07 2011 +0800
+
+ Add PZStringFactory::create functions
+
+ PZStringFactory is responsible for creating and destroy PZString.
+ Since PZString only can exist in heap, it should not be created by normal
+ user code.
+
+commit c3b40a09c7ad181d9dd9af19c50a0c70a8f743da
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 24 11:40:05 2011 +0800
+
+ Add the scaffolding of PZString and PZStringFactory.
+
+ PZString is a Pascal string with zero terminal.
+ Because PZString is a kind of class whose size is various, it's only
+ can be put in dynamic storage. Therefore, it can not use normal allocator.
+
+commit 8c514c26e73af68e96b989b3cf7e23261753003c
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Nov 24 11:12:59 2011 +0800
+
+ Set file mode bits to most common value "755" and "544".
+
+commit cb0eb5d71785a2cd78a022118ffb7f24aa001e62
+Author: pete <petechou@gmail.com>
+Date: Wed Nov 23 20:33:52 2011 +0800
+
+ 1. fine tune the probing performance
+ 2. fix the bug as erasing
+ 3. write testcases for "erase", "clear", and "tombstone"
+
+commit 30abb8e1bc78819ee34b6ecf222059693456d4e7
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Nov 15 16:59:43 2011 +0800
+
+ Remove testing example.
+
+commit 5cf25e3524bcde04874b3782b266125d0ba7030d
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Nov 15 16:54:20 2011 +0800
+
+ Check llvm 3.0.
+
+commit 9819f43d7ca925f581cdcdffcd22e9a37bb6ec0c
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Nov 15 16:53:30 2011 +0800
+
+ Remove lit, we use llvm's lit
+
+commit a251244f111fcf4c80d0682557edc5c36c6e7616
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Nov 15 15:37:02 2011 +0800
+
+ Use Makefile.am. Use llvm build dir for test tool.
+
+ Now can use some llvm tool such as FileCheck.
+
+commit 9a761813eaacc6354d09be74498c992950aa7b19
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 15 14:35:57 2011 +0800
+
+ Changes to fit LLVM Release 3.0
+
+ 1. generate the diff for llvm 3.0 based on r142614
+
+ 2. made the corresponding changes about TargetRegistry and TargetSelect
+
+ commit 3e74d6fdd248e20a280f1dff3da9a6c689c2c4c3
+ Author: Evan Cheng <evan.cheng@apple.com>
+ Date: Wed Aug 24 18:08:43 2011 +0000
+
+ Move TargetRegistry and TargetSelect from Target to Support where they belong.
+ These are strictly utilities for registering targets and components.
+
+ git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@138450 91177308-0d34-0410-b5e6-96231b3b80d8
+
+ 3. remove the code for llvm 2.9
+
+commit 61cdc16ec58247719ec881816dc001cd559c31a4
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 10 23:21:37 2011 +0800
+
+ write comments in HashTable::rehash()s
+
+commit e530bb829207fcf285aa37ec703c19c61e8f4d32
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 10 22:57:39 2011 +0800
+
+ Add MCRegionFragment
+
+ MCRegionFragment is a kind of MCFragment which is used to represent the
+ section data when reading a object/DSO file.
+
+commit 70ef2cf40a845ac10617405d57df3db7e0eba70f
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 10 14:30:56 2011 +0800
+
+ Add a some testcases for hash table.
+
+ 1. a pressure test to insert 4000000 elements
+ 2. test case for traversing chains of the hash table
+
+commit 8dae4b66bbb8ba019a8c24f5a8ef08c3cac03e6a
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 10 14:24:06 2011 +0800
+
+ 1. Change the HashTable from quadratic probing to linear probing.
+ 2. Fix bugs in ChainIteratorBase
+
+ At first, we follow llvm, use quadratic probing. However, in llvm, the quadratic function is not real quadratic, it's a triangle function - K(K+1)/2. Some number of buckets, even when the load factor is under the threshold, can not be probed by given triangle function. This will cause a infinite loop in HashBase::lookUpBucketFor. In order to avoid the problem, I change the hash table to linear probing.
+
+ ChainIteratorBase::advance behave wrong. It returned when meeting a empty bucket. It should ignore empty bucket.
+
+commit 2e0a251e8e87a30125c27e45ce3b39dd1ae17e2a
+Author: luba <lubatang@gmail.com>
+Date: Wed Nov 9 14:56:03 2011 +0800
+
+ Fix bugs in HashTable
+
+ Thanks for TDY, we resolve the bug - use the bucket reference that is deleted after rehash
+
+commit 28569f6e455c2d0a9fe077e912842d2d4c81227e
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Nov 9 14:30:34 2011 +0800
+
+ Cleanup tests which cannot pass.
+
+commit bfda46018175dfe691451382e2d0be17d396edfa
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Nov 9 11:15:46 2011 +0800
+
+ Let tests can use llvm-tools.
+
+commit f77630965e5ae8db82fa83db1080cd122166f702
+Author: luba <lubatang@gmail.com>
+Date: Wed Nov 9 06:34:04 2011 +0800
+
+ fix a bug in HashTable::load_factor()
+
+ HashTable::load_factor() has typo error. Since it's a template class, typo-error is not easy to be found.
+
+commit 7da98b64d1d0781870abda659a295be3abfa40bc
+Author: luba <lubatang@gmail.com>
+Date: Wed Nov 9 06:09:56 2011 +0800
+
+ Add a new testcase - alloc100 - for HashTable
+
+ alloc100 sequentically inserts 100 elements into the HashTable
+
+commit 4f461a3a2147e20a363609ffa73738f567a11fb1
+Author: luba <lubatang@gmail.com>
+Date: Wed Nov 9 05:56:13 2011 +0800
+
+ Refactoring HashTable
+
+ 1. make HashTable is no longer limited to llvm::StringRef key type.
+
+ HashTable get the type of key and value from HashEntry.
+ HashEntry::key_type and HashEntry::value_type. HashTable does not assume the key type is based on string. Moreover, the hash function is also not limited to the string hash.
+
+ 2. move the construction of HashEntry outside from the HashTable.
+
+ Clients must pass the factory of HashEntry as a template argument into the HashTable. That is,
+
+ HashTable<..., EntryFactory>
+
+ The memory can control by the factory. HashTable no longer takes care of it.
+
+commit 5a5694a55753d0a6e68bae33072c578a4b4697ec
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Nov 8 16:27:33 2011 +0800
+
+ Move regtests into test/ subdir.
+
+ Since MCLinker is not done yet.
+ `make check' will get 4 errors. That is okay.
+
+commit ad0e76dcaa623db67ff9eb58667b7249a8a10d13
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 3 02:54:41 2011 +0800
+
+ Unit test of mcld::HashTable
+
+ Only few cases are tested. Please contribute more cases.
+
+commit 3f09d3c77917baebee346283caf64665f6f74f68
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 3 02:51:38 2011 +0800
+
+ A HashTable whose hash function is changable
+
+ Since the hash function in linkers can be changed in GNU ld, MCLinker should
+ provide such feature to change the hash table. mcld::HashTable is the implementation.
+
+ Features:
+ - Can change hash table
+ - User defined hash entry - Symbol table uses this feature to keep string and symbol in the same cache line.
+ - Quadratic probing, open addressing hash table.
+
+commit 975c757ce17eb83f2e7357e78554b59f94963b85
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Nov 2 19:07:08 2011 +0800
+
+ Add llvm-lit for testing.
+
+ We use lit(LLVM Integrated Tester) for MCLinker testing.
+ Add basic config and some simple tests.
+
+commit 1f9a62dfdc1907be35278f767bfa466f67153887
+Author: luba <lubatang@gmail.com>
+Date: Mon Oct 31 08:19:39 2011 +0800
+
+ Add MallocAllocator
+
+ LLVM has provided a llvm::MallocAllocator, but it is a 'plain' allocator.
+ That is, llvm::MallocAllocator returns a raw byte string and users need to
+ cast the raw byte string on a new type by itself. Additionally,
+ llvm::MallocAllocator does not follow the API defined in C++ standard.
+ So, I decide to give them a new MallocaAllocator.
+
+commit 83c8f2bd7b417cee2f095ef28d2bf08bbbda82c3
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Sun Oct 23 20:56:04 2011 +0800
+
+ Force RegionWriter to be used only through auto variables
+
+commit 7ecaef28263a26caf73f49d6c624aefbeaeff3a5
+Author: pete <petechou@gmail.com>
+Date: Mon Nov 28 09:51:08 2011 +0800
+
+ HashTable
+ 1. fine tune the probing performance
+ 2. refine the erasing code
+ 3. write testcases for "erase", "clear", and "tombstone"
+
+commit 5cbc4f2546d046ec50e5930f7e6da4ae99201d32
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Nov 16 11:06:21 2011 +0800
+
+ Add comments
+
+commit f783a732c31e44744863d60b0bf86c196320ebe1
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 15 11:37:01 2011 +0800
+
+ Add missing '<'
+
+commit 49c8beabfacfdef9171a24e038a1bb0e243c628f
+Author: luba <lubatang@gmail.com>
+Date: Thu Nov 10 23:21:37 2011 +0800
+
+ write comments in HashTable::rehash()s
+
+commit 1b3c38cd68808aa6ab9a4ac96d4e698105e6dc86
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 13:16:50 2011 +0800
+
+ Add testcase to make sure two MCRegionFragment::classof()s are correct.
+
+commit f95de000888b22fb7af57d2053b53dd239f9ec16
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 13:11:36 2011 +0800
+
+ Add MCRegionFragment
+
+ MCRegionFragment is a kind of MCFragment which is used to represent the
+ section data when reading a object/DSO file.
+
+commit b87c95aa31d90e7bec8834f715462a2a9cc5d0ca
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 13:00:16 2011 +0800
+
+ Add a some testcases for hash table.
+
+ 1. a pressure test to insert 4000000 elements
+ 2. test case for traversing chains of the hash table
+
+commit 14cc34ee4583e807b0dd606c0ef0c68571bece14
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 12:59:20 2011 +0800
+
+ 1. Change the HashTable from quadratic probing to linear probing.
+ 2. Fix bugs in ChainIteratorBase
+
+ At first, we follow llvm, use quadratic probing. However, in llvm, the quadratic function is not real quadratic, it's a triangle function - K(K+1)/
+
+ ChainIteratorBase::advance behave wrong. It returned when meeting a empty bucket. It should ignore empty bucket.
+
+commit 6307571e18535b25ee1b63987705762e056ade89
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 12:58:44 2011 +0800
+
+ Fix bugs in HashTable
+
+ Thanks for TDY, we resolve the bug - use the bucket reference that is deleted after rehash
+
+commit 64c155a8bf7256bf8b35cb1c7a420e06c937995c
+Author: luba <lubatang@gmail.com>
+Date: Wed Nov 9 06:34:04 2011 +0800
+
+ fix a bug in HashTable::load_factor()
+
+ HashTable::load_factor() has typo error. Since it's a template class, typo-error is not easy to be found.
+
+commit ede118612a71753ae4a1f990d0f7727534bb7067
+Author: luba <lubatang@gmail.com>
+Date: Wed Nov 9 06:09:56 2011 +0800
+
+ Add a new testcase - alloc100 - for HashTable
+
+ alloc100 sequentically inserts 100 elements into the HashTable
+
+commit b6014605f72bdc76bdbd961cdc3ae67b62606a19
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 11:29:45 2011 +0800
+
+ Refactoring HashTable
+
+ 1. make HashTable is no longer limited to llvm::StringRef key type.
+
+ HashTable get the type of key and value from HashEntry.
+ HashEntry::key_type and HashEntry::value_type. HashTable does not assume the key type is based on string. Moreover, the hash function is also not l
+
+ 2. move the construction of HashEntry outside from the HashTable.
+
+ Clients must pass the factory of HashEntry as a template argument into the HashTable. That is,
+
+ HashTable<..., EntryFactory>
+
+ The memory can control by the factory. HashTable no longer takes care of it.
+
+commit 12ef316a47a7d068a2593cb9510c829662149a73
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 10:59:53 2011 +0800
+
+ Unit test of mcld::HashTable
+
+ Only few cases are tested. Please contribute more cases.
+
+commit 564228ab83535e7f60d043e6923bdb5f5c3ad6f5
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 10:55:34 2011 +0800
+
+ A HashTable whose hash function is changable
+
+ Since the hash function in linkers can be changed in GNU ld, MCLinker should
+ provide such feature to change the hash table. mcld::HashTable is the implementation.
+
+ Features:
+ - Can change hash table
+ - User defined hash entry - Symbol table uses this feature to keep string and symbol in the same cache line.
+ - Quadratic probing, open addressing hash table.
+
+commit 84586bd7ed6e0023f3f661323f8f93140d72439d
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 10:48:44 2011 +0800
+
+ Add MallocAllocator
+
+ LLVM has provided a llvm::MallocAllocator, but it is a 'plain' allocator.
+ That is, llvm::MallocAllocator returns a raw byte string and users need to
+ cast the raw byte string on a new type by itself. Additionally,
+ llvm::MallocAllocator does not follow the API defined in C++ standard.
+ So, I decide to give them a new MallocaAllocator.
+
+commit acc2c370db8c9c1d437bdbb87277f49152c31c53
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Nov 11 10:43:49 2011 +0800
+
+ add all string hash functions
+
+ string hash functions are partial specifized with the prototype:
+
+ template<size_t HASH_TYPE>
+ class StringHash : public std::unary_function<llvm::StringRef, size_t>
+ { };
+
+ MCLinker provides the following hash functions:
+
+ enum StringHashType
+ {
+ RS,
+ JS,
+ PJW,
+ ELF,
+ BKDR,
+ SDBM,
+ DJB,
+ DEK,
+ BP,
+ FNV,
+ AP
+ };
+
+commit 24a8d22a905e0995cfde8b196e3b8cc2f2ab10bd
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 14:48:14 2011 +0800
+
+ Re-add MCLDDriver scaffolding.
+
+ Use MCLDDriver as GNU collect2 to prepare
+ all implicit parameters for MCLinker.
+
+commit c9812dd48671c83261c3ecc182d0d22e64376228
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:37:34 2011 +0800
+
+ Remove legacy code from MCELFObjectReader
+
+commit 1df9138c88d3e76b3882e3ead7dced589ff29508
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:36:51 2011 +0800
+
+ Remove verbose printout from unittest.
+
+commit 9e689583cea552c684483b61d8be1779ccc8c8ce
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:35:29 2011 +0800
+
+ Correct the copyright and license.
+
+commit c143ee81e5d6e36321baabcfd57a96e05445bcdc
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:33:20 2011 +0800
+
+ Change the description of MCLinker.
+
+ The main contribution of MCLinker is not BSD-like license.
+ Instead, is using LLVM machine code layer and perform well under limited memory budget.
+
+commit 396917e17da3a9dcd64f01b9e91e622cdf0c750f
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:30:51 2011 +0800
+
+ Fix Luba's email and the Copyright
+
+commit a23025ae217cb5353826cbad6d9bbf3bc56616bf
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:30:00 2011 +0800
+
+ Remove directory check from the unit test "PathTest".
+
+commit 1f9e256769b3b1c3a3ee6cdb083798a78fc40d0b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:28:51 2011 +0800
+
+ Change the old project name to MCLinker.
+
+commit 405382710ebe8b2f88e0415cd5d8d4275068c902
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Nov 1 10:27:10 2011 +0800
+
+ Add LLVM release license file.
+
+commit 0f5fb0b15f353e777c9d5734b79cf92db632fb27
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Oct 27 13:46:59 2011 +0800
+
+ Replace get_current_dir_name() with getcwd()
+
+ get_current_dir_name() is not portable in Unix-like systems
+
+commit f07dc273f036e1fd1f7616275ff52d065a02378b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Oct 27 13:40:34 2011 +0800
+
+ Refine MemoryAreaTest
+
+ Remove redundant tests, and change file names of sample files
+
+commit 8e67d2da40c2bb2daaea12bf20161415a44c26d5
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Oct 26 17:00:11 2011 +0800
+
+ ./patch/LLVM.patch is for LLVM 3.0 branch, not trunk.
+
+commit b634a59912a1d40ccf99bed32869dc715f0c997e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Oct 26 12:47:26 2011 +0800
+
+ Add ELFEXEWriter header and footer
+
+commit 4ea0616604456788c2e1a7b940f6e584606df707
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Oct 26 12:46:17 2011 +0800
+
+ Move LDScriptReader directory to lib/LD
+
+commit 6cff6d7e074a781a957464d28f3a7c3fc7d7a8a9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Oct 26 11:04:49 2011 +0800
+
+ Remove temporary code of Readers
+
+commit 43a592f296c6af10e6b4af34b18332d1618408fd
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Oct 25 17:35:38 2011 +0800
+
+ Write comments for a number of files
+
+commit 31abc0988cbfd69fca49d8c863004d90de9c9365
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Oct 25 14:23:17 2011 +0800
+
+ Remove ObjectWriter and ObjectTargetWriter
+ Use LDDSOWriter and LDEXEWriter instead
+
+commit a0befa4577e50f6b225a534a1fa885d7d7834612
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Oct 25 10:55:33 2011 +0800
+
+ Rename MCLDDriver to MCLinker, remove old MCLinker
+
+commit bb8c5250771fe50d33ec6cfc6145f361d510cd8d
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Oct 24 19:53:35 2011 +0800
+
+ Tidy up ./patch directory
+
+commit 465bd9fd412465e87c792a0873fe8ee463930f51
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Oct 24 19:34:32 2011 +0800
+
+ Add missing header files
+
+commit 7e9713b1928848551bae4dbea336bcd17f9a6555
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Oct 24 12:59:18 2011 +0800
+
+ Remove include<cerrno>
+
+commit 52418fcb55b764caa163d82ce8f7974a8b9091d5
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Oct 24 12:53:11 2011 +0800
+
+ Remove redundant include<iostream>
+
+commit d935db745b93ae175ae10ce8b75e55c366ca5ad9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Oct 24 11:48:25 2011 +0800
+
+ Fix warning about "NULL used in arithmetic"
+
+commit eea7f316e094e5236f396e974c0c3a52250bb1c1
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Sun Oct 23 21:01:29 2011 +0800
+
+ Force RegionWriter to be used only through auto variables
+
+commit bbb2780e8a078b5cea8391b27be48007dffadcc6
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Sun Oct 23 17:01:15 2011 +0800
+
+ Move MC/MCLDContext to LD/LDContext
+
+commit eab6d7efb73f44d1776001e56634e2d53205685e
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Sun Oct 23 16:30:40 2011 +0800
+
+ Rearrange some code
+
+commit 4c20d4b12dd120ebc820ab385db2571102bfdc2c
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Sun Oct 23 15:47:46 2011 +0800
+
+ Add namespace missing "std::" prefix
+
+commit 576147414854bf04a6c1cea8861ecc56029409e1
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Sun Oct 23 15:45:12 2011 +0800
+
+ Remove unnecessary forward declaration
+
+commit df74078521e645b6fbf97c0e22ab9174e4967980
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Sun Oct 23 15:32:40 2011 +0800
+
+ Avoid building MCLinker in source directory for the case without specifying "--unittest"
+
+commit f7aa1d3a2ede9b40451277ed077098a36c419d71
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Oct 21 22:14:09 2011 +0800
+
+ Remove "#include <iostream>" and rearrange include order
+
+commit 766081a84d93013bb1c5ca28c3370706cbaa9da7
+Author: pete <petechou@gmail.com>
+Date: Fri Oct 21 20:03:51 2011 +0800
+
+ Changes to fit LLVM Release 3.0
+
+ 1. generate the diff for llvm 3.0 based on r142614
+
+ 2. made the corresponding changes about TargetRegistry and TargetSelect
+
+ commit 3e74d6fdd248e20a280f1dff3da9a6c689c2c4c3
+ Author: Evan Cheng <evan.cheng@apple.com>
+ Date: Wed Aug 24 18:08:43 2011 +0000
+
+ Move TargetRegistry and TargetSelect from Target to Support where they belong.
+ These are strictly utilities for registering targets and components.
+
+ git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@138450 91177308-0d34-0410-b5e6-96231b3b80d8
+
+ 3. remove the code for llvm 2.9
+
+commit e3502d9411bab32ddf06accd4ccaff231e2b38e0
+Author: pete <petechou@gmail.com>
+Date: Fri Oct 21 17:51:07 2011 +0800
+
+ Style: Avoid std::endl
+
+commit 059dc0551fa92e068dd145189b377c502784d9f6
+Author: pete <petechou@gmail.com>
+Date: Fri Oct 21 17:36:08 2011 +0800
+
+ Style: Do not use 'using namespace std'
+
+commit e40a57cc29ea1ca3ff835920c30c5279bd85f471
+Author: pete <petechou@gmail.com>
+Date: Fri Oct 21 17:24:38 2011 +0800
+
+ Style: more license fixes
+
+commit e645c3e0e22f92e8a924536b1aa98f2386832aae
+Author: pete <petechou@gmail.com>
+Date: Fri Oct 21 17:20:32 2011 +0800
+
+ extend the AUTHORS list
+
+commit 73d9e668f734c43fa44ec3e214b1321c1781e56f
+Author: pete <petechou@gmail.com>
+Date: Fri Oct 21 16:35:59 2011 +0800
+
+ Style: Modify the license and include style to fit llvm style
+
+commit ddece1991a5d370d80ca2de31f8fcb64197b695c
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Oct 21 11:32:08 2011 +0800
+
+ Rename the standalone tool
+
+commit 83e08ed9788ee0f2a0c896ff3a5f77888dc33946
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Oct 21 10:57:56 2011 +0800
+
+ Modify build script, avoid building in source directory
+
+commit f8dfc828bb7d75714a7a07335b7a1da184c5b248
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Oct 20 19:27:43 2011 +0800
+
+ Remove two folder "./src" and "./debug"
+ Move MCLinker main to tools/llvm-mcld
+
+commit 3e78adc440d54a544a040ba2e83e76d8f117f6e5
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Oct 12 08:14:17 2011 +0800
+
+ Code clean up.
+
+commit ebee2cfab18ce62a6f20e0a09a9acc89af6dad33
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 11 21:08:16 2011 +0800
+
+ Implement shouldOverride.
+
+commit 8c3cf01465d6fb013dd933825a60cf03ea2952a3
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 11 16:14:24 2011 +0800
+
+ Overwrite -> Override.
+
+commit 11a4e5d15095bfb35150aa02685f78d1c92fb118
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Oct 6 10:07:34 2011 +0800
+
+ Add checks before RegionWriter writes buffer
+
+commit 8e70d908ba564cee4d3373ed2d167a01b364c888
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Oct 5 20:09:43 2011 +0800
+
+ Add LDWriter scaffolding
+
+commit 3d16c37f6a0078a9e48e839529d55740865dfd4e
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 4 19:43:37 2011 +0800
+
+ Change some fatal failure to nonfatal.
+
+commit 474175b9230dee039a1128d19417055cfcbb5ab6
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 4 17:14:17 2011 +0800
+
+ Add more StrSymPool tests.
+
+commit 60858969b65dbeaac3b6eae2a85522eda133ba0b
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Oct 4 14:00:04 2011 +0800
+
+ Add unittest for StringTable.
+
+commit 4b904a594ca281419ae15d3250d8151815c7c243
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 4 13:55:57 2011 +0800
+
+ Resolver pass by value.
+
+commit 32f6b6c9dace7546281c7d814a740dad6657f67f
+Merge: 041c1c2 da5dd9e
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 4 12:24:32 2011 +0800
+
+ Merge remote-tracking branch 'origin/master' into symbol-table
+
+commit 041c1c2f45e24cfdb453c743c7e14abed230f7cc
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 4 12:23:49 2011 +0800
+
+ Add StrSymPool unittest.
+
+commit da5dd9ee45bfabd425c68e73722997e58e4d1132
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Oct 4 11:39:57 2011 +0800
+
+ Fix StringTable.
+
+ Move StringTableIF to StringTable.
+ Cleanup useless unittest.
+
+commit bfd56054fb52fe4a54a03f506dac4759fb82c691
+Merge: dc62dd8 ce06c6b
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 4 10:19:07 2011 +0800
+
+ Merge branch 'origin/master' into symbol-table
+
+ Remove SymbolStorage.
+ SymbolTableFactory finished.
+
+commit dc62dd8e6339a08a1d838d753e287fc8a763234f
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Oct 4 09:19:25 2011 +0800
+
+ Fix SymbolTableFactory.
+
+commit ce06c6bfc0d300ee120b9ebd9df05eb5b7ed67cd
+Author: luba <lubatang@gmail.com>
+Date: Mon Oct 3 11:52:14 2011 +0800
+
+ Add SymbolStorage under ${MCLinker}/LD
+
+ This is an early prototype of SymbolStrage. Some trivial bugs may occur.
+
+commit 77cd06378472bdd63752a52578085f077804892f
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Sep 30 17:31:32 2011 +0800
+
+ Add the definition of LDSection
+
+ LDSection represents a section header entry
+ It is a unified abstraction for various file format
+
+commit b756bffdf5061043605a1390818d9a59c089fff8
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 29 23:56:15 2011 +0800
+
+ Fix SymbolTableFactory.
+
+commit c364b0b6530c4de753d74f18af0ec3d5b51ef77d
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 28 20:01:42 2011 +0800
+
+ Add default value for "Value", "Size", and "Other"
+
+commit 28dbc8c229439eea98564ab31d0238d914dd9e83
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 28 19:48:24 2011 +0800
+
+ Sorry for such a large commit again.
+
+ Fix typo: Catagory to Category.
+
+ Implement SymbolCategory::interpose.
+
+ Move out CategorySet from StrSymPool.
+
+ Fix compilation of StringTableIF.
+
+ Add "Value", "Size", and "Other" argument to insertSymbol.
+
+ Add LDSymbol's private copy constructor and operator assign.
+
+commit 3bb98f27f042923a5fbe80e605a630e817fdbd49
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Sep 28 19:51:15 2011 +0800
+
+ Add the testing file for MemoryArea unittest
+
+commit 7b26b4902ad6c91eb62453398865f86df02e4ebc
+Author: Diana Chen <diana.chen@mediatek.com>
+Date: Wed Sep 28 14:28:08 2011 +0800
+
+ Add testcases for MemoryArea
+
+commit 22adaeac58590b2230b0c8a606ef64a9a14bac15
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 28 13:29:06 2011 +0800
+
+ Implement that move symbol to other catagory.
+
+commit 83c50ded317a100f12ac3c543ad60d38e852f75b
+Merge: 9de22cd 74e9046
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 28 11:50:57 2011 +0800
+
+ Merge remote-tracking branch 'origin/master' into symbol-table
+
+ Merge StrSymPool and Resolver.
+
+commit 9de22cdadb8f5ec9fa83f82b144398be0c788e26
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 28 11:48:04 2011 +0800
+
+ Sorry for such a large commit again.
+
+ We use StrSymPool instead of SymbolStorage and StringStorage.
+
+commit d6e65d9b7cc20b22465245a61dd25c771cdbdc26
+Merge: a2a4cd7 7c3b4df
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 28 10:44:18 2011 +0800
+
+ Merge branch 'origin/master' into symbol-table
+
+commit 74e904670ef790ba4425acb9f206effb0ca4c6e0
+Author: luba <lubatang@gmail.com>
+Date: Wed Sep 28 11:41:53 2011 +0800
+
+ 1. add forward declaration of LDSymbol in Resolver's header file.
+ 2. add the including of LDSymbol's header in Resolver's implemenation file.
+
+commit 1128fcfc51ef86d0ad8a9b02681fd773fbe59f9b
+Author: luba <lubatang@gmail.com>
+Date: Wed Sep 28 11:31:21 2011 +0800
+
+ Add mcld::Resolver to bind symbols.
+
+ mcld::Resolver is the object who processes symbol resolution.
+
+commit 7c3b4dfc4f862fe68e2b9c6f9d6ab3fff75eee40
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Sep 27 17:52:46 2011 +0800
+
+ Implement the function of StringTable.
+
+commit 3155131f8487f311818e82248f2270238463dfbe
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Sep 27 16:25:08 2011 +0800
+
+ Fix the architecture of StringTable.
+
+commit 8cbc92b8b84f843ee1c49219cea6e351a1ad1440
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Sep 27 10:18:11 2011 +0800
+
+ Fix twice increment.
+
+commit 51a8cfccfa09a9775060c2b4e1608629259267ce
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Sep 27 09:57:19 2011 +0800
+
+ Move StringTableStorage to StringStorage.
+
+ Change StringStorage API, without changing usage.
+
+commit 2713fd1c933554a508f29f7e1556d3f3d0191db3
+Author: luba <lubatang@gmail.com>
+Date: Mon Sep 26 03:51:51 2011 +0800
+
+ 1. MemoryArea can write back to the mapped file
+ 2. Finish memory mapped I/O parts of MemoryArea
+
+commit a2a4cd7cfa145a7a58773b01e087f835b94e3a5b
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Sep 20 20:27:40 2011 +0800
+
+ Sorry for such a large commit.
+
+ Add all symbol table relative source code to Makefile.
+ Compile success, we need some unittests.
+
+ Add three symbol list: Entire, Dynamic, Common.
+ We cache the specify type symbols, then we can traverse more easy.
+
+ Remove SymbolTableFactory's template.
+ We only use singleton on any cases.
+
+ Move some small function from cpp file to header file.
+ For "inline".
+
+ Move SymbolList to SymbolStorage.
+ Let class dependency become a DAG.
+
+ Use reference instead of pointer when it can't be null.
+
+ Add "rebind" to LinearAllocator.
+ Obey the C++ Standard. For StringUnorderedMap using.
+
+commit 8dd4676cb9dafb7f706be42145ee96260e99eecf
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Sep 20 14:30:25 2011 +0800
+
+ Move SymbolList decl to SymbolTableIF.
+
+commit ab9bc330ea702b4fd01e8fbf8b6b00b9efc7466e
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Sep 20 13:08:50 2011 +0800
+
+ Implement SymbolStorage.
+
+ Change LDSymbol's friend from SymbolTableEntry to SymbolStorage.
+ Add SymbolStorage and SymbolTableEntry to Makefile.
+
+commit c258dfe219d00f9aa29406af6e72922489c3b9a5
+Author: TDYa127 <a127a127@gmail.com>
+Date: Tue Sep 20 11:20:05 2011 +0800
+
+ Modify StringUnorderedMap functor and allocator.
+
+ For empty base class optimization.
+
+commit f4010b6d6b0a5eb15c766799daa78a170348f913
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Fri Sep 16 22:13:22 2011 +0800
+
+ Fix StringTable unittest bug.
+
+commit 4fb28d22ee9b8678a04a91a945ea6c151ee71548
+Author: luba <lubatang@gmail.com>
+Date: Fri Sep 16 18:12:30 2011 +0800
+
+ 1. add readSymbolTables() and mergeSymbolTables() in MCLDDriver.
+ 2. remove obsolete class SymbolTable
+
+commit f8b323d1e834b8beac3c21634e3545f3610d4ce8
+Author: luba <lubatang@gmail.com>
+Date: Fri Sep 16 18:08:14 2011 +0800
+
+ Review SymbolTableIF
+
+ 1. Fix a but - the last embrace of class SymbolTableIF is not followed with ';'
+ 2. Add comments
+ 3. change the name merge_impl() and insertSymbol_impl() to doMerge() and doInsertSymbol()
+ 4. let getSymbol as a observer - return const LDSymbol*
+ 5. add a new modifier getSymbol() - returns non-constant LDSymbol*
+
+commit 641d648470b231c49fb6e8a2bb1bd3895b70ddcc
+Merge: 61a2476 106f9c3
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Fri Sep 16 16:28:50 2011 +0800
+
+ Merge remote branch 'origin/master' into HEAD
+
+ Conflicts:
+ debug/Makefile.am
+
+commit 106f9c304e96625fa8b762a24fdd8b2e8a0abefe
+Author: luba <lubatang@gmail.com>
+Date: Fri Sep 16 15:51:47 2011 +0800
+
+ add --add-needed/--no-add-needed attributes
+
+ MCLinker needs to double confirm if it is allowed not to copy the DT_NEED of input files when
+ checking the dependencies of dynamic libraries.
+
+commit 61a247653b9d748dd9f29eb40acef06695a178af
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 15 23:33:19 2011 +0800
+
+ Add SymbolTableEntry usage to SymbolStorage.
+
+commit cef15fdcc1178658abafda99b14b9ea8773f637b
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 15 23:31:28 2011 +0800
+
+ Add SymbolTableEntry.
+
+commit 637f5ed17d6e51ca63bd11ce9c6fb2920a36167b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Sep 15 20:53:25 2011 +0800
+
+ Add a unittest for MemoryArea
+
+commit 8828be501730baf80cbf675323cfa8742b879dd6
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 20:27:30 2011 +0800
+
+ Finish LDSymbol and move SymbolTableTest out of unittest
+
+ Because SymbolTable has not finished yet, and it conflicts with current LDSymbol,
+ I move it out of the compilation list.
+
+commit ec89c687a517e8b24c38b3b3f29fe8b5eb1f214c
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 19:55:02 2011 +0800
+
+ Fix a bug - MemoryArea::isGood() returns the opposite value.
+
+commit 7b40a5172acb2ce2f307699b61082ab37d0cdf3f
+Merge: bce4c35 43e7101
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 15 18:08:22 2011 +0800
+
+ Merge remote branch 'origin/symbol-table' into nowar
+
+commit 596d478524ec9afc462aa323b4c23e7cb6209e6d
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 16:18:32 2011 +0800
+
+ Finish the implementation of MemoryArea.
+
+ I have not implemented memory mapped I/O parts of MemoryArea.
+ Because when we link in Android platform, linkers load few sections of input files.
+ And memory performance is not a critical issue under such scenario.
+
+commit 67f7ab10981ef3721800d47b3ac8152ea42ab2a5
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 16:17:26 2011 +0800
+
+ Fix a typo error - Allocator::isAvailable()
+
+commit 70b53f382c158a50c8931eb772e92535e45a8ee6
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 14:51:11 2011 +0800
+
+ MemoryArea::request add a new case: if we find an existing space.
+
+commit 001cd1479c9d0b2ff4c0965e7412ab9bcf40b379
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 14:05:57 2011 +0800
+
+ Let MemoryAreaFactory create MemoryRegion by RegionFactory.
+
+commit 94d8c0040a9d6238197a6b0a6f263d46d8df48f8
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 14:05:35 2011 +0800
+
+ add RegionFactory to manage all MemoryRegion.
+
+commit f007e2bb769933593d4d2aea78e78e41f0037a18
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 14:00:49 2011 +0800
+
+ add an empty testcase of MemoryAreaTest
+
+commit cdd634ba7dc67514b63aae56127f11e14ac20ce5
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 11:10:46 2011 +0800
+
+ Finish the scaffolding of MemoryArea and implementation of MemoryArea::request
+
+commit c2c5540083f281eaff49e1d0980dc5186f7dfbee
+Author: luba <lubatang@gmail.com>
+Date: Thu Sep 15 11:09:23 2011 +0800
+
+ Let the implementation source of unittest searches in the local directory first.
+
+commit bce4c358e6a402585fbdf619d777f75efc047f7a
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 15 10:23:13 2011 +0800
+
+ Fix memory leak on string table.
+
+commit 3618c931ceb0d633ec2d842682c5fd77c1ba6d99
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 15 09:57:10 2011 +0800
+
+ Fix null-terminated string size bug.
+
+commit 43e7101747b1f9c193a44fbd7fe07cb112125fb1
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 14 18:23:27 2011 +0800
+
+ Fix StringUnorderedMap StringType.
+
+commit f2f18f7eef077ed67618d8b1414e0eb4c8eb44fb
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 14 17:28:00 2011 +0800
+
+ Fix SymbolTableFactory singleton.
+
+commit 81845fad57b14465791c392333c6c4adc8e7f367
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 14 17:00:48 2011 +0800
+
+ StringUnorderedMap: clear() & destructor.
+
+commit 3f91c8eefdf3d0e9007f32b2dd0031b76fbd6eb2
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 14 16:42:29 2011 +0800
+
+ Add StringUnorderedMapTest.
+
+commit 67505dc6fc7a281adbba5089293270ca87d196f2
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 14 14:16:00 2011 +0800
+
+ StringUnorderedMap is close to finish.
+
+commit 4ca681b2db8bf4a0b881924fe57fab357b65e3ca
+Merge: 0d78df2 239064e
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 14 10:53:22 2011 +0800
+
+ Merge 'origin/a127-tmp' into symbol-table.
+
+ Merge our StringUnorderedMap.
+
+ Conflicts:
+ include/mcld/LD/StringTable.h
+
+commit 0d78df23fb8f6308fea9d43b81668ee687d6c76c
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 14 10:48:23 2011 +0800
+
+ Use StringTableIF rather then StringTable.
+
+commit 7a378374448df0265c57cb3253d79d09e48a089f
+Author: luba <lubatang@gmail.com>
+Date: Tue Sep 13 15:25:59 2011 +0800
+
+ All mcld::MCLDFile gets its MemoryArea.
+
+commit 45c920eab8f6adfa1e14242eafde9ec5c6dfb752
+Author: luba <lubatang@gmail.com>
+Date: Tue Sep 13 15:16:53 2011 +0800
+
+ add MemoryAreaFactory in MCLDInfo.
+
+ The architect decides let MCLDInfo carries MemoryAreaFactory to everywhere.
+ It may be a stupid decision. If it's stupid, please tell Luba gentely.
+
+commit cfd9de20f114265e371a2f65fdb759c72a4a1ff5
+Author: luba <lubatang@gmail.com>
+Date: Tue Sep 13 14:54:49 2011 +0800
+
+ add new class MemoryAreaFactory
+
+ MCLinker should let two different inputs with identical file path share
+ the same MemoryArea. So, like ContextFactory does, we provides a new
+ factory to do that.
+
+commit 2a43699955b158a36126736fd4a0591e8c49f466
+Author: luba <lubatang@gmail.com>
+Date: Tue Sep 13 12:03:49 2011 +0800
+
+ Add UniqueGCFactoryBase.
+
+ Because we have more and more request for an associative factories which
+ has unique key and value pair, for example ContextFactory and
+ MemoryAreaFactory, therefore, I create a class UniqueGCFactoryBase for
+ the common parts of these factories.
+
+commit ea30a3a7b79db9cb8940a0a8c239141bd13367c9
+Author: luba <lubatang@gmail.com>
+Date: Tue Sep 13 12:01:45 2011 +0800
+
+ envsetup.sh determines if the user is on SWRD server stg01 and add git commands in the searching path.
+
+commit ce0ea9786d7e03e7efc091a43d356c4f99b8e06e
+Merge: 2e3d040 4ae7094
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 8 18:56:48 2011 +0800
+
+ Merge remote-tracking branch 'origin/symbol-table' into nowar
+
+commit 4ae7094eba1c2296b3e0b057a6eedff4d6a46e8b
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 18:53:49 2011 +0800
+
+ Add SymbolStorage's some code.
+
+commit 2e3d040969f804665d4f3c6177457827445e82cd
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 8 18:49:46 2011 +0800
+
+ Add StringTable, DynStrTable, and unittest.
+
+commit f35dbb5fea04d1166a5b193873f686cf3dbe661c
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 17:58:00 2011 +0800
+
+ Reserve SymbolList size when construct.
+
+commit 808a7b1e5c91916e8c81a86faf9d6597b565e279
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 17:30:28 2011 +0800
+
+ Remove LD prefix.
+
+commit 878e229732e29e65bb3527b7152039b9d8aec905
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 17:26:39 2011 +0800
+
+ Remove LD prefix.
+
+commit d58566b0bd8f7f77491cd983c4fdb34a84d75816
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 8 17:14:15 2011 +0800
+
+ Code cleanup. Remove LD prefix and old StringTable.
+
+commit d23795114d9a4f215f14316e013a9f039a9ad128
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 8 16:54:46 2011 +0800
+
+ Add scaffolding of StringTableFactory.
+
+commit 58db1a9e2fbe7fc7f826e6c04f741d0bffb90851
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 16:52:24 2011 +0800
+
+ Add LDSymbolTableStorage draft.
+
+commit 8b1ba35c2f4b9ebf0bfa09dc9fb8d7abf1259f1c
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Sep 8 16:51:39 2011 +0800
+
+ Add scaffolding of StringTableStorage and StringTableInterface.
+
+commit 337f6adeba144944e49ef83489f560506f099ad6
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 13:43:36 2011 +0800
+
+ Fix LDSymbolTable initialization.
+
+commit 75a7945082edf34aee1f26af01c7673f8c75f7ea
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 13:31:46 2011 +0800
+
+ Implement constructor and distructor.
+
+commit 0c981e9f50f727da824015d3a5d8856dd59df8c0
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 12:28:57 2011 +0800
+
+ Remove LDDirectSymbolTable and LDIOSymbolTableIF.
+
+ Now:
+ LDSymbolTable
+ /\
+ /__\
+ |
+ --------------------------
+ | |
+ LDInputSymbolTable LDOutputSymbolTable
+
+commit b47ffc09d2b70c3c8c5f8156ecc2da6ffe26c955
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 10:25:08 2011 +0800
+
+ Remove unwanted typename.
+
+commit 3e545b352c7b63b950125000800bdfa9f47384c0
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 10:04:21 2011 +0800
+
+ Move virtual member to private.
+
+ Use NVI pattern let the iterator operation can be hidden by derived class.
+ Then the iterator operation can be fast when know the type.
+
+commit f2b687ba31b5662427b85cc4aa35a0044edb4c45
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 08:15:15 2011 +0800
+
+ Impl Input and Output SymbolTable::insertSymbol.
+
+commit 215ed62dd6d0ac5b729d30050749557d9f90d1ee
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 08:04:50 2011 +0800
+
+ Add MCLDOutput.h include.
+
+commit 841774e4cc04573cd845c426842bb5aaa95cf24c
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 8 07:54:36 2011 +0800
+
+ Interface changes. Implement DirectSymbolTable.
+
+ Move iterator relative interface to lower level interface.
+ Implement DirectSymbolTable.
+
+commit 8ee8cf8b610cbeb07bef36685e5f48be0008ebae
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 23:09:55 2011 +0800
+
+ Add LDSymbolTableFactory<true> draft.
+
+commit d176b5138db7f5096b0bab3ce2b2d1031521d1e2
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 22:38:02 2011 +0800
+
+ LDSymbolTableFactory is LDSymbolTables' friend.
+
+commit a769c14a1cb7f313bfb2420305a06e5c0729520e
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 22:20:31 2011 +0800
+
+ Add draft note.
+
+commit 47eab80a93cddba2ae838d28ba13f24b6d6f59a2
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 22:15:48 2011 +0800
+
+ Add symbol table factory draft.
+
+commit e7e916941a99b27eca092493792eac757ff68ee0
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 21:59:48 2011 +0800
+
+ Fix typo: talbe -> table...
+
+commit a8300f3914b371e62a350fb2b8aec82d1b5bafaa
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 21:43:24 2011 +0800
+
+ Add direct symbol table draft.
+
+commit a932f98a838a65fe7ccec131859e170384d6cf4c
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 21:40:19 2011 +0800
+
+ Add LDOutputSymbolTable.h include.
+
+commit 99543babb6db39bcaa4259344ba9056e6bf7f1ae
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 21:21:19 2011 +0800
+
+ Add Output symbol table draft.
+
+commit 1bbecf1d27db4cf2e2afd4333a19d53bffa9bfce
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 20:39:43 2011 +0800
+
+ Add input symbol table draft.
+
+commit 871ca4c0b31a20126a839d08a5bc45f2a984cbf1
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 20:31:28 2011 +0800
+
+ Add IO symbol table interface draft.
+
+commit 8cab6036f0afaddc22e49c169ecf68116c5cf344
+Author: TDYa127 <a127a127@gmail.com>
+Date: Wed Sep 7 20:23:28 2011 +0800
+
+ Add Symbol table interface draft.
+
+commit d7895e40690b87418f14cb84fa13b9756e120308
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Sep 7 10:15:48 2011 +0800
+
+ Add FIXME to unittests for "DirIteratorTest"
+
+ Some bugs modifies the global value "errno" to non-zero.
+ This makes readir() failed when daily build system runs unittest
+ Remove the FIXME after fixing those bugs
+
+ This unittest fails only when running unittests by daily build system
+
+commit 239064e6d8f23558ad5ecc1cf59e6088c14062e5
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Sep 1 19:14:01 2011 +0800
+
+ Add StringUnorderedMap draft(not complete).
+
+commit 3d65138fdfdab0b994888aee195a9135f73e7429
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 31 08:04:46 2011 +0800
+
+ Add some missing unittest of StringMap.
+
+commit fe7ff2a94c9fd787f9fa0f7b3c6f399eb7e324af
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 31 07:47:19 2011 +0800
+
+ Add SymbolTable, LDSymbol and corresponding unittest.
+
+commit 3e67358487dd0ff11ae97571eca2ee1bb719e27f
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Aug 30 13:43:26 2011 +0800
+
+ Add StringTable and corresponding unittest.
+
+commit 4bbe75fe3202a731b303ef0dd38d8dd77b9a0308
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Aug 30 11:17:09 2011 +0800
+
+ Improve StringMap unittest. Replace tab by 2 space.
+
+commit a893afcb5bf673e5703614796101949ce248bce2
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 30 16:10:06 2011 +0800
+
+ Let MCLDFile get MemoryArea.
+
+ MemoryArea is the manager of memory map I/O and allocated memory array for files.
+ MCLDFile uses MemoryArea to get memory regions.
+
+commit 66a232e3cdf4a22ed4094b126f9c579c7bcae354
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 30 16:09:09 2011 +0800
+
+ add the scaffolding of MemoryArea and MemoryRegion.
+
+commit af909522fe4369afda1f3aa111b3c297537f2442
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 30 14:05:36 2011 +0800
+
+ The result of unittest BFS_BasicTraversal was wrong, fixed it.
+
+ Root
+ /
+ 111
+ / \
+ 9 10
+ / \
+ 7 8
+
+ ROL, the result should be 111, 10, 9, 8, 7
+
+commit a8e920dcb2bc8e6f7361b967e3f696aaa343257d
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Aug 30 09:54:16 2011 +0800
+
+ Add features into scripts.
+
+commit e11caa50c0486246788a0f43b05c1a326d7e8675
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Aug 29 20:35:15 2011 +0800
+
+ Adding a header file for std::cerr
+
+commit 24e84578d7aa5f30c6f13693778d9d75d3c3296e
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 29 20:21:56 2011 +0800
+
+ Add a Config.h.in
+
+ autoconf reads Config.h.in and generage Config.h
+ Some target-independent information about MCLinker are in.
+
+commit c2224729a2907edf6753c7fcc77294926d25a5cd
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 29 20:21:13 2011 +0800
+
+ add unittest for StringMap
+
+commit 1d11a78bc8608da1dd46b6a1553bdc98533e113a
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 29 20:19:16 2011 +0800
+
+ add X86 target in compilation.
+
+commit c15f0c015fe65831f63e307a399fdeefaadee0fb
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 29 20:18:53 2011 +0800
+
+ add X86 target
+
+commit dd067673e230d69f1bd2b4c98c6d9bfd236273cf
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 29 19:53:46 2011 +0800
+
+ Fix bugs
+
+ 1. StringMap's constructor set value to parameter, not member variable
+ 2. cur_node in SectLinker initializeInputTree does not move forward correctly.
+ 3. refine BFSIterator algorithm
+
+commit 4accb839a02ea302b9dcdd72cc77f56e89421fa2
+Author: luba <lubatang@gmail.com>
+Date: Sat Aug 27 16:59:05 2011 +0800
+
+ VERSION - The document of software versioning.
+
+commit b66e4d97bbd3d4c9d72f7eafb2ae70fb16457a09
+Author: luba <lubatang@gmail.com>
+Date: Fri Aug 26 18:13:09 2011 +0800
+
+ add option -V and -verbose for demo.
+
+commit 9051b6f3de4fff555dc1860bded747b601e80e5e
+Author: luba <lubatang@gmail.com>
+Date: Fri Aug 26 17:46:12 2011 +0800
+
+ LLVM 3.0svn removes IsSymbolRefDifferenceFullyResolvedImpl from target writers.
+
+ Since LLVM 3.0svn let MCObjectWriter finish the jobs of IsSymbolRefDifferenceFullyResolvedImpl,
+ we do not need to expose this function in MCAsmObjectReader any more.
+
+ This patch also fixes the bug - an unexpected assert in ARMObjectReader::getRelocInner().
+
+commit 89bc3b6d8513a8f7da6ddb0b5e2305fb69dc0335
+Author: luba <lubatang@gmail.com>
+Date: Fri Aug 26 11:26:51 2011 +0800
+
+ This patch is by Wen-Han Gu - Add the Relocation class.
+
+ BTW, PLEASE make sure EVERY COMMIT can be COMPILED!!
+
+commit 1f9c0c5c10fd6de0154712b365126d901800eeb9
+Author: luba <lubatang@gmail.com>
+Date: Fri Aug 26 10:57:11 2011 +0800
+
+ LinearAllocator doesn't mean to release memory at destruction.
+
+ By the C++ standard, allocator is just an abstruction of underlying memory.
+ It should not refer to the area of garbage collection, even memory stack.
+
+ Please ask the author written in the header before you starting modifing code.
+
+commit 786c71c9255a2d55de3b2b47406583e712c7f80d
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 25 18:59:07 2011 +0800
+
+ Improve MCAsmObjectReader::RecordRelocation().
+
+commit 8fa8a35f3b7a44aded948651d8c793768798f7bd
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 25 17:12:09 2011 +0800
+
+ Move RelocationInfo from MC to LD.
+
+commit a3cbae418e766aca4c0c495ca59e8a683ed06746
+Author: luba <lubatang@gmail.com>
+Date: Thu Aug 25 11:43:29 2011 +0800
+
+ enhance -t output
+
+ Display the name of a object file when -t enabled.
+
+commit b2d9280de1d8632dc50f4ed666adb708b3f98ccd
+Author: TDYa127 <a127a127@gmail.com>
+Date: Thu Aug 25 13:21:37 2011 +0800
+
+ Add LD/StringTable draft.
+
+commit 59bb714dc3561b6aa6b058cf6df14eadd0891fdd
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 25 10:24:16 2011 +0800
+
+ Let objects in StringMap live consistently.
+
+commit 09371704bdc653fbe14141828aa87d42a8349746
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 24 21:17:50 2011 +0800
+
+ Keep valgrind leak-check silent.
+
+ Call clear() in destructor of LinearAllocator.
+
+commit c2e92a3b1b06400b04ef0ab1feba2ea882317171
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 24 20:31:35 2011 +0800
+
+ Fix memory leak in unittest.
+
+commit 5c0d0906951cf4bf20394fe08269426d2102c75b
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 24 17:57:27 2011 +0800
+
+ fix a bug in AttributeProxy.
+
+ Bug: AttributeProxy::isStatic() check the wrong condition of AttributeConstraint.
+
+commit fe21a3652b594834475eecc22ea0eea7c8943327
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 24 15:26:58 2011 +0800
+
+ Implement our mcld::StringMap.
+
+ An object adaptor of llvm::StringMap to make it
+ - While insert, only find once, and we can get the iterator to the Value
+ - Stable iterator
+
+ Thanks for TDYa127!
+
+commit 8ffed91cbd22b31dc9264da31bff829550e6b9a8
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Aug 24 13:38:29 2011 +0800
+
+ Adding type identification for -dy & -static
+
+commit f92a911524478c09bc2108f590bcc378cce5addc
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Aug 24 09:34:30 2011 +0800
+
+ Adding missing header files
+
+commit c11ee37e58a36af6531d10670c3787221c8f097b
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 24 02:33:51 2011 +0800
+
+ Fisrt stable version of normalization.
+
+ Bugs List:
+ 1. ArchiveReader can not read members correctly
+
+commit a22efb5ebe91b7bd8e3e887991f4e4bf24c9ca17
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 24 00:21:41 2011 +0800
+
+ MCLDDirectory should not be opened if in sysroot.
+
+commit 2ecc851588c4a7c350b16e9bea113618152a93cf
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 23 22:53:51 2011 +0800
+
+ Fix the bugs in Path library
+
+ canoncal_form is wrong in some cases.
+ For example - '//' should not be entirely removed. There should be existing a '/'.
+ Another case is '/.kde.local/../', the result of old conocal_form is 'kde.local/../'
+ the correct result should be '/'
+
+commit edc85d4ad21f741ca033ebb39afbffd99f4c890c
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Aug 23 14:06:32 2011 +0800
+
+ Never use the space having been freed.
+
+ RehashTable() of llvm::StringMap *MIGHT* delete the table.
+ That cause us has SIGSEGV sometimes.
+ Now this is bug-free, but less efficient.
+ When inserting, lookup happens twice.
+
+ I'm thinking maybe I should re-design a mcld::StringMap.
+
+commit 928641b775aca69db87fa157dc8e68a0f40e9a2c
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 23 11:42:19 2011 +0800
+
+ Add function - RealPath& RealPath::assign(const Path& pPath)
+
+ Since RealPath has default constructor and copy constructor, it should have an assign function.
+
+commit b50a378d67448f76972456d9551a7b6111b259e3
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 23 11:26:55 2011 +0800
+
+ move SearchDirs under MC
+
+ Since SearchDirs is customized for linking, not a normal case for all searchable directories,
+ we move it from ADT to MC.
+
+commit 376368af3711f813cc0ba54415c0692ae3148af4
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 22 19:39:52 2011 +0800
+
+ add regression test - trace
+
+commit b5b9033a2acadb2c635c100f65994b6cdcf9a06e
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Mon Aug 22 19:19:53 2011 +0800
+
+ Follow the default template parameter.
+
+commit c26fcc7b036e977ef6008090d6c3d951ef3de49d
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 22 19:02:24 2011 +0800
+
+ Fix the bug - IteratorBase should have a default constructor
+
+ DFSIterator's constructor needs the access its left child and right child.
+ However, in the default constructor of IteratorBase, both left and right children are NULL.
+
+ For avoid dereference NULL pointers, I create a new default constructor of DFSIterator that does not pre-read the left and right children.
+
+commit 0c6bed4492fca5ac3d89c1786ee4f29f6ba15e9b
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Mon Aug 22 18:06:14 2011 +0800
+
+ Make a partial-specialization of llvm::StringMap.
+
+ We need a more-suitable-interface one when template parameter
+ is our mcld::Path.
+
+commit 53933ce899edbed2ecbf2af8e310e9839d32a25c
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 22 17:11:07 2011 +0800
+
+ Fix the bugs in BFS iterators.
+
+ Pin-Roung is so stupid.
+
+commit c645a0c678857a4f36340a33d9e183627325eda3
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 22 16:58:48 2011 +0800
+
+ Fix the bug of DFS Iterator
+
+ Pin-Roung is stupid.
+
+commit 9cb394d2be904f26f00f75f7d430151d687615d9
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 22 14:44:23 2011 +0800
+
+ Bug free but bad performance Directory
+
+ This version of Directory needs two StringMap::find
+
+commit 93d8305872a5eaf08bf30b9648f4f19a8007e215
+Author: luba <lubatang@gmail.com>
+Date: Sun Aug 21 22:25:33 2011 +0800
+
+ Fix a bug - read an entry in the directory immediately after opening a directory.
+
+commit 87a1bfeb89dd3675fdba264c8452d237c0e5d0a9
+Author: luba <lubatang@gmail.com>
+Date: Fri Aug 19 14:33:36 2011 +0800
+
+ add some diagnostic code in MCELFObjectReader::isMyFormat
+
+commit 8cede7eeda6bf4798f11339f1c82db4f7bb0bb63
+Author: luba <lubatang@gmail.com>
+Date: Fri Aug 19 14:08:41 2011 +0800
+
+ Change the PositonDependentOptions
+
+ Since LLVM removes the data of cl::list<Data> when it leaves scope.
+ We let PositionDependentOption stores the data.
+
+commit 5d2db3f9fb2355556cd8eb9523621c3bb8401ad0
+Author: luba <lubatang@gmail.com>
+Date: Fri Aug 19 13:50:40 2011 +0800
+
+ Release AsmStreamer in the wrong time.
+
+commit 5a6100474a49ac801c9ebc5abc8caca928c4e88f
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Fri Aug 19 13:25:01 2011 +0800
+
+ First compile-able release for 8/11's scope.
+
+ !!WARNING!! This version is not debugged.
+
+commit f991492dfba6de66c720270fccdbb9c7e0692f19
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 8 20:37:20 2011 +0800
+
+ Cancel the target-dependent archive reader.
+
+ Since the difference of the formats of archive files are only on
+ the OS type, not on target, we remove all target-dependent archive readers.
+
+commit 48fe63f04e8fe6d158d9290b4dd4a1c6203dd94b
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 1 10:40:07 2011 +0800
+
+ add iterator for each data in the Allocator.
+
+commit c0223e1943542c1fd1ad4ca34ad55e1870ffc703
+Author: luba <lubatang@gmail.com>
+Date: Fri Jul 29 02:05:11 2011 +0800
+
+ A syntax-correct BinaryTree
+
+commit 4368ec551ebb65fd127f5d93caafdf8304c93753
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Aug 18 18:18:47 2011 +0800
+
+ add scaffording of algorithm about MCArchiveReader.
+
+commit 25fb7e66a8d5eeee84e333f39d32b3d673aa0a4a
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 18 17:40:12 2011 +0800
+
+ Change design: Need no MCObjectTargetReader.
+
+commit ab133b6d81efc4cdb03b233289b7d341fd6691b4
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 18 16:40:55 2011 +0800
+
+ Implement mcld::MCAsmObjectReader::RecordRelocation() done.
+
+commit a5b299ed5fc0614867cff23949d0c679b60a999a
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Aug 18 16:36:00 2011 +0800
+
+ fix a bug: archive map is big-endian, and turn on the binaryTree test case.
+
+commit 3ae4df53b920d33e5ff4daa9be8532eecf386441
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Aug 18 10:40:31 2011 +0800
+
+ Refine BinaryTree::merge(): change template argument order.
+
+commit 89c9f31107b7cd98732176bf1201d08270d886b6
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Aug 18 10:06:49 2011 +0800
+
+ Fixing MCObjectReader
+ it reads hello-jni.o & libhellojni in NDK samples
+
+commit 1d65d9314fee829ef96cf032cf0c4f131e9410bc
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 18 09:09:47 2011 +0800
+
+ Implement mcld::MCAsmObjectReader::RecordRelocation().
+
+commit a9d1e8f2ff5db35977ce46d8a6f0b7ea16d2fbb2
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Aug 17 22:15:41 2011 +0800
+
+ Refine the DFSIterator inheritance system. Add scaffording of MCArchiveReader. Modify MCLDDriver::normalize(), and let it can traverse to an archive. Use "using BinaryTree<Input>::merge" expression in InputTree, so we can use it from object of InputTree. Shut donw The test case of BinaryTree. I will fix it later.
+
+commit 17b939b0d4b942c10da0c27d96a5baa98da31965
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Wed Aug 17 20:29:40 2011 +0800
+
+ add a new class - PathSet
+
+ PathSet is a specifized set of Path for fast searching.
+
+commit 0e2b86f9f80b2fd92b321492df1dcb1db4b7d750
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Aug 17 19:58:54 2011 +0800
+
+ Fixing isMyFormat() for MCELFObjectReader
+
+commit a9e63c955ab1765e349056c3b52bbe9414143f7d
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 17 18:03:42 2011 +0800
+
+ Offer reloc_iterator for MCLDContext.
+
+commit 38d447e04716c45e09a13a76968c31116ff7b0a0
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 17 17:52:22 2011 +0800
+
+ Add `has_addend' field into RelocationEntry.
+
+commit 881b7fb08a0c63a2fb077130709f3f9f2bc343df
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 17 17:34:35 2011 +0800
+
+ Make comment more clear for r_info.
+
+commit ffb5d1c298dfe2679fb07d05b6af6a31b9341220
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 17 17:25:45 2011 +0800
+
+ Determine the common relocation entry.
+
+commit 09ab13aee039f0f0cc2acef622f8d54aaa1ed5df
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Aug 17 17:09:20 2011 +0800
+
+ Let it no compilation error.
+
+commit a787aecfd812b6094a08cd42b9e618d6597c9e8b
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 17 13:36:47 2011 +0800
+
+ Remove a redundant function - Inputfactory::produce(StringRef pName);
+
+commit 93862ae3fc92ae806cdc40bd36999591e08bc744
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 17 12:03:28 2011 +0800
+
+ Move Relocation to ELFRelocation.
+
+ There is a design defect in MCLDContext which should have a
+ RelocationInfo reference or pointer, not an ELFRelocationInfo.
+ This version of MCLDContext will break scalability from ELF
+ to other format.
+
+ This code is not done yet.
+
+commit ee5b46e5350cb889d9e077daaf8cba888b8529d7
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 17 11:17:19 2011 +0800
+
+ Code cleanup for end-of-line space.
+
+commit e9b7421319e2b1dfe82dfc5dc534223f56417716
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 17 09:58:07 2011 +0800
+
+ We don't need `-relocation-model=pic' anymore.
+
+commit 18d8ec16c4a20a0ed58e7fc7e5667bceac9556e1
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 17 09:56:56 2011 +0800
+
+ enable MCLDDriver::normalize() in SectLinker::doFinialization()
+
+commit 240c7ba85ce5b6c4da79f81254a1f588a0fe210b
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 17 09:55:43 2011 +0800
+
+ bool trace() has been moved in GeneralOptions.
+
+ User can get trace() by calling MCLDInfo.options().trace()
+
+commit 365e42996b540e6780aadfdf3d2215b728ef7994
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 17 09:51:03 2011 +0800
+
+ In normalization, ContextFactory should produce Context by the path of mcld::Input. Not a empty path.
+
+commit d0c193c27afb258ac60e9a22b2f0df312ea230db
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Aug 16 21:01:24 2011 +0800
+
+ Add scaffolding of RelocationEntry.
+
+commit 2fcae7190c95cd1773d7b1ff809575242f2021f7
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Aug 16 20:32:23 2011 +0800
+
+ Move RelocationTable from MCLinker to MCLDContext.
+
+commit f4ddd568fc9716bd875556e5c4723a608fc9cfdd
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Tue Aug 16 20:23:38 2011 +0800
+
+ Take out -mcpu option from MCELFObjectReader.
+
+commit 4a881cdebf2200f61daa39a74b4981b6b485812f
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Aug 16 19:54:26 2011 +0800
+
+ Adding scaffolding of normalize()
+
+commit abdae55a774537da7d2275e2ca6b6768776e3739
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Aug 16 19:53:42 2011 +0800
+
+ Adding missing header files
+
+commit 248fffdc3060fde55c905718694c5cb3b3097ad6
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 19:18:12 2011 +0800
+
+ call InitializeAllTargetMCs() in main()
+
+commit ef001ac6fa6c57d193f33b14e47e5ba26777814a
+Merge: 9dd3ca2 d94fde2
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 18:10:16 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 9dd3ca28740de2e117d0cac00961b2d3ce36d829
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 18:05:50 2011 +0800
+
+ mcld::InputTree::bfs/dfs iterators advance more one step when it meets a Group.
+
+commit d94fde270f14e94c80ffebd6504c4044ce8c76e9
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 18:05:50 2011 +0800
+
+ mcld::InputTree::bfs/dfs iterators advance more one step when it meets a Group.
+
+commit ea3a2cdfc8a50dfa796718f9d79d2df27566514e
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 16:21:09 2011 +0800
+
+ Default bitcode is add in MCLDInfo.
+
+ MCLDInfo::bitcode can get the default bitcode that comes from LLVM.
+
+ default bitcode is inserted into MCLDInputTree with mcld::Input::Object
+ type and namespec - "default bitcode"
+
+ Of course, it's the first element of the input tree, and its attribute
+ is predefined.
+
+commit fcc4c583c5fbfe2137af9de68637851780700c4d
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 15:16:55 2011 +0800
+
+ Finish MCLDDriver::linkable()
+
+commit 5571053cbd3b56bcfd3ee567f3b8190be52e2f05
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 14:41:08 2011 +0800
+
+ AttrConstraint - The constraint of attributes.
+
+ Create a dedicated class for the constraint of attributes.
+
+commit 2a06832f716272d94c6a7823ec3c7998d62cb16b
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 11:40:53 2011 +0800
+
+ add the scaffolding of MCLDDriver::linkable.
+
+commit 489c64c9fb1004130de3341ffe40b4547a443eb7
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 16 11:04:52 2011 +0800
+
+ Fix a bug - all MCLDInput get the same attribute.
+
+ For easilier readable, I rename
+ MCLDAttribute -> AttributeProxy
+ AttributeBase -> Attribute
+
+ Since many mcld::Input shares common attribute, but AttributeFactory
+ can not assign the very identical pointer of attribute to different
+ mcld::Input when the pointed attribute will be modified in the future.
+
+ So, we let AttributeProxy hold the pointer of the attriubte. When we
+ change the attributes by proxy, mcld::Input will be affected and stick
+ to the same Attribute.
+
+commit 6b0fb384d0b103289d7c1f4f8cd53656c6879be3
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 15 23:11:41 2011 +0800
+
+ Luba changes the big design of MC Linker
+
+ 1. all factories are composed in MCLDInfo.
+ 2. ARMELFSectLinker is responsed for initialize Attribute and Factories
+ 3. MCLDContext is created by ContextFactory
+ 4. Allocator<DataType, ChunkSize> and Allocator<DataType, 0> means two different allocation timing.
+ 5. AttributeFactory is a Makov-chain of produced attribute
+ 6. AttributeFactory is hidden in InputTree and MCLDInfo.
+
+commit 54d196cecedb2b3557f3a486d177bd33f4ffe344
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 15 15:58:57 2011 +0800
+
+ Create the scaffolding of RealPath.
+
+commit 008073c80b760f43856e78cdae94a9ab71c0427a
+Author: luba <lubatang@gmail.com>
+Date: Sun Aug 14 03:19:39 2011 +0800
+
+ partial specification template of Allcoator<DataType, 0> is the run-time allocator.
+
+ Benefit from template partial specification on Allocator<DataType, ChunkSize>,
+ we use Allocator<DataType, 0> as the run-time allocator. The size of chunk of run-time
+ allocators is no longer a compile-time constant, instead, a run-time integer passed in
+ by constructor.
+
+commit 8723b5b5a8a5de9bd35e7d57edfaae5daa546425
+Author: luba <lubatang@gmail.com>
+Date: Sun Aug 14 01:33:36 2011 +0800
+
+ Change the roles of SectLinker, MCLDInfo, and LLVMTargetMachine.
+
+ MCLDInfo comprises of
+ - attribute factory
+ - input factory
+ - context factory
+ - the default output
+ - script options
+ - general options
+ - input tree.
+
+ The construction of MCLDInfo is target-independent.
+ Although MCLDInfo contains some target-dependent information, such as the
+ default attribute and the default script, the construction of these data
+ should be target-independent. Therefore, we move the construction of MCLDInfo
+ to LLVMTargetMachine.
+
+ SectLinker now is in charge of the construction of target-indepedent data.
+ Such as the default input file and the default output file. The target-
+ dependent data are contructed by the inheritor of SectLinker. Take
+ ARMELFSectLinker for example, target depedent data, like default link script
+ and the defaut attribute are configured in the constructor of ARMELFSectLinker.
+
+commit 95d1833f8c0b05fd5e309cf48f68cbd1c3ff6cd0
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Aug 15 21:30:37 2011 +0800
+
+ Removing verbose debugging information
+
+commit a6afc50cd2bad2b558b0c6272088fbec73849a5d
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Mon Aug 15 20:36:19 2011 +0800
+
+ Fixing MCObjectReader for new commits
+
+ The tool "MCObjectReader"
+ in "tools/MCObjectReader" works again
+
+commit 4e471a376dfd693a75820d724926476b638551a4
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 11 16:54:59 2011 +0800
+
+ Fix typo of RTGCFactory.
+
+commit eef6a26070c136d5d4e61a65a0bae725b8d9f9fb
+Author: luba <lubatang@gmail.com>
+Date: Thu Aug 11 16:48:36 2011 +0800
+
+ finish the implementation of RTGCFactory
+
+commit 2c535a11f7ed4a5bb25b6c4e369db7a5b5177598
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 11 16:41:39 2011 +0800
+
+ fix some typo error
+
+commit f8669a7161bf32007d69c80136509cbe297e2cbf
+Author: luba <lubatang@gmail.com>
+Date: Thu Aug 11 16:04:35 2011 +0800
+
+ Implementation of RTLinearAllocator
+
+commit 880b2a188c2a50b3b35f02b94db29a349dd322d6
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 11 15:32:15 2011 +0800
+
+ Add unittest of RTLinearAllocator.
+
+commit b35d1e81872946af73b58d61b71bcfeced2bf07d
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 11 15:24:56 2011 +0800
+
+ Take out the third parameter of RTLinearAllocator constructor.
+
+ Since `llvm::BumpPtrAllocator::DefaultSlabAllocator’ is private,
+ I think we don't need this default parameter.
+
+commit 63d05ca9bc638aae051c3b01e892a294c14bcb4b
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Thu Aug 11 14:42:47 2011 +0800
+
+ Add missing namespace llvm.
+
+commit 5d1c0c59490647636c558fc4690003c5fc6413f7
+Author: luba <lubatang@gmail.com>
+Date: Thu Aug 11 14:33:34 2011 +0800
+
+ Add a new Linear Allocator for run-time
+
+commit 89af031c2a52fda3ec7ede2e8343576334c2fee5
+Author: luba <lubatang@gmail.com>
+Date: Thu Aug 11 10:03:50 2011 +0800
+
+ allow MCLDInputTree insert a mcld::Input from outside.
+
+ In original design, MCLDInputTree should handle the construction of
+ mcld::Input. Now, we loose this constraint and let MCLDInputTree can
+ insert a mcld::Input from the outside world.
+
+commit 82e499de419fb359b23cd99a1aebd21b728ef318
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Aug 10 22:49:45 2011 +0800
+
+ Add some implementation of RelocData and MCLinker.
+
+ Sorry I cannot write a unittest, since MCLDInfo and TargetLDBackend
+ is not done yet, and MCLinker needs both of these.
+
+ This is a placeholder commit that tell others I have started doing
+ the relocation part. The function is not done yet.
+
+ BTW, the LLVM patch has a bug.
+ We use `delete' in MCAssembler.h, so we should use `include' instead
+ of forward declaration.
+
+ Be care of compilation warning!!
+
+commit 4c52ab1a94d11c1a427893a35c79f473e4c198c8
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 10 18:02:18 2011 +0800
+
+ attribute is attached on MCLDFile.
+
+ SectLinker can create attribute by the command line.
+ InputTree::Input can attach attributes
+ default attributes is set up by ARMELFSectLinker
+
+commit d44c009bdafa554d34cc6b4d8c521334f1589e72
+Author: luba <lubatang@gmail.com>
+Date: Wed Aug 10 11:20:01 2011 +0800
+
+ add a new class MCLDInput to replace original MCLDFile.
+
+ Since the information of input and of output are different, we separate
+ the API of MCLDFile into MCLDInput and MCLDOutput.
+
+ This also help MCLDInput to have a clear Type information.
+
+commit cf36b90a49f9b9ce0869b7886f6d80c2339ccf81
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 9 20:55:21 2011 +0800
+
+ attach attributes on MCLDFile
+
+commit dd6f24dc258ebab40990ca47c826f8d16732b65a
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 9 20:37:43 2011 +0800
+
+ create MCLDAttribute and AttributeFactory
+
+commit 28ede4c5b059684bd1781c7e0012470118c42d6e
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 9 19:10:36 2011 +0800
+
+ Luba is so stupid
+
+commit 302c02d95568158ea42b990e6e187cf6a3e68b2f
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 9 19:07:54 2011 +0800
+
+ Sorry, Luba is stupid.
+
+commit fe6427aa910cbe43ee40e7709e676ff1c2678d3e
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 9 19:00:41 2011 +0800
+
+ Sorry, Luba forgot to add GNULDBackend
+
+commit 578716cb391c50b1c30c8f2ece5d1fc63906545a
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 9 15:57:35 2011 +0800
+
+ add partial specific less<mcld::sys::fs::MCLDFile>
+
+ add this template functor to help map insert MCLDFile.
+
+commit 0fda962322d03f59b6c9541c702fc391b5724706
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 9 15:02:48 2011 +0800
+
+ create a new garbage collection factory - GCFactory
+
+commit 919ba478b7ac30c837d30868a11b4efbe0989669
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Tue Aug 9 14:46:19 2011 +0800
+
+ finish is_directory and exists
+
+commit 7ec21a0559f49e6bee6556e77a4475e761a7c431
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 8 20:37:20 2011 +0800
+
+ Cancel the target-dependent archive reader.
+
+ Since the difference of the formats of archive files are only on
+ the OS type, not on target, we remove all target-dependent archive readers.
+
+commit 8d7f351964693b4e4ab5cd56d0d604b438eb7ddf
+Author: Duo <pinronglu@gmail.com>
+Date: Mon Aug 8 20:06:55 2011 +0800
+
+ Add a test case for class InputTree at file MCLDInputTree.
+
+commit 7ff101919738cac6ac7b865b8205a9a8156d4c6a
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Mon Aug 8 17:59:09 2011 +0800
+
+ Fix scaffolding of class MCLinker.
+
+ There are still some functions not implemented yet.
+ But this won't bother the regression test.
+
+commit 8791439a87a605a510e818e88e07c3110d63539c
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Aug 4 19:21:45 2011 +0800
+
+ Add DFSIterator and BFSIterator of InputTree.
+
+ Fix a bug : BinaryTree::join() runs the opposite direction when join a new node.
+
+commit 07efe81e55fed84e85aa7d625579d2d1ba8b71ff
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Aug 2 21:44:41 2011 +0800
+
+ Fix a bug :
+ Leftward => Downward => Inclusive
+ Rightward => Afterward => Positional
+
+ ROOT (right == self == end)
+ /
+ begin
+ / \
+ A B
+
+commit 139b56db6f0a1e66a02406607ab4e74a73cd2cff
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Aug 2 20:40:15 2011 +0800
+
+ Fix the bug - self assignment of BinaryTree and TreeImpl
+
+commit 29cfb44b90dd8a1a0bfbda1e2ab12b7fff47d2fb
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 20:28:50 2011 +0800
+
+ add testcase LinearAllocator and FactoriesTest.
+
+commit 27096837de3748c003e968c1e1d5582b37dab15c
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 20:27:04 2011 +0800
+
+ fix a bug coming from LLVM. LLVM StringRef::size does not contain '\0' character.
+ Therefore, if we use strcpy, we always copy lack of the last charactor.
+
+commit ec71a6ec68b282b3dc442f7ddc0ca60cc5542f6b
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 19:42:06 2011 +0800
+
+ Fix a bug - NodeFactory object can not delegate itself.
+ If the object detect this situation, do nothing.
+
+commit fb0c7a4c0e7aa078647d57a5e67e0b3d2ac9d558
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 18:59:21 2011 +0800
+
+ Fix a bug in LinearAllocator.
+ If there are no chunks being initialized, end() will segmentation fault by access m_pCurrent->bound.
+
+commit 4c207da72add8936f5ba396473560e00170a8a7c
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Aug 2 17:59:49 2011 +0800
+
+ Fix bugs in BinaryTree
+ 1. TreeImpl::summon calls the wrong function
+ 2. Move NodeFactory::iterator function to public
+
+commit 7577359a7b01b50f673a43522502a5b1f2f49fdd
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Aug 2 17:34:06 2011 +0800
+
+ Fix a bug - compiler can not specify template function TreeBase::move()
+
+ - incorrect template argument type - template<size_t DIR> move()
+
+commit 1d3de703a7df46b3d49526e20fe81935f8cd8eec
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 17:22:48 2011 +0800
+
+ remove redundant message in TreeAllocator
+
+commit 1133f8acdae1cad09c3a0756b94c49ffa9aa68ca
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 17:19:31 2011 +0800
+
+ Fix a bug in the LinearAllocator
+
+ Bug - Iterator never goes to the end()
+
+commit ab35d771eda74e000ddb88bfe5736dc64fb3d88d
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 13:53:42 2011 +0800
+
+ Fix bugs in LinearAllocatr
+
+ 1. the conditions of equivalent comparison is insufficient. We should
+ also compare the positon of iterators
+
+commit c25906995a913dba516a560f9a5b5d9852a7cec3
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Aug 2 10:56:54 2011 +0800
+
+ add directory, and fix some basic syntax bugs in MCLDDirectory.
+
+commit a247cb32d8c4ffe3489d8acda41c9b0eaf602ac8
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 10:45:11 2011 +0800
+
+ Add host-specific Path libraries
+
+commit 8d7d3c5f720db801e3bac0c02b821b0b23da56bb
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 10:45:11 2011 +0800
+
+ Add host-specific Path libraries
+
+commit 105397d60a3313e59f71951462133bfd0ea378f6
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 10:39:34 2011 +0800
+
+ add new class - Directory
+
+commit 2b694ac4ee4f8dbe89869fae53f4a0bdbd10e424
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Aug 2 10:20:24 2011 +0800
+
+ initialize MCAsmInfo for LLVM 3.0svn's demand
+
+commit 27fd0e6462f1382880ba0dcd7e143f962a52d914
+Author: luba <lubatang@gmail.com>
+Date: Tue Aug 2 10:18:10 2011 +0800
+
+ fix a bug - m_pRoot is forgetten to be initialized.
+
+commit 02f62cf3e15dcd21ab3ba544d5cd6ac70978fdc7
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 1 20:57:37 2011 +0800
+
+ Check host. If host is unix, set LLVM_ON_UNIX=1. On the other heand, if host is win-32, set LLVM_ON_WIN32=1.
+
+commit 2bf6cc71e2b7cd1617f89a0330cc2d96c5404db1
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 1 18:58:03 2011 +0800
+
+ move create function of MCLDInfo out of SectLiner, and let it work like MCAsmInfo.
+
+commit 577ae17fa105f9e01d93df344d30d0936c4f2a02
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 1 13:32:32 2011 +0800
+
+ add `-t' argument on the command line.
+
+commit af25232ed7848ff7e4ad7029311dc693eccf0fa7
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 1 12:30:10 2011 +0800
+
+ move out traits from TreeBase.h
+ extract common code of LinearAllocator::iterator and const_iterator to DataIteratorBase
+
+commit bfe60efa3a076ced231e61eff65b80728966f90f
+Author: luba <lubatang@gmail.com>
+Date: Mon Aug 1 10:40:07 2011 +0800
+
+ add iterator for each data in the Allocator.
+
+commit 6ccff786637f1f0367c765bf9e9019c337a7b761
+Author: luba <lubatang@gmail.com>
+Date: Fri Jul 29 12:01:54 2011 +0800
+
+ make binary tree and allocators are uncopyable.
+
+commit 2554fcf2b1791d4664718f273892686c4c8b7f7a
+Author: luba <lubatang@gmail.com>
+Date: Fri Jul 29 11:50:46 2011 +0800
+
+ remove the DataType construction in Binary Tree.
+
+ Data construction should be handled by the user of binary tree, not
+ tree itself.
+
+commit 557270c556ddbdf3719ff32c552378ec85ef5bf6
+Author: luba <lubatang@gmail.com>
+Date: Fri Jul 29 02:05:11 2011 +0800
+
+ A syntax-correct BinaryTree
+
+commit d9b60663c5dccde749adddb058086d51202b5a15
+Author: luba <lubatang@gmail.com>
+Date: Fri Jul 29 01:15:19 2011 +0800
+
+ - Finish LinearAllocator
+ - Finish STL Compatible Binary Tree
+ - Remove useless MCLDBackend file
+
+commit 43835d5a177724b3c16173fad79164824f25225b
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 28 14:31:08 2011 +0800
+
+ finish the implementation of linear allocator.
+
+ linear allocator is a two-phase memory allocator.
+
+commit 0a8f0553b1edcf8bd11d20a2a29318d11fa3efaa
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 28 10:59:04 2011 +0800
+
+ Add a new directory - ADT to store abstract data types.
+
+commit 715d7ed9b72c168a7841ba31994022c6ed708677
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 27 22:18:25 2011 +0800
+
+ finish the scaffolding of binary tree
+
+commit 40df3d49c5facf0bf8f1002ba3c597244cc33f28
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 27 20:36:45 2011 +0800
+
+ finish the scaffolding of InputTree, which be used in SectLinker.
+
+commit bfdb6d770ca14e070131a9ead11088086d28f341
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 27 15:14:24 2011 +0800
+
+ change MCLDInfo's member from pointers to reference.
+
+commit 7d0f04541d188135cca533a043a4a0bb37d51a01
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Jul 28 13:17:20 2011 +0800
+
+ a test for BinTr[Cee
+
+commit cb971398cf663efc4e07f96f1e1aee70ad561ecf
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Wed Aug 3 22:20:50 2011 +0800
+
+ Adding a new tool "MCELFObjectReader"
+ Seeing tools/MCObjectReader/README for the details
+
+commit cc3be0820ab0296171757db207612373de627a91
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Wed Aug 3 22:18:36 2011 +0800
+
+ Adding parts of implementation of MCELFObjectReader
+ It includes readObject() & dump()
+
+ MCELFObjectReader reads entries in Symbol Table
+ It stores entries with MC data structures
+ such as MCSectionData & MCSymbolData
+
+commit 6ef3ae35c0c7939ec7be65ded4392bfbd1105556
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Wed Aug 3 22:17:17 2011 +0800
+
+ Updating LLVM.diff.patch for MCObjectReader
+ LLVM.diff is obsolete here, it should be updated by someone
+
+commit b0aa341084d4dbf0520169c3697dbe6c9ae16921
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 27 14:23:13 2011 +0800
+
+ add Tree of inputs in the MCLDInfo
+
+commit ca878a61afbf3564d616d5419649cda5a740231f
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 27 10:06:45 2011 +0800
+
+ change the name of method merge to join
+
+commit 9340a5219aeda55e2dee4ca3d060f6b264e8e58b
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 26 21:48:07 2011 +0800
+
+ new an abstract BinaryTree
+
+commit 3c34067b2c229797d9f8ec8ac8d529e427ae532d
+Merge: 9e54bab c1466b6
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 25 16:57:18 2011 +0800
+
+ Merge branch 'master' of upstream
+
+ Conflicts:
+ include/mcld/MC/MCLDInputFileList.h
+ lib/MC/MCLDInputTree.cpp
+
+commit 9e54bab294d03e22510e0b6c8ffc20f6b5fbcb5f
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 25 16:46:09 2011 +0800
+
+ add a new sub-class - SectLinker::PositionDependentOptions to handle the position of options on the command line.
+ SectLinker can traverse the list of PositionDependentOptions and push each option into the tree of input files.
+
+commit 3b33658b41bf31157199aa55ab679e68686a966b
+Author: luba <lubatang@gmail.com>
+Date: Fri Jul 22 00:04:20 2011 +0800
+
+ describes the classes of Command line options.
+
+commit c1466b6987aae2ee090b9c4b01de6d2719290320
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Fri Jul 22 14:37:16 2011 +0800
+
+ Creating patches for "patch" command & "git apply"
+ All patches are for LLVM r135569
+
+ For building MCLinker project,
+ Choosing one of them is enough.
+
+ Applying patches from $(LLVM_ROOT)
+
+commit a64e424c39585edc7baf4641b56001a4348814c8
+Author: Nowar Gu <nowar100@gmail.com>
+Date: Wed Jul 20 14:01:55 2011 +0800
+
+ Update patches.
+
+commit add2cb3dc1c70ae32f5fd9055f3bd6bcc149bcd8
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 20 13:57:40 2011 +0800
+
+ fix error : lack of destructor of MCLDInputFile::Node
+
+commit d7386c24bf457606647b8aa2546d329f047fb65d
+Merge: 70c2f5f 9d9c56b
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 20 09:17:24 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 70c2f5f549d6a8a3d3aae0dde20028d53a87a3c3
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 20 09:15:22 2011 +0800
+
+ change the algorithm of MCLDInputFileList creation.
+
+commit 9d9c56be8967adabde6fc2b0bd2a865aadb19d0a
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 19 21:48:21 2011 +0800
+
+ write the basic idea about how to get position of input options from command list.
+
+commit 0acf73aecc22ee6b670443f205367ea04b5b71c2
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 19 21:08:08 2011 +0800
+
+ add four testcases for exists and is_directory
+
+commit 7d499957063a2fb5ec5aa21ae3823a6afa7de533
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 19 21:07:43 2011 +0800
+
+ let -dB not be necessary
+
+commit 7fd5edc2908ea0e0a7f247e0040ea405b4488f6d
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 19 20:54:14 2011 +0800
+
+ complete parser<mcld::MCLDDirectory>
+
+commit a99fcd8701a961735f73c5e4282705e3482d8046
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 19 19:44:24 2011 +0800
+
+ Add destructor of Path
+
+commit bc93dd7c35e4bd37e8aeb9202a09e2005a7440d4
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 19 19:43:46 2011 +0800
+
+ add a new testcase for mcld::sys::fs::Path
+
+commit d49d5d75f05beae037af960b146f4310de3df9b0
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 19 19:14:21 2011 +0800
+
+ 1. add Path library for MC Linker
+ 2. let CommandLine library can parse Path, Directory and MCLDDirectory
+ 3. refine SectLinker
+
+commit b37451de4e030adb22a06d6e462ec94fd9602aca
+Author: Duo <duo@duo-laptop.(none)>
+Date: Tue Jul 19 16:15:06 2011 +0800
+
+ delete unnecessary file.
+
+commit c76959008f9ca054fe42ade590b42d452812f702
+Author: Duo <duo@duo-laptop.(none)>
+Date: Tue Jul 19 16:02:43 2011 +0800
+
+ refine the code of MCLDInputFileList
+
+commit c5724a63c306b1261201cd0f7d12885f8ad134a8
+Author: Duo <duo@duo-laptop.(none)>
+Date: Tue Jul 19 14:15:15 2011 +0800
+
+ Change the data structure of MCLDInputFileList from graph to binary tree.
+
+commit d46e90b0d55de5cd04801f691b69053a94e702d6
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Jul 19 13:42:29 2011 +0800
+
+ patch for LLVM. ${llvm_src}$patch -p0 < ${mclinker}/patch/LLVM.diff
+
+commit 2e7bb382da1c4c0f5a2ee69814655f786e8f6802
+Author: Duo <pinronglu@gmail.com>
+Date: Mon Jul 18 22:18:41 2011 +0800
+
+ Change the interface of MCLDInputFileList::iterator.
+ Remove member function insert and delelte ,and add to MCLDInputFileList.
+
+commit 2af10e40c60f811dcfdf92fcb74230b50149c5dc
+Author: Duo <pinronglu@gmail.com>
+Date: Sat Jul 16 20:13:15 2011 +0800
+
+ build scaffolding of class MCLDInputFileList
+
+commit 2b562e2c563066246ad140c83635ac38551260e0
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Fri Jul 15 10:27:47 2011 +0800
+
+ Removing readers from Target directories
+ Using MCTargetObjectReader as target-dependent reader
+
+commit 127ac107c998d8fc39d61fc7ad681999d2dd2425
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 14 17:44:25 2011 +0800
+
+ remove attribute from MCLDFile
+
+commit 9acc1afca6cc15e60e65430b5e3eb2b30b58f011
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 14 17:28:16 2011 +0800
+
+ add sysroot functions in MCLDInfo
+
+commit 27e7620fdfd50dd95adfd5992d00fe8fe89181b2
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 14 16:48:25 2011 +0800
+
+ refine the indent of MCLDFile to fit LLVM style.
+
+commit d032e2fff236158f58dcbd5f5432aed656b25c79
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 14 16:20:33 2011 +0800
+
+ add SearchDirs class.
+
+commit c10c150e630f18c3baf84d349895926cf4cd410f
+Merge: 4f21432 4975671
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 14 16:13:20 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 4f21432c245e0a7fba6b484db5395308ac002482
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 14 16:09:46 2011 +0800
+
+ 1. add Support directory to deployment
+ 2. add a new flag `-dB' to indicate default bitcode.
+
+commit 49756716c3587b7867c03fa3180f6d0f9d7ab2d1
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 14 16:09:46 2011 +0800
+
+ 1. add Support directory to deployment
+ 2. add a new flag `-dB' to indicate default bitcode.
+
+commit 88c40df44a703822110da88f03a1291add5f92a9
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 13 18:41:10 2011 +0800
+
+ add a new class MCLDFileTree using to decide the linking order.
+ Delete unnecessary component of MCLDFile.
+
+commit 82c826db4de17b7ead4d116baeed0489320fd1e5
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 13 18:09:03 2011 +0800
+
+ add a "should be failed" case into search_patch case
+
+commit 7d5ecb8a2e9947e74cd82eb7758da540f4b5663f
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 13 15:52:43 2011 +0800
+
+ fixes a bug of undefined StringRef. We forget to expose llvm namespace scope to him.
+
+commit 76c6111032f0a1efc644002c7e40d0ce0eff4308
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 13 15:19:46 2011 +0800
+
+ add the basic interface of MCLDDriver for input files being listed in command line
+
+commit 21ab372cf2373743e6653ccff05daeb12035531e
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 13 15:06:12 2011 +0800
+
+ add a new regression test for search path of MCLinker
+
+commit e9052e14e5dfba835a6c0643be6a7b48bfad5185
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 13 15:05:32 2011 +0800
+
+ make the output format of regression test pretty.
+
+commit 6eacfa06a1301bd54f7f290726d11c047a53a520
+Author: luba <lubatang@gmail.com>
+Date: Wed Jul 13 12:34:39 2011 +0800
+
+ connect SectLinkers and MCAsmObjectReader by default bitcode.
+
+commit 70b24badc0d4ecf72b4a8ca61256bdabff98cd50
+Merge: 08a7dc6 1f35ba1
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 13 12:01:49 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 08a7dc684e98d91aeffda8468dfd116e7c291dd8
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 13 11:50:32 2011 +0800
+
+ build scaffolding from SectLinker to MCLDDriver.
+ Associative ARM target SectLinker is also built.
+
+commit 1f35ba1650b309d8a07f599b978d329814bf6ef5
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 13 11:50:32 2011 +0800
+
+ build scaffolding from SectLinker to MCLDDriver.
+ Associative ARM target SectLinker is also built.
+
+commit 0fb90820592c45c91458fd5d8285b7dd1314b41e
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Tue Jul 12 17:40:41 2011 +0800
+
+ add empty class of MCLDInfo.
+
+commit 7f85da66537af515455074306f98a778656896f3
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Jul 12 14:20:04 2011 +0800
+
+ Remove files that can not be compiled well
+ MCFragment
+
+commit 15fcc51a77f33d12ac6a464041fbf15b016b4ae4
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 12 14:07:17 2011 +0800
+
+ add patch to llvm::MCAssembler
+
+commit b89166ef732ac3e08e831f81b00459b68b234310
+Author: Duo <pinronglu@gmail.com>
+Date: Tue Jul 12 13:55:45 2011 +0800
+
+ Merge Makefile.am
+
+commit dfe026a989117000fde23bc768d2bf397cff62f3
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 12 12:13:19 2011 +0800
+
+ remove AsmPrinter from SectLinker.
+
+ Every MachineFunctionPass must be added into PassManager before calling MachineFunctionPass::runOnMachineFunction().
+ However, in our original design, AsmPrinter is called by SectLinker. AsmPrinter is not added into PassManager and can not be initialized correctly.
+ Therefore, we move AsmPrinter out from SectLinker, and add AsmPrinter back to PassManager.
+ SectLinker gets the result of AsmPrinter by the references of common data - MCLDContext.
+
+commit 246dc88093431e928c882e516f0b16f365d00359
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 12 11:29:20 2011 +0800
+
+ redirect assembler to MCAsmObjectReader
+
+commit 34a7c5f905f1f289664699ff5aba649fc205b6d3
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 12 11:28:46 2011 +0800
+
+ remove invalid testcases
+
+commit 423d4a4291568f0e0e8b2008b2e494eea564747b
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 12 09:52:56 2011 +0800
+
+ add the scaffolding of class MCAsmObjectReader.
+
+commit 8416f02ae41a056052a0daa2edfcb29b9d2e017c
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 11 17:36:19 2011 +0800
+
+ Follows the most new LLVM svn3.0. refine the patch
+
+commit 8de15e5bb9e6f993443c47ded878a829fbc8de36
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 11 14:23:25 2011 +0800
+
+ add a new regression test - file.
+
+ `file' make sure the output can be examined by `file' command.
+
+commit 7cabe6765817c51cb4ef44b9f597b772ccb5be51
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 11 14:09:19 2011 +0800
+
+ clean all temporary files while tearing down.
+
+commit 7c8fb9792c6212b1324be83b24df33149637b457
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 11 13:45:10 2011 +0800
+
+ add -typefile=asm, obj to MCLinker.
+
+ Now, MCLinker has full ability of llc.
+
+commit 7e292189aa7df0f3a129d769b5040b15084a252c
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 11 13:43:41 2011 +0800
+
+ add setup()/teardown() functions in regression test. Rename the majar test function as testcase().
+
+commit 1530b82d3118b56ee0833bfd9ae809d39bf9edfe
+Author: Duo <pinronglu@gmail.com>
+Date: Sun Jul 10 22:31:06 2011 +0800
+
+ scaffolding of MCObjectFile : MCSectionData Proxy
+
+commit 29a64bcce7ab848c1aa0fa33904b22a147531233
+Merge: 1318d11 87bf885
+Author: Duo <pinronglu@gmail.com>
+Date: Sun Jul 10 22:23:11 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 1318d111fa3c782fd1c9ef36e787f24bcc169a1e
+Author: Duo <pinronglu@gmail.com>
+Date: Sun Jul 10 22:19:51 2011 +0800
+
+ scaffolding of MCObjectFile : MCSectionData Proxy
+
+commit 87bf88552b388c202aeeab97f1b0e19458a45444
+Author: Luba Tang <luba@LubaSite.site>
+Date: Sun Jul 10 02:59:57 2011 +0800
+
+ remove some files that should not be pushed into git repositry
+
+commit d718be5216f28b5e3219a614779fb1981558f3a6
+Author: luba <lubatang@gmail.com>
+Date: Sat Jul 9 21:43:21 2011 +0800
+
+ create SectLinker in LLVMTargetMachine
+
+commit d79eeec475ee7c58b33b06de2e9ae0408ee68a17
+Merge: 578c1a2 fdd7db8
+Author: luba <lubatang@gmail.com>
+Date: Sat Jul 9 20:59:15 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 578c1a299aefbbc1b0b0e670e8ee95ecfce1e373
+Author: luba <lubatang@gmail.com>
+Date: Sat Jul 9 20:47:21 2011 +0800
+
+ register target-dependent SectLinker into mcld::TargetRegistry
+
+commit fdd7db8b56b8011b8fdcbef589f30169fe30cfc8
+Author: Duo <pinronglu@gmail.com>
+Date: Sat Jul 9 00:17:56 2011 +0800
+
+ Modify MCObjetfile.cpp and MCObjectFile.h
+
+commit b4bea44a7996f7c7c066a20855c56bb536f178bc
+Author: luba <lubatang@gmail.com>
+Date: Fri Jul 8 20:13:26 2011 +0800
+
+ add regression test
+
+commit 5e0041bd6002e192cd4cc50dfe2e50b733735a22
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Jul 7 21:10:20 2011 +0800
+
+ Modify mclinker/debug/Makefile.am : add MCObjetFile.h MCObjectFile.cpp
+
+commit e14640dcb45f5803b5cd88be53b6af011c5f206e
+Merge: 272e6f4 f4674cb
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Jul 7 20:47:41 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 272e6f4773d661464eb2cbac2a0dee6741931d18
+Author: Duo <pinronglu@gmail.com>
+Date: Thu Jul 7 20:39:42 2011 +0800
+
+ Scaffolding of MCObjectFile : Finish Iterator
+
+commit f4674cb222ae9f42b4979311133bc05bf602355b
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 7 18:22:36 2011 +0800
+
+ Finish scaffolding of all readers and writers.
+
+commit f04d1ce24a52f26ed32792bb4252c2de86ef8571
+Author: luba <lubatang@gmail.com>
+Date: Thu Jul 7 11:50:20 2011 +0800
+
+ add_class can add target-dependent files into source directory.
+
+commit 0abe2a2f36291f1240b139e73fdf03592e180675
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 6 23:50:47 2011 +0800
+
+ Test case for MCArchiveReader/MCObjectReader.
+
+commit 237df5f6c266e18198b76f880fd5b265e4c5e7a9
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 6 20:42:31 2011 +0800
+
+ Build the interface of ELF Archive/Object readers.
+
+commit 81182a67a348361bd882c66bf55ccfe0d3a2b112
+Author: Duo <pinronglu@gmail.com>
+Date: Wed Jul 6 20:38:18 2011 +0800
+
+ build the abstract interface of ArchiveReader and ObjectReader
+ Let TargetLDBackend owns the function pointer of the constructor of readers
+
+commit c2679593c1cb7849df679fc920633f514c93802c
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 5 22:18:41 2011 +0800
+
+ make the scaffolding for createTargetLDBackend.
+
+ ARM's createTargetLDBackend has not implemented yet.
+ The result is assert in
+ MCLinker: ../lib/Target/ARM/ARMLDBackend.cpp:25: mcld::TargetLDBackend* mcld::createARMLDBackend(const llvm::Target&, const std::string&): Assertion `0 && "MC Linker for ELF system has not been supported yet"' failed.
+
+commit 8c80a4949dbed040cdc2df8258487860491d60e9
+Author: CIT
+Date: Tue Jul 5 15:12:23 2011 +0800
+
+ LLVM version 3.0svn changes the API about llvm::TargetMachine.
+ downstream with the macro LLVM_VERSION
+
+commit d7d4560bf7eadb9e23bedb9248d84aa73911e21f
+Author: CIT
+Date: Tue Jul 5 15:08:53 2011 +0800
+
+ pass LLVM_VERSION into source code.
+
+ add -DLLVM_VERSION=${LLVM_VERSION} in the compilation command line
+
+commit 5bb8e229139994709c200c1b9d753d58fbadbb95
+Merge: 16c4c90 128b419
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 5 14:57:21 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 16c4c901b88b6475483360312359f84cf23b9291
+Merge: de71d4e bccffcd
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 5 14:53:13 2011 +0800
+
+ Merge branch 'master' of upstream
+ add ARMTargetInfo
+
+commit 128b419b7688ddef6c2ae9bcee7201932112307c
+Merge: de71d4e bccffcd
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 5 14:53:13 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit de71d4e3110f16b739cc7581050baa0d3d1770d5
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 5 12:29:09 2011 +0800
+
+ Initialize mcld::TargetMachine
+
+ mcld::TargetMachine has right mcld::Target
+ mcld::TargetRegistry can find corresponding mcld::Target
+ mcld::Target::createTargetMachine can create mcld::TargetMachine
+
+commit bccffcdcc2c1dd854bbcca2a64051fb1e6dda3e4
+Author: luba <lubatang@gmail.com>
+Date: Tue Jul 5 12:29:09 2011 +0800
+
+ Initialize mcld::TargetMachine
+
+ mcld::TargetMachine has right mcld::Target
+ mcld::TargetRegistry can find corresponding mcld::Target
+ mcld::Target::createTargetMachine can create mcld::TargetMachine
+
+commit 4d1d9b34b89b942918a410ca186b2f85fd3e1122
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 4 21:42:30 2011 +0800
+
+ Finish adapters of mcld::TargetMachine, mcld::Target, and mcld::TargetRegistry
+
+ Now, mcld::Target::createLDBackend works.
+
+commit fbb629cace23e37adba86623ab44380103f822be
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 4 17:53:10 2011 +0800
+
+ Add a new alias mk.
+
+ command `mk' can make MCLinker in any level of directory.
+
+commit f3b5cec6bc19a8d19a83767a9ccdfcfd0def7d00
+Author: luba <lubatang@gmail.com>
+Date: Mon Jul 4 12:26:43 2011 +0800
+
+ add Initialize##TargetName##Linkers() and corresponding InitializeARMSectLinker() functions.
+
+commit b514f27c60b1d5cc0b65a3a981511fe73b43a1db
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 30 21:05:56 2011 +0800
+
+ add m4 macro to specify targets when executing `./configure' script.
+
+ * Enumlate all targets in include/mcld/Config/Targets.def
+ * Enumlate all linkers in include/mcld/Config/Linkers.def
+
+commit 7e3056811244ca3429dc73ff038f3e906cccf5c2
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 30 14:26:21 2011 +0800
+
+ Add implementation of Target
+
+commit 41d758f2ee25665de835c54b44a9ae3cb2c9a8d0
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Sun Jun 26 21:08:07 2011 +0800
+
+ Add a core function "getMCInstruction"
+ to MCELFObjectReader
+
+ Which is based on MC Disassembler
+
+commit 95c6fc7a8dd0ecffa27b507f183dbac2c25e2769
+Merge: 7cdd6dd 514c75a
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 17:35:22 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 7cdd6dd3dea91c22fbcf36617bdf6386b7d8650e
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 17:34:43 2011 +0800
+
+ finish a basic scaffolding of mcld::TargetMachine
+
+commit 41303498bcf209f8596dd49bce5fa6d3caddc920
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 17:13:27 2011 +0800
+
+ a new patch for LLVM. Move function LLVMTargetMachine::setCodeModelForStatic() to public field.
+
+commit 514c75a4c4db94348a9e684c1c0930ab0412c172
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jun 23 14:28:36 2011 +0800
+
+ Add MCLDCommand header and footer
+
+commit 48e02772557403c2323a588fc28eb28c0e6bc19c
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 13:29:41 2011 +0800
+
+ adds new UML object diagram of MCLinker
+
+commit 8c33cc12e4e98024487c90e5e8377932eeb3e7d9
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 12:05:44 2011 +0800
+
+ fix a typo error in header template.
+
+commit 6d6349e91c6c38b2f10383ef3ea040a52dcb43b1
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 12:01:08 2011 +0800
+
+ Add header and footer in MCLDDriver
+
+commit 20e91885a70cb4114393ae0267d15899b47914dd
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Thu Jun 23 11:44:17 2011 +0800
+
+ Add MCLDDriver header file
+
+commit f1f330d1d9da0bf6550f888442ddc85d513609a1
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 11:23:58 2011 +0800
+
+ Add mcld::LLVMTargetMachien to do object adapter of llvm::TargetMachine
+
+commit 37b5687318121493422c07adff2b448798ef21f6
+Author: luba <lubatang@gmail.com>
+Date: Thu Jun 23 09:30:27 2011 +0800
+
+ change debug macro from -DDEBUG to -DMCLD_DEBUG.
+
+ Google test also has a macro -DDEBUG. In order to avoid from conflict, we rename our own macro.
+
+commit 828928ec7d8fa497003411b617e189bc10dd078b
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jun 22 17:53:41 2011 +0800
+
+ Update Makefile.am for LLVMTargetMachine
+
+commit bfc89176b49a6634fd29cf636bfd34972b1a45b3
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jun 22 17:47:53 2011 +0800
+
+ Rename lib/CodeGen/TargetMachine.cpp
+ to lib/CodeGen/LLVMTargetMachine.cpp
+
+ Avoid confusion with lib/Target/TargetMachine.cpp
+
+commit fa383b819cfce9fe343e6087cd41e27e0e6ae8c0
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Jun 22 16:51:02 2011 +0800
+
+ LLVM 2.9 (stablest) and LLVM 3.1 (newest) have different API.
+ In order to run on these versions, I add new macro - LLVM_VERSION
+
+ In LLVM 2.9, LLVM_VERSION is 2, and in LLVM 3.1, LLVM_VERSION is 3.
+ Developers can separate code into different versions like that:
+ {{{
+ #!cpp
+ #if LLVM_VERSION > 2
+ ... code in LLVM 3.1 API...
+ #end
+ }}}
+
+commit edb0c63e826178304b75809440b517bf6022d560
+Merge: dc2bc00 1345fe4
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Jun 22 16:39:26 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 1345fe46fc9ff6daf7aaabb413a01e15b8204d29
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jun 22 15:40:16 2011 +0800
+
+ Add LDBackend creation and registry
+
+commit dc2bc00d94472ddb8af699c5d81381c876cba689
+Merge: 3527e74 3a57e65
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed Jun 22 15:07:05 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 3a57e65fe1d7728f317bd14bd4f05bb9fa6995a3
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jun 22 11:54:55 2011 +0800
+
+ Add createLDDriver
+
+commit 71c5abea9295a59b8f1045ba5ce31bf4355358f9
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jun 22 11:48:43 2011 +0800
+
+ Comment createStreamer
+ Add LDDriver
+
+commit 30401a99499413bdfbf0ea081678c54b44322cdd
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Wed Jun 22 11:44:48 2011 +0800
+
+ Adding MCLDDriver stub
+
+commit eb1bb9813e95c98dbcc449c019ecff824a353ca1
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jun 21 21:50:17 2011 +0800
+
+ Adding implementation of TargetLDBackend
+ Which is similar to TargetAsmBackend
+
+commit 3527e74f6760a8f41c1c08412197d5532791d063
+Merge: 937032d e3039fb
+Author: Luba Tang <lubatang@gmail.com>
+Date: Tue Jun 21 21:40:54 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit e3039fb8e51d11664895570362e2bc99724770ea
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jun 21 21:34:04 2011 +0800
+
+ Create TargetLDBackend.cpp
+ Move TargetLDBackend.h
+
+commit 82fc3f57dcc678ed026a5da516b3095e333b53b0
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jun 21 19:25:40 2011 +0800
+
+ Adding LDBackend header files
+
+commit ed5708821020fc1a5dcf627e9860174f2bce4dd6
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jun 21 19:20:23 2011 +0800
+
+ Adding implementation of addPassesToEmitFile
+
+commit 9638fe989a26ecf4418044174234cc376e666013
+Author: Jush Lu <Jush.Lu@mediatek.com>
+Date: Tue Jun 21 16:59:05 2011 +0800
+
+ Removing merge legacy
+
+commit 937032de3e1724326c61f0d3102a531eebda0af3
+Author: Luba Tang <lubatang@gmail.com>
+Date: Tue Jun 21 00:26:49 2011 +0800
+
+ fix a typo error
+
+commit 2cdd7e52e24f3d60cdb4655f04e4840f8502ad7b
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 17:37:38 2011 +0800
+
+ Change the name of project - from bold to MCLinker
+
+commit 194ff3bb3abdaac1a8751046e986b91435bef5e2
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 17:30:50 2011 +0800
+
+ Move addPassToEmitFile from extern "C" to namespace mcld
+
+commit 31d2211b9c6fdcc9c6bec2e3357bc2da1f18585e
+Merge: 402686b 9668907
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 17:08:47 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 402686b6034c87add9d85d935880bcbfe02910e8
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 17:07:19 2011 +0800
+
+ Change the deployment
+
+ * from lib to lib/MC, lib/CodeGen, lib/Target
+ * from include to include/mcld/MC, include/mcld/CodeGen, include/mcld/Target
+
+commit 96689072ec13ef8d24a1bf2cb64698edabcaa2bd
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 16:40:39 2011 +0800
+
+ Copying ELFObjectWriter into ELFLDWriter
+ Replacing "ObjectWriet" by "LDWriter"
+
+commit 3a0c8ef7e635f7a01464e408071298c6a843cd85
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 16:24:34 2011 +0800
+
+ change the template files:
+
+ *. project name - MCLinker
+ *. namespace - mcld and mcldtest
+
+commit ba07f54285b901e7307cd5e943a6858f73fe4d4c
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 16:19:10 2011 +0800
+
+ Adding MCELFLDTargetWriter
+
+commit ce739351767ee26d46f840c165a9c3e1ac3983c3
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 16:18:55 2011 +0800
+
+ add virtual function addCommonPasses() to class TargetMachine.
+ Original, it's a private member function of LLVMTargetMachine.
+
+commit 4ebe8ec401b05c7532db36aa309d23c5b4612e34
+Merge: 2055a07 6dd7074
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 15:59:37 2011 +0800
+
+ Fix a stupid typo error
+ Conflicts:
+ src/main.cpp
+
+commit 2055a07192fca451b24da12e092bba2c477da7ea
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 15:52:55 2011 +0800
+
+ FileType in GetOutputStream() should be compared with mcld::CGFT_XXXFile, not old TargetMachine::CGFT_XXXFile
+
+commit 6dd7074906b6965d56cd891db270aed480a6fa55
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 15:52:55 2011 +0800
+
+ FileType in GetOutputStream() should be compared with mcld::CGFT_XXXFile, not old TargetMachine::CGFT_XXXFile
+
+commit e12362af59a508ca61c7e8f88356483db954528a
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 14:35:16 2011 +0800
+
+ Add a README of `patch' directory.
+
+commit a079b86e5d316641416d43127774de21d5e028e0
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 14:28:43 2011 +0800
+
+ Add a patch of LLVM. In LLVM, the function addCommonCodeGenPasses() is hidden.
+ Let addCommonCodeGenPasses() be public.
+
+commit 6c27377a22e5b420809a7fb20b1451e2122ef50e
+Author: luba <lubatang@gmail.com>
+Date: Mon Jun 20 14:02:14 2011 +0800
+
+ CodeGen has a sub-directory CodeGen. It dis-follows the rule of LLVM directory structure.
+
+ remove CodeGen/CodeGen, and move all files to the up CodeGen directory.
+
+commit aee528f7cd55ff97e44eb8a36fbb00543251e2d4
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 00:37:45 2011 +0800
+
+ Adding MCLD header files
+
+commit 4613cdedb8d987ad7a4301cd70379c755561d0ce
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 00:27:20 2011 +0800
+
+ Adding CodeGen stubs
+
+commit 81b188f30a851e5045e1d223ec4f8b7cf3f79ebf
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 00:24:16 2011 +0800
+
+ Add mcld headers
+
+commit 0d5669cc5654c15d99f7cde0099a57e21d79bc4b
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 00:09:07 2011 +0800
+
+ Update build scripts
+
+commit c1f4f9ebcd06f093beeef03e8e444ebd9f521a63
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 00:04:54 2011 +0800
+
+ Adding unittest for TargetMachine
+
+commit ae4faa7f5654ce0caa0d0b0f206c22445d816ef8
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 00:03:32 2011 +0800
+
+ Adding MCLDScriptReader stub
+
+commit 6ca29571adb961e8b15174eac02163df890720c6
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Mon Jun 20 00:02:17 2011 +0800
+
+ Adding MCLinker stub
+
+commit 17f4f2df233f266334f0fb8d2ba024053eed5c52
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Sun Jun 19 19:11:25 2011 +0800
+
+ Rename MCLDWriter to ELFLDWriter
+
+commit 22e8328de9407e585731c34dd46930f547abb279
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Sun Jun 19 14:53:54 2011 +0800
+
+ Adding stubs for ARMLDBackend.
+
+commit 26dca80bfeed3852582dd053fd1b634f62365e6b
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Sun Jun 19 13:21:41 2011 +0800
+
+ Adding README
+
+commit a83e4f52cd5267013b5ae32e3e357f428a7ed0b8
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Sat Jun 18 00:51:10 2011 +0800
+
+ Adding Java side implementation of NDK-MCLinker
+ NDK-MCLinker invokes MCLinker via NDK
+
+commit 8848eebd46440d2b4fdc76f24707b840914171a8
+Author: Jush Lu <jush.msn@gmail.com>
+Date: Fri Jun 17 23:46:53 2011 +0800
+
+ Creating directories and files for MCLinker architecture
+
+commit 97bf250afe8e3d1cecc67782786c2497bd942e03
+Author: luba <lubatang@gmail.com>
+Date: Wed Jun 1 10:22:47 2011 +0800
+
+ fix a bug
+
+ if either llvm-config --version is A.Bsvn, or minor version is less than required minor version,
+ configure return error.
+
+commit b64d8cbda3946b9b9000e38c05ce27b63761e6d1
+Author: luba <lubatang@gmail.com>
+Date: Thu May 26 15:58:56 2011 +0800
+
+ `./configure' script for checking LLVM is done.
+ see [ticket:36]
+
+commit 8798e5d890a6abb6a2c3ee594269a8eebe586b4d
+Author: luba <lubatang@gmail.com>
+Date: Wed May 25 20:25:05 2011 +0800
+
+ Move TEST_F from the header to the implementation.
+ This is more fit using scenario.
+
+commit 4152b15f8bf84e960d9f0c27510b6a9075e60239
+Merge: 3a6af50 b4fd4b4
+Author: luba <lubatang@gmail.com>
+Date: Wed May 25 17:49:36 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 3a6af5027bc1a8ba114613383242041d1140111a
+Author: luba <lubatang@gmail.com>
+Date: Wed May 25 17:46:43 2011 +0800
+
+ Add empty but necessary directories.
+
+commit b4fd4b471548b438f8a2e1e211a3de9d6f15dd84
+Author: luba <lubatang@gmail.com>
+Date: Wed May 25 17:46:43 2011 +0800
+
+ Add empty but necessary directories.
+
+commit 8ffdbc6323d3da1bac857b5eb8339254cf9eb432
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 17:38:35 2011 +0800
+
+ put created headers in the ${BOLDTOP}/include/
+
+commit ee26ff715b457e3e81bbfacdfaa128ba18f2e5a7
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 17:37:56 2011 +0800
+
+ main function doesn't invoke gtest correctly. fixes these bugs.
+
+commit 31d5729e35caec19a891bb6dee0cc9863462a409
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 17:24:28 2011 +0800
+
+ The same bug like [ticket:46] in the `add_class' program.
+
+commit 1c5bc38d4e355334ba35e3b8c9da50bb12163340
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 17:20:48 2011 +0800
+
+ Fix a bug in envsetup.sh
+ see [ticket:46]
+
+commit 666d5974763bc6505166af60d9ee40a3bfc78fba
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 17:19:22 2011 +0800
+
+ include unit-test header
+
+commit 7f4383c62d978776f693cdbc37b1140676c5d95c
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 17:08:29 2011 +0800
+
+ add friend class for the unit-test
+
+commit 35e67c3dc80fa8419ee444e625cf7e19b2032897
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 17:06:52 2011 +0800
+
+ Modify the template of testcases.
+ see [ticket:44]
+
+commit 55097d1ed67274906fa67f146d2d71ff8566d244
+Author: Luba Tang <lubatang@gmail.com>
+Date: Wed May 25 15:34:33 2011 +0800
+
+ Change some configurations of the testing framework.
+ * put compiled object files into obj/
+ * use libtool to create `libgtest.la' library
+ * modify configure.ac to add above functionalities.
+ * change the #include path `gtest.h'
+
+commit 1fa3e17175b520915cf59ac3f02f8b64b110db06
+Author: luba <lubatang@gmail.com>
+Date: Wed May 25 14:31:30 2011 +0800
+
+ create the basic infrastructure of unit-test.
+ using google C++ test
+ see [ticket:37]
+
+commit b059d14f37660ae196148a03a89ed8166e67197d
+Author: luba <lubatang@gmail.com>
+Date: Tue May 24 18:39:49 2011 +0800
+
+ Implementation of the add_class tool is completed.
+ See [ticket:39]
+
+commit bc6f1008bb26ea90e18c531613563911120e903c
+Merge: 68cd61e 4b4b6e0
+Author: luba <lubatang@gmail.com>
+Date: Mon May 23 20:31:26 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 68cd61ef8bc135b04295196786679e6e7bab56ff
+Merge: 2b52163 40b3a4c
+Author: luba <lubatang@gmail.com>
+Date: Mon May 23 17:55:19 2011 +0800
+
+ create the building system - using auto-tools, and basic directories.
+
+commit 4b4b6e0b340e87996a6573edee48f02cd26cbe5d
+Merge: 2b52163 40b3a4c
+Author: luba <lubatang@gmail.com>
+Date: Mon May 23 17:55:19 2011 +0800
+
+ Merge branch 'master' of upstream
+
+commit 2b52163847724611b3f788eac22193e6b18abb03
+Author: luba <lubatang@gmail.com>
+Date: Mon May 23 17:44:59 2011 +0800
+
+ creates the building system - using auto-tools, and basic directories
+
+commit 40b3a4c09e1437356c9cb56ddb6c17c02fa9c117
+Author: luba <lubatang@gmail.com>
+Date: Mon May 23 17:44:59 2011 +0800
+
+ creates the building system - using auto-tools, and basic directories
+
+commit 32562fc969851b1cda32729dc475265e59e6c3ec
+Author: TDYa127 <a127a127@gmail.com>
+Date: Mon May 23 14:19:31 2011 +0800
+
+ Test proxy.
+
+commit b85e50a9971913a9ff6ba9786cea38198f8d540f
+Author: luba <lubatang@gmail.com>
+Date: Tue May 17 10:31:26 2011 +0800
+
+ On branch master
+ Changes to be committed:
+ new file: bold/Makefile.am
+ new file: bold/README
+ new file: bold/configure.ac
+ new file: bold/debug/Makefile.am
+ new file: bold/optimized/Makefile.am
+
+ Build the basic directory structure of BOLD project.
+ I choose auto-tools as our build system for following reasons:
+ 1. auto-tools are standard build system for cross platform compilation
+ 2. CMake is another building system for cross platform. although it's
+ also used in LLVM, it support less libraries than auto-tools.
+
+commit 13a0eafbe004a0364e16cc2980d8cac0b83710bb
+Author: luba <lubatang@gmail.com>
+Date: Mon May 16 17:59:08 2011 +0800
+
+ Test for big file
+
+commit dbca9ba423827d80d8449582838f2e2d7bd62766
+Author: luba <lubatang@gmail.com>
+Date: Mon May 16 17:49:25 2011 +0800
+
+ try to commit files
+
+commit 93b33cc586bc288ff62fcd0b252ee26b1fe0ed8b
+Author: duo <duo@duo-desktop.(none)>
+Date: Wed May 11 22:54:36 2011 +0800
+
+ add a new file hello
+
+commit ab80f8a8c0816105777a2156fcaec0dcce928bb2
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Wed May 11 19:18:13 2011 +0800
+
+ push to new brach csmon
+
+commit fd5b000f8eaf2bdd306de7ce8489f251c172ccf5
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Wed May 11 19:15:37 2011 +0800
+
+ add a folder source
+
+commit 73b347ed1941bef06dd946365d72a9cbbb21ba43
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Wed May 11 17:22:42 2011 +0800
+
+ First revision
+
+commit 4af68d56600382997a90cf7541d95b734d71bb37
+Author: csmon7507 <csmon7507@gmail.com>
+Date: Tue May 10 12:12:29 2011 +0800
+
+ First revision
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5894b8d
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,237 @@
+ The MCLinker project
+
+This file is distributed under the University of Illinois Open Source
+License. See LICENSE.TXT for details.
+
+==================
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+=====================
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+====================================
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+==================
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+=================
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+==========================
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+================
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+==================
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+======================
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 0000000..17ba080
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,66 @@
+==============================================================================
+MCLinker Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2011-2012 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+ Authors in ChangeLog.txt.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+Copyrights and Licenses for Third Party Software Distributed with LLVM:
+==============================================================================
+The LLVM software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program Directory
+------- ---------
+Google Test utils/gtest/
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..ceb628d
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,5 @@
+ACLOCAL_AMFLAGS=-I m4
+
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = utils debug test
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..de3437d
--- /dev/null
+++ b/README
@@ -0,0 +1,64 @@
+------------------------------------------------------------------------------
+ MCLinker Project
+------------------------------------------------------------------------------
+============
+Introduction
+============
+ MCLinker is a linkage editor.
+
+========================
+Compilation Instructions
+========================
+ The simplest way to compile this package is:
+
+----------------------
+Prepare LLVM and Clang
+----------------------
+ 0.a Download LLVM 3.1@r152063
+ `svn co -r 152063 http://llvm.org/svn/llvm-project/llvm/trunk llvm-src'
+
+ 0.b Type `cd llvm-src' to enter the directory containing LLVM source code
+
+ 0.c Apply patches from MCLinker
+ `patch -p0 < ${MCLinker}/patch/LLVM.patch'
+
+ 0.d Download Clang @r146744
+ `cd tools'
+ `svn co -r 146744 http://llvm.org/svn/llvm-project/cfe/trunk clang'
+
+ 0.e Build and install LLVM
+ `cd ../../'
+ `mkdir llvm-build && cd ./llvm-build'
+ `../llvm/configure --prefix=${LLVM_INSTALL}'
+ `make all install'
+
+--------------
+Build MCLinker
+--------------
+
+ 1. Type `cd ${MCLinker}' to the directory containing the source code.
+
+ 2. source ./scripts/envsetup.sh
+
+ 3. If there are no `configure' shell script in the directory, type
+ `./autogen.sh' to generate `configure' script.
+
+ 4. Type `./configure` to configure the package for your system. See INSTALL
+ for more details.
+
+ 5. Type `make` to compile the package
+
+ 6. Type `make install` to install the package into your system.
+
+===================
+Directory Structure
+===================
+README - this document
+Makefile.am - input of automake
+configure.ac - input of autoconf
+src/ - source code of verification tool
+include/ - include file, exported interface
+lib/ - source code of exported interface
+debug/ - placeholder of object files which are compiled for debugging
+optimized/ - placeholder of object files which are compiled for optimization
+test/ - placeholder of testcases
diff --git a/VERSION.in b/VERSION.in
new file mode 100644
index 0000000..3e2a7af
--- /dev/null
+++ b/VERSION.in
@@ -0,0 +1,21 @@
+@MCLD_VERSION@
+==================
+Versioning Format:
+ [MAJOR].[MINOR].[MICRO].[AGE]-[PKG BUILD]
+
+[MAJOR]
+ It is changed for marketing purposes.
+
+[MINOR]
+ ALPHA - 0 for alpha
+ BETA - 1 for beta
+ RC - 2 for release candidate
+ FR - 3 for final release
+ MA - 4 for market acceptance
+ GM - 5 for golden model
+
+Making a release:
+ If any inputs/outputs have been changed, set AGE to 0.
+ If all inputs/outputs/ are not changed, but make a significant change, increase MICRO.
+ If backward compatiblity has been broken, then set both MICRO and AGE to 0, and increase MINOR.
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..8ce8cf4
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# The MCLinker project
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+LIBTOOLIZE=libtoolize
+my_uname=`uname`
+
+if [ ${my_uname} = "Darwin" ]; then
+ LIBTOOLIZE=glibtoolize
+fi
+root=`dirname $0`
+cd $root
+
+aclocal -I ./m4
+${LIBTOOLIZE} --force
+automake --add-missing
+autoconf
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..2fc25ea
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,97 @@
+# The MCLinker project
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+##############################################################################
+### WARNING: this file contains embedded tabs. Do not run untabify on this file.
+
+####################
+# m4 includes
+m4_include(m4/acx_pthread.m4)
+####################
+# Autoconf/Automake Initialization
+
+dnl AC_INIT(PKG_NAME, CONFIG_VERSION, BUG_REPORTER)
+AC_INIT([MCLinker],[1.1],[mclinker@googlegroups.com])
+AC_PREREQ(2.59)
+
+AC_CONFIG_SRCDIR([./COPYING])
+AC_CONFIG_MACRO_DIR([m4])
+
+AM_INIT_AUTOMAKE([1.9 dist-bzip2 foreign])
+
+####################
+# Versioning, see VERSION
+MAJOR=0
+MINOR=2
+MICRO=10
+AGE=1
+BUILD=18peaks
+
+DEV_VERSION=$MAJOR.$MINOR.$MICRO.$AGE-$BUILD
+PKG_VERSION=$MAJOR.$MINOR.$MICRO-$BUILD
+MCLD_VERSION=$DEV_VERSION
+AC_SUBST(MCLD_VERSION)
+
+####################
+# Languages
+AC_PROG_CC
+AC_PROG_CXX
+AC_LANG([C++])
+LT_INIT
+
+####################
+# Check for libraries
+
+# Configure pthreads.
+AC_ARG_WITH([pthreads],
+ [AS_HELP_STRING([--with-pthreads],
+ [use pthreads (default is yes)])],
+ [with_pthreads=$withval],
+ [with_pthreads=check])
+
+have_pthreads=no
+AS_IF([test "x$with_pthreads" != "xno"],
+ [ACX_PTHREAD(
+ [],
+ [AS_IF([test "x$with_pthreads" != "xcheck"],
+ [AC_MSG_FAILURE(
+ [--with-pthreads was specified, but unable to be used])])])
+ have_pthreads="$acx_pthread_ok"])
+AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"])
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_LIBS)
+
+# Configure Unit-test
+AC_ARG_ENABLE(unittest,
+ [AS_HELP_STRING([--enable-unittest],
+ [turn on unit-tests (default is no)])],
+ [case "${enableval}" in
+ yes) unittest=true ;;
+ no) unittest=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-unittest) ;;
+ esac],
+ [unittest=false])
+AM_CONDITIONAL([ENABLE_UNITTEST],[test "x${unittest}" == "xtrue" ])
+
+####################
+# Configure LLVM
+CHECK_LLVM([3.0])
+ENUM_LLVM_TARGETS
+
+####################
+# OUTPUT
+AC_CONFIG_FILES([VERSION])
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([debug/Makefile])
+AC_CONFIG_FILES([optimized/Makefile])
+AC_CONFIG_FILES([utils/Makefile])
+AC_CONFIG_FILES([utils/gtest/Makefile])
+AC_CONFIG_FILES([utils/gtest/obj/Makefile])
+AC_CONFIG_FILES([include/mcld/Config/Targets.def])
+AC_CONFIG_FILES([include/mcld/Config/Linkers.def])
+AC_CONFIG_FILES([include/mcld/Config/Config.h])
+AC_CONFIG_FILES([test/Makefile])
+
+AC_OUTPUT
diff --git a/debug/Makefile.am b/debug/Makefile.am
new file mode 100644
index 0000000..4f9d24d
--- /dev/null
+++ b/debug/Makefile.am
@@ -0,0 +1,280 @@
+BUILDTOP=..
+TOPLEVEL=${srcdir}/..
+TOOLDIR=${TOPLEVEL}/tools/llvm-mcld
+LIBDIR=${TOPLEVEL}/lib
+INCDIR=${TOPLEVEL}/include/mcld
+UNITTEST=${TOPLEVEL}/unittests
+
+ANDROID_CPPFLAGS=-Wformat -Werror=format-security -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point
+
+bin_PROGRAMS = llvm-mcld
+
+if ENABLE_UNITTEST
+llvm_mcld_CPPFLAGS = -g -O1 -DTOPDIR=\"${abs_top_srcdir}\" -DLLVM_VERSION=${LLVM_VERSION} -DENABLE_UNITTEST -DMCLD_DEBUG -I$(TOPLEVEL)/utils/gtest/include -I$(TOPLEVEL)/include -I$(TOPLEVEL)/unittests -I$(BUILDTOP)/include ${LLVM_CPPFLAGS} -DGTEST_HAS_RTTI=0 ${ANDROID_CPPFLAGS}
+llvm_mcld_LDADD = -L$(BUILDTOP)/utils/gtest/lib/ ${LLVM_LDFLAGS} -lgtest
+else
+llvm_mcld_CPPFLAGS = -g -O1 -DLLVM_VERSION=${LLVM_VERSION} -I$(TOPLEVEL)/utils/gtest/include -I$(TOPLEVEL)/include -I$(TOPLEVEL)/include -I$(BUILDTOP)/include ${LLVM_CPPFLAGS} ${ANDROID_CPPFLAGS}
+llvm_mcld_LDADD = ${LLVM_LDFLAGS}
+endif
+
+NORMAL_SOURCE = ${TOOLDIR}/llvm-mcld.cpp \
+ ${INCDIR}/ADT/Uncopyable.h \
+ ${INCDIR}/ADT/TypeTraits.h \
+ ${INCDIR}/ADT/TreeBase.h \
+ ${INCDIR}/ADT/Allocators.h \
+ ${INCDIR}/ADT/TreeAllocator.h \
+ ${INCDIR}/ADT/BinTree.h \
+ ${INCDIR}/Support/Path.h \
+ ${LIBDIR}/Support/Path.cpp \
+ ${INCDIR}/Support/RealPath.h \
+ ${LIBDIR}/Support/RealPath.cpp \
+ ${INCDIR}/Support/Directory.h \
+ ${LIBDIR}/Support/Directory.cpp \
+ ${INCDIR}/Support/FileSytem.h \
+ ${LIBDIR}/Support/FileSystem.cpp \
+ ${INCDIR}/Support/LEB128.h \
+ ${LIBDIR}/Support/LEB128.cpp \
+ ${INCDIR}/Support/MemoryArea.h \
+ ${LIBDIR}/Support/MemoryArea.cpp \
+ ${INCDIR}/Support/MemoryRegion.h \
+ ${LIBDIR}/Support/MemoryRegion.cpp \
+ ${INCDIR}/Support/RegionFactory.h \
+ ${LIBDIR}/Support/RegionFactory.cpp \
+ ${INCDIR}/Support/MemoryAreaFactory.h \
+ ${LIBDIR}/Support/MemoryAreaFactory.cpp \
+ ${INCDIR}/Support/CommandLine.h \
+ ${LIBDIR}/Support/CommandLine.cpp \
+ ${INCDIR}/Support/GCFactory.h \
+ ${INCDIR}/Support/UniqueGCFactory.h \
+ ${INCDIR}/Support/PositionDependentOption.h \
+ ${INCDIR}/Support/DerivedPositionDependentOptions.h \
+ ${LIBDIR}/CodeGen/LLVMTargetMachine.cpp \
+ ${INCDIR}/CodeGen/SectLinker.h \
+ ${LIBDIR}/CodeGen/SectLinker.cpp \
+ ${INCDIR}/CodeGen/SectLinkerOption.h \
+ ${LIBDIR}/CodeGen/SectLinkerOption.cpp \
+ ${INCDIR}/Target/PLT.h\
+ ${LIBDIR}/Target/PLT.cpp\
+ ${INCDIR}/Target/GOT.h \
+ ${LIBDIR}/Target/GOT.cpp \
+ ${INCDIR}/Target/TargetMachine.h \
+ ${INCDIR}/Target/TargetRegistry.h \
+ ${LIBDIR}/Support/TargetRegistry.cpp \
+ ${LIBDIR}/Target/Target.cpp \
+ ${INCDIR}/Target/TargetSelect.h \
+ ${INCDIR}/Target/TargetLDBackend.h \
+ ${LIBDIR}/Target/TargetLDBackend.cpp \
+ ${INCDIR}/Target/GNULDBackend.h \
+ ${LIBDIR}/Target/GNULDBackend.cpp \
+ ${INCDIR}/Target/AndroidSectLinker.h \
+ ${LIBDIR}/Target/AndroidSectLinker.cpp \
+ ${INCDIR}/Target/ELFDynamic.h \
+ ${LIBDIR}/Target/ELFDynamic.cpp \
+ ${INCDIR}/Target/OutputRelocSection.h \
+ ${LIBDIR}/Target/OutputRelocSection.cpp \
+ ${LIBDIR}/Target/ARM/ARMELFDynamic.h \
+ ${LIBDIR}/Target/ARM/ARMELFDynamic.cpp \
+ ${LIBDIR}/Target/ARM/ARMLDBackend.h \
+ ${LIBDIR}/Target/ARM/ARMLDBackend.cpp \
+ ${LIBDIR}/Target/ARM/ARMGOT.h \
+ ${LIBDIR}/Target/ARM/ARMGOT.cpp \
+ ${LIBDIR}/Target/ARM/ARMPLT.h \
+ ${LIBDIR}/Target/ARM/ARMPLT.cpp \
+ ${LIBDIR}/Target/ARM/ARMTargetMachine.h \
+ ${LIBDIR}/Target/ARM/ARMTargetMachine.cpp \
+ ${LIBDIR}/Target/ARM/ARMRelocationFactory.h \
+ ${LIBDIR}/Target/ARM/ARMRelocationFactory.cpp \
+ ${LIBDIR}/Target/ARM/ARMSectLinker.cpp \
+ ${LIBDIR}/Target/ARM/ARMELFSectLinker.h \
+ ${LIBDIR}/Target/ARM/ARMELFSectLinker.cpp \
+ ${LIBDIR}/Target/ARM/ARMAndroidSectLinker.h \
+ ${LIBDIR}/Target/ARM/ARMAndroidSectLinker.cpp \
+ ${LIBDIR}/Target/ARM/TargetInfo/ARMTargetInfo.cpp \
+ ${LIBDIR}/Target/Mips/MipsELFDynamic.h \
+ ${LIBDIR}/Target/Mips/MipsELFDynamic.cpp \
+ ${LIBDIR}/Target/Mips/MipsLDBackend.h \
+ ${LIBDIR}/Target/Mips/MipsLDBackend.cpp \
+ ${LIBDIR}/Target/Mips/MipsGOT.h \
+ ${LIBDIR}/Target/Mips/MipsGOT.cpp \
+ ${LIBDIR}/Target/Mips/MipsTargetMachine.h \
+ ${LIBDIR}/Target/Mips/MipsTargetMachine.cpp \
+ ${LIBDIR}/Target/Mips/MipsRelocationFactory.h \
+ ${LIBDIR}/Target/Mips/MipsRelocationFactory.cpp \
+ ${LIBDIR}/Target/Mips/MipsSectLinker.cpp \
+ ${LIBDIR}/Target/Mips/MipsELFSectLinker.h \
+ ${LIBDIR}/Target/Mips/MipsELFSectLinker.cpp \
+ ${LIBDIR}/Target/Mips/MipsAndroidSectLinker.h \
+ ${LIBDIR}/Target/Mips/MipsAndroidSectLinker.cpp \
+ ${LIBDIR}/Target/Mips/TargetInfo/MipsTargetInfo.cpp \
+ ${LIBDIR}/Target/X86/X86ELFDynamic.h \
+ ${LIBDIR}/Target/X86/X86ELFDynamic.cpp \
+ ${LIBDIR}/Target/X86/X86LDBackend.h \
+ ${LIBDIR}/Target/X86/X86LDBackend.cpp \
+ ${LIBDIR}/Target/X86/X86GOT.h \
+ ${LIBDIR}/Target/X86/X86GOT.cpp \
+ ${LIBDIR}/Target/X86/X86GOTPLT.h \
+ ${LIBDIR}/Target/X86/X86GOTPLT.cpp \
+ ${LIBDIR}/Target/X86/X86PLT.h \
+ ${LIBDIR}/Target/X86/X86PLT.cpp \
+ ${LIBDIR}/Target/X86/X86TargetMachine.h \
+ ${LIBDIR}/Target/X86/X86TargetMachine.cpp \
+ ${LIBDIR}/Target/X86/X86RelocationFactory.h \
+ ${LIBDIR}/Target/X86/X86RelocationFactory.cpp \
+ ${LIBDIR}/Target/X86/X86SectLinker.cpp \
+ ${LIBDIR}/Target/X86/X86ELFSectLinker.h \
+ ${LIBDIR}/Target/X86/X86ELFSectLinker.cpp \
+ ${LIBDIR}/Target/X86/X86AndroidSectLinker.h \
+ ${LIBDIR}/Target/X86/X86AndroidSectLinker.cpp \
+ ${LIBDIR}/Target/X86/TargetInfo/X86TargetInfo.cpp \
+ ${INCDIR}/MC/MCLDDriver.h \
+ ${LIBDIR}/MC/MCLDDriver.cpp \
+ ${INCDIR}/MC/SymbolCategory.h \
+ ${LIBDIR}/MC/SymbolCategory.cpp \
+ ${INCDIR}/MC/MCLinker.h \
+ ${LIBDIR}/MC/MCLinker.cpp \
+ ${INCDIR}/MC/MCBitcodeInterceptor.h \
+ ${LIBDIR}/MC/MCBitcodeInterceptor.cpp \
+ ${INCDIR}/MC/MCLDFile.h \
+ ${LIBDIR}/MC/MCLDFile.cpp \
+ ${INCDIR}/MC/MCLDInput.h \
+ ${LIBDIR}/MC/MCLDInput.cpp \
+ ${INCDIR}/MC/MCLDOutput.h \
+ ${LIBDIR}/MC/MCLDOutput.cpp \
+ ${INCDIR}/MC/InputFactory.h \
+ ${LIBDIR}/MC/InputFactory.cpp \
+ ${INCDIR}/MC/MCLDOptions.h \
+ ${LIBDIR}/MC/MCLDOptions.cpp \
+ ${INCDIR}/MC/MCLDInfo.h \
+ ${LIBDIR}/MC/MCLDInfo.cpp \
+ ${INCDIR}/MC/ContextFactory.h \
+ ${LIBDIR}/MC/ContextFactory.cpp \
+ ${INCDIR}/MC/SearchDirs.h \
+ ${LIBDIR}/MC/SearchDirs.cpp \
+ ${INCDIR}/MC/MCLDDirectory.h \
+ ${LIBDIR}/MC/MCLDDirectory.cpp \
+ ${INCDIR}/MC/MCLDAttribute.h \
+ ${LIBDIR}/MC/MCLDAttribute.cpp \
+ ${INCDIR}/MC/AttributeFactory.h \
+ ${LIBDIR}/MC/AttributeFactory.cpp \
+ ${INCDIR}/MC/MCLDInputTree.h \
+ ${LIBDIR}/MC/MCLDInputTree.cpp \
+ ${INCDIR}/MC/MCRegionFragment.h \
+ ${LIBDIR}/MC/MCRegionFragment.cpp \
+ ${INCDIR}/MC/MCTargetFragment.h \
+ ${INCDIR}/MC/MCFragmentRef.h \
+ ${LIBDIR}/MC/MCFragmentRef.cpp \
+ ${INCDIR}/LD/LDContext.h \
+ ${LIBDIR}/LD/LDContext.cpp \
+ ${INCDIR}/LD/LDSection.h \
+ ${LIBDIR}/LD/LDSection.cpp \
+ ${INCDIR}/LD/ResolveInfo.h \
+ ${LIBDIR}/LD/ResolveInfo.cpp \
+ ${INCDIR}/LD/ResolveInfoFactory.h \
+ ${LIBDIR}/LD/ResolveInfoFactory.cpp \
+ ${INCDIR}/LD/Resolver.h \
+ ${LIBDIR}/LD/Resolver.cpp \
+ ${INCDIR}/LD/LDSymbol.h \
+ ${LIBDIR}/LD/LDSymbol.cpp \
+ ${INCDIR}/LD/Layout.h \
+ ${LIBDIR}/LD/Layout.cpp\
+ ${INCDIR}/LD/Relocation.h \
+ ${LIBDIR}/LD/Relocation.cpp \
+ ${INCDIR}/LD/RelocationFactory.h \
+ ${LIBDIR}/LD/RelocationFactory.cpp \
+ ${INCDIR}/LD/StaticResolver.h \
+ ${LIBDIR}/LD/StaticResolver.cpp \
+ ${INCDIR}/LD/StrSymPool.h \
+ ${LIBDIR}/LD/StrSymPool.cpp \
+ ${INCDIR}/LD/LDReader.h \
+ ${LIBDIR}/LD/LDReader.cpp \
+ ${INCDIR}/LD/LDWriter.h \
+ ${LIBDIR}/LD/LDWriter.cpp \
+ ${INCDIR}/LD/ArchiveReader.h \
+ ${LIBDIR}/LD/ArchiveReader.cpp \
+ ${INCDIR}/LD/ObjectReader.h \
+ ${INCDIR}/LD/DynObjReader.h \
+ ${LIBDIR}/LD/DynObjReader.cpp \
+ ${INCDIR}/LD/ObjectWriter.h \
+ ${LIBDIR}/LD/ObjectWriter.cpp \
+ ${INCDIR}/LD/DynObjWriter.h \
+ ${LIBDIR}/LD/DynObjWriter.cpp \
+ ${INCDIR}/LD/ELFReader.h \
+ ${LIBDIR}/LD/ELFReader.cpp \
+ ${INCDIR}/LD/ELFWriter.h \
+ ${LIBDIR}/LD/ELFWriter.cpp \
+ ${INCDIR}/LD/GNUArchiveReader.h \
+ ${LIBDIR}/LD/GNUArchiveReader.cpp \
+ ${INCDIR}/LD/BSDArchiveReader.h \
+ ${LIBDIR}/LD/BSDArchiveReader.cpp \
+ ${INCDIR}/LD/ELFObjectReader.h \
+ ${LIBDIR}/LD/ELFObjectReader.cpp \
+ ${INCDIR}/LD/ELFDynObjReader.h \
+ ${LIBDIR}/LD/ELFDynObjReader.cpp \
+ ${INCDIR}/LD/ELFObjectWriter.h \
+ ${LIBDIR}/LD/ELFObjectWriter.cpp \
+ ${INCDIR}/LD/ELFDynObjWriter.h \
+ ${LIBDIR}/LD/ELFDynObjWriter.cpp \
+ ${INCDIR}/LD/LDFileFormat.h \
+ ${LIBDIR}/LD/LDFileFormat.cpp \
+ ${INCDIR}/LD/ELFFileFormat.h \
+ ${LIBDIR}/LD/ELFFileFormat.cpp \
+ ${INCDIR}/LD/ELFDynObjFileFormat.h \
+ ${LIBDIR}/LD/ELFDynObjFileFormat.cpp \
+ ${INCDIR}/LD/ELFExecFileFormat.h \
+ ${LIBDIR}/LD/ELFExecFileFormat.cpp \
+ ${INCDIR}/LD/LDSectionFactory.h \
+ ${LIBDIR}/LD/LDSectionFactory.cpp \
+ ${INCDIR}/LD/SectionMap.h \
+ ${LIBDIR}/LD/SectionMap.cpp \
+ ${INCDIR}/LD/SectionMerger.h \
+ ${LIBDIR}/LD/SectionMerger.cpp \
+ ${INCDIR}/LD/ELFSegment.h \
+ ${LIBDIR}/LD/ELFSegment.cpp \
+ ${INCDIR}/LD/ELFSegmentFactory.h \
+ ${LIBDIR}/LD/ELFSegmentFactory.cpp
+# ${LIBDIR}/CodeGen/LDPrinter.cpp \
+# ${INCDIR}/CodeGen/LDPrinter.h
+# ${INCDIR}/Support/ScopedRegion.h \
+# ${LIBDIR}/Support/ScopedRegion.cpp
+
+if ENABLE_UNITTEST
+SOURCE = ${NORMAL_SOURCE} \
+ ${UNITTEST}/PathTest.h \
+ ${UNITTEST}/PathTest.cpp \
+ ${UNITTEST}/BinTreeTest.h \
+ ${UNITTEST}/BinTreeTest.cpp \
+ ${UNITTEST}/LinearAllocatorTest.h \
+ ${UNITTEST}/LinearAllocatorTest.cpp \
+ ${UNITTEST}/InputTreeTest.h \
+ ${UNITTEST}/InputTreeTest.cpp \
+ ${UNITTEST}/RTLinearAllocatorTest.h \
+ ${UNITTEST}/RTLinearAllocatorTest.cpp \
+ ${UNITTEST}/DirIteratorTest.h \
+ ${UNITTEST}/DirIteratorTest.cpp \
+ ${UNITTEST}/UniqueGCFactoryBaseTest.h \
+ ${UNITTEST}/UniqueGCFactoryBaseTest.cpp \
+ ${UNITTEST}/MemoryAreaTest.h \
+ ${UNITTEST}/MemoryAreaTest.cpp \
+ ${UNITTEST}/HashTableTest.h \
+ ${UNITTEST}/HashTableTest.cpp \
+ ${UNITTEST}/LDSymbolTest.h \
+ ${UNITTEST}/LDSymbolTest.cpp \
+ ${UNITTEST}/MCFragmentRefTest.h \
+ ${UNITTEST}/MCFragmentRefTest.cpp \
+ ${UNITTEST}/StaticResolverTest.h \
+ ${UNITTEST}/StaticResolverTest.cpp \
+ ${UNITTEST}/GCFactoryListTraitsTest.h \
+ ${UNITTEST}/GCFactoryListTraitsTest.cpp \
+ ${UNITTEST}/LEB128Test.h \
+ ${UNITTEST}/LEB128Test.cpp \
+ ${UNITTEST}/SymbolCategoryTest.h \
+ ${UNITTEST}/SymbolCategoryTest.cpp
+# ${UNITTEST}/SymbolTableTest.h \
+# ${UNITTEST}/SymbolTableTest.cpp \
+# ${UNITTEST}/TargetRegistryTest.h \
+# ${UNITTEST}/TargetRegistryTest.cpp
+else
+SOURCE = ${NORMAL_SOURCE}
+endif
+
+llvm_mcld_SOURCES = ${SOURCE}
diff --git a/docs/DesignNote b/docs/DesignNote
new file mode 100644
index 0000000..d0eee5e
--- /dev/null
+++ b/docs/DesignNote
@@ -0,0 +1,11 @@
+Design Note
+===================
+1st Milestone:
+
+Architecture | ARM v7
+Operating System | Android
+Runtime Support | without C-runtime library
+Inputs | bitcode, shared object
+Output | shared object
+Numeral system | imprecise 64-bit (sufficiently large number)
+
diff --git a/docs/LLVM-architecture.dia b/docs/LLVM-architecture.dia
new file mode 100755
index 0000000..2db8cf9
--- /dev/null
+++ b/docs/LLVM-architecture.dia
Binary files differ
diff --git a/docs/MCLinker.dia b/docs/MCLinker.dia
new file mode 100755
index 0000000..c447bcc
--- /dev/null
+++ b/docs/MCLinker.dia
Binary files differ
diff --git a/include/mcld/ADT/BinTree.h b/include/mcld/ADT/BinTree.h
new file mode 100644
index 0000000..0a7fe28
--- /dev/null
+++ b/include/mcld/ADT/BinTree.h
@@ -0,0 +1,481 @@
+//===- BinTree.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_BINARY_TREE_H
+#define MCLD_BINARY_TREE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/ADT/TreeAllocator.h"
+
+#include <iterator>
+#include <memory>
+#include <queue>
+#include <stack>
+
+namespace mcld
+{
+
+template<class DataType>
+class BinaryTree;
+
+class DFSIterator : public TreeIteratorBase
+{
+public:
+ DFSIterator()
+ : TreeIteratorBase()
+ { }
+
+ DFSIterator(NodeBase *X)
+ : TreeIteratorBase(X) {
+ if (hasRightChild())
+ m_Stack.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Stack.push(m_pNode->left);
+ }
+
+ virtual ~DFSIterator()
+ { }
+
+ void advance() {
+ if (m_Stack.empty()) { // reach the end
+ m_pNode = m_pNode->right; // should be root
+ return;
+ }
+ m_pNode = m_Stack.top();
+ m_Stack.pop();
+ if (hasRightChild())
+ m_Stack.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Stack.push(m_pNode->left);
+ }
+
+private:
+ std::stack<NodeBase *> m_Stack;
+};
+
+class BFSIterator : public TreeIteratorBase
+{
+public:
+ BFSIterator()
+ : TreeIteratorBase()
+ { }
+
+ BFSIterator(NodeBase *X)
+ : TreeIteratorBase(X) {
+ if (hasRightChild())
+ m_Queue.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Queue.push(m_pNode->left);
+ }
+
+ virtual ~BFSIterator()
+ { }
+
+ void advance() {
+ if (m_Queue.empty()) { // reach the end
+ m_pNode = m_pNode->right; // should be root
+ return;
+ }
+ m_pNode = m_Queue.front();
+ m_Queue.pop();
+ if (hasRightChild())
+ m_Queue.push(m_pNode->right);
+ if (hasLeftChild())
+ m_Queue.push(m_pNode->left);
+ }
+
+private:
+ std::queue<NodeBase *> m_Queue;
+};
+
+template<class DataType, class Traits, class IteratorType>
+class PolicyIteratorBase : public IteratorType
+{
+public:
+ typedef DataType value_type;
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+
+ typedef PolicyIteratorBase<value_type, Traits, IteratorType> Self;
+ typedef Node<value_type> node_type;
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef PolicyIteratorBase<value_type, nonconst_traits, IteratorType> iterator;
+ typedef typename traits::const_traits const_traits;
+ typedef PolicyIteratorBase<value_type, const_traits, IteratorType> const_iterator;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+public:
+ PolicyIteratorBase()
+ : IteratorType() {}
+
+ PolicyIteratorBase(const iterator &X)
+ : IteratorType(X.m_pNode) {}
+
+ explicit PolicyIteratorBase(NodeBase* X)
+ : IteratorType(X) {}
+
+ virtual ~PolicyIteratorBase() {}
+
+ // ----- operators ----- //
+ pointer operator*() const
+ { return static_cast<node_type*>(IteratorType::m_pNode)->data; }
+
+ reference operator->() const
+ { return *static_cast<node_type*>(IteratorType::m_pNode)->data; }
+
+ bool isRoot() const
+ { return (IteratorType::m_pNode->right == IteratorType::m_pNode); }
+
+ bool hasData() const
+ { return (!isRoot() && (0 != static_cast<node_type*>(IteratorType::m_pNode)->data)); }
+
+};
+
+template<class DataType, class Traits, class IteratorType>
+class PolicyIterator : public PolicyIteratorBase<DataType, Traits, IteratorType>
+{
+public:
+ typedef PolicyIterator<DataType, Traits, IteratorType> Self;
+ typedef PolicyIteratorBase<DataType, Traits, IteratorType> Base;
+ typedef PolicyIterator<DataType, typename Traits::nonconst_traits, IteratorType> iterator;
+ typedef PolicyIterator<DataType, typename Traits::const_traits, IteratorType> const_iterator;
+
+public:
+ PolicyIterator()
+ : Base() {}
+
+ PolicyIterator(const iterator &X)
+ : Base(X.m_pNode) {}
+
+ explicit PolicyIterator(NodeBase* X)
+ : Base(X) {}
+
+ virtual ~PolicyIterator() {}
+
+ Self& operator++() {
+ IteratorType::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ IteratorType::advance();
+ return tmp;
+ }
+};
+
+template<class DataType>
+class BinaryTree;
+
+/** \class TreeIterator
+ * \brief TreeIterator provides full functions of binary tree's iterator.
+ *
+ * TreeIterator is designed to compatible with STL iterators.
+ * TreeIterator is bi-directional. Incremental direction means to move
+ * rightward, and decremental direction is leftward.
+ *
+ * @see TreeIteratorBase
+ */
+template<class DataType, class Traits>
+struct TreeIterator : public TreeIteratorBase
+{
+public:
+ typedef DataType value_type;
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+
+ typedef TreeIterator<value_type, Traits> Self;
+ typedef Node<value_type> node_type;
+
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef TreeIterator<value_type, nonconst_traits> iterator;
+ typedef typename traits::const_traits const_traits;
+ typedef TreeIterator<value_type, const_traits> const_iterator;
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+public:
+ TreeIterator()
+ : TreeIteratorBase() {}
+
+ TreeIterator(const iterator &X)
+ : TreeIteratorBase(X.m_pNode) {}
+
+ ~TreeIterator() {}
+
+ // ----- operators ----- //
+ pointer operator*() const
+ { return static_cast<node_type*>(m_pNode)->data; }
+
+ reference operator->() const
+ { return *static_cast<node_type*>(m_pNode)->data; }
+
+ bool isRoot() const
+ { return (m_pNode->right == m_pNode); }
+
+ bool hasData() const
+ { return (!isRoot() && (0 != static_cast<node_type*>(m_pNode)->data)); }
+
+ Self& operator++() {
+ this->move<TreeIteratorBase::Rightward>();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ this->move<TreeIteratorBase::Rightward>();
+ return tmp;
+ }
+
+ Self& operator--() {
+ this->move<TreeIteratorBase::Leftward>();
+ return *this;
+ }
+
+ Self operator--(int) {
+ Self tmp = *this;
+ this->move<TreeIteratorBase::Leftward>();
+ return tmp;
+ }
+
+ explicit TreeIterator(NodeBase* X)
+ : TreeIteratorBase(X) {}
+};
+
+/** \class BinaryTreeBase
+ * \brief BinaryTreeBase gives root node and memory management.
+ *
+ * The memory management of nodes in is hidden by BinaryTreeBase.
+ * BinaryTreeBase also provides the basic functions for merging a tree and
+ * inserton of a node.
+ *
+ * @see BinaryTree
+ */
+template<class DataType>
+class BinaryTreeBase : private Uncopyable
+{
+public:
+ typedef Node<DataType> NodeType;
+protected:
+ /// TreeImpl - TreeImpl records the root node and the number of nodes
+ //
+ // +---> Root(end) <---+
+ // | |left |
+ // | begin |
+ // | / \ |
+ // | Left Right |
+ // +---/ \-----+
+ //
+ class TreeImpl : public NodeFactory<DataType>
+ {
+ typedef typename NodeFactory<DataType>::iterator iterator;
+ typedef typename NodeFactory<DataType>::const_iterator const_iterator;
+
+ public:
+ NodeBase node;
+
+ public:
+ TreeImpl()
+ : NodeFactory<DataType>() {
+ node.left = node.right = &node;
+ }
+
+ ~TreeImpl()
+ { }
+
+ /// summon - change the final edges of pClient to our root
+ void summon(TreeImpl& pClient) {
+ if (this == &pClient)
+ return;
+
+ iterator data;
+ iterator dEnd = pClient.end();
+ for (data = pClient.begin(); data!=dEnd; ++data ) {
+ if ((*data).left == &pClient.node)
+ (*data).left = &node;
+ if ((*data).right == &pClient.node)
+ (*data).right = &node;
+ }
+ }
+ }; // TreeImpl
+
+protected:
+ /// m_Root is a special object who responses:
+ // - the pointer of root
+ // - the simple factory of nodes.
+ TreeImpl m_Root;
+
+protected:
+ NodeType *createNode() {
+ NodeType *result = m_Root.produce();
+ result->left = result->right = &m_Root.node;
+ return result;
+ }
+
+ void destroyNode(NodeType *pNode) {
+ pNode->left = pNode->right = 0;
+ pNode->data = 0;
+ m_Root.deallocate(pNode);
+ }
+
+public:
+ BinaryTreeBase()
+ : m_Root()
+ { }
+
+ virtual ~BinaryTreeBase()
+ { }
+
+ size_t size() const {
+ return m_Root.size();
+ }
+
+ bool empty() const {
+ return m_Root.empty();
+ }
+
+protected:
+ void clear() {
+ m_Root.clear();
+ }
+};
+
+/** \class BinaryTree
+ * \brief An abstract data type of binary tree.
+ *
+ * @see mcld::InputTree
+ */
+template<class DataType>
+class BinaryTree : public BinaryTreeBase<DataType>
+{
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef DataType value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef const value_type* const_pointer;
+ typedef const value_type& const_reference;
+
+ typedef BinaryTree<DataType> Self;
+ typedef TreeIterator<value_type, NonConstTraits<value_type> > iterator;
+ typedef TreeIterator<value_type, ConstTraits<value_type> > const_iterator;
+
+ typedef PolicyIterator<value_type, NonConstTraits<value_type>, DFSIterator> dfs_iterator;
+ typedef PolicyIterator<value_type, ConstTraits<value_type>, DFSIterator> const_dfs_iterator;
+ typedef PolicyIterator<value_type, NonConstTraits<value_type>, BFSIterator> bfs_iterator;
+ typedef PolicyIterator<value_type, ConstTraits<value_type>, BFSIterator> const_bfs_iterator;
+
+protected:
+ typedef Node<value_type> node_type;
+
+public:
+ // ----- constructors and destructor ----- //
+ BinaryTree()
+ : BinaryTreeBase<DataType>()
+ { }
+
+ ~BinaryTree() {
+ }
+
+ // ----- iterators ----- //
+ bfs_iterator bfs_begin()
+ { return bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ bfs_iterator bfs_end()
+ { return bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ const_bfs_iterator bfs_begin() const
+ { return const_bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ const_bfs_iterator bfs_end() const
+ { return const_bfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ dfs_iterator dfs_begin()
+ { return dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ dfs_iterator dfs_end()
+ { return dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ const_dfs_iterator dfs_begin() const
+ { return const_dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ const_dfs_iterator dfs_end() const
+ { return const_dfs_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ iterator root()
+ { return iterator(&(BinaryTreeBase<DataType>::m_Root.node)); }
+
+ const_iterator root() const
+ { return const_iterator(&(BinaryTreeBase<DataType>::m_Root.node)); }
+
+ iterator begin()
+ { return iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ iterator end()
+ { return iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ const_iterator begin() const
+ { return const_iterator(BinaryTreeBase<DataType>::m_Root.node.left); }
+
+ const_iterator end() const
+ { return const_iterator(BinaryTreeBase<DataType>::m_Root.node.right); }
+
+ // ----- modifiers ----- //
+ /// join - create a leaf node and merge it in the tree.
+ // This version of join determines the direction on compilation time.
+ // @param DIRECT the direction of the connecting edge of the parent node.
+ // @param position the parent node
+ // @param value the value being pushed.
+ template<size_t DIRECT, class Pos>
+ BinaryTree& join(Pos position, const DataType& value) {
+ node_type *node = BinaryTreeBase<DataType>::createNode();
+ node->data = const_cast<DataType*>(&value);
+ if (position.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(position.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(position.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+ }
+
+ /// merge - merge the tree
+ // @param DIRECT the direction of the connecting edge of the parent node.
+ // @param position the parent node
+ // @param the tree being joined.
+ // @return the joined tree
+ template<size_t DIRECT, class Pos>
+ BinaryTree& merge(Pos position, BinaryTree& pTree) {
+ if (this == &pTree)
+ return *this;
+
+ if (!pTree.empty()) {
+ proxy::hook<DIRECT>(position.m_pNode,
+ const_cast<const NodeBase*>(pTree.m_Root.node.left));
+ BinaryTreeBase<DataType>::m_Root.summon(
+ pTree.BinaryTreeBase<DataType>::m_Root);
+ BinaryTreeBase<DataType>::m_Root.delegate(pTree.m_Root);
+ pTree.m_Root.node.left = pTree.m_Root.node.right = &pTree.m_Root.node;
+ }
+ return *this;
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashBase.h b/include/mcld/ADT/HashBase.h
new file mode 100644
index 0000000..76410ab
--- /dev/null
+++ b/include/mcld/ADT/HashBase.h
@@ -0,0 +1,139 @@
+//===- HashBase.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_HASH_BASE_H
+#define MCLD_HASH_BASE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include <cstdlib>
+
+namespace mcld {
+
+/** forward declaration **/
+template<typename HashTableImplTy>
+class ChainIteratorBase;
+
+template<typename HashTableImplTy>
+class EntryIteratorBase;
+
+/** \class HashBucket
+ * \brief HashBucket is an entry in the hash table.
+ */
+template<typename HashEntryTy>
+class HashBucket
+{
+public:
+ typedef HashEntryTy entry_type;
+
+public:
+ unsigned int FullHashValue;
+ entry_type *Entry;
+
+public:
+ static entry_type* getEmptyBucket();
+ static entry_type* getTombstone();
+
+};
+
+/** \class HashTableImpl
+ * \brief HashTableImpl is the base class of HashTable.
+ *
+ * HashTableImpl uses open-addressing, linear probing hash table.
+ * linear probing hash table obviously has high performance when the
+ * load factor is less than 0.7.
+ * The drawback is that the number of the stored items can notbe more
+ * than the size of the hash table.
+ *
+ * MCLinker tries to merge every things in the same HashEntry. It can
+ * keep every thing in the same cache line and improve the locality
+ * efficiently. HashTableImpl provides a template argument to change the
+ * definition of HashEntries.
+ *
+ * HashEntryTy must provide getKey() and getKenLength() functions.
+ *
+ * Different environments have different demands of HashFunctions. For
+ * example, on-device linkers needs a more light-weight hash function
+ * than static linkers. HashTableImpl also provides a template argument to
+ * change the hash functions.
+ */
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+class HashTableImpl
+{
+private:
+ static const unsigned int NumOfInitBuckets = 16;
+
+public:
+ typedef size_t size_type;
+ typedef HashFunctionTy hasher;
+ typedef HashEntryTy entry_type;
+ typedef typename HashEntryTy::key_type key_type;
+ typedef HashBucket<HashEntryTy> bucket_type;
+ typedef HashTableImpl<HashEntryTy, HashFunctionTy> Self;
+
+
+public:
+ HashTableImpl();
+ explicit HashTableImpl(unsigned int pInitSize);
+ virtual ~HashTableImpl();
+
+ // ----- observers ----- //
+ bool empty() const;
+
+ size_t numOfBuckets() const
+ { return m_NumOfBuckets; }
+
+ size_t numOfEntries() const
+ { return m_NumOfEntries; }
+
+ hasher& hash()
+ { return m_Hasher; }
+
+ const hasher& hash() const
+ { return m_Hasher; }
+
+protected:
+ /// initialize the hash table.
+ void init(unsigned int pInitSize);
+
+ /// lookUpBucketFor - search the index of bucket whose key is p>ey
+ // @return the index of the found bucket
+ unsigned int lookUpBucketFor(const key_type& pKey);
+
+ /// findKey - finds an element with key pKey
+ // return the index of the element, or -1 when the element does not exist.
+ int findKey(const key_type& pKey) const;
+
+ /// mayRehash - check the load_factor, compute the new size, and then doRehash
+ void mayRehash();
+
+ /// doRehash - re-new the hash table, and rehash all elements into the new buckets
+ void doRehash(unsigned int pNewSize);
+
+friend class ChainIteratorBase<Self>;
+friend class ChainIteratorBase<const Self>;
+friend class EntryIteratorBase<Self>;
+friend class EntryIteratorBase<const Self>;
+protected:
+ // Array of Buckets
+ bucket_type* m_Buckets;
+ unsigned int m_NumOfBuckets;
+ unsigned int m_NumOfEntries;
+ unsigned int m_NumOfTombstones;
+ hasher m_Hasher;
+
+};
+
+#include "HashBase.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashBase.tcc b/include/mcld/ADT/HashBase.tcc
new file mode 100644
index 0000000..62d92b1
--- /dev/null
+++ b/include/mcld/ADT/HashBase.tcc
@@ -0,0 +1,250 @@
+//===- HashBase.tcc -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===--------------------------------------------------------------------===//
+// internal non-member functions
+inline static unsigned int compute_bucket_count(unsigned int pNumOfBuckets)
+{
+ static const unsigned int bucket_size[] =
+ {
+ 1, 3, 17, 37, 67, 97, 197, 419, 977, 2593, 4099, 8209, 12289,
+ 16411, 20483, 32771, 49157, 65537, 98317, 131101, 196613
+ };
+
+ const unsigned int buckets_count =
+ sizeof(bucket_size) / sizeof(bucket_size[0]);
+ unsigned int idx = 0;
+ do {
+ if (pNumOfBuckets < bucket_size[idx]) {
+ return bucket_size[idx];
+ }
+ ++idx;
+ } while(idx < buckets_count);
+
+ return (pNumOfBuckets+131101); // rare case. increase constantly
+}
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashBucket
+template<typename DataType>
+typename HashBucket<DataType>::entry_type*
+HashBucket<DataType>::getEmptyBucket()
+{
+ static entry_type* empty_bucket = reinterpret_cast<entry_type*>(0x0);
+ return empty_bucket;
+}
+
+template<typename DataType>
+typename HashBucket<DataType>::entry_type*
+HashBucket<DataType>::getTombstone()
+{
+ static entry_type* tombstone = reinterpret_cast<entry_type*>(0x1);
+ return tombstone;
+}
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashTableImpl
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+HashTableImpl<HashEntryTy, HashFunctionTy>::HashTableImpl()
+ : m_Buckets(0),
+ m_NumOfBuckets(0),
+ m_NumOfEntries(0),
+ m_NumOfTombstones(0),
+ m_Hasher() {
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+HashTableImpl<HashEntryTy, HashFunctionTy>::HashTableImpl(
+ unsigned int pInitSize)
+ : m_Hasher() {
+ if (pInitSize) {
+ init(pInitSize);
+ return;
+ }
+
+ m_Buckets = 0;
+ m_NumOfBuckets = 0;
+ m_NumOfEntries = 0;
+ m_NumOfTombstones = 0;
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+HashTableImpl<HashEntryTy, HashFunctionTy>::~HashTableImpl()
+{
+ free(m_Buckets);
+}
+
+/// empty - check if the hash table is empty
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+bool HashTableImpl<HashEntryTy, HashFunctionTy>::empty() const
+{
+ return (0 == m_NumOfEntries);
+}
+
+/// init - initialize the hash table.
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+void HashTableImpl<HashEntryTy, HashFunctionTy>::init(unsigned int pInitSize)
+{
+ m_NumOfBuckets = pInitSize? compute_bucket_count(pInitSize): NumOfInitBuckets;
+
+ m_NumOfEntries = 0;
+ m_NumOfTombstones = 0;
+
+ /** calloc also set bucket.Item = bucket_type::getEmptyStone() **/
+ m_Buckets = (bucket_type*)calloc(m_NumOfBuckets, sizeof(bucket_type));
+}
+
+/// lookUpBucketFor - look up the bucket whose key is pKey
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+unsigned int
+HashTableImpl<HashEntryTy, HashFunctionTy>::lookUpBucketFor(
+ const typename HashTableImpl<HashEntryTy, HashFunctionTy>::key_type& pKey)
+{
+ if (0 == m_NumOfBuckets) {
+ // NumOfBuckets is changed after init(pInitSize)
+ init(NumOfInitBuckets);
+ }
+
+ unsigned int full_hash = m_Hasher(pKey);
+ unsigned int index = full_hash % m_NumOfBuckets;
+
+ const unsigned int probe = 1;
+ int firstTombstone = -1;
+
+ // linear probing
+ while(true) {
+ bucket_type& bucket = m_Buckets[index];
+ // If we found an empty bucket, this key isn't in the table yet, return it.
+ if (bucket_type::getEmptyBucket() == bucket.Entry) {
+ if (-1 != firstTombstone) {
+ m_Buckets[firstTombstone].FullHashValue = full_hash;
+ return firstTombstone;
+ }
+
+ bucket.FullHashValue = full_hash;
+ return index;
+ }
+
+ if (bucket_type::getTombstone() == bucket.Entry) {
+ if (-1 == firstTombstone) {
+ firstTombstone = index;
+ }
+ }
+ else if (bucket.FullHashValue == full_hash) {
+ if (bucket.Entry->compare(pKey)) {
+ return index;
+ }
+ }
+
+ index += probe;
+ if (index == m_NumOfBuckets)
+ index = 0;
+ }
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+int
+HashTableImpl<HashEntryTy, HashFunctionTy>::findKey(
+ const typename HashTableImpl<HashEntryTy, HashFunctionTy>::key_type& pKey) const
+{
+ if (0 == m_NumOfBuckets)
+ return -1;
+
+ unsigned int full_hash = m_Hasher(pKey);
+ unsigned int index = full_hash % m_NumOfBuckets;
+
+ const unsigned int probe = 1;
+ // linear probing
+ while (true) {
+ bucket_type &bucket = m_Buckets[index];
+
+ if (bucket_type::getEmptyBucket() == bucket.Entry)
+ return -1;
+
+ if (bucket_type::getTombstone() == bucket.Entry) {
+ // Ignore tombstones.
+ }
+ else if (full_hash == bucket.FullHashValue) {
+ // get string, compare, if match, return index
+ if (bucket.Entry->compare(pKey))
+ return index;
+ }
+ index += probe;
+ if (index == m_NumOfBuckets)
+ index = 0;
+ }
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+void HashTableImpl<HashEntryTy, HashFunctionTy>::mayRehash()
+{
+
+ unsigned int new_size;
+ // If the hash table is now more than 3/4 full, or if fewer than 1/8 of
+ // the buckets are empty (meaning that many are filled with tombstones),
+ // grow/rehash the table.
+ if ((m_NumOfEntries<<2) > m_NumOfBuckets*3)
+ new_size = compute_bucket_count(m_NumOfBuckets);
+ else if (((m_NumOfBuckets-(m_NumOfEntries+m_NumOfTombstones))<<3) < m_NumOfBuckets)
+ new_size = m_NumOfBuckets;
+ else
+ return;
+
+ doRehash(new_size);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy>
+void HashTableImpl<HashEntryTy, HashFunctionTy>::doRehash(unsigned int pNewSize)
+{
+ bucket_type* new_table = (bucket_type*)calloc(pNewSize, sizeof(bucket_type));
+
+ // Rehash all the items into their new buckets. Luckily :) we already have
+ // the hash values available, so we don't have to recall hash function again.
+ for (bucket_type *IB = m_Buckets, *E = m_Buckets+m_NumOfBuckets; IB != E; ++IB) {
+ if (IB->Entry != bucket_type::getEmptyBucket() &&
+ IB->Entry != bucket_type::getTombstone()) {
+ // Fast case, bucket available.
+ unsigned full_hash = IB->FullHashValue;
+ unsigned new_bucket = full_hash % pNewSize;
+ if (bucket_type::getEmptyBucket() == new_table[new_bucket].Entry) {
+ new_table[new_bucket].Entry = IB->Entry;
+ new_table[new_bucket].FullHashValue = full_hash;
+ continue;
+ }
+
+ // Otherwise probe for a spot.
+ const unsigned int probe = 1;
+ do {
+ new_bucket += probe;
+ if (new_bucket == pNewSize)
+ new_bucket = 0;
+ } while (new_table[new_bucket].Entry != bucket_type::getEmptyBucket());
+
+ // Finally found a slot. Fill it in.
+ new_table[new_bucket].Entry = IB->Entry;
+ new_table[new_bucket].FullHashValue = full_hash;
+ }
+ }
+
+ free(m_Buckets);
+
+ m_Buckets = new_table;
+ m_NumOfBuckets = pNewSize;
+ m_NumOfTombstones = 0;
+}
+
diff --git a/include/mcld/ADT/HashEntry.h b/include/mcld/ADT/HashEntry.h
new file mode 100644
index 0000000..c034783
--- /dev/null
+++ b/include/mcld/ADT/HashEntry.h
@@ -0,0 +1,95 @@
+//===- HashEntry.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_HASH_ENTRY_H
+#define MCLD_HASH_ENTRY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld {
+
+/** forward declaration **/
+template<typename HashEntryTy>
+class EntryFactory;
+
+/** \class HashEntry
+ * \brief HashEntry is the item in the bucket of hash table.
+ *
+ * mcld::HashEntry illustrates the demand from mcld::HashTable.
+ * Since HashTable can change the definition of the HashEntry by changing
+ * the template argument. class mcld::HashEntry here is used to show the
+ * basic interfaces that HashTable requests. You can define your own entry
+ * of the hash table which has no relation to mcld::HashEntry
+ *
+ * Since mcld::HashEntry here is a special class whose size is changing,
+ * derive a new class from it is risky. Make sure you understand what you
+ * are doing when you let a new class inherit from mcld::HashEntry.
+ */
+template <typename KeyType, typename ValueType, typename KeyCompare>
+class HashEntry
+{
+public:
+ typedef KeyType key_type;
+ typedef ValueType value_type;
+ typedef KeyCompare key_compare;
+
+private:
+ typedef HashEntry<KeyType, ValueType, KeyCompare> Self;
+ friend class EntryFactory<Self>;
+
+private:
+ HashEntry(const KeyType& pKey);
+ ~HashEntry();
+
+public:
+ KeyType& key()
+ { return m_Key; }
+
+ const KeyType& key() const
+ { return m_Key; }
+
+ ValueType& value()
+ { return m_Value; }
+
+ const ValueType& value() const
+ { return m_Value; }
+
+ void setValue(const ValueType& pValue)
+ { m_Value = pValue; }
+
+ bool compare(const key_type& pKey);
+
+public:
+ KeyType m_Key;
+ ValueType m_Value;
+};
+
+template <typename HashEntryTy>
+class EntryFactory
+{
+public:
+ typedef HashEntryTy entry_type;
+ typedef typename HashEntryTy::key_type key_type;
+ typedef typename HashEntryTy::value_type value_type;
+
+public:
+ EntryFactory();
+ ~EntryFactory();
+
+ HashEntryTy* produce(const key_type& pKey);
+ void destroy(HashEntryTy* pEntry);
+};
+
+#include "HashEntry.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashEntry.tcc b/include/mcld/ADT/HashEntry.tcc
new file mode 100644
index 0000000..fdd886b
--- /dev/null
+++ b/include/mcld/ADT/HashEntry.tcc
@@ -0,0 +1,53 @@
+//===- HashEntry.tcc ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashEntry
+template <typename KeyType, typename ValueType, typename KeyCompare>
+HashEntry<KeyType, ValueType, KeyCompare>::HashEntry(const KeyType& pKey)
+ : m_Key(pKey) {
+}
+
+template <typename KeyType, typename ValueType, typename KeyCompare>
+HashEntry<KeyType, ValueType, KeyCompare>::~HashEntry()
+{
+}
+
+template <typename KeyType, typename ValueType, typename KeyCompare>
+bool HashEntry<KeyType, ValueType, KeyCompare>::compare(const KeyType& pKey)
+{
+ static KeyCompare comparator;
+ return comparator(m_Key, pKey);
+}
+
+//===--------------------------------------------------------------------===//
+// template implementation of EntryFactory
+template <typename HashEntryTy>
+EntryFactory<HashEntryTy>::EntryFactory()
+{
+}
+
+template <typename HashEntryTy>
+EntryFactory<HashEntryTy>::~EntryFactory()
+{
+}
+
+template <typename HashEntryTy>
+void EntryFactory<HashEntryTy>::destroy(HashEntryTy* pEntry)
+{
+ delete pEntry;
+}
+
+template <typename HashEntryTy>
+HashEntryTy*
+EntryFactory<HashEntryTy>::produce(const typename EntryFactory<HashEntryTy>::key_type& pKey)
+{
+ return new HashEntryTy(pKey);
+}
+
diff --git a/include/mcld/ADT/HashIterator.h b/include/mcld/ADT/HashIterator.h
new file mode 100644
index 0000000..92ccdc5
--- /dev/null
+++ b/include/mcld/ADT/HashIterator.h
@@ -0,0 +1,323 @@
+//===- HashIterator.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_HASH_ITERATOR_H
+#define MCLD_HASH_ITERATOR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld {
+
+/** \class ChainIteratorBase
+ * \brief ChaintIteratorBase follows the HashEntryTy with the same hash value.
+ */
+template<typename HashTableImplTy>
+class ChainIteratorBase
+{
+public:
+ typedef HashTableImplTy hash_table;
+ typedef typename HashTableImplTy::key_type key_type;
+ typedef typename HashTableImplTy::entry_type entry_type;
+ typedef typename HashTableImplTy::bucket_type bucket_type;
+
+public:
+ ChainIteratorBase()
+ : m_pHashTable(0), m_HashValue(0), m_Index(0), m_EndIndex(0)
+ { }
+
+ ChainIteratorBase(HashTableImplTy* pTable, const key_type& pKey)
+ : m_pHashTable(pTable)
+ {
+ m_HashValue = pTable->hash()(pKey);
+ m_EndIndex = m_Index = m_HashValue % m_pHashTable->m_NumOfBuckets;
+ const unsigned int probe = 1;
+ while(true) {
+ bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
+ if (bucket_type::getTombstone() == bucket.Entry) {
+ // Ignore tombstones.
+ }
+ else if (m_HashValue == bucket.FullHashValue) {
+ if (bucket.Entry->compare(pKey)) {
+ m_EndIndex = m_Index;
+ break;
+ }
+ }
+ m_Index += probe;
+ if (m_Index == m_pHashTable->m_NumOfBuckets)
+ m_Index = 0;
+ // doesn't exist
+ if (m_EndIndex == m_Index) {
+ reset();
+ break;
+ }
+ }
+ }
+
+ ChainIteratorBase(const ChainIteratorBase& pCopy)
+ : m_pHashTable(pCopy.m_pHashTable),
+ m_Index(pCopy.m_Index),
+ m_EndIndex(pCopy.m_EndIndex),
+ m_HashValue(pCopy.m_HashValue)
+ { }
+
+ ChainIteratorBase& assign(const ChainIteratorBase& pCopy) {
+ m_pHashTable = pCopy.m_pHashTable;
+ m_Index = pCopy.m_Index;
+ m_EndIndex = pCopy.m_EndIndex;
+ m_HashValue = pCopy.m_HashValue;
+ return *this;
+ }
+
+ inline bucket_type* getBucket() {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline const bucket_type* getBucket() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline entry_type* getEntry() {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline const entry_type* getEntry() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline void reset() {
+ m_pHashTable = 0;
+ m_Index = 0;
+ m_EndIndex = 0;
+ m_HashValue = 0;
+ }
+
+ inline void advance() {
+ if (0 == m_pHashTable)
+ return;
+ const unsigned int probe = 1;
+ while(true) {
+ m_Index += probe;
+ if (m_Index == m_pHashTable->m_NumOfBuckets)
+ m_Index = 0;
+ // reach end()
+ if (m_Index == m_EndIndex) {
+ reset();
+ return;
+ }
+
+ bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
+
+ if (bucket_type::getTombstone() == bucket.Entry ||
+ bucket_type::getEmptyBucket() == bucket.Entry) {
+ // Ignore tombstones.
+ }
+ else if (m_HashValue == bucket.FullHashValue) {
+ return;
+ }
+ }
+ }
+
+ bool operator==(const ChainIteratorBase& pCopy) const {
+ if (m_pHashTable == pCopy.m_pHashTable) {
+ if (0 == m_pHashTable)
+ return true;
+ return ((m_HashValue == pCopy.m_HashValue) &&
+ (m_EndIndex == pCopy.m_EndIndex) &&
+ (m_Index == pCopy.m_Index));
+ }
+ return false;
+ }
+
+ bool operator!=(const ChainIteratorBase& pCopy) const
+ { return !(*this == pCopy); }
+
+private:
+ HashTableImplTy* m_pHashTable;
+ unsigned int m_Index;
+ unsigned int m_HashValue;
+ unsigned int m_EndIndex;
+};
+
+/** \class EntryIteratorBase
+ * \brief EntryIteratorBase walks over hash table by the natural layout of the
+ * buckets
+ */
+template<typename HashTableImplTy>
+class EntryIteratorBase
+{
+public:
+ typedef HashTableImplTy hash_table;
+ typedef typename HashTableImplTy::key_type key_type;
+ typedef typename HashTableImplTy::entry_type entry_type;
+ typedef typename HashTableImplTy::bucket_type bucket_type;
+
+public:
+ EntryIteratorBase()
+ : m_pHashTable(0), m_Index(0)
+ { }
+
+ EntryIteratorBase(HashTableImplTy* pTable,
+ unsigned int pIndex)
+ : m_pHashTable(pTable), m_Index(pIndex)
+ { }
+
+ EntryIteratorBase(const EntryIteratorBase& pCopy)
+ : m_pHashTable(pCopy.m_pHashTable), m_Index(pCopy.m_Index)
+ { }
+
+ EntryIteratorBase& assign(const EntryIteratorBase& pCopy) {
+ m_pHashTable = pCopy.m_pHashTable;
+ m_Index = pCopy.m_Index;
+ return *this;
+ }
+
+ inline bucket_type* getBucket() {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline const bucket_type* getBucket() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return &(m_pHashTable->m_Buckets[m_Index]);
+ }
+
+ inline entry_type* getEntry() {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline const entry_type* getEntry() const {
+ if (0 == m_pHashTable)
+ return 0;
+ return m_pHashTable->m_Buckets[m_Index].Entry;
+ }
+
+ inline void reset() {
+ m_pHashTable = 0;
+ m_Index = 0;
+ }
+
+ inline void advance() {
+ if (0 == m_pHashTable)
+ return;
+ do {
+ ++m_Index;
+ if (m_pHashTable->m_NumOfBuckets == m_Index) { // to the end
+ reset();
+ return;
+ }
+ } while(bucket_type::getEmptyBucket() == m_pHashTable->m_Buckets[m_Index].Entry ||
+ bucket_type::getTombstone() == m_pHashTable->m_Buckets[m_Index].Entry);
+ }
+
+ bool operator==(const EntryIteratorBase& pCopy) const
+ { return ((m_pHashTable == pCopy.m_pHashTable) &&
+ (m_Index == pCopy.m_Index)); }
+
+ bool operator!=(const EntryIteratorBase& pCopy) const
+ { return !(*this == pCopy); }
+
+private:
+ HashTableImplTy* m_pHashTable;
+ unsigned int m_Index;
+
+};
+
+/** \class HashIterator
+ * \brief HashIterator provides a policy-based iterator.
+ *
+ * HashTable has two kinds of iterators. One is used to traverse buckets
+ * with the same hash value; the other is used to traverse all entries of the
+ * hash table.
+ *
+ * HashIterator is a template policy-based iterator, which can change its
+ * behavior by change the template argument IteratorBase. HashTable defines
+ * above two iterators by defining HashIterators with different IteratorBase.
+ */
+template<typename IteratorBase,
+ typename Traits>
+class HashIterator : public IteratorBase
+{
+public:
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef IteratorBase Base;
+
+ typedef HashIterator<IteratorBase,
+ Traits> Self;
+
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef HashIterator<IteratorBase,
+ nonconst_traits> iterator;
+
+ typedef typename traits::const_traits const_traits;
+ typedef HashIterator<IteratorBase,
+ const_traits> const_iterator;
+ typedef std::forward_iterator_tag iterator_category;
+
+public:
+ HashIterator()
+ : IteratorBase()
+ { }
+
+ /// HashIterator - constructor for EntryIterator
+ HashIterator(typename IteratorBase::hash_table* pTable, unsigned int pIndex)
+ : IteratorBase(pTable, pIndex)
+ { }
+
+ /// HashIterator - constructor for ChainIterator
+ explicit HashIterator(typename IteratorBase::hash_table* pTable,
+ const typename IteratorBase::key_type& pKey,
+ int)
+ : IteratorBase(pTable, pKey)
+ { }
+
+ HashIterator(const HashIterator& pCopy)
+ : IteratorBase(pCopy)
+ { }
+
+ ~HashIterator()
+ { }
+
+ HashIterator& operator=(const HashIterator& pCopy) {
+ IteratorBase::assign(pCopy);
+ return *this;
+ }
+
+ // ----- operators ----- //
+ Self& operator++() {
+ this->Base::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ this->Base::advance();
+ return tmp;
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashTable.h b/include/mcld/ADT/HashTable.h
new file mode 100644
index 0000000..dfc2f5a
--- /dev/null
+++ b/include/mcld/ADT/HashTable.h
@@ -0,0 +1,126 @@
+//===- HashTable.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_HASH_TABLE_H
+#define MCLD_HASH_TABLE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/HashBase.h"
+#include "mcld/ADT/HashIterator.h"
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/Support/Allocators.h"
+#include <utility>
+
+namespace mcld
+{
+
+/** \class HashTable
+ * \brief HashTable is a hash table which follows boost::unordered_map, but it
+ * is open addressing and can linear probing.
+ *
+ * mcld::HashTable is a linear probing hash table. It does not allocate
+ * the memory space of the entries by itself. Instead, entries are allocated
+ * outside and then emplaced into the hash table.
+ */
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+class HashTable : public HashTableImpl<HashEntryTy, HashFunctionTy>,
+ private Uncopyable
+{
+private:
+ typedef HashTableImpl<HashEntryTy, HashFunctionTy> BaseTy;
+
+public:
+ typedef size_t size_type;
+ typedef HashFunctionTy hasher;
+ typedef HashEntryTy entry_type;
+ typedef typename BaseTy::bucket_type bucket_type;
+ typedef typename HashEntryTy::key_type key_type;
+
+ typedef HashIterator<ChainIteratorBase<BaseTy>,
+ NonConstTraits<HashEntryTy> > chain_iterator;
+ typedef HashIterator<ChainIteratorBase<const BaseTy>,
+ ConstTraits<HashEntryTy> > const_chain_iterator;
+
+ typedef HashIterator<EntryIteratorBase<BaseTy>,
+ NonConstTraits<HashEntryTy> > entry_iterator;
+ typedef HashIterator<EntryIteratorBase<const BaseTy>,
+ ConstTraits<HashEntryTy> > const_entry_iterator;
+
+ typedef entry_iterator iterator;
+ typedef const_entry_iterator const_iterator;
+
+public:
+ // ----- constructor ----- //
+ explicit HashTable(size_type pSize=3);
+ ~HashTable();
+
+ EntryFactoryTy& getEntryFactory()
+ { return m_EntryFactory; }
+
+ // ----- modifiers ----- //
+ void clear();
+
+ /// insert - insert a new element to the container. The element is
+ // constructed in-place, i.e. no copy or move operations are performed.
+ // If the element already exists, return the element, and set pExist true.
+ entry_type* insert(const key_type& pKey, bool& pExist);
+
+ /// erase - remove the element with the same key
+ size_type erase(const key_type& pKey);
+
+ // ----- lookups ----- //
+ /// find - finds an element with key pKey
+ // If the element does not exist, return end()
+ iterator find(const key_type& pKey);
+
+ /// find - finds an element with key pKey, constant version
+ // If the element does not exist, return end()
+ const_iterator find(const key_type& pKey) const;
+
+ size_type count(const key_type& pKey) const;
+
+ // ----- hash policy ----- //
+ float load_factor() const;
+
+ /// rehash - if the load factor is larger than 75%, or the empty buckets is
+ // less than 12.5%, the rehash the hash table
+ void rehash();
+
+ /// rehash - immediately re-new the hash table to the size pCount, and
+ // rehash all elements.
+ void rehash(size_type pCount);
+
+ // ----- iterators ----- //
+ iterator begin();
+ iterator end();
+
+ const_entry_iterator begin() const;
+ const_entry_iterator end() const;
+
+ chain_iterator begin(const key_type& pKey);
+ chain_iterator end(const key_type& pKey);
+ const_chain_iterator begin(const key_type& pKey) const;
+ const_chain_iterator end(const key_type& pKey) const;
+
+private:
+ EntryFactoryTy m_EntryFactory;
+
+};
+
+#include "HashTable.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/HashTable.tcc b/include/mcld/ADT/HashTable.tcc
new file mode 100644
index 0000000..6fb05a3
--- /dev/null
+++ b/include/mcld/ADT/HashTable.tcc
@@ -0,0 +1,268 @@
+//===- HashTable.tcc ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===--------------------------------------------------------------------===//
+// template implementation of HashTable
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::HashTable(size_type pSize)
+ : HashTableImpl<HashEntryTy, HashFunctionTy>(pSize), m_EntryFactory()
+{
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::~HashTable()
+{
+ if (BaseTy::empty())
+ return;
+
+ /** clean up **/
+ for (unsigned int i=0; i < BaseTy::m_NumOfBuckets; ++i) {
+ if (bucket_type::getEmptyBucket() != BaseTy::m_Buckets[i].Entry &&
+ bucket_type::getTombstone() != BaseTy::m_Buckets[i].Entry ) {
+ m_EntryFactory.destroy(BaseTy::m_Buckets[i].Entry);
+ }
+ }
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+void HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::clear()
+{
+ if (BaseTy::empty())
+ return;
+
+ /** clean up **/
+ for (unsigned int i=0; i < BaseTy::m_NumOfBuckets; ++i) {
+ if (bucket_type::getEmptyBucket() != BaseTy::m_Buckets[i].Entry ) {
+ if (bucket_type::getTombstone() != BaseTy::m_Buckets[i].Entry ) {
+ m_EntryFactory.destroy(BaseTy::m_Buckets[i].Entry);
+ }
+ BaseTy::m_Buckets[i].Entry = bucket_type::getEmptyBucket();
+ }
+ }
+ BaseTy::m_NumOfEntries = 0;
+ BaseTy::m_NumOfTombstones = 0;
+}
+
+/// insert - insert a new element to the container. If the element already
+// exist, return the element.
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::entry_type*
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::insert(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey,
+ bool& pExist)
+{
+ unsigned int index = BaseTy::lookUpBucketFor(pKey);
+ bucket_type& bucket = BaseTy::m_Buckets[index];
+ entry_type* entry = bucket.Entry;
+ if (bucket_type::getEmptyBucket() != entry &&
+ bucket_type::getTombstone() != entry) {
+ // Already exist in the table
+ pExist = true;
+ return entry;
+ }
+
+ // find a tombstone
+ if (bucket_type::getTombstone() == entry)
+ --BaseTy::m_NumOfTombstones;
+
+ entry = bucket.Entry = m_EntryFactory.produce(pKey);
+ ++BaseTy::m_NumOfEntries;
+ BaseTy::mayRehash();
+ pExist = false;
+ return entry;
+}
+
+/// erase - remove the elements with the pKey
+// @return the number of removed elements.
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::size_type
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::erase(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ int index;
+ if (-1 == (index = BaseTy::findKey(pKey)))
+ return 0;
+
+ bucket_type& bucket = BaseTy::m_Buckets[index];
+ m_EntryFactory.destroy(bucket.Entry);
+ bucket.Entry = bucket_type::getTombstone();
+
+ --BaseTy::m_NumOfEntries;
+ ++BaseTy::m_NumOfTombstones;
+ BaseTy::mayRehash();
+ return 1;
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::find(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ int index;
+ if (-1 == (index = BaseTy::findKey(pKey)))
+ return end();
+ return iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::find(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ int index;
+ if (-1 == (index = BaseTy::findKey(pKey)))
+ return end();
+ return const_iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::size_type
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::count(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ const_chain_iterator bucket, bEnd = end(pKey);
+ size_type count = 0;
+ for (bucket = begin(pKey); bucket != bEnd; ++bucket)
+ ++count;
+ return count;
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+float HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::load_factor() const
+{
+ return ((float)BaseTy::m_NumOfEntries/(float)BaseTy::m_NumOfBuckets);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+void
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::rehash()
+{
+ BaseTy::mayRehash();
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+void
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::rehash(
+ typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::size_type pCount)
+{
+ BaseTy::doRehash(pCount);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin()
+{
+ if (BaseTy::empty())
+ return iterator(this, 0);
+ unsigned int index = 0;
+ while (bucket_type::getTombstone() == BaseTy::m_Buckets[index].Entry ||
+ bucket_type::getEmptyBucket() == BaseTy::m_Buckets[index].Entry) {
+ ++index;
+ }
+ return iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end()
+{
+ return iterator(NULL, 0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin() const
+{
+ if (BaseTy::empty())
+ return const_iterator(this, 0);
+ unsigned int index = 0;
+ while (bucket_type::getTombstone() == BaseTy::m_Buckets[index].Entry ||
+ bucket_type::getEmptyBucket() == BaseTy::m_Buckets[index].Entry) {
+ ++index;
+ }
+ return const_iterator(this, index);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end() const
+{
+ return const_iterator(NULL, 0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ return chain_iterator(this, pKey, 0x0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey)
+{
+ return chain_iterator();
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::begin(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ return const_chain_iterator(this, pKey, 0x0);
+}
+
+template<typename HashEntryTy,
+ typename HashFunctionTy,
+ typename EntryFactoryTy>
+typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::const_chain_iterator
+HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::end(
+ const typename HashTable<HashEntryTy, HashFunctionTy, EntryFactoryTy>::key_type& pKey) const
+{
+ return const_chain_iterator();
+}
+
diff --git a/include/mcld/ADT/SizeTraits.h b/include/mcld/ADT/SizeTraits.h
new file mode 100644
index 0000000..8d307bd
--- /dev/null
+++ b/include/mcld/ADT/SizeTraits.h
@@ -0,0 +1,102 @@
+//===- SizeTraits.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SIZE_TRAITS_H
+#define MCLD_SIZE_TRAITS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+
+namespace mcld
+{
+
+template<size_t SIZE>
+struct SizeTraits;
+
+template<>
+class SizeTraits<32>
+{
+ typedef uint32_t Address;
+ typedef uint32_t Offset;
+ typedef uint32_t Word;
+ typedef int32_t SWord;
+};
+
+template<>
+class SizeTraits<64>
+{
+ typedef uint64_t Address;
+ typedef uint64_t Offset;
+ typedef uint64_t Word;
+ typedef int64_t SWord;
+};
+
+/// alignAddress - helper function to align an address with given alignment
+/// constraint
+///
+/// @param pAddr - the address to be aligned
+/// @param pAlignConstraint - the alignment used to align the given address
+inline void alignAddress(uint64_t& pAddr, uint64_t pAlignConstraint)
+{
+ if (pAlignConstraint != 0)
+ pAddr = (pAddr + pAlignConstraint - 1) &~ (pAlignConstraint - 1);
+}
+
+template<size_t Constraint>
+uint64_t Align(uint64_t pAddress);
+
+template<>
+inline uint64_t Align<32>(uint64_t pAddress)
+{
+ return (pAddress + 0x1F) & (~0x1F);
+}
+
+template<>
+inline uint64_t Align<64>(uint64_t pAddress)
+{
+ return (pAddress + 0x3F) & (~0x3F);
+}
+
+/// bswap16 - byte swap 16-bit version
+/// @ref binary utilities - elfcpp_swap
+inline uint16_t bswap16(uint16_t pData)
+{
+ return ((pData >> 8) & 0xFF) | ((pData & 0xFF) << 8);
+}
+
+/// bswap32 - byte swap 32-bit version
+/// @ref elfcpp_swap
+inline uint32_t bswap32(uint32_t pData)
+{
+ return (((pData & 0xFF000000) >> 24) |
+ ((pData & 0x00FF0000) >> 8) |
+ ((pData & 0x0000FF00) << 8) |
+ ((pData & 0x000000FF) << 24));
+
+}
+
+/// bswap64 - byte swap 64-bit version
+/// @ref binary utilities - elfcpp_swap
+inline uint64_t bswap64(uint64_t pData)
+{
+ return (((pData & 0xFF00000000000000ULL) >> 56) |
+ ((pData & 0x00FF000000000000ULL) >> 40) |
+ ((pData & 0x0000FF0000000000ULL) >> 24) |
+ ((pData & 0x000000FF00000000ULL) >> 8) |
+ ((pData & 0x00000000FF000000ULL) << 8) |
+ ((pData & 0x0000000000FF0000ULL) << 24) |
+ ((pData & 0x000000000000FF00ULL) << 40) |
+ ((pData & 0x00000000000000FFULL) << 56));
+}
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/StringHash.h b/include/mcld/ADT/StringHash.h
new file mode 100644
index 0000000..f100a49
--- /dev/null
+++ b/include/mcld/ADT/StringHash.h
@@ -0,0 +1,289 @@
+//===- StringHash.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_STRING_HASH_FUNCTION_H
+#define MCLD_STRING_HASH_FUNCTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <functional>
+
+namespace mcld
+{
+
+enum StringHashType
+{
+ RS,
+ JS,
+ PJW,
+ ELF,
+ BKDR,
+ SDBM,
+ DJB,
+ DEK,
+ BP,
+ FNV,
+ AP
+};
+
+/** \class template<size_t TYPE> StringHash
+ * \brief the template StringHash class, for specification
+ */
+template<size_t TYPE>
+struct StringHash : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ llvm::report_fatal_error("Undefined StringHash function.\n");
+ }
+};
+
+/** \class StringHash<RSHash>
+ * \brief RS StringHash funciton
+ */
+template<>
+struct StringHash<RS> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const unsigned int b = 378551;
+ size_t a = 63689;
+ size_t hash_val = 0;
+
+ for(unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val = hash_val * a + pKey[i];
+ a = a * b;
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<JSHash>
+ * \brief JS hash funciton
+ */
+template<>
+struct StringHash<JS> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 1315423911;
+
+ for(unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val ^= ((hash_val << 5) + pKey[i] + (hash_val >> 2));
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<PJW>
+ * \brief P.J. Weinberger hash function
+ */
+template<>
+struct StringHash<PJW> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
+ const unsigned int ThreeQuarters = (unsigned int)((BitsInUnsignedInt * 3) / 4);
+ const unsigned int OneEighth = (unsigned int)(BitsInUnsignedInt / 8);
+ const unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
+ size_t hash_val = 0;
+ size_t test = 0;
+
+ for(unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val = (hash_val << OneEighth) + pKey[i];
+
+ if((test = hash_val & HighBits) != 0) {
+ hash_val = (( hash_val ^ (test >> ThreeQuarters)) & (~HighBits));
+ }
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<ELF>
+ * \brief ELF hash function.
+ */
+template<>
+struct StringHash<ELF> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 0;
+ size_t x = 0;
+
+ for (unsigned int i = 0; i < pKey.size(); ++i) {
+ hash_val = (hash_val << 4) + pKey[i];
+ if((x = hash_val & 0xF0000000L) != 0)
+ hash_val ^= (x >> 24);
+ hash_val &= ~x;
+ }
+ return hash_val;
+ }
+};
+
+/** \class StringHash<BKDR>
+ * \brief BKDR hash function
+ */
+template<>
+struct StringHash<BKDR> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const size_t seed = 131;
+ size_t hash_val = 0;
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = (hash_val * seed) + pKey[i];
+ return hash_val;
+ }
+};
+
+
+/** \class StringHash<SDBM>
+ * \brief SDBM hash function
+ * 0.049s in 100000 test
+ */
+template<>
+struct StringHash<SDBM> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 0;
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = pKey[i] + (hash_val << 6) + (hash_val << 16) - hash_val;
+ return hash_val;
+ }
+};
+
+/** \class StringHash<DJB>
+ * \brief DJB hash function
+ * 0.057s in 100000 test
+ */
+template<>
+struct StringHash<DJB> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 5381;
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = ((hash_val << 5) + hash_val) + pKey[i];
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<DEK>
+ * \brief DEK hash function
+ * 0.60s
+ */
+template<>
+struct StringHash<DEK> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = pKey.size();
+
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = ((hash_val << 5) ^ (hash_val >> 27)) ^ pKey[i];
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<BP>
+ * \brief BP hash function
+ * 0.057s
+ */
+template<>
+struct StringHash<BP> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ size_t hash_val = 0;
+ for(size_t i = 0; i < pKey.size(); ++i)
+ hash_val = hash_val << 7 ^ pKey[i];
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<FNV>
+ * \brief FNV hash function
+ * 0.058s
+ */
+template<>
+struct StringHash<FNV> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ const size_t fnv_prime = 0x811C9DC5;
+ size_t hash_val = 0;
+ for(size_t i = 0; i < pKey.size(); ++i) {
+ hash_val *= fnv_prime;
+ hash_val ^= pKey[i];
+ }
+
+ return hash_val;
+ }
+};
+
+/** \class StringHash<AP>
+ * \brief AP hash function
+ * 0.060s
+ */
+template<>
+struct StringHash<AP> : public std::unary_function<const llvm::StringRef&, size_t>
+{
+ size_t operator()(const llvm::StringRef& pKey) const
+ {
+ unsigned int hash_val = 0xAAAAAAAA;
+
+ for(size_t i = 0; i < pKey.size(); ++i) {
+ hash_val ^= ((i & 1) == 0)?
+ ((hash_val << 7) ^ pKey[i] * (hash_val >> 3)):
+ (~((hash_val << 11) + (pKey[i] ^ (hash_val >> 5))));
+ }
+
+ return hash_val;
+ }
+};
+
+/** \class template<size_t TYPE> StringCompare
+ * \brief the template StringCompare class, for specification
+ */
+template<typename STRING_TYPE>
+struct StringCompare : public std::binary_function<const STRING_TYPE&, const STRING_TYPE&, bool>
+{
+ bool operator()(const STRING_TYPE& X, const STRING_TYPE& Y) const
+ { return X == Y; }
+};
+
+template<>
+struct StringCompare<const char*> : public std::binary_function<const char*, const char*, bool>
+{
+ bool operator()(const char* X, const char* Y) const
+ { return (0 == std::strcmp(X, Y)); }
+};
+
+template<>
+struct StringCompare<char*> : public std::binary_function<const char*, const char*, bool>
+{
+ bool operator()(const char* X, const char* Y) const
+ { return (0 == std::strcmp(X, Y)); }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/TreeAllocator.h b/include/mcld/ADT/TreeAllocator.h
new file mode 100644
index 0000000..899896c
--- /dev/null
+++ b/include/mcld/ADT/TreeAllocator.h
@@ -0,0 +1,98 @@
+//===- TreeAllocator.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TREE_ALLOCATOR_H
+#define MCLD_TREE_ALLOCATOR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <set>
+#include "mcld/Support/GCFactory.h"
+#include "mcld/ADT/TreeBase.h"
+
+namespace mcld
+{
+
+/** \class NodeFactory
+ * \brief NodeFactory manages the creation and destruction of mcld::Node.
+ *
+ * NodeFactory guarantees all allocated memory are released finally. When
+ * the destructor of NodeFactory is called, all allocated memory are freed.
+ *
+ * NodeFactory provides delegation of memory. Sometimes, we have to merge two
+ * NodeFactories, and NodeFactory::delegate() can move the memory from one
+ * NodeFactories to another.
+ *
+ * @see LinearAllocator
+ */
+template<typename DataType>
+class NodeFactory : public GCFactory<Node<DataType>, 64>
+{
+private:
+ typedef GCFactory<Node<DataType>, 64> Alloc;
+
+public:
+ typedef Node<DataType> NodeType;
+ typedef typename Alloc::iterator iterator;
+ typedef typename Alloc::const_iterator const_iterator;
+
+public:
+ /// produce - produce a node, add it under control
+ NodeType* produce() {
+ NodeType* result = Alloc::allocate();
+ Alloc::construct(result);
+ return result;
+ }
+
+ /// delegate - get the control of chunks owned by the client
+ // after calling delegate(), client will renouce its control
+ // of memory space.
+ void delegate(NodeFactory& pClient) {
+ if (this == &pClient)
+ return;
+
+ if (pClient.empty())
+ return;
+
+ if (Alloc::empty()) {
+ replace(pClient);
+ pClient.renounce();
+ return;
+ }
+
+ // neither me nor client is empty
+ concatenate(pClient);
+ pClient.renounce();
+ }
+
+private:
+ /// renounce - give up the control of all chunks
+ void renounce()
+ { Alloc::reset(); }
+
+ /// replace - be the agent of client.
+ void replace(NodeFactory& pClient) {
+ Alloc::m_pRoot = pClient.Alloc::m_pRoot;
+ Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
+ Alloc::m_AllocatedNum = pClient.Alloc::m_AllocatedNum;
+ Alloc::m_NumAllocData = pClient.Alloc::m_NumAllocData;
+ }
+
+ /// concatenate - conncet two factories
+ void concatenate(NodeFactory& pClient) {
+ Alloc::m_pCurrent->next = pClient.Alloc::m_pRoot;
+ Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
+ Alloc::m_AllocatedNum += pClient.Alloc::m_AllocatedNum;
+ Alloc::m_NumAllocData += pClient.Alloc::m_NumAllocData;
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/TreeBase.h b/include/mcld/ADT/TreeBase.h
new file mode 100644
index 0000000..c518975
--- /dev/null
+++ b/include/mcld/ADT/TreeBase.h
@@ -0,0 +1,127 @@
+//===- TreeBase.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TREE_BASE_H
+#define MCLD_TREE_BASE_H
+#include "mcld/ADT/TypeTraits.h"
+
+namespace mcld
+{
+
+class NodeBase
+{
+public:
+ NodeBase *left;
+ NodeBase *right;
+
+public:
+ NodeBase()
+ : left(0), right(0)
+ { }
+};
+
+namespace proxy
+{
+ template<size_t DIRECT>
+ inline void move(NodeBase *&X)
+ { assert(0 && "not allowed"); }
+
+ template<size_t DIRECT>
+ inline void hook(NodeBase *X, const NodeBase *Y)
+ { assert(0 && "not allowed"); }
+
+} // namespace of template proxy
+
+struct TreeIteratorBase
+{
+public:
+ enum Direct {
+ Leftward,
+ Rightward
+ };
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+public:
+ NodeBase* m_pNode;
+
+public:
+ TreeIteratorBase()
+ : m_pNode(0)
+ { }
+
+ TreeIteratorBase(NodeBase *X)
+ : m_pNode(X)
+ { }
+
+ virtual ~TreeIteratorBase(){};
+
+ template<size_t DIRECT>
+ inline void move() {
+ proxy::move<DIRECT>(m_pNode);
+ }
+
+ bool hasRightChild() const
+ { return ((m_pNode->right) != (m_pNode->right->right)); }
+
+ bool hasLeftChild() const
+ { return ((m_pNode->left) != (m_pNode->left->right)); }
+
+ bool operator==(const TreeIteratorBase& y) const
+ { return this->m_pNode == y.m_pNode; }
+
+ bool operator!=(const TreeIteratorBase& y) const
+ { return this->m_pNode != y.m_pNode; }
+};
+
+namespace proxy
+{
+ template<>
+ inline void move<TreeIteratorBase::Leftward>(NodeBase *&X)
+ { X = X->left; }
+
+ template<>
+ inline void move<TreeIteratorBase::Rightward>(NodeBase *&X)
+ { X = X->right; }
+
+ template<>
+ inline void hook<TreeIteratorBase::Leftward>(NodeBase *X, const NodeBase *Y)
+ { X->left = const_cast<NodeBase*>(Y); }
+
+ template<>
+ inline void hook<TreeIteratorBase::Rightward>(NodeBase* X, const NodeBase* Y)
+ { X->right = const_cast<NodeBase*>(Y); }
+
+} //namespace of template proxy
+
+template<typename DataType>
+class Node : public NodeBase
+{
+public:
+ typedef DataType value_type;
+
+public:
+ value_type* data;
+
+public:
+ Node()
+ : NodeBase(), data(0)
+ { }
+
+ Node(const value_type& pValue)
+ : NodeBase(), data(&pValue)
+ { }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/TypeTraits.h b/include/mcld/ADT/TypeTraits.h
new file mode 100644
index 0000000..90b2224
--- /dev/null
+++ b/include/mcld/ADT/TypeTraits.h
@@ -0,0 +1,71 @@
+//===- TypeTraits.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TYPE_TRAITS_H
+#define MCLD_TYPE_TRAITS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <cstdlib>
+
+namespace mcld
+{
+template<typename DataType>
+struct NonConstTraits;
+
+template<typename DataType>
+struct ConstTraits
+{
+ typedef DataType value_type;
+ typedef const DataType* pointer;
+ typedef const DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+};
+
+template<typename DataType>
+struct NonConstTraits
+{
+ typedef DataType value_type;
+ typedef DataType* pointer;
+ typedef DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+};
+
+template<typename DataType>
+struct ConstIteratorTraits
+{
+ typedef DataType value_type;
+ typedef const DataType* pointer;
+ typedef const DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+ typedef typename DataType::const_iterator iterator;
+};
+
+template<typename DataType>
+struct NonConstIteratorTraits
+{
+ typedef DataType value_type;
+ typedef DataType* pointer;
+ typedef DataType& reference;
+ typedef size_t size_type;
+ typedef ConstTraits<DataType> const_traits;
+ typedef NonConstTraits<DataType> nonconst_traits;
+ typedef typename DataType::iterator iterator;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/ADT/Uncopyable.h b/include/mcld/ADT/Uncopyable.h
new file mode 100644
index 0000000..7ddfbe3
--- /dev/null
+++ b/include/mcld/ADT/Uncopyable.h
@@ -0,0 +1,36 @@
+//===- Uncopyable.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_UNCOPYABLE_H
+#define MCLD_UNCOPYABLE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class Uncopyable
+ * \brief Uncopyable provides the base class to forbit copy operations.
+ *
+ */
+class Uncopyable
+{
+protected:
+ Uncopyable() { }
+ ~Uncopyable() { }
+
+private:
+ Uncopyable(const Uncopyable&); /// NOT TO IMPLEMENT
+ Uncopyable& operator=(const Uncopyable&); /// NOT TO IMPLEMENT
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/CodeGen/SectLinker.h b/include/mcld/CodeGen/SectLinker.h
new file mode 100644
index 0000000..31fae4a
--- /dev/null
+++ b/include/mcld/CodeGen/SectLinker.h
@@ -0,0 +1,107 @@
+//===- SectLinker.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//SectLinker is a base class inherited by target specific linker.
+//This class primarily handles common functionality used by all linkers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SECTION_LINKER_H
+#define SECTION_LINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/CodeGen/MachineFunctionPass.h>
+#include <mcld/Support/PositionDependentOption.h>
+#include <vector>
+
+namespace llvm
+{
+ class Module;
+ class MachineFunction;
+} // namespace of llvm
+
+namespace mcld
+{
+ class MCLDFile;
+ class MCLDDriver;
+ class TargetLDBackend;
+ class AttributeFactory;
+ class SectLinkerOption;
+
+ /** \class SectLinker
+ * \brief SectLinker provides a linking pass for standard compilation flow
+ *
+ * SectLinker is responded for
+ * - provide an interface for target-specific SectLinekr
+ * - set up environment for MCLDDriver
+ * - control AsmPrinter, make sure AsmPrinter has already prepared
+ * all MCSectionDatas for linking
+ *
+ * SectLinker resolves the absolue paths of input arguments.
+ *
+ * @see MachineFunctionPass MCLDDriver
+ */
+ class SectLinker : public llvm::MachineFunctionPass
+ {
+ protected:
+ // Constructor. Although SectLinker has only two arguments,
+ // TargetSectLinker should handle
+ // - enabled attributes
+ // - the default attribute
+ // - the default link script
+ // - the standard symbols
+ SectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend);
+
+ public:
+ virtual ~SectLinker();
+
+ /// addTargetOptions - target SectLinker can hook this function to add
+ /// target-specific inputs
+ virtual void addTargetOptions(llvm::Module &pM,
+ SectLinkerOption &pOption)
+ { }
+
+ /// doInitialization - Read all parameters and set up the AsmPrinter.
+ /// If your pass overrides this, it must make sure to explicitly call
+ /// this implementation.
+ virtual bool doInitialization(llvm::Module &pM);
+
+ /// doFinalization - Shut down the AsmPrinter, and do really linking.
+ /// If you override this in your pass, you must make sure to call it
+ /// explicitly.
+ virtual bool doFinalization(llvm::Module &pM);
+
+ /// runOnMachineFunction
+ /// redirect to AsmPrinter
+ virtual bool runOnMachineFunction(llvm::MachineFunction& pMFn);
+
+ protected:
+ void initializeInputTree(const PositionDependentOptions &pOptions) const;
+
+ AttributeFactory* attrFactory()
+ { return m_pAttrFactory; }
+
+ private:
+ SectLinkerOption *m_pOption;
+
+ protected:
+ TargetLDBackend *m_pLDBackend;
+ MCLDDriver *m_pLDDriver;
+ AttributeFactory *m_pAttrFactory;
+
+ private:
+ static char m_ID;
+ };
+
+} // namespace of MC Linker
+
+#endif
+
diff --git a/include/mcld/CodeGen/SectLinkerOption.h b/include/mcld/CodeGen/SectLinkerOption.h
new file mode 100644
index 0000000..b3e3327
--- /dev/null
+++ b/include/mcld/CodeGen/SectLinkerOption.h
@@ -0,0 +1,57 @@
+//===- SectLinkerOption.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SECTLINKERDATA_H
+#define MCLD_SECTLINKERDATA_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/MC/MCLDInfo.h"
+#include "mcld/Support/PositionDependentOption.h"
+
+#include <string>
+
+namespace mcld
+{
+ class PositionDependentOption;
+
+ /** \class SectLinkerOption
+ * \brief This file collects inputs to linker.
+ */
+ class SectLinkerOption
+ {
+ public:
+ // Constructor.
+ SectLinkerOption(MCLDInfo &pLDInfo);
+
+ // ----- Position-dependent Options ----- //
+ inline void appendOption(PositionDependentOption *pOption)
+ { m_PosDepOptions.push_back(pOption); }
+
+ inline void prependOption(PositionDependentOption *pOption)
+ { m_PosDepOptions.insert(m_PosDepOptions.begin(), pOption); }
+
+ inline const PositionDependentOptions &pos_dep_options() const
+ { return m_PosDepOptions; }
+ inline PositionDependentOptions &pos_dep_options()
+ { return m_PosDepOptions; }
+
+ inline const MCLDInfo &info() const { return *m_pLDInfo; }
+ inline MCLDInfo &info() { return *m_pLDInfo; }
+
+ ~SectLinkerOption();
+
+ private:
+ MCLDInfo *m_pLDInfo;
+ PositionDependentOptions m_PosDepOptions;
+ };
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Config/Config.h b/include/mcld/Config/Config.h
new file mode 100644
index 0000000..362b076
--- /dev/null
+++ b/include/mcld/Config/Config.h
@@ -0,0 +1,26 @@
+//===- Config.h.in --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Hand-coded for Android build
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_CONFIG_H
+#define MCLD_CONFIG_H
+
+namespace mcld {
+namespace internal {
+
+static const char* version="0.2.10.1-18peaks";
+
+} // namespace of internal
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Config/Config.h.in b/include/mcld/Config/Config.h.in
new file mode 100644
index 0000000..6d428c0
--- /dev/null
+++ b/include/mcld/Config/Config.h.in
@@ -0,0 +1,21 @@
+//===- Config.h.in --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_CONFIG_H
+#define MCLD_CONFIG_H
+
+namespace mcld {
+namespace internal {
+
+static const char* version="@MCLD_VERSION@";
+
+} // namespace of internal
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Config/Linkers.def b/include/mcld/Config/Linkers.def
new file mode 100644
index 0000000..2781461
--- /dev/null
+++ b/include/mcld/Config/Linkers.def
@@ -0,0 +1,33 @@
+//===- llvm/Config/Linkers.def - LLVM Linkers -------------------*- C++ -*-===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file enumerates all of the linkers supported by this build of LLVM.
+// Clients of this file should define the LLVM_LINKER macro to be a function-like
+// macro with a single parameter (the name of the target whose exe/dso can be
+// generated); including this file will then enumerate all of the targets with
+// linkers.
+//
+// The set of targets supported by LLVM is generated at configuration
+// time, at which point this header is generated. Do not modify this
+// header directly.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Hand-coded for Android build
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LINKER
+# error Please define the macro LLVM_LINKER(TargetName)
+#endif
+
+#define LLVM_TARGET LLVM_LINKER
+#include <llvm/Config/Targets.def>
+
+#undef LLVM_LINKER
diff --git a/include/mcld/Config/Linkers.def.in b/include/mcld/Config/Linkers.def.in
new file mode 100644
index 0000000..0e09040
--- /dev/null
+++ b/include/mcld/Config/Linkers.def.in
@@ -0,0 +1,28 @@
+//===- llvm/Config/Linkers.def - LLVM Linkers -------------------*- C++ -*-===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file enumerates all of the linkers supported by this build of LLVM.
+// Clients of this file should define the LLVM_LINKER macro to be a function-like
+// macro with a single parameter (the name of the target whose exe/dso can be
+// generated); including this file will then enumerate all of the targets with
+// linkers.
+//
+// The set of targets supported by LLVM is generated at configuration
+// time, at which point this header is generated. Do not modify this
+// header directly.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LINKER
+# error Please define the macro LLVM_LINKER(TargetName)
+#endif
+
+@LLVM_ENUM_LINKERS@
+
+#undef LLVM_LINKER
diff --git a/include/mcld/Config/Targets.def b/include/mcld/Config/Targets.def
new file mode 100644
index 0000000..a0981d6
--- /dev/null
+++ b/include/mcld/Config/Targets.def
@@ -0,0 +1,32 @@
+/*===- llvm/Config/Targets.def - LLVM Target Architectures ------*- C++ -*-===*\
+|* *|
+|* The MCLinker Project *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This file enumerates all of the target architectures supported by *|
+|* this build of LLVM. Clients of this file should define the *|
+|* LLVM_TARGET macro to be a function-like macro with a single *|
+|* parameter (the name of the target); including this file will then *|
+|* enumerate all of the targets. *|
+|* *|
+|* The set of targets supported by LLVM is generated at configuration *|
+|* time, at which point this header is generated. Do not modify this *|
+|* header directly. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+//===----------------------------------------------------------------------===//
+// Hand-coded for Android build
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGET
+# error Please define the macro LLVM_TARGET(TargetName)
+#endif
+
+#include <llvm/Config/Targets.def>
+
+#undef LLVM_TARGET
diff --git a/include/mcld/Config/Targets.def.in b/include/mcld/Config/Targets.def.in
new file mode 100644
index 0000000..a73b9b7
--- /dev/null
+++ b/include/mcld/Config/Targets.def.in
@@ -0,0 +1,28 @@
+/*===- llvm/Config/Targets.def - LLVM Target Architectures ------*- C++ -*-===*\
+|* *|
+|* The MCLinker Project *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This file enumerates all of the target architectures supported by *|
+|* this build of LLVM. Clients of this file should define the *|
+|* LLVM_TARGET macro to be a function-like macro with a single *|
+|* parameter (the name of the target); including this file will then *|
+|* enumerate all of the targets. *|
+|* *|
+|* The set of targets supported by LLVM is generated at configuration *|
+|* time, at which point this header is generated. Do not modify this *|
+|* header directly. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_TARGET
+# error Please define the macro LLVM_TARGET(TargetName)
+#endif
+
+@LLVM_ENUM_TARGETS@
+
+#undef LLVM_TARGET
diff --git a/include/mcld/LD/ArchiveReader.h b/include/mcld/LD/ArchiveReader.h
new file mode 100644
index 0000000..99db0db
--- /dev/null
+++ b/include/mcld/LD/ArchiveReader.h
@@ -0,0 +1,39 @@
+//===- ArchiveReader.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARCHIVE_READER_INTERFACE_H
+#define MCLD_ARCHIVE_READER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/LDReader.h"
+
+namespace mcld
+{
+
+class Input;
+class InputTree;
+
+/** \class ArchiveReader
+ * \brief ArchiveReader provides an common interface for all archive readers.
+ *
+ * ArchiveReader also reads the target-independent parts of an archive file.
+ */
+class ArchiveReader : public LDReader
+{
+public:
+ ArchiveReader();
+ virtual ~ArchiveReader();
+
+ virtual InputTree *readArchive(Input &input) = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/BSDArchiveReader.h b/include/mcld/LD/BSDArchiveReader.h
new file mode 100644
index 0000000..a275621
--- /dev/null
+++ b/include/mcld/LD/BSDArchiveReader.h
@@ -0,0 +1,39 @@
+//===- BSDArchiveReader.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_BSD_ARCHIVE_READER_H
+#define MCLD_BSD_ARCHIVE_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/ArchiveReader.h"
+
+namespace mcld
+{
+
+class Input;
+class InputTree;
+
+/** \class BSDArchiveReader
+ * \brief BSDArchiveReader reads BSD-variant archive files.
+ *
+ */
+class BSDArchiveReader : public ArchiveReader
+{
+public:
+ BSDArchiveReader();
+ ~BSDArchiveReader();
+
+ InputTree *readArchive(Input &input);
+ bool isMyFormat(Input& pInput) const;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/BranchIsland.h b/include/mcld/LD/BranchIsland.h
new file mode 100644
index 0000000..8e5cf9c
--- /dev/null
+++ b/include/mcld/LD/BranchIsland.h
@@ -0,0 +1,30 @@
+//===- BranchIsland.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef BRANCHISLAND_H
+#define BRANCHISLAND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class BranchIsland
+ * \brief BranchIsland is a collection of stubs
+ *
+ */
+class BranchIsland
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DynObjFileFormat.h b/include/mcld/LD/DynObjFileFormat.h
new file mode 100644
index 0000000..7b1626d
--- /dev/null
+++ b/include/mcld/LD/DynObjFileFormat.h
@@ -0,0 +1,29 @@
+//===- header.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DYNOBJFORMAT_H
+#define DYNOBJFORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class DynObjFormat
+ * \brief DynObjFormat describes the file format for dynamic objects.
+ */
+class DynObjFormat : public LDFileFormat
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DynObjReader.h b/include/mcld/LD/DynObjReader.h
new file mode 100644
index 0000000..0900109
--- /dev/null
+++ b/include/mcld/LD/DynObjReader.h
@@ -0,0 +1,45 @@
+//===- DynObjReader.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DYNAMIC_SHARED_OBJECT_READER_H
+#define MCLD_DYNAMIC_SHARED_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/LDReader.h"
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class TargetLDBackend;
+class Input;
+
+/** \class DynObjReader
+ * \brief DynObjReader provides an common interface for different object
+ * formats.
+ */
+class DynObjReader : public LDReader
+{
+protected:
+ DynObjReader()
+ { }
+
+public:
+ virtual ~DynObjReader() { }
+
+ virtual bool readDSO(Input& pFile) = 0;
+
+ virtual bool readSymbols(Input& pFile) = 0;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/DynObjWriter.h b/include/mcld/LD/DynObjWriter.h
new file mode 100644
index 0000000..1c77bd4
--- /dev/null
+++ b/include/mcld/LD/DynObjWriter.h
@@ -0,0 +1,41 @@
+//===- DynObjWriter.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H
+#define MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/LD/LDWriter.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+/** \class DynObjWriter
+ * \brief DynObjWriter provides an common interface for different object
+ * formats.
+ */
+class DynObjWriter : public LDWriter
+{
+protected:
+ // force to have a TargetLDBackend
+ DynObjWriter(TargetLDBackend& pLDBackend)
+ { }
+
+public:
+ virtual ~DynObjWriter() { }
+
+ virtual llvm::error_code writeDynObj(Output& pOutput) = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFDynObjFileFormat.h b/include/mcld/LD/ELFDynObjFileFormat.h
new file mode 100644
index 0000000..9b77e91
--- /dev/null
+++ b/include/mcld/LD/ELFDynObjFileFormat.h
@@ -0,0 +1,38 @@
+//===- ELFDynObjFileFormat.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_OBJECT_FILE_FROMAT_H
+#define MCLD_ELF_DYNAMIC_OBJECT_FILE_FROMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/ELFFileFormat.h>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFDynObjFileFormat
+ * \brief ELFDynObjFileFormat describes the format for ELF dynamic objects.
+ */
+class ELFDynObjFileFormat : public ELFFileFormat
+{
+public:
+ ELFDynObjFileFormat(GNULDBackend& pBackend) : ELFFileFormat(pBackend)
+ {}
+
+ void initObjectType(MCLinker& pLinker);
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFDynObjReader.h b/include/mcld/LD/ELFDynObjReader.h
new file mode 100644
index 0000000..72a3336
--- /dev/null
+++ b/include/mcld/LD/ELFDynObjReader.h
@@ -0,0 +1,51 @@
+//===- ELFDynObjReader.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_SHARED_OBJECT_READER_H
+#define MCLD_ELF_DYNAMIC_SHARED_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/DynObjReader.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class Input;
+class MCLinker;
+class GNULDBackend;
+class ELFReaderIF;
+
+/** \class ELFDynObjReader
+ * \brief ELFDynObjReader reads ELF dynamic shared objects.
+ *
+ */
+class ELFDynObjReader : public DynObjReader
+{
+public:
+ ELFDynObjReader(GNULDBackend& pBackend, MCLinker& pLinker);
+ ~ELFDynObjReader();
+
+ // ----- observers ----- //
+ bool isMyFormat(Input &pFile) const;
+
+ // ----- readers ----- //
+ bool readDSO(Input& pFile);
+
+ bool readSymbols(Input& pInput);
+
+private:
+ ELFReaderIF *m_pELFReader;
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFDynObjWriter.h b/include/mcld/LD/ELFDynObjWriter.h
new file mode 100644
index 0000000..dc0e37b
--- /dev/null
+++ b/include/mcld/LD/ELFDynObjWriter.h
@@ -0,0 +1,53 @@
+//===- ELFDynObjWriter.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H
+#define MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/DenseMap.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/LD/DynObjWriter.h>
+#include <mcld/LD/ELFWriter.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/Support/MemoryArea.h>
+#include <vector>
+#include <utility>
+
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFDynObjWriter
+ * \brief ELFDynObjWriter writes the dynamic sections.
+ */
+class ELFDynObjWriter : public DynObjWriter, private ELFWriter
+{
+public:
+ typedef ELFWriter::FileOffset FileOffset;
+
+public:
+ ELFDynObjWriter(GNULDBackend& pBackend, MCLinker& pLinker);
+ ~ELFDynObjWriter();
+
+ llvm::error_code writeDynObj(Output& pOutput);
+
+private:
+ GNULDBackend& m_Backend;
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFExecFileFormat.h b/include/mcld/LD/ELFExecFileFormat.h
new file mode 100644
index 0000000..315300a
--- /dev/null
+++ b/include/mcld/LD/ELFExecFileFormat.h
@@ -0,0 +1,38 @@
+//===- ELFExecFileFormat.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_EXEC_FILE_FORMAT_H
+#define MCLD_ELF_EXEC_FILE_FORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/ELFFileFormat.h>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFExecFileFormat
+ * \brief ELFExecFileFormat describes the format for ELF dynamic objects.
+ */
+class ELFExecFileFormat : public ELFFileFormat
+{
+public:
+ ELFExecFileFormat(GNULDBackend& pBackend) : ELFFileFormat(pBackend)
+ {}
+
+ void initObjectType(MCLinker& pLinker)
+ { /** TODO **/ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFFileFormat.h b/include/mcld/LD/ELFFileFormat.h
new file mode 100644
index 0000000..94d3df3
--- /dev/null
+++ b/include/mcld/LD/ELFFileFormat.h
@@ -0,0 +1,654 @@
+//===- LDFileFormat.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_FILE_FORMAT_H
+#define MCLD_ELF_FILE_FORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class MCLinker;
+
+/** \class ELFFileFormat
+ * \brief ELFFileFormat describes the common file formats in ELF.
+ * LDFileFormats control the formats of the output file.
+ *
+ * @ref "Object Files," Ch. 4, in System V Application Binary Interface,
+ * Fourth Edition.
+ *
+ * @ref "Object Format," Ch. 10, in ISO/IEC 23360 Part 1:2010(E), Linux
+ * Standard Base Core Specification 4.1.
+ */
+class ELFFileFormat : public LDFileFormat
+{
+public:
+ ELFFileFormat(GNULDBackend& pBackend);
+
+ virtual ~ELFFileFormat();
+
+ virtual void initObjectFormat(MCLinker& pLinker);
+
+ virtual void initObjectType(MCLinker& pLinker) = 0;
+
+ // ----- capacity ----- //
+ /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
+ bool hasNULLSection() const
+ { return (NULL != f_pNULLSection) && (0 != f_pNULLSection->size()); }
+
+ bool hasGOT() const
+ { return (NULL != f_pGOT) && (0 != f_pGOT->size()); }
+
+ bool hasPLT() const
+ { return (NULL != f_pPLT) && (0 != f_pPLT->size()); }
+
+ bool hasRelDyn() const
+ { return (NULL != f_pRelDyn) && (0 != f_pRelDyn->size()); }
+
+ bool hasRelPlt() const
+ { return (NULL != f_pRelPlt) && (0 != f_pRelPlt->size()); }
+
+ bool hasRelaDyn() const
+ { return (NULL != f_pRelaDyn) && (0 != f_pRelaDyn->size()); }
+
+ bool hasRelaPlt() const
+ { return (NULL != f_pRelaPlt) && (0 != f_pRelaPlt->size()); }
+
+ /// @ref 10.3.1.1, ISO/IEC 23360, Part 1:2010(E), p. 21.
+ bool hasComment() const
+ { return (NULL != f_pComment) && (0 != f_pComment->size()); }
+
+ bool hasData1() const
+ { return (NULL != f_pData1) && (0 != f_pData1->size()); }
+
+ bool hasDebug() const
+ { return (NULL != f_pDebug) && (0 != f_pDebug->size()); }
+
+ bool hasDynamic() const
+ { return (NULL != f_pDynamic) && (0 != f_pDynamic->size()); }
+
+ bool hasDynStrTab() const
+ { return (NULL != f_pDynStrTab) && (0 != f_pDynStrTab->size()); }
+
+ bool hasDynSymTab() const
+ { return (NULL != f_pDynSymTab) && (0 != f_pDynSymTab->size()); }
+
+ bool hasFini() const
+ { return (NULL != f_pFini) && (0 != f_pFini->size()); }
+
+ bool hasFiniArray() const
+ { return (NULL != f_pFiniArray) && (0 != f_pFiniArray->size()); }
+
+ bool hasHashTab() const
+ { return (NULL != f_pHashTab) && (0 != f_pHashTab->size()); }
+
+ bool hasInit() const
+ { return (NULL != f_pInit) && (0 != f_pInit->size()); }
+
+ bool hasInitArray() const
+ { return (NULL != f_pInitArray) && (0 != f_pInitArray->size()); }
+
+ bool hasInterp() const
+ { return (NULL != f_pInterp) && (0 != f_pInterp->size()); }
+
+ bool hasLine() const
+ { return (NULL != f_pLine) && (0 != f_pLine->size()); }
+
+ bool hasNote() const
+ { return (NULL != f_pNote) && (0 != f_pNote->size()); }
+
+ bool hasPreInitArray() const
+ { return (NULL != f_pPreInitArray) && (0 != f_pPreInitArray->size()); }
+
+ bool hasROData1() const
+ { return (NULL != f_pROData1) && (0 != f_pROData1->size()); }
+
+ bool hasShStrTab() const
+ { return (NULL != f_pShStrTab) && (0 != f_pShStrTab->size()); }
+
+ bool hasStrTab() const
+ { return (NULL != f_pStrTab) && (0 != f_pStrTab->size()); }
+
+ bool hasSymTab() const
+ { return (NULL != f_pSymTab) && (0 != f_pSymTab->size()); }
+
+ bool hasTBSS() const
+ { return (NULL != f_pTBSS) && (0 != f_pTBSS->size()); }
+
+ bool hasTData() const
+ { return (NULL != f_pTData) && (0 != f_pTData->size()); }
+
+ /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
+ bool hasCtors() const
+ { return (NULL != f_pCtors) && (0 != f_pCtors->size()); }
+
+ bool hasDataRelRo() const
+ { return (NULL != f_pDataRelRo) && (0 != f_pDataRelRo->size()); }
+
+ bool hasDtors() const
+ { return (NULL != f_pDtors) && (0 != f_pDtors->size()); }
+
+ bool hasEhFrame() const
+ { return (NULL != f_pEhFrame) && (0 != f_pEhFrame->size()); }
+
+ bool hasEhFrameHdr() const
+ { return (NULL != f_pEhFrameHdr) && (0 != f_pEhFrameHdr->size()); }
+
+ bool hasGCCExceptTable() const
+ { return (NULL != f_pGCCExceptTable) && (0 != f_pGCCExceptTable->size()); }
+
+ bool hasGNUVersion() const
+ { return (NULL != f_pGNUVersion) && (0 != f_pGNUVersion->size()); }
+
+ bool hasGNUVersionD() const
+ { return (NULL != f_pGNUVersionD) && (0 != f_pGNUVersionD->size()); }
+
+ bool hasGNUVersionR() const
+ { return (NULL != f_pGNUVersionR) && (0 != f_pGNUVersionR->size()); }
+
+ bool hasGOTPLT() const
+ { return (NULL != f_pGOTPLT) && (0 != f_pGOTPLT->size()); }
+
+ bool hasJCR() const
+ { return (NULL != f_pJCR) && (0 != f_pJCR->size()); }
+
+ bool hasNoteABITag() const
+ { return (NULL != f_pNoteABITag) && (0 != f_pNoteABITag->size()); }
+
+ bool hasStab() const
+ { return (NULL != f_pStab) && (0 != f_pStab->size()); }
+
+ bool hasStabStr() const
+ { return (NULL != f_pStabStr) && (0 != f_pStabStr->size()); }
+
+ // ----- access functions ----- //
+ /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
+ LDSection& getNULLSection() {
+ assert(NULL != f_pNULLSection);
+ return *f_pNULLSection;
+ }
+
+ const LDSection& getNULLSection() const {
+ assert(NULL != f_pNULLSection);
+ return *f_pNULLSection;
+ }
+
+ LDSection& getGOT() {
+ assert(NULL != f_pGOT);
+ return *f_pGOT;
+ }
+
+ const LDSection& getGOT() const {
+ assert(NULL != f_pGOT);
+ return *f_pGOT;
+ }
+
+ LDSection& getPLT() {
+ assert(NULL != f_pPLT);
+ return *f_pPLT;
+ }
+
+ const LDSection& getPLT() const {
+ assert(NULL != f_pPLT);
+ return *f_pPLT;
+ }
+
+ LDSection& getRelDyn() {
+ assert(NULL != f_pRelDyn);
+ return *f_pRelDyn;
+ }
+
+ const LDSection& getRelDyn() const {
+ assert(NULL != f_pRelDyn);
+ return *f_pRelDyn;
+ }
+
+ LDSection& getRelPlt() {
+ assert(NULL != f_pRelPlt);
+ return *f_pRelPlt;
+ }
+
+ const LDSection& getRelPlt() const {
+ assert(NULL != f_pRelPlt);
+ return *f_pRelPlt;
+ }
+
+ LDSection& getRelaDyn() {
+ assert(NULL != f_pRelaDyn);
+ return *f_pRelaDyn;
+ }
+
+ const LDSection& getRelaDyn() const {
+ assert(NULL != f_pRelaDyn);
+ return *f_pRelaDyn;
+ }
+
+ LDSection& getRelaPlt() {
+ assert(NULL != f_pRelaPlt);
+ return *f_pRelaPlt;
+ }
+
+ const LDSection& getRelaPlt() const {
+ assert(NULL != f_pRelaPlt);
+ return *f_pRelaPlt;
+ }
+
+ LDSection& getComment() {
+ assert(NULL != f_pComment);
+ return *f_pComment;
+ }
+
+ /// @ref 10.3.1.1, ISO/IEC 23360, Part 1:2010(E), p. 21.
+ const LDSection& getComment() const {
+ assert(NULL != f_pComment);
+ return *f_pComment;
+ }
+
+ LDSection& getData1() {
+ assert(NULL != f_pData1);
+ return *f_pData1;
+ }
+
+ const LDSection& getData1() const {
+ assert(NULL != f_pData1);
+ return *f_pData1;
+ }
+
+ LDSection& getDebug() {
+ assert(NULL != f_pDebug);
+ return *f_pDebug;
+ }
+
+ const LDSection& getDebug() const {
+ assert(NULL != f_pDebug);
+ return *f_pDebug;
+ }
+
+ LDSection& getDynamic() {
+ assert(NULL != f_pDynamic);
+ return *f_pDynamic;
+ }
+
+ const LDSection& getDynamic() const {
+ assert(NULL != f_pDynamic);
+ return *f_pDynamic;
+ }
+
+ LDSection& getDynStrTab() {
+ assert(NULL != f_pDynStrTab);
+ return *f_pDynStrTab;
+ }
+
+ const LDSection& getDynStrTab() const {
+ assert(NULL != f_pDynStrTab);
+ return *f_pDynStrTab;
+ }
+
+ LDSection& getDynSymTab() {
+ assert(NULL != f_pDynSymTab);
+ return *f_pDynSymTab;
+ }
+
+ const LDSection& getDynSymTab() const {
+ assert(NULL != f_pDynSymTab);
+ return *f_pDynSymTab;
+ }
+
+ LDSection& getFini() {
+ assert(NULL != f_pFini);
+ return *f_pFini;
+ }
+
+ const LDSection& getFini() const {
+ assert(NULL != f_pFini);
+ return *f_pFini;
+ }
+
+ LDSection& getFiniArray() {
+ assert(NULL != f_pFiniArray);
+ return *f_pFiniArray;
+ }
+
+ const LDSection& getFiniArray() const {
+ assert(NULL != f_pFiniArray);
+ return *f_pFiniArray;
+ }
+
+ LDSection& getHashTab() {
+ assert(NULL != f_pHashTab);
+ return *f_pHashTab;
+ }
+
+ const LDSection& getHashTab() const {
+ assert(NULL != f_pHashTab);
+ return *f_pHashTab;
+ }
+
+ LDSection& getInit() {
+ assert(NULL != f_pInit);
+ return *f_pInit;
+ }
+
+ const LDSection& getInit() const {
+ assert(NULL != f_pInit);
+ return *f_pInit;
+ }
+
+ LDSection& getInitArray() {
+ assert(NULL != f_pInitArray);
+ return *f_pInitArray;
+ }
+
+ const LDSection& getInitArray() const {
+ assert(NULL != f_pInitArray);
+ return *f_pInitArray;
+ }
+
+ LDSection& getInterp() {
+ assert(NULL != f_pInterp);
+ return *f_pInterp;
+ }
+
+ const LDSection& getInterp() const {
+ assert(NULL != f_pInterp);
+ return *f_pInterp;
+ }
+
+ LDSection& getLine() {
+ assert(NULL != f_pLine);
+ return *f_pLine;
+ }
+
+ const LDSection& getLine() const {
+ assert(NULL != f_pLine);
+ return *f_pLine;
+ }
+
+ LDSection& getNote() {
+ assert(NULL != f_pNote);
+ return *f_pNote;
+ }
+
+ const LDSection& getNote() const {
+ assert(NULL != f_pNote);
+ return *f_pNote;
+ }
+
+ LDSection& getPreInitArray() {
+ assert(NULL != f_pPreInitArray);
+ return *f_pPreInitArray;
+ }
+
+ const LDSection& getPreInitArray() const {
+ assert(NULL != f_pPreInitArray);
+ return *f_pPreInitArray;
+ }
+
+ LDSection& getROData1() {
+ assert(NULL != f_pROData1);
+ return *f_pROData1;
+ }
+
+ const LDSection& getROData1() const {
+ assert(NULL != f_pROData1);
+ return *f_pROData1;
+ }
+
+ LDSection& getShStrTab() {
+ assert(NULL != f_pShStrTab);
+ return *f_pShStrTab;
+ }
+
+ const LDSection& getShStrTab() const {
+ assert(NULL != f_pShStrTab);
+ return *f_pShStrTab;
+ }
+
+ LDSection& getStrTab() {
+ assert(NULL != f_pStrTab);
+ return *f_pStrTab;
+ }
+
+ const LDSection& getStrTab() const {
+ assert(NULL != f_pStrTab);
+ return *f_pStrTab;
+ }
+
+ LDSection& getSymTab() {
+ assert(NULL != f_pSymTab);
+ return *f_pSymTab;
+ }
+
+ const LDSection& getSymTab() const {
+ assert(NULL != f_pSymTab);
+ return *f_pSymTab;
+ }
+
+ LDSection& getTBSS() {
+ assert(NULL != f_pTBSS);
+ return *f_pTBSS;
+ }
+
+ const LDSection& getTBSS() const {
+ assert(NULL != f_pTBSS);
+ return *f_pTBSS;
+ }
+
+ LDSection& getTData() {
+ assert(NULL != f_pTData);
+ return *f_pTData;
+ }
+
+ const LDSection& getTData() const {
+ assert(NULL != f_pTData);
+ return *f_pTData;
+ }
+
+ /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
+ LDSection& getCtors() {
+ assert(NULL != f_pCtors);
+ return *f_pCtors;
+ }
+
+ const LDSection& getCtors() const {
+ assert(NULL != f_pCtors);
+ return *f_pCtors;
+ }
+
+ LDSection& getDataRelRo() {
+ assert(NULL != f_pDataRelRo);
+ return *f_pDataRelRo;
+ }
+
+ const LDSection& getDataRelRo() const {
+ assert(NULL != f_pDataRelRo);
+ return *f_pDataRelRo;
+ }
+
+ LDSection& getDtors() {
+ assert(NULL != f_pDtors);
+ return *f_pDtors;
+ }
+
+ const LDSection& getDtors() const {
+ assert(NULL != f_pDtors);
+ return *f_pDtors;
+ }
+
+ LDSection& getEhFrame() {
+ assert(NULL != f_pEhFrame);
+ return *f_pEhFrame;
+ }
+
+ const LDSection& getEhFrame() const {
+ assert(NULL != f_pEhFrame);
+ return *f_pEhFrame;
+ }
+
+ LDSection& getEhFrameHdr() {
+ assert(NULL != f_pEhFrameHdr);
+ return *f_pEhFrameHdr;
+ }
+
+ const LDSection& getEhFrameHdr() const {
+ assert(NULL != f_pEhFrameHdr);
+ return *f_pEhFrameHdr;
+ }
+
+ LDSection& getGCCExceptTable() {
+ assert(NULL != f_pGCCExceptTable);
+ return *f_pGCCExceptTable;
+ }
+
+ const LDSection& getGCCExceptTable() const {
+ assert(NULL != f_pGCCExceptTable);
+ return *f_pGCCExceptTable;
+ }
+
+ LDSection& getGNUVersion() {
+ assert(NULL != f_pGNUVersion);
+ return *f_pGNUVersion;
+ }
+
+ const LDSection& getGNUVersion() const {
+ assert(NULL != f_pGNUVersion);
+ return *f_pGNUVersion;
+ }
+
+ LDSection& getGNUVersionD() {
+ assert(NULL != f_pGNUVersionD);
+ return *f_pGNUVersionD;
+ }
+
+ const LDSection& getGNUVersionD() const {
+ assert(NULL != f_pGNUVersionD);
+ return *f_pGNUVersionD;
+ }
+
+ LDSection& getGNUVersionR() {
+ assert(NULL != f_pGNUVersionR);
+ return *f_pGNUVersionR;
+ }
+
+ const LDSection& getGNUVersionR() const {
+ assert(NULL != f_pGNUVersionR);
+ return *f_pGNUVersionR;
+ }
+
+ LDSection& getGOTPLT() {
+ assert(NULL != f_pGOTPLT);
+ return *f_pGOTPLT;
+ }
+
+ const LDSection& getGOTPLT() const {
+ assert(NULL != f_pGOTPLT);
+ return *f_pGOTPLT;
+ }
+
+ LDSection& getJCR() {
+ assert(NULL != f_pJCR);
+ return *f_pJCR;
+ }
+
+ const LDSection& getJCR() const {
+ assert(NULL != f_pJCR);
+ return *f_pJCR;
+ }
+
+ LDSection& getNoteABITag() {
+ assert(NULL != f_pNoteABITag);
+ return *f_pNoteABITag;
+ }
+
+ const LDSection& getNoteABITag() const {
+ assert(NULL != f_pNoteABITag);
+ return *f_pNoteABITag;
+ }
+
+ LDSection& getStab() {
+ assert(NULL != f_pStab);
+ return *f_pStab;
+ }
+
+ const LDSection& getStab() const {
+ assert(NULL != f_pStab);
+ return *f_pStab;
+ }
+
+ LDSection& getStabStr() {
+ assert(NULL != f_pStabStr);
+ return *f_pStabStr;
+ }
+
+ const LDSection& getStabStr() const {
+ assert(NULL != f_pStabStr);
+ return *f_pStabStr;
+ }
+
+protected:
+ GNULDBackend& f_Backend;
+
+ // variable name : ELF
+ /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition.
+ LDSection* f_pNULLSection;
+ LDSection* f_pGOT; // .got
+ LDSection* f_pPLT; // .plt
+ LDSection* f_pRelDyn; // .rel.dyn
+ LDSection* f_pRelPlt; // .rel.plt
+ LDSection* f_pRelaDyn; // .rela.dyn
+ LDSection* f_pRelaPlt; // .rela.plt
+
+ /// @ref 10.3.1.1, ISO/IEC 23360, Part 1:2010(E), p. 21.
+ LDSection* f_pComment; // .comment
+ LDSection* f_pData1; // .data1
+ LDSection* f_pDebug; // .debug
+ LDSection* f_pDynamic; // .dynamic
+ LDSection* f_pDynStrTab; // .dynstr
+ LDSection* f_pDynSymTab; // .dynsym
+ LDSection* f_pFini; // .fini
+ LDSection* f_pFiniArray; // .fini_array
+ LDSection* f_pHashTab; // .hash
+ LDSection* f_pInit; // .init
+ LDSection* f_pInitArray; // .init_array
+ LDSection* f_pInterp; // .interp
+ LDSection* f_pLine; // .line
+ LDSection* f_pNote; // .note
+ LDSection* f_pPreInitArray; // .preinit_array
+ LDSection* f_pROData1; // .rodata1
+ LDSection* f_pShStrTab; // .shstrtab
+ LDSection* f_pStrTab; // .strtab
+ LDSection* f_pSymTab; // .symtab
+ LDSection* f_pTBSS; // .tbss
+ LDSection* f_pTData; // .tdata
+
+ /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
+ LDSection* f_pCtors; // .ctors
+ LDSection* f_pDataRelRo; // .data.rel.ro
+ LDSection* f_pDtors; // .dtors
+ LDSection* f_pEhFrame; // .eh_frame
+ LDSection* f_pEhFrameHdr; // .eh_frame_hdr
+ LDSection* f_pGCCExceptTable; // .gcc_except_table
+ LDSection* f_pGNUVersion; // .gnu.version
+ LDSection* f_pGNUVersionD; // .gnu.version_d
+ LDSection* f_pGNUVersionR; // .gnu.version_r
+ LDSection* f_pGOTPLT; // .got.plt
+ LDSection* f_pJCR; // .jcr
+ LDSection* f_pNoteABITag; // .note.ABI-tag
+ LDSection* f_pStab; // .stab
+ LDSection* f_pStabStr; // .stabstr
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFObjectReader.h b/include/mcld/LD/ELFObjectReader.h
new file mode 100644
index 0000000..ac11261
--- /dev/null
+++ b/include/mcld/LD/ELFObjectReader.h
@@ -0,0 +1,59 @@
+//===- ELFObjectReader.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_OBJECT_READER_H
+#define MCLD_ELF_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/ObjectReader.h>
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class Input;
+class MCLinker;
+class GNULDBackend;
+class ELFReaderIF;
+
+/** \lclass ELFObjectReader
+ * \brief ELFObjectReader reads target-independent parts of ELF object file
+ */
+class ELFObjectReader : public ObjectReader
+{
+public:
+ ELFObjectReader(GNULDBackend& pBackend, MCLinker& pLinker);
+
+ ~ELFObjectReader();
+
+ // ----- observers ----- //
+ bool isMyFormat(Input &pFile) const;
+
+ // ----- readers ----- //
+ bool readObject(Input& pFile);
+
+ virtual bool readSections(Input& pFile);
+
+ virtual bool readSymbols(Input& pFile);
+
+ /// readRelocations - read relocation sections
+ ///
+ /// This function should be called after symbol resolution.
+ virtual bool readRelocations(Input& pFile);
+
+private:
+ ELFReaderIF* m_pELFReader;
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h
new file mode 100644
index 0000000..a6b9a87
--- /dev/null
+++ b/include/mcld/LD/ELFObjectWriter.h
@@ -0,0 +1,47 @@
+//===- ELFObjectWriter.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_OBJECT_WRITER_H
+#define MCLD_ELF_OBJECT_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/system_error.h>
+#include <mcld/LD/ObjectWriter.h>
+#include <mcld/LD/ELFWriter.h>
+
+namespace mcld
+{
+
+class Input;
+class MCLinker;
+class GNULDBackend;
+
+/** \class ELFObjectWriter
+ * \brief ELFObjectWriter writes the target-independent parts of object files.
+ * ELFObjectWriter reads a MCLDFile and writes into raw_ostream
+ *
+ */
+class ELFObjectWriter : public ObjectWriter, protected ELFWriter
+{
+public:
+ ELFObjectWriter(GNULDBackend& pBackend, MCLinker& pLinker);
+
+ ~ELFObjectWriter();
+
+ llvm::error_code writeObject(Output& pOutput)
+ { return llvm::make_error_code(llvm::errc::not_supported); }
+
+private:
+ MCLinker& m_Linker;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFReader.h b/include/mcld/LD/ELFReader.h
new file mode 100644
index 0000000..cac0175
--- /dev/null
+++ b/include/mcld/LD/ELFReader.h
@@ -0,0 +1,224 @@
+//===- ELFReader.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_READER_INTERFACE_H
+#define MCLD_ELF_READER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MemoryRegion.h>
+
+namespace mcld
+{
+
+/** \class ELFReaderIF
+ * \brief ELFReaderIF provides common interface for all kind of ELF readers.
+ */
+class ELFReaderIF
+{
+public:
+ ELFReaderIF(GNULDBackend& pBackend)
+ : m_Backend(pBackend)
+ { }
+
+ virtual ~ELFReaderIF() { }
+
+ /// ELFHeaderSize - return the size of the ELFHeader
+ virtual size_t getELFHeaderSize() const = 0;
+
+ /// isELF - is this a ELF file
+ virtual bool isELF(void* pELFHeader) const = 0;
+
+ /// isMyEndian - is this ELF file in the same endian to me?
+ virtual bool isMyEndian(void* pELFHeader) const = 0;
+
+ /// isMyMachine - is this ELF file generated for the same machine.
+ virtual bool isMyMachine(void* pELFHeader) const = 0;
+
+ /// fileType - the file type of this file
+ virtual MCLDFile::Type fileType(void* pELFHeader) const = 0;
+
+ /// target - the target backend
+ GNULDBackend& target()
+ { return m_Backend; }
+
+ /// target - the target backend
+ const GNULDBackend& target() const
+ { return m_Backend; }
+
+ /// readSectionHeaders - read ELF section header table and create LDSections
+ virtual bool readSectionHeaders(Input& pInput,
+ MCLinker& pLinker,
+ void* pELFHeader) const = 0;
+
+ /// readRegularSection - read a regular section and create fragments.
+ virtual bool readRegularSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSectHdr) const = 0;
+
+ /// readRegularSection - read a target section and create fragments.
+ virtual bool readTargetSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSectHdr) = 0;
+
+ /// readSymbols - read ELF symbols and create LDSymbol
+ virtual bool readSymbols(Input& pInput,
+ MCLinker& pLinker,
+ const MemoryRegion& pRegion,
+ const char* StrTab) const = 0;
+
+ /// readSymbol - read a symbol from the given Input and index in symtab
+ virtual ResolveInfo* readSymbol(Input& pInput,
+ LDSection& pSymTab,
+ MCLDInfo& pLDInfo,
+ uint32_t pSymIdx) const = 0;
+
+ /// readRela - read ELF rela and create Relocation
+ virtual bool readRela(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const = 0;
+
+ /// readRel - read ELF rel and create Relocation
+ virtual bool readRel(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const = 0;
+protected:
+ /// LinkInfo - some section needs sh_link and sh_info, remember them.
+ struct LinkInfo {
+ LDSection* section;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ };
+
+ typedef std::vector<LinkInfo> LinkInfoList;
+
+protected:
+ LDFileFormat::Kind getLDSectionKind(uint32_t pType, const char* pName) const;
+
+ ResolveInfo::Desc getSymDesc(uint16_t pShndx, const Input& pInput) const;
+
+ ResolveInfo::Binding getSymBinding(uint8_t pBinding,
+ uint16_t pShndx,
+ uint8_t pVisibility) const;
+
+ uint64_t getSymValue(uint64_t pValue,
+ uint16_t pShndx,
+ const Input& pInput) const;
+
+ MCFragmentRef* getSymFragmentRef(Input& pInput,
+ MCLinker& pLinker,
+ uint16_t pShndx,
+ uint32_t pOffset) const;
+
+ ResolveInfo::Visibility getSymVisibility(uint8_t pVis) const;
+
+private:
+ GNULDBackend& m_Backend;
+};
+
+/** \class ELFReader
+ * \brief ELFReader is a template scaffolding for partial specification.
+ */
+template<size_t BIT, bool LITTLEENDIAN>
+class ELFReader
+{ };
+
+/** \class ELFReader<32, true>
+ * \brief ELFReader<32, true> is a 32-bit, little endian ELFReader.
+ */
+template<>
+class ELFReader<32, true> : public ELFReaderIF
+{
+public:
+ typedef llvm::ELF::Elf32_Ehdr ELFHeader;
+ typedef llvm::ELF::Elf32_Shdr SectionHeader;
+ typedef llvm::ELF::Elf32_Sym Symbol;
+ typedef llvm::ELF::Elf32_Rel Rel;
+ typedef llvm::ELF::Elf32_Rela Rela;
+
+public:
+ inline ELFReader(GNULDBackend& pBackend);
+
+ inline ~ELFReader();
+
+ /// ELFHeaderSize - return the size of the ELFHeader
+ inline size_t getELFHeaderSize() const
+ { return sizeof(ELFHeader); }
+
+ /// isELF - is this a ELF file
+ inline bool isELF(void* pELFHeader) const;
+
+ /// isMyEndian - is this ELF file in the same endian to me?
+ inline bool isMyEndian(void* pELFHeader) const;
+
+ /// isMyMachine - is this ELF file generated for the same machine.
+ inline bool isMyMachine(void* pELFHeader) const;
+
+ /// fileType - the file type of this file
+ inline MCLDFile::Type fileType(void* pELFHeader) const;
+
+ /// readSectionHeaders - read ELF section header table and create LDSections
+ inline bool readSectionHeaders(Input& pInput,
+ MCLinker& pLinker,
+ void* pELFHeader) const;
+
+ /// readRegularSection - read a regular section and create fragments.
+ inline bool readRegularSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr) const;
+
+ /// readRegularSection - read a target section and create fragments.
+ inline bool readTargetSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr);
+
+ /// readSymbols - read ELF symbols and create LDSymbol
+ inline bool readSymbols(Input& pInput,
+ MCLinker& pLinker,
+ const MemoryRegion& pRegion,
+ const char* StrTab) const;
+
+ /// readSymbol - read a symbol from the given Input and index in symtab
+ inline ResolveInfo* readSymbol(Input& pInput,
+ LDSection& pSymTab,
+ MCLDInfo& pLDInfo,
+ uint32_t pSymIdx) const;
+
+ /// readRela - read ELF rela and create Relocation
+ inline bool readRela(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const;
+
+ /// readRel - read ELF rel and create Relocation
+ inline bool readRel(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const;
+};
+
+#include "ELFReader.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFReader.tcc b/include/mcld/LD/ELFReader.tcc
new file mode 100644
index 0000000..693a780
--- /dev/null
+++ b/include/mcld/LD/ELFReader.tcc
@@ -0,0 +1,532 @@
+//===- ELFReader.tcc ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is the template implemenation of ELFReaders
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// ELFReader<32, true>
+#include <cstring>
+#include <vector>
+
+/// constructor
+ELFReader<32, true>::ELFReader(GNULDBackend& pBackend)
+ : ELFReaderIF(pBackend) {
+}
+
+/// destructor
+ELFReader<32, true>::~ELFReader()
+{
+}
+
+/// isELF - is this a ELF file
+bool ELFReader<32, true>::isELF(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ if (0 == memcmp(llvm::ELF::ElfMagic, hdr, 4))
+ return true;
+ return false;
+}
+
+/// isMyEndian - is this ELF file in the same endian to me?
+bool ELFReader<32, true>::isMyEndian(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+
+ return (hdr->e_ident[llvm::ELF::EI_DATA] == llvm::ELF::ELFDATA2LSB);
+}
+
+/// isMyMachine - is this ELF file generated for the same machine.
+bool ELFReader<32, true>::isMyMachine(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+
+ if (llvm::sys::isLittleEndianHost())
+ return (hdr->e_machine == target().machine());
+ return (bswap16(hdr->e_machine) == target().machine());
+}
+
+/// fileType - return the file type
+MCLDFile::Type ELFReader<32, true>::fileType(void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* hdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+ uint32_t type = 0x0;
+ if (llvm::sys::isLittleEndianHost())
+ type = hdr->e_type;
+ else
+ type = bswap16(hdr->e_type);
+
+ switch(type) {
+ case llvm::ELF::ET_REL:
+ return MCLDFile::Object;
+ case llvm::ELF::ET_EXEC:
+ return MCLDFile::Exec;
+ case llvm::ELF::ET_DYN:
+ return MCLDFile::DynObj;
+ case llvm::ELF::ET_CORE:
+ return MCLDFile::CoreFile;
+ case llvm::ELF::ET_NONE:
+ default:
+ return MCLDFile::Unknown;
+ }
+}
+
+/// readSectionHeaders - read ELF section header table and create LDSections
+bool ELFReader<32, true>::readSectionHeaders(Input& pInput,
+ MCLinker& pLinker,
+ void* pELFHeader) const
+{
+ llvm::ELF::Elf32_Ehdr* ehdr =
+ reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(pELFHeader);
+
+ uint32_t shoff = 0x0;
+ uint16_t shentsize = 0x0;
+ uint16_t shnum = 0x0;
+ uint16_t shstrtab = 0x0;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ shoff = ehdr->e_shoff;
+ shentsize = ehdr->e_shentsize;
+ shnum = ehdr->e_shnum;
+ shstrtab = ehdr->e_shstrndx;
+ }
+ else {
+ shoff = bswap32(ehdr->e_shoff);
+ shentsize = bswap16(ehdr->e_shentsize);
+ shnum = bswap16(ehdr->e_shnum);
+ shstrtab = bswap16(ehdr->e_shstrndx);
+ }
+
+ // If the file has no section header table, e_shoff holds zero.
+ if (0x0 == shoff)
+ return true;
+
+ MemoryRegion* shdr_region = pInput.memArea()->request(shoff, shnum*shentsize);
+ llvm::ELF::Elf32_Shdr* shdrTab =
+ reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start());
+
+ uint32_t sh_name = 0x0;
+ uint32_t sh_type = 0x0;
+ uint32_t sh_flags = 0x0;
+ uint32_t sh_offset = 0x0;
+ uint32_t sh_size = 0x0;
+ uint32_t sh_link = 0x0;
+ uint32_t sh_info = 0x0;
+ uint32_t sh_addralign = 0x0;
+
+ // get .shstrtab first
+ llvm::ELF::Elf32_Shdr* shdr = &shdrTab[shstrtab];
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_offset = shdr->sh_offset;
+ sh_size = shdr->sh_size;
+ }
+ else {
+ sh_offset = bswap32(shdr->sh_offset);
+ sh_size = bswap32(shdr->sh_size);
+ }
+
+ MemoryRegion* sect_name_region = pInput.memArea()->request(sh_offset, sh_size);
+ const char* sect_name = reinterpret_cast<const char*>(sect_name_region->start());
+
+ LinkInfoList link_info_list;
+
+ // create all LDSections
+ for (size_t idx = 0; idx < shnum; ++idx) {
+ if (llvm::sys::isLittleEndianHost()) {
+ sh_name = shdrTab[idx].sh_name;
+ sh_type = shdrTab[idx].sh_type;
+ sh_flags = shdrTab[idx].sh_flags;
+ sh_offset = shdrTab[idx].sh_offset;
+ sh_size = shdrTab[idx].sh_size;
+ sh_link = shdrTab[idx].sh_link;
+ sh_info = shdrTab[idx].sh_info;
+ sh_addralign = shdrTab[idx].sh_addralign;
+ }
+ else {
+ sh_name = bswap32(shdrTab[idx].sh_name);
+ sh_type = bswap32(shdrTab[idx].sh_type);
+ sh_flags = bswap32(shdrTab[idx].sh_flags);
+ sh_offset = bswap32(shdrTab[idx].sh_offset);
+ sh_size = bswap32(shdrTab[idx].sh_size);
+ sh_link = bswap32(shdrTab[idx].sh_link);
+ sh_info = bswap32(shdrTab[idx].sh_info);
+ sh_addralign = bswap32(shdrTab[idx].sh_addralign);
+ }
+
+ LDFileFormat::Kind kind = getLDSectionKind(sh_type,
+ sect_name+sh_name);
+
+ LDSection& section = pLinker.createSectHdr(sect_name+sh_name,
+ kind,
+ sh_type,
+ sh_flags);
+
+ section.setSize(sh_size);
+ section.setOffset(sh_offset);
+ section.setIndex(pInput.context()->numOfSections());
+ section.setInfo(sh_info);
+ section.setAlign(sh_addralign);
+
+ if (sh_link != 0x0 || sh_info != 0x0) {
+ LinkInfo link_info = { §ion, sh_link, sh_info };
+ link_info_list.push_back(link_info);
+ }
+
+ pInput.context()->getSectionTable().push_back(§ion);
+ } // end of for
+
+ // set up InfoLink
+ LinkInfoList::iterator info, infoEnd = link_info_list.end();
+ for (info = link_info_list.begin(); info != infoEnd; ++info) {
+ if (LDFileFormat::NamePool == info->section->kind() ||
+ LDFileFormat::Group == info->section->kind()) {
+ info->section->setLink(pInput.context()->getSection(info->sh_link));
+ continue;
+ }
+ if (LDFileFormat::Relocation == info->section->kind()) {
+ info->section->setLink(pInput.context()->getSection(info->sh_info));
+ continue;
+ }
+ }
+
+ pInput.memArea()->release(shdr_region);
+ pInput.memArea()->release(sect_name_region);
+
+ return true;
+}
+
+/// readRegularSection - read a regular section and create fragments.
+bool ELFReader<32, true>::readRegularSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr) const
+{
+ LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
+ pInputSectHdr.kind(),
+ pInputSectHdr.type(),
+ pInputSectHdr.flag());
+
+ MemoryRegion* region = pInput.memArea()->request(pInputSectHdr.offset(),
+ pInputSectHdr.size());
+
+ llvm::MCSectionData& sect_data = pLinker.getOrCreateSectData(pInputSectHdr);
+
+ llvm::MCFragment* frag = NULL;
+ if (NULL == region) {
+ // If the input section's size is zero, we got a NULL region.
+ // use a virtual fill fragment
+ frag = new llvm::MCFillFragment(0x0, 0, 0);
+ }
+ else
+ frag = new MCRegionFragment(*region);
+
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ sect_data,
+ pInputSectHdr.align());
+
+ out_sect.setSize(out_sect.size() + size);
+ return true;
+}
+
+/// readRegularSection - read a target section and create fragments.
+bool ELFReader<32, true>::readTargetSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr)
+{
+ return target().readSection(pInput, pLinker, pInputSectHdr);
+}
+
+/// readSymbols - read ELF symbols and create LDSymbol
+bool ELFReader<32, true>::readSymbols(Input& pInput,
+ MCLinker& pLinker,
+ const MemoryRegion& pRegion,
+ const char* pStrTab) const
+{
+ // get number of symbols
+ size_t entsize = pRegion.size()/sizeof(llvm::ELF::Elf32_Sym);
+ llvm::ELF::Elf32_Sym* symtab =
+ reinterpret_cast<llvm::ELF::Elf32_Sym*>(pRegion.start());
+
+ uint32_t st_name = 0x0;
+ uint32_t st_value = 0x0;
+ uint32_t st_size = 0x0;
+ uint8_t st_info = 0x0;
+ uint8_t st_other = 0x0;
+ uint16_t st_shndx = 0x0;
+ // skip the first NULL symbol
+ pInput.context()->addSymbol(NULL);
+
+ for (size_t idx = 1; idx < entsize; ++idx) {
+ st_info = symtab[idx].st_info;
+ st_other = symtab[idx].st_other;
+
+ if (llvm::sys::isLittleEndianHost()) {
+ st_name = symtab[idx].st_name;
+ st_value = symtab[idx].st_value;
+ st_size = symtab[idx].st_size;
+ st_shndx = symtab[idx].st_shndx;
+ }
+ else {
+ st_name = bswap32(symtab[idx].st_name);
+ st_value = bswap32(symtab[idx].st_value);
+ st_size = bswap32(symtab[idx].st_size);
+ st_shndx = bswap16(symtab[idx].st_shndx);
+ }
+
+ // If the section should not be included, set the st_shndx SHN_UNDEF
+ // - A section in interrelated groups are not included.
+ if (pInput.type() == Input::Object &&
+ st_shndx < llvm::ELF::SHN_LORESERVE &&
+ st_shndx != llvm::ELF::SHN_UNDEF) {
+ if (NULL == pInput.context()->getSection(st_shndx))
+ st_shndx = llvm::ELF::SHN_UNDEF;
+ }
+
+ // get ld_name
+ llvm::StringRef ld_name(pStrTab + st_name);
+
+ // get ld_type
+ ResolveInfo::Type ld_type = static_cast<ResolveInfo::Type>(st_info & 0xF);
+
+ // get ld_desc
+ ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput);
+
+ // get ld_binding
+ ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other);
+
+ // get ld_value - ld_value must be section relative.
+ uint64_t ld_value = getSymValue(st_value, st_shndx, pInput);
+
+ // get the input fragment
+ MCFragmentRef* ld_frag_ref = getSymFragmentRef(pInput,
+ pLinker,
+ st_shndx,
+ ld_value);
+
+ // get ld_vis
+ ResolveInfo::Visibility ld_vis = getSymVisibility(st_other);
+
+ // push into MCLinker
+ LDSymbol* input_sym = NULL;
+
+ if (pInput.type() == Input::Object) {
+ input_sym = pLinker.addSymbol<Input::Object>(ld_name,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_value,
+ ld_frag_ref,
+ ld_vis);
+ // push into the input file
+ pInput.context()->addSymbol(input_sym);
+ continue;
+ }
+ else if (pInput.type() == Input::DynObj) {
+ input_sym = pLinker.addSymbol<Input::DynObj>(ld_name,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_value,
+ ld_frag_ref,
+ ld_vis);
+ continue;
+ }
+
+ } // end of for loop
+ return true;
+}
+
+/// readSymbol - read a symbol from the given Input and index in symtab
+ResolveInfo* ELFReader<32, true>::readSymbol(Input& pInput,
+ LDSection& pSymTab,
+ MCLDInfo& pLDInfo,
+ uint32_t pSymIdx) const
+{
+ LDSection* symtab = &pSymTab;
+ LDSection* strtab = symtab->getLink();
+ assert(NULL != symtab && NULL != strtab);
+
+ uint32_t offset = symtab->offset() + sizeof(llvm::ELF::Elf32_Sym) * pSymIdx;
+ MemoryRegion* symbol_region =
+ pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf32_Sym));
+ llvm::ELF::Elf32_Sym* entry =
+ reinterpret_cast<llvm::ELF::Elf32_Sym*>(symbol_region->start());
+
+ uint32_t st_name = 0x0;
+ uint32_t st_value = 0x0;
+ uint32_t st_size = 0x0;
+ uint8_t st_info = 0x0;
+ uint8_t st_other = 0x0;
+ uint16_t st_shndx = 0x0;
+ st_info = entry->st_info;
+ st_other = entry->st_other;
+ if (llvm::sys::isLittleEndianHost()) {
+ st_name = entry->st_name;
+ st_value = entry->st_value;
+ st_size = entry->st_size;
+ st_shndx = entry->st_shndx;
+ }
+ else {
+ st_name = bswap32(entry->st_name);
+ st_value = bswap32(entry->st_value);
+ st_size = bswap32(entry->st_size);
+ st_shndx = bswap16(entry->st_shndx);
+ }
+
+ MemoryRegion* strtab_region =
+ pInput.memArea()->request(strtab->offset(), strtab->size());
+
+ // get ld_name
+ llvm::StringRef ld_name(reinterpret_cast<char*>(strtab_region->start() + st_name));
+
+ // get ld_type
+ ResolveInfo::Type ld_type = static_cast<ResolveInfo::Type>(st_info & 0xF);
+
+ // get ld_desc
+ ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput);
+
+ // get ld_binding
+ ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other);
+
+ // get ld_vis
+ ResolveInfo::Visibility ld_vis = getSymVisibility(st_other);
+
+ ResolveInfo* result =
+ pLDInfo.getStrSymPool().createSymbol(ld_name,
+ pInput.type() == Input::DynObj,
+ ld_type,
+ ld_desc,
+ ld_binding,
+ st_size,
+ ld_vis);
+ // release regions
+ pInput.memArea()->release(symbol_region);
+ pInput.memArea()->release(strtab_region);
+
+ return result;
+}
+
+/// readRela - read ELF rela and create Relocation
+bool ELFReader<32, true>::readRela(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const
+{
+ // get the number of rela
+ size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rela);
+ llvm::ELF::Elf32_Rela* relaTab =
+ reinterpret_cast<llvm::ELF::Elf32_Rela*>(pRegion.start());
+
+ for (size_t idx=0; idx < entsize; ++idx) {
+ uint32_t r_offset = 0x0;
+ uint32_t r_info = 0x0;
+ int32_t r_addend = 0;
+ if (llvm::sys::isLittleEndianHost()) {
+ r_offset = relaTab[idx].r_offset;
+ r_info = relaTab[idx].r_info;
+ r_addend = relaTab[idx].r_addend;
+ }
+ else {
+ r_offset = bswap32(relaTab[idx].r_offset);
+ r_info = bswap32(relaTab[idx].r_info);
+ r_addend = bswap32(relaTab[idx].r_addend);
+ }
+
+ uint8_t r_type = static_cast<unsigned char>(r_info);
+ uint32_t r_sym = (r_info >> 8);
+ LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
+ if (NULL == symbol) {
+ llvm::report_fatal_error(llvm::Twine("invalid symbol index :") +
+ llvm::Twine(r_sym) +
+ llvm::Twine(" in file `") +
+ pInput.path().native() +
+ llvm::Twine("'.\n"));
+ }
+
+ ResolveInfo* resolve_info = symbol->resolveInfo();
+
+ MCFragmentRef* frag_ref =
+ pLinker.getLayout().getFragmentRef(*pSection.getLink(), r_offset);
+
+ if (NULL == frag_ref) {
+ llvm::report_fatal_error(llvm::Twine("invalid sh_info: ") +
+ llvm::Twine(pSection.getLink()->index()) +
+ llvm::Twine(" of the relocation section `") +
+ pSection.name() +
+ llvm::Twine("' in file `") +
+ pInput.path().native() +
+ llvm::Twine(".\n"));
+ }
+
+ pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref, r_addend);
+ }
+ return true;
+}
+
+/// readRel - read ELF rel and create Relocation
+bool ELFReader<32, true>::readRel(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pSection,
+ const MemoryRegion& pRegion) const
+{
+ // get the number of rel
+ size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rel);
+ llvm::ELF::Elf32_Rel* relTab =
+ reinterpret_cast<llvm::ELF::Elf32_Rel*>(pRegion.start());
+
+ for (size_t idx=0; idx < entsize; ++idx) {
+ uint32_t r_offset = 0x0;
+ uint32_t r_info = 0x0;
+ if (llvm::sys::isLittleEndianHost()) {
+ r_offset = relTab[idx].r_offset;
+ r_info = relTab[idx].r_info;
+ }
+ else {
+ r_offset = bswap32(relTab[idx].r_offset);
+ r_info = bswap32(relTab[idx].r_info);
+ }
+
+ uint8_t r_type = static_cast<unsigned char>(r_info);
+ uint32_t r_sym = (r_info >> 8);
+
+ LDSymbol* symbol = pInput.context()->getSymbol(r_sym);
+ if (NULL == symbol) {
+ llvm::report_fatal_error(llvm::Twine("invalid symbol index :") +
+ llvm::Twine(r_sym) +
+ llvm::Twine(" in file `") +
+ pInput.path().native() +
+ llvm::Twine("'.\n"));
+ }
+
+ ResolveInfo* resolve_info = symbol->resolveInfo();
+
+ MCFragmentRef* frag_ref =
+ pLinker.getLayout().getFragmentRef(*pSection.getLink(), r_offset);
+
+ if (NULL == frag_ref) {
+ llvm::report_fatal_error(llvm::Twine("invalid sh_info: ") +
+ llvm::Twine(pSection.getLink()->index()) +
+ llvm::Twine(" of the relocation section `") +
+ pSection.name() +
+ llvm::Twine("' in file `") +
+ pInput.path().native() +
+ llvm::Twine(".\n"));
+ }
+
+ pLinker.addRelocation(r_type, *symbol, *resolve_info, *frag_ref);
+ }
+ return true;
+}
+
diff --git a/include/mcld/LD/ELFSegment.h b/include/mcld/LD/ELFSegment.h
new file mode 100644
index 0000000..24f9458
--- /dev/null
+++ b/include/mcld/LD/ELFSegment.h
@@ -0,0 +1,163 @@
+//===- ELFSegment.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_SEGMENT_H
+#define MCLD_ELF_SEGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/LD/LDSection.h>
+#include <cassert>
+#include <vector>
+
+namespace mcld
+{
+
+/** \class ELFSegment
+ * \brief decribe the program header for ELF executable or shared object
+ */
+class ELFSegment
+{
+public:
+ typedef std::vector<LDSection*>::iterator sect_iterator;
+ typedef std::vector<LDSection*>::const_iterator const_sect_iterator;
+public:
+ ELFSegment(uint32_t pType,
+ uint32_t pFlag = llvm::ELF::PF_R,
+ uint64_t pOffset = 0,
+ uint64_t pVaddr = 0,
+ uint64_t pPaddr = 0,
+ uint64_t pFilesz = 0,
+ uint64_t pMemsz = 0,
+ uint64_t pAlign = 0);
+ ~ELFSegment();
+
+ /// ----- iterators ----- ///
+ sect_iterator sectBegin()
+ { return m_SectionList.begin(); }
+
+ sect_iterator sectEnd()
+ { return m_SectionList.end(); }
+
+ const_sect_iterator sectBegin() const
+ { return m_SectionList.begin(); }
+
+ const_sect_iterator sectEnd() const
+ { return m_SectionList.end(); }
+
+ const LDSection* getFirstSection()
+ {
+ if (0 == m_SectionList.size())
+ return NULL;
+ return m_SectionList[0];
+ }
+
+ const LDSection* getLastSection()
+ {
+ size_t size = m_SectionList.size();
+ if (0 == size)
+ return NULL;
+ return m_SectionList[size - 1];
+ }
+
+ const LDSection* getFirstSection() const
+ {
+ if (0 == m_SectionList.size())
+ return NULL;
+ return m_SectionList[0];
+ }
+
+ const LDSection* getLastSection() const
+ {
+ size_t size = m_SectionList.size();
+ if (0 == size)
+ return NULL;
+ return m_SectionList[size - 1];
+ }
+
+ /// ----- observers ----- ///
+ uint32_t type() const
+ { return m_Type; }
+
+ uint64_t offset() const
+ { return m_Offset; }
+
+ uint64_t vaddr() const
+ { return m_Vaddr; }
+
+ uint64_t paddr() const
+ { return m_Paddr; }
+
+ uint64_t filesz() const
+ { return m_Filesz; }
+
+ uint64_t memsz() const
+ { return m_Memsz; }
+
+ uint32_t flag() const
+ { return m_Flag; }
+
+ uint64_t align() const
+ { return m_Align; }
+
+ size_t numOfSections() const
+ { return m_SectionList.size(); }
+
+ /// ----- modifiers ----- ///
+ void setOffset(uint64_t pOffset)
+ { m_Offset = pOffset; }
+
+ void setVaddr(uint64_t pVaddr)
+ { m_Vaddr = pVaddr; }
+
+ void setPaddr(uint64_t pPaddr)
+ { m_Paddr = pPaddr; }
+
+ void setFilesz(uint64_t pFilesz)
+ { m_Filesz = pFilesz; }
+
+ void setMemsz(uint64_t pMemsz)
+ { m_Memsz = pMemsz; }
+
+ void setFlag(uint32_t pFlag)
+ { m_Flag = pFlag; }
+
+ void updateFlag(uint32_t pFlag)
+ {
+ // PT_TLS segment should be PF_R
+ if (llvm::ELF::PT_TLS != m_Type)
+ m_Flag |= pFlag;
+ }
+
+ void setAlign(uint64_t pAlign)
+ { m_Align = pAlign; }
+
+ void addSection(LDSection* pSection)
+ {
+ assert(NULL != pSection);
+ m_SectionList.push_back(pSection);
+ }
+
+private:
+ uint32_t m_Type; // Type of segment
+ uint32_t m_Flag; // Segment flags
+ uint64_t m_Offset; // File offset where segment is located, in bytes
+ uint64_t m_Vaddr; // Virtual address of beginning of segment
+ uint64_t m_Paddr; // Physical address of beginning of segment (OS-specific)
+ uint64_t m_Filesz; // Num. of bytes in file image of segment (may be zero)
+ uint64_t m_Memsz; // Num. of bytes in mem image of segment (may be zero)
+ uint64_t m_Align; // Segment alignment constraint
+ std::vector<LDSection*> m_SectionList;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFSegmentFactory.h b/include/mcld/LD/ELFSegmentFactory.h
new file mode 100644
index 0000000..5dd55cb
--- /dev/null
+++ b/include/mcld/LD/ELFSegmentFactory.h
@@ -0,0 +1,43 @@
+//===- ELFSegmentFactory.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELFSEGMENT_FACTORY_H
+#define MCLD_ELFSEGMENT_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/ELFSegment.h>
+
+namespace mcld
+{
+
+/** \class ELFSegmentFactory
+ * \brief provide the interface to create and delete an ELFSegment
+ */
+class ELFSegmentFactory : public GCFactory<ELFSegment, 0>
+{
+public:
+ /// ELFSegmentFactory - the factory of ELFSegment
+ /// pNum is the magic number of the ELF segments in the output
+ ELFSegmentFactory(size_t pNum);
+ ~ELFSegmentFactory();
+
+ /// produce - produce an empty ELF segment information.
+ /// this function will create an ELF segment
+ /// @param pType - p_type in ELF program header
+ ELFSegment* produce(uint32_t pType);
+
+ /// destroy - destruct the ELF segment
+ void destroy(ELFSegment*& pSegment);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ELFWriter.h b/include/mcld/LD/ELFWriter.h
new file mode 100644
index 0000000..e9db7f5
--- /dev/null
+++ b/include/mcld/LD/ELFWriter.h
@@ -0,0 +1,122 @@
+//===- ELFWriter.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_WRITER_H
+#define MCLD_ELF_WRITER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDOutput.h>
+
+namespace llvm {
+class MCSectionData;
+}
+
+namespace mcld
+{
+
+class MCLDInfo;
+class Layout;
+class GNULDBackend;
+class Relocation;
+class LDSection;
+
+/** \class ELFWriter
+ * \brief ELFWriter provides basic functions to write ELF sections, symbols,
+ * and so on.
+ */
+class ELFWriter
+{
+public:
+ typedef uint64_t FileOffset;
+
+protected:
+ ELFWriter(GNULDBackend& pBackend)
+ : f_Backend(pBackend) {
+ }
+
+public:
+ virtual ~ELFWriter() { }
+
+ GNULDBackend& target()
+ { return f_Backend; }
+
+ const GNULDBackend& target() const
+ { return f_Backend; }
+
+ virtual void writeELF32Header(const MCLDInfo& pInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ Output& pOutput) const;
+
+ virtual void writeELF64Header(const MCLDInfo& pInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ Output& pOutput) const;
+
+ virtual uint64_t getEntryPoint(const MCLDInfo& pInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ const Output& pOutput) const;
+
+protected:
+ void emitELF32SectionHeader(Output& pOutput, MCLinker& pLinker) const;
+
+ void emitELF64SectionHeader(Output& pOutput, MCLinker& pLinker) const;
+
+ // emitShStrTab - emit .shstrtab
+ void emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const;
+
+ void emitELF64ShStrTab(Output& pOutput, MCLinker& pLinker) const;
+
+ void emitSectionData(const Layout& pLayout,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ void emitRelocation(const Layout& pLayout,
+ const Output& pOutput,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const;
+
+ void emitRel(const Layout& pLayout,
+ const Output& pOutput,
+ const llvm::MCSectionData& pSectionData,
+ MemoryRegion& pRegion) const;
+
+ void emitRela(const Layout& pLayout,
+ const Output& pOutput,
+ const llvm::MCSectionData& pSectionData,
+ MemoryRegion& pRegion) const;
+
+private:
+ // getSectEntrySize - compute ElfXX_Shdr::sh_entsize
+ uint64_t getELF32SectEntrySize(const LDSection& pSection) const;
+
+ // getSectEntrySize - compute ElfXX_Shdr::sh_entsize
+ uint64_t getELF64SectEntrySize(const LDSection& pSection) const;
+
+ // getSectEntrySize - compute ElfXX_Shdr::sh_link
+ uint64_t getSectLink(const LDSection& pSection, const Output& pOutput) const;
+
+ // getSectEntrySize - compute ElfXX_Shdr::sh_info
+ uint64_t getSectInfo(const LDSection& pSection, const Output& pOutput) const;
+
+ uint64_t getELF32LastStartOffset(const Output& pOutput) const;
+
+ uint64_t getELF64LastStartOffset(const Output& pOutput) const;
+
+protected:
+ GNULDBackend& f_Backend;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/GNUArchiveReader.h b/include/mcld/LD/GNUArchiveReader.h
new file mode 100644
index 0000000..57aee10
--- /dev/null
+++ b/include/mcld/LD/GNUArchiveReader.h
@@ -0,0 +1,86 @@
+//===- GNUArchiveReader.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GNU_ARCHIVE_READER_H
+#define MCLD_GNU_ARCHIVE_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/LD/ArchiveReader.h"
+#include "mcld/Support/Path.h"
+#include <llvm/ADT/OwningPtr.h>
+
+#include <vector>
+#include <string>
+
+namespace llvm
+{
+class MemoryBuffer;
+
+}
+
+namespace mcld
+{
+class MCLDInfo;
+class Input;
+class InputTree;
+
+/** \class GNUArchiveReader
+ * \brief GNUArchiveReader reads GNU archive files.
+ */
+class GNUArchiveReader : public ArchiveReader
+{
+private:
+ struct ArchiveMemberHeader;
+ struct SymbolTableEntry;
+
+public:
+ explicit GNUArchiveReader(MCLDInfo &pLDInfo, LDReader::Endian endian)
+ : m_pLDInfo(pLDInfo),
+ m_endian(endian)
+ { }
+
+ ~GNUArchiveReader()
+ { }
+
+ /// Read an archive and extract each member in.
+ /// Construct the coresponding Input for each member.
+ InputTree *readArchive(Input &input);
+
+ bool isMyFormat(Input &input) const;
+
+ LDReader::Endian endian(Input& pFile) const;
+
+private:
+ /// set up the archive, including
+ /// first, read symbol table
+ /// second, read extended file name which is used in thin archive
+ InputTree *setupNewArchive(Input &pInput, size_t off);
+
+ /// parse the archive header, and return the member size
+ size_t parseMemberHeader(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ off_t off,
+ std::string *p_Name,
+ off_t *nestedOff,
+ std::string &p_ExtendedName);
+
+ void readSymbolTable(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ std::vector<SymbolTableEntry> &pSymbolTable,
+ off_t start,
+ size_t size);
+
+private:
+ MCLDInfo &m_pLDInfo;
+ LDReader::Endian m_endian;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/Group.h b/include/mcld/LD/Group.h
new file mode 100644
index 0000000..31c4a68
--- /dev/null
+++ b/include/mcld/LD/Group.h
@@ -0,0 +1,28 @@
+//===- Group.h ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_GROUP_H
+#define LD_GROUP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class Group
+ * \brief Group records the grouping of all regions
+ */
+class Group
+{
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/InputSymbolTable.h b/include/mcld/LD/InputSymbolTable.h
new file mode 100644
index 0000000..c5e3864
--- /dev/null
+++ b/include/mcld/LD/InputSymbolTable.h
@@ -0,0 +1,46 @@
+//===- InputSymbolTable.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef INPUTSYMBOLTABLE_H
+#define INPUTSYMBOLTABLE_H
+#include <llvm/ADT/StringRef.h>
+#include "mcld/LD/SymbolTableIF.h"
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+class LDSymbol;
+
+/** \class InputSymbolTable
+ * \brief Input symbol table, for MCLDInput.
+ *
+ * \see
+ */
+class InputSymbolTable : public SymbolTableIF
+{
+ /* draft. */
+ friend class SymbolTableFactory;
+private:
+ InputSymbolTable(StrSymPool &pStrSymPool,
+ size_t pNumOfSymbols,
+ StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable);
+private:
+ virtual void doInsertSymbol(LDSymbol *);
+ virtual void doMerge(const SymbolTableIF &);
+public:
+ virtual ~InputSymbolTable();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDContext.h b/include/mcld/LD/LDContext.h
new file mode 100644
index 0000000..878ba8d
--- /dev/null
+++ b/include/mcld/LD/LDContext.h
@@ -0,0 +1,105 @@
+//===- LDContext.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDCONTEXT_H
+#define MCLD_LDCONTEXT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+#include <mcld/LD/LDFileFormat.h>
+#include <llvm/Support/DataTypes.h>
+#include <string>
+#include <cassert>
+
+namespace llvm {
+class StringRef;
+}
+
+namespace mcld
+{
+
+class LDSymbol;
+class LDSection;
+
+/** \class LDContext
+ * \brief LDContext stores the data which a object file should has
+ */
+class LDContext
+{
+public:
+ typedef std::vector<LDSection*> SectionTable;
+ typedef SectionTable::iterator sect_iterator;
+ typedef SectionTable::const_iterator const_sect_iterator;
+
+ typedef std::vector<LDSymbol*> SymbolTable;
+ typedef SymbolTable::iterator sym_iterator;
+ typedef SymbolTable::const_iterator const_sym_iterator;
+
+public:
+ LDContext();
+
+ ~LDContext();
+
+ // ----- sections ----- //
+ SectionTable& getSectionTable()
+ { return m_SectionTable; }
+
+ const SectionTable& getSectionTable() const
+ { return m_SectionTable; }
+
+ sect_iterator sectBegin()
+ { return m_SectionTable.begin(); }
+
+ sect_iterator sectEnd()
+ { return m_SectionTable.end(); }
+
+ const_sect_iterator sectBegin() const
+ { return m_SectionTable.begin(); }
+
+ const_sect_iterator sectEnd() const
+ { return m_SectionTable.end(); }
+
+ LDSection* getSection(unsigned int pIdx);
+
+ const LDSection* getSection(unsigned int pIdx) const;
+
+ LDSection* getSection(const std::string& pName);
+
+ const LDSection* getSection(const std::string& pName) const;
+
+ size_t getSectionIdx(const std::string& pName) const;
+
+ size_t numOfSections() const
+ { return m_SectionTable.size(); }
+
+ // ----- symbols ----- //
+ LDSymbol* getSymbol(unsigned int pIdx);
+
+ const LDSymbol* getSymbol(unsigned int pIdx) const;
+
+ LDSymbol* getSymbol(const llvm::StringRef& pName);
+
+ const LDSymbol* getSymbol(const llvm::StringRef& pName) const;
+
+ void addSymbol(LDSymbol* pSym)
+ { m_SymTab.push_back(pSym); }
+
+private:
+ SectionTable m_SectionTable;
+ SymbolTable m_SymTab;
+
+ // FIXME : maintain a map<section name, section index>
+};
+
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDFileFormat.h b/include/mcld/LD/LDFileFormat.h
new file mode 100644
index 0000000..df80f67
--- /dev/null
+++ b/include/mcld/LD/LDFileFormat.h
@@ -0,0 +1,113 @@
+//===- LDFileFormat.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDFILE_FORMAT_H
+#define MCLD_LDFILE_FORMAT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <cstdio>
+#include <cassert>
+
+namespace mcld
+{
+
+class MCLinker;
+class LDSection;
+
+/** \class LDFileFormat
+ * \brief LDFileFormat describes the common file formats.
+ */
+class LDFileFormat
+{
+public:
+ enum Kind {
+ Null,
+ Regular,
+ BSS,
+ NamePool,
+ Relocation,
+ Debug,
+ Target,
+ Exception,
+ Version,
+ Note,
+ MetaData,
+ Group,
+ };
+
+protected:
+ LDFileFormat();
+
+public:
+ virtual ~LDFileFormat();
+
+ /// initStdSections - initialize all standard sections.
+ void initStdSections(MCLinker& pLinker);
+
+ /// initObjectFormat - different format, such as ELF and MachO, should
+ /// implement this
+ virtual void initObjectFormat(MCLinker& pLinker) = 0;
+
+ /// initObjectType - different types, such as shared object, executable
+ /// files, should implement this
+ virtual void initObjectType(MCLinker& pLinker) = 0;
+
+ // ----- access functions ----- //
+ LDSection& getText() {
+ assert(NULL != f_pTextSection);
+ return *f_pTextSection;
+ }
+
+ const LDSection& getText() const {
+ assert(NULL != f_pTextSection);
+ return *f_pTextSection;
+ }
+
+ LDSection& getData() {
+ assert(NULL != f_pDataSection);
+ return *f_pDataSection;
+ }
+
+ const LDSection& getData() const {
+ assert(NULL != f_pDataSection);
+ return *f_pDataSection;
+ }
+
+ LDSection& getBSS() {
+ assert(NULL != f_pBSSSection);
+ return *f_pBSSSection;
+ }
+
+ const LDSection& getBSS() const {
+ assert(NULL != f_pBSSSection);
+ return *f_pBSSSection;
+ }
+
+ LDSection& getReadOnly() {
+ assert(NULL != f_pReadOnlySection);
+ return *f_pReadOnlySection;
+ }
+
+ const LDSection& getReadOnly() const {
+ assert(NULL != f_pReadOnlySection);
+ return *f_pReadOnlySection;
+ }
+protected:
+ // variable name : ELF MachO
+ LDSection* f_pTextSection; // .text __text
+ LDSection* f_pDataSection; // .data __data
+ LDSection* f_pBSSSection; // .bss __bss
+ LDSection* f_pReadOnlySection; // .rodata __const
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDReader.h b/include/mcld/LD/LDReader.h
new file mode 100644
index 0000000..4fde9f0
--- /dev/null
+++ b/include/mcld/LD/LDReader.h
@@ -0,0 +1,47 @@
+//===- LDReader.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_READER_INTERFACE_H
+#define MCLD_READER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+
+namespace mcld
+{
+
+class Input;
+
+/** \class LDReader
+ * \brief LDReader provides the basic interfaces for all readers. It also
+ * provides basic functions to read data stream.
+ */
+class LDReader
+{
+public:
+ enum Endian {
+ LittleEndian,
+ BigEndian
+ };
+
+protected:
+ LDReader() { }
+
+public:
+ virtual ~LDReader() { }
+
+ virtual bool isMyFormat(Input& pInput) const = 0;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDSection.h b/include/mcld/LD/LDSection.h
new file mode 100644
index 0000000..4c793de
--- /dev/null
+++ b/include/mcld/LD/LDSection.h
@@ -0,0 +1,205 @@
+//===- LDSection.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LD_LDSECTION_H
+#define MCLD_LD_LDSECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/MC/MCSection.h>
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <string>
+
+namespace llvm {
+
+class MCAsmInfo;
+class raw_ostream;
+
+} // namespace of llvm
+
+namespace mcld {
+/** \class LDSection
+ * \brief LDSection represents a section header entry. It is a unified
+ * abstraction for various file formats.
+ *
+ * LDSection contains both the format-dependent data and LLVM specific data.
+ *
+ */
+class LDSection : public llvm::MCSection
+{
+public:
+ LDSection(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag,
+ uint64_t pSize = 0,
+ uint64_t pOffset = 0,
+ uint64_t pAddr = 0);
+
+ /// name - the name of this section.
+ const std::string& name() const
+ { return m_Name; }
+
+ /// kind - the kind of this section, such as Text, BSS, GOT, and so on.
+ /// from LDFileFormat::Kind
+ LDFileFormat::Kind kind() const
+ { return m_Kind; }
+
+ /// type - The categorizes the section's contents and semantics. It's
+ /// different from llvm::SectionKind. Type is format-dependent, but
+ /// llvm::SectionKind is format independent and is used for bit-code.
+ /// In ELF, it is sh_type
+ /// In MachO, it's type field of struct section::flags
+ uint32_t type() const
+ { return m_Type; }
+
+ /// flag - An integer describes miscellaneous attributes.
+ /// In ELF, it is sh_flags.
+ /// In MachO, it's attribute field of struct section::flags
+ uint32_t flag() const
+ { return m_Flag; }
+
+ /// size - An integer specifying the size in bytes of the virtual memory
+ /// occupied by this section.
+ /// In ELF, if the type() is SHT_NOBITS, this function return zero.
+ /// Before layouting, output's LDSection::size() should return zero.
+ uint64_t size() const
+ { return m_Size; }
+
+ /// offset - An integer specifying the offset of this section in the file.
+ /// Before layouting, output's LDSection::offset() should return zero.
+ uint64_t offset() const
+ { return m_Offset; }
+
+ /// addr - An integer specifying the virtual address of this section in the
+ /// virtual image.
+ /// Before layouting, output's LDSection::offset() should return zero.
+ /// ELF uses sh_addralign to set alignment constraints. In LLVM, alignment
+ /// constraint is set in MCSectionData::setAlignment. addr() contains the
+ /// original ELF::sh_addr. Modulo sh_addr by sh_addralign is not necessary.
+ /// MachO uses the same scenario.
+ ///
+ /// Because addr() in output is changing during linking, MCLinker does not
+ /// store the address of the output here. The address is in Layout
+ uint64_t addr() const
+ { return m_Addr; }
+
+ /// align - An integer specifying the align of this section in the file.
+ /// Before layouting, output's LDSection::align() should return zero.
+ uint32_t align() const
+ { return m_Align; }
+
+ size_t index() const
+ { return m_Index; }
+
+ /// getLink - return the Link. When a section A needs the other section B
+ /// during linking or loading, we say B is A's Link section.
+ /// In ELF, InfoLink section control the ElfNN_Shdr::sh_link and sh_info.
+ ///
+ /// @return if the section needs no other sections, return NULL
+ LDSection* getLink()
+ { return m_pLink; }
+
+ const LDSection* getLink() const
+ { return m_pLink; }
+
+ size_t getInfo() const
+ { return m_Info; }
+
+ void setKind(LDFileFormat::Kind pKind)
+ { m_Kind = pKind; }
+
+ void setSize(uint64_t size)
+ { m_Size = size; }
+
+ void setOffset(uint64_t Offset)
+ { m_Offset = Offset; }
+
+ void setAddr(uint64_t addr)
+ { m_Addr = addr; }
+
+ void setAlign(uint32_t align)
+ { m_Align = align; }
+
+ void setFlag(uint32_t flag)
+ { m_Flag = flag; }
+
+ void setType(uint32_t type)
+ { m_Type = type; }
+
+ static bool classof(const MCSection *S)
+ { return S->getVariant() == SV_LDContext; }
+
+ static bool classof(const LDSection *)
+ { return true; }
+
+ // ----- methods for adapt to llvm::MCSection ----- //
+ void PrintSwitchToSection(const llvm::MCAsmInfo &MAI,
+ llvm::raw_ostream &OS) const
+ { }
+
+ bool UseCodeAlign() const
+ { return true; }
+
+ bool isVirtualSection() const
+ { return false; }
+
+ llvm::MCSectionData* getSectionData()
+ { return m_pSectionData; }
+
+ const llvm::MCSectionData* getSectionData() const
+ { return m_pSectionData; }
+
+ void setSectionData(llvm::MCSectionData* pSD)
+ { m_pSectionData = pSD; }
+
+ bool hasSectionData() const
+ { return (NULL != m_pSectionData); }
+
+ /// setLink - set the sections should link with.
+ /// if pLink is NULL, no Link section is set.
+ void setLink(LDSection* pLink)
+ { m_pLink = pLink; }
+
+ void setInfo(size_t pInfo)
+ { m_Info = pInfo; }
+
+ void setIndex(size_t pIndex)
+ { m_Index = pIndex; }
+
+private:
+ std::string m_Name;
+ LDFileFormat::Kind m_Kind;
+ uint32_t m_Type;
+ uint32_t m_Flag;
+
+ uint64_t m_Size;
+ uint64_t m_Offset;
+ uint64_t m_Addr;
+ uint32_t m_Align;
+
+ size_t m_Info;
+ LDSection* m_pLink;
+
+ // pointer to MCSectionData.
+ llvm::MCSectionData* m_pSectionData;
+
+ // the index of the file
+ size_t m_Index;
+
+}; // end of LDSection
+
+} // end namespace mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDSectionFactory.h b/include/mcld/LD/LDSectionFactory.h
new file mode 100644
index 0000000..49b11c7
--- /dev/null
+++ b/include/mcld/LD/LDSectionFactory.h
@@ -0,0 +1,58 @@
+//===- LDSectionFactory.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDSECTION_FACTORY_H
+#define MCLD_LDSECTION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <string>
+
+namespace mcld
+{
+
+/** \class LDSectionFactory
+ * \brief provide the interface to create and delete section data for output
+ */
+class LDSectionFactory : public GCFactory<LDSection, 0>
+{
+public:
+ /// LDSectionFactory - the factory of LDSection
+ /// pNum is the average number of the LDSections in the system.
+ LDSectionFactory(size_t pNum);
+ ~LDSectionFactory();
+
+ /// produce - produce an empty section information.
+ /// This function will create an empty MCSectionData and its LDSection.
+ /// @param pName - The name of the section.
+ /// @param pKind - The kind of the section. Used to create default section map
+ /// @param pType - sh_type in ELF.
+ /// @param pFlag - is the same as sh_flags.
+ LDSection* produce(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag);
+
+ /// destroy - destruct the LDSection.
+ /// @oaram - the reference of the pointer to the destructed LDSection.
+ /// after the destruction, the pointer is set to zero.
+ void destroy(LDSection*& pSD);
+
+ /// find - find the LDSection* in factory from the given section name.
+ /// return NULL if not found.
+ /// @param pName - the name of section
+ LDSection* find(const std::string& pName);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h
new file mode 100644
index 0000000..45c0b75
--- /dev/null
+++ b/include/mcld/LD/LDSymbol.h
@@ -0,0 +1,128 @@
+//===- LDSymbol.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LD_SYMBOL_H
+#define MCLD_LD_SYMBOL_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/LD/ResolveInfo.h"
+#include "mcld/MC/MCFragmentRef.h"
+#include <llvm/MC/MCAssembler.h>
+#include <assert.h>
+
+namespace mcld
+{
+
+/** \class LDSymbol
+ * \brief LDSymbol provides a consistent abstraction for different formats
+ * in different targets.
+ */
+class LDSymbol
+{
+public:
+ // FIXME: use SizeTrait<32> or SizeTrait<64> instead of big type
+ typedef ResolveInfo::SizeType SizeType;
+ typedef uint64_t ValueType;
+ typedef MCFragmentRef::Offset Offset;
+
+public:
+ LDSymbol();
+ LDSymbol(const LDSymbol& pCopy);
+ LDSymbol& operator=(const LDSymbol& pCopy);
+ ~LDSymbol();
+
+ // ----- observers ----- //
+ const char* name() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->name();
+ }
+
+ unsigned int nameSize() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->nameSize();
+ }
+
+ llvm::StringRef str() const {
+ assert(NULL != m_pResolveInfo);
+ return llvm::StringRef(m_pResolveInfo->name(), m_pResolveInfo->nameSize());
+ }
+
+ bool isDyn() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->isDyn();
+ }
+
+ unsigned int type() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->type();
+ }
+ unsigned int desc() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->desc();
+ }
+ unsigned int binding() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->binding();
+ }
+
+ uint8_t other() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->other();
+ }
+
+ uint8_t visibility() const {
+ assert(NULL != m_pResolveInfo);
+ return m_pResolveInfo->other();
+ }
+
+ ValueType value() const
+ { return m_Value; }
+
+ const MCFragmentRef* fragRef() const
+ { return m_pFragRef; }
+
+ SizeType size() const
+ { return m_pResolveInfo->size(); }
+
+ ResolveInfo* resolveInfo()
+ { return m_pResolveInfo; }
+
+ const ResolveInfo* resolveInfo() const
+ { return m_pResolveInfo; }
+
+ bool hasFragRef() const
+ { return (NULL != m_pFragRef); }
+
+ // ----- modifiers ----- //
+ void setSize(SizeType pSize) {
+ assert(NULL != m_pResolveInfo);
+ m_pResolveInfo->setSize(pSize);
+ }
+
+ void setValue(ValueType pValue)
+ { m_Value = pValue; }
+
+ void setFragmentRef(MCFragmentRef* pFragmentRef);
+
+ void setResolveInfo(const ResolveInfo& pInfo);
+
+private:
+ // ----- Symbol's fields ----- //
+ ResolveInfo* m_pResolveInfo;
+ MCFragmentRef* m_pFragRef;
+ ValueType m_Value;
+
+};
+
+} // namespace mcld
+
+#endif
+
diff --git a/include/mcld/LD/LDWriter.h b/include/mcld/LD/LDWriter.h
new file mode 100644
index 0000000..78c2871
--- /dev/null
+++ b/include/mcld/LD/LDWriter.h
@@ -0,0 +1,41 @@
+//===- LDWriter.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LDWriter provides an interface used by MCLinker,
+// which writes the result of linking into a .so file or a executable.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_WRITER_INTERFACE_H
+#define MCLD_WRITER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/TargetLDBackend.h>
+
+namespace mcld
+{
+
+/** \class LDWriter
+ * \brief LDWriter provides the basic interfaces for all writers.
+ * (ObjectWriter, DynObjWriter, and EXEObjWriter)
+ */
+class LDWriter
+{
+protected:
+ LDWriter() { }
+
+public:
+ virtual ~LDWriter() { }
+
+};
+
+} //end namespace
+
+#endif
+
diff --git a/include/mcld/LD/Layout.h b/include/mcld/LD/Layout.h
new file mode 100644
index 0000000..28f2d83
--- /dev/null
+++ b/include/mcld/LD/Layout.h
@@ -0,0 +1,270 @@
+//===- Layout.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LAYOUT_H
+#define MCLD_LAYOUT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/ilist.h>
+#include <llvm/ADT/ilist_node.h>
+#include <llvm/ADT/DenseMap.h>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/MC/MCFragmentRef.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/LDSection.h>
+#include <map>
+
+namespace mcld
+{
+class MCLinker;
+class Output;
+class TargetLDBackend;
+
+/** \class Layout
+ * \brief Layout maintains the mapping between sections and fragments.
+ *
+ * MCLinker is a fragment-based linker. But readers and target backends
+ * still need section information. Layout is used to maintain the mapping
+ * between sections and fragments. Layout helps readers and target backends
+ * get the input or output section information from a fragment.
+ */
+class Layout
+{
+public:
+ typedef std::vector<LDSection*> SectionOrder;
+ typedef SectionOrder::iterator sect_iterator;
+ typedef SectionOrder::const_iterator const_sect_iterator;
+
+public:
+ /// constructor
+ Layout();
+
+ /// destructor
+ ~Layout();
+
+ /// getInputLDSection - give a MCFragment, return the corresponding input
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in input
+ LDSection* getInputLDSection(const llvm::MCFragment& pFrag);
+
+ /// getInputLDSection - give a MCFragment, return the corresponding input
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in input
+ const LDSection* getInputLDSection(const llvm::MCFragment& pFrag) const;
+
+ /// getFragmentRef - give a LDSection in input file and an offset, return
+ /// the fragment reference.
+ ///
+ /// @param pInputSection - the given input section
+ /// @param pOffset - the offset, cannot be larger than this input section.
+ /// @return if found, return the fragment. Otherwise, return NULL.
+ MCFragmentRef*
+ getFragmentRef(const LDSection& pInputSection, uint64_t pOffset);
+
+ /// getFragmentRef - give a fragment and a big offset, return the fragment
+ /// reference in the section data.
+ ///
+ /// @param pFrag - the given fragment
+ /// @param pBigOffset - the offset, can be larger than the fragment, but can
+ /// not larger than this input section.
+ /// @return if found, return the fragment. Otherwise, return NULL.
+ MCFragmentRef*
+ getFragmentRef(const llvm::MCFragment& pFrag, uint64_t pBigOffset);
+
+ /// getOutputOffset - Get the offset of the given fragment inside the
+ /// the output's MCSectionData.
+ uint64_t getOutputOffset(const llvm::MCFragment& pFrag);
+
+ /// getOutputOffset - Get the offset of the given fragment inside the
+ /// the output's MCSectionData.
+ uint64_t getOutputOffset(const llvm::MCFragment& pFrag) const;
+
+ /// getOutputOffset - Get the offset of the given fragment inside
+ /// the output's MCSectionData.
+ ///
+ /// @return return -1 if the fragment is not found in output's MCSectionData.
+
+ uint64_t getOutputOffset(const MCFragmentRef& pFragRef);
+ /// getOutputOffset - Get the offset of the given fragment inside
+ /// the output's MCSectionData.
+ ///
+ /// @return return -1 if the fragment is not found in output's MCSectionData.
+ uint64_t getOutputOffset(const MCFragmentRef& pFragRef) const;
+
+ /// getOutputLDSection - give a MCFragment, return the corresponding output
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in the output
+ LDSection* getOutputLDSection(const llvm::MCFragment& pFrag);
+
+ /// getOutputLDSection - give a MCFragment, return the corresponding output
+ /// LDSection*
+ ///
+ /// @return return NULL if the fragment is not found in the output
+ const LDSection* getOutputLDSection(const llvm::MCFragment& pFrag) const;
+
+ // ----- modifiers ----- //
+ bool layout(Output& pOutput, const TargetLDBackend& pBackend);
+
+ /// addInputRange
+ void addInputRange(const llvm::MCSectionData& pSD,
+ const LDSection& pInputHdr);
+
+ /// appendFragment - append the given MCFragment to the given MCSectionData,
+ /// and insert a MCAlignFragment to preserve the required align constraint if
+ /// needed
+ /// @return return the inserted size, i.e., the size of pFrag and alignment
+ /// size if any
+ uint64_t appendFragment(llvm::MCFragment& pFrag,
+ llvm::MCSectionData& pSD,
+ uint32_t pAlignConstraint = 1);
+private:
+ /** \class Range
+ * \brief Range is a <input's LDSection, previous rear fragment> pair
+ */
+ struct Range : public llvm::ilist_node<Range>
+ {
+ public:
+ Range();
+ Range(const LDSection& pHeader);
+ ~Range();
+
+ public:
+ LDSection* header;
+ llvm::MCFragment* prevRear;
+ };
+
+ typedef llvm::iplist<Range> RangeList;
+
+ typedef std::map<const llvm::MCSectionData*, RangeList*> SDRangeMap;
+
+ typedef GCFactory<MCFragmentRef, 0> FragRefFactory;
+
+private:
+ inline bool isFirstRange(const Range& pRange) const
+ { return (NULL == pRange.prevRear); }
+
+ inline bool isLastRange(const Range& pRange) const
+ { return (NULL == pRange.getNextNode()); }
+
+ inline bool isEmptyRange(const Range& pRange) const
+ {
+ if (isFirstRange(pRange)) {
+ if (!pRange.header->hasSectionData() ||
+ pRange.header->getSectionData()->getFragmentList().empty())
+ return true;
+ else
+ return false;
+ }
+ return (NULL == pRange.prevRear->getNextNode());
+ }
+
+ // get the front fragment in the range.
+ inline llvm::MCFragment* getFront(Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isFirstRange(pRange))
+ return &pRange.header->getSectionData()->getFragmentList().front();
+
+ if (isEmptyRange(pRange))
+ return NULL;
+
+ return pRange.prevRear->getNextNode();
+ }
+
+ inline const llvm::MCFragment* getFront(const Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isFirstRange(pRange))
+ return &pRange.header->getSectionData()->getFragmentList().front();
+
+ if (isEmptyRange(pRange))
+ return NULL;
+
+ return pRange.prevRear->getNextNode();
+ }
+
+ // get the rear fragment in the range.
+ inline llvm::MCFragment* getRear(Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isLastRange(pRange)) {
+ if (isEmptyRange(pRange))
+ return NULL;
+ return &pRange.header->getSectionData()->getFragmentList().back();
+ }
+ return pRange.getNextNode()->prevRear;
+ }
+
+ inline const llvm::MCFragment* getRear(const Range& pRange) const
+ {
+ if (!pRange.header->hasSectionData())
+ return NULL;
+ if (pRange.header->getSectionData()->getFragmentList().empty())
+ return NULL;
+
+ if (isLastRange(pRange)) {
+ if (isEmptyRange(pRange))
+ return NULL;
+ return &pRange.header->getSectionData()->getFragmentList().back();
+ }
+ return pRange.getNextNode()->prevRear;
+ }
+
+ MCFragmentRef* getFragmentRef(Range &pRange, uint64_t pOffset);
+
+ MCFragmentRef* getFragmentRef(llvm::MCFragment& pFront,
+ llvm::MCFragment& pRear,
+ uint64_t pOffset);
+
+ bool hasLayoutOrder(const llvm::MCFragment& pFragment) const
+ { return (pFragment.getLayoutOrder() != ~(0U)); }
+
+ bool hasLayoutOffset(const llvm::MCFragment& pFragment) const
+ { return (pFragment.Offset != ~UINT64_C(0)); }
+
+ bool isValidOffset(const llvm::MCFragment& pFrag, uint64_t pTargetOffset) const;
+
+ void setFragmentLayoutOrder(llvm::MCFragment* pFragment);
+
+ void setFragmentLayoutOffset(llvm::MCFragment* pFragment);
+
+ /// sortSectionOrder - perform sorting on m_SectionOrder to get final layout
+ /// ordering
+ void sortSectionOrder(const Output& pOutput,
+ const TargetLDBackend& pBackend);
+
+private:
+ /// a vector to describe the order of sections
+ SectionOrder m_SectionOrder;
+
+ /// the map from MCSectionData* to its own RangeList.
+ SDRangeMap m_SDRangeMap;
+
+ FragRefFactory m_FragRefFactory;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ObjectReader.h b/include/mcld/LD/ObjectReader.h
new file mode 100644
index 0000000..9dbe9ac
--- /dev/null
+++ b/include/mcld/LD/ObjectReader.h
@@ -0,0 +1,69 @@
+//===- ObjectReader.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_OBJECT_READER_H
+#define MCLD_OBJECT_READER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/LDReader.h"
+#include <llvm/Support/system_error.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/StringHash.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/ResolveInfoFactory.h>
+
+namespace mcld
+{
+
+class Input;
+
+/** \class ObjectReader
+ * \brief ObjectReader provides an common interface for different object
+ * formats.
+ */
+class ObjectReader : public LDReader
+{
+protected:
+ typedef HashTable<ResolveInfo,
+ StringHash<ELF>,
+ ResolveInfoFactory> GroupSignatureMap;
+
+protected:
+ ObjectReader()
+ { }
+
+public:
+ virtual ~ObjectReader() { }
+
+ virtual bool readObject(Input& pFile) = 0;
+
+ virtual bool readSymbols(Input& pFile) = 0;
+
+ virtual bool readSections(Input& pFile) = 0;
+
+ /// readRelocations - read relocation sections
+ ///
+ /// This function should be called after symbol resolution.
+ virtual bool readRelocations(Input& pFile) = 0;
+
+ GroupSignatureMap& signatures()
+ { return f_GroupSignatureMap; }
+
+ const GroupSignatureMap& signatures() const
+ { return f_GroupSignatureMap; }
+
+protected:
+ GroupSignatureMap f_GroupSignatureMap;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h
new file mode 100644
index 0000000..0c48723
--- /dev/null
+++ b/include/mcld/LD/ObjectWriter.h
@@ -0,0 +1,39 @@
+//===- ObjectWriter.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_OBJECT_WRITER_INTERFACE_H
+#define MCLD_OBJECT_WRITER_INTERFACE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Support/system_error.h>
+
+namespace mcld
+{
+
+class Output;
+class GNULDBackend;
+
+/** \class ObjectWriter
+ * \brief ObjectWriter provides a common interface for object file writers.
+ */
+class ObjectWriter
+{
+protected:
+ ObjectWriter(GNULDBackend& pBackend);
+
+public:
+ virtual ~ObjectWriter();
+
+ virtual llvm::error_code writeObject(Output& pOutput) = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/OutputSymbolTable.h b/include/mcld/LD/OutputSymbolTable.h
new file mode 100644
index 0000000..fdcf0bc
--- /dev/null
+++ b/include/mcld/LD/OutputSymbolTable.h
@@ -0,0 +1,44 @@
+//===- OutputSymbolTable.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef OUTPUTSYMBOLTABLE_H
+#define OUTPUTSYMBOLTABLE_H
+#include <llvm/ADT/StringRef.h>
+#include "mcld/LD/SymbolTableIF.h"
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+class LDSymbol;
+
+/** \class OutputSymbolTable
+ * \brief Output symbol table, for MCLDOutput.
+ *
+ * \see
+ */
+class OutputSymbolTable : public SymbolTableIF
+{
+ /* draft. */
+ friend class SymbolTableFactory;
+private:
+ OutputSymbolTable(StrSymPool &pStrSymPool,
+ size_t pNumOfSymbols,
+ StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable);
+private:
+ virtual void doInsertSymbol(LDSymbol *);
+ virtual void doMerge(const SymbolTableIF &);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/Relocation.h b/include/mcld/LD/Relocation.h
new file mode 100644
index 0000000..09ff6e4
--- /dev/null
+++ b/include/mcld/LD/Relocation.h
@@ -0,0 +1,115 @@
+//===- Relocation.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_RELOCATION_H
+#define LD_RELOCATION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/ilist_node.h>
+#include <llvm/Support/DataTypes.h>
+#include <mcld/MC/MCFragmentRef.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/LDSymbol.h>
+
+
+namespace mcld
+{
+class Layout;
+class RelocationFactory;
+class MCLDInfo;
+
+class Relocation : public llvm::MCFragment
+{
+friend class RelocationFactory;
+
+public:
+ typedef uint64_t Address; // FIXME: use SizeTrait<T>::Address instead
+ typedef uint64_t DWord; // FIXME: use SizeTrait<T>::Word instead
+ typedef uint8_t Type;
+
+private:
+ Relocation(Type pType,
+ MCFragmentRef* pTargetRef,
+ Address pAddend,
+ DWord pTargetData);
+
+public:
+ ~Relocation();
+
+ /// type - relocation type
+ Type type() const
+ { return m_Type; }
+
+ /// symValue - S value - the symbol address
+ Address symValue() const;
+
+ /// addend - A value
+ Address addend() const
+ { return m_Addend; }
+
+ /// place - P value - address of the place being relocated
+ Address place(const Layout& pLayout) const;
+
+ /// symbol info - binding, type
+ const ResolveInfo* symInfo() const
+ { return m_pSymInfo; }
+
+ /// symbol info - binding, type
+ ResolveInfo* symInfo()
+ { return m_pSymInfo; }
+
+ /// target - the target data to relocate
+ DWord& target();
+
+ /// target - the target data to relocate
+ const DWord& target() const;
+
+ /// targetRef - the reference of the target data
+ MCFragmentRef& targetRef()
+ { return m_TargetAddress; }
+
+ /// targetRef - the reference of the target data
+ const MCFragmentRef& targetRef() const
+ { return m_TargetAddress; }
+
+ void apply(RelocationFactory& pRelocFactory, const MCLDInfo& pLDInfo);
+
+ /// ----- modifiers ----- ///
+ void setType(Type pType);
+
+ void setAddend(Address pAddend);
+
+ void setSymInfo(ResolveInfo* pSym);
+
+ // Relocation is a kind of MCFragment with type of FT_Reloc
+ static bool classof(const MCFragment *F)
+ { return F->getKind() == MCFragment::FT_Reloc;}
+ static bool classof(const Relocation *) { return true; }
+
+private:
+ /// m_Type - the type of the relocation entries
+ Type m_Type;
+
+ /// m_TargetData - target data of the place being relocated
+ DWord m_TargetData;
+
+ /// m_pSymInfo - resolved symbol info of relocation target symbol
+ ResolveInfo* m_pSymInfo;
+
+ /// m_TargetAddress - MCFragmentRef of the place being relocated
+ MCFragmentRef m_TargetAddress;
+
+ /// m_Addend - the addend
+ Address m_Addend;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/RelocationFactory.h b/include/mcld/LD/RelocationFactory.h
new file mode 100644
index 0000000..eed3eae
--- /dev/null
+++ b/include/mcld/LD/RelocationFactory.h
@@ -0,0 +1,81 @@
+//===- Relocation.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_RELOCATION_FACTORY_H
+#define LD_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Support/GCFactory.h>
+#include <mcld/LD/Relocation.h>
+
+namespace mcld
+{
+
+class LDSymbol;
+class ResolveInfo;
+class MCFragmentRef;
+class Layout;
+class GOT;
+class TargetLDBackend;
+class MCLDInfo;
+
+/** \class RelocationFactory
+ * \brief RelocationFactory provides the interface for generating target
+ * relocation
+ *
+ */
+class RelocationFactory : public GCFactory<Relocation, 0>
+{
+public:
+ typedef Relocation::Type Type;
+ typedef Relocation::Address Address;
+ typedef Relocation::DWord DWord;
+
+public:
+ explicit RelocationFactory(size_t pNum);
+
+ virtual ~RelocationFactory();
+
+ /// apply - general apply function
+ virtual void applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo) = 0;
+
+ // ----- production ----- //
+ /// produce - produce a relocation entry
+ /// @param pType - the type of the relocation entry
+ /// @param pFragRef - the place to apply the relocation
+ /// @param pAddend - the addend of the relocation entry
+ Relocation* produce(Type pType,
+ MCFragmentRef& pFragRef,
+ Address pAddend = 0);
+
+ /// produceEmptyEntry - produce an empty relocation which
+ /// occupied memory space but all contents set to zero.
+ Relocation* produceEmptyEntry();
+
+ void destroy(Relocation* pRelocation);
+
+ void setLayout(const Layout& pLayout);
+
+ // ------ observers -----//
+ const Layout& getLayout() const;
+
+ virtual TargetLDBackend& getTarget() = 0;
+
+ virtual const TargetLDBackend& getTarget() const = 0;
+
+private:
+ const Layout* m_pLayout;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ResolveInfo.h b/include/mcld/LD/ResolveInfo.h
new file mode 100644
index 0000000..f48f1c2
--- /dev/null
+++ b/include/mcld/LD/ResolveInfo.h
@@ -0,0 +1,279 @@
+//===- ResolveInfo.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_RESOLVE_INFO_H
+#define MCLD_RESOLVE_INFO_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+#include <llvm/ADT/StringRef.h>
+
+namespace mcld
+{
+
+class LDSymbol;
+
+/** \class ResolveInfo
+ * \brief ResolveInfo records the information about how to resolve a symbol.
+ *
+ * A symbol must have some `attributes':
+ * - Desc - Defined, Reference, Common or Indirect
+ * - Binding - Global, Local, Weak
+ * - IsDyn - appear in dynamic objects or regular objects
+ * - Type - what the symbol points to
+ * - Size - the size of the symbol point to
+ * - Value - the pointer to another LDSymbol
+ * In order to save the memory and speed up the performance, MCLinker uses
+ * a bit field to store all attributes.
+ *
+ * The maximum string length is (2^16 - 1)
+ */
+class ResolveInfo
+{
+friend class ResolveInfoFactory;
+friend class MCLinker;
+public:
+ typedef uint64_t SizeType;
+
+ /** \enum Type
+ * \brief What the symbol stand for
+ *
+ * It is like ELF32_ST_TYPE
+ * MachO does not need this, and can not jump between Thumb and ARM code.
+ */
+ enum Type {
+ NoType = 0,
+ Object = 1,
+ Function = 2,
+ Section = 3,
+ File = 4,
+ CommonBlock = 5,
+ ThreadLocal = 6,
+ LoProc = 13,
+ HiProc = 15
+ };
+
+ /** \enum Desc
+ * \brief Description of the symbols.
+ *
+ * Follow the naming in MachO. Like MachO nlist::n_desc
+ * In ELF, is a part of st_shndx
+ */
+ enum Desc {
+ Undefined = 0,
+ Define = 1,
+ Common = 2,
+ Indirect = 3,
+ NoneDesc
+ };
+
+ enum Binding {
+ Global = 0,
+ Weak = 1,
+ Local = 2,
+ Absolute = 3,
+ NoneBinding
+ };
+
+ enum Visibility {
+ Default = 0,
+ Internal = 1,
+ Hidden = 2,
+ Protected = 3
+ };
+
+ // ----- For HashTable ----- //
+ typedef llvm::StringRef key_type;
+
+public:
+ // ----- modifiers ----- //
+ /// setRegular - set the source of the file is a regular object
+ void setRegular();
+
+ /// setDynamic - set the source of the file is a dynamic object
+ void setDynamic();
+
+ /// setSource - set the source of the file
+ /// @param pIsDyn is the source from a dynamic object?
+ void setSource(bool pIsDyn);
+
+ void setType(uint32_t pType);
+
+ void setDesc(uint32_t pDesc);
+
+ void setBinding(uint32_t pBinding);
+
+ void setOther(uint32_t pOther);
+
+ void setVisibility(Visibility pVisibility);
+
+ void setIsSymbol(bool pIsSymbol);
+
+ void setReserved(uint32_t pReserved);
+
+ void setSize(SizeType pSize)
+ { m_Size = pSize; }
+
+ void override(const ResolveInfo& pForm);
+
+ void overrideAttributes(const ResolveInfo& pFrom);
+
+ void overrideVisibility(const ResolveInfo& pFrom);
+
+ void setSymPtr(const LDSymbol* pSymPtr)
+ { m_Ptr.sym_ptr = const_cast<LDSymbol*>(pSymPtr); }
+
+ void setLink(const ResolveInfo* pTarget) {
+ m_Ptr.info_ptr = const_cast<ResolveInfo*>(pTarget);
+ m_BitField |= indirect_flag;
+ }
+
+
+ // ----- observers ----- //
+ bool isSymbol() const;
+
+ bool isString() const;
+
+ bool isGlobal() const;
+
+ bool isWeak() const;
+
+ bool isLocal() const;
+
+ bool isAbsolute() const;
+
+ bool isDefine() const;
+
+ bool isUndef() const;
+
+ bool isDyn() const;
+
+ bool isCommon() const;
+
+ bool isIndirect() const;
+
+ uint32_t type() const;
+
+ uint32_t desc() const;
+
+ uint32_t binding() const;
+
+ uint32_t reserved() const;
+
+ uint8_t other() const
+ { return (uint8_t)visibility(); }
+
+ Visibility visibility() const;
+
+ LDSymbol* outSymbol()
+ { return m_Ptr.sym_ptr; }
+
+ const LDSymbol* outSymbol() const
+ { return m_Ptr.sym_ptr; }
+
+ ResolveInfo* link()
+ { return m_Ptr.info_ptr; }
+
+ const ResolveInfo* link() const
+ { return m_Ptr.info_ptr; }
+
+ SizeType size() const
+ { return m_Size; }
+
+ const char* name() const
+ { return m_Name; }
+
+ unsigned int nameSize() const
+ { return (m_BitField >> NAME_LENGTH_OFFSET); }
+
+ uint32_t info() const
+ { return (m_BitField & INFO_MASK); }
+
+ uint32_t bitfield() const
+ { return m_BitField; }
+
+ // ----- For HashTable ----- //
+ bool compare(const key_type& pKey);
+
+private:
+ static const uint32_t GLOBAL_OFFSET = 0;
+ static const uint32_t GLOBAL_MASK = 1;
+
+ static const uint32_t DYN_OFFSET = 1;
+ static const uint32_t DYN_MASK = 1 << DYN_OFFSET;
+
+ static const uint32_t DESC_OFFSET = 2;
+ static const uint32_t DESC_MASK = 0x3 << DESC_OFFSET;
+
+ static const uint32_t LOCAL_OFFSET = 4;
+ static const uint32_t LOCAL_MASK = 1 << LOCAL_OFFSET;
+
+ static const uint32_t BINDING_MASK = GLOBAL_MASK | LOCAL_MASK;
+
+ static const uint32_t VISIBILITY_OFFSET = 5;
+ static const uint32_t VISIBILITY_MASK = 0x3 << VISIBILITY_OFFSET;
+
+ static const uint32_t TYPE_OFFSET = 7;
+ static const uint32_t TYPE_MASK = 0xF << TYPE_OFFSET;
+
+ static const uint32_t SYMBOL_OFFSET = 11;
+ static const uint32_t SYMBOL_MASK = 1 << SYMBOL_OFFSET;
+
+ static const uint32_t RESERVED_OFFSET = 12;
+ static const uint32_t RESERVED_MASK = 0xF << RESERVED_OFFSET;
+ static const uint32_t NAME_LENGTH_OFFSET = 16;
+ static const uint32_t INFO_MASK = 0xF;
+ static const uint32_t RESOLVE_MASK = 0xFFFF;
+
+ union SymOrInfo {
+ LDSymbol* sym_ptr;
+ ResolveInfo* info_ptr;
+ };
+
+public:
+ static const uint32_t global_flag = 0 << GLOBAL_OFFSET;
+ static const uint32_t weak_flag = 1 << GLOBAL_OFFSET;
+ static const uint32_t regular_flag = 0 << DYN_OFFSET;
+ static const uint32_t dynamic_flag = 1 << DYN_OFFSET;
+ static const uint32_t undefine_flag = 0 << DESC_OFFSET;
+ static const uint32_t define_flag = 1 << DESC_OFFSET;
+ static const uint32_t common_flag = 2 << DESC_OFFSET;
+ static const uint32_t indirect_flag = 3 << DESC_OFFSET;
+ static const uint32_t local_flag = 1 << LOCAL_OFFSET;
+ static const uint32_t absolute_flag = BINDING_MASK;
+ static const uint32_t object_flag = Object << TYPE_OFFSET;
+ static const uint32_t function_flag = Function << TYPE_OFFSET;
+ static const uint32_t section_flag = Section << TYPE_OFFSET;
+ static const uint32_t file_flag = File << TYPE_OFFSET;
+ static const uint32_t string_flag = 0 << SYMBOL_OFFSET;
+ static const uint32_t symbol_flag = 1 << SYMBOL_OFFSET;
+
+private:
+ ResolveInfo();
+ ResolveInfo(const ResolveInfo& pCopy);
+ ResolveInfo& operator=(const ResolveInfo& pCopy);
+ ~ResolveInfo();
+
+private:
+ SizeType m_Size;
+ SymOrInfo m_Ptr;
+
+ /** m_BitField
+ * 31 ... 16 15 12 11 10..7 6 .. 5 4 3 2 1 0
+ * |length of m_Name|reserved|Symbol|Type |ELF visibility|Local|Com|Def|Dyn|Weak|
+ */
+ uint32_t m_BitField;
+ char m_Name[0];
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/ResolveInfoFactory.h b/include/mcld/LD/ResolveInfoFactory.h
new file mode 100644
index 0000000..fcadf48
--- /dev/null
+++ b/include/mcld/LD/ResolveInfoFactory.h
@@ -0,0 +1,37 @@
+//===- ResolveInfoFactory.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_RESOLVE_INFO_FACTORY_H
+#define MCLD_RESOLVE_INFO_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/ResolveInfo.h"
+
+namespace mcld
+{
+
+/** \class ResolveInfoFactory
+ * \brief ResolveInfoFactory creates ResolveInfos.
+ */
+class ResolveInfoFactory
+{
+public:
+ typedef ResolveInfo entry_type;
+ typedef ResolveInfo::key_type key_type;
+
+public:
+ entry_type* produce(const key_type& pKey);
+ void destroy(entry_type* pEntry);
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/Resolver.h b/include/mcld/LD/Resolver.h
new file mode 100644
index 0000000..98dfe2c
--- /dev/null
+++ b/include/mcld/LD/Resolver.h
@@ -0,0 +1,100 @@
+//===- Resolver.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYMBOL_RESOLVER_H
+#define MCLD_SYMBOL_RESOLVER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <string>
+#include <utility>
+
+namespace mcld
+{
+
+class ResolveInfo;
+class StrSymPool;
+
+/** \class Resolver
+ * \brief Resolver binds a symbol reference from one file to a symbol
+ * definition of another file.
+ *
+ * Resolver seals up the algorithm of symbol resolution. The resolution of
+ * two symbols depends on their type, binding and whether it is belonging to
+ * a shared object.
+ */
+class Resolver
+{
+public:
+ enum Action {
+ Success,
+ Warning,
+ Abort,
+ LastAction
+ };
+
+ /** \class Resolver::Result
+ * \brief the result of symbol resolution
+ * - info, the pointer to overrided info
+ * - existent, if true, the info is existent
+ * - overriden, if true, the info is being overriden.
+ */
+ struct Result {
+ ResolveInfo* info;
+ bool existent;
+ bool overriden;
+ };
+
+public:
+ Resolver();
+
+ Resolver(const Resolver& pCopy);
+
+ virtual ~Resolver();
+
+ /// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
+ /// @return the action should be taken.
+ /// @param pOld the symbol which may be overridden.
+ /// @param pNew the symbol which is used to replace pOld
+ virtual unsigned int resolve(ResolveInfo & __restrict__ pOld,
+ const ResolveInfo & __restrict__ pNew,
+ bool &pOverride) = 0;
+
+ /// resolveAgain - Can override by derived classes.
+ /// @return the pointer to resolved ResolveInfo
+ /// @return is the symbol existent?
+ virtual void resolveAgain(StrSymPool& pStrSymPool,
+ unsigned int pAction,
+ ResolveInfo& __restrict__ pOld,
+ const ResolveInfo& __restrict__ pNew,
+ Result& pResult) {
+ pResult.info = NULL;
+ pResult.existent = false;
+ pResult.overriden = false;
+ }
+
+ const std::string& mesg() const
+ { return m_Mesg; }
+
+ void clearMesg();
+
+ Resolver* clone() const {
+ return doClone();
+ }
+
+protected:
+ std::string m_Mesg;
+
+private:
+ virtual Resolver* doClone() const = 0;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/SectionMap.h b/include/mcld/LD/SectionMap.h
new file mode 100644
index 0000000..424d785
--- /dev/null
+++ b/include/mcld/LD/SectionMap.h
@@ -0,0 +1,105 @@
+//===- SectionMap.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SECTION_MAP_H
+#define MCLD_SECTION_MAP_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/DataTypes.h>
+#include <vector>
+#include <string>
+
+namespace mcld
+{
+
+/** \class SectionMap
+ * \brief descirbe the mappings of input section's name (or prefix) to
+ * its associated output section's name and offset
+ */
+class SectionMap
+{
+public:
+ // a mapping in SectionMap is the triple of
+ // {input substr, output section's name, output section's offset}
+ struct Mapping {
+ std::string inputSubStr;
+ std::string outputStr;
+ uint64_t offset;
+ };
+
+ typedef std::vector<struct Mapping> SectionMappingTy;
+
+ typedef SectionMappingTy::iterator iterator;
+ typedef SectionMappingTy::const_iterator const_iterator;
+
+public:
+ SectionMap();
+ ~SectionMap();
+
+ // get the possible output section name based on the mapping table
+ // return NULL if not found
+ const std::string& getOutputSectName(const std::string& pInput);
+
+ // add a mapping from input substr to output name and offset.
+ bool push_back(const std::string& pInput,
+ const std::string& pOutput,
+ const uint64_t pOffset = 0);
+
+ // find - return the iterator to the mapping
+ iterator find(const std::string& pInput);
+
+ // at - return the pointer to the mapping
+ Mapping* at(const std::string& pInput);
+
+ // ----- observers ----- //
+ bool empty() const
+ { return m_SectMap.empty(); }
+
+ size_t size() const
+ { return m_SectMap.size(); }
+
+ size_t capacity () const
+ { return m_SectMap.capacity(); }
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return m_SectMap.begin(); }
+
+ iterator end()
+ { return m_SectMap.end(); }
+
+ const_iterator begin() const
+ { return m_SectMap.begin(); }
+
+ const_iterator end() const
+ { return m_SectMap.end(); }
+
+ // initStdSectionMap - add common mappings of ELF and other formats
+ // to SectionMap
+ bool initStdSectionMap();
+
+private:
+ struct SectionNameMapping {
+ const char* from;
+ const char* to;
+ };
+
+ // used to store common mappings of ELF and other formants
+ static const SectionNameMapping m_StdSectionMap[];
+
+ static const int m_StdSectionMapSize;
+
+ SectionMappingTy m_SectMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/SectionMerger.h b/include/mcld/LD/SectionMerger.h
new file mode 100644
index 0000000..40f1453
--- /dev/null
+++ b/include/mcld/LD/SectionMerger.h
@@ -0,0 +1,98 @@
+//===- SectionMerger.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SECTION_MERGER_H
+#define MCLD_SECTION_MERGER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+#include <string>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/SectionMap.h>
+
+namespace mcld
+{
+class MCLinker;
+
+/** \class SectionMerger
+ * \brief maintain the mappings of substr of input section name to associated
+ * output section (data)
+ */
+class SectionMerger
+{
+public:
+ struct Mapping {
+ std::string inputSubStr;
+ LDSection* outputSection;
+ };
+ typedef std::vector<Mapping> LDSectionMapTy;
+
+ typedef LDSectionMapTy::iterator iterator;
+ typedef LDSectionMapTy::const_iterator const_iterator;
+
+public:
+ SectionMerger(SectionMap& pSectionMap, LDContext& pContext);
+ ~SectionMerger();
+
+ /// getOutputSectHdr - return a associated output section header
+ LDSection* getOutputSectHdr(const std::string& pName);
+
+ /// getOutputSectData - return a associated output section data
+ llvm::MCSectionData* getOutputSectData(const std::string& pName);
+
+ /// addMapping - add a mapping as creating one new output LDSection
+ /// @param pName - a input section name
+ /// @param pSection - the output LDSection*
+ bool addMapping(const std::string& pName, LDSection* pSection);
+
+ // ----- observers ----- //
+ bool empty() const
+ { return m_LDSectionMap.empty(); }
+
+ size_t size() const
+ { return m_LDSectionMap.size(); }
+
+ size_t capacity () const
+ { return m_LDSectionMap.capacity(); }
+
+ // ----- iterators ----- //
+ iterator find(const std::string& pName);
+
+ iterator begin()
+ { return m_LDSectionMap.begin(); }
+
+ iterator end()
+ { return m_LDSectionMap.end(); }
+
+ const_iterator begin() const
+ { return m_LDSectionMap.begin(); }
+
+ const_iterator end() const
+ { return m_LDSectionMap.end(); }
+
+private:
+ /// initOutputSectMap - initialize the map from input substr to associated
+ /// output LDSection*
+ void initOutputSectMap();
+
+private:
+ SectionMap& m_SectionNameMap;
+
+ LDContext& m_Output;
+
+ LDSectionMapTy m_LDSectionMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/StaticResolver.h b/include/mcld/LD/StaticResolver.h
new file mode 100644
index 0000000..5bf5c5d
--- /dev/null
+++ b/include/mcld/LD/StaticResolver.h
@@ -0,0 +1,145 @@
+//===- StaticResolver.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_STATIC_SYMBOL_RESOLVER_H
+#define MCLD_STATIC_SYMBOL_RESOLVER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <string>
+#include <mcld/LD/Resolver.h>
+#include <mcld/LD/ResolveInfo.h>
+
+namespace mcld
+{
+
+class StrSymPool;
+
+/** \class StaticResolver
+ */
+class StaticResolver : public Resolver
+{
+public:
+ /** \enum LinkAction
+ * LinkAction follows BFD:linker.c (binary file descriptor).
+ * List all actions to take in the state table
+ */
+ enum LinkAction
+ {
+ FAIL, /* abort. */
+ NOACT, /* no action. */
+ UND, /* override by symbol undefined symbol. */
+ WEAK, /* override by symbol weak undefined. */
+ DEF, /* override by symbol defined. */
+ DEFW, /* override by symbol weak defined. */
+ DEFD, /* override by symbol dynamic defined. */
+ DEFWD, /* override by symbol dynamic weak defined. */
+ MDEFD, /* mark symbol dynamic defined. */
+ MDEFWD, /* mark symbol dynamic weak defined. */
+ DUND, /* override dynamic defined symbol by undefined one. */
+ DUNDW, /* oevrride dynamic defined symbol by weak undefined one. */
+ COM, /* override by symbol common. */
+ CREF, /* Possibly warn about common reference to defined symbol. */
+ CDEF, /* redefine existing common symbol. */
+ BIG, /* override by symbol common using largest size. */
+ MBIG, /* mark common symbol by larger size. */
+ IND, /* override by indirect symbol. */
+ CIND, /* mark indirect symbol from existing common symbol. */
+ MDEF, /* multiple definition error. */
+ MIND, /* multiple indirect symbols. */
+ REFC /* Mark indirect symbol referenced and then CYCLE. */
+ };
+
+private:
+ // These are the values generated by the bit codes.
+ /** Encoding:
+ * D -> define
+ * U -> undefine
+ * d -> dynamic
+ * w -> weak
+ * C -> common
+ * I -> indirect
+ */
+ enum
+ {
+ U = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::undefine_flag,
+ w_U = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::undefine_flag,
+ d_U = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::undefine_flag,
+ wd_U = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::undefine_flag,
+ D = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::define_flag,
+ w_D = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::define_flag,
+ d_D = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,
+ wd_D = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::define_flag,
+ C = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,
+ w_C = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::common_flag,
+ d_C = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,
+ wd_C = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::common_flag,
+ I = ResolveInfo::global_flag | ResolveInfo::regular_flag | ResolveInfo::indirect_flag,
+ w_I = ResolveInfo::weak_flag | ResolveInfo::regular_flag | ResolveInfo::indirect_flag,
+ d_I = ResolveInfo::global_flag | ResolveInfo::dynamic_flag | ResolveInfo::indirect_flag,
+ wd_I = ResolveInfo::weak_flag | ResolveInfo::dynamic_flag | ResolveInfo::indirect_flag
+ };
+
+ enum ORDINATE
+ {
+ U_ORD,
+ w_U_ORD,
+ d_U_ORD,
+ wd_U_ORD,
+ D_ORD,
+ w_D_ORD,
+ d_D_ORD,
+ wd_D_ORD,
+ C_ORD,
+ w_C_ORD,
+ Cs_ORD,
+ Is_ORD,
+ LAST_ORD
+ };
+
+public:
+ StaticResolver();
+
+ StaticResolver(const StaticResolver& pCopy);
+
+ virtual ~StaticResolver();
+
+ /// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
+ /// @return the action should be taken.
+ /// @param pOld the symbol which may be overridden.
+ /// @param pNew the symbol which is used to replace pOld
+ virtual unsigned int resolve(ResolveInfo & __restrict__ pOld,
+ const ResolveInfo & __restrict__ pNew,
+ bool &pOverride);
+
+ StaticResolver* doClone() const {
+ return new StaticResolver(*this);
+ }
+
+private:
+ inline unsigned int getOrdinate(const ResolveInfo& pInfo) const {
+ if (pInfo.isAbsolute() && pInfo.isDyn())
+ return d_D_ORD;
+ if (pInfo.isAbsolute())
+ return D_ORD;
+ if (pInfo.isCommon() && pInfo.isDyn())
+ return Cs_ORD;
+ if (pInfo.isCommon() && pInfo.isDefine())
+ return C_ORD;
+ if (pInfo.isCommon() && pInfo.isWeak())
+ return w_C_ORD;
+ if (pInfo.isIndirect())
+ return Is_ORD;
+ return pInfo.info();
+ }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/StrSymPool.h b/include/mcld/LD/StrSymPool.h
new file mode 100644
index 0000000..da5ed1f
--- /dev/null
+++ b/include/mcld/LD/StrSymPool.h
@@ -0,0 +1,111 @@
+//===- StrSymPool.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_STRING_SYMBOL_POOL_H
+#define MCLD_STRING_SYMBOL_POOL_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/StringRef.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/StringHash.h>
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/Resolver.h>
+#include <mcld/LD/ResolveInfoFactory.h>
+#include <utility>
+
+namespace llvm
+{
+ class MCSectionData;
+}
+
+namespace mcld
+{
+
+class Resolver;
+class StringTable;
+class SymbolTableIF;
+
+/** \class StrSymPool
+ * \brief Store symbol and search symbol by name. Can help symbol resolution.
+ *
+ * - MCLinker is responsed for creating StrSymPool.
+ */
+class StrSymPool : private Uncopyable
+{
+public:
+ typedef HashTable<ResolveInfo, StringHash<ELF>, ResolveInfoFactory> Table;
+ typedef size_t size_type;
+
+public:
+ StrSymPool(const Resolver& pResolver, size_type pSize = 3);
+ ~StrSymPool();
+
+ // ----- modifiers ----- //
+ /// createSymbol - create a symbol but do not insert into the pool.
+ ResolveInfo* createSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
+
+ /// insertSymbol - insert a symbol and resolve the symbol immediately
+ /// @param pOldInfo - if pOldInfo is not NULL, the old ResolveInfo being
+ /// overriden is kept in pOldInfo.
+ /// @param pResult the result of symbol resultion.
+ /// @note pResult.override is true if the output LDSymbol also need to be
+ /// overriden
+ void insertSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ ResolveInfo::Visibility pVisibility,
+ ResolveInfo* pOldInfo,
+ Resolver::Result& pResult);
+
+ /// findSymbol - find the resolved output LDSymbol
+ LDSymbol* findSymbol(const llvm::StringRef& pName);
+ const LDSymbol* findSymbol(const llvm::StringRef& pName) const;
+
+ /// findInfo - find the resolved ResolveInfo
+ ResolveInfo* findInfo(const llvm::StringRef& pName);
+ const ResolveInfo* findInfo(const llvm::StringRef& pName) const;
+
+ /// insertString - insert a string
+ /// if the string has existed, modify pString to the existing string
+ /// @return the StringRef points to the hash table
+ llvm::StringRef insertString(const llvm::StringRef& pString);
+
+ // ----- observers ----- //
+ size_type size() const
+ { return m_Table.numOfEntries(); }
+
+ bool empty() const
+ { return m_Table.empty(); }
+
+ // ----- capacity ----- //
+ void reserve(size_type pN);
+
+ size_type capacity() const;
+
+private:
+ Resolver* m_pResolver;
+ Table m_Table;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/StringUnorderedMap.h b/include/mcld/LD/StringUnorderedMap.h
new file mode 100644
index 0000000..05788aa
--- /dev/null
+++ b/include/mcld/LD/StringUnorderedMap.h
@@ -0,0 +1,225 @@
+//===- StringUnorderedMap.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SEARCH_TABLE_H
+#define MCLD_SEARCH_TABLE_H
+#include <vector>
+// For std::allocate.
+#include <memory>
+// For uint32_t.
+#include <stdint.h>
+#include <cassert>
+// For memset.
+#include <cstring>
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+/* FIXME: Move StringUnorderedMap under ADT. */
+
+namespace mcld
+{
+
+struct StringUnorderedMapDefaultHash
+{
+ size_t operator()(const char *pStr) {
+ size_t hashVal = 31;
+ while (*pStr)
+ hashVal = hashVal * 131 + (*pStr++);
+ return hashVal;
+ }
+};
+
+template<typename ValueType,
+ typename KeyType>
+struct StringUnorderedMapEntryInit
+{
+ template <typename InitType>
+ void operator()(KeyType &pKey, ValueType &pValue,
+ const KeyType &pStr, InitType pInitVal) {
+ ::new ((void*)&pKey) KeyStorageType(pStr);
+ ::new ((void*)&pValue) ValueType(pInitVal);
+ }
+};
+
+uint32_t findNextPrime(uint32_t x);
+
+/** \class StringUnorderedMap
+ * \brief The most simple hash of linked list version.
+ *
+ * \see
+ */
+template<typename KeyType,
+ typename ValueType,
+ typename KeyCompareFunctor,
+ typename HashFunction = StringUnorderedMapDefaultHash,
+ typename Allocator = std::allocator<std::pair<KeyType, ValueType> > >
+class StringUnorderedMap
+{
+public:
+ explicit StringUnorderedMap(size_t pCapacity = 17)
+ : m_Impl(pCapacity)
+ {}
+
+ ~StringUnorderedMap();
+
+ void reserve(size_t pCapacity);
+
+ ValueType &getOrCreate(const KeyType &pStr, const ValueType &pInitVal);
+
+ ValueType &getOrCreate(const KeyType &pStr);
+
+ bool empty()
+ { return m_Size == 0; }
+
+ size_t capacity() const
+ { return m_Capacity; }
+
+ void clear();
+
+private:
+ struct HashEntry {
+ size_t hashVal;
+ std::pair<KeyType, ValueType>
+ HashEntry *next;
+ };
+ typedef Allocator::template rebind<HashEntry>::other HashEntryAllocator;
+ void rehash(size_t pCapacity);
+
+private:
+ size_t m_Capacity;
+ size_t m_Size;
+ // array of pointers to hash entries
+ HashEntry **m_HashTable;
+ HashEntryAllocator m_HashEntryAllocator;
+};
+
+
+// =================================implementation============================
+// StringUnorderedMap::StringUnorderedMapImpl
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::StringUnorderedMapImpl(size_t pCapacity)
+ : m_Capacity(0), m_Size(0), m_HashTable(0)
+{
+ this->reserve(pCapacity);
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+void
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::reserve(size_t pCapacity)
+{
+ if (pCapacity < this->m_Capacity)
+ return;
+ size_t nextSize = findNextPrime(static_cast<uint32_t>(pCapacity));
+ // FIXME: Error handling.
+ assert(nextSize > this->m_Capacity && "findNextPrime error.");
+ if (this->m_Capacity != nextSize)
+ this->rehash(nextSize);
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+void
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::rehash(size_t pCapacity)
+{
+ HashEntry **tmpTable = new HashEntry*[pCapacity];
+ std::memset(tmpTable, 0, pCapacity * sizeof(HashEntry*));
+ if (this->m_HashTable) {
+ for (size_t i = 0; i < this->m_Capacity; ++i)
+ for (HashEntry *j = this->m_HashTable[i]; j != 0; ) {
+ HashEntry *nextJ = j->next;
+ j->next = tmpTable[j->hashVal % pCapacity];
+ tmpTable[j->hashVal % pCapacity] = j;
+ j = nextJ;
+ }
+ delete[] m_HashTable;
+ }
+ this->m_Capacity = pCapacity;
+ this->m_HashTable = tmpTable;
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+template<typename InitType>
+ValueType &
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::getOrCreate(const KeyType &pStr, ValueType &pInitVal)
+{
+ HashFunction hash;
+ size_t hashVal = hash(pStr);
+ HashEntry *&head = this->m_HashTable[hashVal % this->m_Capacity];
+
+ HashEntry *ans = 0;
+ for(HashEntry *ptr = head; ptr != 0; ptr = ptr->next)
+ if(hashVal == ptr->hashVal && pStr.equals(ptr->str)) {
+ ans = ptr;
+ break;
+ }
+ if (ans == 0) {
+ ans = this->allocate(1);
+ ans->hashVal = hashVal;
+ StringUnorderedMapEntryInit<ValueType, KeyStorageType> init;
+ init(ans->str, ans->value, pStr, pInitVal);
+ ans->next = head;
+ head = ans;
+ ++m_Size;
+ if(this->m_Size * 4LL >= this->m_Capacity * 3LL) // load factor = 0.75
+ this->reserve(this->m_Capacity+1);
+ }
+
+ return ans->value;
+}
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+void
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::clear()
+{
+ if (this->m_HashTable) {
+ for (size_t i = 0; i < this->m_Capacity; ++i)
+ for (HashEntry *j = this->m_HashTable[i]; j != 0; ) {
+ HashEntry *nextJ = j->next;
+ this->destroy(j);
+ this->deallocate(j, 1);
+ j = nextJ;
+ }
+ delete[] m_HashTable;
+ }
+}
+
+
+template<typename ValueType,
+ typename KeyStorageType,
+ typename HashFunction,
+ typename Allocator>
+StringUnorderedMap<ValueType, KeyStorageType, HashFunction, Allocator>::
+StringUnorderedMapImpl::~StringUnorderedMapImpl()
+{
+ this->clear();
+}
+
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/LD/SymbolTableFactory.h b/include/mcld/LD/SymbolTableFactory.h
new file mode 100644
index 0000000..cc02241
--- /dev/null
+++ b/include/mcld/LD/SymbolTableFactory.h
@@ -0,0 +1,73 @@
+//===- SymbolTableFactory.h -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYMBOL_TABLE_FACTORY_H
+#define MCLD_SYMBOL_TABLE_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/InputSymbolTable.h"
+#include "mcld/LD/OutputSymbolTable.h"
+
+namespace mcld
+{
+
+class StringTable;
+class StrSymPool;
+
+/** \class SymbolTableFactory
+ * \brief SymbolTableFactory manages SymbolTableIFs.
+ *
+ * SymbolTableFactory is responsed for construction and destruction of
+ * SymbolTableIF. Since different MCLDFiles have different type of
+ * SymbolTableIF, SymbolTableFactory separates the construction of
+ * SymbolTableIF into createInputTable() and createOutputTable().
+ *
+ * @see SymbolTableIF InputSymbolTable OutputSymbolTable
+ */
+class SymbolTableFactory
+{
+public:
+ /// SymbolTableFactory - constructor
+ // @param pNumOfSymbolTables is the most appropriate number of created
+ // symbol tables.
+ // @param pStorage the real storage of created symbols
+ explicit SymbolTableFactory(size_t pNumOfSymbolTables,
+ StrSymPool& pStrSymPool);
+ /// ~SymbolTableFactory - destructor
+ // destructor destroys all created symbol tables.
+ ~SymbolTableFactory();
+
+ /// createInputTable - create a symbol table for an input file
+ // @param pEntireStringTable the string table of created Symbols.
+ // @param pDynamicStringTable the string table of created Dynamic Symbols.
+ // @param pReserve Created symbol table must reserve pReserve number of
+ // storages of symbol for creating symbols.
+ SymbolTableIF *createInputTable(StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable,
+ size_t pReserve=256);
+
+ /// createOutputTable - create a symbol table for an output file
+ // @param pEntireStringTable the string table of created Symbols.
+ // @param pDynamicStringTable the string table of created Dynamic Symbols.
+ // @param pReserve Created symbol table must reserve pReserve number of
+ // storages of symbol for creating symbols.
+ SymbolTableIF *createOutputTable(StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable,
+ size_t pReserve=256);
+private:
+ StrSymPool &m_StrSymPool;
+ GCFactory<InputSymbolTable, 0> m_InputFactory;
+ GCFactory<OutputSymbolTable, 0> m_OutputFactory;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/AttributeFactory.h b/include/mcld/MC/AttributeFactory.h
new file mode 100644
index 0000000..eb4368b
--- /dev/null
+++ b/include/mcld/MC/AttributeFactory.h
@@ -0,0 +1,99 @@
+//===- AttributeFactory.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ATTRIBUTE_FACTORY_H
+#define MCLD_ATTRIBUTE_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/MC/MCLDAttribute.h"
+
+namespace mcld
+{
+
+/** \class AttributeFactory
+ * \brief AttributeFactory contructs the AttributeProxys.
+ *
+ * Since the number of AttributeProxys is usually small, sequential search
+ * on a small vector is enough.
+ */
+class AttributeFactory : private Uncopyable
+{
+private:
+ typedef std::vector<Attribute*> AttrSet;
+
+public:
+ typedef AttrSet::iterator iterator;
+ typedef AttrSet::const_iterator const_iterator;
+
+public:
+ AttributeFactory();
+ explicit AttributeFactory(size_t pNum);
+ ~AttributeFactory();
+
+ // reserve - reserve the memory space for attributes
+ // @param pNum the number of reserved attributes
+ void reserve(size_t pNum);
+
+ // predefined - return the predefined attribute
+ Attribute& predefined();
+ const Attribute& predefined() const;
+
+ // constraint - return the constraint of attributes
+ AttrConstraint& constraint()
+ { return m_Constraint; }
+
+ const AttrConstraint& constraint() const
+ { return m_Constraint; }
+
+ // produce - produce a attribute, but do not record it yet.
+ // the produced attribute is identical to the pre-defined attribute.
+ AttributeProxy* produce();
+
+ // last - the last touched attribute.
+ AttributeProxy& last();
+ const AttributeProxy& last() const;
+
+ // exists- return the recorded attribute whose content is identical to the
+ // input attribute.
+ Attribute *exists(const Attribute& pAttr) const;
+
+ // record - record the attribute no mater if it has been recorded.
+ void record(Attribute& pAttr);
+
+ // ----- observers ----- //
+ size_t size() const
+ { return m_AttrSet.size(); }
+
+ bool empty() const
+ { return m_AttrSet.empty(); }
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return m_AttrSet.begin(); }
+
+ iterator end()
+ { return m_AttrSet.end(); }
+
+ const_iterator begin() const
+ { return m_AttrSet.begin(); }
+
+ const_iterator end() const
+ { return m_AttrSet.end(); }
+
+private:
+ AttrSet m_AttrSet;
+ AttrConstraint m_Constraint;
+ AttributeProxy *m_pLast;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/ContextFactory.h b/include/mcld/MC/ContextFactory.h
new file mode 100644
index 0000000..1ae0d45
--- /dev/null
+++ b/include/mcld/MC/ContextFactory.h
@@ -0,0 +1,47 @@
+//===- ContextFactory.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_CONTEXT_FACTORY_H
+#define MCLD_CONTEXT_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/LDContext.h>
+#include <mcld/Support/UniqueGCFactory.h>
+#include <mcld/Support/Path.h>
+
+namespace mcld
+{
+/** \class ContextFactory
+ * \brief ContextFactory avoids the duplicated LDContext of the same file.
+ *
+ * MCLinker is designed for efficient memory usage. Because user can give
+ * MCLinker the same input file many times on the command line, MCLinker must
+ * avoid opening identical file twice.
+ *
+ * ContextFactory is the guard to prevent redundant opening. MCLinker does not
+ * create LDContext directly. Instead, it creates LDContext by ContextFactory.
+ * ContextFactory returns the identical reference of LDContext if it's openend.
+ *
+ * @see LDContext
+ * @see UniqueGCFactoryBase
+ */
+class ContextFactory : public UniqueGCFactoryBase<sys::fs::Path, LDContext, 0>
+{
+public:
+ explicit ContextFactory(size_t pNum);
+ ~ContextFactory();
+
+ LDContext* produce(const sys::fs::Path& pPath);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/InputFactory.h b/include/mcld/MC/InputFactory.h
new file mode 100644
index 0000000..5dc99c4
--- /dev/null
+++ b/include/mcld/MC/InputFactory.h
@@ -0,0 +1,56 @@
+//===- InputFactory.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_INPUT_FACTORY_H
+#define MCLD_INPUT_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/GCFactory.h"
+#include "mcld/MC/MCLDInput.h"
+
+namespace mcld
+{
+
+class AttributeFactory;
+
+/** \class InputFactory
+ * \brief InputFactory controls the production and destruction of
+ * MCLDInput.
+ *
+ * All MCLDFiles created by MCLDFileFactory are guaranteed to be destructed
+ * while MCLDFileFactory is destructed.
+ *
+ * FIXME: the number of the Inputs should be passed in by Target or any
+ * target specific class.
+ *
+ * \see llvm::sys::Path
+ */
+class InputFactory : public GCFactory<Input,0>
+{
+public:
+ typedef GCFactory<Input, 0> Alloc;
+
+public:
+ InputFactory(size_t pNum, AttributeFactory& pAttrFactory);
+ ~InputFactory();
+
+ // ----- production ----- //
+ Input* produce(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Input::Unknown,
+ off_t pFileOffset = 0);
+
+private:
+ AttributeFactory &m_AttrFactory;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCBitcodeInterceptor.h b/include/mcld/MC/MCBitcodeInterceptor.h
new file mode 100644
index 0000000..182b157
--- /dev/null
+++ b/include/mcld/MC/MCBitcodeInterceptor.h
@@ -0,0 +1,75 @@
+//===- MCBitcodeInterceptor.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_BITCODE_INTERCEPTOR_H
+#define MCLD_BITCODE_INTERCEPTOR_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCObjectWriter.h>
+
+
+namespace llvm
+{
+ class MCStreamer;
+ class MCObjectStreamer;
+ class MCAsmLayout;
+ class MCAssembler;
+ class MCFixup;
+ class MCFragment;
+ class MCSymbol;
+ class MCSymbolData;
+ class MCSymbolRefExpr;
+ class MCValue;
+ class raw_ostream;
+} // namespace of llvm
+
+namespace mcld
+{
+
+class MCLDInfo;
+class TargetLDBackend;
+
+/** \class MCBitcodeInterceptor
+ * \brief MCBitcodeInterceptor converts bitcode into LDContext
+ *
+ * @see LDContext
+ * @see MCObjectWriter
+ */
+class MCBitcodeInterceptor : public llvm::MCObjectWriter
+{
+public:
+ MCBitcodeInterceptor(llvm::MCObjectStreamer&, TargetLDBackend&, MCLDInfo&);
+ ~MCBitcodeInterceptor();
+
+ void ExecutePostLayoutBinding(llvm::MCAssembler &Asm,
+ const llvm::MCAsmLayout &Layout);
+
+ /// RecordRelocation - record relocations
+ // make a LDRelocation and recordds in the LDContext.
+ void RecordRelocation(const llvm::MCAssembler &Asm,
+ const llvm::MCAsmLayout &Layout,
+ const llvm::MCFragment *Fragment,
+ const llvm::MCFixup &Fixup,
+ llvm::MCValue Target,
+ uint64_t &FixedValue);
+
+ /// WriteObject - not really write out a object. Instead, load data to
+ /// LDContext
+ void WriteObject(llvm::MCAssembler &Asm, const llvm::MCAsmLayout &Layout);
+
+private:
+ TargetLDBackend& m_Backend;
+ MCLDInfo& m_LDInfo;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCDataFragment.h b/include/mcld/MC/MCDataFragment.h
new file mode 100644
index 0000000..330c9be
--- /dev/null
+++ b/include/mcld/MC/MCDataFragment.h
@@ -0,0 +1,85 @@
+//===- MCDataFragment.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCDATAFRAGMENT_H
+#define MCDATAFRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/MC/MCInst.h>
+#include <llvm/ADT/SmallString.h>
+#include "mcld/LD/Relocation.h"
+
+namespace mcld
+{
+
+/** \class MCDataFragment
+ * \brief MCDataFragment for mcld
+ *
+ * \see
+ * \author Diana Chen <diana.chen@mediatek.com>
+ */
+class MCDataFragment : public llvm::MCFragment
+{
+public:
+ typedef std::vector<Relocation*> RelocationsType;
+private:
+
+ /// m_pFragment - llvm MCDataFragment for this MCDataFragment
+ llvm::MCDataFragment* m_pFragment;
+
+ /// m_Relocation - The list of relocations in this fragment
+ RelocationsType m_Relocations;
+
+public:
+ typedef RelocationsType::const_iterator const_relocation_iterator;
+ typedef RelocationsType::iterator relocation_iterator;
+
+public:
+ MCDataFragment(llvm::MCDataFragment& pFragment)
+ : m_pFragment(&pFragment) {
+ setParent( pFragment.getParent() );
+ setAtom( pFragment.getAtom() );
+ setLayoutOrder( pFragment.getLayoutOrder());
+ }
+ ~MCDataFragment(){}
+
+ // ------ observers ------//
+ llvm::SmallString<32> &getContents() { return m_pFragment->getContents(); }
+ const llvm::SmallString<32> &getContents() const { return m_pFragment->getContents(); }
+
+ // relocation access
+ void addRelocation(Relocation &pReloc){ m_Relocations.push_back(&pReloc); }
+
+ RelocationsType &getRelocations() { return m_Relocations; }
+ const RelocationsType &getRelcoations() const { return m_Relocations; }
+
+ relocation_iterator relocation_begin() { return m_Relocations.begin(); }
+ const_relocation_iterator relocation_begin() const { return m_Relocations.begin(); }
+
+ relocation_iterator relocation_end() {return m_Relocations.end();}
+ const_relocation_iterator relocation_end() const {return m_Relocations.end();}
+
+ size_t relocations_size() const { return m_Relocations.size(); }
+
+ // fragment identification
+ static bool classof(const MCFragment *pF) {
+ return pF->getKind() == llvm::MCFragment::FT_Data;
+ }
+ static bool classof(const MCDataFragment *) { return true; }
+
+ // overwrite parent method
+ FragmentType getKind() const { return m_pFragment->getKind(); }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCFragmentRef.h b/include/mcld/MC/MCFragmentRef.h
new file mode 100644
index 0000000..b7d94cd
--- /dev/null
+++ b/include/mcld/MC/MCFragmentRef.h
@@ -0,0 +1,85 @@
+//===- MCFragmentRef.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MCFRAGMENT_REFERENCE_H
+#define MCLD_MCFRAGMENT_REFERENCE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/ADT/TypeTraits.h>
+
+namespace mcld
+{
+
+class Layout;
+
+/// compunteFragmentSize - compute the specific MCFragment size
+uint64_t computeFragmentSize(const Layout& pLayout,
+ const llvm::MCFragment& pFrag);
+
+/** \class MCFragmentRef
+ * \brief MCFragmentRef is a reference of a MCFragment's contetnt.
+ *
+ */
+class MCFragmentRef
+{
+public:
+ typedef uint64_t Offset; // FIXME: use SizeTraits<T>::Offset
+ typedef NonConstTraits<unsigned char>::pointer Address;
+ typedef ConstTraits<unsigned char>::pointer ConstAddress;
+
+public:
+ MCFragmentRef();
+ MCFragmentRef(llvm::MCFragment& pFrag, Offset pOffset = 0);
+ ~MCFragmentRef();
+
+ // ----- modifiers ----- //
+ MCFragmentRef& assign(const MCFragmentRef& pCopy);
+
+ MCFragmentRef& assign(llvm::MCFragment& pFrag, Offset pOffset = 0);
+
+ /// memcpy - copy memory
+ /// copy memory from the fragment to the pDesc.
+ /// @pDest - the destination address
+ /// @pNBytes - copies pNBytes from the fragment[offset()+pOffset]
+ /// @pOffset - additional offset.
+ /// the start address offset from fragment[offset()]
+ void memcpy(void* pDest, size_t pNBytes, Offset pOffset = 0) const;
+
+ // ----- observers ----- //
+ llvm::MCFragment* frag()
+ { return m_pFragment; }
+
+ const llvm::MCFragment* frag() const
+ { return m_pFragment; }
+
+ Offset offset() const
+ { return m_Offset; }
+
+ // ----- dereference ----- //
+ Address deref();
+
+ ConstAddress deref() const;
+
+ Address operator*()
+ { return deref(); }
+
+ ConstAddress operator*() const
+ { return deref(); }
+
+private:
+ llvm::MCFragment* m_pFragment;
+ Offset m_Offset;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCInstFragment.h b/include/mcld/MC/MCInstFragment.h
new file mode 100644
index 0000000..8625c42
--- /dev/null
+++ b/include/mcld/MC/MCInstFragment.h
@@ -0,0 +1,95 @@
+//===- MCInstFragment.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCINSTFRAGMENT_H
+#define MCINSTFRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/MC/MCInst.h>
+#include <llvm/ADT/SmallString.h>
+#include <llvm/ADT/ilist.h>
+#include "mcld/LD/Relocation.h"
+
+
+namespace mcld
+{
+
+/** \class MCInstFragment
+ * \brief MCInstFragment for mcld
+ *
+ * \see
+ * \author Diana Chen <diana.chen@mediatek.com>
+ */
+class MCInstFragment : public llvm::MCFragment
+{
+public:
+ typedef std::vector<Relocation*> RelocationsType;
+private:
+
+ /// m_pFragment - llvm MCInstFragment for this MCInstFragment
+ llvm::MCInstFragment* m_pFragment;
+
+ /// m_Relocation - The list of relocations in this fragment
+ RelocationsType m_Relocations;
+
+public:
+ typedef RelocationsType::const_iterator const_relocation_iterator;
+ typedef RelocationsType::iterator relocation_iterator;
+
+public:
+ MCInstFragment( llvm::MCInstFragment& pFragment )
+ : m_pFragment(&pFragment){
+ setParent( pFragment.getParent() );
+ setAtom( pFragment.getAtom() );
+ setLayoutOrder( pFragment.getLayoutOrder());
+ }
+ ~MCInstFragment(){}
+
+ // ------ observers ------//
+ llvm::SmallVectorImpl<char> &getCode() { return m_pFragment->getCode(); }
+ const llvm::SmallVectorImpl<char> &getCode() const { return m_pFragment->getCode(); }
+
+ unsigned getInstSize() const { return m_pFragment->getCode().size(); }
+
+ llvm::MCInst &getInst() { return m_pFragment->getInst(); }
+ const llvm::MCInst &getInst() const { return m_pFragment->getInst(); }
+
+ // ----- modifiers ------//
+ void setInst(llvm::MCInst pValue) { m_pFragment->setInst(pValue); }
+
+ // relocation access
+ void addRelocation(Relocation &pReloc){ m_Relocations.push_back(&pReloc); }
+
+ RelocationsType &getRelocations() { return m_Relocations; }
+ const RelocationsType &getRelcoations() const { return m_Relocations; }
+
+ relocation_iterator relocation_begin() { return m_Relocations.begin(); }
+ const_relocation_iterator relocation_begin() const { return m_Relocations.begin(); }
+
+ relocation_iterator relocation_end() {return m_Relocations.end();}
+ const_relocation_iterator relocation_end() const {return m_Relocations.end();}
+
+ size_t relocations_size() const { return m_Relocations.size(); }
+
+ // fragment identification
+ static bool classof(const MCFragment *pF) {
+ return pF->getKind() == llvm::MCFragment::FT_Inst;
+ }
+ static bool classof(const MCInstFragment *) { return true; }
+
+ // overwrite parent method
+ FragmentType getKind() const { return m_pFragment->getKind(); }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDAttribute.h b/include/mcld/MC/MCLDAttribute.h
new file mode 100644
index 0000000..829cf61
--- /dev/null
+++ b/include/mcld/MC/MCLDAttribute.h
@@ -0,0 +1,247 @@
+//===- MCLDAttribute.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ATTRIBUTE_H
+#define MCLD_ATTRIBUTE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <vector>
+#include <string>
+
+namespace mcld
+{
+class AttributeFactory;
+
+/** \class AttributeBase
+ * \brief AttributeBase provides the real storage for attributes of options.
+ *
+ * Attributes are options affecting the link editing of input files.
+ * Some options affects the input files mentioned on the command line after
+ * them. For example, --whole-archive option affects archives mentioned on
+ * the command line after the --whole-archve option. We call such options
+ * "attributes of input files"
+ *
+ * AttributeBase is the storage for attributes of input files. Each input
+ * file (@see mcld::Input in MCLinker) has a pointer of an attribute. Since
+ * most attributes of input files are identical, our design lets input files
+ * which have identical attributes share common attribute. AttributeBase is
+ * the shared storage for attribute.
+ */
+class AttributeBase
+{
+public:
+ AttributeBase()
+ : m_WholeArchive(false),
+ m_AsNeeded(false),
+ m_AddNeeded(true),
+ m_Static(false)
+ { }
+
+ AttributeBase(const AttributeBase& pBase)
+ : m_WholeArchive(pBase.m_WholeArchive),
+ m_AsNeeded(pBase.m_AsNeeded),
+ m_AddNeeded(pBase.m_AddNeeded),
+ m_Static(pBase.m_Static)
+ { }
+
+ virtual ~AttributeBase()
+ { }
+
+ // ----- observers ----- //
+ // represent GNU ld --whole-archive/--no-whole-archive options
+ bool isWholeArchive() const
+ { return m_WholeArchive; }
+
+ // represent GNU ld --as-needed/--no-as-needed options
+ bool isAsNeeded() const
+ { return m_AsNeeded; }
+
+ // represent GNU ld --add-needed/--no-add-needed options
+ bool isAddNeeded() const
+ { return m_AddNeeded; }
+
+ // represent GNU ld -static option
+ bool isStatic() const
+ { return m_Static; }
+
+ // represent GNU ld -call_shared option
+ bool isDynamic() const
+ { return !m_Static; }
+public:
+ bool m_WholeArchive : 1;
+ bool m_AsNeeded : 1;
+ bool m_AddNeeded : 1;
+ bool m_Static : 1;
+};
+
+/** \class Attribute
+ * \brief The base class of attributes. Providing the raw operations of an
+ * attributes
+ *
+ * For conventience and producing less bugs, we move the stoarges of attributes
+ * onto AttributeBase, and modifiers remains with the class Attribute.
+ */
+class Attribute : public AttributeBase
+{
+public:
+ // ----- modifiers ----- //
+ void setWholeArchive()
+ { m_WholeArchive = true; }
+
+ void unsetWholeArchive()
+ { m_WholeArchive = false; }
+
+ void setAsNeeded()
+ { m_AsNeeded = true; }
+
+ void unsetAsNeeded()
+ { m_AsNeeded = false; }
+
+ void setAddNeeded()
+ { m_AddNeeded = true; }
+
+ void unsetAddNeeded()
+ { m_AddNeeded = false; }
+
+ void setStatic()
+ { m_Static = true; }
+
+ void setDynamic()
+ { m_Static = false; }
+};
+
+/** \class AttrConstraint
+ * \brief AttrConstarint is the constraint of a system.
+ *
+ * Some systems can not enable certain attributes of a input file.
+ * For example, systems which have no shared libraries can not enable
+ * --call_shared options. We call the ability of enabling attributes
+ * as the constraint of attributes of a system.
+ *
+ * Systems enable attributes at the target implementation of SectLinker.
+ *
+ * @see SectLinker
+ */
+class AttrConstraint : public AttributeBase
+{
+public:
+ void enableWholeArchive()
+ { m_WholeArchive = true; }
+
+ void disableWholeArchive()
+ { m_WholeArchive = false; }
+
+ void enableAsNeeded()
+ { m_AsNeeded = true; }
+
+ void disableAsNeeded()
+ { m_AsNeeded = false; }
+
+ void enableAddNeeded()
+ { m_AddNeeded = true; }
+
+ void disableAddNeeded()
+ { m_AddNeeded = false; }
+
+ void setSharedSystem()
+ { m_Static = false; }
+
+ void setStaticSystem()
+ { m_Static = true; }
+
+ bool isSharedSystem() const
+ { return !m_Static; }
+
+ bool isStaticSystem() const
+ { return m_Static; }
+
+ bool isLegal(const Attribute& pAttr, std::string& pErrMesg) const;
+};
+
+/** \class AttributeProxy
+ * \brief AttributeProxys is the illusion of private attribute of each
+ * input file.
+ *
+ * We designers want to hide the details of sharing common attributes
+ * between input files. We want input files under the illusion that they
+ * have their own private attributes to simplify the linking algorithms.
+ *
+ * AttributeProxy hides the reality of sharing. An input file can change
+ * its attribute without explicit searching of existing attributes
+ * as it has a private ownership of the attribute. AttributeProxy does
+ * the searching in the AttributeFactory and changes the pointer of
+ * the attribute of the input file. If the searching fails, AttributeProxy
+ * requests a new attribute from the AttributeFactory.
+ */
+class AttributeProxy
+{
+private:
+ friend class AttributeFactory;
+
+ explicit AttributeProxy(AttributeFactory& pParent, Attribute& pBase);
+ ~AttributeProxy();
+
+public:
+ // ----- observers ----- //
+ bool isWholeArchive() const;
+
+ bool isAsNeeded() const;
+
+ bool isAddNeeded() const;
+
+ bool isStatic() const;
+
+ bool isDynamic() const;
+
+ Attribute* attr()
+ { return m_pBase; }
+
+ const Attribute* attr() const
+ { return m_pBase; }
+
+ // ----- modifiers ----- //
+ void setWholeArchive();
+ void unsetWholeArchive();
+ void setAsNeeded();
+ void unsetAsNeeded();
+ void setAddNeeded();
+ void unsetAddNeeded();
+ void setStatic();
+ void setDynamic();
+
+private:
+ AttributeProxy* clone() const;
+
+ void change(Attribute* pBase)
+ { m_pBase = pBase; }
+
+private:
+ AttributeFactory &m_AttrPool;
+ Attribute *m_pBase;
+};
+
+
+// ----- comparisons ----- //
+inline bool operator== (const Attribute& pLHS, const Attribute& pRHS)
+{
+ return ((pLHS.isWholeArchive() == pRHS.isWholeArchive()) &&
+ (pLHS.isAsNeeded() == pRHS.isAsNeeded()) &&
+ (pLHS.isAddNeeded() == pRHS.isAddNeeded()) &&
+ (pLHS.isStatic() == pRHS.isStatic()));
+}
+
+inline bool operator!= (const Attribute& pLHS, const Attribute& pRHS)
+{
+ return !(pLHS == pRHS);
+}
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDDirectory.h b/include/mcld/MC/MCLDDirectory.h
new file mode 100644
index 0000000..988f9d3
--- /dev/null
+++ b/include/mcld/MC/MCLDDirectory.h
@@ -0,0 +1,53 @@
+//===- MCLDDirectory.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MCLDDIRECTORY_H
+#define MCLD_MCLDDIRECTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/Directory.h"
+#include "mcld/Support/FileSystem.h"
+#include <llvm/ADT/StringRef.h>
+#include <string>
+
+namespace mcld
+{
+
+/** \class MCLDDirectory
+ * \brief MCLDDirectory is an directory entry for library search.
+ *
+ */
+class MCLDDirectory : public sys::fs::Directory
+{
+public:
+ MCLDDirectory();
+ MCLDDirectory(const char* pName);
+ MCLDDirectory(const std::string& pName);
+ MCLDDirectory(llvm::StringRef pName);
+ virtual ~MCLDDirectory();
+
+public:
+ MCLDDirectory &assign(llvm::StringRef pName);
+ bool isInSysroot() const;
+
+ /// setSysroot - if MCLDDirectory is in sysroot, modify the path.
+ void setSysroot(const sys::fs::Path& pPath);
+
+ const std::string& name() const
+ { return m_Name; }
+
+private:
+ std::string m_Name;
+ bool m_bInSysroot;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDDriver.h b/include/mcld/MC/MCLDDriver.h
new file mode 100644
index 0000000..b4a7288
--- /dev/null
+++ b/include/mcld/MC/MCLDDriver.h
@@ -0,0 +1,117 @@
+//===- MCLDDriver.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// MCLDDriver plays the same role as GNU collect2 to prepare all implicit
+// parameters for MCLinker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LDDRIVER_H
+#define MCLD_LDDRIVER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/SectionMap.h>
+namespace mcld
+{
+
+class MCLinker;
+class MCLDInfo;
+class TargetLDBackend;
+
+//===----------------------------------------------------------------------===//
+/// MCLDDriver - MCLDDriver prepares parameters for MCLinker.
+///
+class MCLDDriver
+{
+public:
+ MCLDDriver(MCLDInfo& pLDInfo, TargetLDBackend& pLDBackend);
+ ~MCLDDriver();
+
+ /// normalize - normalize the input files
+ void normalize();
+
+ /// linkable - check the linkability of current MCLDInfo
+ /// Check list:
+ /// - check the Attributes are not violate the constaint
+ /// - check every Input has a correct Attribute
+ bool linkable() const;
+
+ /// initMCLinker - initialize MCLinker
+ /// Connect all components in MCLinker
+ bool initMCLinker();
+
+ /// readSections - read all input section headers
+ bool readSections();
+
+ /// mergeSections - put allinput sections into output sections
+ bool mergeSections();
+
+ /// readSymbolTables - read symbol tables from the input files.
+ /// for each input file, loads its symbol table from file.
+ bool readSymbolTables();
+
+ /// mergeSymbolTables - merge the symbol tables of input files into the
+ /// output's symbol table.
+ bool mergeSymbolTables();
+
+ /// addStandardSymbols - shared object and executable files need some
+ /// standard symbols
+ /// @return if there are some input symbols with the same name to the
+ /// standard symbols, return false
+ bool addStandardSymbols();
+
+ /// addTargetSymbols - some targets, such as MIPS and ARM, need some
+ /// target-dependent symbols
+ /// @return if there are some input symbols with the same name to the
+ /// target symbols, return false
+ bool addTargetSymbols();
+
+ /// readRelocations - read all relocation entries
+ bool readRelocations();
+
+ /// prelayout - help backend to do some modification before layout
+ bool prelayout();
+
+ /// layout - linearly layout all output sections and reserve some space
+ /// for GOT/PLT
+ /// Because we do not support instruction relaxing in this early version,
+ /// if there is a branch can not jump to its target, we return false
+ /// directly
+ bool layout();
+
+ /// postlayout - help backend to do some modification after layout
+ bool postlayout();
+
+ /// relocate - applying relocation entries and create relocation
+ /// section in the output files
+ /// Create relocation section, asking TargetLDBackend to
+ /// read the relocation information into RelocationEntry
+ /// and push_back into the relocation section
+ bool relocate();
+
+ /// finalizeSymbolValue - finalize the symbol value
+ bool finalizeSymbolValue();
+
+ /// emitOutput - emit the output file.
+ bool emitOutput();
+
+ /// postProcessing - do modificatiion after all processes
+ bool postProcessing();
+
+private:
+ MCLDInfo& m_LDInfo;
+ TargetLDBackend &m_LDBackend;
+ MCLinker* m_pLinker;
+ SectionMap m_SectionMap;
+};
+
+} // end namespace mcld
+#endif
diff --git a/include/mcld/MC/MCLDFile.h b/include/mcld/MC/MCLDFile.h
new file mode 100644
index 0000000..30cac7e
--- /dev/null
+++ b/include/mcld/MC/MCLDFile.h
@@ -0,0 +1,173 @@
+//===- MCLDFile.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// MCLDFile represents a file, the content of the file is stored in LDContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LDFILE_H
+#define MCLD_LDFILE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/LD/LDContext.h"
+#include "mcld/Support/Path.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/GCFactory.h"
+#include "mcld/Support/MemoryArea.h"
+#include <llvm/ADT/StringRef.h>
+#include <string>
+#include <sys/stat.h>
+
+
+namespace mcld
+{
+class MemoryArea;
+
+/** \class MCLDFile
+ * \brief MCLDFile represents the file being linked or produced.
+ *
+ * MCLDFile is the storage of name, path and type
+ * A MCLDFile just refers to LDContext, not owns it.
+ *
+ * @see mcld::sys::fs::Path LDContext
+ */
+class MCLDFile : private Uncopyable
+{
+public:
+ enum Type {
+ Unknown,
+ Object,
+ Exec,
+ DynObj,
+ CoreFile,
+ Script,
+ Archive
+ };
+
+public:
+ MCLDFile();
+ MCLDFile(llvm::StringRef pName);
+ MCLDFile(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Unknown);
+
+ virtual ~MCLDFile();
+
+ // ----- modifiers ----- //
+ void setType(unsigned int pType)
+ { m_Type = pType; }
+
+ void setContext(LDContext* pContext)
+ { m_pContext = pContext; }
+
+ void setPath(const sys::fs::Path& pPath)
+ { m_Path = pPath; }
+
+ void setMemArea(MemoryArea* pMemArea)
+ {
+ m_pMemArea = pMemArea;
+ }
+
+ /// setSOName - set the name of the shared object.
+ /// In ELF, this will be written in DT_SONAME
+ void setSOName(const std::string& pName);
+
+ // ----- observers ----- //
+ unsigned int type() const
+ { return m_Type; }
+
+ const std::string& name() const
+ { return m_Name; }
+
+ const sys::fs::Path& path() const
+ { return m_Path; }
+
+ bool hasContext() const
+ { return (0 != m_pContext); }
+
+ LDContext* context()
+ { return m_pContext; }
+
+ const LDContext* context() const
+ { return m_pContext; }
+
+ bool hasMemArea() const
+ { return (0 != m_pMemArea); }
+
+ MemoryArea* memArea()
+ { return m_pMemArea; }
+
+ const MemoryArea* memArea() const
+ { return m_pMemArea; }
+
+protected:
+ unsigned int m_Type;
+ LDContext *m_pContext;
+ sys::fs::Path m_Path;
+ std::string m_Name;
+ MemoryArea* m_pMemArea;
+};
+
+/** \class MCLDFileFactory
+ * \brief MCLDFileFactory controls the production and destruction of
+ * MCLDFiles.
+ *
+ * All MCLDFiles created by MCLDFileFactory are guaranteed to be destructed
+ * while MCLDFileFactory is destructed.
+ *
+ * MCLDFileFactory also provides the MCLCContextFactory to MCLDFile.
+ * MCLDFile is responsed for the life of LDContext, therefore, the best
+ * idea is let MCLDFile control the life of LDContext. Since SectLinker
+ * has the need to count the number of LDContext, we give a central factory
+ * for LDContext.
+ *
+ * \see llvm::sys::Path
+ */
+template<size_t NUM>
+class MCLDFileFactory : public GCFactory<MCLDFile, NUM>
+{
+public:
+ typedef GCFactory<MCLDFile, NUM> Alloc;
+
+public:
+ // ----- production ----- //
+ MCLDFile* produce(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType = MCLDFile::Unknown);
+
+ MCLDFile* produce();
+};
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// MCLDFileFactory
+template<size_t NUM>
+mcld::MCLDFile* mcld::MCLDFileFactory<NUM>::produce(llvm::StringRef pName,
+ const mcld::sys::fs::Path& pPath,
+ unsigned int pType)
+{
+ mcld::MCLDFile* result = Alloc::allocate();
+ new (result) mcld::MCLDFile(pName, pPath, pType);
+ return result;
+}
+
+template<size_t NUM>
+mcld::MCLDFile* mcld::MCLDFileFactory<NUM>::produce()
+{
+ mcld::MCLDFile* result = Alloc::allocate();
+ new (result) mcld::MCLDFile();
+ return result;
+}
+
+#endif
+
diff --git a/include/mcld/MC/MCLDInfo.h b/include/mcld/MC/MCLDInfo.h
new file mode 100644
index 0000000..15e70ff
--- /dev/null
+++ b/include/mcld/MC/MCLDInfo.h
@@ -0,0 +1,138 @@
+//===- MCLDInfo.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LDINFO_H
+#define MCLD_LDINFO_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/Triple.h>
+
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLDOptions.h>
+#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/AttributeFactory.h>
+#include <mcld/MC/ContextFactory.h>
+#include <mcld/LD/StrSymPool.h>
+
+#include <string>
+#include <cassert>
+
+namespace mcld
+{
+
+/** \class MCLDInfo
+ * \brief MCLDInfo is composed of argumments of MCLinker.
+ * options() - the general options.
+ * inputs() - the tree of inputs
+ * bitcode() - the bitcode being linked
+ * output() - the output file
+ * inputFactory() - the list of all inputs
+ * attrFactory() - the list of all attributes
+ * contextFactory() - the list of all contexts.
+ * memAreaFactory() - the list of all MemoryAreas.
+ */
+class MCLDInfo
+{
+public:
+ explicit MCLDInfo(const std::string &pTripleString,
+ size_t pAttrNum,
+ size_t InputSize);
+
+ virtual ~MCLDInfo();
+
+ GeneralOptions& options()
+ { return m_Options; }
+
+ const GeneralOptions& options() const
+ { return m_Options; }
+
+ void setBitcode(const Input& pInput);
+ Input& bitcode();
+ const Input& bitcode() const;
+
+ Output& output()
+ { return *m_pOutput; }
+
+ const Output& output() const
+ { return *m_pOutput; }
+
+ InputTree& inputs()
+ { return *m_pInputTree; }
+
+ const InputTree& inputs() const
+ { return *m_pInputTree; }
+
+ InputFactory& inputFactory()
+ { return *m_pInputFactory; }
+
+ const InputFactory& inputFactory() const
+ { return *m_pInputFactory; }
+
+ AttributeFactory& attrFactory()
+ { return *m_pAttrFactory; }
+
+
+ const AttributeFactory& attrFactory() const
+ { return *m_pAttrFactory; }
+
+ ContextFactory& contextFactory()
+ { return *m_pCntxtFactory; }
+
+ const ContextFactory& contextFactory() const
+ { return *m_pCntxtFactory; }
+
+ MemoryAreaFactory& memAreaFactory()
+ { return *m_pMemAreaFactory; }
+
+ const MemoryAreaFactory& memAreaFactory() const
+ { return *m_pMemAreaFactory; }
+
+ const llvm::Triple& triple() const
+ { return m_Triple; }
+
+ static const char* version();
+
+ void setNamePool(StrSymPool& pPool)
+ { m_pStrSymPool = &pPool; }
+
+ StrSymPool& getStrSymPool() {
+ assert(NULL != m_pStrSymPool);
+ return *m_pStrSymPool;
+ }
+
+ const StrSymPool& getStrSymPool() const {
+ assert(NULL != m_pStrSymPool);
+ return *m_pStrSymPool;
+ }
+
+private:
+ // ----- General Options ----- //
+ GeneralOptions m_Options;
+ InputTree *m_pInputTree;
+ Input* m_pBitcode;
+ Output* m_pOutput;
+ llvm::Triple m_Triple;
+
+ // ----- factories ----- //
+ InputFactory *m_pInputFactory;
+ AttributeFactory *m_pAttrFactory;
+ ContextFactory *m_pCntxtFactory;
+ MemoryAreaFactory *m_pMemAreaFactory;
+
+ // ----- string and symbols ----- //
+ StrSymPool* m_pStrSymPool;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDInput.h b/include/mcld/MC/MCLDInput.h
new file mode 100644
index 0000000..097b8f6
--- /dev/null
+++ b/include/mcld/MC/MCLDInput.h
@@ -0,0 +1,86 @@
+//===- MCLDInput.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Input class inherits MCLDFile, which is used to represent a input file
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_INPUT_H
+#define MCLD_INPUT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/MC/MCLDFile.h"
+
+namespace mcld
+{
+
+class AttributeProxy;
+class Attribute;
+class InputFactory;
+
+/** \class Input
+ * \brief Input provides the information of a input file.
+ *
+ * @see MCLDFile
+ */
+class Input : public MCLDFile
+{
+friend class InputFactory;
+public:
+ enum Type {
+ Unknown = MCLDFile::Unknown,
+ Object = MCLDFile::Object,
+ DynObj = MCLDFile::DynObj,
+ Archive = MCLDFile::Archive,
+ Script = MCLDFile::Script
+ };
+
+private:
+ explicit Input(llvm::StringRef pName,
+ const AttributeProxy& pAttr);
+
+ Input(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ const AttributeProxy& pAttr,
+ unsigned int pType = Unknown,
+ off_t pFileOffset = 0);
+
+public:
+ ~Input();
+
+ bool isRecognized() const
+ { return (m_Type != Unknown); }
+
+ const Attribute* attribute() const
+ { return m_pAttr; }
+
+ bool isNeeded() const
+ { return m_bNeeded; }
+
+ void setNeeded()
+ { m_bNeeded = true; }
+
+ off_t fileOffset() const
+ { return m_fileOffset; }
+
+ void setFileOffset(off_t pFileOffset)
+ { m_fileOffset = pFileOffset; }
+
+private:
+ Attribute *m_pAttr;
+ bool m_bNeeded;
+ off_t m_fileOffset;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDInputTree.h b/include/mcld/MC/MCLDInputTree.h
new file mode 100644
index 0000000..7d8050c
--- /dev/null
+++ b/include/mcld/MC/MCLDInputTree.h
@@ -0,0 +1,237 @@
+//===- MCLDInputTree.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_INPUT_TREE_H
+#define MCLD_INPUT_TREE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/BinTree.h"
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/MC/MCLDInput.h"
+#include "mcld/MC/InputFactory.h"
+#include "mcld/Support/FileSystem.h"
+
+#include <string>
+
+
+namespace mcld
+{
+
+/** \class template<typename Traits, typename Iterator> PolicyIterator<mcld::Input>
+ * \brief PolicyIterator<mcld::Input> is a partially specific PolicyIterator
+ */
+template<typename Traits, typename IteratorType>
+class PolicyIterator<mcld::Input, Traits, IteratorType> : public PolicyIteratorBase<Input, Traits, IteratorType>
+{
+public:
+ typedef PolicyIterator<Input, Traits, IteratorType> Self;
+ typedef PolicyIteratorBase<Input, Traits, IteratorType> Base;
+ typedef PolicyIterator<Input, typename Traits::nonconst_traits, IteratorType> iterator;
+ typedef PolicyIterator<Input, typename Traits::const_traits, IteratorType> const_iterator;
+
+public:
+ PolicyIterator()
+ : Base() {}
+
+ PolicyIterator(const iterator &X)
+ : Base(X.m_pNode) {}
+
+ explicit PolicyIterator(NodeBase* X)
+ : Base(X) {}
+
+ virtual ~PolicyIterator() {}
+
+ bool isGroup() const
+ { return !Base::hasData(); }
+
+ Self& operator++() {
+ IteratorType::advance();
+ if (isGroup())
+ IteratorType::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp(*this);
+ IteratorType::advance();
+ if (isGroup())
+ IteratorType::advance();
+ return tmp;
+ }
+};
+
+/** \class InputTree
+ * \brief InputTree is the input tree to contains all inputs from the
+ * command line.
+ *
+ * InputTree, of course, is uncopyable.
+ *
+ * @see Input
+ */
+class InputTree : public BinaryTree<Input>
+{
+private:
+ typedef BinaryTree<Input> BinTreeTy;
+
+public:
+ enum Direction {
+ Inclusive = TreeIteratorBase::Leftward,
+ Positional = TreeIteratorBase::Rightward
+ };
+
+ typedef BinaryTree<Input>::iterator iterator;
+ typedef BinaryTree<Input>::const_iterator const_iterator;
+
+public:
+ struct Connector {
+ virtual ~Connector() {}
+ virtual void connect(iterator& pFrom, const const_iterator& pTo) const = 0;
+ virtual void move(iterator& pNode) const = 0;
+ };
+
+ struct Succeeder : public Connector {
+ virtual void connect(iterator& pFrom, const const_iterator& pTo) const {
+ proxy::hook<Positional>(pFrom.m_pNode, pTo.m_pNode);
+ }
+
+ virtual void move(iterator& pNode) const {
+ pNode.move<Positional>();
+ }
+ };
+
+ struct Includer : public Connector {
+ virtual void connect(iterator& pFrom, const const_iterator& pTo) const {
+ proxy::hook<Inclusive>(pFrom.m_pNode, pTo.m_pNode);
+ }
+
+ virtual void move(iterator& pNode) const {
+ pNode.move<Inclusive>();
+ }
+ };
+
+public:
+ static Succeeder Afterward;
+ static Includer Downward;
+
+public:
+
+ using BinTreeTy::merge;
+
+ InputTree(InputFactory& pInputFactory);
+ ~InputTree();
+
+ // ----- modify ----- //
+ /// insert - create a leaf node and merge it in the tree.
+ // This version of join determines the direction at run time.
+ // @param position the parent node
+ // @param value the value being pushed.
+ // @param pConnector the direction of the connecting edge of the parent node.
+ template<size_t DIRECT>
+ InputTree& insert(iterator pPosition,
+ const std::string& pNamespec,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Input::Unknown);
+
+ template<size_t DIRECT>
+ InputTree& enterGroup(iterator pPosition);
+
+ template<size_t DIRECT>
+ InputTree& insert(iterator pPosition,
+ const Input& pInput);
+
+ InputTree& merge(iterator pPosition,
+ const Connector& pConnector,
+ InputTree& pTree);
+
+ InputTree& insert(iterator pPosition,
+ const Connector& pConnector,
+ const std::string& pNamespec,
+ const sys::fs::Path& pPath,
+ unsigned int pType = Input::Unknown);
+
+ InputTree& insert(iterator pPosition,
+ const Connector& pConnector,
+ const Input& pInput);
+
+ InputTree& enterGroup(iterator pPosition,
+ const Connector& pConnector);
+
+ // ----- observers ----- //
+ unsigned int numOfInputs() const
+ { return m_FileFactory.size(); }
+
+ bool hasInput() const
+ { return !m_FileFactory.empty(); }
+
+private:
+ InputFactory& m_FileFactory;
+
+};
+
+bool isGroup(const InputTree::iterator& pos);
+bool isGroup(const InputTree::const_iterator& pos);
+bool isGroup(const InputTree::dfs_iterator& pos);
+bool isGroup(const InputTree::const_dfs_iterator& pos);
+bool isGroup(const InputTree::bfs_iterator& pos);
+bool isGroup(const InputTree::const_bfs_iterator& pos);
+
+} // namespace of mcld
+
+//===----------------------------------------------------------------------===//
+// template member functions
+template<size_t DIRECT>
+mcld::InputTree&
+mcld::InputTree::insert(mcld::InputTree::iterator pPosition,
+ const std::string& pNamespec,
+ const mcld::sys::fs::Path& pPath,
+ unsigned int pType)
+{
+ BinTreeTy::node_type* node = createNode();
+ node->data = m_FileFactory.produce(pNamespec, pPath, pType);
+ if (pPosition.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+}
+
+template<size_t DIRECT>
+mcld::InputTree&
+mcld::InputTree::enterGroup(mcld::InputTree::iterator pPosition)
+{
+ BinTreeTy::node_type* node = createNode();
+ if (pPosition.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+}
+
+template<size_t DIRECT>
+mcld::InputTree& mcld::InputTree::insert(mcld::InputTree::iterator pPosition,
+ const mcld::Input& pInput)
+{
+ BinTreeTy::node_type* node = createNode();
+ node->data = const_cast<mcld::Input*>(&pInput);
+ if (pPosition.isRoot())
+ proxy::hook<TreeIteratorBase::Leftward>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ else
+ proxy::hook<DIRECT>(pPosition.m_pNode,
+ const_cast<const node_type*>(node));
+ return *this;
+}
+
+#endif
+
diff --git a/include/mcld/MC/MCLDOptions.h b/include/mcld/MC/MCLDOptions.h
new file mode 100644
index 0000000..06097aa
--- /dev/null
+++ b/include/mcld/MC/MCLDOptions.h
@@ -0,0 +1,98 @@
+//===- MCLDOptions.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_OPTIONS_H
+#define MCLD_OPTIONS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/RealPath.h"
+#include "mcld/MC/SearchDirs.h"
+#include "mcld/Support/FileSystem.h"
+
+namespace mcld
+{
+class Input;
+
+/** \class ScriptOptions
+ *
+ */
+class ScriptOption
+{
+};
+
+/** \class GeneralOptions
+ * \brief GeneralOptions collects the options that not be one of the
+ * - input files
+ * - attribute of input files
+ * - script options
+ */
+class GeneralOptions
+{
+public:
+ /// default link script
+ bool hasDefaultLDScript() const;
+ const char* defaultLDScript() const;
+ void setDefaultLDScript(const std::string& pFilename);
+
+ /// sysroot
+ const sys::fs::Path& sysroot() const
+ { return m_Sysroot; }
+
+ void setSysroot(const sys::fs::Path &pPath);
+
+ /// search directory
+ SearchDirs& directories()
+ { return m_SearchDirs; }
+
+ const SearchDirs& directories() const
+ { return m_SearchDirs; }
+
+ /// trace
+ void setTrace(bool pEnableTrace = true)
+ { m_bTrace = pEnableTrace; }
+
+ bool trace() const
+ { return m_bTrace; }
+
+ void setVerbose(bool pVerbose = true)
+ { m_bVerbose = pVerbose; }
+
+ bool verbose() const
+ { return m_bVerbose; }
+
+ void setBsymbolic(bool pBsymbolic = false)
+ { m_Bsymbolic = pBsymbolic; }
+
+ bool Bsymbolic() const
+ { return m_Bsymbolic; }
+
+ bool hasEntry() const
+ { return !m_Entry.empty(); }
+
+ void setEntry(const std::string& pEntry)
+ { m_Entry = pEntry; }
+
+ const std::string& entry() const
+ { return m_Entry; }
+
+private:
+ Input* m_pDefaultBitcode;
+ std::string m_DefaultLDScript;
+ sys::fs::RealPath m_Sysroot;
+ SearchDirs m_SearchDirs;
+ bool m_bTrace;
+ bool m_bVerbose;
+ bool m_Bsymbolic;
+ std::string m_Entry;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLDOutput.h b/include/mcld/MC/MCLDOutput.h
new file mode 100644
index 0000000..14768ce
--- /dev/null
+++ b/include/mcld/MC/MCLDOutput.h
@@ -0,0 +1,52 @@
+//===- MCLDOutput.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Output class inherits MCLDFile, which is used to represent a output file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_OUTPUT_H
+#define MCLD_OUTPUT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/MC/MCLDFile.h>
+#include <mcld/Support/RealPath.h>
+#include <string>
+
+namespace mcld
+{
+
+/** \class MCLDOutput
+ * \brief MCLDOutput provides the information about the output.
+ *
+ * @see MCLDFile
+ */
+class Output : public MCLDFile
+{
+public:
+ enum Type {
+ Object = MCLDFile::Object,
+ DynObj = MCLDFile::DynObj,
+ Exec = MCLDFile::Exec
+ };
+
+public:
+ Output();
+ explicit Output(const sys::fs::Path& pRealPath,
+ Type pType);
+
+ ~Output();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLinker.h b/include/mcld/MC/MCLinker.h
new file mode 100644
index 0000000..8de7148
--- /dev/null
+++ b/include/mcld/MC/MCLinker.h
@@ -0,0 +1,279 @@
+//===- MCLinker.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a number of APIs used by SectLinker.
+// These APIs do the things which a linker should do.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MCLINKER_H
+#define MCLD_MCLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/ilist.h>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/LD/StrSymPool.h>
+#include <mcld/LD/StaticResolver.h>
+#include <mcld/LD/LDSectionFactory.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/Relocation.h>
+#include <mcld/LD/SectionMerger.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/SymbolCategory.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Support/GCFactoryListTraits.h>
+#include <set>
+#include <string>
+
+namespace mcld {
+
+class TargetLDBackend;
+class MCLDInfo;
+class LDSection;
+class LDSectionFactory;
+class SectionMap;
+class Output;
+
+/** \class MCLinker
+ * \brief MCLinker provides a pass to link object files.
+ */
+class MCLinker
+{
+public:
+ enum DefinePolicy
+ {
+ Force,
+ AsRefered
+ };
+
+ enum ResolvePolicy
+ {
+ Unresolve,
+ Resolve
+ };
+
+public:
+ MCLinker(TargetLDBackend& pBackend,
+ MCLDInfo& pLDInfo,
+ LDContext& pContext,
+ SectionMap& pSectionMap,
+ const Resolver& pResolver = StaticResolver());
+ ~MCLinker();
+
+ // ----- about symbols ----- //
+ /// addDynSymbol - add a symbol and resolve it immediately
+ template<Input::Type FROM>
+ LDSymbol* addSymbol(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
+
+ /// defineSymbol - add a symbol
+ /// defineSymbol define a output symbol
+ ///
+ /// @tparam POLICY idicate how to define the symbol.
+ /// - Force
+ /// - Define the symbol forcefully. If the symbol has existed, override
+ /// it. Otherwise, define it.
+ /// - AsRefered
+ /// - If the symbol has existed, override it. Otherwise, return NULL
+ /// immediately.
+ ///
+ /// @tparam RESOLVE indicate whether to resolve the symbol or not.
+ /// - Unresolve
+ /// - Do not resolve the symbol, and override the symbol immediately.
+ /// - Resolve
+ /// - Resolve the defined symbol.
+ ///
+ /// @return If the output symbol has existed, return it. Otherwise, create
+ /// a new symbol and return the new one.
+ template<DefinePolicy POLICY, ResolvePolicy RESOLVE>
+ LDSymbol* defineSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility = ResolveInfo::Default);
+
+ /// mergeSymbolTable - merge the symbol table and resolve symbols.
+ /// Since in current design, MCLinker resolves symbols when reading symbol
+ /// tables, this function do nothing.
+ bool mergeSymbolTable(Input& pInput)
+ { return true; }
+
+ bool finalizeSymbols();
+
+ // ----- sections ----- //
+ /// getSectionMap - getSectionMap to change the behavior of SectionMerger
+ /// SectionMap& getSectionMap()
+ /// { return m_SectionMap; }
+
+ /// createSectHdr - for reader and standard/target format to create a section
+ /// header. This function will create a new LDSection and return it. If the
+ /// output has no related LDSection, this function will also create one and
+ /// push into the output.
+ LDSection& createSectHdr(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag);
+
+ /// getOrCreateOutputSectHdr - for reader and standard/target format to get
+ /// or create the output's section header
+ LDSection& getOrCreateOutputSectHdr(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag,
+ uint32_t pAlign = 0x0);
+
+ /// getOrCreateSectData - for reader to map and perform section merging immediately
+ llvm::MCSectionData& getOrCreateSectData(LDSection& pSection);
+
+ // ----- relocations ----- //
+ /// addRelocation - add a relocation entry in MCLinker (only for object file)
+ /// @param pType - the type of the relocation
+ /// @param pResolveInfo - the symbol should be the symbol in the input file. MCLinker
+ /// computes the real applied address by the output symbol.
+ /// @param pFragmentRef - the fragment reference of the applied address.
+ /// @param pAddend - the addend value for applying relocation
+ Relocation* addRelocation(Relocation::Type pType,
+ const LDSymbol& pSym,
+ ResolveInfo& pResolveInfo,
+ MCFragmentRef& pFragmentRef,
+ Relocation::Address pAddend = 0);
+
+ /// applyRelocations - apply all relocation enties.
+ bool applyRelocations();
+
+ /// syncRelocationResult - After applying relocation, write back relocation target
+ /// data to output file.
+ void syncRelocationResult();
+
+ // ----- layout ----- //
+ Layout& getLayout()
+ { return m_Layout; }
+
+ const Layout& getLayout() const
+ { return m_Layout; }
+
+ bool layout();
+
+ // ----- output symbols ----- //
+ SymbolCategory& getOutputSymbols()
+ { return m_OutputSymbols; }
+
+ const SymbolCategory& getOutputSymbols() const
+ { return m_OutputSymbols; }
+
+ // ----- capacity ----- //
+ MCLDInfo& getLDInfo()
+ { return m_Info; }
+
+ const MCLDInfo& getLDInfo() const
+ { return m_Info; }
+
+private:
+ LDSymbol* defineSymbolForcefully(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* defineAndResolveSymbolForcefully(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* defineSymbolAsRefered(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* defineAndResolveSymbolAsRefered(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ bool shouldForceLocal(const ResolveInfo& pInfo) const;
+
+ LDSymbol* addSymbolFromDynObj(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+
+ LDSymbol* addSymbolFromObject(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility);
+private:
+ typedef GCFactory<LDSymbol, 0> LDSymbolFactory;
+ typedef GCFactory<llvm::MCSectionData, 0> LDSectionDataFactory;
+ typedef llvm::iplist<llvm::MCFragment,
+ GCFactoryListTraits<llvm::MCFragment> > RelocationListType;
+ typedef std::set<LDSymbol*> ForceLocalSymbolTable;
+ typedef std::vector<LDSymbol*> OutputSymbolTable;
+
+private:
+ TargetLDBackend& m_Backend;
+ MCLDInfo& m_Info;
+ LDContext& m_Output;
+ SectionMap& m_SectionMap;
+ LDSymbolFactory m_LDSymbolFactory;
+ LDSectionFactory m_LDSectHdrFactory;
+ LDSectionDataFactory m_LDSectDataFactory;
+ SectionMerger m_SectionMerger;
+ StrSymPool m_StrSymPool;
+ Layout m_Layout;
+ RelocationListType m_RelocationList;
+ SymbolCategory m_OutputSymbols;
+
+};
+
+#include "MCLinker.tcc"
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCLinker.tcc b/include/mcld/MC/MCLinker.tcc
new file mode 100644
index 0000000..19a83ec
--- /dev/null
+++ b/include/mcld/MC/MCLinker.tcc
@@ -0,0 +1,105 @@
+//===- MCLinker.tcc -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/// addSymbol - add a symbol and resolve it immediately
+template<Input::Type FROM>
+LDSymbol* MCLinker::addSymbol(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ // These if/else should be optimized by compiler.
+ // This function is defined for clarity.
+ if (FROM == Input::DynObj)
+ return addSymbolFromDynObj(pName,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (FROM == Input::Object)
+ return addSymbolFromObject(pName,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ llvm::report_fatal_error("add a symbol from unknown file type.\n");
+ return NULL;
+}
+
+// defineSymbol - define a new symbol
+template<MCLinker::DefinePolicy POLICY, MCLinker::ResolvePolicy RESOLVE>
+LDSymbol* MCLinker::defineSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ // These if/return should be optimized by compiler.
+ // This function is defined for clarity.
+ if (MCLinker::Force == POLICY && MCLinker::Unresolve == RESOLVE)
+ return defineSymbolForcefully(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (MCLinker::AsRefered == POLICY && MCLinker::Unresolve == RESOLVE)
+ return defineSymbolAsRefered(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (MCLinker::Force == POLICY && MCLinker::Resolve == RESOLVE)
+ return defineAndResolveSymbolForcefully(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+
+ if (MCLinker::AsRefered == POLICY && MCLinker::Resolve == RESOLVE)
+ return defineAndResolveSymbolAsRefered(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+}
+
diff --git a/include/mcld/MC/MCRegionFragment.h b/include/mcld/MC/MCRegionFragment.h
new file mode 100644
index 0000000..7dd088b
--- /dev/null
+++ b/include/mcld/MC/MCRegionFragment.h
@@ -0,0 +1,53 @@
+//===- MCRegionFragment.h - MCFragment containing MemoryRegion ------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_REGION_FRAGMENT_H
+#define MCLD_REGION_FRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/MC/MCAssembler.h>
+
+namespace mcld
+{
+
+/** \class MCRegionFragment
+ * \brief MCRegionFragment is a kind of MCFragment containing
+ * mcld::MemoryRegion
+ */
+class MCRegionFragment : public llvm::MCFragment
+{
+public:
+ MCRegionFragment(MemoryRegion& pRegion, llvm::MCSectionData* pSD = 0);
+ ~MCRegionFragment();
+
+ MemoryRegion& getRegion()
+ { return m_Region; }
+
+ const MemoryRegion& getRegion() const
+ { return m_Region; }
+
+ static bool classof(const MCFragment *F)
+ { return F->getKind() == llvm::MCFragment::FT_Region; }
+
+ static bool classof(const MCRegionFragment *)
+ { return true; }
+
+private:
+ MemoryRegion& m_Region;
+ llvm::MCSectionData* m_pSectionData;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/MCTargetFragment.h b/include/mcld/MC/MCTargetFragment.h
new file mode 100644
index 0000000..4050708
--- /dev/null
+++ b/include/mcld/MC/MCTargetFragment.h
@@ -0,0 +1,48 @@
+//===- MCTargetFragment.h - MCFragment containing MemoryRegion ------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_TARGET_FRAGMENT_H
+#define MCLD_TARGET_FRAGMENT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/MC/MCAssembler.h>
+
+namespace mcld
+{
+
+/** \class MCTargetFragment
+ * \brief MCTargetFragment is a kind of MCFragment inherited by
+ * target-depedent MCFragment.
+ */
+class MCTargetFragment : public llvm::MCFragment
+{
+protected:
+ MCTargetFragment(llvm::MCFragment::FragmentType pKind,
+ llvm::MCSectionData* pSD = 0) :
+ llvm::MCFragment(pKind, pSD) {}
+
+public:
+ virtual ~MCTargetFragment() {}
+
+ virtual size_t getSize() const = 0;
+
+public:
+ static bool classof(const MCFragment *F)
+ { return F->getKind() == llvm::MCFragment::FT_Target; }
+
+ static bool classof(const MCTargetFragment *)
+ { return true; }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/SearchDirs.h b/include/mcld/MC/SearchDirs.h
new file mode 100644
index 0000000..1a22cf4
--- /dev/null
+++ b/include/mcld/MC/SearchDirs.h
@@ -0,0 +1,76 @@
+//===- SearchDirs.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SEARCHDIRS_H
+#define SEARCHDIRS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/MC/MCLDInput.h"
+
+namespace mcld
+{
+
+class MCLDFile;
+class MCLDDirectory;
+
+namespace sys {
+namespace fs {
+class Path;
+} // namespace of fs
+} // namespace of sys
+
+/** \class SearchDirs
+ * \brief SearchDirs contains the list of paths that MCLinker will search for
+ * archive libraries and control scripts.
+ *
+ * SearchDirs is customized for linking. It handles -L on the command line
+ * and SEARCH_DIR macro in the link script.
+ *
+ * @see MCLDDirectory.
+ */
+class SearchDirs : private Uncopyable
+{
+public:
+ typedef std::vector<MCLDDirectory*> DirList;
+ typedef DirList::iterator iterator;
+ typedef DirList::const_iterator const_iterator;
+
+public:
+ SearchDirs();
+ ~SearchDirs();
+
+ /// find - give a namespec, return a real path of the shared object.
+ sys::fs::Path* find(const std::string& pNamespec, mcld::Input::Type pType);
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return m_DirList.begin(); }
+
+ iterator end()
+ { return m_DirList.end(); }
+
+ const_iterator begin() const
+ { return m_DirList.begin(); }
+
+ const_iterator end() const
+ { return m_DirList.end(); }
+
+ // ----- modifiers ----- //
+ void add(const MCLDDirectory& pDirectory);
+
+private:
+ DirList m_DirList;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/MC/SymbolCategory.h b/include/mcld/MC/SymbolCategory.h
new file mode 100644
index 0000000..9432c2a
--- /dev/null
+++ b/include/mcld/MC/SymbolCategory.h
@@ -0,0 +1,158 @@
+//===- SymbolCategory.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYMBOL_CATEGORY_H
+#define MCLD_SYMBOL_CATEGORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/ADT/TypeTraits.h>
+#include <vector>
+
+namespace mcld
+{
+
+class LDSymbol;
+class ResolveInfo;
+/** \class SymbolCategory
+ * \brief SymbolCategory groups output LDSymbol into different categories.
+ */
+class SymbolCategory
+{
+private:
+ typedef std::vector<LDSymbol*> OutputSymbols;
+
+public:
+ typedef OutputSymbols::iterator iterator;
+ typedef OutputSymbols::const_iterator const_iterator;
+
+public:
+ SymbolCategory();
+
+ ~SymbolCategory();
+
+ // ----- modifiers ----- //
+ SymbolCategory& add(LDSymbol& pSymbol);
+
+ SymbolCategory& forceLocal(LDSymbol& pSymbol);
+
+ SymbolCategory& arrange(LDSymbol& pSymbol, const ResolveInfo& pSourceInfo);
+
+ SymbolCategory& changeCommonsToGlobal();
+
+ // ----- access ----- //
+ LDSymbol& at(size_t pPosition)
+ { return *m_OutputSymbols.at(pPosition); }
+
+ const LDSymbol& at(size_t pPosition) const
+ { return *m_OutputSymbols.at(pPosition); }
+
+ LDSymbol& operator[](size_t pPosition)
+ { return *m_OutputSymbols[pPosition]; }
+
+ const LDSymbol& operator[](size_t pPosition) const
+ { return *m_OutputSymbols[pPosition]; }
+
+ // ----- observers ----- //
+ size_t numOfSymbols() const;
+
+ size_t numOfLocals() const;
+
+ size_t numOfCommons() const;
+
+ size_t numOfRegulars() const;
+
+ bool empty() const;
+
+ bool emptyLocals() const;
+
+ bool emptyCommons() const;
+
+ bool emptyRegulars() const;
+
+ // ----- iterators ----- //
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator localBegin();
+ iterator localEnd();
+ const_iterator localBegin() const;
+ const_iterator localEnd() const;
+
+ iterator commonBegin();
+ iterator commonEnd();
+ const_iterator commonBegin() const;
+ const_iterator commonEnd() const;
+
+ iterator regularBegin();
+ iterator regularEnd();
+ const_iterator regularBegin() const;
+ const_iterator regularEnd() const;
+
+private:
+ class Category
+ {
+ public:
+ enum Type {
+ File,
+ Local,
+ Common,
+ Weak,
+ Global
+ };
+
+ public:
+ Type type;
+
+ size_t begin;
+ size_t end;
+
+ Category* prev;
+ Category* next;
+
+ public:
+ Category(Type pType)
+ : type(pType),
+ begin(0),
+ end(0),
+ prev(NULL),
+ next(NULL) {
+ }
+
+ size_t size() const
+ { return (end - begin); }
+
+ bool empty() const
+ { return (begin == end); }
+
+ bool isFirst() const
+ { return (NULL == prev); }
+
+ bool isLast() const
+ { return (NULL == next); }
+
+ static Type categorize(const ResolveInfo& pInfo);
+
+ };
+
+private:
+ OutputSymbols m_OutputSymbols;
+
+ Category* m_pFile;
+ Category* m_pLocal;
+ Category* m_pCommon;
+ Category* m_pWeak;
+ Category* m_pGlobal;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/Allocators.h b/include/mcld/Support/Allocators.h
new file mode 100644
index 0000000..962c900
--- /dev/null
+++ b/include/mcld/Support/Allocators.h
@@ -0,0 +1,439 @@
+//===- Allocators.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ALLOCATORS_H
+#define LLVM_ALLOCATORS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/LD/LDContext.h"
+#include <cstdlib>
+
+namespace mcld
+{
+
+/** \class Chunk
+ * \brief Chunk is the basic unit of the storage of the LinearAllocator
+ *
+ * @see LinearAllocator
+ */
+template<typename DataType, size_t ChunkSize>
+struct Chunk
+{
+public:
+ typedef DataType value_type;
+public:
+ Chunk()
+ : next(0), bound(0)
+ { }
+
+ static size_t size() { return ChunkSize; }
+
+public:
+ Chunk* next;
+ size_t bound;
+ DataType data[ChunkSize];
+};
+
+template<typename DataType>
+struct Chunk<DataType, 0>
+{
+public:
+ typedef DataType value_type;
+
+public:
+ Chunk()
+ : next(0), bound(0) {
+ if (0 != m_Size)
+ data = (DataType*)malloc(sizeof(DataType)*m_Size);
+ else
+ data = 0;
+ }
+
+ ~Chunk() {
+ if (data)
+ free(data);
+ }
+
+ static size_t size() { return m_Size; }
+ static void setSize(size_t pSize) { m_Size = pSize; }
+
+public:
+ Chunk* next;
+ size_t bound;
+ DataType *data;
+ static size_t m_Size;
+};
+
+template<typename DataType>
+size_t Chunk<DataType, 0>::m_Size = 0;
+
+template<typename ChunkType>
+class LinearAllocatorBase : private Uncopyable
+{
+public:
+ typedef ChunkType chunk_type;
+ typedef typename ChunkType::value_type value_type;
+ typedef typename ChunkType::value_type* pointer;
+ typedef typename ChunkType::value_type& reference;
+ typedef const typename ChunkType::value_type* const_pointer;
+ typedef const typename ChunkType::value_type& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef unsigned char byte_type;
+
+protected:
+ LinearAllocatorBase()
+ : m_pRoot(0),
+ m_pCurrent(0),
+ m_AllocatedNum(0) {
+ }
+
+ // LinearAllocatorBase does NOT mean to destroy the allocated memory.
+ // If you want a memory allocator to release memory at destruction, please
+ // use GCFactory series.
+ virtual ~LinearAllocatorBase()
+ { }
+
+public:
+ pointer address(reference X) const
+ { return &X; }
+
+ const_pointer address(const_reference X) const
+ { return &X; }
+
+ /// standard construct - constructing an object on the location pointed by
+ // pPtr, and using its copy constructor to initialized its value to pValue.
+ //
+ // @param pPtr the address where the object to be constructed
+ // @param pValue the value to be constructed
+ void construct(pointer pPtr, const_reference pValue)
+ { new (pPtr) value_type(pValue); }
+
+ /// default construct - constructing an object on the location pointed by
+ // pPtr, and using its default constructor to initialized its value to
+ // pValue.
+ //
+ // @param pPtr the address where the object to be constructed
+ void construct(pointer pPtr)
+ { new (pPtr) value_type(); }
+
+ /// standard destroy - destroy data on arbitrary address
+ // @para pPtr the address where the data to be destruected.
+ void destroy(pointer pPtr)
+ { pPtr->~value_type(); }
+
+ /// allocate - allocate N data in order.
+ // - Disallow to allocate a chunk whose size is bigger than a chunk.
+ //
+ // @param N the number of allocated data.
+ // @return the start address of the allocated memory
+ pointer allocate(size_type N) {
+ if (0 == N || N > chunk_type::size())
+ return 0;
+
+ if (empty())
+ initialize();
+
+ size_type rest_num_elem = chunk_type::size() - m_pCurrent->bound;
+ pointer result = 0;
+ if (N > rest_num_elem)
+ createChunk();
+ result = const_cast<pointer>(&(m_pCurrent->data[m_pCurrent->bound]));
+ m_pCurrent->bound += N;
+ return result;
+ }
+
+ /// allocate - clone function of allocating one datum.
+ pointer allocate() {
+ if (empty())
+ initialize();
+
+ pointer result = 0;
+ if (chunk_type::size() == m_pCurrent->bound)
+ createChunk();
+ result = const_cast<pointer>(&(m_pCurrent->data[m_pCurrent->bound]));
+ ++m_pCurrent->bound;
+ return result;
+ }
+
+ /// deallocate - deallocate N data from the pPtr
+ // - if we can simply release some memory, then do it. Otherwise, do
+ // nothing.
+ void deallocate(pointer &pPtr, size_type N) {
+ if (0 == N ||
+ N > chunk_type::size() ||
+ 0 == m_pCurrent->bound ||
+ N >= m_pCurrent->bound)
+ return;
+ if (!isAvailable(pPtr))
+ return;
+ m_pCurrent->bound -= N;
+ pPtr = 0;
+ }
+
+ /// deallocate - clone function of deallocating one datum
+ void deallocate(pointer &pPtr) {
+ if (0 == m_pCurrent->bound)
+ return;
+ if (!isAvailable(pPtr))
+ return;
+ m_pCurrent->bound -= 1;
+ pPtr = 0;
+ }
+
+ /// isIn - whether the pPtr is in the current chunk?
+ bool isIn(pointer pPtr) const {
+ if (pPtr >= &(m_pCurrent->data[0]) &&
+ pPtr <= &(m_pCurrent->data[chunk_type::size()-1]))
+ return true;
+ return false;
+ }
+
+ /// isIn - whether the pPtr is allocated, and can be constructed.
+ bool isAvailable(pointer pPtr) const {
+ if (pPtr >= &(m_pCurrent->data[m_pCurrent->bound]) &&
+ pPtr <= &(m_pCurrent->data[chunk_type::size()-1]))
+ return true;
+ return false;
+ }
+
+ void reset() {
+ m_pRoot = 0;
+ m_pCurrent = 0;
+ m_AllocatedNum = 0;
+ }
+
+ /// clear - clear all chunks
+ void clear() {
+ chunk_type *cur = m_pRoot, *prev;
+ while (0 != cur) {
+ unsigned int idx=0;
+ prev = cur;
+ cur = cur->next;
+ while (idx != prev->bound) {
+ destroy(&prev->data[idx]);
+ ++idx;
+ }
+ delete prev;
+ }
+ reset();
+ }
+
+ // ----- observers ----- //
+ bool empty() const {
+ return (0 == m_pRoot);
+ }
+
+ size_type max_size() const
+ { return m_AllocatedNum; }
+
+protected:
+ inline void initialize() {
+ m_pRoot = new chunk_type();
+ m_pCurrent = m_pRoot;
+ m_AllocatedNum += chunk_type::size();
+ }
+
+ inline chunk_type *createChunk() {
+ chunk_type *result = new chunk_type();
+ m_pCurrent->next = result;
+ m_pCurrent = result;
+ m_AllocatedNum += chunk_type::size();
+ return result;
+ }
+
+protected:
+ chunk_type *m_pRoot;
+ chunk_type *m_pCurrent;
+ size_type m_AllocatedNum;
+};
+
+/** \class LinearAllocator
+ * \brief LinearAllocator is another bump pointer allocator which should be
+ * limited in use of two-phase memory allocation.
+ *
+ * Two-phase memory allocation clear separates the use of memory into 'claim'
+ * and 'release' phases. There are no interleaving allocation and
+ * deallocation. Interleaving 'allocate' and 'deallocate' increases the size
+ * of allocated memory, and causes bad locality.
+ *
+ * The underlying concept of LinearAllocator is a memory pool. LinearAllocator
+ * is a simple implementation of boost::pool's ordered_malloc() and
+ * ordered_free().
+ *
+ * template argument DataType is the DataType to be allocated
+ * template argument ChunkSize is the number of bytes of a chunk
+ */
+template<typename DataType, size_t ChunkSize>
+class LinearAllocator : public LinearAllocatorBase<Chunk<DataType, ChunkSize> >
+{
+public:
+ template<typename NewDataType>
+ struct rebind {
+ typedef LinearAllocator<NewDataType, ChunkSize> other;
+ };
+
+public:
+ LinearAllocator()
+ : LinearAllocatorBase<Chunk<DataType, ChunkSize> >() {
+ }
+
+ virtual ~LinearAllocator()
+ { }
+};
+
+template<typename DataType>
+class LinearAllocator<DataType, 0> : public LinearAllocatorBase<Chunk<DataType, 0> >
+{
+public:
+ template<typename NewDataType>
+ struct rebind {
+ typedef LinearAllocator<NewDataType, 0> other;
+ };
+
+public:
+ explicit LinearAllocator(size_t pNum)
+ : LinearAllocatorBase<Chunk<DataType, 0> >() {
+ Chunk<DataType, 0>::setSize(pNum);
+ }
+
+ virtual ~LinearAllocator()
+ { }
+};
+
+template<typename DataType>
+class MallocAllocator
+{
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef DataType* pointer;
+ typedef const DataType* const_pointer;
+ typedef DataType& reference;
+ typedef const DataType& const_reference;
+ typedef DataType value_type;
+
+ template<typename OtherDataType>
+ struct rebind
+ {
+ typedef MallocAllocator<OtherDataType> other;
+ };
+
+public:
+ MallocAllocator() throw()
+ { }
+
+ MallocAllocator(const MallocAllocator&) throw()
+ { }
+
+ ~MallocAllocator() throw()
+ { }
+
+ pointer address(reference X) const
+ { return &X; }
+
+ const_pointer address(const_reference X) const
+ { return &X; }
+
+ pointer allocate(size_type pNumOfElements, const void* = 0)
+ {
+ return static_cast<DataType*>(
+ std::malloc(pNumOfElements*sizeof(DataType)));
+ }
+
+ void deallocate(pointer pObject, size_type)
+ { std::free(static_cast<void*>(pObject)); }
+
+ size_type max_size() const throw()
+ { return size_t(-1) / sizeof(DataType); }
+
+ void construct(pointer pObject, const DataType& pValue)
+ { ::new((void *)pObject) value_type(pValue); }
+
+ void destroy(pointer pObject)
+ { pObject->~DataType(); }
+
+};
+
+template<>
+class MallocAllocator<void>
+{
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+ typedef void* reference;
+ typedef const void* const_reference;
+ typedef void* value_type;
+
+ template<typename OtherDataType>
+ struct rebind
+ {
+ typedef MallocAllocator<OtherDataType> other;
+ };
+
+public:
+ MallocAllocator() throw()
+ { }
+
+ MallocAllocator(const MallocAllocator&) throw()
+ { }
+
+ ~MallocAllocator() throw()
+ { }
+
+ size_type max_size() const throw()
+ { return size_t(-1) / sizeof(void*); }
+
+ pointer address(reference X) const
+ { return X; }
+
+ const_pointer address(const_reference X) const
+ { return X; }
+
+ template<typename DataType>
+ DataType* allocate(size_type pNumOfElements, const void* = 0) {
+ return static_cast<DataType*>(
+ std::malloc(pNumOfElements*sizeof(DataType)));
+ }
+
+ pointer allocate(size_type pNumOfElements, const void* = 0) {
+ return std::malloc(pNumOfElements);
+ }
+
+ template<typename DataType>
+ void deallocate(DataType* pObject, size_type)
+ { std::free(static_cast<void*>(pObject)); }
+
+ void deallocate(pointer pObject, size_type)
+ { std::free(pObject); }
+
+ template<typename DataType>
+ void construct(DataType* pObject, const DataType& pValue)
+ { /* do nothing */ }
+
+ void construct(pointer pObject, const_reference pValue)
+ { /* do nothing */ }
+
+ template<typename DataType>
+ void destroy(DataType* pObject)
+ { /* do nothing */ }
+
+ void destroy(pointer pObject)
+ { /* do nothing */ }
+};
+
+} // namespace mcld
+
+#endif
+
diff --git a/include/mcld/Support/CommandLine.h b/include/mcld/Support/CommandLine.h
new file mode 100644
index 0000000..e52c4a3
--- /dev/null
+++ b/include/mcld/Support/CommandLine.h
@@ -0,0 +1,63 @@
+//===- CommandLine.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_COMMANDLINE_H
+#define MCLD_COMMANDLINE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/CommandLine.h>
+#include "mcld/Support/FileSystem.h"
+#include "mcld/MC/MCLDDirectory.h"
+
+//--------------------------------------------------
+// parser<mcld::sys::fs::Path>
+//
+namespace llvm {
+namespace cl {
+
+template<>
+class parser<mcld::sys::fs::Path> : public basic_parser<mcld::sys::fs::Path>
+{
+public:
+ bool parse(Option &O,
+ StringRef ArgName,
+ StringRef Arg,
+ mcld::sys::fs::Path &Val);
+
+ virtual const char *getValueName() const { return "path"; }
+ void printOptionDiff(const Option &O,
+ const mcld::sys::fs::Path &V,
+ OptVal Default,
+ size_t GlobalWidth) const;
+ virtual void anchor();
+};
+
+//--------------------------------------------------
+// parser<mcld::MCLDDirectory>
+//
+template<>
+class parser<mcld::MCLDDirectory> : public llvm::cl::basic_parser<mcld::MCLDDirectory>
+{
+public:
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, mcld::MCLDDirectory &Val);
+
+ virtual const char *getValueName() const { return "directory"; }
+ void printOptionDiff(const Option &O,
+ const mcld::MCLDDirectory &V,
+ OptVal Default,
+ size_t GlobalWidth) const;
+ virtual void anchor();
+};
+
+} // namespace of cl
+} // namespace of llvm
+
+#endif
+
diff --git a/include/mcld/Support/DerivedPositionDependentOptions.h b/include/mcld/Support/DerivedPositionDependentOptions.h
new file mode 100644
index 0000000..2254a5f
--- /dev/null
+++ b/include/mcld/Support/DerivedPositionDependentOptions.h
@@ -0,0 +1,137 @@
+//===- DerivedPositionDependentOptions.h ----------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DERIVEDPOSITIONDEPENDENTOPTIONS_H
+#define MCLD_DERIVEDPOSITIONDEPENDENTOPTIONS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <string>
+
+#include "mcld/Support/RealPath.h"
+#include "mcld/Support/PositionDependentOption.h"
+
+namespace mcld
+{
+
+ /** \class DerivedPositionDependentOptions
+ * \brief This file contains the declarations of classes derived from PositionDependentOption.
+ */
+
+ class FileOption : public PositionDependentOption {
+ private:
+ sys::fs::RealPath m_Path;
+
+ protected:
+ FileOption(unsigned pPosition, Type pType, const sys::fs::Path &pPath)
+ : PositionDependentOption(pPosition, pType)
+ { m_Path.assign(pPath); }
+
+ public:
+ inline const sys::fs::Path *path() const { return &m_Path; }
+ };
+
+ class NamespecOption : public PositionDependentOption {
+ private:
+ std::string m_pNamespec;
+
+ public:
+ NamespecOption(unsigned pPosition, const std::string &pNamespec)
+ : PositionDependentOption(pPosition, PositionDependentOption::NAMESPEC),
+ m_pNamespec(pNamespec) { }
+
+ inline const std::string &namespec() const { return m_pNamespec; }
+ };
+
+ class BitcodeOption : public FileOption {
+ public:
+ BitcodeOption(unsigned pPosition, const sys::fs::Path &pPath)
+ : FileOption(pPosition, PositionDependentOption::BITCODE, pPath) { }
+ };
+
+ class StartGroupOption : public PositionDependentOption {
+ public:
+ StartGroupOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::START_GROUP) { }
+ };
+
+ class EndGroupOption : public PositionDependentOption {
+ public:
+ EndGroupOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::END_GROUP) { }
+ };
+
+ class InputFileOption : public FileOption {
+ public:
+ InputFileOption(unsigned pPosition, const sys::fs::Path &pPath)
+ : FileOption(pPosition, PositionDependentOption::INPUT_FILE, pPath) { }
+ };
+
+ class WholeArchiveOption : public PositionDependentOption {
+ public:
+ WholeArchiveOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::WHOLE_ARCHIVE) { }
+ };
+
+ class NoWholeArchiveOption : public PositionDependentOption {
+ public:
+ NoWholeArchiveOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::NO_WHOLE_ARCHIVE) { }
+ };
+
+ class AsNeededOption : public PositionDependentOption {
+ public:
+ AsNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::AS_NEEDED) { }
+ };
+
+ class NoAsNeededOption : public PositionDependentOption {
+ public:
+ NoAsNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::NO_AS_NEEDED) { }
+ };
+
+ class AddNeededOption : public PositionDependentOption {
+ public:
+ AddNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::ADD_NEEDED) { }
+ };
+
+ class NoAddNeededOption : public PositionDependentOption {
+ public:
+ NoAddNeededOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::NO_ADD_NEEDED) { }
+ };
+
+ class BDynamicOption : public PositionDependentOption {
+ public:
+ BDynamicOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::BDYNAMIC) { }
+ };
+
+ class BStaticOption : public PositionDependentOption {
+ public:
+ BStaticOption(unsigned pPosition)
+ : PositionDependentOption(pPosition,
+ PositionDependentOption::BSTATIC) { }
+ };
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/Directory.h b/include/mcld/Support/Directory.h
new file mode 100644
index 0000000..8383e9e
--- /dev/null
+++ b/include/mcld/Support/Directory.h
@@ -0,0 +1,153 @@
+//===- Directory.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIRECTORY_H
+#define MCLD_DIRECTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/Path.h"
+#include "mcld/Support/PathCache.h"
+#include <llvm/Support/Allocator.h>
+
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+class DirIterator;
+
+/** \class Directory
+ * \brief A Directory object stores a Path object, a FileStatus object for
+ * non-symbolic link status, and a FileStatus object for symbolic link
+ * status. The FileStatus objects act as value caches.
+ */
+class Directory
+{
+friend mcld::sys::fs::PathCache::entry_type* detail::bring_one_into_cache(DirIterator& pIter);
+friend void detail::open_dir(Directory& pDir);
+friend void detail::close_dir(Directory& pDir);
+private:
+ friend class DirIterator;
+
+public:
+ typedef DirIterator iterator;
+
+public:
+ /// default constructor
+ Directory();
+
+ /// constructor - a directory whose path is pPath
+ explicit Directory(const Path& pPath,
+ FileStatus st = FileStatus(),
+ FileStatus symlink_st = FileStatus());
+
+ /// copy constructor
+ /// when a copying construction happens, the cache is not copied.
+ Directory(const Directory& pCopy);
+
+ /// assignment
+ /// When an assignment occurs, the cache is clear.
+ Directory& operator=(const Directory& pCopy);
+
+ /// destructor, inheritable.
+ virtual ~Directory();
+
+ /// Since we have default construtor, we must provide assign.
+ void assign(const Path& pPath,
+ FileStatus st = FileStatus(),
+ FileStatus symlink_st = FileStatus());
+
+ /// clear - clear the cache and close the directory handler
+ void clear();
+
+ bool isGood() const;
+
+ /// path - the path of the directory
+ const Path& path() const
+ { return m_Path; }
+
+ FileStatus status() const;
+ FileStatus symlinkStatus() const;
+
+ // ----- iterators ----- //
+ // While the iterators move, the direcotry is modified.
+ // Thus, we only provide non-constant iterator.
+ iterator begin();
+ iterator end();
+
+protected:
+ mcld::sys::fs::Path m_Path;
+ mutable FileStatus m_FileStatus;
+ mutable FileStatus m_SymLinkStatus;
+ intptr_t m_Handler;
+ // the cache of directory
+ mcld::sys::fs::PathCache m_Cache;
+ bool m_CacheFull;
+};
+
+/** \class DirIterator
+ * \brief A DirIterator object can traverse all entries in a Directory
+ *
+ * DirIterator will open the directory and add entry into Directory::m_Cache
+ * DirIterator() is the end of a directory.
+ * If the end of the directory elements is reached, the iterator becomes
+ * equal to the end iterator value - DirIterator().
+ *
+ * @see Directory
+ */
+class DirIterator
+{
+friend mcld::sys::fs::PathCache::entry_type* detail::bring_one_into_cache(DirIterator& pIter);
+friend class Directory;
+public:
+ typedef mcld::sys::fs::PathCache DirCache;
+
+public:
+ typedef Directory value_type;
+ typedef ConstTraits<Directory> const_traits;
+ typedef NonConstTraits<Directory> non_const_traits;
+ typedef std::input_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+private:
+ explicit DirIterator(Directory* pParent,
+ const DirCache::iterator& pIter);
+
+public:
+ // Since StringMapIterator has no default constructor, we also have none.
+ DirIterator(const DirIterator &X);
+ ~DirIterator();
+ DirIterator& operator=(const DirIterator& pCopy);
+
+ DirIterator& operator++();
+ DirIterator operator++(int);
+
+ Path* generic_path();
+
+ Path* path();
+ const Path* path() const;
+
+ bool operator==(const DirIterator& y) const;
+ bool operator!=(const DirIterator& y) const;
+
+private:
+ Directory* m_pParent; // get handler
+ DirCache::iterator m_Iter; // for full situation
+ DirCache::entry_type* m_pEntry;
+};
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Support/FileSystem.h b/include/mcld/Support/FileSystem.h
new file mode 100644
index 0000000..28dc563
--- /dev/null
+++ b/include/mcld/Support/FileSystem.h
@@ -0,0 +1,119 @@
+//===- FileSystem.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file declares the mcld::sys::fs:: namespace. It follows TR2/boost
+// filesystem (v3), but modified to remove exception handling and the
+// path class.
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_FILE_SYSTEM_H
+#define MCLD_FILE_SYSTEM_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Support/PathCache.h"
+#include <string>
+#include <iosfwd>
+#include <locale>
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+enum FileType
+{
+ StatusError,
+ StatusUnknown = StatusError,
+ FileNotFound,
+ RegularFile,
+ DirectoryFile,
+ SymlinkFile,
+ BlockFile,
+ CharacterFile,
+ FifoFile,
+ SocketFile,
+ ReparseFile,
+ TypeUnknown,
+ StatusKnown,
+ IsSymLink
+};
+
+/** \class FileStatus
+ * \brief FileStatus
+ */
+class FileStatus
+{
+public:
+ FileStatus()
+ : m_Value(StatusError) {}
+
+ explicit FileStatus(FileType v)
+ : m_Value(v) {}
+
+ void setType(FileType v) { m_Value = v; }
+ FileType type() const { return m_Value; }
+
+private:
+ FileType m_Value;
+};
+
+inline bool operator==(const FileStatus& rhs, const FileStatus& lhs) {
+ return rhs.type() == lhs.type();
+}
+
+inline bool operator!=(const FileStatus& rhs, const FileStatus& lhs ) {
+ return !(rhs == lhs);
+}
+
+class Path;
+class DirIterator;
+class Directory;
+
+bool exists(const Path &pPath);
+bool is_directory(const Path &pPath);
+
+inline static bool exists(FileStatus f) {
+ return (f.type() != StatusError)&&(f.type() != FileNotFound);
+}
+
+inline static bool is_directory(FileStatus f) {
+ return f.type() == mcld::sys::fs::DirectoryFile;
+}
+
+namespace detail
+{
+
+typedef unsigned char* Address;
+typedef off_t Offset;
+extern std::string static_library_extension;
+extern std::string shared_library_extension;
+extern std::string executable_extension;
+extern std::string relocatable_extension;
+extern std::string assembly_extension;
+extern std::string bitcode_extension;
+
+size_t canonicalize(std::string& pPathName);
+bool not_found_error(int perrno);
+void status(const Path& p, FileStatus& pFileStatus);
+void symlink_status(const Path& p, FileStatus& pFileStatus);
+mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter);
+void open_dir(Directory& pDir);
+void close_dir(Directory& pDir);
+void get_pwd(std::string& pPWD);
+size_t pread(int pFD, Address pBuf, size_t pCount, off_t pOffset);
+size_t pwrite(int pFD, const Address pBuf, size_t pCount, off_t pOffset);
+char *strerror(int pErrnum);
+
+} // namespace of detail
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/GCFactory.h b/include/mcld/Support/GCFactory.h
new file mode 100644
index 0000000..103188e
--- /dev/null
+++ b/include/mcld/Support/GCFactory.h
@@ -0,0 +1,230 @@
+//===- GCFactory.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GC_FACTORY_H
+#define MCLD_GC_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/Support/Allocators.h"
+
+#include <assert.h>
+#include <iterator>
+
+namespace mcld
+{
+
+/** \class DataIteratorBase
+ * \brief DataIteratorBase provides the basic functions of DataIterator
+ * @see DataIterator
+ */
+template<typename ChunkType>
+struct DataIteratorBase
+{
+public:
+ ChunkType* m_pChunk;
+ unsigned int m_Pos;
+
+public:
+ DataIteratorBase(ChunkType* X, unsigned int pPos)
+ : m_pChunk(X), m_Pos(pPos)
+ { }
+
+ inline void advance() {
+ ++m_Pos;
+ if ((m_Pos == m_pChunk->bound) && (0 == m_pChunk->next))
+ return;
+ if (m_Pos == m_pChunk->bound) {
+ m_pChunk = m_pChunk->next;
+ m_Pos = 0;
+ }
+ }
+
+ bool operator==(const DataIteratorBase& y) const
+ { return ((this->m_pChunk == y.m_pChunk) && (this->m_Pos == y.m_Pos)); }
+
+ bool operator!=(const DataIteratorBase& y) const
+ { return ((this->m_pChunk != y.m_pChunk) || (this->m_Pos != y.m_Pos)); }
+};
+
+/** \class DataIterator
+ * \brief DataIterator provides STL compatible iterator for allocators
+ */
+template<typename ChunkType, class Traits>
+class DataIterator : public DataIteratorBase<ChunkType>
+{
+public:
+ typedef typename ChunkType::value_type value_type;
+ typedef Traits traits;
+ typedef typename traits::pointer pointer;
+ typedef typename traits::reference reference;
+ typedef DataIterator<ChunkType, Traits> Self;
+ typedef DataIteratorBase<ChunkType> Base;
+
+ typedef typename traits::nonconst_traits nonconst_traits;
+ typedef DataIterator<ChunkType, nonconst_traits> iterator;
+ typedef typename traits::const_traits const_traits;
+ typedef DataIterator<ChunkType, const_traits> const_iterator;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+public:
+ DataIterator()
+ : Base(0, 0)
+ { }
+
+ DataIterator(ChunkType* pChunk, unsigned int pPos)
+ : Base(pChunk, pPos)
+ { }
+
+ DataIterator(const DataIterator& pCopy)
+ : Base(pCopy.m_pChunk, pCopy.m_Pos)
+ { }
+
+ ~DataIterator()
+ { }
+
+ // ----- operators ----- //
+ reference operator*() {
+ if (0 == this->m_pChunk)
+ assert(0 && "data iterator goes to a invalid position");
+ return this->m_pChunk->data[Base::m_Pos];
+ }
+
+ Self& operator++() {
+ this->Base::advance();
+ return *this;
+ }
+
+ Self operator++(int) {
+ Self tmp = *this;
+ this->Base::advance();
+ return tmp;
+ }
+};
+
+template<typename Alloc>
+class GCFactoryBase : public Alloc
+{
+public:
+ typedef DataIterator<typename Alloc::chunk_type,
+ NonConstTraits<
+ typename Alloc::value_type> > iterator;
+ typedef DataIterator<typename Alloc::chunk_type,
+ ConstTraits<
+ typename Alloc::value_type> > const_iterator;
+
+ typedef typename Alloc::value_type value_type;
+ typedef typename Alloc::pointer pointer;
+ typedef typename Alloc::reference reference;
+ typedef typename Alloc::size_type size_type;
+
+protected:
+ GCFactoryBase()
+ : Alloc(), m_NumAllocData(0)
+ { }
+
+ GCFactoryBase(size_t pNum)
+ : Alloc(pNum), m_NumAllocData(0)
+ { }
+
+public:
+ virtual ~GCFactoryBase()
+ { Alloc::clear(); }
+
+ // ----- modifiers ----- //
+ value_type* allocate(size_t N) {
+ value_type* result = Alloc::allocate(N);
+ if (0 != result)
+ m_NumAllocData += N;
+ return result;
+ }
+
+ value_type* allocate() {
+ ++m_NumAllocData;
+ return Alloc::allocate();
+ }
+
+ void deallocate(pointer &pPtr, size_type N) {
+ Alloc::deallocate(pPtr, N);
+ if (0 == pPtr)
+ m_NumAllocData -= N;
+ }
+
+ void deallocate(pointer &pPtr) {
+ Alloc::deallocate(pPtr);
+ if (0 == pPtr)
+ --m_NumAllocData;
+ }
+
+ void reset() {
+ Alloc::reset();
+ m_NumAllocData = 0;
+ }
+
+ // ----- iterators ----- //
+ iterator begin()
+ { return iterator(Alloc::m_pRoot, 0); }
+
+ const_iterator begin() const
+ { return const_iterator(Alloc::m_pRoot, 0); }
+
+ iterator end() {
+ return (0 == Alloc::m_pCurrent)?
+ begin():
+ iterator(Alloc::m_pCurrent, Alloc::m_pCurrent->bound);
+ }
+
+ const_iterator end() const {
+ return (0 == Alloc::m_pCurrent)?
+ begin():
+ const_iterator(Alloc::m_pCurrent, Alloc::m_pCurrent->bound);
+ }
+
+ // ----- observers ----- //
+ bool empty() const
+ { return Alloc::empty(); }
+
+ unsigned int capacity() const
+ { return Alloc::max_size(); }
+
+ unsigned int size() const
+ { return m_NumAllocData; }
+
+protected:
+ unsigned int m_NumAllocData;
+};
+
+/** \class GCFactory
+ * \brief GCFactory provides a factory that guaratees to remove all allocated
+ * data.
+ */
+template<typename DataType, size_t ChunkSize>
+class GCFactory : public GCFactoryBase<LinearAllocator<DataType, ChunkSize> >
+{
+public:
+ GCFactory()
+ : GCFactoryBase<LinearAllocator<DataType, ChunkSize> >()
+ { }
+};
+
+template<typename DataType>
+class GCFactory<DataType, 0> : public GCFactoryBase<LinearAllocator<DataType, 0> >
+{
+public:
+ GCFactory(size_t pNum)
+ : GCFactoryBase<LinearAllocator<DataType, 0> >(pNum)
+ { }
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/GCFactoryListTraits.h b/include/mcld/Support/GCFactoryListTraits.h
new file mode 100644
index 0000000..418ec57
--- /dev/null
+++ b/include/mcld/Support/GCFactoryListTraits.h
@@ -0,0 +1,65 @@
+//===- GCFactoryListTraits.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GC_FACTORY_LIST_TRAITS_H
+#define MCLD_GC_FACTORY_LIST_TRAITS_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/ADT/ilist_node.h>
+#include <llvm/ADT/ilist.h>
+
+#include <assert.h>
+
+namespace mcld
+{
+
+/** \class GCFactoryListTraits
+ * \brief GCFactoryListTraits provides trait class for llvm::iplist when
+ * the nodes in the list is produced by GCFactory.
+ */
+template<typename DataType>
+class GCFactoryListTraits : public llvm::ilist_default_traits<DataType> {
+private:
+ class SentinelNode : public llvm::ilist_node<DataType> {
+ public:
+ SentinelNode() : llvm::ilist_node<DataType>() { }
+ };
+
+public:
+ // override the traits provided in llvm::ilist_sentinel_traits since we've
+ // defined our own sentinel.
+ DataType *createSentinel() const
+ { return reinterpret_cast<DataType*>(&mSentinel); }
+
+ static void destroySentinel(DataType*) { }
+
+ DataType *provideInitialHead() const
+ { return createSentinel(); }
+
+ DataType *ensureHead(DataType*) const
+ { return createSentinel(); }
+
+ static void noteHead(DataType*, DataType*) { }
+
+ // override the traits provided in llvm::ilist_node_traits since
+ static DataType *createNode(const DataType &V) {
+ assert(false && "Only GCFactory knows how to create a node.");
+ }
+ static void deleteNode(DataType *V) {
+ // No action. GCFactory will handle it by itself.
+ }
+
+private:
+ mutable SentinelNode mSentinel;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Support/LEB128.h b/include/mcld/Support/LEB128.h
new file mode 100644
index 0000000..816ed72
--- /dev/null
+++ b/include/mcld/Support/LEB128.h
@@ -0,0 +1,117 @@
+//===- LEB128.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_LEB128_H
+#define MCLD_LEB128_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace mcld {
+
+namespace leb128 {
+
+typedef unsigned char ByteType;
+
+/* Forward declarations */
+template<typename IntType>
+size_t encode(ByteType *&pBuf, IntType pValue);
+
+template<typename IntType>
+IntType decode(const ByteType *pBuf, size_t &pSize);
+
+template<typename IntType>
+IntType decode(const ByteType *&pBuf);
+
+/*
+ * Given an integer, this function returns the number of bytes required to
+ * encode it in ULEB128 format.
+ */
+template<typename IntType>
+size_t size(IntType pValue) {
+ size_t size = 1;
+ while (pValue > 0x80) {
+ pValue >>= 7;
+ ++size;
+ }
+ return size;
+}
+
+/*
+ * Write an unsigned integer in ULEB128 to the given buffer. The client should
+ * ensure there's enough space in the buffer to hold the result. Update the
+ * given buffer pointer to the point just past the end of the write value and
+ * return the number of bytes being written.
+ */
+template<>
+size_t encode<uint64_t>(ByteType *&pBuf, uint64_t pValue);
+
+template<>
+size_t encode<uint32_t>(ByteType *&pBuf, uint32_t pValue);
+
+/*
+ * Encoding functions for signed LEB128.
+ */
+template<>
+size_t encode<int64_t>(ByteType *&pBuf, int64_t pValue);
+
+template<>
+size_t encode<int32_t>(ByteType *&pBuf, int32_t pValue);
+
+/*
+ * Read an integer encoded in ULEB128 format from the given buffer. pSize will
+ * contain the number of bytes used in the buffer to encode the returned
+ * integer.
+ */
+template<>
+uint64_t decode<uint64_t>(const ByteType *pBuf, size_t &pSize);
+
+/*
+ * Read an integer encoded in ULEB128 format from the given buffer. Update the
+ * given buffer pointer to the point just past the end of the read value.
+ */
+template<>
+uint64_t decode<uint64_t>(const ByteType *&pBuf);
+
+/*
+ * Decoding functions for signed LEB128.
+ */
+template<>
+int64_t decode<int64_t>(const ByteType *pBuf, size_t &pSize);
+
+template<>
+int64_t decode<int64_t>(const ByteType *&pBuf);
+
+/*
+ * The functions below handle the signed byte stream. This helps the user to get
+ * rid of annoying type conversions when using the LEB128 encoding/decoding APIs
+ * defined above.
+ */
+template<typename IntType>
+size_t encode(char *&pBuf, IntType pValue) {
+ return encode<IntType>(reinterpret_cast<ByteType*&>(pBuf), pValue);
+}
+
+template<typename IntType>
+IntType decode(const char *pBuf, size_t &pSize) {
+ return decode<IntType>(reinterpret_cast<const ByteType*>(pBuf), pSize);
+}
+
+template<typename IntType>
+IntType decode(const char *&pBuf) {
+ return decode<IntType>(reinterpret_cast<const ByteType*&>(pBuf));
+}
+
+} // namespace of leb128
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/Support/MemoryArea.h b/include/mcld/Support/MemoryArea.h
new file mode 100644
index 0000000..2c04aff
--- /dev/null
+++ b/include/mcld/Support/MemoryArea.h
@@ -0,0 +1,260 @@
+//===- MemoryArea.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MEMORY_AREA_H
+#define MCLD_MEMORY_AREA_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/Uncopyable.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/Path.h"
+#include <llvm/ADT/ilist.h>
+#include <llvm/ADT/ilist_node.h>
+#include <fcntl.h>
+#include <string>
+#include <list>
+
+#if defined(ENABLE_UNITTEST)
+namespace mcldtest
+{
+ class MemoryAreaTest;
+} // namespace of mcldtest
+
+#endif
+namespace mcld
+{
+
+class MemoryRegion;
+class RegionFactory;
+
+/** \class MemoryArea
+ * \brief MemoryArea is used to manage distinct MemoryRegions of address space.
+ *
+ * Good linkers must well manipulate memory mapped I/O and dynamic memory.
+ * In MCLinker, MemoryArea is the decision-maker to use memory mapped I/O or
+ * dynamic memory. When a client requests MemoryArea for a piece of memory
+ * to hold a part of a file, MemoryArea is going to see whether the requested
+ * part of the file is already in any existing memory which is requested
+ * before. If it is, MemoryArea creates a new MemoryRegion within the memory
+ * requested before. Otherwise, MemoryArea uses memory mapped I/O or dynamic
+ * memory to load the file.
+ *
+ * If the part a file being loaded is larger than 3/4 pages, MemoryArea uses
+ * memory mapped I/O to load the file. Otherwise, MemoryArea uses dynamic
+ * memory to read the content of file into the memory space.
+ */
+class MemoryArea : private Uncopyable
+{
+#if defined(ENABLE_UNITTEST)
+friend class mcldtest::MemoryAreaTest;
+#endif
+public:
+ enum IOState
+ {
+ GoodBit = 0,
+ BadBit = 1L << 0,
+ EOFBit = 1L << 1,
+ FailBit = 1L << 2,
+ IOStateEnd = 1L << 16
+ };
+
+ enum AccessMode
+ {
+ ReadOnly = O_RDONLY,
+ WriteOnly = O_WRONLY,
+ ReadWrite = O_RDWR,
+ AccessMask = O_ACCMODE
+ };
+
+private:
+ typedef sys::fs::detail::Address Address;
+
+ friend class MemoryRegion;
+ friend class RegionFactory;
+ struct Space : public llvm::ilist_node<Space>
+ {
+ public:
+ enum Type
+ {
+ ALLOCATED_ARRAY,
+ MMAPED,
+ UNALLOCATED
+ };
+
+ public:
+ Space()
+ : m_pParent(NULL),
+ type(UNALLOCATED),
+ file_offset(0),
+ size(0),
+ data(0),
+ region_num(0)
+ { }
+
+ Space(MemoryArea* pParent, size_t pOffset, size_t pLength)
+ : m_pParent(pParent),
+ type(UNALLOCATED),
+ file_offset(pOffset),
+ size(pLength),
+ data(0),
+ region_num(0)
+ { }
+
+ ~Space()
+ { }
+
+ void sync()
+ { m_pParent->write(*this); }
+
+ private:
+ MemoryArea* m_pParent;
+
+ public:
+ Type type;
+ size_t file_offset;
+ size_t size;
+ sys::fs::detail::Address data;
+ size_t region_num;
+ };
+
+ friend class Space;
+ typedef llvm::iplist<Space> SpaceList;
+
+public:
+ // constructor
+ // @param pRegionFactory the factory to manage MemoryRegions
+ MemoryArea(RegionFactory& pRegionFactory);
+
+ // destructor
+ ~MemoryArea();
+
+ // request - create a MemoryRegion within a sufficient space
+ // find an existing space to hold the MemoryRegion.
+ // if MemoryArea does not find such space, then it creates a new space and
+ // assign a MemoryRegion into the space.
+ MemoryRegion* request(size_t pOffset, size_t pLength);
+
+ // release - release a MemoryRegion.
+ // release a MemoryRegion does not cause
+ void release(MemoryRegion* pRegion);
+
+ // clean - release all MemoryRegion and unmap all spaces.
+ void clean();
+
+ // sync - sync all MemoryRegion
+ void sync();
+
+ // map - open the file pPath and mapped it onto MemoryArea
+ // @param flags see man 2 open
+ void map(const sys::fs::Path& pPath, int flags);
+
+ // map - open the file pPath and mapped it onto MemoryArea
+ // @param flags see man 2 open
+ // @param mode see man 2 open
+ void map(const sys::fs::Path& pPath, int flags, int mode);
+
+ // unmap - close the opened file and unmap the MemoryArea
+ void unmap();
+
+ // path - the path of the mapped file.
+ const sys::fs::Path& path() const
+ { return m_FilePath; }
+
+ // size - the real size of the mapped file.
+ size_t size() const
+ { return m_FileSize; }
+
+ // isMapped - check if MemoryArea is mapped to a file
+ bool isMapped() const;
+
+ // isGood - check if the state of the opened area is good for read/write
+ // operations
+ bool isGood() const;
+
+ // isBad - check if an error causes the loss of integrity of the memory space
+ bool isBad() const;
+
+ // isFailed - check if an error related to the internal logic of the operation
+ // itself occurs
+ bool isFailed() const;
+
+ // isEOF - check if we reach the end of the file
+ bool isEOF() const;
+
+ // isReadable - check if the memory area is readable
+ bool isReadable() const;
+
+ // isWriteable - check if the memory area is writable
+ bool isWritable() const;
+
+ // rdstate - get error state flags
+ // Returns the current internal error state flags of the stream
+ int rdstate() const;
+
+ // setState - set error state flag
+ void setState(IOState pState);
+
+ // clear - set error state flag
+ void clear(IOState pState = GoodBit);
+
+private:
+ // readToBuffer - read data from the file behind this MemorySpace and store
+ // those bytes in pBuf. Return the number of byte read or -1 on error.
+ ssize_t readToBuffer(sys::fs::detail::Address pBuf,
+ size_t pSize, size_t pOffset);
+
+private:
+ // find - first fit search
+ Space* find(size_t pOffset, size_t pLength);
+
+ // release a Space, but does not remove it from space list
+ void release(Space* pSpace);
+
+ // read - read data from mapped file into virtual memroy of pSpace. Return
+ // false on error.
+ bool read(Space& pSpace);
+
+ // write - write back the virtual memory of pSpace into mapped file.
+ void write(const Space& pSpace);
+
+ // truncate - truncate the file size to length.
+ void truncate(size_t pLength);
+
+ // policy - decide whehter to use dynamic memory or memory mapped I/O
+ Space::Type policy(off_t pOffset, size_t pLength);
+
+ // the size of one page
+ static const off_t PageSize = 4096;
+
+ // page_boundary - Given a file size, return the size to read integral pages.
+ // return the first page boundary after pFileOffset
+ static off_t page_boundary(off_t pFileOffset)
+ { return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
+
+ // Given a file offset, return the page offset.
+ // return the first page boundary before pFileOffset
+ static off_t page_offset(off_t pFileOffset)
+ { return pFileOffset & ~ (PageSize - 1); }
+
+private:
+ RegionFactory& m_RegionFactory;
+ sys::fs::Path m_FilePath;
+ int m_FileDescriptor;
+ size_t m_FileSize;
+ int m_AccessFlags;
+ int m_State;
+
+ SpaceList m_SpaceList;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/MemoryAreaFactory.h b/include/mcld/Support/MemoryAreaFactory.h
new file mode 100644
index 0000000..f9ffa6e
--- /dev/null
+++ b/include/mcld/Support/MemoryAreaFactory.h
@@ -0,0 +1,64 @@
+//===- MemoryAreaFactory.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MEMORY_AREA_FACTORY_H
+#define MCLD_MEMORY_AREA_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Support/UniqueGCFactory.h"
+#include "mcld/Support/MemoryArea.h"
+#include "mcld/Support/Path.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+namespace mcld
+{
+
+class RegionFactory;
+/** \class MemoryAreaFactory
+ * \brief MemoryAreaFactory avoids creating duplicated MemoryAreas of the
+ * same file.
+ *
+ * Users can give duplicated input files on the command line. In order to
+ * prevent opening the same file twice, and create redundant MemoryRegions,
+ * mcld::Input should not create MemoryArea directly. Instead, it should ask
+ * MemoryAreaFactory and get the unique MemoryArea.
+ *
+ * The timing of opening and closing files is not strictly bound to the
+ * constructor and destructor of MCLDFile. For mcld::Output, MCLinker
+ * opens the file rather after assigning offset to sections. On the other
+ * aside, mcld::Input opens the file at constructor. In order to hide the
+ * file operations, MemoryAreaFactory actually open the file untill the first
+ * MemoryRegion is requested.
+ *
+ * @see MemoryRegion
+ * @see UniqueGCFactoryBase
+ */
+class MemoryAreaFactory : public UniqueGCFactoryBase<sys::fs::Path, MemoryArea, 0>
+{
+public:
+ explicit MemoryAreaFactory(size_t pNum);
+ ~MemoryAreaFactory();
+
+ // produce - create a MemoryArea and open its file
+ // If the file fails to be opened, the returned MemoryArea::isMapped()
+ // should be false
+ MemoryArea* produce(const sys::fs::Path& pPath, int pFlags);
+ MemoryArea* produce(const sys::fs::Path& pPath, int pFlags, mode_t pMode);
+
+private:
+ RegionFactory* m_pRegionFactory;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/MemoryRegion.h b/include/mcld/Support/MemoryRegion.h
new file mode 100644
index 0000000..49f5fda
--- /dev/null
+++ b/include/mcld/Support/MemoryRegion.h
@@ -0,0 +1,97 @@
+//===- MemoryRegion.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_MEMORY_REGION_H
+#define LD_MEMORY_REGION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/ADT/Uncopyable.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/ADT/TypeTraits.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MemoryArea.h>
+#include <llvm/ADT/ilist.h>
+#include <llvm/ADT/StringRef.h>
+
+namespace mcld
+{
+
+/** \class MemoryRegion
+ * \brief MemoryRegion is a range of virtual memory which is mapped onto a
+ * range of files which is opened by MemoryArea.
+ *
+ * MemoryArea maps a file onto virtual memory. Clients can get a range of
+ * mapped memory space by requesting a MemoryRegion from MemoryArea, and
+ * read/write the mapped file through the MemoryRegion.
+ *
+ * When two different MemoryRegion may overlap memory space, race condition
+ * may occurs. Clients must call MemoryRegion::sync() explicit to tell the
+ * MemoryArea when to synchronize the virtual memory space with the mapped
+ * file.
+ */
+class MemoryRegion : private Uncopyable
+{
+friend class RegionFactory;
+friend class MemoryArea;
+
+public:
+typedef NonConstTraits<mcld::sys::fs::detail::Address>::value_type Address;
+typedef ConstTraits<mcld::sys::fs::detail::Address>::value_type ConstAddress;
+typedef NonConstTraits<mcld::sys::fs::detail::Offset>::value_type Offset;
+typedef ConstTraits<mcld::sys::fs::detail::Offset>::value_type ConstOffset;
+
+private:
+ MemoryRegion(MemoryArea::Space* pParentSpace,
+ const Address pVMAStart,
+ size_t pSize);
+
+ // drift - leave parent space
+ void drift();
+
+ MemoryArea::Space* parent()
+ { return m_pParentSpace; }
+
+ const MemoryArea::Space* parent() const
+ { return m_pParentSpace; }
+
+public:
+ ~MemoryRegion();
+
+ Address start()
+ { return m_VMAStart; }
+
+ ConstAddress start() const
+ { return m_VMAStart; }
+
+ Address end()
+ { return m_VMAStart+m_Length; }
+
+ ConstAddress end() const
+ { return m_VMAStart+m_Length; }
+
+ size_t size() const
+ { return m_Length; }
+
+ Address getBuffer(Offset pOffset = 0)
+ { return m_VMAStart+pOffset; }
+
+ ConstAddress getBuffer(Offset pOffset = 0) const
+ { return m_VMAStart+pOffset; }
+
+private:
+ MemoryArea::Space* m_pParentSpace;
+ Address m_VMAStart;
+ size_t m_Length;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/Path.h b/include/mcld/Support/Path.h
new file mode 100644
index 0000000..f5ee56c
--- /dev/null
+++ b/include/mcld/Support/Path.h
@@ -0,0 +1,179 @@
+//===- Path.h -------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file declares the mcld::sys::fs:: namespace. It follows TR2/boost
+// filesystem (v3), but modified to remove exception handling and the
+// path class.
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_PATH_H
+#define MCLD_PATH_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/raw_ostream.h>
+#include <functional>
+#include <string>
+
+//#include "mcld/Support/Directory.h"
+namespace mcld {
+namespace sys {
+namespace fs {
+
+#ifdef LLVM_ON_WIN32
+const wchar_t separator = L'\\';
+const wchar_t preferred_separator = L'\\';
+#else
+const char separator = '/';
+const char preferred_separator = '/';
+#endif
+
+/** \class Path
+ * \brief Path provides an abstraction for the path to a file or directory in
+ * the operating system's filesystem.
+ *
+ * FIXME: current Path library only support UTF-8 chararcter set.
+ *
+ */
+class Path
+{
+public:
+#ifdef LLVM_ON_WIN32
+ typedef wchar_t ValueType;
+#else
+ typedef char ValueType;
+#endif
+ typedef std::basic_string<ValueType> StringType;
+
+public:
+ Path();
+ Path(const ValueType* s);
+ Path(const StringType &s);
+ Path(const Path& pCopy);
+ virtual ~Path();
+
+ // ----- assignments ----- //
+ template <class InputIterator>
+ Path& assign(InputIterator begin, InputIterator end);
+ Path& assign(const StringType &s);
+ Path& assign(const ValueType* s, unsigned int length);
+
+ // ----- appends ----- //
+ template <class InputIterator>
+ Path& append(InputIterator begin, InputIterator end);
+ Path& append(const Path& pPath);
+
+ // ----- observers ----- //
+ bool empty() const;
+
+ bool isFromRoot() const;
+ bool isFromPWD() const;
+
+ const StringType &native() const
+ { return m_PathName; }
+
+ StringType &native()
+ { return m_PathName; }
+
+ const ValueType* c_str() const
+ { return m_PathName.c_str(); }
+
+ std::string string() const;
+
+ // ----- decomposition ----- //
+ Path stem() const;
+ Path extension() const;
+
+ // ----- generic form observers ----- //
+ StringType generic_string() const;
+ bool canonicalize();
+
+public:
+ StringType::size_type m_append_separator_if_needed();
+ void m_erase_redundant_separator(StringType::size_type sep_pos);
+
+protected:
+ StringType m_PathName;
+};
+
+bool operator==(const Path& pLHS,const Path& pRHS);
+bool operator!=(const Path& pLHS,const Path& pRHS);
+
+//--------------------------------------------------------------------------//
+// non-member functions //
+//--------------------------------------------------------------------------//
+
+/// is_separator - is the given character a separator of a path.
+// @param value a character
+// @result true if \a value is a path separator character on the host OS
+//bool status_known(FileStatus f) { return f.type() != StatusError; }
+
+bool is_separator(char value);
+
+bool exists(const Path &pPath);
+
+bool is_directory(const Path &pPath);
+
+
+std::ostream &operator<<(std::ostream& pOS, const Path& pPath);
+
+std::istream &operator>>(std::istream& pOS, Path& pPath);
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Path &pPath);
+
+
+//--------------------------------------------------------------------------------------//
+// class path member template implementation //
+//--------------------------------------------------------------------------------------//
+template <class InputIterator>
+Path& Path::assign(InputIterator begin, InputIterator end)
+{
+ m_PathName.clear();
+ if (begin != end)
+ m_PathName.append<InputIterator>(begin, end);
+ return *this;
+}
+
+template <class InputIterator>
+Path& Path::append(InputIterator begin, InputIterator end)
+{
+ if (begin == end)
+ return *this;
+ StringType::size_type sep_pos(m_append_separator_if_needed());
+ m_PathName.append<InputIterator>(begin, end);
+ if (sep_pos)
+ m_erase_redundant_separator(sep_pos);
+ return *this;
+}
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+//-------------------------------------------------------------------------//
+// STL compatible functions //
+//-------------------------------------------------------------------------//
+namespace std {
+
+template<>
+struct less<mcld::sys::fs::Path> : public binary_function<mcld::sys::fs::Path,
+ mcld::sys::fs::Path,
+ bool>
+{
+ bool operator() (const mcld::sys::fs::Path& pX,const mcld::sys::fs::Path& pY) const {
+ if (pX.generic_string().size() < pY.generic_string().size())
+ return true;
+ return (pX.generic_string() < pY.generic_string());
+ }
+};
+
+} // namespace of std
+
+#endif
+
diff --git a/include/mcld/Support/PathCache.h b/include/mcld/Support/PathCache.h
new file mode 100644
index 0000000..89ec513
--- /dev/null
+++ b/include/mcld/Support/PathCache.h
@@ -0,0 +1,38 @@
+//===- PathCache.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_PATHCACHE_H
+#define MCLD_PATHCACHE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/ADT/HashEntry.h"
+#include "mcld/ADT/HashTable.h"
+#include "mcld/ADT/StringHash.h"
+#include "mcld/Support/Path.h"
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+namespace {
+ typedef HashEntry<llvm::StringRef,
+ mcld::sys::fs::Path*,
+ StringCompare<llvm::StringRef> > HashEntryType;
+} // anonymous namespace
+
+typedef HashTable<HashEntryType, StringHash<BKDR>, EntryFactory<HashEntryType> > PathCache;
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/PositionDependentOption.h b/include/mcld/Support/PositionDependentOption.h
new file mode 100644
index 0000000..b5d60e8
--- /dev/null
+++ b/include/mcld/Support/PositionDependentOption.h
@@ -0,0 +1,63 @@
+//===- PositionDependentOption.h ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_POSITIONDEPENDENTOPTION_H
+#define MCLD_POSITIONDEPENDENTOPTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <vector>
+
+namespace mcld
+{
+
+ /** \class PositionDependentOption
+ * \brief PositionDependentOptions converts LLVM options into MCLDInfo
+ */
+ class PositionDependentOption
+ {
+ public:
+ enum Type {
+ BITCODE,
+ NAMESPEC,
+ INPUT_FILE,
+ START_GROUP,
+ END_GROUP,
+ WHOLE_ARCHIVE,
+ NO_WHOLE_ARCHIVE,
+ AS_NEEDED,
+ NO_AS_NEEDED,
+ ADD_NEEDED,
+ NO_ADD_NEEDED,
+ BDYNAMIC,
+ BSTATIC
+ };
+
+ protected:
+ PositionDependentOption(unsigned pPosition, Type pType)
+ : m_Type(pType),
+ m_Position(pPosition) {}
+
+ public:
+ inline const Type& type() const
+ { return m_Type; }
+
+ inline unsigned position() const
+ { return m_Position; }
+
+ private:
+ Type m_Type;
+ unsigned m_Position;
+ };
+
+ typedef std::vector<PositionDependentOption*> PositionDependentOptions;
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/RealPath.h b/include/mcld/Support/RealPath.h
new file mode 100644
index 0000000..6c0cd40
--- /dev/null
+++ b/include/mcld/Support/RealPath.h
@@ -0,0 +1,72 @@
+//===- RealPath.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_REAL_PATH_H
+#define MCLD_REAL_PATH_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/Path.h"
+#include <string>
+
+namespace mcld {
+namespace sys {
+namespace fs {
+
+/** \class RealPath
+ * \brief The canonicalized absolute pathname.
+ *
+ */
+class RealPath : public Path
+{
+public:
+ typedef Path::ValueType ValueType;
+ typedef Path::StringType StringType;
+
+public:
+ RealPath();
+ explicit RealPath(const ValueType* s );
+ explicit RealPath(const StringType &s );
+ explicit RealPath(const Path& pPath);
+
+ ~RealPath();
+
+ RealPath& assign(const Path& pPath);
+
+protected:
+ void initialize();
+};
+
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
+//-------------------------------------------------------------------------//
+// STL compatible functions //
+//-------------------------------------------------------------------------//
+namespace std {
+
+template<>
+struct less<mcld::sys::fs::RealPath> : public binary_function<
+ mcld::sys::fs::RealPath,
+ mcld::sys::fs::RealPath,
+ bool>
+{
+ bool operator() (const mcld::sys::fs::RealPath& pX,
+ const mcld::sys::fs::RealPath& pY) const {
+ if (pX.native().size() < pY.native().size())
+ return true;
+ return (pX.native() < pY.native());
+ }
+};
+
+} // namespace of std
+
+
+#endif
+
diff --git a/include/mcld/Support/RegionFactory.h b/include/mcld/Support/RegionFactory.h
new file mode 100644
index 0000000..ba9a88d
--- /dev/null
+++ b/include/mcld/Support/RegionFactory.h
@@ -0,0 +1,48 @@
+//===- RegionFactory.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_REGION_FACTORY_H
+#define MCLD_REGION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/Support/GCFactory.h"
+#include "mcld/Support/MemoryRegion.h"
+#include "mcld/Support/MemoryArea.h"
+#include "mcld/Support/FileSystem.h"
+
+namespace mcld
+{
+
+class MemoryArea;
+
+/** \class RegionFactory
+ * \brief RegionFactory produces and destroys MemoryRegions
+ *
+ */
+class RegionFactory : public GCFactory<MemoryRegion, 0>
+{
+public:
+ typedef GCFactory<MemoryRegion, 0> Alloc;
+
+public:
+ RegionFactory(size_t pNum);
+ ~RegionFactory();
+
+ // ----- production ----- //
+ MemoryRegion* produce(MemoryArea::Space* pSpace,
+ const sys::fs::detail::Address pVMAStart,
+ size_t pSize);
+
+ void destruct(MemoryRegion* pRegion);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/TargetRegistry.h b/include/mcld/Support/TargetRegistry.h
new file mode 100644
index 0000000..a9ad875
--- /dev/null
+++ b/include/mcld/Support/TargetRegistry.h
@@ -0,0 +1,230 @@
+//===- TargetRegistry.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGET_REGISTRY_H
+#define TARGET_REGISTRY_H
+#include <llvm/Support/TargetRegistry.h>
+#include <string>
+#include <list>
+
+namespace llvm {
+class TargetMachine;
+class MCCodeEmitter;
+class MCContext;
+class AsmPrinter;
+} // namespace of llvm
+
+namespace mcld {
+class LLVMTargetMachine;
+class TargetRegistry;
+class SectLinker;
+class SectLinkerOption;
+class TargetLDBackend;
+class AttributeFactory;
+class InputFactory;
+class ContextFactory;
+
+//===----------------------------------------------------------------------===//
+/// Target - mcld::Target is an object adapter of llvm::Target
+///
+class Target
+{
+ friend class mcld::LLVMTargetMachine;
+ friend class mcld::TargetRegistry;
+public:
+ typedef mcld::LLVMTargetMachine *(*TargetMachineCtorTy)(const mcld::Target &,
+ llvm::TargetMachine &,
+ const std::string&);
+
+ typedef SectLinker *(*SectLinkerCtorTy)(const std::string& pTriple,
+ SectLinkerOption &,
+ TargetLDBackend&);
+
+ typedef TargetLDBackend *(*TargetLDBackendCtorTy)(const llvm::Target&,
+ const std::string&);
+
+private:
+ TargetMachineCtorTy TargetMachineCtorFn;
+ SectLinkerCtorTy SectLinkerCtorFn;
+ TargetLDBackendCtorTy TargetLDBackendCtorFn;
+
+public:
+ Target();
+
+ void setTarget(const llvm::Target& pTarget) {
+ m_pT = &pTarget;
+ }
+
+ mcld::LLVMTargetMachine *createTargetMachine(const std::string &pTriple,
+ const std::string &pCPU, const std::string &pFeatures,
+ const llvm::TargetOptions &Options,
+ llvm::Reloc::Model RM = llvm::Reloc::Default,
+ llvm::CodeModel::Model CM = llvm::CodeModel::Default,
+ llvm::CodeGenOpt::Level OL = llvm::CodeGenOpt::Default) const {
+ if (TargetMachineCtorFn && m_pT) {
+ llvm::TargetMachine *tm = m_pT->createTargetMachine(pTriple, pCPU, pFeatures, Options, RM, CM, OL);
+ if (tm)
+ return TargetMachineCtorFn(*this, *tm, pTriple);
+ }
+ return 0;
+ }
+
+ /// createSectLinker - create target-specific SectLinker
+ ///
+ /// @return created SectLinker
+ SectLinker *createSectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend) const {
+ if (!SectLinkerCtorFn)
+ return 0;
+ return SectLinkerCtorFn(pTriple,
+ pOption,
+ pLDBackend);
+ }
+
+ /// createLDBackend - create target-specific LDBackend
+ ///
+ /// @return created TargetLDBackend
+ TargetLDBackend *createLDBackend(const llvm::Target& T, const std::string& Triple) const {
+ if (!TargetLDBackendCtorFn)
+ return 0;
+ return TargetLDBackendCtorFn(T, Triple);
+ }
+
+ const llvm::Target* get() const {
+ return m_pT;
+ }
+
+private:
+ const llvm::Target* m_pT;
+};
+
+//===----------------------------------------------------------------------===//
+/// TargetRegistry - mcld::TargetRegistry is an object adapter of
+/// llvm::TargetRegistry
+///
+class TargetRegistry
+{
+public:
+ typedef std::list<mcld::Target*> TargetListTy;
+ typedef TargetListTy::iterator iterator;
+
+private:
+ static TargetListTy s_TargetList;
+
+public:
+ static iterator begin() { return s_TargetList.begin(); }
+ static iterator end() { return s_TargetList.end(); }
+
+ static size_t size() { return s_TargetList.size(); }
+ static bool empty() { return s_TargetList.empty(); }
+
+ /// RegisterTarget - Register the given target. Attempts to register a
+ /// target which has already been registered will be ignored.
+ ///
+ /// Clients are responsible for ensuring that registration doesn't occur
+ /// while another thread is attempting to access the registry. Typically
+ /// this is done by initializing all targets at program startup.
+ ///
+ /// @param T - The target being registered.
+ static void RegisterTarget(mcld::Target &T);
+
+ /// RegisterTargetMachine - Register a TargetMachine implementation for the
+ /// given target.
+ ///
+ /// @param T - The target being registered.
+ /// @param Fn - A function to construct a TargetMachine for the target.
+ static void RegisterTargetMachine(mcld::Target &T, mcld::Target::TargetMachineCtorTy Fn) {
+ // Ignore duplicate registration.
+ if (!T.TargetMachineCtorFn)
+ T.TargetMachineCtorFn = Fn;
+ }
+
+ /// RegisterSectLinker - Register a SectLinker implementation for the given
+ /// target.
+ ///
+ /// @param T - the target being registered
+ /// @param Fn - A function to create SectLinker for the target
+ static void RegisterSectLinker(mcld::Target &T, mcld::Target::SectLinkerCtorTy Fn) {
+ if (!T.SectLinkerCtorFn)
+ T.SectLinkerCtorFn = Fn;
+ }
+
+ /// RegisterTargetLDBackend - Register a TargetLDBackend implementation for
+ /// the given target.
+ ///
+ /// @param T - The target being registered
+ /// @param Fn - A function to create TargetLDBackend for the target
+ static void RegisterTargetLDBackend(mcld::Target &T, mcld::Target::TargetLDBackendCtorTy Fn) {
+ if (!T.TargetLDBackendCtorFn)
+ T.TargetLDBackendCtorFn = Fn;
+ }
+
+ /// lookupTarget - Lookup a target based on a llvm::Target.
+ ///
+ /// @param T - The llvm::Target to find
+ static const mcld::Target *lookupTarget(const llvm::Target& T);
+
+ /// lookupTarget - function wrapper of llvm::TargetRegistry::lookupTarget
+ ///
+ /// @param Triple - The Triple string
+ /// @param Error - The returned error message
+ static const mcld::Target *lookupTarget(const std::string &Triple,
+ std::string &Error);
+};
+
+/// RegisterTarget - Helper function for registering a target, for use in the
+/// target's initialization function. Usage:
+///
+/// Target TheFooTarget; // The global target instance.
+///
+/// extern "C" void LLVMInitializeFooTargetInfo() {
+/// RegisterTarget X(TheFooTarget, "foo", "Foo description");
+/// }
+struct RegisterTarget
+{
+ RegisterTarget(mcld::Target &T, const char *Name) {
+ llvm::TargetRegistry::iterator TIter, TEnd = llvm::TargetRegistry::end();
+ // lookup llvm::Target
+ for( TIter=llvm::TargetRegistry::begin(); TIter!=TEnd; ++TIter ) {
+ if( 0==strcmp(TIter->getName(), Name) )
+ break;
+ }
+ T.setTarget(*TIter);
+
+ TargetRegistry::RegisterTarget(T);
+ }
+};
+
+/// RegisterTargetMachine - Helper template for registering a target machine
+/// implementation, for use in the target machine initialization
+/// function. Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+/// extern mcld::Target TheFooTarget;
+/// RegisterTargetMachine<mcld::FooTargetMachine> X(TheFooTarget);
+/// }
+template<class TargetMachineImpl>
+struct RegisterTargetMachine
+{
+ RegisterTargetMachine(mcld::Target &T) {
+ TargetRegistry::RegisterTargetMachine(T, &Allocator);
+ }
+
+private:
+ static mcld::LLVMTargetMachine *Allocator(const mcld::Target &T,
+ llvm::TargetMachine& TM,
+ const std::string &Triple) {
+ return new TargetMachineImpl(TM, T, Triple);
+ }
+};
+
+} //end namespace mcld
+
+#endif
+
diff --git a/include/mcld/Support/TargetSelect.h b/include/mcld/Support/TargetSelect.h
new file mode 100644
index 0000000..e040ae2
--- /dev/null
+++ b/include/mcld/Support/TargetSelect.h
@@ -0,0 +1,77 @@
+//===- TargetSelect.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGETSELECT_H
+#define TARGETSELECT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+extern "C" {
+ // Declare all of the target-initialization functions that are available.
+#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##LDTargetInfo();
+#include "mcld/Config/Targets.def"
+
+ // Declare all of the target-dependent functions that are available.
+#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##LDTarget();
+#include "mcld/Config/Targets.def"
+
+ // Declare all of the target-depedent linker information
+#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##LDInfo();
+#include "mcld/Config/Linkers.def"
+
+ // Declare all of the available linker environment.
+#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##SectLinker();
+#include "mcld/Config/Linkers.def"
+
+ // Declare all of the available target-specific linker
+#define LLVM_LINKER(TargetName) void LLVMInitialize##TargetName##LDBackend();
+#include "mcld/Config/Linkers.def"
+} // extern "C"
+
+namespace mcld
+{
+ /// InitializeAllTargetInfos - The main program should call this function if
+ /// it wants access to all available targets that LLVM is configured to
+ /// support, to make them available via the TargetRegistry.
+ ///
+ /// It is legal for a client to make multiple calls to this function.
+ inline void InitializeAllTargetInfos() {
+#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##LDTargetInfo();
+#include "mcld/Config/Targets.def"
+ }
+
+ /// InitializeAllTargets - The main program should call this function if it
+ /// wants access to all available target machines that LLVM is configured to
+ /// support, to make them available via the TargetRegistry.
+ ///
+ /// It is legal for a client to make multiple calls to this function.
+ inline void InitializeAllTargets() {
+ mcld::InitializeAllTargetInfos();
+
+#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##LDTarget();
+#include "mcld/Config/Targets.def"
+ }
+
+ /// InitializeAllLinkers - The main program should call this function if it
+ /// wants all linkers that LLVM is configured to support, to make them
+ /// available via the TargetRegistry.
+ ///
+ /// It is legal for a client to make multiple calls to this function.
+ inline void InitializeAllLinkers() {
+#define LLVM_LINKER(TargetName) LLVMInitialize##TargetName##SectLinker();
+#include "mcld/Config/Linkers.def"
+
+#define LLVM_LINKER(TargetName) LLVMInitialize##TargetName##LDBackend();
+#include "mcld/Config/Linkers.def"
+ }
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Support/UniqueGCFactory.h b/include/mcld/Support/UniqueGCFactory.h
new file mode 100644
index 0000000..3147bab
--- /dev/null
+++ b/include/mcld/Support/UniqueGCFactory.h
@@ -0,0 +1,94 @@
+//===- UniqueGCFactory.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_UNIQUE_GCFACTORY_H
+#define MCLD_UNIQUE_GCFACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Support/GCFactory.h"
+#include <map>
+#include <utility>
+
+namespace mcld
+{
+
+/** \class UniqueGCFactoryBase
+ * \brief UniqueGCFactories are unique associative factories, meaning that
+ * no two elements have the same key.
+ */
+template<typename KeyType, typename DataType, size_t ChunkSize>
+class UniqueGCFactoryBase : public GCFactoryBase<LinearAllocator<DataType, ChunkSize> >
+{
+protected:
+ typedef GCFactoryBase<LinearAllocator<DataType, ChunkSize> > Alloc;
+ typedef std::map<KeyType, DataType*> KeyMap;
+
+protected:
+ UniqueGCFactoryBase()
+ : GCFactoryBase<LinearAllocator<DataType, ChunkSize> >()
+ { }
+
+ UniqueGCFactoryBase(size_t pNum)
+ : GCFactoryBase<LinearAllocator<DataType, ChunkSize> >(pNum)
+ { }
+
+public:
+ virtual ~UniqueGCFactoryBase()
+ { f_KeyMap.clear(); }
+
+ DataType* find(const KeyType& pKey) {
+ typename KeyMap::iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end())
+ return dataIter->second;
+ return 0;
+ }
+
+ const DataType* find(const KeyType& pKey) const {
+ typename KeyMap::const_iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end())
+ return dataIter->second;
+ return 0;
+ }
+
+ DataType* produce(const KeyType& pKey, bool& pExist) {
+ typename KeyMap::iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end()) {
+ pExist = true;
+ return dataIter->second;
+ }
+ DataType* data = Alloc::allocate();
+ construct(data);
+ f_KeyMap.insert(std::make_pair(pKey, data));
+ pExist = false;
+ return data;
+ }
+
+ DataType* produce(const KeyType& pKey, const DataType& pValue, bool& pExist) {
+ typename KeyMap::iterator dataIter = f_KeyMap.find(pKey);
+ if (dataIter != f_KeyMap.end()) {
+ pExist = true;
+ return dataIter->second;
+ }
+ DataType* data = Alloc::allocate();
+ construct(data, pValue);
+ f_KeyMap.insert(std::make_pair(pKey, data));
+ pExist = false;
+ return data;
+ }
+
+protected:
+ KeyMap f_KeyMap;
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/AndroidSectLinker.h b/include/mcld/Target/AndroidSectLinker.h
new file mode 100644
index 0000000..dd68ff2
--- /dev/null
+++ b/include/mcld/Target/AndroidSectLinker.h
@@ -0,0 +1,42 @@
+//===- AndroidSectLinker.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AndroidSectLinker is a customized linker pass for Android platform.
+// This pass set up default parameters for Android.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ANDROID_SECTLINKER_H
+#define ANDROID_SECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+class AndroidSectLinker : public SectLinker
+{
+public:
+ AndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ virtual ~AndroidSectLinker();
+
+ // addTargetInputs - add Android-specific linker options
+ virtual void addTargetOptions(llvm::Module &pM,
+ SectLinkerOption &pOption);
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/DarwinLDBackend.h b/include/mcld/Target/DarwinLDBackend.h
new file mode 100644
index 0000000..d55055a
--- /dev/null
+++ b/include/mcld/Target/DarwinLDBackend.h
@@ -0,0 +1,31 @@
+//===- DarwinLDBackend.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DARWINLDBACKEND_H
+#define DARWINLDBACKEND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class DarwinLDBackend
+ * \brief DarwinLDBackend provides a common interface for all Darwin OS LDBackend.
+ *
+ * \see
+ */
+class DarwinLDBackend
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/ELFDynamic.h b/include/mcld/Target/ELFDynamic.h
new file mode 100644
index 0000000..ed18dc0
--- /dev/null
+++ b/include/mcld/Target/ELFDynamic.h
@@ -0,0 +1,174 @@
+//===- ELFDynamic.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ELF_DYNAMIC_SECTION_H
+#define MCLD_ELF_DYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/ELF.h>
+#include <mcld/LD/LDSection.h>
+#include <vector>
+#include <cstring>
+
+namespace mcld
+{
+
+class GNULDBackend;
+class ELFFileFormat;
+class MCLDInfo;
+class MemoryRegion;
+
+namespace elf_dynamic {
+
+/** \class EntryIF
+* \brief EntryIF provides a common interface for one entry in the dynamic
+* section
+*/
+class EntryIF
+{
+protected:
+ EntryIF();
+
+public:
+ virtual ~EntryIF();
+
+ virtual EntryIF* clone() const = 0;
+ virtual size_t size() const = 0;
+ virtual size_t symbolSize() const = 0;
+ virtual size_t relSize() const = 0;
+ virtual size_t relaSize() const = 0;
+ virtual size_t emit(uint8_t* pAddress) const = 0;
+ virtual void setValue(uint64_t pTag, uint64_t pValue) = 0;
+};
+
+template<size_t BITNUMBER, bool LITTLEENDIAN>
+class Entry
+{ };
+
+template<>
+class Entry<32, true> : public EntryIF
+{
+public:
+ typedef llvm::ELF::Elf32_Dyn Pair;
+ typedef llvm::ELF::Elf32_Sym Symbol;
+ typedef llvm::ELF::Elf32_Rel Rel;
+ typedef llvm::ELF::Elf32_Rela Rela;
+
+public:
+ inline Entry();
+
+ inline ~Entry();
+
+ Entry* clone() const
+ { return new Entry(); }
+
+ size_t size() const
+ { return sizeof(Pair); }
+
+ size_t symbolSize() const
+ { return sizeof(Symbol); }
+
+ size_t relSize() const
+ { return sizeof(Rel); }
+
+ size_t relaSize() const
+ { return sizeof(Rela); }
+
+ inline void setValue(uint64_t pTag, uint64_t pValue);
+
+ inline size_t emit(uint8_t* pAddress) const;
+
+private:
+ Pair m_Pair;
+};
+
+#include "ELFDynamic.tcc"
+
+} // namespace of elf_dynamic
+
+/** \class ELFDynamic
+ * \brief ELFDynamic is the .dynamic section in ELF shared and executable
+ * files.
+ */
+class ELFDynamic
+{
+public:
+ typedef std::vector<elf_dynamic::EntryIF*> EntryListType;
+ typedef EntryListType::iterator iterator;
+ typedef EntryListType::const_iterator const_iterator;
+
+public:
+ ELFDynamic(const GNULDBackend& pParent);
+
+ virtual ~ELFDynamic();
+
+ size_t size() const;
+
+ size_t entrySize() const;
+
+ size_t numOfBytes() const;
+
+ /// reserveEntries - reserve entries
+ void reserveEntries(const MCLDInfo& pInfo,
+ const ELFFileFormat& pFormat);
+
+ /// reserveNeedEntry - reserve on DT_NEED entry.
+ void reserveNeedEntry();
+
+ /// applyEntries - apply entries
+ void applyEntries(const MCLDInfo& pInfo,
+ const ELFFileFormat& pFormat);
+
+ void applySoname(uint64_t pStrTabIdx);
+
+ iterator needBegin()
+ { return m_NeedList.begin(); }
+
+ iterator needEnd()
+ { return m_NeedList.end(); }
+
+ const_iterator needBegin() const
+ { return m_NeedList.begin(); }
+
+ const_iterator needEnd() const
+ { return m_NeedList.end(); }
+
+ /// emit
+ void emit(const LDSection& pSection, MemoryRegion& pRegion) const;
+
+protected:
+ /// reserveTargetEntries - reserve target dependent entries
+ virtual void reserveTargetEntries(const ELFFileFormat& pFormat) = 0;
+
+ /// applyTargetEntries - apply target-dependant
+ virtual void applyTargetEntries(const ELFFileFormat& pFormat) = 0;
+
+protected:
+ void reserveOne(uint64_t pTag);
+
+ void applyOne(uint64_t pTag, uint64_t pValue);
+
+ size_t symbolSize() const;
+
+private:
+ EntryListType m_EntryList;
+ EntryListType m_NeedList;
+ elf_dynamic::EntryIF* m_pEntryFactory;
+
+ // The entry reserved and the entry being applied are not must matched.
+ // For better performance, we use a simple counter and apply entry one-by-one
+ // by the counter. m_Idx is the counter indicating to the entry being applied.
+ size_t m_Idx;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/ELFDynamic.tcc b/include/mcld/Target/ELFDynamic.tcc
new file mode 100644
index 0000000..8b04651
--- /dev/null
+++ b/include/mcld/Target/ELFDynamic.tcc
@@ -0,0 +1,33 @@
+//===- ELFDynamic.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+Entry<32, true>::Entry()
+{
+ m_Pair.d_tag = 0;
+ m_Pair.d_un.d_val = 0;
+}
+
+Entry<32, true>::~Entry()
+{
+}
+
+void Entry<32, true>::setValue(uint64_t pTag, uint64_t pValue)
+{
+ m_Pair.d_tag = pTag;
+ m_Pair.d_un.d_val = pValue;
+}
+
+size_t Entry<32, true>::emit(uint8_t* pAddress) const
+{
+ memcpy(reinterpret_cast<void*>(pAddress),
+ reinterpret_cast<const void*>(&m_Pair),
+ sizeof(Pair));
+ return sizeof(Pair);
+}
+
diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h
new file mode 100644
index 0000000..7f51448
--- /dev/null
+++ b/include/mcld/Target/GNULDBackend.h
@@ -0,0 +1,322 @@
+//===- GNULDBackend.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_GNU_LDBACKEND_H
+#define MCLD_TARGET_GNU_LDBACKEND_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/Support/ELF.h>
+#include <mcld/ADT/HashTable.h>
+#include <mcld/ADT/HashEntry.h>
+#include <mcld/LD/ELFDynObjReader.h>
+#include <mcld/LD/ELFDynObjWriter.h>
+#include <mcld/LD/ELFObjectReader.h>
+#include <mcld/LD/ELFObjectWriter.h>
+#include <mcld/LD/ELFDynObjFileFormat.h>
+#include <mcld/LD/ELFExecFileFormat.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/GNUArchiveReader.h>
+#include <mcld/Support/GCFactory.h>
+#include <mcld/Target/ELFDynamic.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <mcld/LD/ELFSegmentFactory.h>
+
+namespace mcld
+{
+
+struct SymCompare
+{
+ bool operator()(const LDSymbol* X, const LDSymbol* Y) const
+ { return (X==Y); }
+};
+
+struct PtrHash
+{
+ size_t operator()(const LDSymbol* pKey) const
+ {
+ return (unsigned((uintptr_t)pKey) >> 4) ^
+ (unsigned((uintptr_t)pKey) >> 9);
+ }
+};
+
+class MCLDInfo;
+class Layout;
+class SymbolCategory;
+
+/** \class GNULDBackend
+ * \brief GNULDBackend provides a common interface for all GNU Unix-OS
+ * LDBackend.
+ */
+class GNULDBackend : public TargetLDBackend
+{
+ // These dynamic section tags are GNU extension.
+ enum {
+ DT_RELACOUNT = 0x6ffffff9,
+ DT_RELCOUNT = 0x6ffffffa,
+ DT_FLAGS_1 = 0x6ffffffb,
+ DT_VERDEF = 0x6ffffffc,
+ DT_VERDEFNUM = 0x6ffffffd,
+ DT_VERNEED = 0x6ffffffe,
+ DT_VERNEEDNUM = 0x6fffffff
+ };
+
+protected:
+ // Based on Kind in LDFileFormat to define basic section orders for ELF, and
+ // refer gold linker to add more enumerations to handle Regular and BSS kind
+ enum SectionOrder {
+ SHO_INTERP = 1, // .interp
+ SHO_RO_NOTE, // .note.ABI-tag, .note.gnu.build-id
+ SHO_NAMEPOOL, // *.hash, .dynsym, .dynstr
+ SHO_RELOCATION, // .rel.*, .rela.*
+ SHO_REL_PLT, // .rel.plt should come after other .rel.*
+ SHO_INIT, // .init
+ SHO_PLT, // .plt
+ SHO_TEXT, // .text
+ SHO_FINI, // .fini
+ SHO_RO, // .rodata
+ SHO_EHFRAME, // .eh_frame_hdr, .eh_frame
+ SHO_TLS_DATA, // .tdata
+ SHO_TLS_BSS, // .tbss
+ SHO_RELRO_LOCAL, // .data.rel.ro.local
+ SHO_RELRO, // .data.rel.ro,
+ SHO_RELRO_LAST, // for x86 to adjust .got if needed
+ SHO_NON_RELRO_FIRST, // for x86 to adjust .got.plt if needed
+ SHO_DATA, // .data
+ SHO_LARGE_DATA, // .ldata
+ SHO_RW_NOTE, //
+ SHO_SMALL_DATA, // .sdata
+ SHO_SMALL_BSS, // .sbss
+ SHO_BSS, // .bss
+ SHO_LARGE_BSS, // .lbss
+ SHO_UNDEFINED = ~(0U) // default order
+ };
+
+protected:
+ GNULDBackend();
+
+public:
+ virtual ~GNULDBackend();
+
+ bool initArchiveReader(MCLinker& pLinker, MCLDInfo& pInfo);
+ bool initObjectReader(MCLinker& pLinker);
+ bool initDynObjReader(MCLinker& pLinker);
+ bool initObjectWriter(MCLinker& pLinker);
+ bool initDynObjWriter(MCLinker& pLinker);
+
+ bool initExecSections(MCLinker& pMCLinker);
+ bool initDynObjSections(MCLinker& pMCLinker);
+
+ bool initStandardSymbols(MCLinker& pLinker);
+
+ GNUArchiveReader *getArchiveReader();
+ GNUArchiveReader *getArchiveReader() const;
+
+ ELFObjectReader *getObjectReader();
+ ELFObjectReader *getObjectReader() const;
+
+ ELFDynObjReader *getDynObjReader();
+ ELFDynObjReader *getDynObjReader() const;
+
+ ELFObjectWriter *getObjectWriter();
+ ELFObjectWriter *getObjectWriter() const;
+
+ ELFDynObjWriter *getDynObjWriter();
+ ELFDynObjWriter *getDynObjWriter() const;
+
+ ELFDynObjFileFormat* getDynObjFileFormat();
+ ELFDynObjFileFormat* getDynObjFileFormat() const;
+
+ ELFExecFileFormat* getExecFileFormat();
+ ELFExecFileFormat* getExecFileFormat() const;
+
+ size_t sectionStartOffset() const;
+
+ /// The return value of machine() it the same as e_machine in the ELF header*/
+ virtual uint32_t machine() const = 0;
+
+ /// ELFVersion - the value of e_ident[EI_VERSION]
+ virtual uint8_t ELFVersion() const
+ { return llvm::ELF::EV_CURRENT; }
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ virtual uint8_t OSABI() const = 0;
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ virtual uint8_t ABIVersion() const = 0;
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ virtual uint64_t flags() const = 0;
+
+ /// entry - the symbol name of the entry point
+ virtual const char* entry() const
+ { return "_start"; }
+
+ /// sizeNamePools - compute the size of regular name pools
+ /// In ELF executable files, regular name pools are .symtab, .strtab.,
+ /// .dynsym, .dynstr, and .hash
+ virtual void sizeNamePools(const Output& pOutput,
+ const SymbolCategory& pSymbols,
+ const MCLDInfo& pLDInfo);
+
+ /// emitSectionData - emit target-dependent section data
+ virtual uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const = 0;
+
+ /// emitRegNamePools - emit regular name pools - .symtab, .strtab
+ virtual void emitRegNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo);
+
+ /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+ virtual void emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo);
+
+ /// getSectionOrder - compute the layout order of the section
+ /// Layout calls this function to get the default order of the pSectHdr.
+ /// If the pSectHdr.type() is LDFileFormat::Target, then getSectionOrder()
+ /// will call getTargetSectionOrder().
+ ///
+ /// If targets favors certain order for general sections, please override
+ /// this function.
+ ///
+ /// @see getTargetSectionOrder
+ virtual unsigned int getSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// getTargetSectionOrder - compute the layout order of target section
+ /// If the target favors certain order for the given gSectHdr, please
+ /// override this function.
+ ///
+ /// By default, this function returns the maximun order, and pSectHdr
+ /// will be the last section to be laid out.
+ virtual unsigned int
+ getTargetSectionOrder(const Output& pOutput, const LDSection& pSectHdr) const
+ { return (unsigned int)-1; }
+
+ /// emitProgramHdrs - emit ELF program headers
+ /// if the target favors other ways to emit program header, please override
+ /// this function
+ virtual void emitProgramHdrs(Output& pOutput);
+
+ /// numOfSegments - return the number of segments
+ /// if the target favors other ways to emit program header, please override
+ /// this function
+ virtual unsigned int numOfSegments() const
+ { return m_ELFSegmentTable.size(); }
+
+ /// pagesize - the page size of the target machine, we set it to 4K here.
+ /// If target favors tht different size of page, please override this function
+ virtual unsigned int pagesize() const
+ { return 0x1000; }
+
+ /// getSymbolIdx - get the symbol index of ouput symbol table
+ size_t getSymbolIdx(LDSymbol* pSymbol) const;
+
+private:
+ /// createProgramHdrs - base on output sections to create the program headers
+ void createProgramHdrs(LDContext& pContext);
+
+ /// writeELF32ProgramHdrs - write out the ELF32 program headers
+ void writeELF32ProgramHdrs(Output& pOutput);
+
+ /// writeELF64ProgramHdrs - write out the ELF64 program headers
+ void writeELF64ProgramHdrs(Output& pOutput);
+
+ /// getSegmentFlag - give a section flag and return the corresponding segment
+ /// flag
+ inline uint32_t getSegmentFlag(const uint32_t pSectionFlag)
+ {
+ uint32_t flag = llvm::ELF::PF_R;
+ if (0 != (pSectionFlag & llvm::ELF::SHF_WRITE))
+ flag |= llvm::ELF::PF_W;
+ if (0 != (pSectionFlag & llvm::ELF::SHF_EXECINSTR))
+ flag |= llvm::ELF::PF_X;
+ return flag;
+ }
+
+ /// preLayout - Backend can do any needed modification before layout
+ void preLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// postLayout -Backend can do any needed modification after layout
+ void postLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+protected:
+ uint64_t getSymbolSize(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolInfo(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolValue(const LDSymbol& pSymbol) const;
+
+ uint64_t getSymbolShndx(const LDSymbol& pSymbol, const Layout& pLayout) const;
+
+private:
+ /// preLayout - Backend can do any needed modification before layout
+ virtual void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// postLayout -Backend can do any needed modification after layout
+ virtual void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// dynamic - the dynamic section of the target machine.
+ virtual ELFDynamic& dynamic() = 0;
+
+ /// dynamic - the dynamic section of the target machine.
+ virtual const ELFDynamic& dynamic() const = 0;
+
+protected:
+ // ----- readers and writers ----- //
+ GNUArchiveReader* m_pArchiveReader;
+ ELFObjectReader* m_pObjectReader;
+ ELFDynObjReader* m_pDynObjReader;
+ ELFObjectWriter* m_pObjectWriter;
+ ELFDynObjWriter* m_pDynObjWriter;
+
+ // ----- file formats ----- //
+ ELFDynObjFileFormat* m_pDynObjFileFormat;
+ ELFExecFileFormat* m_pExecFileFormat;
+
+ // ----- ELF segment factory ----- //
+ ELFSegmentFactory m_ELFSegmentTable;
+
+ // ----- ELF special sections ----- //
+
+protected:
+ /// getHashBucketCount - calculate hash bucket count.
+ /// @ref Google gold linker, dynobj.cc:791
+ static unsigned getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle);
+
+ /// isDynamicSymbol
+ /// @ref Google gold linker: symtab.cc:311
+ static bool isDynamicSymbol(const LDSymbol& pSymbol, const Output& pOutput);
+
+protected:
+ typedef HashEntry<LDSymbol*, size_t, SymCompare> HashEntryType;
+ typedef HashTable<HashEntryType, PtrHash, EntryFactory<HashEntryType> > HashTableType;
+
+ /// m_pSymIndexMap - Map the LDSymbol to its index in the output symbol table
+ HashTableType* m_pSymIndexMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/GOT.h b/include/mcld/Target/GOT.h
new file mode 100644
index 0000000..eb0873a
--- /dev/null
+++ b/include/mcld/Target/GOT.h
@@ -0,0 +1,106 @@
+//===- GOT.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GOT_H
+#define MCLD_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/MC/MCTargetFragment.h>
+
+namespace mcld
+{
+
+class GOT;
+class ResolveInfo;
+
+/** \class GOTEntry
+ * \brief The entry of Global Offset Table
+ */
+class GOTEntry : public MCTargetFragment
+{
+public:
+ explicit GOTEntry(uint64_t pContent, size_t pEntrySize,
+ llvm::MCSectionData* pParent);
+
+ virtual ~GOTEntry();
+
+ uint64_t& getContent()
+ { return f_Content; }
+
+ uint64_t getContent() const
+ { return f_Content; }
+
+ void setContent(uint64_t pValue)
+ { f_Content = pValue; }
+
+ static bool classof(const MCFragment *pFrag)
+ { return pFrag->getKind() == llvm::MCFragment::FT_Target; }
+
+ static bool classof(const GOTEntry* pFrag)
+ { return true; }
+
+ // Override pure virtual function
+ size_t getSize() const
+ { return m_EntrySize; }
+
+protected:
+ uint64_t f_Content;
+ size_t m_EntrySize;
+};
+
+/** \class GOT
+ * \brief The Global Offset Table
+ */
+class GOT
+{
+protected:
+ GOT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ size_t pEntrySize);
+
+public:
+ virtual ~GOT();
+
+ /// entrySize - the number of bytes per entry
+ size_t getEntrySize() const;
+
+ const LDSection& getSection() const
+ { return m_Section; }
+
+ llvm::MCSectionData& getSectionData()
+ { return m_SectionData; }
+
+ const llvm::MCSectionData& getSectionData() const
+ { return m_SectionData; }
+
+public:
+ /// reserveEntry - reseve number of pNum of empty entries
+ /// Before layout, we scan all relocations to determine if GOT entries are
+ /// needed. If an entry is needed, the empty entry is reserved for layout
+ /// to adjust the fragment offset. After that, we fill up the entries when
+ /// applying relocations.
+ virtual void reserveEntry(size_t pNum = 1) = 0;
+
+ /// getEntry - get an empty entry or an exitsted filled entry with pSymbol.
+ /// @param pSymbol - the target symbol
+ /// @param pExist - ture if a filled entry with pSymbol existed, otherwise false.
+ virtual GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist) = 0;
+
+protected:
+ LDSection& m_Section;
+ llvm::MCSectionData& m_SectionData;
+ size_t f_EntrySize;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/OutputRelocSection.h b/include/mcld/Target/OutputRelocSection.h
new file mode 100644
index 0000000..c0cb5ca
--- /dev/null
+++ b/include/mcld/Target/OutputRelocSection.h
@@ -0,0 +1,71 @@
+//===- OutputRelocSection.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef OUTPUTRELOCSECTION_H
+#define OUTPUTRELOCSECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/ADT/DenseMap.h>
+#include <mcld/LD/RelocationFactory.h>
+
+namespace mcld
+{
+
+class ResolveInfo;
+class Relocation;
+
+/** \class OutputRelocSection
+ * \brief Dynamic relocation section for ARM .rel.dyn and .rel.plt
+ */
+class OutputRelocSection
+{
+public:
+ typedef llvm::DenseMap<const ResolveInfo*, Relocation*> SymRelMapType;
+ typedef SymRelMapType::iterator SymRelMapIterator;
+
+ typedef llvm::MCSectionData::iterator MCFragmentIterator;
+
+public:
+ OutputRelocSection(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ unsigned int pEntrySize);
+ ~OutputRelocSection();
+
+ void reserveEntry(RelocationFactory& pRelFactory, size_t pNum=1);
+
+ Relocation* getEntry(const ResolveInfo& pSymbol,
+ bool isForGOT,
+ bool& pExist);
+
+private:
+ /// m_pSection - LDSection of this Section
+ LDSection* m_pSection;
+
+ /// m_SectionData - MCSectionData which contains the dynamic relocations
+ llvm::MCSectionData* m_pSectionData;
+
+ /// m_EntryBytes - size of a relocation entry
+ unsigned int m_EntryBytes;
+
+ /// m_isVisit - First time visit the function getEntry() or not
+ bool m_isVisit ;
+
+ /// m_ValidEntryIterator - point to the first valid entry
+ MCFragmentIterator m_ValidEntryIterator;
+
+ /// m_SymRelMap - map the resolved symbol to the Relocation entry
+ SymRelMapType m_SymRelMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/PLT.h b/include/mcld/Target/PLT.h
new file mode 100644
index 0000000..6a7522a
--- /dev/null
+++ b/include/mcld/Target/PLT.h
@@ -0,0 +1,86 @@
+//===- PLT.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef PROCEDURE_LINKAGE_TABLE_H
+#define PROCEDURE_LINKAGE_TABLE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/MC/MCTargetFragment.h>
+#include <llvm/ADT/ilist.h>
+
+namespace mcld
+{
+
+class ResolveInfo;
+
+/** \class PLTEntry
+ */
+class PLTEntry : public MCTargetFragment
+{
+public:
+ PLTEntry(size_t pSize, llvm::MCSectionData* pParent);
+ virtual ~PLTEntry();
+
+ size_t getEntrySize() const
+ { return m_EntrySize; }
+
+ void setContent(unsigned char* pContent)
+ { m_pContent = pContent; }
+
+ const unsigned char* getContent() const
+ { return m_pContent; }
+
+ //Used by llvm::cast<>.
+ static bool classof(const MCFragment *O)
+ { return true; }
+
+ size_t getSize() const
+ { return m_EntrySize; }
+
+protected:
+ size_t m_EntrySize;
+ unsigned char* m_pContent;
+};
+
+/** \class PLT
+ * \brief Procedure linkage table
+ */
+class PLT
+{
+public:
+ PLT(LDSection& pSection, llvm::MCSectionData& pSectionData);
+ virtual ~PLT();
+
+ const LDSection& getSection() const
+ { return m_Section; }
+
+ const llvm::MCSectionData& getSectionData() const
+ { return m_SectionData; }
+
+public:
+ /// reserveEntry - reseve the number of pNum of empty entries
+ /// The empty entris are reserved for layout to adjust the fragment offset.
+ virtual void reserveEntry(size_t pNum = 1) = 0;
+
+ /// getPLTEntry - get an empty entry or an exitsted filled entry with pSymbol.
+ /// @param pSymbol - the target symbol
+ /// @param pExist - ture if the a filled entry with pSymbol existed, otherwise false.
+ virtual PLTEntry* getPLTEntry(const ResolveInfo& pSymbol, bool& pExist) = 0;
+
+protected:
+ LDSection& m_Section;
+ llvm::MCSectionData& m_SectionData;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/Stub.h b/include/mcld/Target/Stub.h
new file mode 100644
index 0000000..3bc778f
--- /dev/null
+++ b/include/mcld/Target/Stub.h
@@ -0,0 +1,30 @@
+//===- Stub.h -------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_STUB_H
+#define LD_STUB_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include "mcld/LD/Relocation.h"
+
+namespace mcld
+{
+
+/** \class Stub
+ * \brief Stub is a piece of jumpping code.
+ */
+class Stub
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h
new file mode 100644
index 0000000..781b86f
--- /dev/null
+++ b/include/mcld/Target/TargetLDBackend.h
@@ -0,0 +1,146 @@
+//===-- llvm/Target/TargetLDBackend.h - Target LD Backend -----*- C++ -*-===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TARGET_TARGETLDBACKEND_H
+#define LLVM_TARGET_TARGETLDBACKEND_H
+
+#include <llvm/Support/DataTypes.h>
+#include <mcld/MC/MCLDOutput.h>
+
+namespace mcld {
+
+class MCLinker;
+class Relocation;
+class RelocationFactory;
+class Layout;
+class ArchiveReader;
+class ObjectReader;
+class DynObjReader;
+class ObjectWriter;
+class DynObjWriter;
+class LDContext;
+class SectionMap;
+class Output;
+class MCLDInfo;
+class SymbolCategory;
+class Input;
+class LDFileFormat;
+class GOT;
+
+//===----------------------------------------------------------------------===//
+/// TargetLDBackend - Generic interface to target specific assembler backends.
+///
+class TargetLDBackend
+{
+ TargetLDBackend(const TargetLDBackend &); // DO NOT IMPLEMENT
+ void operator=(const TargetLDBackend &); // DO NOT IMPLEMENT
+
+protected:
+ TargetLDBackend();
+
+public:
+ virtual ~TargetLDBackend();
+
+ // ----- target dependent ----- //
+ virtual bool initTargetSectionMap(SectionMap& pSectionMap) { return true;}
+ virtual void initTargetSegments(MCLinker& pLinker) { }
+ virtual void initTargetSections(MCLinker& pLinker) { }
+ virtual void initTargetSymbols(MCLinker& pLinker) { }
+ virtual void initTargetRelocation(MCLinker& pLinker) { }
+ virtual bool initStandardSymbols(MCLinker& pLinker) = 0;
+ virtual bool initRelocFactory(const MCLinker& pLinker) = 0;
+
+ virtual RelocationFactory* getRelocFactory() = 0;
+
+ /// scanRelocation - When read in relocations, backend can do any modification
+ /// to relocation and generate empty entries, such as GOT, dynamic relocation
+ /// entries and other target dependent entries. These entries are generated
+ /// for layout to adjust the ouput offset.
+ /// @param pReloc - a read in relocation entry
+ /// @param pInputSym - the input LDSymbol of relocation target symbol
+ /// @param pOutput - the ouput file
+ virtual void scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) = 0;
+
+ // ----- format dependent ----- //
+ virtual bool initArchiveReader(MCLinker&, MCLDInfo&) = 0;
+ virtual bool initObjectReader(MCLinker&) = 0;
+ virtual bool initDynObjReader(MCLinker&) = 0;
+ virtual bool initObjectWriter(MCLinker&) = 0;
+ virtual bool initDynObjWriter(MCLinker&) = 0;
+
+ virtual bool initExecSections(MCLinker&) = 0;
+ virtual bool initDynObjSections(MCLinker&) = 0;
+
+ virtual ArchiveReader *getArchiveReader() = 0;
+ virtual ObjectReader *getObjectReader() = 0;
+ virtual DynObjReader *getDynObjReader() = 0;
+ virtual ObjectWriter *getObjectWriter() = 0;
+ virtual DynObjWriter *getDynObjWriter() = 0;
+
+ virtual LDFileFormat* getDynObjFileFormat() = 0;
+ virtual LDFileFormat* getExecFileFormat() = 0;
+
+ /// preLayout - Backend can do any needed modification before layout
+ virtual void preLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// postLayout -Backend can do any needed modification after layout
+ virtual void postLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker) = 0;
+
+ /// Is the target machine little endian? **/
+ virtual bool isLittleEndian() const = 0;
+
+ /// bit class. the bit length of the target machine, 32 or 64 **/
+ virtual unsigned int bitclass() const = 0;
+
+ /// the page size of the target machine
+ virtual unsigned int pagesize() const = 0;
+
+ /// section start offset in the output file
+ virtual size_t sectionStartOffset() const = 0;
+
+ /// computeSectionOrder - compute the layout order of the given section
+ virtual unsigned int getSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const = 0;
+
+ /// sizeNamePools - compute the size of regular name pools
+ /// In ELF executable files, regular name pools are .symtab, .strtab.,
+ /// .dynsym, .dynstr, and .hash
+ virtual void
+ sizeNamePools(const Output& pOutput,
+ const SymbolCategory& pSymbols,
+ const MCLDInfo& pLDInfo) = 0;
+
+ /// finalizeSymbol - Linker checks pSymbol.reserved() if it's not zero,
+ /// then it will ask backend to finalize the symbol value.
+ /// @return ture - if backend set the symbol value sucessfully
+ /// @return false - if backend do not recognize the symbol
+ virtual bool finalizeSymbol(LDSymbol& pSymbol) const = 0;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ virtual bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const = 0;
+
+ /// readSection - read a target dependent section
+ virtual bool readSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr)
+ { return true; }
+
+};
+
+} // End mcld namespace
+
+#endif
diff --git a/include/mcld/Target/TargetMachine.h b/include/mcld/Target/TargetMachine.h
new file mode 100644
index 0000000..438edfd
--- /dev/null
+++ b/include/mcld/Target/TargetMachine.h
@@ -0,0 +1,127 @@
+//===- TargetMachine.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_TARGET_MACHINE_H
+#define MCLD_TARGET_MACHINE_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <llvm/Target/TargetMachine.h>
+#include <string>
+#include "mcld/MC/MCLDFile.h"
+
+namespace llvm
+{
+class Target;
+class TargetData;
+class TargetMachine;
+class PassManagerBase;
+class formatted_raw_ostream;
+
+} // namespace of llvm
+
+namespace mcld
+{
+
+class Target;
+class MCLDInfo;
+class SectLinkerOption;
+using namespace llvm;
+
+enum CodeGenFileType {
+ CGFT_ASMFile,
+ CGFT_OBJFile,
+ CGFT_ARCFile,
+ CGFT_DSOFile,
+ CGFT_EXEFile,
+ CGFT_NULLFile
+};
+
+
+/** \class mcld::LLVMTargetMachine
+ * \brief mcld::LLVMTargetMachine is a object adapter of
+ * llvm::LLVMTargetMachine.
+ *
+ * mcld::LLVMTargetMachine is also in charge of MCLDInfo.
+ *
+ * @see MCLDInfo
+ */
+class LLVMTargetMachine
+{
+public:
+ /// Adapter of llvm::TargetMachine
+ ///
+ LLVMTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+ virtual ~LLVMTargetMachine();
+
+ /// getTarget - adapt llvm::TargetMachine::getTarget
+ const mcld::Target& getTarget() const;
+
+ /// getTM - return adapted the llvm::TargetMachine.
+ const llvm::TargetMachine& getTM() const { return m_TM; }
+ llvm::TargetMachine& getTM() { return m_TM; }
+
+ /// getLDInfo - return the mcld::MCLDInfo
+ virtual mcld::MCLDInfo& getLDInfo() = 0;
+ virtual const mcld::MCLDInfo& getLDInfo() const = 0;
+
+ /// appPassesToEmitFile - The target function which we has to modify as
+ /// upstreaming.
+ bool addPassesToEmitFile(PassManagerBase &,
+ formatted_raw_ostream &Out,
+ const std::string &pOutputFilename,
+ mcld::CodeGenFileType,
+ CodeGenOpt::Level,
+ SectLinkerOption *pLinkerOpt = NULL,
+ bool DisableVerify = true);
+
+ /// getTargetData
+ const TargetData *getTargetData() const { return m_TM.getTargetData(); }
+
+ /// setAsmVerbosityDefault
+ static void setAsmVerbosityDefault(bool pAsmVerbose) {
+ llvm::TargetMachine::setAsmVerbosityDefault(pAsmVerbose);
+ }
+
+private:
+ /// addCommonCodeGenPasses - Add standard LLVM codegen passes used for
+ /// both emitting to assembly files or machine code output.
+ bool addCommonCodeGenPasses(PassManagerBase &,
+ mcld::CodeGenFileType,
+ CodeGenOpt::Level,
+ bool DisableVerify,
+ llvm::MCContext *&OutCtx);
+
+ bool addCompilerPasses(PassManagerBase &,
+ formatted_raw_ostream &Out,
+ const std::string& pOutputFilename,
+ llvm::MCContext *&OutCtx);
+
+ bool addAssemblerPasses(PassManagerBase &,
+ formatted_raw_ostream &Out,
+ const std::string& pOutputFilename,
+ llvm::MCContext *&OutCtx);
+
+ bool addLinkerPasses(PassManagerBase &,
+ SectLinkerOption *pLinkerOpt,
+ const std::string& pOutputFilename,
+ MCLDFile::Type pOutputLinkType,
+ llvm::MCContext *&OutCtx);
+
+private:
+ llvm::TargetMachine &m_TM;
+ const mcld::Target *m_pTarget;
+ const std::string& m_Triple;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/CodeGen/Android.mk b/lib/CodeGen/Android.mk
new file mode 100644
index 0000000..8754d65
--- /dev/null
+++ b/lib/CodeGen/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_codegen_SRC_FILES := \
+ LLVMTargetMachine.cpp \
+ SectLinker.cpp \
+ SectLinkerOption.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_codegen_SRC_FILES)
+LOCAL_MODULE:= libmcldCodeGen
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_codegen_SRC_FILES)
+LOCAL_MODULE:= libmcldCodeGen
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp
new file mode 100644
index 0000000..acf5254
--- /dev/null
+++ b/lib/CodeGen/LLVMTargetMachine.cpp
@@ -0,0 +1,412 @@
+//===- LLVMTargetMachine.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mcld/CodeGen/SectLinker.h"
+#include "mcld/CodeGen/SectLinkerOption.h"
+#include "mcld/MC/MCBitcodeInterceptor.h"
+#include "mcld/MC/MCLDFile.h"
+#include "mcld/Support/RealPath.h"
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Target/TargetLDBackend.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/Analysis/Passes.h>
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/Assembly/PrintModulePass.h>
+#include <llvm/CodeGen/AsmPrinter.h>
+#include <llvm/CodeGen/MachineFunctionAnalysis.h>
+#include <llvm/CodeGen/MachineModuleInfo.h>
+#include <llvm/CodeGen/GCStrategy.h>
+#include <llvm/CodeGen/Passes.h>
+#include <llvm/MC/MCAsmInfo.h>
+#include <llvm/MC/MCStreamer.h>
+#include <llvm/MC/MCInstrInfo.h>
+#include <llvm/MC/MCSubtargetInfo.h>
+#include <llvm/MC/MCObjectStreamer.h>
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/MC/MCObjectWriter.h>
+#include <llvm/MC/MCContext.h>
+#include <llvm/PassManager.h>
+#include <llvm/Support/CommandLine.h>
+#include <llvm/Support/Debug.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/ToolOutputFile.h>
+#include <llvm/Target/TargetData.h>
+#include <llvm/Target/TargetInstrInfo.h>
+#include <llvm/Target/TargetLowering.h>
+#include <llvm/Target/TargetOptions.h>
+#include <llvm/Target/TargetSubtargetInfo.h>
+#include <llvm/Target/TargetLoweringObjectFile.h>
+#include <llvm/Target/TargetRegisterInfo.h>
+#include <llvm/Transforms/Scalar.h>
+
+#include <string>
+
+using namespace mcld;
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+/// Arguments
+// Enable or disable FastISel. Both options are needed, because
+// FastISel is enabled by default with -fast, and we wish to be
+// able to enable or disable fast-isel independently from -O0.
+
+static cl::opt<cl::boolOrDefault>
+ArgEnableFastISelOption("lfast-isel", cl::Hidden,
+ cl::desc("Enable the \"fast\" instruction selector"));
+
+static cl::opt<bool>
+ArgShowMCEncoding("lshow-mc-encoding",
+ cl::Hidden,
+ cl::desc("Show encoding in .s output"));
+
+static cl::opt<bool>
+ArgShowMCInst("lshow-mc-inst",
+ cl::Hidden,
+ cl::desc("Show instruction structure in .s output"));
+
+static cl::opt<cl::boolOrDefault>
+ArgAsmVerbose("fverbose-asm",
+ cl::desc("Put extra commentary information in the \
+ generated assembly code to make it more readable."),
+ cl::init(cl::BOU_UNSET));
+
+static bool getVerboseAsm() {
+ switch (ArgAsmVerbose) {
+ default:
+ case cl::BOU_UNSET: return TargetMachine::getAsmVerbosityDefault();
+ case cl::BOU_TRUE: return true;
+ case cl::BOU_FALSE: return false;
+ }
+}
+
+
+//===---------------------------------------------------------------------===//
+/// LLVMTargetMachine
+mcld::LLVMTargetMachine::LLVMTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target& pTarget,
+ const std::string& pTriple )
+ : m_TM(pTM), m_pTarget(&pTarget), m_Triple(pTriple) {
+}
+
+mcld::LLVMTargetMachine::~LLVMTargetMachine() {
+ m_pTarget = 0;
+}
+
+const mcld::Target& mcld::LLVMTargetMachine::getTarget() const
+{
+ return *m_pTarget;
+}
+
+/// Turn exception handling constructs into something the code generators can
+/// handle.
+static void addPassesToHandleExceptions(llvm::TargetMachine *TM,
+ PassManagerBase &PM) {
+ switch (TM->getMCAsmInfo()->getExceptionHandlingType()) {
+ case llvm::ExceptionHandling::SjLj:
+ // SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both
+ // Dwarf EH prepare needs to be run after SjLj prepare. Otherwise,
+ // catch info can get misplaced when a selector ends up more than one block
+ // removed from the parent invoke(s). This could happen when a landing
+ // pad is shared by multiple invokes and is also a target of a normal
+ // edge from elsewhere.
+ PM.add(createSjLjEHPass(TM->getTargetLowering()));
+ // FALLTHROUGH
+ case llvm::ExceptionHandling::DwarfCFI:
+ case llvm::ExceptionHandling::ARM:
+ case llvm::ExceptionHandling::Win64:
+ PM.add(createDwarfEHPass(TM));
+ break;
+ case llvm::ExceptionHandling::None:
+ PM.add(createLowerInvokePass(TM->getTargetLowering()));
+
+ // The lower invoke pass may create unreachable code. Remove it.
+ PM.add(createUnreachableBlockEliminationPass());
+ break;
+ }
+}
+
+
+static llvm::MCContext *addPassesToGenerateCode(llvm::LLVMTargetMachine *TM,
+ PassManagerBase &PM,
+ bool DisableVerify)
+{
+ // Targets may override createPassConfig to provide a target-specific sublass.
+ TargetPassConfig *PassConfig = TM->createPassConfig(PM);
+
+ // Set PassConfig options provided by TargetMachine.
+ PassConfig->setDisableVerify(DisableVerify);
+
+ PM.add(PassConfig);
+
+ PassConfig->addIRPasses();
+
+ addPassesToHandleExceptions(TM, PM);
+
+ PassConfig->addISelPrepare();
+
+ // Install a MachineModuleInfo class, which is an immutable pass that holds
+ // all the per-module stuff we're generating, including MCContext.
+ MachineModuleInfo *MMI =
+ new MachineModuleInfo(*TM->getMCAsmInfo(), *TM->getRegisterInfo(),
+ &TM->getTargetLowering()->getObjFileLowering());
+ PM.add(MMI);
+ MCContext *Context = &MMI->getContext(); // Return the MCContext by-ref.
+
+ // Set up a MachineFunction for the rest of CodeGen to work on.
+ PM.add(new MachineFunctionAnalysis(*TM));
+
+ // Enable FastISel with -fast, but allow that to be overridden.
+ if (ArgEnableFastISelOption == cl::BOU_TRUE ||
+ (TM->getOptLevel() == CodeGenOpt::None &&
+ ArgEnableFastISelOption != cl::BOU_FALSE))
+ TM->setFastISel(true);
+
+ // Ask the target for an isel.
+ if (PassConfig->addInstSelector())
+ return NULL;
+
+ PassConfig->addMachinePasses();
+
+ PassConfig->setInitialized();
+
+ return Context;
+
+}
+
+bool mcld::LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &pPM,
+ formatted_raw_ostream &Out,
+ const std::string& pOutputFilename,
+ mcld::CodeGenFileType pFileType,
+ CodeGenOpt::Level pOptLvl,
+ SectLinkerOption *pLinkerOpt,
+ bool pDisableVerify)
+{
+
+ llvm::MCContext* Context =
+ addPassesToGenerateCode(static_cast<llvm::LLVMTargetMachine*>(&m_TM),
+ pPM, pDisableVerify);
+ if (!Context)
+ return true;
+
+ switch(pFileType) {
+ default:
+ case mcld::CGFT_NULLFile:
+ assert(0 && "fatal: file type is not set!");
+ break;
+ case CGFT_ASMFile: {
+ assert(Context != 0 && "Failed to get MCContext");
+
+ if (getTM().hasMCSaveTempLabels())
+ Context->setAllowTemporaryLabels(false);
+
+ if (addCompilerPasses(pPM,
+ Out,
+ pOutputFilename,
+ Context))
+ return true;
+
+ pPM.add(createGCInfoDeleter()); // not in addPassesToMC
+ break;
+ }
+ case CGFT_OBJFile: {
+ assert(Context != 0 && "Failed to get MCContext");
+
+ if (getTM().hasMCSaveTempLabels())
+ Context->setAllowTemporaryLabels(false);
+ if (addAssemblerPasses(pPM,
+ Out,
+ pOutputFilename,
+ Context))
+ return true;
+
+ pPM.add(createGCInfoDeleter()); // not in addPassesToMC
+ break;
+ }
+ case CGFT_ARCFile: {
+ assert(0 && "Output to archive file has not been supported yet!");
+ break;
+ }
+ case CGFT_EXEFile: {
+ if (pLinkerOpt == NULL)
+ return true;
+
+ if (addLinkerPasses(pPM,
+ pLinkerOpt,
+ pOutputFilename,
+ MCLDFile::Exec,
+ Context))
+ return true;
+ break;
+ }
+ case CGFT_DSOFile: {
+ if (pLinkerOpt == NULL)
+ return true;
+
+ if (addLinkerPasses(pPM,
+ pLinkerOpt,
+ pOutputFilename,
+ MCLDFile::DynObj,
+ Context))
+ return true;
+ break;
+ }
+ } // switch
+ return false;
+}
+
+bool mcld::LLVMTargetMachine::addCompilerPasses(PassManagerBase &pPM,
+ formatted_raw_ostream &Out,
+ const std::string& pOutputFilename,
+ llvm::MCContext *&Context)
+{
+ const MCAsmInfo &MAI = *getTM().getMCAsmInfo();
+ const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>();
+
+ MCInstPrinter *InstPrinter =
+ getTarget().get()->createMCInstPrinter(MAI.getAssemblerDialect(), MAI,
+ Context->getRegisterInfo(), STI);
+
+ MCCodeEmitter* MCE = 0;
+ MCAsmBackend *MAB = 0;
+ if (ArgShowMCEncoding) {
+ MCE = getTarget().get()->createMCCodeEmitter(*(getTM().getInstrInfo()), STI, *Context);
+ MAB = getTarget().get()->createMCAsmBackend(m_Triple);
+ }
+
+
+ // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
+ OwningPtr<MCStreamer> AsmStreamer(
+ getTarget().get()->createAsmStreamer(*Context, Out,
+ getVerboseAsm(),
+ getTM().hasMCUseLoc(),
+ getTM().hasMCUseCFI(),
+ getTM().hasMCUseDwarfDirectory(),
+ InstPrinter,
+ MCE, MAB,
+ ArgShowMCInst));
+
+ llvm::MachineFunctionPass* funcPass =
+ getTarget().get()->createAsmPrinter(getTM(), *AsmStreamer.get());
+
+ if (funcPass == 0)
+ return true;
+ // If successful, createAsmPrinter took ownership of AsmStreamer
+ AsmStreamer.take();
+ pPM.add(funcPass);
+ return false;
+}
+
+bool mcld::LLVMTargetMachine::addAssemblerPasses(PassManagerBase &pPM,
+ formatted_raw_ostream &Out,
+ const std::string& pOutputFilename,
+ llvm::MCContext *&Context)
+{
+ // MCCodeEmitter
+ const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>();
+ MCCodeEmitter* MCE = getTarget().get()->createMCCodeEmitter(*getTM().getInstrInfo(), STI, *Context);
+
+ // MCAsmBackend
+ MCAsmBackend* MAB = getTarget().get()->createMCAsmBackend(m_Triple);
+ if (MCE == 0 || MAB == 0)
+ return true;
+
+ // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
+ OwningPtr<MCStreamer> AsmStreamer(getTarget().get()->createMCObjectStreamer(
+ m_Triple,
+ *Context,
+ *MAB,
+ Out,
+ MCE,
+ getTM().hasMCRelaxAll(),
+ getTM().hasMCNoExecStack()));
+ AsmStreamer.get()->InitSections();
+ MachineFunctionPass *funcPass = getTarget().get()->createAsmPrinter(getTM(),
+ *AsmStreamer.get());
+ if (funcPass == 0)
+ return true;
+ // If successful, createAsmPrinter took ownership of AsmStreamer
+ AsmStreamer.take();
+ pPM.add(funcPass);
+ return false;
+}
+
+bool mcld::LLVMTargetMachine::addLinkerPasses(PassManagerBase &pPM,
+ SectLinkerOption *pLinkerOpt,
+ const std::string &pOutputFilename,
+ MCLDFile::Type pOutputLinkType,
+ llvm::MCContext *&Context)
+{
+// FIXME: when MCLinker can directly turn bitcode into shared object, turn on this
+// block of code.
+#if 0
+ // Initialize MCAsmStreamer first, than chain its output into SectLinker.
+ // MCCodeEmitter
+ const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>();
+ MCCodeEmitter* MCE = getTarget().get()->createMCCodeEmitter(*getTM().getInstrInfo(),
+ STI,
+ *Context);
+ // MCAsmBackend
+ MCAsmBackend *MAB = getTarget().get()->createMCAsmBackend(m_Triple);
+ if (MCE == 0 || MAB == 0)
+ return true;
+
+ // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
+ MCStreamer* AsmStreamer =
+ getTarget().get()->createMCObjectStreamer(m_Triple,
+ *Context,
+ *MAB,
+ llvm::nulls(),
+ MCE,
+ getTM().hasMCRelaxAll(),
+ getTM().hasMCNoExecStack());
+ if (0 == AsmStreamer)
+ return true;
+
+ AsmStreamer->InitSections();
+ AsmPrinter* printer = getTarget().get()->createAsmPrinter(getTM(), *AsmStreamer);
+ if (0 == printer)
+ return true;
+ pPM.add(printer);
+#endif
+ TargetLDBackend* ldBackend = getTarget().createLDBackend(*getTarget().get(), m_Triple);
+ if (0 == ldBackend)
+ return true;
+
+// FIXME: when MCLinker can directly turn bitcode into shared object, turn on this
+// block of code.
+#if 0
+ MCBitcodeInterceptor* objReader = new MCBitcodeInterceptor(
+ static_cast<MCObjectStreamer&>(*AsmStreamer),
+ *ldBackend,
+ getLDInfo());
+#endif
+ // set up output's SOName
+ if (pOutputLinkType == MCLDFile::DynObj &&
+ pLinkerOpt->info().output().name().empty()) {
+ // if the output is a shared object, and the option -soname was not
+ // enable, set soname as the output file name.
+ pLinkerOpt->info().output().setSOName(pOutputFilename);
+ }
+
+ pLinkerOpt->info().output().setPath(sys::fs::RealPath(pOutputFilename));
+ pLinkerOpt->info().output().setType(pOutputLinkType);
+
+ MachineFunctionPass* funcPass = getTarget().createSectLinker(m_Triple,
+ *pLinkerOpt,
+ *ldBackend);
+ if (0 == funcPass)
+ return true;
+
+ pPM.add(funcPass);
+ return false;
+}
+
diff --git a/lib/CodeGen/SectLinker.cpp b/lib/CodeGen/SectLinker.cpp
new file mode 100644
index 0000000..95e9e4f
--- /dev/null
+++ b/lib/CodeGen/SectLinker.cpp
@@ -0,0 +1,315 @@
+//===- SectLinker.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SectLinker class.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/ADT/BinTree.h>
+#include <mcld/CodeGen/SectLinker.h>
+#include <mcld/CodeGen/SectLinkerOption.h>
+#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/MCLDDriver.h>
+#include <mcld/Support/DerivedPositionDependentOptions.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Target/TargetLDBackend.h>
+
+#include <llvm/Module.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include <algorithm>
+#include <stack>
+#include <string>
+
+using namespace mcld;
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Forward declarations
+char SectLinker::m_ID = 0;
+static bool CompareOption(const PositionDependentOption* X,
+ const PositionDependentOption* Y);
+
+//===----------------------------------------------------------------------===//
+// SectLinker
+SectLinker::SectLinker(SectLinkerOption &pOption,
+ TargetLDBackend& pLDBackend)
+ : MachineFunctionPass(m_ID),
+ m_pOption(&pOption),
+ m_pLDBackend(&pLDBackend),
+ m_pLDDriver(NULL) { }
+
+SectLinker::~SectLinker()
+{
+ delete m_pLDDriver;
+ // FIXME: current implementation can not change the order of delete.
+ //
+ // Instance of TargetLDBackend was created outside and is not managed by
+ // SectLinker. It should not be destroyed here and by SectLinker. However, in
+ // order to follow the LLVM convention - that is, the pass manages all the
+ // objects it used during the processing, we destroy the object of
+ // TargetLDBackend here.
+ delete m_pLDBackend;
+}
+
+bool SectLinker::doInitialization(Module &pM)
+{
+ MCLDInfo &info = m_pOption->info();
+
+ // setup the output
+ info.output().setContext(info.contextFactory().produce(info.output().path()));
+
+ int mode = (Output::Object == info.output().type())? 0544 : 0755;
+ info.output().setMemArea(
+ info.memAreaFactory().produce(info.output().path(),
+ O_RDWR | O_CREAT | O_TRUNC,
+ mode));
+
+ // make sure output is openend successfully.
+ if (!info.output().hasMemArea())
+ report_fatal_error("output is not given on the command line\n");
+
+ if (!info.output().memArea()->isGood())
+ report_fatal_error("can not open output file :"+info.output().path().native());
+
+ // let the target override the target-specific parameters
+ addTargetOptions(pM, *m_pOption);
+
+ // ----- convert position dependent options into tree of input files ----- //
+ PositionDependentOptions &PosDepOpts = m_pOption->pos_dep_options();
+ std::stable_sort(PosDepOpts.begin(), PosDepOpts.end(), CompareOption);
+ initializeInputTree(PosDepOpts);
+
+ // Now, all input arguments are prepared well, send it into MCLDDriver
+ m_pLDDriver = new MCLDDriver(info, *m_pLDBackend);
+
+ return false;
+}
+
+bool SectLinker::doFinalization(Module &pM)
+{
+ const MCLDInfo &info = m_pOption->info();
+
+ // 3. - initialize output's standard segments and sections
+ if (!m_pLDDriver->initMCLinker())
+ return true;
+
+ // 4. - normalize the input tree
+ m_pLDDriver->normalize();
+
+ if (info.options().verbose()) {
+ outs() << "MCLinker (LLVM Sub-project) - ";
+ outs() << MCLDInfo::version();
+ outs() << "\n";
+ }
+
+ if (info.options().trace()) {
+ static int counter = 0;
+ outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n";
+ InputTree::const_dfs_iterator input, inEnd = info.inputs().dfs_end();
+ for (input=info.inputs().dfs_begin(); input!=inEnd; ++input) {
+ outs() << counter++ << " * " << (*input)->name();
+ switch((*input)->type()) {
+ case Input::Archive:
+ outs() << "\tarchive\t(";
+ break;
+ case Input::Object:
+ outs() << "\tobject\t(";
+ break;
+ case Input::DynObj:
+ outs() << "\tshared\t(";
+ break;
+ case Input::Script:
+ outs() << "\tscript\t(";
+ break;
+ default:
+ report_fatal_error("** Trace a unsupported file. It must be an internal bug!");
+ }
+ outs() << (*input)->path().c_str() << ")\n";
+ }
+ }
+
+ // 5. - check if we can do static linking and if we use split-stack.
+ if (!m_pLDDriver->linkable())
+ return true;
+
+
+ // 6. - read all sections
+ if (!m_pLDDriver->readSections() ||
+ !m_pLDDriver->mergeSections())
+ return true;
+
+ // 7. - read all symbol tables of input files and resolve them
+ if (!m_pLDDriver->readSymbolTables() ||
+ !m_pLDDriver->mergeSymbolTables())
+ return true;
+
+ // 7.a - add standard symbols and target-dependent symbols
+ // m_pLDDriver->addUndefSymbols();
+ if (!m_pLDDriver->addStandardSymbols() ||
+ !m_pLDDriver->addTargetSymbols())
+ return true;
+
+ // 8. - read all relocation entries from input files
+ m_pLDDriver->readRelocations();
+
+ // 9. - pre-layout
+ m_pLDDriver->prelayout();
+
+ // 10. - linear layout
+ m_pLDDriver->layout();
+
+ // 10.b - post-layout
+ m_pLDDriver->postlayout();
+
+ // 11. - finalize symbol value
+ m_pLDDriver->finalizeSymbolValue();
+
+ // 12. - apply relocations
+ m_pLDDriver->relocate();
+
+ // 13. - write out output
+ m_pLDDriver->emitOutput();
+
+ // 14. - post processing
+ m_pLDDriver->postProcessing();
+ return false;
+}
+
+bool SectLinker::runOnMachineFunction(MachineFunction& pF)
+{
+ // basically, linkers do nothing during function is generated.
+ return false;
+}
+
+void SectLinker::initializeInputTree(const PositionDependentOptions &pPosDepOptions) const
+{
+ if (pPosDepOptions.empty())
+ return;
+
+ MCLDInfo &info = m_pOption->info();
+ PositionDependentOptions::const_iterator cur_char = pPosDepOptions.begin();
+ if (1 == pPosDepOptions.size() &&
+ ((*cur_char)->type() != PositionDependentOption::INPUT_FILE &&
+ (*cur_char)->type() != PositionDependentOption::NAMESPEC))
+ return;
+
+ InputTree::Connector *prev_ward = &InputTree::Downward;
+
+ std::stack<InputTree::iterator> returnStack;
+ InputTree::iterator cur_node = info.inputs().root();
+
+ PositionDependentOptions::const_iterator charEnd = pPosDepOptions.end();
+ while (cur_char != charEnd ) {
+ switch ((*cur_char)->type()) {
+ case PositionDependentOption::BITCODE: {
+ // threat bitcode as a script in this version.
+ const BitcodeOption *bitcode_option =
+ static_cast<const BitcodeOption*>(*cur_char);
+ info.inputs().insert(cur_node,
+ *prev_ward,
+ bitcode_option->path()->native(),
+ *(bitcode_option->path()),
+ Input::Script);
+ info.setBitcode(**cur_node);
+ prev_ward->move(cur_node);
+ prev_ward = &InputTree::Afterward;
+ break;
+ }
+ case PositionDependentOption::INPUT_FILE: {
+ const InputFileOption *input_file_option =
+ static_cast<const InputFileOption*>(*cur_char);
+ info.inputs().insert(cur_node,
+ *prev_ward,
+ input_file_option->path()->native(),
+ *(input_file_option->path()));
+ prev_ward->move(cur_node);
+ prev_ward = &InputTree::Afterward;
+ break;
+ }
+ case PositionDependentOption::NAMESPEC: {
+ sys::fs::Path* path = 0;
+ const NamespecOption *namespec_option =
+ static_cast<const NamespecOption*>(*cur_char);
+ if (info.attrFactory().last().isStatic()) {
+ path = info.options().directories().find(namespec_option->namespec(),
+ Input::Archive);
+ }
+ else {
+ path = info.options().directories().find(namespec_option->namespec(),
+ Input::DynObj);
+ }
+
+ if (0 == path) {
+ llvm::report_fatal_error(std::string("Can't find namespec: ")+
+ namespec_option->namespec());
+ }
+ info.inputs().insert(cur_node,
+ *prev_ward,
+ namespec_option->namespec(),
+ *path);
+ prev_ward->move(cur_node);
+ prev_ward = &InputTree::Afterward;
+ break;
+ }
+ case PositionDependentOption::START_GROUP:
+ info.inputs().enterGroup(cur_node, *prev_ward);
+ prev_ward->move(cur_node);
+ returnStack.push(cur_node);
+ prev_ward = &InputTree::Downward;
+ break;
+ case PositionDependentOption::END_GROUP:
+ cur_node = returnStack.top();
+ returnStack.pop();
+ prev_ward = &InputTree::Afterward;
+ break;
+ case PositionDependentOption::WHOLE_ARCHIVE:
+ info.attrFactory().last().setWholeArchive();
+ break;
+ case PositionDependentOption::NO_WHOLE_ARCHIVE:
+ info.attrFactory().last().unsetWholeArchive();
+ break;
+ case PositionDependentOption::AS_NEEDED:
+ info.attrFactory().last().setAsNeeded();
+ break;
+ case PositionDependentOption::NO_AS_NEEDED:
+ info.attrFactory().last().unsetAsNeeded();
+ break;
+ case PositionDependentOption::ADD_NEEDED:
+ info.attrFactory().last().setAddNeeded();
+ break;
+ case PositionDependentOption::NO_ADD_NEEDED:
+ info.attrFactory().last().unsetAddNeeded();
+ break;
+ case PositionDependentOption::BSTATIC:
+ info.attrFactory().last().setStatic();
+ break;
+ case PositionDependentOption::BDYNAMIC:
+ info.attrFactory().last().setDynamic();
+ break;
+ default:
+ report_fatal_error("can not find the type of input file");
+ }
+ ++cur_char;
+ }
+
+ if (!returnStack.empty()) {
+ report_fatal_error("no matched --start-group and --end-group");
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Non-member functions
+static bool CompareOption(const PositionDependentOption* X,
+ const PositionDependentOption* Y)
+{
+ return (X->position() < Y->position());
+}
+
diff --git a/lib/CodeGen/SectLinkerOption.cpp b/lib/CodeGen/SectLinkerOption.cpp
new file mode 100644
index 0000000..85d6b10
--- /dev/null
+++ b/lib/CodeGen/SectLinkerOption.cpp
@@ -0,0 +1,24 @@
+//===- SectLinkerOption.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/CodeGen/SectLinkerOption.h"
+#include "mcld/Support/DerivedPositionDependentOptions.h"
+#include "mcld/Support/RealPath.h"
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// SectLinkerOption
+SectLinkerOption::SectLinkerOption(MCLDInfo &pLDInfo)
+ : m_pLDInfo(&pLDInfo) { }
+
+SectLinkerOption::~SectLinkerOption() {
+ for (PositionDependentOptions::iterator pdoption = m_PosDepOptions.begin(),
+ pdoptionEnd = m_PosDepOptions.end(); pdoption != pdoptionEnd; ++pdoption)
+ delete *pdoption;
+}
diff --git a/lib/LD/Android.mk b/lib/LD/Android.mk
new file mode 100644
index 0000000..dc356c7
--- /dev/null
+++ b/lib/LD/Android.mk
@@ -0,0 +1,96 @@
+LOCAL_PATH:= $(call my-dir)
+
+# =====================================================
+# Static library: libmcldLD
+# =====================================================
+
+mcld_ld_SRC_FILES := \
+ ArchiveReader.cpp \
+ BranchIsland.cpp \
+ DynObjReader.cpp \
+ DynObjWriter.cpp \
+ ELFSegment.cpp \
+ ELFSegmentFactory.cpp \
+ Layout.cpp \
+ LDContext.cpp \
+ LDFileFormat.cpp \
+ LDReader.cpp \
+ LDSection.cpp \
+ LDSectionFactory.cpp \
+ LDSymbol.cpp \
+ LDWriter.cpp \
+ ObjectWriter.cpp \
+ Relocation.cpp \
+ RelocationFactory.cpp \
+ ResolveInfo.cpp \
+ ResolveInfoFactory.cpp \
+ Resolver.cpp \
+ SectionMap.cpp \
+ SectionMerger.cpp \
+ StaticResolver.cpp \
+ StrSymPool.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_ld_SRC_FILES)
+LOCAL_MODULE:= libmcldLD
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_ld_SRC_FILES)
+LOCAL_MODULE:= libmcldLD
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+# =====================================================
+# Static library: libmcldLDVariant
+# =====================================================
+
+mcld_ld_variant_SRC_FILES := \
+ BSDArchiveReader.cpp \
+ GNUArchiveReader.cpp \
+ ELFDynObjFileFormat.cpp \
+ ELFDynObjReader.cpp \
+ ELFDynObjWriter.cpp \
+ ELFExecFileFormat.cpp \
+ ELFFileFormat.cpp \
+ ELFObjectReader.cpp \
+ ELFObjectWriter.cpp \
+ ELFReader.cpp \
+ ELFWriter.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_ld_variant_SRC_FILES)
+LOCAL_MODULE:= libmcldLDVariant
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_ld_variant_SRC_FILES)
+LOCAL_MODULE:= libmcldLDVariant
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/lib/LD/ArchiveReader.cpp b/lib/LD/ArchiveReader.cpp
new file mode 100644
index 0000000..f43c057
--- /dev/null
+++ b/lib/LD/ArchiveReader.cpp
@@ -0,0 +1,22 @@
+//===- ArchiveReader.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/ArchiveReader.h"
+
+using namespace mcld;
+
+//==========================
+// MCELFArchiveReader
+ArchiveReader::ArchiveReader()
+{
+}
+
+ArchiveReader::~ArchiveReader()
+{
+}
+
diff --git a/lib/LD/BSDArchiveReader.cpp b/lib/LD/BSDArchiveReader.cpp
new file mode 100644
index 0000000..1264824
--- /dev/null
+++ b/lib/LD/BSDArchiveReader.cpp
@@ -0,0 +1,34 @@
+//===- BSDArchiveReader.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDInput.h"
+#include "mcld/MC/MCLDInputTree.h"
+#include "mcld/LD/BSDArchiveReader.h"
+
+using namespace mcld;
+
+BSDArchiveReader::BSDArchiveReader()
+{
+}
+
+BSDArchiveReader::~BSDArchiveReader()
+{
+}
+
+InputTree *BSDArchiveReader::readArchive(Input &input)
+{
+ // TODO
+ return NULL;
+}
+
+bool BSDArchiveReader::isMyFormat(Input& pInput) const
+{
+ // TODO
+ return false;
+}
+
diff --git a/lib/LD/BranchIsland.cpp b/lib/LD/BranchIsland.cpp
new file mode 100644
index 0000000..7a42717
--- /dev/null
+++ b/lib/LD/BranchIsland.cpp
@@ -0,0 +1,15 @@
+//===- BranchIsland.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/BranchIsland.h"
+
+using namespace mcld;
+
+//==========================
+// BranchIsland
+
diff --git a/lib/LD/DynObjReader.cpp b/lib/LD/DynObjReader.cpp
new file mode 100644
index 0000000..60b5cf7
--- /dev/null
+++ b/lib/LD/DynObjReader.cpp
@@ -0,0 +1,16 @@
+//===- DynObjReader.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/DynObjReader.h"
+#include "mcld/Target/TargetLDBackend.h"
+#include "mcld/MC/MCLDInput.h"
+
+using namespace mcld;
+
+//==========================
+// ObjectReader
diff --git a/lib/LD/DynObjWriter.cpp b/lib/LD/DynObjWriter.cpp
new file mode 100644
index 0000000..6f031ff
--- /dev/null
+++ b/lib/LD/DynObjWriter.cpp
@@ -0,0 +1,16 @@
+//===- DynObjWriter.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/DynObjWriter.h"
+#include "mcld/Target/TargetLDBackend.h"
+#include "mcld/MC/MCLDInput.h"
+
+using namespace mcld;
+
+//==========================
+// DynObjWriter
diff --git a/lib/LD/ELFDynObjFileFormat.cpp b/lib/LD/ELFDynObjFileFormat.cpp
new file mode 100644
index 0000000..77034eb
--- /dev/null
+++ b/lib/LD/ELFDynObjFileFormat.cpp
@@ -0,0 +1,81 @@
+//===- ELFDynObjFileFormat.cpp --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFDynObjFileFormat.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/MC/MCLinker.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/Target/GNULDBackend.h>
+
+using namespace mcld;
+
+void ELFDynObjFileFormat::initObjectType(MCLinker& pLinker)
+{
+ f_pDynSymTab = &pLinker.getOrCreateOutputSectHdr(".dynsym",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_DYNSYM,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pDynStrTab = &pLinker.getOrCreateOutputSectHdr(".dynstr",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_STRTAB,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pInterp = &pLinker.getOrCreateOutputSectHdr(".interp",
+ LDFileFormat::Note,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pHashTab = &pLinker.getOrCreateOutputSectHdr(".hash",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_HASH,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pDynamic = &pLinker.getOrCreateOutputSectHdr(".dynamic",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_DYNAMIC,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pRelaDyn = &pLinker.getOrCreateOutputSectHdr(".rela.dyn",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_RELA,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelaPlt = &pLinker.getOrCreateOutputSectHdr(".rela.plt",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_RELA,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelDyn = &pLinker.getOrCreateOutputSectHdr(".rel.dyn",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_REL,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelPlt = &pLinker.getOrCreateOutputSectHdr(".rel.plt",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_REL,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pGOT = &pLinker.getOrCreateOutputSectHdr(".got",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pPLT = &pLinker.getOrCreateOutputSectHdr(".plt",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
+ f_Backend.bitclass() / 8);
+ f_pGOTPLT = &pLinker.getOrCreateOutputSectHdr(".got.plt",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+}
+
diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp
new file mode 100644
index 0000000..12e6d7c
--- /dev/null
+++ b/lib/LD/ELFDynObjReader.cpp
@@ -0,0 +1,99 @@
+//===- ELFDynObjReader.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/Twine.h>
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/Support/ErrorHandling.h>
+
+#include <mcld/LD/ELFDynObjReader.h>
+#include <mcld/LD/ELFReader.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MemoryRegion.h>
+
+#include <string>
+
+using namespace mcld;
+
+//==========================
+// ELFDynObjReader
+ELFDynObjReader::ELFDynObjReader(GNULDBackend& pBackend, MCLinker& pLinker)
+ : DynObjReader(),
+ m_pELFReader(0),
+ m_Linker(pLinker) {
+ if (32 == pBackend.bitclass() && pBackend.isLittleEndian())
+ m_pELFReader = new ELFReader<32, true>(pBackend);
+}
+
+ELFDynObjReader::~ELFDynObjReader()
+{
+ delete m_pELFReader;
+}
+
+/// isMyFormat
+bool ELFDynObjReader::isMyFormat(Input &pInput) const
+{
+ assert(pInput.hasMemArea());
+
+ // Don't warning about the frequently requests.
+ // MemoryArea has a list of cache to handle this.
+ size_t hdr_size = m_pELFReader->getELFHeaderSize();
+ MemoryRegion* region = pInput.memArea()->request(0, hdr_size);
+
+ uint8_t* ELF_hdr = region->start();
+ bool result = true;
+ if (!m_pELFReader->isELF(ELF_hdr))
+ result = false;
+ else if (!m_pELFReader->isMyEndian(ELF_hdr))
+ result = false;
+ else if (!m_pELFReader->isMyMachine(ELF_hdr))
+ result = false;
+ else if (MCLDFile::DynObj != m_pELFReader->fileType(ELF_hdr))
+ result = false;
+ pInput.memArea()->release(region);
+ return result;
+}
+
+/// readDSO
+bool ELFDynObjReader::readDSO(Input& pInput)
+{
+ assert(pInput.hasMemArea());
+
+ size_t hdr_size = m_pELFReader->getELFHeaderSize();
+ MemoryRegion* region = pInput.memArea()->request(0, hdr_size);
+ uint8_t* ELF_hdr = region->start();
+
+ bool result = m_pELFReader->readSectionHeaders(pInput, m_Linker, ELF_hdr);
+ pInput.memArea()->release(region);
+ return result;
+}
+
+/// readSymbols
+bool ELFDynObjReader::readSymbols(Input& pInput)
+{
+ assert(pInput.hasMemArea());
+
+ LDSection* symtab_shdr = pInput.context()->getSection(".dynsym");
+ LDSection* strtab_shdr = symtab_shdr->getLink();
+ if (NULL == symtab_shdr || NULL == strtab_shdr)
+ return false;
+
+ MemoryRegion* symtab_region = pInput.memArea()->request(symtab_shdr->offset(),
+ symtab_shdr->size());
+
+ MemoryRegion* strtab_region = pInput.memArea()->request(strtab_shdr->offset(),
+ strtab_shdr->size());
+ char* strtab = reinterpret_cast<char*>(strtab_region->start());
+ bool result = m_pELFReader->readSymbols(pInput, m_Linker, *symtab_region, strtab);
+ pInput.memArea()->release(symtab_region);
+ pInput.memArea()->release(strtab_region);
+
+ return result;
+}
+
diff --git a/lib/LD/ELFDynObjWriter.cpp b/lib/LD/ELFDynObjWriter.cpp
new file mode 100644
index 0000000..21cd8e4
--- /dev/null
+++ b/lib/LD/ELFDynObjWriter.cpp
@@ -0,0 +1,138 @@
+//===- ELFDynObjWriter.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFDynObjWriter.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLinker.h>
+#include <llvm/Support/ELF.h>
+#include <vector>
+
+using namespace llvm;
+using namespace mcld;
+
+
+//==========================
+// ELFDynObjWriter
+ELFDynObjWriter::ELFDynObjWriter(GNULDBackend& pBackend, MCLinker& pLinker)
+ : DynObjWriter(pBackend),
+ ELFWriter(pBackend),
+ m_Backend(pBackend),
+ m_Linker(pLinker) {
+
+}
+
+ELFDynObjWriter::~ELFDynObjWriter()
+{
+}
+
+llvm::error_code ELFDynObjWriter::writeDynObj(Output& pOutput)
+{
+ // Write out name pool sections: .dynsym, .dynstr, .hash
+ target().emitDynNamePools(pOutput,
+ m_Linker.getOutputSymbols(),
+ m_Linker.getLayout(),
+ m_Linker.getLDInfo());
+
+ // Write out name pool sections: .symtab, .strtab
+ target().emitRegNamePools(pOutput,
+ m_Linker.getOutputSymbols(),
+ m_Linker.getLayout(),
+ m_Linker.getLDInfo());
+
+ // Write out regular ELF sections
+ unsigned int secIdx = 0;
+ unsigned int secEnd = pOutput.context()->numOfSections();
+ for (secIdx = 0; secIdx < secEnd; ++secIdx) {
+ LDSection* sect = pOutput.context()->getSection(secIdx);
+ MemoryRegion* region = NULL;
+ // request output region
+ switch(sect->kind()) {
+ case LDFileFormat::Regular:
+ case LDFileFormat::Relocation:
+ case LDFileFormat::Target: {
+ region = pOutput.memArea()->request(sect->offset(), sect->size());
+ if (NULL == region) {
+ llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section[") +
+ llvm::Twine(secIdx) +
+ llvm::Twine("] - `") +
+ sect->name() +
+ llvm::Twine("'.\n"));
+ }
+ break;
+ }
+ case LDFileFormat::Null:
+ case LDFileFormat::NamePool:
+ case LDFileFormat::BSS:
+ case LDFileFormat::Debug:
+ case LDFileFormat::Note:
+ case LDFileFormat::MetaData:
+ case LDFileFormat::Exception:
+ case LDFileFormat::Version:
+ // ignore these sections
+ continue;
+ default: {
+ llvm::errs() << "WARNING: unsupported section kind: "
+ << sect->kind()
+ << " of section "
+ << sect->name()
+ << ".\n";
+ continue;
+ }
+ }
+
+ // write out sections with data
+ switch(sect->kind()) {
+ case LDFileFormat::Regular: {
+ emitSectionData(m_Linker.getLayout(), *sect, *region);
+ break;
+ }
+ case LDFileFormat::Relocation:
+ emitRelocation(m_Linker.getLayout(), pOutput, *sect, *region);
+ break;
+ case LDFileFormat::Target:
+ target().emitSectionData(pOutput, *sect, m_Linker.getLDInfo(), *region);
+ break;
+ default:
+ continue;
+ }
+ } // end of for loop
+
+ if (32 == target().bitclass()) {
+ // Write out ELF header
+ // Write out section header table
+ emitELF32ShStrTab(pOutput, m_Linker);
+
+ writeELF32Header(m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ target(),
+ pOutput);
+
+ emitELF32SectionHeader(pOutput, m_Linker);
+ }
+ else if (64 == target().bitclass()) {
+ // Write out ELF header
+ // Write out section header table
+ emitELF64ShStrTab(pOutput, m_Linker);
+
+ writeELF64Header(m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ target(),
+ pOutput);
+
+ emitELF64SectionHeader(pOutput, m_Linker);
+ }
+ else
+ return make_error_code(errc::not_supported);
+
+ return llvm::make_error_code(llvm::errc::success);
+}
+
diff --git a/lib/LD/ELFExecFileFormat.cpp b/lib/LD/ELFExecFileFormat.cpp
new file mode 100644
index 0000000..f10d764
--- /dev/null
+++ b/lib/LD/ELFExecFileFormat.cpp
@@ -0,0 +1,13 @@
+//===- ELFExecFileFormat.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFExecFileFormat.h>
+#include <mcld/MC/MCLinker.h>
+
+using namespace mcld;
+
diff --git a/lib/LD/ELFFileFormat.cpp b/lib/LD/ELFFileFormat.cpp
new file mode 100644
index 0000000..9394e44
--- /dev/null
+++ b/lib/LD/ELFFileFormat.cpp
@@ -0,0 +1,242 @@
+//===- ELFFileFormat.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCLDFile.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/Target/GNULDBackend.h>
+
+using namespace mcld;
+
+ELFFileFormat::ELFFileFormat(GNULDBackend& pBackend)
+ : f_Backend(pBackend),
+ f_pNULLSection(NULL),
+ f_pGOT(NULL),
+ f_pPLT(NULL),
+ f_pRelDyn(NULL),
+ f_pRelPlt(NULL),
+ f_pRelaDyn(NULL),
+ f_pRelaPlt(NULL),
+ f_pComment(NULL),
+ f_pData1(NULL),
+ f_pDebug(NULL),
+ f_pDynamic(NULL),
+ f_pDynStrTab(NULL),
+ f_pDynSymTab(NULL),
+ f_pFini(NULL),
+ f_pFiniArray(NULL),
+ f_pHashTab(NULL),
+ f_pInit(NULL),
+ f_pInitArray(NULL),
+ f_pInterp(NULL),
+ f_pLine(NULL),
+ f_pNote(NULL),
+ f_pPreInitArray(NULL),
+ f_pROData1(NULL),
+ f_pShStrTab(NULL),
+ f_pStrTab(NULL),
+ f_pSymTab(NULL),
+ f_pTBSS(NULL),
+ f_pTData(NULL),
+ f_pCtors(NULL),
+ f_pDataRelRo(NULL),
+ f_pDtors(NULL),
+ f_pEhFrame(NULL),
+ f_pEhFrameHdr(NULL),
+ f_pGCCExceptTable(NULL),
+ f_pGNUVersion(NULL),
+ f_pGNUVersionD(NULL),
+ f_pGNUVersionR(NULL),
+ f_pGOTPLT(NULL),
+ f_pJCR(NULL),
+ f_pNoteABITag(NULL),
+ f_pStab(NULL),
+ f_pStabStr(NULL) {
+
+}
+
+ELFFileFormat::~ELFFileFormat()
+{
+}
+
+void ELFFileFormat::initObjectFormat(MCLinker& pLinker)
+{
+ f_pTextSection = &pLinker.getOrCreateOutputSectHdr(".text",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
+ 0x1);
+ f_pNULLSection = &pLinker.getOrCreateOutputSectHdr("",
+ LDFileFormat::Null,
+ llvm::ELF::SHT_NULL,
+ 0x0);
+ f_pReadOnlySection = &pLinker.getOrCreateOutputSectHdr(".rodata",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+
+ f_pBSSSection = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pComment = &pLinker.getOrCreateOutputSectHdr(".comment",
+ LDFileFormat::MetaData,
+ llvm::ELF::SHT_PROGBITS,
+ 0x0,
+ 0x1);
+ f_pDataSection = &pLinker.getOrCreateOutputSectHdr(".data",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pData1 = &pLinker.getOrCreateOutputSectHdr(".data1",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pDebug = &pLinker.getOrCreateOutputSectHdr(".debug",
+ LDFileFormat::Debug,
+ llvm::ELF::SHT_PROGBITS,
+ 0x0,
+ 0x1);
+ f_pInit = &pLinker.getOrCreateOutputSectHdr(".init",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
+ 0x1);
+ f_pInitArray = &pLinker.getOrCreateOutputSectHdr(".init_array",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_INIT_ARRAY,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pFini = &pLinker.getOrCreateOutputSectHdr(".fini",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
+ 0x1);
+ f_pFiniArray = &pLinker.getOrCreateOutputSectHdr(".fini_array",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_FINI_ARRAY,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pLine = &pLinker.getOrCreateOutputSectHdr(".line",
+ LDFileFormat::Debug,
+ llvm::ELF::SHT_PROGBITS,
+ 0x0,
+ 0x1);
+ f_pPreInitArray = &pLinker.getOrCreateOutputSectHdr(".preinit_array",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PREINIT_ARRAY,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ // the definition of SHF_XXX attributes of rodata in Linux Standard Base
+ // conflicts with System V standard. We follow System V standard.
+ f_pROData1 = &pLinker.getOrCreateOutputSectHdr(".rodata1",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pShStrTab = &pLinker.getOrCreateOutputSectHdr(".shstrtab",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_STRTAB,
+ 0x0,
+ 0x1);
+ // In ELF Spec Book I, p1-16. If symbol table and string table are in
+ // loadable segments, set the attribute to SHF_ALLOC bit. But in the
+ // real world, this bit always turn off.
+ f_pSymTab = &pLinker.getOrCreateOutputSectHdr(".symtab",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_SYMTAB,
+ 0x0,
+ f_Backend.bitclass() / 8);
+ f_pStrTab = &pLinker.getOrCreateOutputSectHdr(".strtab",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_STRTAB,
+ 0x0,
+ 0x1);
+ f_pTBSS = &pLinker.getOrCreateOutputSectHdr(".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_WRITE |
+ llvm::ELF::SHF_TLS,
+ 0x1);
+ f_pTData = &pLinker.getOrCreateOutputSectHdr(".tdata",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_WRITE |
+ llvm::ELF::SHF_TLS,
+ 0x1);
+
+ /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
+ f_pCtors = &pLinker.getOrCreateOutputSectHdr(".ctor",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pDataRelRo = &pLinker.getOrCreateOutputSectHdr(".data.rel.ro",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pDtors = &pLinker.getOrCreateOutputSectHdr(".dtors",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pEhFrame = &pLinker.getOrCreateOutputSectHdr(".eh_frame",
+ LDFileFormat::Exception,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pEhFrameHdr = &pLinker.getOrCreateOutputSectHdr(".eh_frame_hdr",
+ LDFileFormat::Exception,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pGCCExceptTable = &pLinker.getOrCreateOutputSectHdr(".gcc_except_table",
+ LDFileFormat::Exception,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pGNUVersion = &pLinker.getOrCreateOutputSectHdr(".gnu.version",
+ LDFileFormat::Version,
+ llvm::ELF::SHT_GNU_versym,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pGNUVersionD = &pLinker.getOrCreateOutputSectHdr(".gnu.version_d",
+ LDFileFormat::Version,
+ llvm::ELF::SHT_GNU_verdef,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pGNUVersionR = &pLinker.getOrCreateOutputSectHdr(".gnu.version_r",
+ LDFileFormat::Version,
+ llvm::ELF::SHT_GNU_verneed,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pJCR = &pLinker.getOrCreateOutputSectHdr(".jcr",
+ LDFileFormat::Regular,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ 0x1);
+ f_pStab = &pLinker.getOrCreateOutputSectHdr(".stab",
+ LDFileFormat::Debug,
+ llvm::ELF::SHT_PROGBITS,
+ 0x0,
+ 0x1);
+ f_pStabStr = &pLinker.getOrCreateOutputSectHdr(".stabstr",
+ LDFileFormat::Debug,
+ llvm::ELF::SHT_STRTAB,
+ 0x0,
+ 0x1);
+}
+
diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp
new file mode 100644
index 0000000..abc3d30
--- /dev/null
+++ b/lib/LD/ELFObjectReader.cpp
@@ -0,0 +1,243 @@
+//===- ELFObjectReader.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/LD/ELFObjectReader.h>
+#include <mcld/LD/ELFReader.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/Target/GNULDBackend.h>
+
+#include <string>
+#include <cassert>
+
+using namespace llvm;
+using namespace mcld;
+
+//==========================
+// ELFObjectReader
+/// constructor
+ELFObjectReader::ELFObjectReader(GNULDBackend& pBackend, MCLinker& pLinker)
+ : ObjectReader(),
+ m_pELFReader(0),
+ m_Linker(pLinker)
+{
+ if (32 == pBackend.bitclass() && pBackend.isLittleEndian()) {
+ m_pELFReader = new ELFReader<32, true>(pBackend);
+ }
+}
+
+/// destructor
+ELFObjectReader::~ELFObjectReader()
+{
+ delete m_pELFReader;
+}
+
+/// isMyFormat
+bool ELFObjectReader::isMyFormat(Input &pInput) const
+{
+ assert(pInput.hasMemArea());
+
+ // Don't warning about the frequently requests.
+ // MemoryArea has a list of cache to handle this.
+ size_t hdr_size = m_pELFReader->getELFHeaderSize();
+ MemoryRegion* region = pInput.memArea()->request(0, hdr_size);
+
+ uint8_t* ELF_hdr = region->start();
+ bool result = true;
+ if (!m_pELFReader->isELF(ELF_hdr))
+ result = false;
+ else if (!m_pELFReader->isMyEndian(ELF_hdr))
+ result = false;
+ else if (!m_pELFReader->isMyMachine(ELF_hdr))
+ result = false;
+ else if (MCLDFile::Object != m_pELFReader->fileType(ELF_hdr))
+ result = false;
+ pInput.memArea()->release(region);
+ return result;
+}
+
+/// readObject - read section header and create LDSections.
+bool ELFObjectReader::readObject(Input& pInput)
+{
+ assert(pInput.hasMemArea());
+
+ size_t hdr_size = m_pELFReader->getELFHeaderSize();
+ MemoryRegion* region = pInput.memArea()->request(0, hdr_size);
+ uint8_t* ELF_hdr = region->start();
+ bool result = m_pELFReader->readSectionHeaders(pInput, m_Linker, ELF_hdr);
+ pInput.memArea()->release(region);
+ return result;
+}
+
+/// readSections - read all regular sections.
+bool ELFObjectReader::readSections(Input& pInput)
+{
+ // handle sections
+ LDContext::sect_iterator section, sectEnd = pInput.context()->sectEnd();
+ for (section = pInput.context()->sectBegin(); section != sectEnd; ++section) {
+ // ignore the section if the LDSection* in input context is NULL
+ if (NULL == *section)
+ continue;
+
+ switch((*section)->kind()) {
+ /** group sections **/
+ case LDFileFormat::Group: {
+ assert(NULL != (*section)->getLink());
+ ResolveInfo* signature =
+ m_pELFReader->readSymbol(pInput,
+ *(*section)->getLink(),
+ m_Linker.getLDInfo(),
+ (*section)->getInfo());
+
+ bool exist = false;
+ signatures().insert(signature->name(), exist);
+
+ if (exist) {
+ // if this is not the first time we see this group signature, then
+ // ignore all the members in this group (set NULL)
+ MemoryRegion* region =
+ pInput.memArea()->request((*section)->offset(),
+ (*section)->size());
+ llvm::ELF::Elf32_Word* value =
+ reinterpret_cast<llvm::ELF::Elf32_Word*>(region->start());
+
+ size_t size = region->size() / sizeof(llvm::ELF::Elf32_Word);
+ if (llvm::ELF::GRP_COMDAT == *value) {
+ for (size_t index = 1; index < size; ++index)
+ pInput.context()->getSectionTable()[value[index]] = NULL;
+ }
+ pInput.memArea()->release(region);
+ }
+ break;
+ }
+ /** relocation sections **/
+ case LDFileFormat::Relocation: {
+ assert(NULL != (*section)->getLink());
+ size_t link_index = (*section)->getLink()->index();
+ if (NULL == pInput.context()->getSectionTable()[link_index]) {
+ // Relocation sections of group members should also be part of the
+ // group. Thus, if the associated member sections are ignored, the
+ // related relocations should be also ignored.
+ *section = NULL;
+ }
+ break;
+ }
+ /** normal sections **/
+ // FIXME: support Debug, Exception and Version Kinds
+ case LDFileFormat::Debug:
+ case LDFileFormat::Exception:
+ case LDFileFormat::Version:
+ /** Fall through **/
+ case LDFileFormat::Regular:
+ case LDFileFormat::Note:
+ case LDFileFormat::MetaData: {
+ if (!m_pELFReader->readRegularSection(pInput, m_Linker, **section))
+ llvm::report_fatal_error(
+ llvm::Twine("can not read regular section `") +
+ (*section)->name() +
+ llvm::Twine("'.\n"));
+ break;
+ }
+ /** target dependent sections **/
+ case LDFileFormat::Target: {
+ if (!m_pELFReader->readTargetSection(pInput, m_Linker, **section))
+ llvm::report_fatal_error(
+ llvm::Twine("can not read target dependentsection `") +
+ (*section)->name() +
+ llvm::Twine("'.\n"));
+ break;
+ }
+ /** BSS sections **/
+ case LDFileFormat::BSS: {
+ LDSection& output_bss = m_Linker.getOrCreateOutputSectHdr(
+ (*section)->name(),
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE);
+
+ llvm::MCSectionData& sect_data = m_Linker.getOrCreateSectData(**section);
+ /* value, valsize, size*/
+ llvm::MCFillFragment* frag =
+ new llvm::MCFillFragment(0x0, 1, (*section)->size());
+
+ uint64_t size = m_Linker.getLayout().appendFragment(*frag,
+ sect_data,
+ (*section)->align());
+ output_bss.setSize(output_bss.size() + size);
+ break;
+ }
+ // ignore
+ case LDFileFormat::Null:
+ case LDFileFormat::NamePool:
+ continue;
+
+ }
+ } // end of for all sections
+
+ return true;
+}
+
+/// readSymbols - read symbols into MCLinker from the input relocatable object.
+bool ELFObjectReader::readSymbols(Input& pInput)
+{
+ assert(pInput.hasMemArea());
+
+ LDSection* symtab_shdr = pInput.context()->getSection(".symtab");
+ LDSection* strtab_shdr = symtab_shdr->getLink();
+ if (NULL == symtab_shdr || NULL == strtab_shdr)
+ return false;
+
+ MemoryRegion* symtab_region = pInput.memArea()->request(symtab_shdr->offset(),
+ symtab_shdr->size());
+ MemoryRegion* strtab_region = pInput.memArea()->request(strtab_shdr->offset(),
+ strtab_shdr->size());
+ char* strtab = reinterpret_cast<char*>(strtab_region->start());
+ bool result = m_pELFReader->readSymbols(pInput,
+ m_Linker,
+ *symtab_region,
+ strtab);
+ pInput.memArea()->release(symtab_region);
+ pInput.memArea()->release(strtab_region);
+ return result;
+}
+
+bool ELFObjectReader::readRelocations(Input& pInput)
+{
+ assert(pInput.hasMemArea());
+
+ MemoryArea* mem = pInput.memArea();
+ LDContext::sect_iterator section, sectEnd = pInput.context()->sectEnd();
+ for (section = pInput.context()->sectBegin(); section != sectEnd; ++section) {
+ // ignore the section if the LDSection* in input context is NULL
+ if (NULL == *section)
+ continue;
+
+ if ((*section)->type() == llvm::ELF::SHT_RELA &&
+ (*section)->kind() == LDFileFormat::Relocation) {
+ MemoryRegion* region = mem->request((*section)->offset(), (*section)->size());
+ bool result = m_pELFReader->readRela(pInput, m_Linker, **section, *region);
+ mem->release(region);
+ if (!result)
+ return false;
+ }
+ else if ((*section)->type() == llvm::ELF::SHT_REL &&
+ (*section)->kind() == LDFileFormat::Relocation) {
+ MemoryRegion* region = mem->request((*section)->offset(), (*section)->size());
+ bool result = m_pELFReader->readRel(pInput, m_Linker, **section, *region);
+ mem->release(region);
+ if (!result)
+ return false;
+ }
+ }
+ return true;
+}
+
diff --git a/lib/LD/ELFObjectWriter.cpp b/lib/LD/ELFObjectWriter.cpp
new file mode 100644
index 0000000..2795d3f
--- /dev/null
+++ b/lib/LD/ELFObjectWriter.cpp
@@ -0,0 +1,23 @@
+//===- ELFObjectWriter.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/ELFObjectWriter.h"
+
+using namespace mcld;
+
+//==========================
+// ELFObjectWriter
+ELFObjectWriter::ELFObjectWriter(GNULDBackend& pBackend, MCLinker& pLinker)
+ : ObjectWriter(pBackend), ELFWriter(pBackend), m_Linker(pLinker) {
+}
+
+ELFObjectWriter::~ELFObjectWriter()
+{
+}
+
+
diff --git a/lib/LD/ELFReader.cpp b/lib/LD/ELFReader.cpp
new file mode 100644
index 0000000..1fd2a13
--- /dev/null
+++ b/lib/LD/ELFReader.cpp
@@ -0,0 +1,188 @@
+//===- ELFReader.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/Support/ELF.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/Host.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/LD/ELFReader.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <cstring>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ELFReaderIF
+/// getLDSectionKind
+LDFileFormat::Kind
+ELFReaderIF::getLDSectionKind(uint32_t pType, const char* pName) const
+{
+ // name rules
+ llvm::StringRef name(pName);
+ if (llvm::StringRef::npos != name.find(".debug"))
+ return LDFileFormat::Debug;
+ if (name.startswith(".comment"))
+ return LDFileFormat::MetaData;
+ if (name.startswith(".interp") || name.startswith(".dynamic"))
+ return LDFileFormat::Note;
+ if (name.startswith(".eh_frame") ||
+ name.startswith(".eh_frame_hdr") ||
+ name.startswith(".gcc_except_table"))
+ return LDFileFormat::Exception;
+
+ // type rules
+ switch(pType) {
+ case llvm::ELF::SHT_NULL:
+ return LDFileFormat::Null;
+ case llvm::ELF::SHT_INIT_ARRAY:
+ case llvm::ELF::SHT_FINI_ARRAY:
+ case llvm::ELF::SHT_PREINIT_ARRAY:
+ case llvm::ELF::SHT_PROGBITS:
+ return LDFileFormat::Regular;
+ case llvm::ELF::SHT_SYMTAB:
+ case llvm::ELF::SHT_DYNSYM:
+ case llvm::ELF::SHT_STRTAB:
+ return LDFileFormat::NamePool;
+ case llvm::ELF::SHT_RELA:
+ case llvm::ELF::SHT_REL:
+ return LDFileFormat::Relocation;
+ case llvm::ELF::SHT_NOBITS:
+ return LDFileFormat::BSS;
+ case llvm::ELF::SHT_DYNAMIC:
+ case llvm::ELF::SHT_NOTE:
+ return LDFileFormat::Note;
+ case llvm::ELF::SHT_HASH:
+ case llvm::ELF::SHT_SHLIB:
+ return LDFileFormat::MetaData;
+ case llvm::ELF::SHT_GROUP:
+ return LDFileFormat::Group;
+ case llvm::ELF::SHT_GNU_versym:
+ case llvm::ELF::SHT_GNU_verdef:
+ case llvm::ELF::SHT_GNU_verneed:
+ return LDFileFormat::Version;
+ default:
+ if ((pType >= llvm::ELF::SHT_LOPROC && pType <= llvm::ELF::SHT_HIPROC) ||
+ (pType >= llvm::ELF::SHT_LOOS && pType <= llvm::ELF::SHT_HIOS) ||
+ (pType >= llvm::ELF::SHT_LOUSER && pType <= llvm::ELF::SHT_HIUSER))
+ return LDFileFormat::Target;
+ llvm::report_fatal_error(llvm::Twine("unsupported ELF section type: ") +
+ llvm::Twine(pType) + llvm::Twine(".\n"));
+ }
+ return LDFileFormat::MetaData;
+}
+
+/// getSymDesc
+ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const
+{
+ if (pShndx == llvm::ELF::SHN_UNDEF)
+ return ResolveInfo::Undefined;
+
+ if (pShndx < llvm::ELF::SHN_LORESERVE) {
+ // an ELF symbol defined in a section which we are not including
+ // must be treated as an Undefined.
+ // @ref Google gold linker: symtab.cc: 1086
+ if (NULL == pInput.context()->getSection(pShndx))
+ return ResolveInfo::Undefined;
+ return ResolveInfo::Define;
+ }
+
+ if (pShndx == llvm::ELF::SHN_ABS)
+ return ResolveInfo::Define;
+
+ if (pShndx == llvm::ELF::SHN_COMMON)
+ return ResolveInfo::Common;
+
+ // FIXME: ELF weak alias should be ResolveInfo::Indirect
+ return ResolveInfo::NoneDesc;
+}
+
+/// getSymBinding
+ResolveInfo::Binding
+ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const
+{
+
+ // TODO:
+ // if --just-symbols option is enabled, the symbol must covert to Absolute
+
+ switch(pBinding) {
+ case llvm::ELF::STB_LOCAL:
+ return ResolveInfo::Local;
+ case llvm::ELF::STB_GLOBAL:
+ return ResolveInfo::Global;
+ case llvm::ELF::STB_WEAK:
+ return ResolveInfo::Weak;
+ }
+
+ if (pShndx == llvm::ELF::SHN_ABS)
+ return ResolveInfo::Absolute;
+
+ return ResolveInfo::NoneBinding;
+}
+
+/// getSymFragmentRef
+MCFragmentRef*
+ELFReaderIF::getSymFragmentRef(Input& pInput,
+ MCLinker& pLinker,
+ uint16_t pShndx,
+ uint32_t pOffset) const
+{
+
+ if (pShndx == llvm::ELF::SHN_UNDEF || pShndx >= llvm::ELF::SHN_LORESERVE)
+ return NULL;
+
+ LDSection* sect_hdr = pInput.context()->getSection(pShndx);
+
+ if (NULL == sect_hdr) {
+ llvm::report_fatal_error(llvm::Twine("section[") +
+ llvm::Twine(pShndx) +
+ llvm::Twine("] is invalid in file `") +
+ pInput.path().native() +
+ llvm::Twine("'.\n"));
+ }
+
+ MCFragmentRef* result = pLinker.getLayout().getFragmentRef(*sect_hdr, pOffset);
+ return result;
+}
+
+/// getSymVisibility
+ResolveInfo::Visibility
+ELFReaderIF::getSymVisibility(uint8_t pVis) const
+{
+ return static_cast<ResolveInfo::Visibility>(pVis);
+}
+
+/// getSymValue - get the section offset of the symbol.
+uint64_t ELFReaderIF::getSymValue(uint64_t pValue,
+ uint16_t pShndx,
+ const Input& pInput) const
+{
+ if (Input::Object == pInput.type()) {
+ // In relocatable files, st_value holds alignment constraints for a symbol
+ // whose section index is SHN_COMMON
+ if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) {
+ return pValue;
+ }
+
+ // In relocatable files, st_value holds a section offset for a defined symbol.
+ // TODO:
+ // if --just-symbols option are enabled, convert the value from section offset
+ // to virtual address by adding input section's virtual address.
+ // The section's virtual address in relocatable files is normally zero, but
+ // people can use link script to change it.
+ return pValue;
+ }
+
+ // In executable and shared object files, st_value holds a virtual address.
+ // the virtual address is useless during linking.
+ return 0x0;
+}
+
diff --git a/lib/LD/ELFSegment.cpp b/lib/LD/ELFSegment.cpp
new file mode 100644
index 0000000..a08641b
--- /dev/null
+++ b/lib/LD/ELFSegment.cpp
@@ -0,0 +1,35 @@
+//===- ELFSegment.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFSegment.h>
+
+using namespace mcld;
+
+//==========================
+// ELFSegment
+ELFSegment::ELFSegment(uint32_t pType,
+ uint32_t pFlag,
+ uint64_t pOffset,
+ uint64_t pVaddr,
+ uint64_t pPaddr,
+ uint64_t pFilesz,
+ uint64_t pMemsz,
+ uint64_t pAlign)
+ : m_Type(pType),
+ m_Flag(pFlag),
+ m_Offset(pOffset),
+ m_Vaddr(pVaddr),
+ m_Paddr(pPaddr),
+ m_Filesz(pFilesz),
+ m_Memsz(pMemsz),
+ m_Align(pAlign) {
+}
+
+ELFSegment::~ELFSegment()
+{
+}
diff --git a/lib/LD/ELFSegmentFactory.cpp b/lib/LD/ELFSegmentFactory.cpp
new file mode 100644
index 0000000..d8ad3cc
--- /dev/null
+++ b/lib/LD/ELFSegmentFactory.cpp
@@ -0,0 +1,40 @@
+//===- ELFSegmentFactory.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFSegmentFactory.h>
+
+using namespace mcld;
+
+//==========================
+// ELFSegmentFactory
+
+ELFSegmentFactory::ELFSegmentFactory(size_t pNum)
+ : GCFactory<ELFSegment, 0>(pNum)
+{
+}
+
+ELFSegmentFactory::~ELFSegmentFactory()
+{
+}
+
+/// produce - produce an empty ELF segment information.
+/// this function will create an ELF segment
+/// @param pType - p_type in ELF program header
+ELFSegment* ELFSegmentFactory::produce(uint32_t pType)
+{
+ ELFSegment* segment = allocate();
+ new (segment) ELFSegment(pType);
+ return segment;
+}
+
+/// destroy - destruct the ELF segment
+void ELFSegmentFactory::destroy(ELFSegment*& pSegment)
+{
+ deallocate(pSegment);
+}
+
diff --git a/lib/LD/ELFWriter.cpp b/lib/LD/ELFWriter.cpp
new file mode 100644
index 0000000..a94fd5c
--- /dev/null
+++ b/lib/LD/ELFWriter.cpp
@@ -0,0 +1,583 @@
+//===- ELFWriter.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/MC/MCAssembler.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/LD/ELFWriter.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <cstdlib>
+#include <cstring>
+
+using namespace llvm::ELF;
+using namespace mcld;
+
+/// writeELF32Header - write ELF header
+void ELFWriter::writeELF32Header(const MCLDInfo& pLDInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ Output& pOutput) const
+{
+ assert(pOutput.hasMemArea());
+
+ // ELF header must start from 0x0
+ MemoryRegion *region = pOutput.memArea()->request(0,
+ sizeof(Elf32_Ehdr));
+ Elf32_Ehdr* header = (Elf32_Ehdr*)region->start();
+
+ memcpy(header->e_ident, ElfMagic, EI_MAG3+1);
+
+ header->e_ident[EI_CLASS] = ELFCLASS32;
+ header->e_ident[EI_DATA] = pBackend.isLittleEndian()?
+ ELFDATA2LSB : ELFDATA2MSB;
+ header->e_ident[EI_VERSION] = pBackend.ELFVersion();
+ header->e_ident[EI_OSABI] = pBackend.OSABI();
+ header->e_ident[EI_ABIVERSION] = pBackend.ABIVersion();
+
+ // FIXME: add processor-specific and core file types.
+ switch(pOutput.type()) {
+ case Output::Object:
+ header->e_type = ET_REL;
+ break;
+ case Output::DynObj:
+ header->e_type = ET_DYN;
+ break;
+ case Output::Exec:
+ header->e_type = ET_EXEC;
+ break;
+ default:
+ llvm::errs() << "unspported output file type: " << pOutput.type() << ".\n";
+ header->e_type = ET_NONE;
+ }
+ header->e_machine = pBackend.machine();
+ header->e_version = header->e_ident[EI_VERSION];
+ header->e_entry = getEntryPoint(pLDInfo, pLayout, pBackend, pOutput);
+ header->e_phoff = sizeof(Elf32_Ehdr);
+ header->e_shoff = getELF32LastStartOffset(pOutput);
+ header->e_flags = pBackend.flags();
+ header->e_ehsize = sizeof(Elf32_Ehdr);
+ header->e_phentsize = sizeof(Elf32_Phdr);
+ header->e_phnum = pBackend.numOfSegments();
+ header->e_shentsize = sizeof(Elf32_Shdr);
+ header->e_shnum = pOutput.context()->numOfSections();
+ header->e_shstrndx = pOutput.context()->getSectionIdx(".shstrtab");
+}
+
+/// writeELF64Header - write ELF header
+void ELFWriter::writeELF64Header(const MCLDInfo& pLDInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ Output& pOutput) const
+{
+ assert(pOutput.hasMemArea());
+
+ // ELF header must start from 0x0
+ MemoryRegion *region = pOutput.memArea()->request(0,
+ sizeof(Elf64_Ehdr));
+ Elf64_Ehdr* header = (Elf64_Ehdr*)region->start();
+
+ memcpy(header->e_ident, ElfMagic, EI_MAG3+1);
+
+ header->e_ident[EI_CLASS] = ELFCLASS64;
+ header->e_ident[EI_DATA] = pBackend.isLittleEndian()?
+ ELFDATA2LSB : ELFDATA2MSB;
+ header->e_ident[EI_VERSION] = pBackend.ELFVersion();
+ header->e_ident[EI_OSABI] = pBackend.OSABI();
+ header->e_ident[EI_ABIVERSION] = pBackend.ABIVersion();
+
+ // FIXME: add processor-specific and core file types.
+ switch(pOutput.type()) {
+ case Output::Object:
+ header->e_type = ET_REL;
+ break;
+ case Output::DynObj:
+ header->e_type = ET_DYN;
+ break;
+ case Output::Exec:
+ header->e_type = ET_EXEC;
+ break;
+ default:
+ llvm::errs() << "unspported output file type: " << pOutput.type() << ".\n";
+ header->e_type = ET_NONE;
+ }
+ header->e_machine = pBackend.machine();
+ header->e_version = header->e_ident[EI_VERSION];
+ header->e_entry = getEntryPoint(pLDInfo, pLayout, pBackend, pOutput);
+ header->e_phoff = sizeof(Elf64_Ehdr);
+ header->e_shoff = getELF64LastStartOffset(pOutput);
+ header->e_flags = pBackend.flags();
+ header->e_ehsize = sizeof(Elf64_Ehdr);
+ header->e_phentsize = sizeof(Elf64_Phdr);
+ header->e_phnum = pBackend.numOfSegments();
+ header->e_shentsize = sizeof(Elf64_Shdr);
+ header->e_shnum = pOutput.context()->numOfSections();
+ header->e_shstrndx = pOutput.context()->getSectionIdx(".shstrtab");
+}
+
+/// getEntryPoint
+uint64_t ELFWriter::getEntryPoint(const MCLDInfo& pLDInfo,
+ const Layout& pLayout,
+ const GNULDBackend& pBackend,
+ const Output& pOutput) const
+{
+
+ llvm::StringRef entry_name;
+ if (pLDInfo.options().hasEntry())
+ entry_name = pLDInfo.options().entry();
+ else
+ entry_name = pBackend.entry();
+
+ uint64_t result = 0x0;
+
+ bool issue_warning = (pLDInfo.options().hasEntry()
+ && (pOutput.type() != Output::Object)
+ && (pOutput.type() != Output::DynObj));
+
+ const LDSymbol* entry_symbol = pLDInfo.getStrSymPool().findSymbol(entry_name);
+
+ // found the symbol
+ if (NULL != entry_symbol) {
+ if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) {
+ llvm::errs() << "WARNING: entry symbol '"
+ << entry_symbol->name()
+ << "' exists but is not defined.\n";
+ }
+ result = entry_symbol->value();
+ }
+ // not in the symbol pool
+ else {
+ // We should parse entry as a number.
+ // @ref GNU ld manual, Options -e. e.g., -e 0x1000.
+ char* endptr;
+ result = strtoull(entry_name.data(), &endptr, 0);
+ if (*endptr != '\0') {
+ if (issue_warning) {
+ llvm::errs() << "cannot find entry symbol '"
+ << entry_name.data()
+ << "'.\n";
+ }
+ result = 0x0;
+ }
+ }
+ return result;
+}
+
+/// emitELF32SectionHeader - emit Elf32_Shdr
+void
+ELFWriter::emitELF32SectionHeader(Output& pOutput, MCLinker& pLinker) const
+{
+ // emit section header
+ unsigned int sectNum = pOutput.context()->numOfSections();
+ unsigned int header_size = sizeof(Elf32_Shdr) * sectNum;
+ MemoryRegion* region = pOutput.memArea()->request(
+ getELF32LastStartOffset(pOutput),
+ header_size);
+ Elf32_Shdr* shdr = (Elf32_Shdr*)region->start();
+
+ // Iterate the SectionTable in LDContext
+ unsigned int sectIdx = 0;
+ unsigned int shstridx = 0; // NULL section has empty name
+ for (; sectIdx < sectNum; ++sectIdx) {
+ const LDSection *ld_sect = pOutput.context()->getSection(sectIdx);
+ shdr[sectIdx].sh_name = shstridx;
+ shdr[sectIdx].sh_type = ld_sect->type();
+ shdr[sectIdx].sh_flags = ld_sect->flag();
+ shdr[sectIdx].sh_addr = ld_sect->addr();
+ shdr[sectIdx].sh_offset = ld_sect->offset();
+ shdr[sectIdx].sh_size = ld_sect->size();
+ shdr[sectIdx].sh_addralign = ld_sect->align();
+ shdr[sectIdx].sh_entsize = getELF32SectEntrySize(*ld_sect);
+ shdr[sectIdx].sh_link = getSectLink(*ld_sect, pOutput);
+ shdr[sectIdx].sh_info = getSectInfo(*ld_sect, pOutput);
+
+ // adjust strshidx
+ shstridx += ld_sect->name().size() + 1;
+ }
+}
+
+/// emitELF64SectionHeader - emit Elf64_Shdr
+void
+ELFWriter::emitELF64SectionHeader(Output& pOutput, MCLinker& pLinker) const
+{
+ // emit section header
+ unsigned int sectNum = pOutput.context()->numOfSections();
+ unsigned int header_size = sizeof(Elf64_Shdr) * sectNum;
+ MemoryRegion* region = pOutput.memArea()->request(
+ getELF64LastStartOffset(pOutput),
+ header_size);
+ Elf64_Shdr* shdr = (Elf64_Shdr*)region->start();
+
+ // Iterate the SectionTable in LDContext
+ unsigned int sectIdx = 0;
+ unsigned int shstridx = 0; // NULL section has empty name
+ for (; sectIdx < sectNum; ++sectIdx) {
+ const LDSection *ld_sect = pOutput.context()->getSection(sectIdx);
+ shdr[sectIdx].sh_name = shstridx;
+ shdr[sectIdx].sh_type = ld_sect->type();
+ shdr[sectIdx].sh_flags = ld_sect->flag();
+ shdr[sectIdx].sh_addr = ld_sect->addr();
+ shdr[sectIdx].sh_offset = ld_sect->offset();
+ shdr[sectIdx].sh_size = ld_sect->size();
+ shdr[sectIdx].sh_addralign = (ld_sect->hasSectionData())?
+ ld_sect->getSectionData()->getAlignment():
+ 0x0;
+
+ shdr[sectIdx].sh_entsize = getELF64SectEntrySize(*ld_sect);
+ shdr[sectIdx].sh_link = getSectLink(*ld_sect, pOutput);
+ shdr[sectIdx].sh_info = getSectInfo(*ld_sect, pOutput);
+
+ // adjust strshidx
+ shstridx += ld_sect->name().size() + 1;
+ }
+}
+
+/// emitELF32ShStrTab - emit section string table
+void ELFWriter::emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const
+{
+ uint64_t shstroffset = getELF32LastStartOffset(pOutput);
+
+ // get shstrtab
+ LDSection& shstrtab = pLinker.getOrCreateOutputSectHdr(".shstrtab",
+ LDFileFormat::NamePool,
+ SHT_STRTAB,
+ 0x0);
+ if (0 != shstrtab.size())
+ llvm::report_fatal_error(".shstrtab has been set.\n");
+
+ // compute size
+ unsigned int shstrsize = 0;
+ LDContext::const_sect_iterator section, sectEnd = pOutput.context()->sectEnd();
+ for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) {
+ shstrsize += (*section)->name().size() + 1;
+ }
+
+ shstrtab.setSize(shstrsize);
+ shstrtab.setOffset(shstroffset);
+
+ // write out data
+ MemoryRegion* region = pOutput.memArea()->request(shstrtab.offset(),
+ shstrtab.size());
+ unsigned char* data = region->start();
+ shstrsize = 0;
+ for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) {
+ strcpy((char*)(data + shstrsize), (*section)->name().c_str());
+ shstrsize += (*section)->name().size() + 1;
+ }
+
+ shstrtab.setKind(LDFileFormat::NamePool);
+ shstrtab.setType(llvm::ELF::SHT_STRTAB);
+ shstrtab.setFlag(0x0);
+ shstrtab.setAddr(0x0);
+}
+
+
+/// emitELF64ShStrTab - emit section string table
+void ELFWriter::emitELF64ShStrTab(Output& pOutput, MCLinker& pLinker) const
+{
+ uint64_t shstroffset = getELF64LastStartOffset(pOutput);
+
+ // get shstrtab
+ LDSection& shstrtab = pLinker.getOrCreateOutputSectHdr(".shstrtab",
+ LDFileFormat::NamePool,
+ SHT_STRTAB,
+ 0x0);
+ if (0 != shstrtab.size())
+ llvm::report_fatal_error(".shstrtab has been set.\n");
+
+ // compute offset
+
+ // compute size
+ unsigned int shstrsize = 0;
+ LDContext::const_sect_iterator section, sectEnd = pOutput.context()->sectEnd();
+ for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) {
+ shstrsize += (*section)->name().size() + 1;
+ }
+
+ shstrtab.setSize(shstrsize);
+ shstrtab.setOffset(shstroffset);
+
+ // write out data
+ MemoryRegion* region = pOutput.memArea()->request(shstrtab.offset(),
+ shstrtab.size());
+ unsigned char* data = region->start();
+ shstrsize = 0;
+ for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) {
+ strcpy((char*)(data + shstrsize), (*section)->name().c_str());
+ shstrsize += (*section)->name().size() + 1;
+ }
+
+ shstrtab.setKind(LDFileFormat::NamePool);
+ shstrtab.setType(llvm::ELF::SHT_STRTAB);
+ shstrtab.setFlag(0x0);
+ shstrtab.setAddr(0x0);
+}
+
+/// emitSectionData
+void
+ELFWriter::emitSectionData(const Layout& pLayout,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const
+{
+ const llvm::MCSectionData* data = pSection.getSectionData();
+ llvm::MCSectionData::const_iterator fragIter, fragEnd = data->end();
+ size_t cur_offset = 0;
+ for (fragIter = data->begin(); fragIter != fragEnd; ++fragIter) {
+ size_t size = computeFragmentSize(pLayout, *fragIter);
+ switch(fragIter->getKind()) {
+ case llvm::MCFragment::FT_Region: {
+ const MCRegionFragment& region_frag = llvm::cast<MCRegionFragment>(*fragIter);
+ const uint8_t* from = region_frag.getRegion().start();
+ memcpy(pRegion.getBuffer(cur_offset), from, size);
+ break;
+ }
+ case llvm::MCFragment::FT_Align: {
+ // TODO: emit values with different sizes (> 1 byte), and emit nops
+ llvm::MCAlignFragment& align_frag = llvm::cast<llvm::MCAlignFragment>(*fragIter);
+ uint64_t count = size / align_frag.getValueSize();
+ switch (align_frag.getValueSize()) {
+ case 1u:
+ std::memset(pRegion.getBuffer(cur_offset),
+ align_frag.getValue(),
+ count);
+ break;
+ default:
+ llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n");
+ break;
+ }
+ break;
+ }
+ case llvm::MCFragment::FT_Fill: {
+ llvm::MCFillFragment& fill_frag = llvm::cast<llvm::MCFillFragment>(*fragIter);
+ if (0 == size ||
+ 0 == fill_frag.getValueSize() ||
+ 0 == fill_frag.getSize()) {
+ // ignore virtual fillment
+ break;
+ }
+
+ uint64_t num_tiles = fill_frag.getSize() / fill_frag.getValueSize();
+ for (uint64_t i = 0; i != num_tiles; ++i) {
+ std::memset(pRegion.getBuffer(cur_offset),
+ fill_frag.getValue(),
+ fill_frag.getValueSize());
+ }
+ break;
+ }
+ case llvm::MCFragment::FT_Data:
+ case llvm::MCFragment::FT_Inst:
+ case llvm::MCFragment::FT_Org:
+ case llvm::MCFragment::FT_Dwarf:
+ case llvm::MCFragment::FT_DwarfFrame:
+ case llvm::MCFragment::FT_LEB: {
+ llvm::report_fatal_error("unsupported fragment yet.\n");
+ break;
+ }
+ case llvm::MCFragment::FT_Reloc:
+ llvm::report_fatal_error("relocation fragment should not be in a regular section.\n");
+ break;
+ case llvm::MCFragment::FT_Target:
+ llvm::report_fatal_error("Target fragment should not be in a regular section.\n");
+ break;
+ default:
+ llvm::report_fatal_error("invalid fragment should not be in a regular section.\n");
+ break;
+ }
+ cur_offset += size;
+ }
+}
+
+/// emitRelocation
+void ELFWriter::emitRelocation(const Layout& pLayout,
+ const Output& pOutput,
+ const LDSection& pSection,
+ MemoryRegion& pRegion) const
+{
+ const llvm::MCSectionData* SectionData = pSection.getSectionData();
+ assert(SectionData && "SectionData is NULL in emitRelocation!");
+
+ if (pSection.type() == SHT_REL)
+ emitRel(pLayout, pOutput, *SectionData, pRegion);
+ else if (pSection.type() == SHT_RELA)
+ emitRela(pLayout, pOutput, *SectionData, pRegion);
+ else
+ llvm::report_fatal_error("unsupported relocation section type!");
+}
+
+
+/// emitRel
+void ELFWriter::emitRel(const Layout& pLayout,
+ const Output& pOutput,
+ const llvm::MCSectionData& pSectionData,
+ MemoryRegion& pRegion) const
+{
+ Elf32_Rel* rel = reinterpret_cast<Elf32_Rel*>(pRegion.start());
+
+ Relocation* relocation = 0;
+ MCFragmentRef* FragmentRef = 0;
+
+ for (llvm::MCSectionData::const_iterator it = pSectionData.begin(),
+ ie = pSectionData.end(); it != ie; ++it, ++rel) {
+
+ relocation = &(llvm::cast<Relocation>(*it));
+ FragmentRef = &(relocation->targetRef());
+
+ if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec) {
+ rel->r_offset = static_cast<Elf32_Addr>(
+ llvm::cast<LDSection>(
+ FragmentRef->frag()->getParent()->getSection()).addr() +
+ pLayout.getOutputOffset(*FragmentRef));
+ }
+ else {
+ rel->r_offset = static_cast<Elf32_Addr>(
+ llvm::cast<LDSection>(
+ FragmentRef->frag()->getParent()->getSection()).offset() +
+ pLayout.getOutputOffset(*FragmentRef));
+ }
+
+ Elf32_Word Index;
+ if( relocation->symInfo() == NULL )
+ Index = 0;
+ else
+ Index = static_cast<Elf32_Word>(
+ f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol()));
+
+ rel->setSymbolAndType(Index, relocation->type());
+ }
+}
+
+/// emitRela
+void ELFWriter::emitRela(const Layout& pLayout,
+ const Output& pOutput,
+ const llvm::MCSectionData& pSectionData,
+ MemoryRegion& pRegion) const
+{
+ Elf32_Rela* rel = reinterpret_cast<Elf32_Rela*>(pRegion.start());
+
+ Relocation* relocation = 0;
+ MCFragmentRef* FragmentRef = 0;
+
+ for (llvm::MCSectionData::const_iterator it = pSectionData.begin(),
+ ie = pSectionData.end(); it != ie; ++it, ++rel) {
+
+ relocation = &(llvm::cast<Relocation>(*it));
+ FragmentRef = &(relocation->targetRef());
+
+ if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec) {
+ rel->r_offset = static_cast<Elf32_Addr>(
+ llvm::cast<LDSection>(
+ FragmentRef->frag()->getParent()->getSection()).addr() +
+ pLayout.getOutputOffset(*FragmentRef));
+ }
+ else {
+ rel->r_offset = static_cast<Elf32_Addr>(
+ llvm::cast<LDSection>(
+ FragmentRef->frag()->getParent()->getSection()).offset() +
+ pLayout.getOutputOffset(*FragmentRef));
+ }
+
+ Elf32_Word Index;
+ if( relocation->symInfo() == NULL )
+ Index = 0;
+ else
+ Index = static_cast<Elf32_Word>(
+ f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol()));
+
+ rel->setSymbolAndType(Index, relocation->type());
+ rel->r_addend = relocation->addend();
+ }
+}
+
+/// getELF32SectEntrySize - compute Elf32_Shdr::sh_entsize
+uint64_t ELFWriter::getELF32SectEntrySize(const LDSection& pSection) const
+{
+ if (llvm::ELF::SHT_DYNSYM == pSection.type() ||
+ llvm::ELF::SHT_SYMTAB == pSection.type())
+ return sizeof(llvm::ELF::Elf32_Sym);
+ if (llvm::ELF::SHT_REL == pSection.type())
+ return sizeof(llvm::ELF::Elf32_Rel);
+ if (llvm::ELF::SHT_RELA == pSection.type())
+ return sizeof(llvm::ELF::Elf32_Rela);
+ if (llvm::ELF::SHT_HASH == pSection.type())
+ return sizeof(llvm::ELF::Elf32_Word);
+ if (llvm::ELF::SHT_DYNAMIC == pSection.type())
+ return sizeof(llvm::ELF::Elf32_Dyn);
+ return 0x0;
+}
+
+/// getELF64SectEntrySize - compute Elf64_Shdr::sh_entsize
+uint64_t ELFWriter::getELF64SectEntrySize(const LDSection& pSection) const
+{
+ if (llvm::ELF::SHT_DYNSYM == pSection.type() ||
+ llvm::ELF::SHT_SYMTAB == pSection.type())
+ return sizeof(llvm::ELF::Elf64_Sym);
+ if (llvm::ELF::SHT_REL == pSection.type())
+ return sizeof(llvm::ELF::Elf64_Rel);
+ if (llvm::ELF::SHT_RELA == pSection.type())
+ return sizeof(llvm::ELF::Elf64_Rela);
+ if (llvm::ELF::SHT_HASH == pSection.type())
+ return sizeof(llvm::ELF::Elf64_Word);
+ if (llvm::ELF::SHT_DYNAMIC == pSection.type())
+ return sizeof(llvm::ELF::Elf64_Dyn);
+ return 0x0;
+}
+
+/// getSectLink - compute ElfXX_Shdr::sh_link
+uint64_t ELFWriter::getSectLink(const LDSection& pSection, const Output& pOutput) const
+{
+ const LDContext* context = pOutput.context();
+ if (llvm::ELF::SHT_SYMTAB == pSection.type())
+ return context->getSectionIdx(".strtab");
+ if (llvm::ELF::SHT_DYNSYM == pSection.type())
+ return context->getSectionIdx(".dynstr");
+ if (llvm::ELF::SHT_DYNAMIC == pSection.type())
+ return context->getSectionIdx(".dynstr");
+ if (llvm::ELF::SHT_HASH == pSection.type())
+ return context->getSectionIdx(".dynsym");
+ if (llvm::ELF::SHT_REL == pSection.type() ||
+ llvm::ELF::SHT_RELA == pSection.type()) {
+ if (pOutput.type() == Output::Object)
+ return context->getSectionIdx(".symtab");
+ else
+ return context->getSectionIdx(".dynsym");
+ }
+ return llvm::ELF::SHN_UNDEF;
+}
+
+/// getSectInfo - compute ElfXX_Shdr::sh_info
+uint64_t ELFWriter::getSectInfo(const LDSection& pSection, const Output& pOutput) const
+{
+ const LDSection* info_link = pSection.getLink();
+ if (NULL == info_link)
+ return 0x0;
+ return info_link->index();
+}
+
+/// getELF32LastStartOffset
+uint64_t ELFWriter::getELF32LastStartOffset(const Output& pOutput) const
+{
+ LDSection* lastSect = pOutput.context()->getSectionTable().back();
+ assert(lastSect != NULL);
+ return Align<32>(lastSect->offset() + lastSect->size());
+}
+
+/// getELF64LastStartOffset
+uint64_t ELFWriter::getELF64LastStartOffset(const Output& pOutput) const
+{
+ LDSection* lastSect = pOutput.context()->getSectionTable().back();
+ assert(lastSect != NULL);
+ return Align<64>(lastSect->offset() + lastSect->size());
+}
+
diff --git a/lib/LD/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp
new file mode 100644
index 0000000..3fa00b8
--- /dev/null
+++ b/lib/LD/GNUArchiveReader.cpp
@@ -0,0 +1,356 @@
+//===- GNUArchiveReader.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDInfo.h"
+#include "mcld/MC/MCLDInput.h"
+#include "mcld/MC/MCLDInputTree.h"
+#include "mcld/LD/GNUArchiveReader.h"
+
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/system_error.h>
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <cstdlib>
+
+using namespace std;
+using namespace mcld;
+
+typedef size_t sectionSizeTy;
+typedef uint32_t elfWord;
+
+/// Archive Header, Magic number, etc..
+
+const unsigned archiveMagicSize = 8;
+const char archiveMagic[archiveMagicSize] = { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' };
+const char thinArchiveMagic[archiveMagicSize] = { '!', '<', 't', 'h', 'i', 'n', '>', '\n' };
+const char archiveFinalMagic[2] = { '`', '\n' };
+
+struct GNUArchiveReader::ArchiveMemberHeader
+{
+ char name[16];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char finalMagic[2];
+};
+
+struct GNUArchiveReader::SymbolTableEntry
+{
+ off_t fileOffset;
+ std::string name;
+};
+
+inline void endian_swap(unsigned int& x)
+{
+ x = (x>>24) |
+ ((x<<8) & 0x00FF0000) |
+ ((x>>8) & 0x0000FF00) |
+ (x<<24);
+}
+
+
+/// convert string to size_t
+template<class Type>
+Type stringToType(const std::string &str)
+{
+ Type n;
+ std::stringstream ss(str);
+ ss >> n;
+ return n;
+}
+
+
+/// GNUArchiveReader Operations
+/// Public API
+bool GNUArchiveReader::isMyFormat(Input &pInput) const
+{
+ llvm::OwningPtr<llvm::MemoryBuffer> mapFile;
+ llvm::MemoryBuffer::getFile(pInput.path().c_str(), mapFile);
+ const char* pFile = mapFile->getBufferStart();
+
+ /// check archive format.
+ if(mapFile->getBufferSize() <= archiveMagicSize)
+ return false;
+ bool isThinArchive = memcmp(pFile, thinArchiveMagic, archiveMagicSize) == 0;
+ if(!isThinArchive && memcmp(pFile, archiveMagic, archiveMagicSize) != 0)
+ return false;
+ return true;
+}
+
+LDReader::Endian GNUArchiveReader::endian(Input& pFile) const
+{
+ return m_endian;
+}
+
+InputTree *GNUArchiveReader::readArchive(Input &pInput)
+{
+ return setupNewArchive(pInput, 0);
+}
+
+/// Read Input as archive. First create a null InputTree.
+/// Then Construct Input object for corresponding member of this archive
+/// and insert the Input object into the InputTree.
+/// Finally, return the InputTree.
+InputTree *GNUArchiveReader::setupNewArchive(Input &pInput,
+ size_t off)
+{
+ llvm::OwningPtr<llvm::MemoryBuffer> mapFile;
+ if(llvm::MemoryBuffer::getFile(pInput.path().c_str(), mapFile))
+ {
+ assert(0 && "GNUArchiveReader:can't map a file to MemoryBuffer\n");
+ return NULL;
+ }
+
+ InputTree *resultTree = new InputTree(m_pLDInfo.inputFactory());
+ std::vector<SymbolTableEntry> symbolTable;
+ std::string archiveMemberName;
+ std::string extendedName;
+ bool isThinArchive;
+ const char *pFile = mapFile->getBufferStart();
+
+ /// check archive format.
+ if(mapFile->getBufferSize() <= archiveMagicSize)
+ return NULL;
+ else
+ {
+ isThinArchive = memcmp(pFile, thinArchiveMagic, archiveMagicSize) == 0;
+ if(!isThinArchive && memcmp(pFile, archiveMagic, archiveMagicSize) != 0)
+ return NULL;
+ }
+
+ off += archiveMagicSize ;
+ size_t symbolTableSize = parseMemberHeader(mapFile, off, &archiveMemberName,
+ NULL, extendedName);
+ /// read archive symbol table
+ if(archiveMemberName.empty())
+ {
+ readSymbolTable(mapFile, symbolTable,
+ off+sizeof(GNUArchiveReader::ArchiveMemberHeader), symbolTableSize);
+ off = off + sizeof(GNUArchiveReader::ArchiveMemberHeader) + symbolTableSize;
+ }
+ else
+ {
+ assert(0 && "fatal error : need symbol table\n");
+ return NULL;
+ }
+
+ if((off&1) != 0)
+ ++off;
+
+ size_t extendedSize = parseMemberHeader(mapFile, off, &archiveMemberName,
+ NULL, extendedName);
+ /// read long Name table if exist
+ if(archiveMemberName == "/")
+ {
+ off += sizeof(GNUArchiveReader::ArchiveMemberHeader);
+ pFile += off;
+ extendedName.assign(pFile,extendedSize);
+ }
+
+ /// traverse all the archive members
+ InputTree::iterator node = resultTree->root();
+ set<string> haveSeen;
+ for(unsigned i=0 ; i<symbolTable.size() ; ++i)
+ {
+ /// We shall get each member at this archive.
+ /// Construct a corresponding mcld::Input, and insert it into
+ /// the original InputTree, resultTree.
+ off_t nestedOff = 0;
+
+ parseMemberHeader(mapFile, symbolTable[i].fileOffset, &archiveMemberName,
+ &nestedOff, extendedName);
+
+ if(haveSeen.find(archiveMemberName)==haveSeen.end())
+ haveSeen.insert(archiveMemberName);
+ else
+ continue;
+
+ if(!isThinArchive)
+ {
+ /// New a Input object and assign fileOffset in MCLDFile.
+ /// Insert the object to resultTree and move ahead.
+ off_t fileOffset = symbolTable[i].fileOffset + sizeof(ArchiveMemberHeader);
+ Input *insertObjectFile = m_pLDInfo.inputFactory().produce(archiveMemberName,
+ pInput.path(),
+ MCLDFile::Object,
+ fileOffset);
+ resultTree->insert<InputTree::Positional>(node, *insertObjectFile);
+ if(i==0)
+ node.move<InputTree::Inclusive>();
+ else
+ node.move<InputTree::Positional>();
+
+ continue;
+ }
+
+ /// create the real path
+ sys::fs::RealPath realPath(archiveMemberName);
+ if(nestedOff > 0)
+ {
+ /// This is a member of a nested archive.
+ /// Create an Input for this archive ,and recursive call setupNewArchive
+ /// Finally, merge the new InputTree with the old one
+ Input *newArchive = m_pLDInfo.inputFactory().produce(archiveMemberName,
+ realPath,
+ MCLDFile::Archive,
+ 0);
+
+ resultTree->insert<InputTree::Positional>(node, *newArchive);
+ if(i==0)
+ node.move<InputTree::Inclusive>();
+ else
+ node.move<InputTree::Positional>();
+ InputTree *newArchiveTree = setupNewArchive(*newArchive, 0);
+ resultTree->merge<InputTree::Inclusive>(node, *newArchiveTree);
+ continue;
+ }
+ /// External member , open it as normal object file
+ /// add new Input to InputTree
+ Input *insertObjectFile = m_pLDInfo.inputFactory().produce(archiveMemberName,
+ realPath,
+ MCLDFile::Object,
+ 0);
+ resultTree->insert<InputTree::Positional>(node, *insertObjectFile);
+ if(i==0)
+ node.move<InputTree::Inclusive>();
+ else
+ node.move<InputTree::Positional>();
+ }
+ return resultTree;
+}
+
+
+/// Parse the member header and return the size of member
+/// Archive member names in System 5 style :
+///
+/// "/ " - symbol table, must be the first member
+/// "// " - long name table
+/// "filename.o/ " - regular file with short name
+/// "/5566 " - name at offset 5566 at long name table
+
+size_t GNUArchiveReader::parseMemberHeader(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ off_t off,
+ std::string *p_Name,
+ off_t *p_NestedOff,
+ std::string &p_ExtendedName)
+{
+ const char *pFile = mapFile->getBufferStart();
+ pFile += off;
+ const ArchiveMemberHeader *header = reinterpret_cast<const ArchiveMemberHeader *>(pFile);
+
+ /// check magic number of member header
+ if(memcmp(header->finalMagic, archiveFinalMagic, sizeof archiveFinalMagic))
+ {
+ assert(0 && "archive member header magic number false");
+ return 0;
+ }
+
+ /// evaluate member size
+ std::string sizeString(header->size, sizeof(header->size)+1);
+ size_t memberSize = stringToType<size_t>(sizeString);
+ if(memberSize == 0)
+ {
+ assert(0 && "member Size Error");
+ return 0;
+ }
+
+ if(header->name[0] != '/')
+ {
+ /// This is a regular file with short name
+ const char* nameEnd = strchr(header->name, '/');
+ size_t nameLen = ((nameEnd == NULL) ? 0 : (nameEnd - header->name));
+ if((nameLen <= 0) || (nameLen >= sizeof(header->name)))
+ {
+ assert(0 && "header name format error\n");
+ return 0;
+ }
+ p_Name->assign(header->name, nameLen);
+
+ if(!p_NestedOff)
+ p_NestedOff = 0;
+ }
+ else if(header->name[1] == ' ')
+ {
+ /// This is symbol table
+ if(!p_Name->empty())
+ p_Name->clear();
+ }
+ else if(header->name[1] == '/')
+ {
+ /// This is long name table
+ p_Name->assign(1,'/');
+ }
+ else
+ {
+ /// This is regular file with long name
+ char *end;
+ long extendedNameOff = strtol(header->name+1, &end, 10);
+ long nestedOff = 0;
+ if(*end == ':')
+ nestedOff = strtol(end+1, &end, 10);
+
+ if(*end != ' '
+ || extendedNameOff < 0
+ || static_cast<size_t>(extendedNameOff) >= p_ExtendedName.size())
+ {
+ assert(0 && "extended name");
+ return 0;
+ }
+
+ const char *name = p_ExtendedName.data() + extendedNameOff;
+ const char *nameEnd = strchr(name, '\n');
+ if(nameEnd[-1] != '/'
+ || static_cast<size_t>(nameEnd-name) > p_ExtendedName.size())
+ {
+ assert(0 && "p_ExtendedName substring is not end with / \n");
+ return 0;
+ }
+ p_Name->assign(name, nameEnd-name-1);
+ if(p_NestedOff)
+ *p_NestedOff = nestedOff;
+ }
+
+ return memberSize;
+}
+
+void GNUArchiveReader::readSymbolTable(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+ std::vector<SymbolTableEntry> &pSymbolTable,
+ off_t start,
+ size_t size)
+{
+ const char *startPtr = mapFile->getBufferStart() + start;
+ const elfWord *p_Word = reinterpret_cast<const elfWord *>(startPtr);
+ unsigned int symbolNum = *p_Word;
+
+ /// Portable Issue on Sparc platform
+ /// Intel, ARM and Mips are littel-endian , Sparc is little-endian after verion 9
+ /// symbolNum in symbol table is always big-endian
+ if(m_endian == LDReader::LittleEndian)
+ endian_swap(symbolNum);
+ ++p_Word;
+
+ const char *p_Name = reinterpret_cast<const char *>(p_Word + symbolNum);
+
+ pSymbolTable.resize(symbolNum);
+ for(unsigned int i=0 ; i<symbolNum ; ++i)
+ {
+ /// assign member offset
+ unsigned int memberOffset = *p_Word;
+ endian_swap(memberOffset);
+ pSymbolTable[i].fileOffset = static_cast<off_t>(memberOffset);
+ ++p_Word;
+ /// assign member name
+ off_t nameEnd = strlen(p_Name) + 1;
+ pSymbolTable[i].name.assign(p_Name, nameEnd);
+ p_Name += nameEnd;
+ }
+}
diff --git a/lib/LD/InputSymbolTable.cpp b/lib/LD/InputSymbolTable.cpp
new file mode 100644
index 0000000..e34679c
--- /dev/null
+++ b/lib/LD/InputSymbolTable.cpp
@@ -0,0 +1,48 @@
+//===- InputSymbolTable.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/InputSymbolTable.h"
+#include <vector>
+
+using namespace mcld;
+
+//==========================
+// InputSymbolTable
+
+InputSymbolTable::InputSymbolTable(StrSymPool &pStrSymPool,
+ size_t pNumOfSymbols,
+ StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable)
+ : SymbolTableIF(pStrSymPool)
+{
+ f_StrSymPool.addIndirectClient(*this);
+
+ f_pCategorySet->at(CategorySet::Entire).reserve(pNumOfSymbols);
+
+ f_pCategorySet->at(CategorySet::Entire).interpose(&pEntireStringTable);
+ f_pCategorySet->at(CategorySet::Dynamic).interpose(&pDynamicStringTable);
+}
+
+void InputSymbolTable::doInsertSymbol(LDSymbol *pSym)
+{
+ f_pCategorySet->insertSymbolPointer(pSym);
+}
+
+void InputSymbolTable::doMerge(const SymbolTableIF &pSymTab)
+{
+ if (this == &pSymTab)
+ return;
+ for (size_t i = 0; i < CategorySet::NumOfCategories; ++i)
+ f_pCategorySet->at(i).insert(f_pCategorySet->at(i).end(),
+ pSymTab.begin(i),
+ pSymTab.end(i));
+}
+
+InputSymbolTable::~InputSymbolTable()
+{
+}
diff --git a/lib/LD/LDContext.cpp b/lib/LD/LDContext.cpp
new file mode 100644
index 0000000..f6556f3
--- /dev/null
+++ b/lib/LD/LDContext.cpp
@@ -0,0 +1,103 @@
+//===- LDContext.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDSymbol.h>
+#include <llvm/ADT/StringRef.h>
+
+using namespace mcld;
+
+//==========================
+// LDReader
+LDContext::LDContext()
+{
+}
+
+LDContext::~LDContext()
+{
+}
+
+LDSection* LDContext::getSection(unsigned int pIdx)
+{
+ if (pIdx >= m_SectionTable.size())
+ return NULL;
+ return m_SectionTable[pIdx];
+}
+
+const LDSection* LDContext::getSection(unsigned int pIdx) const
+{
+ if (pIdx >= m_SectionTable.size())
+ return NULL;
+ return m_SectionTable[pIdx];
+}
+
+LDSection* LDContext::getSection(const std::string& pName)
+{
+ sect_iterator sect_iter, sect_end = sectEnd();
+ for (sect_iter = sectBegin(); sect_iter != sect_end; ++sect_iter) {
+ if(NULL != *sect_iter && (*sect_iter)->name() == pName)
+ return *sect_iter;
+ }
+ return NULL;
+}
+
+const LDSection* LDContext::getSection(const std::string& pName) const
+{
+ const_sect_iterator sect_iter, sect_end = sectEnd();
+ for (sect_iter = sectBegin(); sect_iter != sect_end; ++sect_iter) {
+ if(NULL != *sect_iter && (*sect_iter)->name() == pName)
+ return *sect_iter;
+ }
+ return NULL;
+}
+
+size_t LDContext::getSectionIdx(const std::string& pName) const
+{
+ size_t result = 1;
+ size_t size = m_SectionTable.size();
+ for (; result != size; ++result)
+ if (m_SectionTable[result]->name() == pName)
+ return result;
+ return 0;
+}
+
+LDSymbol* LDContext::getSymbol(unsigned int pIdx)
+{
+ if (pIdx >= m_SymTab.size())
+ return NULL;
+ return m_SymTab[pIdx];
+}
+
+const LDSymbol* LDContext::getSymbol(unsigned int pIdx) const
+{
+ if (pIdx >= m_SymTab.size())
+ return NULL;
+ return m_SymTab[pIdx];
+}
+
+
+LDSymbol* LDContext::getSymbol(const llvm::StringRef& pName)
+{
+ size_t sym = 1;
+ size_t size = m_SymTab.size();
+ for (; sym < size; ++sym)
+ if (m_SymTab[sym]->name() == pName)
+ return m_SymTab[sym];
+ return NULL;
+}
+
+const LDSymbol* LDContext::getSymbol(const llvm::StringRef& pName) const
+{
+ size_t sym = 1;
+ size_t size = m_SymTab.size();
+ for (; sym < size; ++sym)
+ if (m_SymTab[sym]->name() == pName)
+ return m_SymTab[sym];
+ return NULL;
+}
diff --git a/lib/LD/LDFileFormat.cpp b/lib/LD/LDFileFormat.cpp
new file mode 100644
index 0000000..c1ddb52
--- /dev/null
+++ b/lib/LD/LDFileFormat.cpp
@@ -0,0 +1,32 @@
+//===- LDFileFormat.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/MC/MCLinker.h>
+
+using namespace mcld;
+
+//==========================
+// LDFileInfo
+LDFileFormat::LDFileFormat()
+ : f_pTextSection(NULL),
+ f_pDataSection(NULL),
+ f_pBSSSection(NULL),
+ f_pReadOnlySection(NULL) {
+}
+
+LDFileFormat::~LDFileFormat()
+{
+}
+
+void LDFileFormat::initStdSections(MCLinker& pLinker)
+{
+ initObjectFormat(pLinker);
+ initObjectType(pLinker);
+}
+
diff --git a/lib/LD/LDObjectWriter.cpp b/lib/LD/LDObjectWriter.cpp
new file mode 100644
index 0000000..d08c6a7
--- /dev/null
+++ b/lib/LD/LDObjectWriter.cpp
@@ -0,0 +1,23 @@
+//===- LDObjectWriter.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCObjectWriter.h"
+
+using namespace mcld;
+
+//==========================
+// MCObjectWriter
+
+
+MCObjectWriter::MCObjectWriter()
+{
+}
+
+MCObjectWriter::~MCObjectWriter()
+{
+}
diff --git a/lib/LD/LDReader.cpp b/lib/LD/LDReader.cpp
new file mode 100644
index 0000000..b74fc68
--- /dev/null
+++ b/lib/LD/LDReader.cpp
@@ -0,0 +1,14 @@
+//===- LDReader.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDReader.h>
+
+using namespace mcld;
+
+//==========================
+// LDReader
diff --git a/lib/LD/LDSection.cpp b/lib/LD/LDSection.cpp
new file mode 100644
index 0000000..1ec9c13
--- /dev/null
+++ b/lib/LD/LDSection.cpp
@@ -0,0 +1,35 @@
+//===- LDSection.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDSection.h>
+#include <llvm/MC/SectionKind.h>
+
+using namespace mcld;
+
+LDSection::LDSection(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag,
+ uint64_t pSize,
+ uint64_t pOffset,
+ uint64_t pAddr)
+ : llvm::MCSection(llvm::MCSection::SV_LDContext, llvm::SectionKind::getMetadata()),
+ m_Name(pName),
+ m_Kind(pKind),
+ m_Type(pType),
+ m_Flag(pFlag),
+ m_Size(pSize),
+ m_Offset(pOffset),
+ m_Addr(pAddr),
+ m_Align(0),
+ m_Info(0),
+ m_pLink(NULL),
+ m_pSectionData(NULL),
+ m_Index(0) {
+}
+
diff --git a/lib/LD/LDSectionFactory.cpp b/lib/LD/LDSectionFactory.cpp
new file mode 100644
index 0000000..a81c839
--- /dev/null
+++ b/lib/LD/LDSectionFactory.cpp
@@ -0,0 +1,49 @@
+//===- LDSectionFactory.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDSectionFactory.h>
+
+using namespace mcld;
+
+//==========================
+// LDSectionFactory
+LDSectionFactory::LDSectionFactory(size_t pNum)
+ : GCFactory<LDSection, 0>(pNum) {
+}
+
+LDSectionFactory::~LDSectionFactory()
+{
+}
+
+LDSection* LDSectionFactory::produce(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag)
+{
+ // create a LDSection
+ LDSection* result = allocate();
+ new (result) LDSection(pName, pKind, pType, pFlag);
+ return result;
+}
+
+void LDSectionFactory::destroy(LDSection*& pSection)
+{
+ // do not recycle LDSection. HeaderFactory will do that job.
+ deallocate(pSection);
+}
+
+LDSection* LDSectionFactory::find(const std::string& pName)
+{
+ iterator sect_iter, sect_end = end();
+ for (sect_iter = begin(); sect_iter != sect_end; ++sect_iter)
+ if ((*sect_iter).name() == pName)
+ break;
+ if (sect_iter == sect_end)
+ return NULL;
+ return &(*sect_iter);
+}
diff --git a/lib/LD/LDSymbol.cpp b/lib/LD/LDSymbol.cpp
new file mode 100644
index 0000000..f26e052
--- /dev/null
+++ b/lib/LD/LDSymbol.cpp
@@ -0,0 +1,45 @@
+//===- LDSymbol.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/LDSymbol.h"
+#include <cstring>
+
+using namespace mcld;
+
+LDSymbol::LDSymbol()
+ : m_pResolveInfo(NULL), m_pFragRef(NULL), m_Value(0) {
+}
+
+LDSymbol::~LDSymbol()
+{
+}
+
+LDSymbol::LDSymbol(const LDSymbol& pCopy)
+ : m_pResolveInfo(pCopy.m_pResolveInfo),
+ m_pFragRef(pCopy.m_pFragRef),
+ m_Value(pCopy.m_Value) {
+}
+
+LDSymbol& LDSymbol::operator=(const LDSymbol& pCopy)
+{
+ m_pResolveInfo = pCopy.m_pResolveInfo;
+ m_pFragRef = pCopy.m_pFragRef;
+ m_Value = pCopy.m_Value;
+ return (*this);
+}
+
+void LDSymbol::setFragmentRef(MCFragmentRef* pFragmentRef)
+{
+ m_pFragRef = pFragmentRef;
+}
+
+void LDSymbol::setResolveInfo(const ResolveInfo& pInfo)
+{
+ m_pResolveInfo = const_cast<ResolveInfo*>(&pInfo);
+}
+
diff --git a/lib/LD/LDWriter.cpp b/lib/LD/LDWriter.cpp
new file mode 100644
index 0000000..e78f087
--- /dev/null
+++ b/lib/LD/LDWriter.cpp
@@ -0,0 +1,15 @@
+//===- LDWriter.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/LDWriter.h"
+
+using namespace mcld;
+
+//==========================
+// LDReader
+
diff --git a/lib/LD/Layout.cpp b/lib/LD/Layout.cpp
new file mode 100644
index 0000000..9328d74
--- /dev/null
+++ b/lib/LD/Layout.cpp
@@ -0,0 +1,671 @@
+//===- Layout.cpp ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/LDSection.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <cassert>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Range
+Layout::Range::Range()
+ : header(NULL),
+ prevRear(NULL) {
+}
+
+Layout::Range::Range(const LDSection& pHdr)
+ : header(const_cast<LDSection*>(&pHdr)),
+ prevRear(NULL) {
+}
+
+Layout::Range::~Range()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Layout
+Layout::Layout()
+ : m_FragRefFactory(32) /** magic number **/ {
+}
+
+Layout::~Layout()
+{
+}
+
+void Layout::setFragmentLayoutOrder(llvm::MCFragment* pFrag)
+{
+ if (NULL == pFrag)
+ return;
+ // compute the most-recent fragment whose order was set.
+ llvm::MCFragment* first = pFrag;
+
+ while (!hasLayoutOrder(*first)) {
+ if (NULL == first->getPrevNode())
+ break;
+ first = first->getPrevNode();
+ }
+
+ // set all layout order
+ unsigned int layout_order = 0;
+ llvm::MCFragment* frag_not_set = NULL;
+
+ if (NULL == first->getPrevNode()) {
+ layout_order = 0;
+ frag_not_set = first;
+ }
+ else {
+ layout_order = first->getLayoutOrder();
+ frag_not_set = first->getNextNode();
+ }
+
+ // set up all layout order
+ while(NULL != frag_not_set) {
+ frag_not_set->setLayoutOrder(layout_order);
+ ++layout_order;
+ frag_not_set = frag_not_set->getNextNode();
+ }
+}
+
+/// setFragmentLayoutOffset - set the fragment's layout offset. This function
+/// also set up the layout offsets of all the fragments in the same range.
+/// If the offset of the fragment was set before, return immediately.
+void Layout::setFragmentLayoutOffset(llvm::MCFragment* pFrag)
+{
+ if (NULL == pFrag)
+ return;
+ // compute the most-recent fragment whose offset was set.
+ llvm::MCFragment* first = pFrag;
+
+ while (!hasLayoutOffset(*first)) {
+ if (NULL == first->getPrevNode())
+ break;
+ first = first->getPrevNode();
+ }
+
+ // set all layout order
+ uint64_t offset = 0;
+ llvm::MCFragment* frag_not_set = NULL;
+ if (NULL == first->getPrevNode()) {
+ offset = 0;
+ frag_not_set = first;
+ }
+ else {
+ offset = first->Offset;
+ offset += computeFragmentSize(*this, *first);
+ frag_not_set = first->getNextNode();
+ }
+
+ while(NULL != frag_not_set) {
+ frag_not_set->Offset = offset;
+ offset += computeFragmentSize(*this, *frag_not_set);
+ frag_not_set = frag_not_set->getNextNode();
+ }
+}
+
+/// addInputRange
+/// 1. add a new range <pInputHdr, previous rear fragment>
+/// 2. compute the layout order of all previous ranges.
+void Layout::addInputRange(const llvm::MCSectionData& pSD,
+ const LDSection& pInputHdr)
+{
+ RangeList* range_list = NULL;
+
+ // get or create the range_list
+ if (pSD.getFragmentList().empty() || 0 == m_SDRangeMap.count(&pSD)) {
+ range_list = new RangeList();
+ m_SDRangeMap[&pSD] = range_list;
+ }
+ else {
+ range_list = m_SDRangeMap[&pSD];
+#ifdef MCLD_DEBUG
+ RangeList::iterator rangeIter, rangeEnd = range_list->end();
+ for (rangeIter = range_list->begin(); rangeIter != rangeEnd; ++rangeIter) {
+ if (&pInputHdr == rangeIter->header) {
+ llvm::report_fatal_error(llvm::Twine("Trying to map the same LDSection: ") +
+ pInputHdr.name() +
+ llvm::Twine(" into the different ranges.\n"));
+ }
+ }
+#endif
+ }
+
+ // make a range and push it into the range list
+ Range* range = new Range(pInputHdr);
+ range_list->push_back(range);
+
+ // set up previous rear of the range.
+ // FIXME: in current design, we can not add a range before finishing adding
+ // fragments in the previous range. If the limitation keeps, we can set
+ // prevRear to the last fragment in the MCSectionData simply.
+ //
+ // if the pSD's fragment list is empty, the range.prevRear keeps NULL.
+ if (!pSD.getFragmentList().empty()) {
+ range->prevRear =
+ const_cast<llvm::MCFragment*>(&pSD.getFragmentList().back());
+ }
+
+ // compute the layout order of the previous range.
+ if (!isFirstRange(*range)) {
+ setFragmentLayoutOrder(range->prevRear);
+ setFragmentLayoutOffset(range->prevRear);
+ }
+}
+
+/// appendFragment - append the given MCFragment to the given MCSectionData,
+/// and insert a MCAlignFragment to preserve the required align constraint if
+/// needed
+uint64_t Layout::appendFragment(llvm::MCFragment& pFrag,
+ llvm::MCSectionData& pSD,
+ uint32_t pAlignConstraint)
+{
+ // insert MCAlignFragment into MCSectionData first if needed
+ llvm::MCAlignFragment* align_frag = NULL;
+ if (pAlignConstraint > 1) {
+ align_frag = new llvm::MCAlignFragment(pAlignConstraint, // alignment
+ 0x0, // the filled value
+ 1u, // the size of filled value
+ pAlignConstraint - 1, // max bytes to emit
+ &pSD);
+ }
+
+ // append the fragment to the MCSectionData
+ pFrag.setParent(&pSD);
+ pSD.getFragmentList().push_back(&pFrag);
+
+ // update the alignment of associated output LDSection if needed
+ LDSection* output_sect = getOutputLDSection(pFrag);
+ assert(NULL != output_sect);
+ if (pAlignConstraint > output_sect->align())
+ output_sect->setAlign(pAlignConstraint);
+
+ // compute the fragment order and offset
+ setFragmentLayoutOrder(&pFrag);
+ setFragmentLayoutOffset(&pFrag);
+
+ if (NULL != align_frag)
+ return pFrag.Offset - align_frag->Offset + computeFragmentSize(*this, pFrag);
+ else
+ return computeFragmentSize(*this, pFrag);
+}
+
+/// getInputLDSection - give a MCFragment, return the corresponding input
+/// LDSection*
+LDSection*
+Layout::getInputLDSection(const llvm::MCFragment& pFrag)
+{
+ const llvm::MCSectionData* sect_data = pFrag.getParent();
+ // check the MCSectionData
+ if (NULL == sect_data) {
+ llvm::report_fatal_error(llvm::Twine("the fragment does not belong to") +
+ llvm::Twine(" any MCSectionData.\n"));
+ }
+
+ // check the MCSectionData's range list
+ if (0 == m_SDRangeMap.count(sect_data)) {
+ llvm::report_fatal_error(llvm::Twine("INTERNAL BACKEND ERROR: ") +
+ llvm::Twine("the input's MCSectionData is not ") +
+ llvm::Twine("registered in the Layout.\nPlease ") +
+ llvm::Twine("use MCLinker::getOrCreateSectData() ") +
+ llvm::Twine("to get input's MCSectionData.\n"));
+ }
+
+ RangeList* range_list = m_SDRangeMap[sect_data];
+ // the fragment who has the layout order is not in the last range.
+ if (hasLayoutOrder(pFrag)) {
+ Range range = range_list->back();
+ if (isFirstRange(range)) {
+ return range.header;
+ }
+ while(range.prevRear->getLayoutOrder() > pFrag.getLayoutOrder()) {
+ if (NULL != range.getPrevNode())
+ range = *range.getPrevNode();
+ else
+ return NULL;
+ }
+ return range.header;
+ }
+ // the fragment who has no layout order should be in the last range
+ else {
+ if (range_list->empty())
+ return NULL;
+ return range_list->back().header;
+ }
+}
+
+/// getInputLDSection - give a MCFragment, return the corresponding input
+/// LDSection*
+const LDSection*
+Layout::getInputLDSection(const llvm::MCFragment& pFrag) const
+{
+ const llvm::MCSectionData* sect_data = pFrag.getParent();
+ // check the MCSectionData
+ if (NULL == sect_data) {
+ llvm::report_fatal_error(llvm::Twine("the fragment does not belong to") +
+ llvm::Twine(" any MCSectionData.\n"));
+ }
+
+ // check the MCSectionData's range list
+ if (0 == m_SDRangeMap.count(sect_data)) {
+ llvm::report_fatal_error(llvm::Twine("INTERNAL BACKEND ERROR: ") +
+ llvm::Twine("the input's MCSectionData is not ") +
+ llvm::Twine("registered in the Layout.\nPlease ") +
+ llvm::Twine("use MCLinker::getOrCreateSectData() ") +
+ llvm::Twine("to get input's MCSectionData.\n"));
+ }
+
+ SDRangeMap::const_iterator range_list_iter = m_SDRangeMap.find(sect_data);
+ const RangeList* range_list = range_list_iter->second;
+ // the fragment who has the layout order is not in the last range.
+ if (hasLayoutOrder(pFrag)) {
+ Range range = range_list->back();
+ if (isFirstRange(range)) {
+ return range.header;
+ }
+ while(range.prevRear->getLayoutOrder() > pFrag.getLayoutOrder()) {
+ if (NULL != range.getPrevNode())
+ range = *range.getPrevNode();
+ else
+ return NULL;
+ }
+ return range.header;
+ }
+ // the fragment who has no layout order should be in the last range
+ else {
+ if (range_list->empty())
+ return NULL;
+ return range_list->back().header;
+ }
+}
+
+/// getOutputLDSection
+LDSection* Layout::getOutputLDSection(const llvm::MCFragment& pFrag)
+{
+ llvm::MCSectionData* sect_data = pFrag.getParent();
+ if (NULL == sect_data)
+ return NULL;
+
+ return const_cast<LDSection*>(llvm::cast<LDSection>(§_data->getSection()));
+}
+
+/// getOutputLDSection
+const LDSection* Layout::getOutputLDSection(const llvm::MCFragment& pFrag) const
+{
+ const llvm::MCSectionData* sect_data = pFrag.getParent();
+ if (NULL == sect_data)
+ return NULL;
+
+ return llvm::cast<LDSection>(§_data->getSection());
+}
+
+/// getFragmentRef - assume the ragne exist, find the fragment reference
+MCFragmentRef*
+Layout::getFragmentRef(Layout::Range& pRange, uint64_t pOffset)
+{
+ if (isEmptyRange(pRange))
+ return NULL;
+
+ llvm::MCFragment* front = getFront(pRange);
+ if (NULL == front)
+ return NULL;
+
+ llvm::MCFragment* rear = getRear(pRange);
+ if (NULL == rear)
+ return NULL;
+
+ return getFragmentRef(*front, *rear, pOffset);
+}
+
+// @param pFront is the first fragment in the range.
+// @param pRear is the last fragment in the range.
+// @pOffset is the offset started from pFront.
+MCFragmentRef*
+Layout::getFragmentRef(llvm::MCFragment& pFront,
+ llvm::MCFragment& pRear,
+ uint64_t pOffset)
+{
+ llvm::MCFragment* front = &pFront;
+ llvm::MCFragment* rear = &pRear;
+
+ if (!hasLayoutOffset(*rear)) {
+ // compute layout order, offset
+ setFragmentLayoutOrder(rear);
+ setFragmentLayoutOffset(rear);
+ }
+
+ // compute the offset from overall start fragment.
+ uint64_t target_offset = pFront.Offset + pOffset;
+
+ // from front to rear, find the offset which is as large as possible
+ // but smaller than the target_offset.
+ while (front != rear) {
+ if (llvm::MCFragment::FT_Align == front->getKind()) {
+ // alignment fragments were not counted in target_offset.
+ // Count in the size of alignment fragmen in target_offset here.
+ uint64_t align_size = 0x0;
+ if (NULL == front->getNextNode()) {
+ // If the alignment fragment is the last fragment, increase
+ // the target_offset by the alignment fragment's size.
+ align_size = computeFragmentSize(*this, *front);
+ }
+ else {
+ // If the alignment fragment is not the last fragment, the alignment
+ // fragment's size is the distance between the two fragment.
+ align_size = front->getNextNode()->Offset - front->Offset;
+ }
+ target_offset += align_size;
+ front = front->getNextNode();
+ continue;
+ }
+
+ if (target_offset >= front->getNextNode()->Offset) {
+ front = front->getNextNode();
+ }
+ else {
+ // found
+ MCFragmentRef* result = m_FragRefFactory.allocate();
+ new (result) MCFragmentRef(*front, target_offset - front->Offset);
+ return result;
+ }
+ }
+
+ if (front == rear) {
+ if (llvm::MCFragment::FT_Align == front->getKind())
+ return NULL;
+
+ if (!isValidOffset(*front, target_offset))
+ return NULL;
+
+ MCFragmentRef* result = m_FragRefFactory.allocate();
+ new (result) MCFragmentRef(*front, target_offset - front->Offset);
+ return result;
+ }
+ return NULL;
+}
+
+/// getFragmentRef - give a LDSection in input file and an offset, return
+/// the fragment reference.
+MCFragmentRef*
+Layout::getFragmentRef(const LDSection& pInputSection, uint64_t pOffset)
+{
+ // find out which SectionData covers the range of input section header
+ const llvm::MCSectionData* sect_data = pInputSection.getSectionData();
+
+ // check range list
+ if (0 == m_SDRangeMap.count(sect_data))
+ return NULL;
+
+ if (sect_data->getFragmentList().empty())
+ return NULL;
+
+ RangeList* range_list = m_SDRangeMap[sect_data];
+
+ // find out the specific part in SectionData range
+ RangeList::iterator range, rangeEnd = range_list->end();
+ for (range = range_list->begin(); range != rangeEnd; ++range) {
+ // found the range
+ if (&pInputSection == range->header) {
+ break;
+ }
+ }
+
+ // range not found
+ if (range == rangeEnd) {
+ llvm::report_fatal_error(llvm::Twine("section ") +
+ pInputSection.name() +
+ llvm::Twine(" never be in the range list.\n"));
+ }
+
+ return getFragmentRef(*range, pOffset);
+}
+
+/// getFragmentRef - give a fragment and a big offset, return the fragment
+/// reference in the section data.
+///
+/// @param pFrag - the given fragment
+/// @param pBigOffset - the offset, can be larger than the fragment, but can
+/// not larger than this input section.
+/// @return if found, return the fragment. Otherwise, return NULL.
+MCFragmentRef*
+Layout::getFragmentRef(const llvm::MCFragment& pFrag, uint64_t pBigOffset)
+{
+ if (!hasLayoutOffset(pFrag)) {
+ // compute layout order, offset
+ setFragmentLayoutOrder(const_cast<llvm::MCFragment*>(&pFrag));
+ setFragmentLayoutOffset(const_cast<llvm::MCFragment*>(&pFrag));
+ }
+
+ // find out which SectionData covers the range of input section header
+ const llvm::MCSectionData* sect_data = pFrag.getParent();
+
+ // check range list
+ if (0 == m_SDRangeMap.count(sect_data)) {
+ llvm::report_fatal_error(llvm::Twine("MCSectionData has no") +
+ llvm::Twine(" correponding range list.\n"));
+ }
+
+ if (sect_data->getFragmentList().empty())
+ return NULL;
+
+ RangeList* range_list = m_SDRangeMap[sect_data];
+
+ // find out the specific part in SectionData range
+ uint64_t target_offset = pBigOffset + pFrag.Offset;
+
+ RangeList::iterator range, rangeEnd = range_list->end();
+ for (range = range_list->begin(); range != rangeEnd; ++range) {
+ if (isEmptyRange(*range))
+ continue;
+ if (getRear(*range)->Offset >= target_offset) {
+ break;
+ }
+ }
+
+ // range not found
+ if (range == rangeEnd) {
+ llvm::report_fatal_error(llvm::Twine("the offset is too big that") +
+ llvm::Twine(" never be in the range list.\n"));
+ }
+
+ return getFragmentRef(*range, target_offset);
+}
+
+uint64_t Layout::getOutputOffset(const llvm::MCFragment& pFrag)
+{
+ if (!hasLayoutOffset(pFrag)) {
+ // compute layout order, offset
+ setFragmentLayoutOrder(const_cast<llvm::MCFragment*>(&pFrag));
+ setFragmentLayoutOffset(const_cast<llvm::MCFragment*>(&pFrag));
+ }
+ return pFrag.Offset;
+}
+
+uint64_t Layout::getOutputOffset(const llvm::MCFragment& pFrag) const
+{
+ if (!hasLayoutOffset(pFrag)) {
+ llvm::report_fatal_error(llvm::Twine("INTERNAL BACKEND ERROR: ") +
+ llvm::Twine("the function ") +
+ llvm::Twine(__func__) +
+ llvm::Twine(" can not be used before layout().\n"));
+ }
+ return pFrag.Offset;
+}
+
+uint64_t Layout::getOutputOffset(const MCFragmentRef& pFragRef)
+{
+ return getOutputOffset(*(pFragRef.frag())) + pFragRef.offset();
+}
+
+uint64_t Layout::getOutputOffset(const MCFragmentRef& pFragRef) const
+{
+ return getOutputOffset(*(pFragRef.frag())) + pFragRef.offset();
+}
+
+void Layout::sortSectionOrder(const Output& pOutput,
+ const TargetLDBackend& pBackend)
+{
+ typedef std::pair<LDSection*, unsigned int> SectOrder;
+ typedef std::vector<SectOrder > SectListTy;
+ SectListTy sect_list;
+ // get section order from backend
+ for (size_t index = 0; index < m_SectionOrder.size(); ++index)
+ sect_list.push_back(std::make_pair(
+ m_SectionOrder[index],
+ pBackend.getSectionOrder(pOutput, *m_SectionOrder[index])));
+
+ // simple insertion sort should be fine for general cases such as so and exec
+ for (unsigned int i = 1; i < sect_list.size(); ++i) {
+ SectOrder order = sect_list[i];
+ int j = i - 1;
+ while (j >= 0 && sect_list[j].second > order.second) {
+ sect_list[j + 1] = sect_list[j];
+ --j;
+ }
+ sect_list[j + 1] = order;
+ }
+
+ // update the sorted ordering to m_SectionOrder
+ m_SectionOrder.clear();
+ for (size_t index = 0; index < sect_list.size(); ++index) {
+ m_SectionOrder.push_back(sect_list[index].first);
+ }
+}
+
+bool Layout::layout(Output& pOutput, const TargetLDBackend& pBackend)
+{
+ // determine what sections in output context will go into final output, and
+ // push the needed sections into m_SectionOrder for later processing
+ assert(pOutput.hasContext());
+ LDContext& output_context = *pOutput.context();
+ LDContext::sect_iterator it, itEnd = output_context.sectEnd();
+ for (it = output_context.sectBegin(); it != itEnd; ++it) {
+ LDSection* sect = *it;
+
+ switch (sect->kind()) {
+ // ignore if there is no SectionData for certain section kinds
+ case LDFileFormat::Regular:
+ case LDFileFormat::Note:
+ case LDFileFormat::Target:
+ case LDFileFormat::MetaData:
+ case LDFileFormat::BSS:
+ if (0 != sect->size()) {
+ if (NULL != sect->getSectionData() &&
+ !sect->getSectionData()->getFragmentList().empty()) {
+ // make sure that all fragments are valid
+ llvm::MCFragment& frag =
+ sect->getSectionData()->getFragmentList().back();
+ setFragmentLayoutOrder(&frag);
+ setFragmentLayoutOffset(&frag);
+ }
+ m_SectionOrder.push_back(sect);
+ }
+ break;
+ // take NULL directly
+ case LDFileFormat::Null:
+ m_SectionOrder.push_back(sect);
+ break;
+ // ignore if section size is 0
+ case LDFileFormat::NamePool:
+ case LDFileFormat::Relocation:
+ if (0 != sect->size())
+ m_SectionOrder.push_back(sect);
+ break;
+ case LDFileFormat::Group:
+ if (MCLDFile::Object == pOutput.type()) {
+ //TODO: support incremental linking
+ ;
+ }
+ break;
+ case LDFileFormat::Debug:
+ if (0 != sect->size()) {
+ m_SectionOrder.push_back(sect);
+ llvm::errs() << "WARNING: DWRAF debugging has not been fully supported yet.\n"
+ << "section `" << sect->name() << "'.\n";
+ }
+ break;
+ case LDFileFormat::Exception:
+ if (0 != sect->size()) {
+ llvm::errs() << "WARNING: Exception handling has not been fully supported yet.\n"
+ << "section `" << sect->name() << "'.\n";
+ if (NULL != sect->getSectionData() &&
+ !sect->getSectionData()->getFragmentList().empty()) {
+ // make sure that all fragments are valid
+ llvm::MCFragment& frag =
+ sect->getSectionData()->getFragmentList().back();
+ setFragmentLayoutOrder(&frag);
+ setFragmentLayoutOffset(&frag);
+ }
+ m_SectionOrder.push_back(sect);
+ }
+ break;
+ case LDFileFormat::Version:
+ if (0 != sect->size()) {
+ m_SectionOrder.push_back(sect);
+ llvm::errs() << "WARNING: Symbolic versioning has not been fully supported yet.\n"
+ << "section `" << sect->name() << "'.\n";
+ }
+ break;
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unsupported section kind of `") +
+ sect->name() +
+ llvm::Twine("': ") +
+ llvm::Twine(sect->kind()) +
+ llvm::Twine(".\n"));
+ break;
+ }
+ }
+
+ // perform sorting on m_SectionOrder to get a ordering for final layout
+ sortSectionOrder(pOutput, pBackend);
+
+ // Backend defines the section start offset for section 1.
+ uint64_t offset = pBackend.sectionStartOffset();
+ // compute the section offset and handle alignment also. And ignore section 0
+ // (NULL in ELF/COFF), and MachO starts from section 1.
+ for (size_t index = 1; index < m_SectionOrder.size(); ++index) {
+ // we should not preserve file space for the BSS section.
+ if (LDFileFormat::BSS != m_SectionOrder[index - 1]->kind())
+ offset += m_SectionOrder[index - 1]->size();
+
+ alignAddress(offset, m_SectionOrder[index]->align());
+
+ m_SectionOrder[index]->setOffset(offset);
+ }
+
+ // FIXME: Currently Writer bases on the section table in output context to
+ // write out sections, so we have to update its content..
+ output_context.getSectionTable().clear();
+ for (size_t index = 0; index < m_SectionOrder.size(); ++index) {
+ output_context.getSectionTable().push_back(m_SectionOrder[index]);
+ // after sorting, update the correct output section indices
+ m_SectionOrder[index]->setIndex(index);
+ }
+ return true;
+}
+
+bool Layout::isValidOffset(const llvm::MCFragment& pFrag, uint64_t pTargetOffset) const
+{
+ uint64_t size = computeFragmentSize(*this, pFrag);
+ if (0x0 == size)
+ return (pTargetOffset == pFrag.Offset);
+
+ if (NULL != pFrag.getNextNode())
+ return (pTargetOffset >= pFrag.Offset && pTargetOffset < pFrag.getNextNode()->Offset);
+
+ return (pTargetOffset >= pFrag.Offset && pTargetOffset < (pFrag.Offset + size));
+}
+
diff --git a/lib/LD/ObjectWriter.cpp b/lib/LD/ObjectWriter.cpp
new file mode 100644
index 0000000..15691f2
--- /dev/null
+++ b/lib/LD/ObjectWriter.cpp
@@ -0,0 +1,24 @@
+//===- ObjectWriter.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ObjectWriter.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/Target/GNULDBackend.h>
+
+using namespace mcld;
+
+//==========================
+// ObjectWriter
+ObjectWriter::ObjectWriter(GNULDBackend& pBackend)
+{
+}
+
+ObjectWriter::~ObjectWriter()
+{
+}
+
diff --git a/lib/LD/OutputSymbolTable.cpp b/lib/LD/OutputSymbolTable.cpp
new file mode 100644
index 0000000..a17a211
--- /dev/null
+++ b/lib/LD/OutputSymbolTable.cpp
@@ -0,0 +1,41 @@
+//===- OutputSymbolTable.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/OutputSymbolTable.h"
+
+using namespace mcld;
+
+//==========================
+// OutputSymbolTable
+
+
+OutputSymbolTable::OutputSymbolTable(StrSymPool &pStrSymPool,
+ size_t pNumOfSymbols,
+ StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable)
+ : SymbolTableIF(pStrSymPool)
+{
+ f_StrSymPool.addDirectClient(*this);
+
+ f_pCategorySet->at(CategorySet::Entire).reserve(pNumOfSymbols);
+
+ f_pCategorySet->at(CategorySet::Entire).interpose(&pEntireStringTable);
+ f_pCategorySet->at(CategorySet::Dynamic).interpose(&pDynamicStringTable);
+}
+
+void OutputSymbolTable::doInsertSymbol(LDSymbol *sym)
+{
+ // OutputSymbolTable didn't have any real containers,
+ // so no need to do anything.
+}
+
+void OutputSymbolTable::doMerge(const SymbolTableIF &pSymTab)
+{
+ // OutputSymbolTable didn't have any real containers,
+ // so no need to do anything.
+}
diff --git a/lib/LD/Relocation.cpp b/lib/LD/Relocation.cpp
new file mode 100644
index 0000000..73db39b
--- /dev/null
+++ b/lib/LD/Relocation.cpp
@@ -0,0 +1,81 @@
+//===- Relocation.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/MC/MCAssembler.h>
+//#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Relocation.h>
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/LD/Layout.h>
+
+using namespace mcld;
+
+Relocation::Relocation(Relocation::Type pType,
+ MCFragmentRef* pTargetRef,
+ Relocation::Address pAddend,
+ Relocation::DWord pTargetData)
+ : MCFragment(llvm::MCFragment::FT_Reloc),
+ m_Type(pType),
+ m_TargetData(pTargetData),
+ m_pSymInfo(NULL),
+ m_Addend(pAddend)
+{
+ if(NULL != pTargetRef)
+ m_TargetAddress.assign(*pTargetRef->frag(), pTargetRef->offset()) ;
+}
+
+Relocation::~Relocation()
+{
+}
+
+Relocation::Address Relocation::place(const Layout& pLayout) const
+{
+ Address sect_addr = pLayout.getOutputLDSection(*(m_TargetAddress.frag()))->addr();
+ return sect_addr + pLayout.getOutputOffset(m_TargetAddress);
+}
+
+Relocation::Address Relocation::symValue() const
+{
+ if(m_pSymInfo->type() == ResolveInfo::Section &&
+ m_pSymInfo->outSymbol()->hasFragRef()) {
+ return llvm::cast<LDSection>(
+ m_pSymInfo->outSymbol()->fragRef()->frag()->getParent()->getSection()).addr();
+ }
+ return m_pSymInfo->outSymbol()->value();
+}
+
+void Relocation::apply(RelocationFactory& pRelocFactory,
+ const MCLDInfo& pLDInfo)
+{
+ pRelocFactory.applyRelocation(*this, pLDInfo);
+}
+
+void Relocation::setType(Type pType)
+{
+ m_Type = pType;
+}
+
+void Relocation::setAddend(Address pAddend)
+{
+ m_Addend = pAddend;
+}
+
+void Relocation::setSymInfo(ResolveInfo* pSym)
+{
+ m_pSymInfo = pSym;
+}
+
+Relocation::DWord& Relocation::target()
+{
+ return m_TargetData;
+}
+
+const Relocation::DWord& Relocation::target() const
+{
+ return m_TargetData;
+}
+
diff --git a/lib/LD/RelocationFactory.cpp b/lib/LD/RelocationFactory.cpp
new file mode 100644
index 0000000..2bcfeb3
--- /dev/null
+++ b/lib/LD/RelocationFactory.cpp
@@ -0,0 +1,91 @@
+//===- RelocationFactory.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Target/GOT.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <llvm/Support/Host.h>
+#include <cstring>
+#include <cassert>
+
+using namespace mcld;
+
+//==========================
+// RelocationFactory
+RelocationFactory::RelocationFactory(size_t pNum)
+ : GCFactory<Relocation, 0>(pNum),
+ m_pLayout(NULL) {
+}
+
+RelocationFactory::~RelocationFactory()
+{
+}
+
+Relocation* RelocationFactory::produce(RelocationFactory::Type pType,
+ MCFragmentRef& pFragRef,
+ Address pAddend)
+{
+ // target_data is the place where the relocation applys to.
+ // Use TargetDataFactory to generate temporary data, and copy the
+ // content of the fragment into this data.
+ DWord target_data = 0;
+
+ // byte swapping if the host and target have different endian
+ if(llvm::sys::isLittleEndianHost() != getTarget().isLittleEndian()) {
+ uint32_t tmp_data;
+
+ switch(getTarget().bitclass()) {
+ case 32u:
+ pFragRef.memcpy(&tmp_data, 4);
+ tmp_data = bswap32(tmp_data);
+ target_data = tmp_data;
+ break;
+
+ case 64u:
+ pFragRef.memcpy(&target_data, 8);
+ target_data = bswap64(target_data);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ pFragRef.memcpy(&target_data, (getTarget().bitclass()/8));
+ }
+
+ Relocation *result = allocate();
+ new (result) Relocation(pType, &pFragRef, pAddend, target_data);
+ return result;
+}
+
+Relocation* RelocationFactory::produceEmptyEntry()
+{
+ // FIXME: To prevent relocations from double free by both iplist and
+ // GCFactory, currently we new relocations directly and let iplist
+ // delete them.
+
+ return new Relocation(0, 0, 0, 0);
+}
+
+void RelocationFactory::destroy(Relocation* pRelocation)
+{
+ /** GCFactory will recycle the relocation **/
+}
+
+void RelocationFactory::setLayout(const Layout& pLayout)
+{
+ m_pLayout = &pLayout;
+}
+
+const Layout& RelocationFactory::getLayout() const
+{
+ assert(0 != m_pLayout);
+ return *m_pLayout;
+}
+
diff --git a/lib/LD/ResolveInfo.cpp b/lib/LD/ResolveInfo.cpp
new file mode 100644
index 0000000..b931d19
--- /dev/null
+++ b/lib/LD/ResolveInfo.cpp
@@ -0,0 +1,228 @@
+//===- ResolveInfo.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/ResolveInfo.h"
+#include <cstring>
+
+using namespace mcld;
+
+//==========================
+// ResolveInfo
+ResolveInfo::ResolveInfo()
+ : m_Size(0), m_BitField(0) {
+ m_Ptr.sym_ptr = 0;
+}
+
+ResolveInfo::~ResolveInfo()
+{
+}
+
+void ResolveInfo::override(const ResolveInfo& pFrom)
+{
+ m_Size = pFrom.m_Size;
+ overrideAttributes(pFrom);
+ overrideVisibility(pFrom);
+}
+
+void ResolveInfo::overrideAttributes(const ResolveInfo& pFrom)
+{
+ m_BitField &= ~RESOLVE_MASK;
+ m_BitField |= (pFrom.m_BitField & RESOLVE_MASK);
+}
+
+/// overrideVisibility - override the visibility
+/// always use the most strict visibility
+void ResolveInfo::overrideVisibility(const ResolveInfo& pFrom)
+{
+ // Reference: Google gold linker: resolve.cc
+ //
+ // The rule for combining visibility is that we always choose the
+ // most constrained visibility. In order of increasing constraint,
+ // visibility goes PROTECTED, HIDDEN, INTERNAL. This is the reverse
+ // of the numeric values, so the effect is that we always want the
+ // smallest non-zero value.
+ //
+ // enum {
+ // STV_DEFAULT = 0,
+ // STV_INTERNAL = 1,
+ // STV_HIDDEN = 2,
+ // STV_PROTECTED = 3
+ // };
+
+ Visibility from_vis = pFrom.visibility();
+ Visibility cur_vis = visibility();
+ if (0 != from_vis ) {
+ if (0 == cur_vis)
+ setVisibility(from_vis);
+ else if (cur_vis > from_vis)
+ setVisibility(from_vis);
+ }
+}
+
+void ResolveInfo::setRegular()
+{
+ m_BitField &= (~dynamic_flag);
+}
+
+void ResolveInfo::setDynamic()
+{
+ m_BitField |= dynamic_flag;
+}
+
+void ResolveInfo::setSource(bool pIsDyn)
+{
+ if (pIsDyn)
+ m_BitField |= dynamic_flag;
+ else
+ m_BitField &= (~dynamic_flag);
+}
+
+void ResolveInfo::setType(uint32_t pType)
+{
+ m_BitField &= ~TYPE_MASK;
+ m_BitField |= ((pType << TYPE_OFFSET) & TYPE_MASK);
+}
+
+void ResolveInfo::setDesc(uint32_t pDesc)
+{
+ m_BitField &= ~DESC_MASK;
+ m_BitField |= ((pDesc << DESC_OFFSET) & DESC_MASK);
+}
+
+void ResolveInfo::setBinding(uint32_t pBinding)
+{
+ m_BitField &= ~BINDING_MASK;
+ if (pBinding == Local || pBinding == Absolute)
+ m_BitField |= local_flag;
+ if (pBinding == Weak || pBinding == Absolute)
+ m_BitField |= weak_flag;
+}
+
+void ResolveInfo::setReserved(uint32_t pReserved)
+{
+ m_BitField &= ~RESERVED_MASK;
+ m_BitField |= ((pReserved << RESERVED_OFFSET) & RESERVED_MASK);
+}
+
+void ResolveInfo::setOther(uint32_t pOther)
+{
+ setVisibility(static_cast<ResolveInfo::Visibility>(pOther & 0x3));
+}
+
+void ResolveInfo::setVisibility(ResolveInfo::Visibility pVisibility)
+{
+ m_BitField &= ~VISIBILITY_MASK;
+ m_BitField |= pVisibility << VISIBILITY_OFFSET;
+}
+
+void ResolveInfo::setIsSymbol(bool pIsSymbol)
+{
+ if (pIsSymbol)
+ m_BitField |= symbol_flag;
+ else
+ m_BitField &= ~symbol_flag;
+}
+
+bool ResolveInfo::isDyn() const
+{
+ return (dynamic_flag == (m_BitField & DYN_MASK));
+}
+
+bool ResolveInfo::isUndef() const
+{
+ return (undefine_flag == (m_BitField & DESC_MASK));
+}
+
+bool ResolveInfo::isDefine() const
+{
+ return (define_flag == (m_BitField & DESC_MASK));
+}
+
+bool ResolveInfo::isCommon() const
+{
+ return (common_flag == (m_BitField & DESC_MASK));
+}
+
+bool ResolveInfo::isIndirect() const
+{
+ return (indirect_flag == (m_BitField & DESC_MASK));
+}
+
+// isGlobal - [L,W] == [0, 0]
+bool ResolveInfo::isGlobal() const
+{
+ return (global_flag == (m_BitField & BINDING_MASK));
+}
+
+// isWeak - [L,W] == [0, 1]
+bool ResolveInfo::isWeak() const
+{
+ return (weak_flag == (m_BitField & BINDING_MASK));
+}
+
+// isLocal - [L,W] == [1, 0]
+bool ResolveInfo::isLocal() const
+{
+ return (local_flag == (m_BitField & BINDING_MASK));
+}
+
+// isAbsolute - [L,W] == [1, 1]
+bool ResolveInfo::isAbsolute() const
+{
+ return (absolute_flag == (m_BitField & BINDING_MASK));
+}
+
+bool ResolveInfo::isSymbol() const
+{
+ return (symbol_flag == (m_BitField & SYMBOL_MASK));
+}
+
+bool ResolveInfo::isString() const
+{
+ return (string_flag == (m_BitField & SYMBOL_MASK));
+}
+
+uint32_t ResolveInfo::type() const
+{
+ return (m_BitField & TYPE_MASK) >> TYPE_OFFSET;
+}
+
+uint32_t ResolveInfo::desc() const
+{
+ return (m_BitField & DESC_MASK) >> DESC_OFFSET;
+}
+
+uint32_t ResolveInfo::binding() const
+{
+ if (m_BitField & LOCAL_MASK) {
+ if (m_BitField & GLOBAL_MASK) {
+ return ResolveInfo::Absolute;
+ }
+ return ResolveInfo::Local;
+ }
+ return m_BitField & GLOBAL_MASK;
+}
+
+uint32_t ResolveInfo::reserved() const
+{
+ return (m_BitField & RESERVED_MASK) >> RESERVED_OFFSET;
+}
+
+ResolveInfo::Visibility ResolveInfo::visibility() const
+{
+ return static_cast<ResolveInfo::Visibility>((m_BitField & VISIBILITY_MASK) >> VISIBILITY_OFFSET);
+}
+
+bool ResolveInfo::compare(const ResolveInfo::key_type& pKey)
+{
+ size_t length = nameSize();
+ if (length != pKey.size())
+ return false;
+ return (0 == std::memcmp(m_Name, pKey.data(), length));
+}
+
diff --git a/lib/LD/ResolveInfoFactory.cpp b/lib/LD/ResolveInfoFactory.cpp
new file mode 100644
index 0000000..feb52a3
--- /dev/null
+++ b/lib/LD/ResolveInfoFactory.cpp
@@ -0,0 +1,40 @@
+//===- ResolveInfoFactory.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/ResolveInfoFactory.h"
+#include <cstring>
+#include <cstdlib>
+
+using namespace mcld;
+
+//==========================
+// ResolveInfoFactory
+ResolveInfoFactory::entry_type*
+ResolveInfoFactory::produce(const ResolveInfoFactory::key_type& pKey)
+{
+ entry_type* result = static_cast<entry_type*>(
+ malloc(sizeof(entry_type)+pKey.size()+1));
+ if (NULL == result)
+ return NULL;
+
+ new (result) entry_type();
+ std::memcpy(result->m_Name, pKey.data(), pKey.size());
+ result->m_Name[pKey.size()] = '\0';
+ result->m_BitField &= ~ResolveInfo::RESOLVE_MASK;
+ result->m_BitField |= (pKey.size() << ResolveInfo::NAME_LENGTH_OFFSET);
+ return result;
+}
+
+void ResolveInfoFactory::destroy(ResolveInfoFactory::entry_type* pEntry)
+{
+ if (NULL != pEntry) {
+ pEntry->~entry_type();
+ free(pEntry);
+ }
+}
+
diff --git a/lib/LD/Resolver.cpp b/lib/LD/Resolver.cpp
new file mode 100644
index 0000000..0f7f06e
--- /dev/null
+++ b/lib/LD/Resolver.cpp
@@ -0,0 +1,33 @@
+//===- Resolver.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/Resolver.h"
+#include <cassert>
+
+using namespace mcld;
+
+//==========================
+// Resolver
+Resolver::Resolver()
+ : m_Mesg() {
+}
+
+Resolver::Resolver(const Resolver& pCopy)
+ : m_Mesg(pCopy.m_Mesg) {
+}
+
+Resolver::~Resolver()
+{
+ m_Mesg.clear();
+}
+
+void Resolver::clearMesg()
+{
+ m_Mesg.clear();
+}
+
diff --git a/lib/LD/SectionMap.cpp b/lib/LD/SectionMap.cpp
new file mode 100644
index 0000000..d81dfdd
--- /dev/null
+++ b/lib/LD/SectionMap.cpp
@@ -0,0 +1,142 @@
+//===- SectionMap.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <cassert>
+#include <cstring>
+#include <mcld/LD/SectionMap.h>
+
+using namespace mcld;
+
+//==========================
+// SectionMap
+
+SectionMap::SectionMap()
+{
+}
+
+SectionMap::~SectionMap()
+{
+}
+
+const std::string& SectionMap::getOutputSectName(const std::string& pInput)
+{
+ iterator it;
+ for (it = begin(); it != end(); ++it) {
+ if (0 == strncmp(pInput.c_str(),
+ (*it).inputSubStr.c_str(),
+ (*it).inputSubStr.length()))
+ break;
+ // wildcard to a user-defined output section.
+ else if (0 == strcmp("*", (*it).inputSubStr.c_str()))
+ break;
+ }
+ // if still no matching, just let a output seciton has the same input name
+ if (it == end())
+ return pInput;
+
+ return (*it).outputStr;
+}
+
+bool SectionMap::push_back(const std::string& pInput,
+ const std::string& pOutput,
+ const uint64_t pOffset)
+{
+ // Now only check if the mapping exists in the map already
+ // TODO: handle the cases such as overriding the exist mapping and drawing
+ // exception from the given SECTIONS command
+ iterator it;
+ for (it = begin(); it != end(); ++it) {
+ if (pInput == (*it).inputSubStr)
+ return false;
+ }
+ struct Mapping mapping = {
+ pInput,
+ pOutput,
+ pOffset,
+ };
+ m_SectMap.push_back(mapping);
+ return true;
+}
+
+SectionMap::iterator SectionMap::find(const std::string& pInput)
+{
+ iterator it;
+ for (it = begin(); it != end(); ++it) {
+ if(pInput == (*it).inputSubStr)
+ break;
+ }
+ return it;
+}
+
+SectionMap::Mapping* SectionMap::at(const std::string& pInput)
+{
+ iterator it;
+ for (it = begin(); it != end(); ++it) {
+ if(pInput == (*it).inputSubStr)
+ break;
+ }
+ if (end() == it)
+ return NULL;
+ return &(*it);
+}
+
+// Common mappings of ELF and other formants. Now only ELF specific mappings are added
+const SectionMap::SectionNameMapping SectionMap::m_StdSectionMap[] =
+{
+ {".text", ".text"},
+ {".rodata", ".rodata"},
+ {".data.rel.ro.local", ".data.rel.ro.local"},
+ {".data.rel.ro", ".data.rel.ro"},
+ {".data", ".data"},
+ {".bss", ".bss"},
+ {".tdata", ".tdata"},
+ {".tbss", ".tbss"},
+ {".init_array", ".init_array"},
+ {".fini_array", ".fini_array"},
+ // TODO: Support DT_INIT_ARRAY for all constructors?
+ {".ctors", ".ctors"},
+ {".dtors", ".dtors"},
+ {".sdata", ".sdata"},
+ {".sbss", ".sbss"},
+ // FIXME: in GNU ld, if we are creating a shared object .sdata2 and .sbss2
+ // sections would be handled differently.
+ {".sdata2", ".sdata"},
+ {".sbss2", ".sbss"},
+ {".lrodata", ".lrodata"},
+ {".ldata", ".ldata"},
+ {".lbss", ".lbss"},
+ {".gcc_except_table", ".gcc_except_table"},
+ {".gnu.linkonce.d.rel.ro.local", ".data.rel.ro.local"},
+ {".gnu.linkonce.d.rel.ro", ".data.rel.ro"},
+ {".gnu.linkonce.t", ".text"},
+ {".gnu.linkonce.r", ".rodata"},
+ {".gnu.linkonce.d", ".data"},
+ {".gnu.linkonce.b", ".bss"},
+ {".gnu.linkonce.s", ".sdata"},
+ {".gnu.linkonce.sb", ".sbss"},
+ {".gnu.linkonce.s2", ".sdata"},
+ {".gnu.linkonce.sb2", ".sbss"},
+ {".gnu.linkonce.wi", ".debug_info"},
+ {".gnu.linkonce.td", ".tdata"},
+ {".gnu.linkonce.tb", ".tbss"},
+ {".gnu.linkonce.lr", ".lrodata"},
+ {".gnu.linkonce.l", ".ldata"},
+ {".gnu.linkonce.lb", ".lbss"},
+};
+
+const int SectionMap::m_StdSectionMapSize =
+ (sizeof(SectionMap::m_StdSectionMap) / sizeof(SectionMap::m_StdSectionMap[0]));
+
+bool SectionMap::initStdSectionMap()
+{
+ for (int i = 0; i < m_StdSectionMapSize; ++i) {
+ if (!push_back(m_StdSectionMap[i].from, m_StdSectionMap[i].to))
+ return false;
+ }
+ return true;
+}
diff --git a/lib/LD/SectionMerger.cpp b/lib/LD/SectionMerger.cpp
new file mode 100644
index 0000000..f6aef9e
--- /dev/null
+++ b/lib/LD/SectionMerger.cpp
@@ -0,0 +1,93 @@
+//===- SectionMerger.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <cassert>
+#include <cstring>
+#include <mcld/LD/SectionMerger.h>
+
+using namespace mcld;
+
+//==========================
+// SectionMerger
+
+SectionMerger::SectionMerger(SectionMap& pSectionMap, LDContext& pContext)
+: m_SectionNameMap(pSectionMap),
+ m_Output(pContext),
+ m_LDSectionMap(pSectionMap.size())
+{
+}
+
+SectionMerger::~SectionMerger()
+{
+}
+
+SectionMerger::iterator SectionMerger::find(const std::string& pName)
+{
+ if (empty())
+ initOutputSectMap();
+
+ iterator it;
+ for (it = begin(); it != end(); ++it) {
+ if (0 == strncmp(pName.c_str(),
+ (*it).inputSubStr.c_str(),
+ (*it).inputSubStr.length()))
+ break;
+ // wildcard to a user-defined output section.
+ else if(0 == strcmp("*", (*it).inputSubStr.c_str()))
+ break;
+ }
+ return it;
+}
+
+LDSection* SectionMerger::getOutputSectHdr(const std::string& pName)
+{
+ LDSection* section;
+ iterator it = find(pName);
+
+ // check if we can find a matched LDSection.
+ // If not, we need to find it in output context. But this should be rare.
+ if (it != end())
+ section = (*it).outputSection;
+ else
+ section = m_Output.getSection(pName);
+
+ assert(NULL != section);
+ return section;
+}
+
+llvm::MCSectionData* SectionMerger::getOutputSectData(const std::string& pName)
+{
+ return getOutputSectHdr(pName)->getSectionData();
+}
+
+bool SectionMerger::addMapping(const std::string& pName, LDSection* pSection)
+{
+ iterator it = find(pName);
+ if (it != end()) {
+ assert(NULL == (*it).outputSection);
+ (*it).outputSection = pSection;
+ return true;
+ }
+ // the mapping rule is not in SectionMap, and this is handled in getOutputSectHdr.
+ return false;
+}
+
+void SectionMerger::initOutputSectMap()
+{
+ // Based on SectionMap to initialize the map from a input substr to its
+ // associated output LDSection*
+ SectionMap::iterator it;
+ for (it = m_SectionNameMap.begin(); it != m_SectionNameMap.end(); ++it) {
+ struct Mapping mapping = {
+ (*it).inputSubStr,
+ NULL,
+ };
+ m_LDSectionMap.push_back(mapping);
+ }
+ assert(m_SectionNameMap.size() == m_LDSectionMap.size());
+}
diff --git a/lib/LD/StaticResolver.cpp b/lib/LD/StaticResolver.cpp
new file mode 100644
index 0000000..3ba49e2
--- /dev/null
+++ b/lib/LD/StaticResolver.cpp
@@ -0,0 +1,230 @@
+//===- StaticResolver.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/StaticResolver.h>
+#include <mcld/LD/LDSymbol.h>
+#include <cassert>
+
+using namespace mcld;
+
+
+//==========================
+// StaticResolver
+StaticResolver::StaticResolver()
+{
+}
+
+StaticResolver::~StaticResolver()
+{
+}
+
+StaticResolver::StaticResolver(const StaticResolver& pCopy)
+ : Resolver(pCopy) {
+}
+
+unsigned int StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
+ const ResolveInfo& __restrict__ pNew,
+ bool &pOverride)
+{
+
+ /* The state table itself.
+ * The first index is a link_row and the second index is a bfd_link_hash_type.
+ *
+ * Cs -> all rest kind of common (d_C, wd_C)
+ * Is -> all kind of indeirect
+ */
+ static const enum LinkAction link_action[LAST_ORD][LAST_ORD] =
+ {
+ /* new\old U w_U d_U wd_U D w_D d_D wd_D C w_C, Cs, Is */
+ /* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUNDW, NOACT, NOACT, NOACT, REFC },
+ /* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUND, DUNDW, NOACT, NOACT, NOACT, REFC },
+ /* d_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
+ /* wd_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
+ /* D */ {DEF, DEF, DEF, DEF, MDEF, DEF, DEF, DEF, CDEF, CDEF, CDEF, MDEF },
+ /* w_D */ {DEFW, DEFW, DEFW, DEFW, NOACT, NOACT, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT},
+ /* d_D */ {DEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF },
+ /* wd_D */ {MDEFWD, MDEFWD, DEFWD, DEFWD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT},
+ /* C */ {COM, COM, COM, COM, CREF, COM, COM, COM, MBIG, COM, BIG, REFC },
+ /* w_C */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
+ /* Cs */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, MBIG, MBIG, MBIG, REFC },
+ /* Is */ {IND, IND, IND, IND, MDEF, IND, IND, IND, CIND, CIND, CIND, MIND }
+ };
+
+ // Special cases:
+ // * when a dynamic defined symbol meets a dynamic weak defined symbol, act
+ // noting.
+ // * when a undefined symbol meets a dynamic defined symbol, override by
+ // dynamic defined first, then recover back to undefined symbol later.
+ // * when a dynamic defined symbol meets a undefined symbol or a weak
+ // undefined symbol, do not override, instead of marking.
+ // * When a undefined symbol meets a dynamic defined symbol or a weak
+ // undefined symbol meets a dynamic defined symbol, should override.
+ // * When a common symbol meets a weak common symbol, adjust the size of
+ // common symbol (ref: Google gold linker: resolve.cc)
+
+ unsigned int row = getOrdinate(pNew);
+ unsigned int col = getOrdinate(pOld);
+
+ bool cycle = false;
+ unsigned int result = Resolver::Success;
+ pOverride = false;
+ ResolveInfo* old = &pOld;
+ LinkAction action;
+ do {
+ result = Resolver::Success;
+ cycle = false;
+ action = link_action[row][col];
+
+ switch(action) {
+ case FAIL: { /* abort. */
+ m_Mesg = std::string("internal error [StaticResolver.cpp:loc 86].\n") +
+ std::string("Please report to `mclinker@googlegroups.com'.\n");
+ result = Resolver::Abort;
+ break;
+ }
+ case NOACT: { /* no action. */
+ pOverride = false;
+ old->overrideVisibility(pNew);
+ result = Resolver::Success;
+ break;
+ }
+ case UND: /* override by symbol undefined symbol. */
+ case WEAK: /* override by symbol weak undefined. */
+ case DEF: /* override by symbol defined. */
+ case DEFW: /* override by symbol weak defined. */
+ case DEFD: /* override by symbol dynamic defined. */
+ case DEFWD: /* override by symbol dynamic weak defined. */
+ case COM: { /* override by symbol common defined. */
+ pOverride = true;
+ old->override(pNew);
+ result = Resolver::Success;
+ break;
+ }
+ case MDEFD: /* mark symbol dynamic defined. */
+ case MDEFWD: { /* mark symbol dynamic weak defined. */
+ uint32_t binding = old->binding();
+ old->override(pNew);
+ old->setBinding(binding);
+ m_Mesg = std::string("symbol `") +
+ old->name() +
+ std::string("' uses the type, dynamic, size and type in the dynamic symbol.");
+ pOverride = true;
+ result = Resolver::Warning;
+ break;
+ }
+ case DUND:
+ case DUNDW: {
+ if (old->binding() == ResolveInfo::Weak &&
+ pNew.binding() != ResolveInfo::Weak) {
+ old->setBinding(pNew.binding());
+ }
+ old->overrideVisibility(pNew);
+ pOverride = false;
+ result = Resolver::Success;
+ break;
+ }
+ case CREF: { /* Possibly warn about common reference to defined symbol. */
+ // A common symbol does not override a definition.
+ m_Mesg = std::string("common '") +
+ pNew.name() +
+ std::string("' overriden by previous definition.");
+ pOverride = false;
+ result = Resolver::Warning;
+ break;
+ }
+ case CDEF: { /* redefine existing common symbol. */
+ // We've seen a common symbol and now we see a definition. The
+ // definition overrides.
+ //
+ // NOTE: m_Mesg uses 'name' instead of `name' for being compatible to GNU ld.
+ m_Mesg = std::string("definition of '") +
+ old->name() +
+ std::string("' is overriding common.");
+ old->override(pNew);
+ pOverride = true;
+ result = Resolver::Warning;
+ break;
+ }
+ case BIG: { /* override by symbol common using largest size. */
+ if (old->size() < pNew.size())
+ old->setSize(pNew.size());
+ old->overrideAttributes(pNew);
+ old->overrideVisibility(pNew);
+ pOverride = true;
+ result = Resolver::Success;
+ break;
+ }
+ case MBIG: { /* mark common symbol by larger size. */
+ if (old->size() < pNew.size())
+ old->setSize(pNew.size());
+ old->overrideVisibility(pNew);
+ pOverride = false;
+ result = Resolver::Success;
+ break;
+ }
+ case CIND: { /* mark indirect symbol from existing common symbol. */
+ m_Mesg = std::string("indirect symbol `") +
+ pNew.name()+
+ std::string("' point to a common symbol.\n");
+ result = Resolver::Warning;
+ }
+ /* Fall through */
+ case IND: { /* override by indirect symbol. */
+ if (0 == pNew.link()) {
+ m_Mesg = std::string("indirect symbol `") +
+ pNew.name() +
+ std::string("' point to a inexistent symbol.");
+ result = Resolver::Abort;
+ break;
+ }
+
+ /** Should detect the loop of indirect symbol during file reading **/
+ // if (pNew.link()->isIndirect() && pNew.link()->link() == &pNew) {
+ // m_Mesg = "indirect symbol `"+pNew.name()+"' to `"+pNew.link()->name()+"' is a loop.";
+ // return Resolver::Abort;
+ //}
+
+ // change the old symbol to the indirect symbol
+ old->setLink(pNew.link());
+ pOverride = true;
+ break;
+ }
+ case MIND: { /* multiple indirect symbols. */
+ // it is OK if they both point to the same symbol
+ if (old->link() == pNew.link()) {
+ pOverride = false;
+ break;
+ }
+ }
+ /* Fall through */
+ case MDEF: { /* multiple definition error. */
+ m_Mesg = std::string("multiple definitions of `") +
+ pNew.name() +
+ std::string("'.");
+ result = Resolver::Abort;
+ break;
+ }
+ case REFC: { /* Mark indirect symbol referenced and then CYCLE. */
+ if (0 == old->link()) {
+ m_Mesg = std::string("indirect symbol `") +
+ old->name() +
+ std::string("' point to a inexistent symbol.");
+ result = Resolver::Abort;
+ break;
+ }
+
+ old = old->link();
+ col = getOrdinate(*old);
+ cycle = true;
+ break;
+ }
+ } // end of the big switch (action)
+ } while(cycle);
+ return result;
+}
+
diff --git a/lib/LD/StrSymPool.cpp b/lib/LD/StrSymPool.cpp
new file mode 100644
index 0000000..abe3fb7
--- /dev/null
+++ b/lib/LD/StrSymPool.cpp
@@ -0,0 +1,179 @@
+//===- StrSymPool.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mcld/LD/StrSymPool.h"
+#include "mcld/LD/Resolver.h"
+#include <llvm/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//==========================
+// StrSymPool
+StrSymPool::StrSymPool(const Resolver& pResolver, StrSymPool::size_type pSize)
+ : m_pResolver(pResolver.clone()), m_Table(pSize) {
+}
+
+StrSymPool::~StrSymPool()
+{
+ if (0 != m_pResolver)
+ delete m_pResolver;
+}
+
+/// createSymbol - create a symbol
+ResolveInfo* StrSymPool::createSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ ResolveInfo::Visibility pVisibility)
+{
+ ResolveInfo* result = m_Table.getEntryFactory().produce(pName);
+ result->setIsSymbol(true);
+ result->setSource(pIsDyn);
+ result->setType(pType);
+ result->setDesc(pDesc);
+ result->setBinding(pBinding);
+ result->setVisibility(pVisibility);
+ result->setSize(pSize);
+ return result;
+}
+
+/// insertSymbol - insert a symbol and resolve it immediately
+/// @return the pointer of resolved ResolveInfo
+/// @return is the symbol existent?
+void StrSymPool::insertSymbol(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ ResolveInfo::Visibility pVisibility,
+ ResolveInfo* pOldInfo,
+ Resolver::Result& pResult)
+{
+ // We should check if there is any symbol with the same name existed.
+ // If it already exists, we should use resolver to decide which symbol
+ // should be reserved. Otherwise, we insert the symbol and set up its
+ // attributes.
+ bool exist = false;
+ ResolveInfo* old_symbol = m_Table.insert(pName, exist);
+ ResolveInfo* new_symbol = NULL;
+ if (exist && old_symbol->isSymbol()) {
+ exist = true;
+ new_symbol = m_Table.getEntryFactory().produce(pName);
+ }
+ else {
+ exist = false;
+ new_symbol = old_symbol;
+ }
+
+ new_symbol->setIsSymbol(true);
+ new_symbol->setSource(pIsDyn);
+ new_symbol->setType(pType);
+ new_symbol->setDesc(pDesc);
+ new_symbol->setBinding(pBinding);
+ new_symbol->setVisibility(pVisibility);
+ new_symbol->setSize(pSize);
+
+ if (!exist) {
+ // not exit or not a symbol
+ pResult.info = new_symbol;
+ pResult.existent = false;
+ pResult.overriden = true;
+ return;
+ }
+ else if (NULL != pOldInfo) {
+ // existent, remember its attribute
+ pOldInfo->override(*old_symbol);
+ }
+
+ // exit and is a symbol
+ // symbol resolution
+ bool override = false;
+ unsigned int action = Resolver::LastAction;
+ switch(m_pResolver->resolve(*old_symbol, *new_symbol, override)) {
+ case Resolver::Success: {
+ pResult.info = old_symbol;
+ pResult.existent = true;
+ pResult.overriden = override;
+ break;
+ }
+ case Resolver::Warning: {
+ llvm::errs() << "WARNING: " << m_pResolver->mesg() << "\n";
+ m_pResolver->clearMesg();
+ pResult.info = old_symbol;
+ pResult.existent = true;
+ pResult.overriden = override;
+ break;
+ }
+ case Resolver::Abort: {
+ llvm::report_fatal_error(m_pResolver->mesg());
+ pResult.info = old_symbol;
+ pResult.existent = true;
+ pResult.overriden = override;
+ break;
+ }
+ default: {
+ m_pResolver->resolveAgain(*this, action, *old_symbol, *new_symbol, pResult);
+ break;
+ }
+ }
+ return;
+}
+
+llvm::StringRef StrSymPool::insertString(const llvm::StringRef& pString)
+{
+ bool exist = false;
+ ResolveInfo* resolve_info = m_Table.insert(pString, exist);
+ return llvm::StringRef(resolve_info->name(), resolve_info->nameSize());
+}
+
+void StrSymPool::reserve(StrSymPool::size_type pSize)
+{
+ m_Table.rehash(pSize);
+}
+
+StrSymPool::size_type StrSymPool::capacity() const
+{
+ return (m_Table.numOfBuckets() - m_Table.numOfEntries());
+}
+
+/// findInfo - find the resolved ResolveInfo
+ResolveInfo* StrSymPool::findInfo(const llvm::StringRef& pName)
+{
+ Table::iterator iter = m_Table.find(pName);
+ return iter.getEntry();
+}
+
+/// findInfo - find the resolved ResolveInfo
+const ResolveInfo* StrSymPool::findInfo(const llvm::StringRef& pName) const
+{
+ Table::const_iterator iter = m_Table.find(pName);
+ return iter.getEntry();
+}
+
+/// findSymbol - find the resolved output LDSymbol
+LDSymbol* StrSymPool::findSymbol(const llvm::StringRef& pName)
+{
+ ResolveInfo* info = findInfo(pName);
+ if (NULL == info)
+ return NULL;
+ return info->outSymbol();
+}
+
+/// findSymbol - find the resolved output LDSymbol
+const LDSymbol* StrSymPool::findSymbol(const llvm::StringRef& pName) const
+{
+ const ResolveInfo* info = findInfo(pName);
+ if (NULL == info)
+ return NULL;
+ return info->outSymbol();
+}
+
diff --git a/lib/LD/SymbolTableFactory.cpp b/lib/LD/SymbolTableFactory.cpp
new file mode 100644
index 0000000..180a4a9
--- /dev/null
+++ b/lib/LD/SymbolTableFactory.cpp
@@ -0,0 +1,52 @@
+//===- SymbolTableFactory.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/SymbolTableFactory.h"
+
+using namespace mcld;
+
+//==========================
+// SymbolTableFactory
+
+SymbolTableFactory::SymbolTableFactory(size_t pNumOfSymbolTables,
+ StrSymPool& pStrSymPool)
+ : m_StrSymPool(pStrSymPool),
+ m_InputFactory(pNumOfSymbolTables),
+ m_OutputFactory(pNumOfSymbolTables)
+{
+}
+
+SymbolTableFactory::~SymbolTableFactory()
+{
+}
+
+SymbolTableIF *SymbolTableFactory::
+createInputTable(StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable,
+ size_t pReserve)
+{
+ InputSymbolTable *inputSymTab = m_InputFactory.allocate();
+ new (inputSymTab) InputSymbolTable(m_StrSymPool,
+ pReserve,
+ pEntireStringTable,
+ pDynamicStringTable);
+ return inputSymTab;
+}
+
+SymbolTableIF *SymbolTableFactory::
+createOutputTable(StringTable &pEntireStringTable,
+ StringTable &pDynamicStringTable,
+ size_t pReserve)
+{
+ OutputSymbolTable *outputSymTab = m_OutputFactory.allocate();
+ new (outputSymTab) OutputSymbolTable(m_StrSymPool,
+ pReserve,
+ pEntireStringTable,
+ pDynamicStringTable);
+ return outputSymTab;
+}
diff --git a/lib/MC/Android.mk b/lib/MC/Android.mk
new file mode 100644
index 0000000..044b027
--- /dev/null
+++ b/lib/MC/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_mc_SRC_FILES := \
+ AttributeFactory.cpp \
+ ContextFactory.cpp \
+ InputFactory.cpp \
+ MCBitcodeInterceptor.cpp \
+ MCFragmentRef.cpp \
+ MCLDAttribute.cpp \
+ MCLDDirectory.cpp \
+ MCLDDriver.cpp \
+ MCLDFile.cpp \
+ MCLDInfo.cpp \
+ MCLDInput.cpp \
+ MCLDInputTree.cpp \
+ MCLDOptions.cpp \
+ MCLDOutput.cpp \
+ MCLinker.cpp \
+ MCRegionFragment.cpp \
+ SearchDirs.cpp \
+ SymbolCategory.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mc_SRC_FILES)
+LOCAL_MODULE:= libmcldMC
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mc_SRC_FILES)
+LOCAL_MODULE:= libmcldMC
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/lib/MC/AttributeFactory.cpp b/lib/MC/AttributeFactory.cpp
new file mode 100644
index 0000000..f6f4428
--- /dev/null
+++ b/lib/MC/AttributeFactory.cpp
@@ -0,0 +1,91 @@
+//===- AttributeFactory.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDAttribute.h"
+#include "mcld/MC/AttributeFactory.h"
+
+using namespace mcld;
+
+//==========================
+// AttributeFactory
+AttributeFactory::AttributeFactory()
+ : m_AttrSet() {
+ m_AttrSet.push_back(new mcld::Attribute());
+ m_pLast = new AttributeProxy(*this, *m_AttrSet.front());
+}
+
+AttributeFactory::AttributeFactory(size_t pNum)
+ : m_AttrSet() {
+ m_AttrSet.reserve(pNum);
+ m_AttrSet.push_back(new mcld::Attribute());
+ m_pLast = new AttributeProxy(*this, *m_AttrSet.front());
+}
+
+AttributeFactory::~AttributeFactory()
+{
+ iterator cur = m_AttrSet.begin();
+ iterator aEnd = m_AttrSet.end();
+ while(cur != aEnd) {
+ delete (*cur);
+ ++cur;
+ }
+ m_AttrSet.clear();
+ delete m_pLast;
+}
+
+void AttributeFactory::reserve(size_t pNum)
+{
+ m_AttrSet.reserve(pNum);
+}
+
+Attribute &AttributeFactory::predefined()
+{
+ return *m_AttrSet.front();
+}
+
+const Attribute &AttributeFactory::predefined() const
+{
+ return *m_AttrSet.front();
+}
+
+AttributeProxy* AttributeFactory::produce()
+{
+ m_pLast->change(m_AttrSet.front());
+ return m_pLast->clone();
+}
+
+AttributeProxy& AttributeFactory::last()
+{
+ return *m_pLast;
+}
+
+const AttributeProxy& AttributeFactory::last() const
+{
+ return *m_pLast;
+}
+
+Attribute* AttributeFactory::exists(const Attribute& pAttr) const
+{
+ const_iterator cur = m_AttrSet.begin();
+ const_iterator aEnd = m_AttrSet.end();
+ while(cur != aEnd) {
+ if (*(*cur) == pAttr) {
+ m_pLast->change(*cur);
+ return *cur;
+ }
+ ++cur;
+ }
+ return 0;
+}
+
+void AttributeFactory::record(mcld::Attribute &pAttr)
+{
+ m_AttrSet.push_back(&pAttr);
+ m_pLast->change(m_AttrSet.back());
+}
+
diff --git a/lib/MC/ContextFactory.cpp b/lib/MC/ContextFactory.cpp
new file mode 100644
index 0000000..d32ea8b
--- /dev/null
+++ b/lib/MC/ContextFactory.cpp
@@ -0,0 +1,35 @@
+//===- ContextFactory.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDContext.h>
+#include <mcld/MC/ContextFactory.h>
+
+using namespace mcld;
+
+//===---------------------------------------------------------------------===//
+// LDContextFactory
+ContextFactory::ContextFactory(size_t pNum)
+ : UniqueGCFactoryBase<sys::fs::Path, LDContext, 0>(pNum)
+{
+}
+
+ContextFactory::~ContextFactory()
+{
+}
+
+LDContext* ContextFactory::produce(const sys::fs::Path& pPath)
+{
+ LDContext* result = find(pPath);
+ if (0 == result) {
+ result = UniqueGCFactoryBase<sys::fs::Path, LDContext, 0>::allocate();
+ new (result) LDContext();
+ f_KeyMap.insert(std::make_pair(pPath, result));
+ }
+ return result;
+}
+
diff --git a/lib/MC/InputFactory.cpp b/lib/MC/InputFactory.cpp
new file mode 100644
index 0000000..d4d9cc2
--- /dev/null
+++ b/lib/MC/InputFactory.cpp
@@ -0,0 +1,33 @@
+//===- InputFactory.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/InputFactory.h"
+#include "mcld/MC/AttributeFactory.h"
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// InputFactory
+InputFactory::InputFactory(size_t pNum, AttributeFactory& pAttrFactory)
+ : GCFactory<Input,0>(pNum), m_AttrFactory(pAttrFactory) {
+}
+
+InputFactory::~InputFactory()
+{
+}
+
+Input* InputFactory::produce(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType,
+ off_t pFileOffset)
+{
+ mcld::Input* result = Alloc::allocate();
+ new (result) mcld::Input(pName, pPath, m_AttrFactory.last(), pType, pFileOffset);
+ return result;
+}
+
diff --git a/lib/MC/MCBitcodeInterceptor.cpp b/lib/MC/MCBitcodeInterceptor.cpp
new file mode 100644
index 0000000..a79c904
--- /dev/null
+++ b/lib/MC/MCBitcodeInterceptor.cpp
@@ -0,0 +1,70 @@
+//===- MCBitcodeInterceptor.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/Relocation.h>
+#include <mcld/MC/MCBitcodeInterceptor.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/MC/MCExpr.h>
+#include <llvm/MC/MCValue.h>
+#include <llvm/MC/MCFixup.h>
+#include <llvm/MC/MCFixupKindInfo.h>
+#include <llvm/MC/MCSymbol.h>
+#include <llvm/MC/MCAsmLayout.h>
+#include <llvm/MC/MCAsmBackend.h>
+#include <llvm/MC/MCAssembler.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/MC/MCObjectStreamer.h>
+#include <llvm/Support/Casting.h>
+#include <llvm/Support/ELF.h>
+
+using namespace llvm;
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// non-member functions
+
+//===----------------------------------------------------------------------===//
+// MCBitcodeInterceptor
+MCBitcodeInterceptor::MCBitcodeInterceptor(MCObjectStreamer &pStreamer,
+ TargetLDBackend& pBackend,
+ MCLDInfo& pLDInfo)
+ : MCObjectWriter(llvm::nulls(),
+ pStreamer.getAssembler().getWriter().isLittleEndian()),
+ m_Backend(pBackend),
+ m_LDInfo(pLDInfo) {
+ pStreamer.getAssembler().setWriter(*this);
+}
+
+MCBitcodeInterceptor::~MCBitcodeInterceptor()
+{
+}
+
+void MCBitcodeInterceptor::ExecutePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout)
+{
+}
+
+
+void MCBitcodeInterceptor::RecordRelocation(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFragment *Fragment,
+ const MCFixup &Fixup,
+ MCValue Target,
+ uint64_t &FixedValue)
+{
+}
+
+/// WriteObject - not really write out a object. Instead, load data to LDContext
+void MCBitcodeInterceptor::WriteObject(MCAssembler &Asm,
+ const MCAsmLayout &Layout)
+{
+}
+
+
diff --git a/lib/MC/MCFragmentRef.cpp b/lib/MC/MCFragmentRef.cpp
new file mode 100644
index 0000000..69a865e
--- /dev/null
+++ b/lib/MC/MCFragmentRef.cpp
@@ -0,0 +1,199 @@
+//===- MCFragmentRef.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/MathExtras.h>
+#include <mcld/MC/MCFragmentRef.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/MC/MCTargetFragment.h>
+#include <mcld/LD/Layout.h>
+#include <cstring>
+#include <cassert>
+
+using namespace mcld;
+
+/// compunteFragmentSize - compute the specific MCFragment size
+uint64_t mcld::computeFragmentSize(const Layout& pLayout,
+ const llvm::MCFragment& pFrag)
+{
+ switch (pFrag.getKind()) {
+ case llvm::MCFragment::FT_Data:
+ return static_cast<const llvm::MCDataFragment&>(pFrag).getContents().size();
+ case llvm::MCFragment::FT_Fill:
+ return static_cast<const llvm::MCFillFragment&>(pFrag).getSize();
+ case llvm::MCFragment::FT_Inst:
+ return static_cast<const llvm::MCInstFragment&>(pFrag).getInstSize();
+
+ case llvm::MCFragment::FT_LEB:
+ return static_cast<const llvm::MCLEBFragment&>(pFrag).getContents().size();
+
+ case llvm::MCFragment::FT_Align: {
+ uint64_t offset = pLayout.getOutputOffset(pFrag);
+ const llvm::MCAlignFragment& align_frag = static_cast<const llvm::MCAlignFragment&>(pFrag);
+ uint64_t size = llvm::OffsetToAlignment(offset, align_frag.getAlignment());
+ if (size > align_frag.getMaxBytesToEmit())
+ return 0;
+ return size;
+ }
+
+ case llvm::MCFragment::FT_Org: {
+ // TODO
+ assert(0 && "FT_Org: Not implemented yet");
+ return 0;
+ }
+
+ case llvm::MCFragment::FT_Dwarf:
+ return static_cast<const llvm::MCDwarfLineAddrFragment&>(pFrag).getContents().size();
+ case llvm::MCFragment::FT_DwarfFrame:
+ return static_cast<const llvm::MCDwarfCallFrameFragment&>(pFrag).getContents().size();
+
+ case llvm::MCFragment::FT_Region:
+ return static_cast<const MCRegionFragment&>(pFrag).getRegion().size();
+
+ case llvm::MCFragment::FT_Target:
+ return static_cast<const MCTargetFragment&>(pFrag).getSize();
+
+ case llvm::MCFragment::FT_Reloc:
+ assert(0 && "the size of FT_Reloc fragment is handled by backend");
+ return 0;
+
+ default:
+ assert(0 && "invalid fragment kind");
+ return 0;
+ }
+}
+
+//==========================
+// MCFragmentRef
+MCFragmentRef::MCFragmentRef()
+ : m_pFragment(NULL), m_Offset(0) {
+}
+
+MCFragmentRef::MCFragmentRef(llvm::MCFragment& pFrag,
+ MCFragmentRef::Offset pOffset)
+ : m_pFragment(&pFrag), m_Offset(pOffset) {
+}
+
+MCFragmentRef::~MCFragmentRef()
+{
+ m_pFragment = NULL;
+ m_Offset = 0;
+}
+
+MCFragmentRef& MCFragmentRef::assign(const MCFragmentRef& pCopy)
+{
+ m_pFragment = const_cast<llvm::MCFragment*>(pCopy.m_pFragment);
+ m_Offset = pCopy.m_Offset;
+ return *this;
+}
+
+MCFragmentRef& MCFragmentRef::assign(llvm::MCFragment& pFrag, MCFragmentRef::Offset pOffset)
+{
+ m_pFragment = &pFrag;
+ m_Offset = pOffset;
+ return *this;
+}
+
+void MCFragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const
+{
+ // check if the offset is still in a legal range.
+ if (NULL == m_pFragment)
+ return;
+ unsigned int total_offset = m_Offset + pOffset;
+ switch(m_pFragment->getKind()) {
+ case llvm::MCFragment::FT_Inst: {
+ llvm::MCInstFragment* inst_frag = static_cast<llvm::MCInstFragment*>(m_pFragment);
+ unsigned int total_length = inst_frag->getCode().size();
+ if (total_length < (total_offset+pNBytes))
+ pNBytes = total_length - total_offset;
+
+ std::memcpy(pDest, (inst_frag->getCode().data()+total_offset), pNBytes);
+ return;
+ }
+ case llvm::MCFragment::FT_Data: {
+ llvm::MCDataFragment* data_frag = static_cast<llvm::MCDataFragment*>(m_pFragment);
+ unsigned int total_length = data_frag->getContents().size();
+ if (total_length < (total_offset+pNBytes))
+ pNBytes = total_length - total_offset;
+
+ std::memcpy(pDest, (data_frag->getContents().data()+total_offset), pNBytes);
+ return;
+ }
+ case llvm::MCFragment::FT_Region: {
+ MCRegionFragment* region_frag = static_cast<mcld::MCRegionFragment*>(m_pFragment);
+ unsigned int total_length = region_frag->getRegion().size();
+ if (total_length < (total_offset+pNBytes))
+ pNBytes = total_length - total_offset;
+
+ std::memcpy(pDest, region_frag->getRegion().getBuffer(total_offset), pNBytes);
+ return;
+ }
+ case llvm::MCFragment::FT_Align:
+ case llvm::MCFragment::FT_Fill:
+ case llvm::MCFragment::FT_Org:
+ case llvm::MCFragment::FT_Dwarf:
+ case llvm::MCFragment::FT_DwarfFrame:
+ case llvm::MCFragment::FT_LEB:
+ default:
+ return;
+ }
+}
+
+MCFragmentRef::Address MCFragmentRef::deref()
+{
+ if (NULL == m_pFragment)
+ return NULL;
+ Address base = NULL;
+ switch(m_pFragment->getKind()) {
+ case llvm::MCFragment::FT_Inst:
+ base = (Address)static_cast<llvm::MCInstFragment*>(m_pFragment)->getCode().data();
+ break;
+ case llvm::MCFragment::FT_Data:
+ base = (Address)static_cast<llvm::MCDataFragment*>(m_pFragment)->getContents().data();
+ break;
+ case llvm::MCFragment::FT_Region:
+ base = static_cast<mcld::MCRegionFragment*>(m_pFragment)->getRegion().getBuffer();
+ break;
+ case llvm::MCFragment::FT_Align:
+ case llvm::MCFragment::FT_Fill:
+ case llvm::MCFragment::FT_Org:
+ case llvm::MCFragment::FT_Dwarf:
+ case llvm::MCFragment::FT_DwarfFrame:
+ case llvm::MCFragment::FT_LEB:
+ default:
+ return NULL;
+ }
+ return base + m_Offset;
+}
+
+MCFragmentRef::ConstAddress MCFragmentRef::deref() const
+{
+ if (NULL == m_pFragment)
+ return NULL;
+ ConstAddress base = NULL;
+ switch(m_pFragment->getKind()) {
+ case llvm::MCFragment::FT_Inst:
+ base = (ConstAddress)static_cast<const llvm::MCInstFragment*>(m_pFragment)->getCode().data();
+ break;
+ case llvm::MCFragment::FT_Data:
+ base = (ConstAddress)static_cast<const llvm::MCDataFragment*>(m_pFragment)->getContents().data();
+ break;
+ case llvm::MCFragment::FT_Region:
+ base = static_cast<const mcld::MCRegionFragment*>(m_pFragment)->getRegion().getBuffer();
+ break;
+ case llvm::MCFragment::FT_Align:
+ case llvm::MCFragment::FT_Fill:
+ case llvm::MCFragment::FT_Org:
+ case llvm::MCFragment::FT_Dwarf:
+ case llvm::MCFragment::FT_DwarfFrame:
+ case llvm::MCFragment::FT_LEB:
+ default:
+ return NULL;
+ }
+ return base + m_Offset;
+}
+
diff --git a/lib/MC/MCLDAttribute.cpp b/lib/MC/MCLDAttribute.cpp
new file mode 100644
index 0000000..a361691
--- /dev/null
+++ b/lib/MC/MCLDAttribute.cpp
@@ -0,0 +1,172 @@
+//===- MCLDAttribute.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDAttribute.h"
+#include "mcld/MC/AttributeFactory.h"
+
+using namespace mcld;
+
+//==========================
+// AttrConstraint
+bool AttrConstraint::isLegal(const Attribute& pAttr, std::string &pErrMesg) const
+{
+ if (!isWholeArchive() && pAttr.isWholeArchive()) {
+ pErrMesg = std::string("Target does not support --whole-archive");
+ return false;
+ }
+ if (!isAsNeeded() && pAttr.isAsNeeded()) {
+ pErrMesg = std::string("Target does not support --as-needed");
+ return false;
+ }
+ if (!isAddNeeded() && pAttr.isAddNeeded()) {
+ pErrMesg = std::string("Target does not support --add-needed");
+ return false;
+ }
+ if (isStaticSystem() && pAttr.isDynamic()) {
+ pErrMesg = std::string("Target does not support --Bdynamic");
+ return false;
+ }
+ // FIXME: may be it's legal, but ignored by GNU ld.
+ if (isStaticSystem() && pAttr.isAsNeeded()) {
+ pErrMesg = std::string("Can't enable --as-needed on a target which does not support dynamic linking");
+ return false;
+ }
+ // FIXME: may be it's legal, but ignored by GNU ld.
+ if (pAttr.isAsNeeded() && pAttr.isStatic()) {
+ pErrMesg = std::string("Can't mix --static with --as-needed");
+ return false;
+ }
+ return true;
+}
+
+//==========================
+// AttributeProxy
+AttributeProxy::AttributeProxy(AttributeFactory& pParent, Attribute& pBase)
+ : m_AttrPool(pParent), m_pBase(&pBase) {
+}
+
+AttributeProxy::~AttributeProxy()
+{
+}
+
+bool AttributeProxy::isWholeArchive() const
+{
+ if (m_AttrPool.constraint().isWholeArchive())
+ return m_pBase->isWholeArchive();
+ else
+ return false;
+}
+
+bool AttributeProxy::isAsNeeded() const
+{
+ if (m_AttrPool.constraint().isAsNeeded())
+ return m_pBase->isAsNeeded();
+ else
+ return false;
+}
+
+bool AttributeProxy::isAddNeeded() const
+{
+ if (m_AttrPool.constraint().isAddNeeded())
+ return m_pBase->isAddNeeded();
+ else
+ return false;
+}
+
+bool AttributeProxy::isStatic() const
+{
+ if (m_AttrPool.constraint().isSharedSystem())
+ return m_pBase->isStatic();
+ else
+ return true;
+}
+
+bool AttributeProxy::isDynamic() const
+{
+ if (m_AttrPool.constraint().isSharedSystem())
+ return m_pBase->isDynamic();
+ else
+ return false;
+}
+
+static inline void ReplaceOrRecord(AttributeFactory& pParent,
+ Attribute *&pBase,
+ Attribute *&pCopy)
+{
+ Attribute *result = pParent.exists(*pCopy);
+ if (0 == result) { // can not find
+ pParent.record(*pCopy);
+ pBase = pCopy;
+ }
+ else { // find
+ delete pCopy;
+ pBase = result;
+ }
+}
+
+void AttributeProxy::setWholeArchive()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->setWholeArchive();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+void AttributeProxy::unsetWholeArchive()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->unsetWholeArchive();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+void AttributeProxy::setAsNeeded()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->setAsNeeded();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+void AttributeProxy::unsetAsNeeded()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->unsetAsNeeded();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+void AttributeProxy::setAddNeeded()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->setAddNeeded();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+void AttributeProxy::unsetAddNeeded()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->unsetAddNeeded();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+void AttributeProxy::setStatic()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->setStatic();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+void AttributeProxy::setDynamic()
+{
+ Attribute *copy = new Attribute(*m_pBase);
+ copy->setDynamic();
+ ReplaceOrRecord(m_AttrPool, m_pBase, copy);
+}
+
+AttributeProxy* AttributeProxy::clone() const
+{
+ return new AttributeProxy(m_AttrPool, *m_pBase);
+}
+
diff --git a/lib/MC/MCLDDirectory.cpp b/lib/MC/MCLDDirectory.cpp
new file mode 100644
index 0000000..1d7c649
--- /dev/null
+++ b/lib/MC/MCLDDirectory.cpp
@@ -0,0 +1,103 @@
+//===- MCLDDirectory.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDDirectory.h"
+#include "mcld/Support/FileSystem.h"
+
+using namespace mcld;
+using namespace mcld::sys::fs;
+
+//==========================
+// MCLDDirectory
+MCLDDirectory::MCLDDirectory()
+ : Directory(), m_Name(), m_bInSysroot(false) {
+}
+
+MCLDDirectory::MCLDDirectory(const char* pName)
+ : Directory(), m_Name(pName) {
+ Directory::m_Path.assign(pName);
+
+ if (!Directory::m_Path.empty())
+ m_bInSysroot = ('=' == Directory::m_Path.native()[0]);
+
+ Directory::m_Path.m_append_separator_if_needed();
+ if (m_bInSysroot)
+ Directory::m_Path.native().erase(Directory::m_Path.native().begin());
+ else
+ detail::open_dir(*this);
+}
+
+MCLDDirectory::MCLDDirectory(const std::string &pName)
+ : Directory(), m_Name(pName) {
+ Directory::m_Path.assign(pName);
+
+ if (!Directory::m_Path.empty())
+ m_bInSysroot = ('=' == Directory::m_Path.native()[0]);
+
+ Directory::m_Path.m_append_separator_if_needed();
+ if (m_bInSysroot)
+ Directory::m_Path.native().erase(Directory::m_Path.native().begin());
+ else
+ detail::open_dir(*this);
+}
+
+MCLDDirectory::MCLDDirectory(llvm::StringRef pName)
+ : Directory(), m_Name(pName.data(), pName.size()) {
+ Directory::m_Path.assign(pName.str());
+
+ if (!Directory::m_Path.empty())
+ m_bInSysroot = ('=' == Directory::m_Path.native()[0]);
+
+ Directory::m_Path.m_append_separator_if_needed();
+ if (m_bInSysroot)
+ Directory::m_Path.native().erase(Directory::m_Path.native().begin());
+ else
+ detail::open_dir(*this);
+}
+
+MCLDDirectory &MCLDDirectory::assign(llvm::StringRef pName)
+{
+ m_Name.assign(pName.data(), pName.size());
+ Directory::m_Path.assign(pName.str());
+
+ if (!Directory::m_Path.empty())
+ m_bInSysroot = ('=' == Directory::m_Path.native()[0]);
+
+ Directory::m_Path.m_append_separator_if_needed();
+ if (m_bInSysroot)
+ Directory::m_Path.native().erase(Directory::m_Path.native().begin());
+ else
+ detail::open_dir(*this);
+ Directory::m_FileStatus = FileStatus();
+ Directory::m_SymLinkStatus = FileStatus();
+ Directory::m_Cache.clear();
+ Directory::m_Handler = 0;
+ return (*this);
+}
+
+MCLDDirectory::~MCLDDirectory()
+{
+}
+
+bool MCLDDirectory::isInSysroot() const
+{
+ return m_bInSysroot;
+}
+
+void MCLDDirectory::setSysroot(const sys::fs::Path& pSysroot)
+{
+ if (m_bInSysroot) {
+ std::string old_path = Directory::m_Path.native();
+ Directory::m_Path.native() = pSysroot.native();
+ Directory::m_Path.m_append_separator_if_needed();
+ Directory::m_Path.native() += old_path;
+ detail::canonicalize(Directory::m_Path.native());
+ detail::open_dir(*this);
+ }
+}
+
diff --git a/lib/MC/MCLDDriver.cpp b/lib/MC/MCLDDriver.cpp
new file mode 100644
index 0000000..5e89097
--- /dev/null
+++ b/lib/MC/MCLDDriver.cpp
@@ -0,0 +1,358 @@
+//===- MCLDDriver.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/MCLDDriver.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/ArchiveReader.h>
+#include <mcld/LD/ObjectReader.h>
+#include <mcld/LD/DynObjReader.h>
+#include <mcld/LD/ObjectWriter.h>
+#include <mcld/LD/DynObjWriter.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/Support/RealPath.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <llvm/Support/ErrorHandling.h>
+
+using namespace llvm;
+using namespace mcld;
+
+MCLDDriver::MCLDDriver(MCLDInfo& pLDInfo, TargetLDBackend& pLDBackend)
+ : m_LDInfo(pLDInfo),
+ m_LDBackend(pLDBackend),
+ m_pLinker(0) {
+}
+
+MCLDDriver::~MCLDDriver()
+{
+ if (0 != m_pLinker)
+ delete m_pLinker;
+}
+
+void MCLDDriver::normalize() {
+
+ InputTree::dfs_iterator input, inEnd = m_LDInfo.inputs().dfs_end();
+ for (input = m_LDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
+ // already got type - for example, bitcode
+ if ((*input)->type() == Input::Script ||
+ (*input)->type() == Input::Object ||
+ (*input)->type() == Input::DynObj ||
+ (*input)->type() == Input::Archive)
+ continue;
+
+
+ MemoryArea *input_memory =
+ m_LDInfo.memAreaFactory().produce((*input)->path(), O_RDONLY);
+ if ((input_memory != NULL) && input_memory->isGood()) {
+ (*input)->setMemArea(input_memory);
+ }
+ else {
+ llvm::report_fatal_error("can not open file: " + (*input)->path().native());
+ return;
+ }
+
+ // is a relocatable object file
+ if (m_LDBackend.getObjectReader()->isMyFormat(**input)) {
+ (*input)->setType(Input::Object);
+ (*input)->setContext(m_LDInfo.contextFactory().produce((*input)->path()));
+ m_LDBackend.getObjectReader()->readObject(**input);
+ }
+ // is a shared object file
+ else if (m_LDBackend.getDynObjReader()->isMyFormat(**input)) {
+ (*input)->setType(Input::DynObj);
+ (*input)->setContext(m_LDInfo.contextFactory().produce((*input)->path()));
+ (*input)->setSOName((*input)->path().native());
+ m_LDBackend.getDynObjReader()->readDSO(**input);
+ }
+ // is an archive
+ else if (m_LDBackend.getArchiveReader()->isMyFormat(*(*input))) {
+ (*input)->setType(Input::Archive);
+ mcld::InputTree* archive_member = m_LDBackend.getArchiveReader()->readArchive(**input);
+ if(!archive_member) {
+ llvm::report_fatal_error("wrong format archive" + (*input)->path().string());
+ return;
+ }
+
+ m_LDInfo.inputs().merge<InputTree::Inclusive>(input, *archive_member);
+ }
+ else {
+ llvm::report_fatal_error(llvm::Twine("can not recognize file format: ") +
+ (*input)->path().native() +
+ llvm::Twine("\nobject format or target machine is wrong\n"));
+ }
+ }
+}
+
+
+bool MCLDDriver::linkable() const
+{
+ // check all attributes are legal
+ mcld::AttributeFactory::const_iterator attr, attrEnd = m_LDInfo.attrFactory().end();
+ for (attr=m_LDInfo.attrFactory().begin(); attr!=attrEnd; ++attr) {
+ std::string error_code;
+ if (!m_LDInfo.attrFactory().constraint().isLegal((**attr), error_code)) {
+ report_fatal_error(error_code);
+ return false;
+ }
+ }
+
+
+ bool hasDynObj = false;
+ // can not mix -static with shared objects
+ mcld::InputTree::const_bfs_iterator input, inEnd = m_LDInfo.inputs().bfs_end();
+ for (input=m_LDInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
+ if ((*input)->type() == mcld::Input::DynObj ) {
+ hasDynObj = true;
+ if((*input)->attribute()->isStatic()) {
+ report_fatal_error("Can't link shared object with -static option");
+ return false;
+ }
+ }
+ }
+
+ // can not mix -r with shared objects
+ return true;
+}
+
+/// initMCLinker - initialize MCLinker
+/// Connect all components with MCLinker
+bool MCLDDriver::initMCLinker()
+{
+ if (0 == m_pLinker)
+ m_pLinker = new MCLinker(m_LDBackend,
+ m_LDInfo,
+ *m_LDInfo.output().context(),
+ m_SectionMap);
+
+ // initialize the readers and writers
+ // Because constructor can not be failed, we initalize all readers and
+ // writers outside the MCLinker constructors.
+ if (!m_LDBackend.initArchiveReader(*m_pLinker, m_LDInfo) ||
+ !m_LDBackend.initObjectReader(*m_pLinker) ||
+ !m_LDBackend.initDynObjReader(*m_pLinker) ||
+ !m_LDBackend.initObjectWriter(*m_pLinker) ||
+ !m_LDBackend.initDynObjWriter(*m_pLinker))
+ return false;
+
+ /// initialize section mapping for standard format, target-dependent section,
+ /// (and user-defined mapping)
+ if (!m_SectionMap.initStdSectionMap() ||
+ !m_LDBackend.initTargetSectionMap(m_SectionMap))
+ return false;
+
+ // initialize standard segments and sections
+ switch (m_LDInfo.output().type()) {
+ case Output::DynObj: {
+ // intialize standard and target-dependent sections
+ if (!m_LDBackend.initDynObjSections(*m_pLinker))
+ return false;
+ break;
+ }
+ case Output::Exec: {
+ // intialize standard and target-dependent sections
+ if (!m_LDBackend.initExecSections(*m_pLinker))
+ return false;
+ break;
+ }
+ case Output::Object: {
+ llvm::report_fatal_error(llvm::Twine("output type is not implemented yet. file: `") +
+ m_LDInfo.output().name() +
+ llvm::Twine("'."));
+ return false;
+ }
+ default: {
+ llvm::report_fatal_error(llvm::Twine("unknown output type of file `") +
+ m_LDInfo.output().name() +
+ llvm::Twine("'."));
+ return false;
+ }
+ } // end of switch
+
+ // initialize target-dependent segments and sections
+ m_LDBackend.initTargetSections(*m_pLinker);
+
+ // initialize RelocationFactory
+ m_LDBackend.initRelocFactory(*m_pLinker);
+
+ return true;
+}
+
+/// readSections - read all input section headers
+bool MCLDDriver::readSections()
+{
+ // Bitcode is read by the other path. This function reads sections in object
+ // files.
+ mcld::InputTree::bfs_iterator input, inEnd = m_LDInfo.inputs().bfs_end();
+ for (input=m_LDInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
+ if ((*input)->type() == Input::Object) {
+ if (!m_LDBackend.getObjectReader()->readSections(**input))
+ return false;
+ }
+ }
+ return true;
+}
+
+/// mergeSections - put allinput sections into output sections
+bool MCLDDriver::mergeSections()
+{
+ // TODO: when MCLinker can read other object files, we have to merge
+ // sections
+ return true;
+}
+
+/// readSymbolTables - read symbol tables from the input files.
+/// for each input file, loads its symbol table from file.
+bool MCLDDriver::readSymbolTables()
+{
+ mcld::InputTree::dfs_iterator input, inEnd = m_LDInfo.inputs().dfs_end();
+ for (input=m_LDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
+ switch((*input)->type()) {
+ case Input::DynObj:
+ if (!m_LDBackend.getDynObjReader()->readSymbols(**input))
+ return false;
+ break;
+ case Input::Object:
+ if (!m_LDBackend.getObjectReader()->readSymbols(**input))
+ return false;
+ break;
+ }
+ }
+ return true;
+}
+
+/// mergeSymbolTables - merge the symbol tables of input files into the
+/// output's symbol table.
+bool MCLDDriver::mergeSymbolTables()
+{
+ mcld::InputTree::dfs_iterator input, inEnd = m_LDInfo.inputs().dfs_end();
+ for (input=m_LDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
+ if (!m_pLinker->mergeSymbolTable(**input))
+ return false;
+ }
+ return true;
+}
+
+/// addStandardSymbols - shared object and executable files need some
+/// standard symbols
+/// @return if there are some input symbols with the same name to the
+/// standard symbols, return false
+bool MCLDDriver::addStandardSymbols()
+{
+ return m_LDBackend.initStandardSymbols(*m_pLinker);
+}
+
+/// addTargetSymbols - some targets, such as MIPS and ARM, need some
+/// target-dependent symbols
+/// @return if there are some input symbols with the same name to the
+/// target symbols, return false
+bool MCLDDriver::addTargetSymbols()
+{
+ m_LDBackend.initTargetSymbols(*m_pLinker);
+ return true;
+}
+
+/// readRelocations - read all relocation entries
+///
+/// All symbols should be read and resolved before this function.
+bool MCLDDriver::readRelocations()
+{
+ // Bitcode is read by the other path. This function reads relocation sections
+ // in object files.
+ mcld::InputTree::bfs_iterator input, inEnd = m_LDInfo.inputs().bfs_end();
+ for (input=m_LDInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
+ if ((*input)->type() == Input::Object) {
+ if (!m_LDBackend.getObjectReader()->readRelocations(**input))
+ return false;
+ }
+ // ignore the other kinds of files.
+ }
+ return true;
+}
+
+/// prelayout - help backend to do some modification before layout
+bool MCLDDriver::prelayout()
+{
+ m_LDBackend.preLayout(m_LDInfo.output(),
+ m_LDInfo,
+ *m_pLinker);
+
+ m_LDBackend.allocateCommonSymbols(m_LDInfo, *m_pLinker);
+
+ /// measure NamePools - compute the size of name pool sections
+ /// In ELF, will compute the size of.symtab, .strtab, .dynsym, .dynstr,
+ /// and .hash sections.
+ ///
+ /// dump all symbols and strings from MCLinker and build the format-dependent
+ /// hash table.
+ m_LDBackend.sizeNamePools(m_LDInfo.output(), m_pLinker->getOutputSymbols(), m_LDInfo);
+
+ return true;
+}
+
+/// layout - linearly layout all output sections and reserve some space
+/// for GOT/PLT
+/// Because we do not support instruction relaxing in this early version,
+/// if there is a branch can not jump to its target, we return false
+/// directly
+bool MCLDDriver::layout()
+{
+ return m_pLinker->layout();
+}
+
+/// prelayout - help backend to do some modification after layout
+bool MCLDDriver::postlayout()
+{
+ m_LDBackend.postLayout(m_LDInfo.output(),
+ m_LDInfo,
+ *m_pLinker);
+ return true;
+}
+
+/// relocate - applying relocation entries and create relocation
+/// section in the output files
+/// Create relocation section, asking TargetLDBackend to
+/// read the relocation information into RelocationEntry
+/// and push_back into the relocation section
+bool MCLDDriver::relocate()
+{
+ return m_pLinker->applyRelocations();
+}
+
+/// finalizeSymbolValue - finalize the resolved symbol value.
+/// Before relocate(), after layout(), MCLinker should correct value of all
+/// symbol.
+bool MCLDDriver::finalizeSymbolValue()
+{
+ return m_pLinker->finalizeSymbols();
+}
+
+/// emitOutput - emit the output file.
+bool MCLDDriver::emitOutput()
+{
+ switch(m_LDInfo.output().type()) {
+ case Output::Object:
+ m_LDBackend.getObjectWriter()->writeObject(m_LDInfo.output());
+ return true;
+ case Output::DynObj:
+ m_LDBackend.getDynObjWriter()->writeDynObj(m_LDInfo.output());
+ return true;
+ /** TODO: open the executable file writer **/
+ // case Output::Exec:
+ // m_LDBackend.getExecWriter()->writeObject(m_LDInfo.output());
+ // return true;
+ }
+ return false;
+}
+
+/// postProcessing - do modification after all processes
+bool MCLDDriver::postProcessing()
+{
+ m_pLinker->syncRelocationResult();
+ return true;
+}
diff --git a/lib/MC/MCLDFile.cpp b/lib/MC/MCLDFile.cpp
new file mode 100644
index 0000000..e6bbbc4
--- /dev/null
+++ b/lib/MC/MCLDFile.cpp
@@ -0,0 +1,46 @@
+//===- MCLDFile.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDFile.h"
+#include "mcld/LD/LDContext.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/MemoryArea.h"
+#include <cstring>
+#include <cstdlib>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// MCLDFile
+MCLDFile::MCLDFile()
+ : m_Type(Unknown), m_pContext(0), m_Path(), m_Name(), m_pMemArea(0) {
+}
+
+MCLDFile::MCLDFile(llvm::StringRef pName)
+ : m_Type(Unknown), m_pContext(0), m_Path(), m_Name(pName.data()), m_pMemArea(0) {
+}
+
+MCLDFile::MCLDFile(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ unsigned int pType)
+ : m_Type(pType), m_pContext(0), m_Path(pPath), m_Name(pName.data()), m_pMemArea(0) {
+}
+
+MCLDFile::~MCLDFile()
+{
+}
+
+void MCLDFile::setSOName(const std::string& pName)
+{
+ size_t pos = pName.find_last_of(sys::fs::separator);
+ if (std::string::npos == pos)
+ m_Name = pName;
+ else
+ m_Name = pName.substr(pos + 1);
+}
+
diff --git a/lib/MC/MCLDInfo.cpp b/lib/MC/MCLDInfo.cpp
new file mode 100644
index 0000000..3cd0838
--- /dev/null
+++ b/lib/MC/MCLDInfo.cpp
@@ -0,0 +1,67 @@
+//===- MCLDInfo.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/MC/InputFactory.h>
+#include <mcld/MC/AttributeFactory.h>
+#include <mcld/MC/ContextFactory.h>
+#include <mcld/Config/Config.h>
+#include <string>
+
+using namespace mcld;
+
+//==========================
+// MCLDInfo
+MCLDInfo::MCLDInfo(const std::string& pTripleString,
+ size_t pAttrNum,
+ size_t pInputNum)
+ : m_Options(),
+ m_pBitcode(0),
+ m_Triple(pTripleString),
+ m_pStrSymPool(0)
+{
+ m_pAttrFactory = new AttributeFactory(pAttrNum);
+ m_pCntxtFactory = new ContextFactory(pInputNum);
+ m_pMemAreaFactory = new MemoryAreaFactory(pInputNum);
+ m_pInputFactory = new InputFactory(pInputNum, *m_pAttrFactory);
+ m_pInputTree = new InputTree(*m_pInputFactory);
+ m_pOutput = new mcld::Output();
+}
+
+MCLDInfo::~MCLDInfo()
+{
+ delete m_pOutput;
+ delete m_pAttrFactory;
+ delete m_pCntxtFactory;
+ delete m_pMemAreaFactory;
+ delete m_pInputFactory;
+ delete m_pInputTree;
+}
+
+void MCLDInfo::setBitcode(const Input& pInput)
+{
+ m_pBitcode = const_cast<Input*>(&pInput);
+}
+
+Input& MCLDInfo::bitcode()
+{
+ assert((0 != m_pBitcode) && "default bitcode is not set");
+ return *m_pBitcode;
+}
+
+const Input& MCLDInfo::bitcode() const
+{
+ assert((0 != m_pBitcode) && "default bitcode is not set");
+ return *m_pBitcode;
+}
+
+const char* MCLDInfo::version()
+{
+ return mcld::internal::version;
+}
diff --git a/lib/MC/MCLDInput.cpp b/lib/MC/MCLDInput.cpp
new file mode 100644
index 0000000..81a8b60
--- /dev/null
+++ b/lib/MC/MCLDInput.cpp
@@ -0,0 +1,37 @@
+//===- MCLDInput.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDInput.h"
+#include "mcld/MC/MCLDAttribute.h"
+
+using namespace mcld;
+
+//==========================
+// MCInput
+Input::Input(llvm::StringRef pName, const AttributeProxy& pProxy)
+ : MCLDFile(pName),
+ m_pAttr(const_cast<Attribute*>(pProxy.attr())),
+ m_bNeeded(false) {
+}
+
+Input::Input(llvm::StringRef pName,
+ const sys::fs::Path& pPath,
+ const AttributeProxy& pProxy,
+ unsigned int pType,
+ off_t pFileOffset)
+ : MCLDFile(pName, pPath, pType),
+ m_pAttr(const_cast<Attribute*>(pProxy.attr())),
+ m_bNeeded(false),
+ m_fileOffset(pFileOffset) {
+}
+
+Input::~Input()
+{
+ // do nothing. Attribute is deleted by AttributeFactory
+}
+
diff --git a/lib/MC/MCLDInputTree.cpp b/lib/MC/MCLDInputTree.cpp
new file mode 100644
index 0000000..b423988
--- /dev/null
+++ b/lib/MC/MCLDInputTree.cpp
@@ -0,0 +1,107 @@
+//===- MCLDInputTree.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDInputTree.h"
+#include "mcld/MC/InputFactory.h"
+
+using namespace mcld;
+
+InputTree::Succeeder InputTree::Afterward;
+InputTree::Includer InputTree::Downward;
+
+//===----------------------------------------------------------------------===//
+// InputTree
+InputTree::InputTree(InputFactory& pInputFactory)
+ : m_FileFactory(pInputFactory) {
+}
+
+InputTree::~InputTree()
+{
+}
+
+InputTree& InputTree::merge(InputTree::iterator pPosition,
+ const InputTree::Connector& pConnector,
+ InputTree& pTree)
+{
+ if (this == &pTree)
+ return *this;
+
+ if (!pTree.empty()) {
+ pConnector.connect(pPosition, iterator(pTree.m_Root.node.right));
+ BinaryTreeBase<Input>::m_Root.summon(
+ pTree.BinaryTreeBase<Input>::m_Root);
+ BinaryTreeBase<Input>::m_Root.delegate(pTree.m_Root);
+ pTree.m_Root.node.left = pTree.m_Root.node.right = &pTree.m_Root.node;
+ }
+ return *this;
+}
+
+InputTree& InputTree::insert(InputTree::iterator pPosition,
+ const InputTree::Connector& pConnector,
+ const std::string& pNamespec,
+ const sys::fs::Path& pPath,
+ unsigned int pType)
+{
+ BinaryTree<Input>::node_type* node = createNode();
+ node->data = m_FileFactory.produce(pNamespec, pPath, pType);
+ pConnector.connect(pPosition, iterator(node));
+ return *this;
+}
+
+InputTree& InputTree::enterGroup(InputTree::iterator pPosition,
+ const InputTree::Connector& pConnector)
+{
+ NodeBase* node = createNode();
+ pConnector.connect(pPosition, iterator(node));
+ return *this;
+}
+
+InputTree& InputTree::insert(InputTree::iterator pPosition,
+ const InputTree::Connector& pConnector,
+ const mcld::Input& pInput)
+{
+ BinaryTree<Input>::node_type* node = createNode();
+ node->data = const_cast<mcld::Input*>(&pInput);
+ pConnector.connect(pPosition, iterator(node));
+ return *this;
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// non-member functions
+bool mcld::isGroup(const InputTree::iterator& pos)
+{
+ return !pos.hasData();
+}
+
+bool mcld::isGroup(const InputTree::const_iterator& pos)
+{
+ return !pos.hasData();
+}
+
+bool mcld::isGroup(const InputTree::dfs_iterator& pos)
+{
+ return !pos.hasData();
+}
+
+bool mcld::isGroup(const InputTree::const_dfs_iterator& pos)
+{
+ return !pos.hasData();
+}
+
+bool mcld::isGroup(const InputTree::bfs_iterator& pos)
+{
+ return !pos.hasData();
+}
+
+bool mcld::isGroup(const InputTree::const_bfs_iterator& pos)
+{
+ return !pos.hasData();
+}
+
diff --git a/lib/MC/MCLDOptions.cpp b/lib/MC/MCLDOptions.cpp
new file mode 100644
index 0000000..ae07f26
--- /dev/null
+++ b/lib/MC/MCLDOptions.cpp
@@ -0,0 +1,34 @@
+//===- MCLDOptions.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDOptions.h"
+#include "mcld/MC/MCLDInput.h"
+
+using namespace mcld;
+
+//==========================
+// MCLDOptions
+bool GeneralOptions::hasDefaultLDScript() const
+{
+ return true;
+}
+
+const char* GeneralOptions::defaultLDScript() const
+{
+ return NULL;
+}
+
+void GeneralOptions::setDefaultLDScript(const std::string& pFilename)
+{
+}
+
+void GeneralOptions::setSysroot(const mcld::sys::fs::Path &pSysroot)
+{
+ m_Sysroot.assign(pSysroot);
+}
+
diff --git a/lib/MC/MCLDOutput.cpp b/lib/MC/MCLDOutput.cpp
new file mode 100644
index 0000000..c27ee01
--- /dev/null
+++ b/lib/MC/MCLDOutput.cpp
@@ -0,0 +1,27 @@
+//===- MCLDOutput.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDOutput.h"
+
+using namespace mcld;
+
+//==========================
+// MCLDOutput
+Output::Output()
+ : MCLDFile("") {
+}
+
+Output::Output(const sys::fs::Path& pRealPath,
+ Output::Type pType)
+ : MCLDFile("", pRealPath, pType) {
+}
+
+Output::~Output()
+{
+}
+
diff --git a/lib/MC/MCLinker.cpp b/lib/MC/MCLinker.cpp
new file mode 100644
index 0000000..e5327e8
--- /dev/null
+++ b/lib/MC/MCLinker.cpp
@@ -0,0 +1,644 @@
+//===- MCLinker.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MCLinker class
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Resolver.h>
+#include <mcld/LD/LDContext.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/LDSectionFactory.h>
+#include <mcld/LD/SectionMap.h>
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <llvm/Support/Host.h>
+#include <llvm/Support/raw_ostream.h>
+
+using namespace mcld;
+
+/// Constructor
+MCLinker::MCLinker(TargetLDBackend& pBackend,
+ MCLDInfo& pInfo,
+ LDContext& pContext,
+ SectionMap& pSectionMap,
+ const Resolver& pResolver)
+: m_Backend(pBackend),
+ m_Info(pInfo),
+ m_Output(pContext),
+ m_SectionMap(pSectionMap),
+ m_LDSymbolFactory(128),
+ m_LDSectHdrFactory(10), // the average number of sections. (assuming 10.)
+ m_LDSectDataFactory(10),
+ m_SectionMerger(pSectionMap, pContext),
+ m_StrSymPool(pResolver, 128)
+{
+ m_Info.setNamePool(m_StrSymPool);
+}
+
+/// Destructor
+MCLinker::~MCLinker()
+{
+}
+
+/// addSymbolFromObject - add a symbol from object file and resolve it
+/// immediately
+LDSymbol* MCLinker::addSymbolFromObject(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+
+ // resolved_result is a triple <resolved_info, existent, override>
+ Resolver::Result resolved_result;
+ ResolveInfo old_info; // used for arrange output symbols
+
+ if (pBinding == ResolveInfo::Local) {
+ // if the symbol is a local symbol, create a LDSymbol for input, but do not
+ // resolve them.
+ resolved_result.info = m_StrSymPool.createSymbol(pName,
+ false,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pVisibility);
+
+ // No matter if there is a symbol with the same name, insert the symbol
+ // into output symbol table. So, we let the existent false.
+ resolved_result.existent = false;
+ resolved_result.overriden = true;
+ }
+ else {
+ // if the symbol is not local, insert and resolve it immediately
+ m_StrSymPool.insertSymbol(pName, false, pType, pDesc, pBinding, pSize,
+ pVisibility, &old_info, resolved_result);
+ }
+
+ // the return ResolveInfo should not NULL
+ assert(NULL != resolved_result.info);
+
+ // create a LDSymbol for the input file.
+ LDSymbol* input_sym = m_LDSymbolFactory.allocate();
+ new (input_sym) LDSymbol();
+
+ // set the relation between input LDSymbol and its ResolveInfo
+ input_sym->setResolveInfo(*resolved_result.info);
+
+ // set up input LDSymbol
+ input_sym->setFragmentRef(pFragmentRef);
+ input_sym->setValue(pValue);
+
+ LDSymbol* output_sym = resolved_result.info->outSymbol();
+ bool has_output_sym = (NULL != output_sym);
+ if (!resolved_result.existent || !has_output_sym) {
+ // it is a new symbol, the output_sym should be NULL.
+ assert(NULL == output_sym);
+
+ // if it is a new symbol, create a LDSymbol for the output
+ output_sym = m_LDSymbolFactory.allocate();
+ new (output_sym) LDSymbol();
+
+ // set up the relation between output LDSymbol and its ResolveInfo
+ output_sym->setResolveInfo(*resolved_result.info);
+ resolved_result.info->setSymPtr(output_sym);
+ }
+
+ if (resolved_result.overriden || !has_output_sym) {
+ // symbol can be overriden only if it exists.
+ assert(output_sym != NULL);
+
+ // should override output LDSymbol
+ output_sym->setFragmentRef(pFragmentRef);
+ output_sym->setValue(pValue);
+ }
+
+ // After symbol resolution, visibility is changed to the most restrict one.
+ // we need to arrange its position in the output symbol .
+ if (pType != ResolveInfo::Section) {
+ if (!has_output_sym) {
+ // We merge sections when reading them. So we do not need to output symbols
+ // with section type
+
+ // No matter the symbol is already in the output or not, add it if it
+ // should be forcefully set local.
+ if (shouldForceLocal(*resolved_result.info))
+ m_OutputSymbols.forceLocal(*output_sym);
+ else {
+ // the symbol should not be forcefully local.
+ m_OutputSymbols.add(*output_sym);
+ }
+ }
+ else if (resolved_result.overriden) {
+ if (!shouldForceLocal(old_info) ||
+ !shouldForceLocal(*resolved_result.info)) {
+ // If the old info and the new info are both forcefully local, then
+ // we should keep the output_sym in forcefully local category. Else,
+ // we should re-sort the output_sym
+ m_OutputSymbols.arrange(*output_sym, old_info);
+ }
+ }
+ }
+
+ return input_sym;
+}
+
+/// addSymbolFromDynObj - add a symbol from object file and resolve it
+/// immediately
+LDSymbol* MCLinker::addSymbolFromDynObj(const llvm::StringRef& pName,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ // We merge sections when reading them. So we do not need symbols with
+ // section type
+ if (pType == ResolveInfo::Section)
+ return NULL;
+
+ // ignore symbols with local binding or that have internal or hidden
+ // visibility
+ if (pBinding == ResolveInfo::Local ||
+ pVisibility == ResolveInfo::Internal ||
+ pVisibility == ResolveInfo::Hidden)
+ return NULL;
+
+ // A protected symbol in a shared library must be treated as a
+ // normal symbol when viewed from outside the shared library.
+ if (pVisibility == ResolveInfo::Protected)
+ pVisibility = ResolveInfo::Default;
+
+ // insert symbol and resolve it immediately
+ // resolved_result is a triple <resolved_info, existent, override>
+ Resolver::Result resolved_result;
+ m_StrSymPool.insertSymbol(pName, true, pType, pDesc, pBinding, pSize, pVisibility,
+ NULL, resolved_result);
+
+ // the return ResolveInfo should not NULL
+ assert(NULL != resolved_result.info);
+
+ // create a LDSymbol for the input file.
+ LDSymbol* input_sym = m_LDSymbolFactory.allocate();
+ new (input_sym) LDSymbol();
+
+ // set up the relation between input LDSymbol and its ResolveInfo
+ input_sym->setResolveInfo(*resolved_result.info);
+
+ // set up input LDSymbol
+ input_sym->setFragmentRef(pFragmentRef);
+ input_sym->setValue(pValue);
+
+ LDSymbol* output_sym = NULL;
+ if (!resolved_result.existent) {
+ // we get a new symbol, leave it as NULL
+ resolved_result.info->setSymPtr(NULL);
+ }
+ else {
+ // we saw the symbol before, but the output_sym still may be NULL.
+ output_sym = resolved_result.info->outSymbol();
+ }
+
+ if (output_sym != NULL) {
+ // After symbol resolution, visibility is changed to the most restrict one.
+ // If we are not doing incremental linking, then any symbol with hidden
+ // or internal visibility is forcefully set as a local symbol.
+ if (shouldForceLocal(*resolved_result.info)) {
+ m_OutputSymbols.forceLocal(*output_sym);
+ }
+ }
+
+ return input_sym;
+}
+
+/// defineSymbolForcefully - define an output symbol and override it immediately
+LDSymbol* MCLinker::defineSymbolForcefully(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ ResolveInfo* info = m_StrSymPool.findInfo(pName);
+ LDSymbol* output_sym = NULL;
+ if (NULL == info) {
+ // the symbol is not in the pool, create a new one.
+ // create a ResolveInfo
+ Resolver::Result result;
+ m_StrSymPool.insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, pSize, pVisibility,
+ NULL, result);
+ assert(!result.existent);
+
+ // create a output LDSymbol
+ output_sym = m_LDSymbolFactory.allocate();
+ new (output_sym) LDSymbol();
+
+ output_sym->setResolveInfo(*result.info);
+ result.info->setSymPtr(output_sym);
+
+ if (shouldForceLocal(*result.info))
+ m_OutputSymbols.forceLocal(*output_sym);
+ else
+ m_OutputSymbols.add(*output_sym);
+ }
+ else {
+ // the symbol is already in the pool, override it
+ ResolveInfo old_info;
+ old_info.override(*info);
+
+ info->setSource(pIsDyn);
+ info->setType(pType);
+ info->setDesc(pDesc);
+ info->setBinding(pBinding);
+ info->setVisibility(pVisibility);
+ info->setIsSymbol(true);
+ info->setSize(pSize);
+
+ output_sym = info->outSymbol();
+ if (NULL != output_sym)
+ m_OutputSymbols.arrange(*output_sym, old_info);
+ else {
+ // create a output LDSymbol
+ output_sym = m_LDSymbolFactory.allocate();
+ new (output_sym) LDSymbol();
+
+ output_sym->setResolveInfo(*info);
+ info->setSymPtr(output_sym);
+
+ m_OutputSymbols.add(*output_sym);
+ }
+ }
+
+ if (NULL != output_sym) {
+ output_sym->setFragmentRef(pFragmentRef);
+ output_sym->setValue(pValue);
+ }
+
+ return output_sym;
+}
+
+/// defineSymbolAsRefered - define an output symbol and override it immediately
+LDSymbol* MCLinker::defineSymbolAsRefered(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ ResolveInfo* info = m_StrSymPool.findInfo(pName);
+
+ if (NULL == info || !info->isUndef()) {
+ // only undefined symbol can make a reference.
+ return NULL;
+ }
+
+ // the symbol is already in the pool, override it
+ ResolveInfo old_info;
+ old_info.override(*info);
+
+ info->setSource(pIsDyn);
+ info->setType(pType);
+ info->setDesc(pDesc);
+ info->setBinding(pBinding);
+ info->setVisibility(pVisibility);
+ info->setIsSymbol(true);
+ info->setSize(pSize);
+
+ LDSymbol* output_sym = info->outSymbol();
+ if (NULL != output_sym) {
+ output_sym->setFragmentRef(pFragmentRef);
+ output_sym->setValue(pValue);
+ m_OutputSymbols.arrange(*output_sym, old_info);
+ }
+ else {
+ // create a output LDSymbol
+ output_sym = m_LDSymbolFactory.allocate();
+ new (output_sym) LDSymbol();
+
+ output_sym->setResolveInfo(*info);
+ info->setSymPtr(output_sym);
+
+ m_OutputSymbols.add(*output_sym);
+ }
+
+ return output_sym;
+}
+
+/// defineAndResolveSymbolForcefully - define an output symbol and resolve it
+/// immediately
+LDSymbol* MCLinker::defineAndResolveSymbolForcefully(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ // Result is <info, existent, override>
+ Resolver::Result result;
+ ResolveInfo old_info;
+ m_StrSymPool.insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, pSize, pVisibility,
+ &old_info, result);
+
+ LDSymbol* output_sym = result.info->outSymbol();
+ bool has_output_sym = (NULL != output_sym);
+
+ if (!result.existent || !has_output_sym) {
+ output_sym = m_LDSymbolFactory.allocate();
+ new (output_sym) LDSymbol();
+ output_sym->setResolveInfo(*result.info);
+ result.info->setSymPtr(output_sym);
+ }
+
+ if (result.overriden || !has_output_sym) {
+ output_sym->setFragmentRef(pFragmentRef);
+ output_sym->setValue(pValue);
+ }
+
+ // After symbol resolution, the visibility is changed to the most restrict.
+ // arrange the output position
+ if (shouldForceLocal(*result.info))
+ m_OutputSymbols.forceLocal(*output_sym);
+ else if (has_output_sym)
+ m_OutputSymbols.arrange(*output_sym, old_info);
+ else
+ m_OutputSymbols.add(*output_sym);
+
+ return output_sym;
+}
+
+/// defineAndResolveSymbolAsRefered - define an output symbol and resolve it
+/// immediately.
+LDSymbol* MCLinker::defineAndResolveSymbolAsRefered(const llvm::StringRef& pName,
+ bool pIsDyn,
+ ResolveInfo::Type pType,
+ ResolveInfo::Desc pDesc,
+ ResolveInfo::Binding pBinding,
+ ResolveInfo::SizeType pSize,
+ LDSymbol::ValueType pValue,
+ MCFragmentRef* pFragmentRef,
+ ResolveInfo::Visibility pVisibility)
+{
+ ResolveInfo* info = m_StrSymPool.findInfo(pName);
+
+ if (NULL == info || !info->isUndef()) {
+ // only undefined symbol can make a reference
+ return NULL;
+ }
+
+ return defineAndResolveSymbolForcefully(pName,
+ pIsDyn,
+ pType,
+ pDesc,
+ pBinding,
+ pSize,
+ pValue,
+ pFragmentRef,
+ pVisibility);
+}
+
+/// createSectHdr - create the input section header
+LDSection& MCLinker::createSectHdr(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag)
+{
+ // for user such as reader, standard/target fromat
+ LDSection* result =
+ m_LDSectHdrFactory.produce(pName, pKind, pType, pFlag);
+
+ // check if we need to create a output section for output LDContext
+ std::string sect_name = m_SectionMap.getOutputSectName(pName);
+ LDSection* output_sect = m_Output.getSection(sect_name);
+
+ if (NULL == output_sect) {
+ // create a output section and push it into output LDContext
+ output_sect =
+ m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
+ m_Output.getSectionTable().push_back(output_sect);
+ m_SectionMerger.addMapping(pName, output_sect);
+ }
+ return *result;
+}
+
+/// getOrCreateOutputSectHdr - for reader and standard/target format to get
+/// or create the output's section header
+LDSection& MCLinker::getOrCreateOutputSectHdr(const std::string& pName,
+ LDFileFormat::Kind pKind,
+ uint32_t pType,
+ uint32_t pFlag,
+ uint32_t pAlign)
+{
+ // check if we need to create a output section for output LDContext
+ std::string sect_name = m_SectionMap.getOutputSectName(pName);
+ LDSection* output_sect = m_Output.getSection(sect_name);
+
+ if (NULL == output_sect) {
+ // create a output section and push it into output LDContext
+ output_sect =
+ m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
+ output_sect->setAlign(pAlign);
+ m_Output.getSectionTable().push_back(output_sect);
+ m_SectionMerger.addMapping(pName, output_sect);
+ }
+ return *output_sect;
+}
+
+/// getOrCreateSectData - get or create MCSectionData
+/// pSection is input LDSection
+llvm::MCSectionData& MCLinker::getOrCreateSectData(LDSection& pSection)
+{
+ // if there is already a section data pointed by section, return it.
+ llvm::MCSectionData* sect_data = pSection.getSectionData();
+ if (NULL != sect_data) {
+ m_Layout.addInputRange(*sect_data, pSection);
+ return *sect_data;
+ }
+
+ // try to get one from output LDSection
+ LDSection* output_sect =
+ m_SectionMerger.getOutputSectHdr(pSection.name());
+
+ assert(NULL != output_sect);
+
+ sect_data = output_sect->getSectionData();
+
+ if (NULL != sect_data) {
+ pSection.setSectionData(sect_data);
+ m_Layout.addInputRange(*sect_data, pSection);
+ return *sect_data;
+ }
+
+ // if the output LDSection also has no MCSectionData, then create one.
+ sect_data = m_LDSectDataFactory.allocate();
+ new (sect_data) llvm::MCSectionData(*output_sect);
+ pSection.setSectionData(sect_data);
+ output_sect->setSectionData(sect_data);
+ m_Layout.addInputRange(*sect_data, pSection);
+ return *sect_data;
+}
+
+/// addRelocation - add a relocation entry in MCLinker (only for object file)
+///
+/// All symbols should be read and resolved before calling this function.
+Relocation* MCLinker::addRelocation(Relocation::Type pType,
+ const LDSymbol& pSym,
+ ResolveInfo& pResolveInfo,
+ MCFragmentRef& pFragmentRef,
+ Relocation::Address pAddend)
+{
+ Relocation* relocation = m_Backend.getRelocFactory()->produce(pType,
+ pFragmentRef,
+ pAddend);
+
+ relocation->setSymInfo(&pResolveInfo);
+
+ m_RelocationList.push_back(relocation);
+
+ m_Backend.scanRelocation(*relocation, pSym, *this, m_Info,
+ m_Info.output());
+
+ return relocation;
+}
+
+bool MCLinker::applyRelocations()
+{
+ RelocationListType::iterator relocIter, relocEnd = m_RelocationList.end();
+
+ for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) {
+ llvm::MCFragment* frag = (llvm::MCFragment*)relocIter;
+ static_cast<Relocation*>(frag)->apply(*m_Backend.getRelocFactory(), m_Info);
+ }
+ return true;
+}
+
+void MCLinker::syncRelocationResult()
+{
+
+ m_Info.output().memArea()->clean();
+ MemoryRegion* region = m_Info.output().memArea()->request(0,
+ m_Info.output().memArea()->size());
+
+ uint8_t* data = region->getBuffer();
+
+ RelocationListType::iterator relocIter, relocEnd = m_RelocationList.end();
+ for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) {
+
+ llvm::MCFragment* frag = (llvm::MCFragment*)relocIter;
+ Relocation* reloc = static_cast<Relocation*>(frag);
+
+ // get output file offset
+ size_t out_offset = m_Layout.getOutputLDSection(*reloc->targetRef().frag())->offset() +
+ m_Layout.getOutputOffset(reloc->targetRef());
+
+ uint8_t* target_addr = data + out_offset;
+ // byte swapping if target and host has different endian, and then write back
+ if(llvm::sys::isLittleEndianHost() != m_Backend.isLittleEndian()) {
+ uint64_t tmp_data = 0;
+
+ switch(m_Backend.bitclass()) {
+ case 32u:
+ tmp_data = bswap32(reloc->target());
+ std::memcpy(target_addr, &tmp_data, 4);
+ break;
+
+ case 64u:
+ tmp_data = bswap64(reloc->target());
+ std::memcpy(target_addr, &tmp_data, 8);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ std::memcpy(target_addr, &reloc->target(), m_Backend.bitclass()/8);
+ }
+ } // end of for
+
+ m_Info.output().memArea()->sync();
+}
+
+
+bool MCLinker::layout()
+{
+ return m_Layout.layout(m_Info.output(), m_Backend);
+}
+
+bool MCLinker::finalizeSymbols()
+{
+ SymbolCategory::iterator symbol, symEnd = m_OutputSymbols.end();
+ for (symbol = m_OutputSymbols.begin(); symbol != symEnd; ++symbol) {
+
+ if (0x0 != (*symbol)->resolveInfo()->reserved()) {
+ // if the symbol is target reserved, target backend is responsible
+ // for finalizing the value.
+ // if target backend does not know this symbol, it will return false
+ // and we have to take over the symbol.
+ if (m_Backend.finalizeSymbol(**symbol))
+ continue;
+ }
+
+ if ((*symbol)->resolveInfo()->isAbsolute() ||
+ (*symbol)->resolveInfo()->type() == ResolveInfo::File) {
+ // absolute symbols and symbols with function type should have
+ // zero value
+ (*symbol)->setValue(0x0);
+ continue;
+ }
+
+ if ((*symbol)->hasFragRef()) {
+ // set the virtual address of the symbol. If the output file is
+ // relocatable object file, the section's virtual address becomes zero.
+ // And the symbol's value become section relative offset.
+ uint64_t value = getLayout().getOutputOffset(*(*symbol)->fragRef());
+ assert(NULL != (*symbol)->fragRef()->frag());
+ uint64_t addr = getLayout().getOutputLDSection(*(*symbol)->fragRef()->frag())->addr();
+ (*symbol)->setValue(value + addr);
+ continue;
+ }
+ }
+
+ return true;
+}
+
+bool MCLinker::shouldForceLocal(const ResolveInfo& pInfo) const
+{
+ // forced local symbol matches all rules:
+ // 1. We are not doing incremental linking.
+ // 2. The symbol is with Hidden or Internal visibility.
+ // 3. The symbol should be global or weak. Otherwise, local symbol is local.
+ // 4. The symbol is defined or common
+ if (m_Info.output().type() != Output::Object &&
+ (pInfo.visibility() == ResolveInfo::Hidden ||
+ pInfo.visibility() == ResolveInfo::Internal) &&
+ (pInfo.isGlobal() || pInfo.isWeak()) &&
+ (pInfo.isDefine() || pInfo.isCommon()))
+ return true;
+ return false;
+}
+
diff --git a/lib/MC/MCRegionFragment.cpp b/lib/MC/MCRegionFragment.cpp
new file mode 100644
index 0000000..59b109a
--- /dev/null
+++ b/lib/MC/MCRegionFragment.cpp
@@ -0,0 +1,24 @@
+//===- MCRegionFragment.cpp - MCRegionFragment implementation -------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mcld/MC/MCRegionFragment.h"
+
+using namespace mcld;
+using namespace llvm;
+
+//==========================
+// MCRegionFragment
+MCRegionFragment::MCRegionFragment(MemoryRegion& pRegion, MCSectionData* pSD)
+ : MCFragment((llvm::MCFragment::FragmentType)FT_Region, pSD), m_Region(pRegion) {
+}
+
+MCRegionFragment::~MCRegionFragment()
+{
+}
+
diff --git a/lib/MC/README b/lib/MC/README
new file mode 100644
index 0000000..f020b50
--- /dev/null
+++ b/lib/MC/README
@@ -0,0 +1,8 @@
+MCLDStreamer is similar to MCObjectStreamer
+MCLinker is similar to MCAssembler
+MCLDWriter is similar to MCObjectWriter
+
+MCELFObjectReader parses ELF object files
+to MCInst classes
+
+
diff --git a/lib/MC/SearchDirs.cpp b/lib/MC/SearchDirs.cpp
new file mode 100644
index 0000000..0d21e46
--- /dev/null
+++ b/lib/MC/SearchDirs.cpp
@@ -0,0 +1,92 @@
+//===- SearchDirs.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/ADT/Twine.h>
+
+#include "mcld/MC/SearchDirs.h"
+#include "mcld/Support/FileSystem.h"
+#include "mcld/MC/MCLDDirectory.h"
+
+using namespace mcld;
+
+//==========================
+// Non-member functions
+static void SpecToFilename(const std::string& pSpec, std::string& pFile)
+{
+ pFile = "lib";
+ pFile += pSpec;
+}
+
+//==========================
+// SearchDirs
+SearchDirs::SearchDirs()
+{
+ // a magic number 8, no why.
+ // please prove it or change it
+ m_DirList.reserve(8);
+}
+
+SearchDirs::~SearchDirs()
+{
+ iterator dir, dirEnd = end();
+ for (dir = begin(); dir!=dirEnd; ++dir) {
+ delete (*dir);
+ }
+}
+
+void SearchDirs::add(const MCLDDirectory& pDirectory)
+{
+ m_DirList.push_back(new MCLDDirectory(pDirectory));
+}
+
+mcld::sys::fs::Path* SearchDirs::find(const std::string& pNamespec, mcld::Input::Type pType)
+{
+ std::string file;
+ SpecToFilename(pNamespec, file);
+ // for all MCLDDirectorys
+ DirList::iterator mcld_dir, mcld_dir_end = m_DirList.end();
+ for (mcld_dir=m_DirList.begin(); mcld_dir!=mcld_dir_end; ++mcld_dir) {
+ // for all entries in MCLDDirectory
+ MCLDDirectory::iterator entry = (*mcld_dir)->begin();
+ MCLDDirectory::iterator enEnd = (*mcld_dir)->end();
+
+ switch(pType) {
+ case Input::DynObj: {
+ while (entry!=enEnd) {
+ if (file == entry.path()->stem().native() ) {
+ if(mcld::sys::fs::detail::shared_library_extension == entry.path()->extension().native()) {
+ return entry.path();
+ }
+ }
+
+ ++entry;
+ }
+ }
+
+ case Input::Archive : {
+ entry = (*mcld_dir)->begin();
+ enEnd = (*mcld_dir)->end();
+ while ( entry!=enEnd ) {
+ if (file == entry.path()->stem().native() &&
+ mcld::sys::fs::detail::static_library_extension == entry.path()->extension().native()) {
+ return entry.path();
+ }
+ ++entry;
+ }
+ }
+ default: {
+ llvm::report_fatal_error(llvm::Twine("SearchDir can not recoginize namespec: `") +
+ pNamespec +
+ llvm::Twine("'."));
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/lib/MC/SymbolCategory.cpp b/lib/MC/SymbolCategory.cpp
new file mode 100644
index 0000000..4b5e0f7
--- /dev/null
+++ b/lib/MC/SymbolCategory.cpp
@@ -0,0 +1,337 @@
+//===- SymbolCategory.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/MC/SymbolCategory.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <algorithm>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Category
+SymbolCategory::Category::Type
+SymbolCategory::Category::categorize(const ResolveInfo& pInfo)
+{
+ if (ResolveInfo::File == pInfo.type())
+ return Category::File;
+ if (ResolveInfo::Local == pInfo.binding())
+ return Category::Local;
+ if (ResolveInfo::Common == pInfo.desc())
+ return Category::Common;
+ if (ResolveInfo::Weak == pInfo.binding())
+ return Category::Weak;
+ return Category::Global;
+}
+
+//===----------------------------------------------------------------------===//
+// SymbolCategory
+SymbolCategory::SymbolCategory()
+{
+ m_pFile = new Category(Category::File);
+ m_pLocal = new Category(Category::Local);
+ m_pCommon = new Category(Category::Common);
+ m_pWeak = new Category(Category::Weak);
+ m_pGlobal = new Category(Category::Global);
+
+ m_pFile->next = m_pLocal;
+ m_pLocal->next = m_pCommon;
+ m_pCommon->next = m_pWeak;
+ m_pWeak->next = m_pGlobal;
+
+ m_pGlobal->prev = m_pWeak;
+ m_pWeak->prev = m_pCommon;
+ m_pCommon->prev = m_pLocal;
+ m_pLocal->prev = m_pFile;
+}
+
+SymbolCategory::~SymbolCategory()
+{
+ Category* current = m_pFile;
+ while (NULL != current) {
+ Category* tmp = current;
+ current = current->next;
+ delete tmp;
+ }
+}
+
+SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol)
+{
+ m_OutputSymbols.push_back(&pSymbol);
+
+ assert(NULL != pSymbol.resolveInfo());
+ Category::Type target = Category::categorize(*pSymbol.resolveInfo());
+
+ Category* current = m_pGlobal;
+
+ // use non-stable bubble sort to arrange the order of symbols.
+ while (NULL != current) {
+ if (current->type == target) {
+ current->end++;
+ break;
+ }
+ else {
+ if (!current->empty()) {
+ std::swap(m_OutputSymbols[current->begin],
+ m_OutputSymbols[current->end]);
+ }
+ current->end++;
+ current->begin++;
+ current = current->prev;
+ }
+ }
+ return *this;
+}
+
+SymbolCategory& SymbolCategory::forceLocal(LDSymbol& pSymbol)
+{
+ m_OutputSymbols.insert(localEnd(), &pSymbol);
+ m_pLocal->end++;
+ m_pCommon->begin++;
+ m_pCommon->end++;
+ m_pWeak->begin++;
+ m_pWeak->end++;
+ m_pGlobal->begin++;
+ m_pGlobal->end++;
+
+ return *this;
+}
+
+SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, const ResolveInfo& pSourceInfo)
+{
+ assert(NULL != pSymbol.resolveInfo());
+ Category::Type source = Category::categorize(pSourceInfo);
+ Category::Type target = Category::categorize(*pSymbol.resolveInfo());
+
+ int distance = target - source;
+ if (0 == distance) {
+ // in the same category, do not need to re-arrange
+ return *this;
+ }
+
+ // source and target are not in the same category
+ // find the category of source
+ Category* current = m_pFile;
+ while(NULL != current) {
+ if (source == current->type)
+ break;
+ current = current->next;
+ }
+
+ assert(NULL != current);
+ assert(!current->empty());
+
+ // find the position of source
+ size_t pos = current->begin;
+ while (pos != current->end) {
+ if (m_OutputSymbols[pos] == &pSymbol)
+ break;
+ ++pos;
+ }
+
+ assert(current->end != pos);
+
+ // The distance is positive. It means we should bubble sort downward.
+ if (distance > 0) {
+ // downward
+ size_t rear;
+ do {
+ if (current->type == target) {
+ break;
+ }
+ else {
+ assert(!current->isLast() && "target category is wrong.");
+ rear = current->end - 1;
+ std::swap(m_OutputSymbols[pos], m_OutputSymbols[rear]);
+ pos = rear;
+ current->next->begin--;
+ current->end--;
+ }
+ current = current->next;
+ } while(NULL != current);
+
+ return *this;
+ } // downward
+
+ // The distance is negative. It means we should bubble sort upward.
+ if (distance < 0) {
+
+ // upward
+ do {
+ if (current->type == target) {
+ break;
+ }
+ else {
+ assert(!current->isFirst() && "target category is wrong.");
+ std::swap(m_OutputSymbols[current->begin], m_OutputSymbols[pos]);
+ pos = current->begin;
+ current->begin++;
+ current->prev->end++;
+ }
+ current = current->prev;
+ } while(NULL != current);
+
+ return *this;
+ } // upward
+ return *this;
+}
+
+SymbolCategory& SymbolCategory::changeCommonsToGlobal()
+{
+ if (emptyCommons())
+ return *this;
+
+ size_t com_rear = m_pCommon->end - 1;
+ size_t com_front = m_pCommon->begin;
+ size_t weak_rear = m_pWeak->end - 1;
+ size_t weak_size = m_pWeak->end - m_pWeak->begin;
+ for (size_t sym = com_rear; sym >= com_front; --sym) {
+ std::swap(m_OutputSymbols[weak_rear], m_OutputSymbols[sym]);
+ --weak_rear;
+ }
+
+ m_pWeak->begin = m_pCommon->begin;
+ m_pWeak->end = m_pCommon->begin + weak_size;
+ m_pGlobal->begin = m_pWeak->end;
+ m_pCommon->begin = m_pCommon->end = m_pWeak->begin;
+
+ return *this;
+}
+
+size_t SymbolCategory::numOfSymbols() const
+{
+ return m_OutputSymbols.size();
+}
+
+size_t SymbolCategory::numOfLocals() const
+{
+ return (m_pFile->size() + m_pLocal->size());
+}
+
+size_t SymbolCategory::numOfCommons() const
+{
+ return m_pCommon->size();
+}
+
+size_t SymbolCategory::numOfRegulars() const
+{
+ return (m_pWeak->size() + m_pGlobal->size());
+}
+
+bool SymbolCategory::empty() const
+{
+ return (emptyLocals() &&
+ emptyCommons() &&
+ emptyRegulars());
+}
+
+bool SymbolCategory::emptyLocals() const
+{
+ return (m_pFile->empty() && m_pLocal->empty());
+}
+
+bool SymbolCategory::emptyCommons() const
+{
+ return m_pCommon->empty();
+}
+
+bool SymbolCategory::emptyRegulars() const
+{
+ return (m_pWeak->empty() && m_pGlobal->empty());
+}
+
+SymbolCategory::iterator SymbolCategory::begin()
+{
+ return m_OutputSymbols.begin();
+}
+
+SymbolCategory::iterator SymbolCategory::end()
+{
+ return m_OutputSymbols.end();
+}
+
+SymbolCategory::const_iterator SymbolCategory::begin() const
+{
+ return m_OutputSymbols.begin();
+}
+
+SymbolCategory::const_iterator SymbolCategory::end() const
+{
+ return m_OutputSymbols.end();
+}
+
+SymbolCategory::iterator SymbolCategory::localBegin()
+{
+ return m_OutputSymbols.begin();
+}
+
+SymbolCategory::iterator SymbolCategory::localEnd()
+{
+ iterator iter = m_OutputSymbols.begin();
+ iter += m_pFile->size();
+ iter += m_pLocal->size();
+ return iter;
+}
+
+SymbolCategory::const_iterator SymbolCategory::localBegin() const
+{
+ return m_OutputSymbols.begin();
+}
+
+SymbolCategory::const_iterator SymbolCategory::localEnd() const
+{
+ const_iterator iter = m_OutputSymbols.begin();
+ iter += m_pFile->size();
+ iter += m_pLocal->size();
+ return iter;
+}
+
+SymbolCategory::iterator SymbolCategory::commonBegin()
+{
+ return localEnd();
+}
+
+SymbolCategory::iterator SymbolCategory::commonEnd()
+{
+ iterator iter = localEnd();
+ iter += m_pCommon->size();
+ return iter;
+}
+
+SymbolCategory::const_iterator SymbolCategory::commonBegin() const
+{
+ return localEnd();
+}
+
+SymbolCategory::const_iterator SymbolCategory::commonEnd() const
+{
+ const_iterator iter = localEnd();
+ iter += m_pCommon->size();
+ return iter;
+}
+
+SymbolCategory::iterator SymbolCategory::regularBegin()
+{
+ return commonEnd();
+}
+
+SymbolCategory::iterator SymbolCategory::regularEnd()
+{
+ return m_OutputSymbols.end();
+}
+
+SymbolCategory::const_iterator SymbolCategory::regularBegin() const
+{
+ return commonEnd();
+}
+
+SymbolCategory::const_iterator SymbolCategory::regularEnd() const
+{
+ return m_OutputSymbols.end();
+}
+
diff --git a/lib/Support/Android.mk b/lib/Support/Android.mk
new file mode 100644
index 0000000..952ba53
--- /dev/null
+++ b/lib/Support/Android.mk
@@ -0,0 +1,38 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_support_SRC_FILES := \
+ CommandLine.cpp \
+ Directory.cpp \
+ FileSystem.cpp \
+ LEB128.cpp \
+ MemoryArea.cpp \
+ MemoryAreaFactory.cpp \
+ MemoryRegion.cpp \
+ Path.cpp \
+ RealPath.cpp \
+ RegionFactory.cpp \
+ TargetRegistry.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_support_SRC_FILES)
+LOCAL_MODULE:= libmcldSupport
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_support_SRC_FILES)
+LOCAL_MODULE:= libmcldSupport
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
new file mode 100644
index 0000000..57b82df
--- /dev/null
+++ b/lib/Support/CommandLine.cpp
@@ -0,0 +1,84 @@
+//===- CommandLine.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/CommandLine.h"
+#include <llvm/ADT/StringRef.h>
+
+using namespace llvm;
+using namespace llvm::cl;
+
+//--------------------------------------------------
+// parser<mcld::sys::fs::Path>
+//
+bool parser<mcld::sys::fs::Path>::parse(llvm::cl::Option &O,
+ llvm::StringRef ArgName,
+ llvm::StringRef Arg,
+ mcld::sys::fs::Path &Val)
+{
+ Val.assign<llvm::StringRef::const_iterator>(Arg.begin(), Arg.end());
+ return false;
+}
+
+static const size_t MaxOptWidth = 8; // arbitrary spacing for printOptionDiff
+
+void parser<mcld::sys::fs::Path>::printOptionDiff(const llvm::cl::Option &O,
+ const mcld::sys::fs::Path &V,
+ parser<mcld::sys::fs::Path>::OptVal Default,
+ size_t GlobalWidth) const
+{
+ printOptionName(O, GlobalWidth);
+ outs() << "= " << V;
+ size_t VSize = V.native().size();
+ size_t NumSpaces = MaxOptWidth > VSize ? MaxOptWidth - VSize : 0;
+ outs().indent(NumSpaces) << " (default: ";
+ if (Default.hasValue())
+ outs() << Default.getValue().c_str();
+ else
+ outs() << "*no default*";
+ outs() << ")\n";
+}
+
+void parser<mcld::sys::fs::Path>::anchor()
+{
+ // do nothing
+}
+
+//--------------------------------------------------
+// parser<mcld::MCLDDirectory>
+//
+bool parser<mcld::MCLDDirectory>::parse(llvm::cl::Option &O,
+ llvm::StringRef ArgName,
+ llvm::StringRef Arg,
+ mcld::MCLDDirectory &Val)
+{
+ Val.assign(Arg);
+ return false;
+}
+
+void parser<mcld::MCLDDirectory>::printOptionDiff(const llvm::cl::Option &O,
+ const mcld::MCLDDirectory &V,
+ parser<mcld::MCLDDirectory>::OptVal Default,
+ size_t GlobalWidth) const
+{
+ printOptionName(O, GlobalWidth);
+ outs() << "= " << V.name();
+ size_t VSize = V.name().size();
+ size_t NumSpaces = MaxOptWidth > VSize ? MaxOptWidth - VSize : 0;
+ outs().indent(NumSpaces) << " (default: ";
+ if (Default.hasValue())
+ outs() << Default.getValue().name();
+ else
+ outs() << "*no default*";
+ outs() << ")\n";
+}
+
+void parser<mcld::MCLDDirectory>::anchor()
+{
+ // do nothing
+}
+
diff --git a/lib/Support/Directory.cpp b/lib/Support/Directory.cpp
new file mode 100644
index 0000000..211b42a
--- /dev/null
+++ b/lib/Support/Directory.cpp
@@ -0,0 +1,252 @@
+//===- Directory.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/Directory.h"
+#include "mcld/Support/FileSystem.h"
+
+using namespace mcld;
+using namespace mcld::sys::fs;
+
+namespace { // anonymous
+
+bool status_known(FileStatus f)
+{
+ return f.type() != StatusError;
+}
+
+bool is_symlink(FileStatus f)
+{
+ return f.type() == SymlinkFile;
+}
+
+} // namespace of anonymous
+
+//==========================
+// Directory
+Directory::Directory()
+ : m_Path(),
+ m_FileStatus(),
+ m_SymLinkStatus(),
+ m_Handler(NULL),
+ m_Cache(),
+ m_CacheFull(false) {
+}
+
+Directory::Directory(const Path& pPath,
+ FileStatus st,
+ FileStatus symlink_st)
+ : m_Path(pPath),
+ m_FileStatus(st),
+ m_SymLinkStatus(symlink_st),
+ m_Handler(NULL),
+ m_Cache(),
+ m_CacheFull(false) {
+ if (m_Path.native() == ".")
+ detail::get_pwd(m_Path.native());
+ m_Path.m_append_separator_if_needed();
+ mcld::sys::fs::detail::open_dir(*this);
+}
+
+Directory::Directory(const Directory& pCopy)
+ : m_Path(pCopy.m_Path),
+ m_FileStatus(pCopy.m_FileStatus),
+ m_SymLinkStatus(pCopy.m_SymLinkStatus),
+ m_Handler(NULL),
+ m_Cache(),
+ m_CacheFull(false) {
+ mcld::sys::fs::detail::open_dir(*this);
+}
+
+Directory::~Directory()
+{
+ detail::close_dir(*this);
+}
+
+bool Directory::isGood() const
+{
+ return (0 != m_Handler);
+}
+
+Directory& Directory::operator=(const Directory& pCopy)
+{
+ assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus);
+ return *this;
+}
+
+void Directory::assign(const Path& pPath,
+ FileStatus st,
+ FileStatus symlink_st)
+{
+ if (isGood())
+ clear();
+
+ m_Path = pPath;
+ if (m_Path.native() == ".")
+ detail::get_pwd(m_Path.native());
+ m_Path.m_append_separator_if_needed();
+
+ m_FileStatus = st;
+ m_SymLinkStatus = symlink_st;
+ detail::open_dir(*this);
+}
+
+FileStatus Directory::status() const
+{
+ if (!status_known(m_FileStatus))
+ {
+ // optimization: if the symlink status is known, and it isn't a symlink,
+ // then status and symlink_status are identical so just copy the
+ // symlink status to the regular status.
+ if (status_known(m_SymLinkStatus)
+ && !is_symlink(m_SymLinkStatus))
+ {
+ m_FileStatus = m_SymLinkStatus;
+ }
+ else detail::status(m_Path,m_FileStatus);
+ }
+ return m_FileStatus;
+
+}
+
+FileStatus Directory::symlinkStatus() const
+{
+ if (!status_known(m_SymLinkStatus))
+ detail::symlink_status(m_Path,m_SymLinkStatus);
+ return m_SymLinkStatus;
+}
+
+Directory::iterator Directory::begin()
+{
+ if (m_CacheFull && m_Cache.empty())
+ return end();
+ PathCache::iterator iter = m_Cache.begin();
+ if (NULL == iter.getEntry())
+ ++iter;
+ return iterator(this, iter);
+}
+
+Directory::iterator Directory::end()
+{
+ return iterator(0, m_Cache.end());
+}
+
+void Directory::clear()
+{
+ m_Path.native().clear();
+ m_FileStatus = FileStatus();
+ m_SymLinkStatus = FileStatus();
+ m_Cache.clear();
+ detail::close_dir(*this);
+}
+
+//==========================
+// DirIterator
+DirIterator::DirIterator(Directory* pParent,
+ const DirIterator::DirCache::iterator& pIter)
+ : m_pParent(pParent),
+ m_Iter(pIter) {
+ m_pEntry = m_Iter.getEntry();
+}
+
+DirIterator::DirIterator(const DirIterator& pCopy)
+ : m_pParent(pCopy.m_pParent),
+ m_Iter(pCopy.m_Iter),
+ m_pEntry(pCopy.m_pEntry) {
+}
+
+DirIterator::~DirIterator()
+{
+}
+
+Path* DirIterator::path()
+{
+ if (m_pParent == 0) // end
+ return 0;
+ return m_pEntry->value();
+}
+
+const Path* DirIterator::path() const
+{
+ if (m_pParent == 0) // end
+ return 0;
+ return m_pEntry->value();
+}
+
+DirIterator& DirIterator::operator=(const DirIterator& pCopy)
+{
+ m_pParent = pCopy.m_pParent;
+ m_Iter = pCopy.m_Iter;
+ m_pEntry = pCopy.m_pEntry;
+ return (*this);
+}
+
+DirIterator& DirIterator::operator++()
+{
+ if (0 == m_pParent)
+ return *this;
+
+ // move forward one step first.
+ ++m_Iter;
+
+ if (m_pParent->m_Cache.end() == m_Iter) {
+ if (!m_pParent->m_CacheFull) {
+ m_pEntry = detail::bring_one_into_cache(*this);
+ if (0 == m_pEntry && m_pParent->m_CacheFull)
+ m_pParent = 0;
+ return *this;
+ }
+ m_pParent = 0;
+ return *this;
+ }
+
+ m_pEntry = m_Iter.getEntry();
+ return *this;
+}
+
+DirIterator DirIterator::operator++(int)
+{
+ DirIterator tmp(*this);
+
+ // move forward one step first.
+ ++m_Iter;
+
+ if (m_pParent->m_Cache.end() == m_Iter) {
+ if (!m_pParent->m_CacheFull) {
+ m_pEntry = detail::bring_one_into_cache(*this);
+ if (0 == m_pEntry && m_pParent->m_CacheFull)
+ m_pParent = 0;
+ return tmp;
+ }
+ m_pParent = 0;
+ return tmp;
+ }
+
+ m_pEntry = m_Iter.getEntry();
+ return tmp;
+}
+
+bool DirIterator::operator==(const DirIterator& y) const
+{
+ if (m_pParent != y.m_pParent)
+ return false;
+ if (0 == m_pParent)
+ return true;
+ const Path* x_path = path();
+ const Path* y_path = y.path();
+ if (0 == x_path && 0 == y_path)
+ return true;
+ if (0 == x_path || 0 == y_path)
+ return false;
+ return (*x_path == *y_path);
+}
+
+bool DirIterator::operator!=(const DirIterator& y) const
+{
+ return !this->operator==(y);
+}
+
diff --git a/lib/Support/FileSystem.cpp b/lib/Support/FileSystem.cpp
new file mode 100644
index 0000000..d3366c0
--- /dev/null
+++ b/lib/Support/FileSystem.cpp
@@ -0,0 +1,33 @@
+//===- FileSystem.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/Path.h"
+
+#if defined(ANDROID)
+#include <llvm/Config/config.h>
+#endif
+
+using namespace mcld::sys::fs;
+
+
+//===--------------------------------------------------------------------===//
+// SearchDirs
+
+//===--------------------------------------------------------------------===//
+// non-member functions
+
+// Include the truly platform-specific parts.
+#if defined(LLVM_ON_UNIX)
+#include "Unix/FileSystem.inc"
+#include "Unix/PathV3.inc"
+#endif
+#if defined(LLVM_ON_WIN32)
+#include "Windows/FileSystem.inc"
+#include "Windows/PathV3.inc"
+#endif
diff --git a/lib/Support/LEB128.cpp b/lib/Support/LEB128.cpp
new file mode 100644
index 0000000..02d7f24
--- /dev/null
+++ b/lib/Support/LEB128.cpp
@@ -0,0 +1,228 @@
+//===- LEB128.cpp ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/LEB128.h>
+
+namespace mcld {
+
+namespace leb128 {
+
+//===---------------------- LEB128 Encoding APIs -------------------------===//
+template<>
+size_t encode<uint64_t>(ByteType *&pBuf, uint64_t pValue) {
+ size_t size = 0;
+ do {
+ ByteType byte = pValue & 0x7f;
+ pValue >>= 7;
+ if (pValue)
+ byte |= 0x80;
+ *pBuf++ = byte;
+ size++;
+ } while (pValue);
+
+ return size;
+}
+
+/*
+ * Fast version for encoding 32-bit integer. This unrolls the loop in the
+ * generic version defined above.
+ */
+template<>
+size_t encode<uint32_t>(ByteType *&pBuf, uint32_t pValue) {
+ if ((pValue & ~0x7f) == 0) {
+ *pBuf++ = static_cast<ByteType>(pValue);
+ return 1;
+ } else if ((pValue & ~0x3fff) == 0){
+ *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>((pValue >> 7) & 0x7f);
+ return 2;
+ } else if ((pValue & ~0x1fffff) == 0) {
+ *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>((pValue >> 14) & 0x7f);
+ return 3;
+ } else if ((pValue & ~0xfffffff) == 0) {
+ *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>(((pValue >> 14) & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>((pValue >> 21) & 0x7f);
+ return 4;
+ } else {
+ *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>(((pValue >> 14) & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>(((pValue >> 21) & 0x7f) | 0x80);
+ *pBuf++ = static_cast<ByteType>((pValue >> 28) & 0x7f);
+ return 5;
+ }
+ // unreachable
+}
+
+template<>
+size_t encode<int64_t>(ByteType *&pBuf, int64_t pValue) {
+ size_t size = 0;
+ bool more = true;
+
+ do {
+ ByteType byte = pValue & 0x7f;
+ pValue >>= 7;
+
+ if (((pValue == 0) && ((byte & 0x40) == 0)) ||
+ ((pValue == -1) && ((byte & 0x40) == 0x40)))
+ more = false;
+ else
+ byte |= 0x80;
+
+ *pBuf++ = byte;
+ size++;
+ } while (more);
+
+ return size;
+}
+
+template<>
+size_t encode<int32_t>(ByteType *&pBuf, int32_t pValue) {
+ return encode<int64_t>(pBuf, static_cast<int64_t>(pValue));
+}
+
+//===---------------------- LEB128 Decoding APIs -------------------------===//
+
+template<>
+uint64_t decode<uint64_t>(const ByteType *pBuf, size_t &pSize) {
+ uint64_t result = 0;
+
+ if ((*pBuf & 0x80) == 0) {
+ pSize = 1;
+ return *pBuf;
+ } else if ((*(pBuf + 1) & 0x80) == 0) {
+ pSize = 2;
+ return ((*(pBuf + 1) & 0x7f) << 7) |
+ (*pBuf & 0x7f);
+ } else if ((*(pBuf + 2) & 0x80) == 0) {
+ pSize = 3;
+ return ((*(pBuf + 2) & 0x7f) << 14) |
+ ((*(pBuf + 1) & 0x7f) << 7) |
+ (*pBuf & 0x7f);
+ } else {
+ pSize = 4;
+ result = ((*(pBuf + 3) & 0x7f) << 21) |
+ ((*(pBuf + 2) & 0x7f) << 14) |
+ ((*(pBuf + 1) & 0x7f) << 7) |
+ (*pBuf & 0x7f);
+ }
+
+ if ((*(pBuf + 3) & 0x80) != 0) {
+ // Large number which is an unusual case.
+ unsigned shift;
+ ByteType byte;
+
+ // Start the read from the 4th byte.
+ shift = 28;
+ pBuf += 4;
+ do {
+ byte = *pBuf;
+ pBuf++;
+ pSize++;
+ result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
+ shift += 7;
+ } while (byte & 0x80);
+ }
+
+ return result;
+}
+
+template<>
+uint64_t decode<uint64_t>(const ByteType *&pBuf) {
+ ByteType byte;
+ uint64_t result;
+
+ byte = *pBuf++;
+ result = byte & 0x7f;
+ if ((byte & 0x80) == 0) {
+ return result;
+ } else {
+ byte = *pBuf++;
+ result |= ((byte & 0x7f) << 7);
+ if ((byte & 0x80) == 0) {
+ return result;
+ } else {
+ byte = *pBuf++;
+ result |= (byte & 0x7f) << 14;
+ if ((byte & 0x80) == 0) {
+ return result;
+ } else {
+ byte = *pBuf++;
+ result |= (byte & 0x7f) << 21;
+ if ((byte & 0x80) == 0) {
+ return result;
+ }
+ }
+ }
+ }
+
+ // Large number which is an unusual case.
+ unsigned shift;
+
+ // Start the read from the 4th byte.
+ shift = 28;
+ do {
+ byte = *pBuf++;
+ result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
+ shift += 7;
+ } while (byte & 0x80);
+
+ return result;
+}
+
+/*
+ * Signed LEB128 decoding is Similar to the unsigned version but setup the sign
+ * bit if necessary. This is rarely used, therefore we don't provide unrolling
+ * version like decode() to save the code size.
+ */
+template<>
+int64_t decode<int64_t>(const ByteType *pBuf, size_t &pSize) {
+ uint64_t result = 0;
+ ByteType byte;
+ unsigned shift = 0;
+
+ pSize = 0;
+ do {
+ byte = *pBuf;
+ pBuf++;
+ pSize++;
+ result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
+ shift += 7;
+ } while (byte & 0x80);
+
+ if ((shift < (8 * sizeof(result))) && (byte & 0x40))
+ result |= ((static_cast<uint64_t>(-1)) << shift);
+
+ return result;
+}
+
+template<>
+int64_t decode<int64_t>(const ByteType *&pBuf) {
+ uint64_t result = 0;
+ ByteType byte;
+ unsigned shift = 0;
+
+ do {
+ byte = *pBuf;
+ pBuf++;
+ result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
+ shift += 7;
+ } while (byte & 0x80);
+
+ if ((shift < (8 * sizeof(result))) && (byte & 0x40))
+ result |= ((static_cast<uint64_t>(-1)) << shift);
+
+ return result;
+}
+
+} // namespace of leb128
+} // namespace of mcld
diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp
new file mode 100644
index 0000000..f388e94
--- /dev/null
+++ b/lib/Support/MemoryArea.cpp
@@ -0,0 +1,426 @@
+//===- MemoryArea.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/ADT/Twine.h>
+
+#include <mcld/Support/RegionFactory.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/FileSystem.h>
+
+#include <cerrno>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+using namespace mcld;
+
+//===--------------------------------------------------------------------===//
+// MemoryArea
+MemoryArea::MemoryArea(RegionFactory& pRegionFactory)
+ : m_RegionFactory(pRegionFactory),
+ m_FileDescriptor(-1),
+ m_FileSize(0),
+ m_AccessFlags(ReadOnly),
+ m_State(BadBit) {
+}
+
+MemoryArea::~MemoryArea()
+{
+ // truncate the file to real size
+ if (isWritable())
+ truncate(m_FileSize);
+
+ unmap();
+}
+
+void MemoryArea::truncate(size_t pLength)
+{
+ if (!isWritable())
+ return;
+
+ if (-1 == ::ftruncate(m_FileDescriptor, static_cast<off_t>(pLength))) {
+ llvm::report_fatal_error(llvm::Twine("Cannot truncate `") +
+ m_FilePath.native() +
+ llvm::Twine("' to size: ") +
+ llvm::Twine(pLength) +
+ llvm::Twine(".\n"));
+ }
+}
+
+void MemoryArea::map(const sys::fs::Path& pPath, int pFlags)
+{
+ m_AccessFlags = pFlags;
+ m_FilePath = pPath;
+ m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags);
+
+ if (-1 == m_FileDescriptor) {
+ m_State |= FailBit;
+ }
+ else {
+ struct stat st;
+ int stat_result = ::stat(m_FilePath.native().c_str(), &st);
+ if (0x0 == stat_result) {
+ m_FileSize = static_cast<size_t>(st.st_size);
+ m_State = GoodBit;
+ }
+ else {
+ m_FileSize = 0x0;
+ m_State |= FailBit;
+ m_State |= BadBit;
+ }
+ }
+}
+
+void MemoryArea::map(const sys::fs::Path& pPath, int pFlags, int pMode)
+{
+ m_AccessFlags = pFlags;
+ m_FilePath = pPath;
+ m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags, pMode);
+
+ if (-1 == m_FileDescriptor) {
+ m_State |= FailBit;
+ }
+ else {
+ struct stat st;
+ int stat_result = ::stat(m_FilePath.native().c_str(), &st);
+ if (0x0 == stat_result) {
+ m_FileSize = static_cast<size_t>(st.st_size);
+ m_State = GoodBit;
+ }
+ else {
+ m_FileSize = 0x0;
+ m_State |= FailBit;
+ m_State |= BadBit;
+ }
+ }
+}
+
+void MemoryArea::unmap()
+{
+ if (isMapped()) {
+ if (-1 == ::close(m_FileDescriptor))
+ m_State |= FailBit;
+ else {
+ m_FileDescriptor = -1;
+ m_AccessFlags = ReadOnly;
+ }
+ }
+}
+
+bool MemoryArea::isMapped() const
+{
+ return (-1 != m_FileDescriptor);
+}
+
+bool MemoryArea::isGood() const
+{
+ return 0x0 == (m_State & (BadBit | FailBit));
+}
+
+bool MemoryArea::isBad() const
+{
+ return 0x0 != (m_State & BadBit);
+}
+
+bool MemoryArea::isFailed() const
+{
+ return 0x0 != (m_State & FailBit);
+}
+
+bool MemoryArea::isEOF() const
+{
+ return 0x0 != (m_State & EOFBit);
+}
+
+bool MemoryArea::isReadable() const
+{
+ return (((m_AccessFlags & AccessMask) == ReadOnly) ||
+ ((m_AccessFlags & AccessMask) == ReadWrite));
+}
+
+bool MemoryArea::isWritable() const
+{
+ return (((m_AccessFlags & AccessMask) == WriteOnly) ||
+ ((m_AccessFlags & AccessMask) == ReadWrite));
+}
+
+int MemoryArea::rdstate() const
+{
+ return m_State;
+}
+
+void MemoryArea::setState(MemoryArea::IOState pState)
+{
+ m_State |= pState;
+}
+
+void MemoryArea::clear(MemoryArea::IOState pState)
+{
+ m_State = pState;
+}
+
+// The layout of MemorySpace in the virtual memory space
+//
+// | : page boundary
+// [,]: MemoryRegion
+// - : fillment
+// = : data
+//
+// |---[=|====|====|==]--|
+// ^ ^ ^ ^
+// | | | |
+// | r_start +r_len |
+// space.data +space.size
+//
+// space.file_offset is the offset of the mapped file segment from the start of
+// the file. if the MemorySpace's type is ALLOCATED_ARRAY, the distances of
+// (space.data, r_start) and (r_len, space.size) are zero.
+//
+MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
+{
+ if (!isMapped() || !isGood())
+ return NULL;
+
+ if (0x0 == pLength)
+ return NULL;
+
+ if (!isWritable() && (pOffset + pLength) > m_FileSize)
+ return NULL;
+
+ if (isWritable() && (pOffset + pLength) > m_FileSize) {
+ // If the memory area is writable, user can expand the size of file by
+ // request a region larger than the file.
+ // MemoryArea should enlarge the file if the requested region is larger
+ // than the file.
+ m_FileSize = page_boundary(pOffset + pLength + 1);
+ truncate(m_FileSize);
+ }
+
+ Space* space = find(pOffset, pLength);
+ MemoryArea::Address r_start = 0;
+ if (NULL == space) {
+ // the space does not exist, create a new space.
+ space = new Space(this, pOffset, pLength);
+ m_SpaceList.push_back(space);
+ switch(space->type = policy(pOffset, pLength)) {
+ case Space::MMAPED: {
+ int mm_prot, mm_flag;
+ if (isWritable()) {
+ mm_prot = PROT_READ | PROT_WRITE;
+ mm_flag = MAP_FILE | MAP_SHARED;
+ }
+ else {
+ mm_prot = PROT_READ;
+ mm_flag = MAP_FILE | MAP_PRIVATE;
+ }
+
+ space->file_offset = page_offset(pOffset);
+
+ // The space's size may be larger than filesize.
+ space->size = page_boundary(pLength + pOffset + 1 - space->file_offset);
+ space->data = (Address) ::mmap(NULL,
+ space->size,
+ mm_prot, mm_flag,
+ m_FileDescriptor,
+ space->file_offset);
+
+ if (space->data == MAP_FAILED) {
+ llvm::report_fatal_error(llvm::Twine("cannot open memory map file :") +
+ m_FilePath.native() +
+ llvm::Twine(" (") +
+ sys::fs::detail::strerror(errno) +
+ llvm::Twine(").\n"));
+ }
+
+ r_start = space->data + (pOffset - space->file_offset);
+ break;
+ }
+ case Space::ALLOCATED_ARRAY: {
+ // space->offset and space->size are set in constructor. We only need
+ // to set up data.
+ space->data = new unsigned char[pLength];
+ r_start = space->data;
+ if ((m_AccessFlags & AccessMask) != WriteOnly) {
+ // Read data from the backend file.
+ if (!read(*space)) {
+ llvm::report_fatal_error(llvm::Twine("Failed to read data from ") +
+ m_FilePath.native() +
+ llvm::Twine(" (") +
+ sys::fs::detail::strerror(errno) +
+ llvm::Twine(") at offset ") +
+ llvm::Twine(pOffset) +
+ llvm::Twine(" lenght ") +
+ llvm::Twine(pLength) + llvm::Twine(".\n"));
+ }
+ }
+ break;
+ } // case
+ default: {
+ llvm::report_fatal_error("unhandled space type\n");
+ }
+ } // switch
+ }
+ else { // found
+ off_t distance = pOffset - space->file_offset;
+ r_start = space->data + distance;
+ }
+
+ // now, we have a legal space to hold the new MemoryRegion
+ return m_RegionFactory.produce(space, r_start, pLength);
+}
+
+// release - release a MemoryRegion
+void MemoryArea::release(MemoryRegion* pRegion)
+{
+ if (!isMapped() || !isGood())
+ return;
+
+ Space *space = pRegion->parent();
+ m_RegionFactory.destruct(pRegion);
+
+ if (0 == space->region_num) {
+ write(*space);
+ m_SpaceList.remove(*space);
+ release(space);
+ }
+}
+
+void MemoryArea::clean()
+{
+ m_RegionFactory.clear();
+
+ SpaceList::iterator sIter, sEnd = m_SpaceList.end();
+ for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
+ write(*sIter);
+ release(sIter);
+ }
+ m_SpaceList.clear();
+}
+
+void MemoryArea::sync()
+{
+ SpaceList::iterator sIter, sEnd = m_SpaceList.end();
+ for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
+ write(*sIter);
+ }
+}
+
+MemoryArea::Space* MemoryArea::find(size_t pOffset, size_t pLength)
+{
+ SpaceList::iterator sIter, sEnd = m_SpaceList.end();
+ for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
+ if (sIter->file_offset <= pOffset &&
+ (pOffset+pLength) <= (sIter->file_offset+sIter->size) ) { // within
+ return sIter;
+ }
+ }
+ return NULL;
+}
+
+void MemoryArea::release(MemoryArea::Space* pSpace)
+{
+ switch (pSpace->type) {
+ case Space::ALLOCATED_ARRAY: {
+ delete [] pSpace->data;
+ break;
+ }
+ case Space::MMAPED: {
+ ::munmap(pSpace->data, pSpace->size);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+MemoryArea::Space::Type MemoryArea::policy(off_t pOffset, size_t pLength)
+{
+ const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
+ if (pLength < threshold)
+ return Space::ALLOCATED_ARRAY;
+ else
+ return Space::MMAPED;
+}
+
+ssize_t MemoryArea::readToBuffer(sys::fs::detail::Address pBuf,
+ size_t pSize, size_t pOffset) {
+ assert(((m_AccessFlags & AccessMask) != WriteOnly) &&
+ "Write-only file cannot be read!");
+
+ ssize_t read_bytes = sys::fs::detail::pread(m_FileDescriptor, pBuf,
+ pSize, pOffset);
+ if (static_cast<size_t>(read_bytes) != pSize) {
+ // Some error occurred during pread().
+ if (read_bytes < 0) {
+ m_State |= FailBit;
+ }
+ else if (static_cast<size_t>(read_bytes) < pSize) {
+ m_State |= EOFBit;
+ if ((m_AccessFlags & AccessMask) != ReadWrite) {
+ // Files which is not read-write are not allowed read beyonds the EOF
+ // marker.
+ m_State |= BadBit;
+ }
+ }
+ else {
+ m_State |= BadBit;
+ }
+ }
+ return read_bytes;
+}
+
+bool MemoryArea::read(Space& pSpace) {
+ if (!isGood() || !isReadable())
+ return false;
+
+ if (pSpace.type == Space::ALLOCATED_ARRAY) {
+ readToBuffer(pSpace.data, pSpace.size, pSpace.file_offset);
+ return isGood();
+ }
+ else {
+ // Data associated with mmap()'ed space is already at the position the
+ // pSpace points to.
+ assert((pSpace.type == Space::MMAPED) && "Unknown type of Space!");
+ return true;
+ }
+}
+
+
+void MemoryArea::write(const Space& pSpace)
+{
+ if (!isMapped() || !isGood() || !isWritable())
+ return;
+
+ switch(pSpace.type) {
+ case Space::MMAPED: {
+ if(-1 == ::msync(pSpace.data, pSpace.size, MS_SYNC))
+ m_State |= FailBit;
+ return;
+ }
+ case Space::ALLOCATED_ARRAY: {
+ ssize_t write_bytes = sys::fs::detail::pwrite(m_FileDescriptor,
+ pSpace.data,
+ pSpace.size,
+ pSpace.file_offset);
+ if (0 > write_bytes) {
+ m_State |= FailBit;
+ return;
+ }
+ if (0 == write_bytes && 0 != pSpace.size)
+ m_State |= BadBit;
+ if ( pSpace.size > static_cast<size_t>(write_bytes) )
+ m_State |= EOFBit;
+ return;
+ }
+ default:
+ return;
+ }
+}
+
diff --git a/lib/Support/MemoryAreaFactory.cpp b/lib/Support/MemoryAreaFactory.cpp
new file mode 100644
index 0000000..1f7e523
--- /dev/null
+++ b/lib/Support/MemoryAreaFactory.cpp
@@ -0,0 +1,52 @@
+//===- MemoryAreaFactory.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/MemoryAreaFactory.h"
+#include "mcld/Support/RegionFactory.h"
+
+using namespace mcld;
+
+//==========================
+// MemoryAreaFactory
+MemoryAreaFactory::MemoryAreaFactory(size_t pNum)
+ : UniqueGCFactoryBase<sys::fs::Path, MemoryArea, 0>(pNum) {
+ // For each loaded file, MCLinker must load ELF header, section header,
+ // symbol table, and string table. So, we set the size of chunk quadruple
+ // larger than the number of input files.
+ m_pRegionFactory = new RegionFactory(pNum*4);
+}
+
+MemoryAreaFactory::~MemoryAreaFactory()
+{
+ delete m_pRegionFactory;
+}
+
+MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags)
+{
+ MemoryArea* result = find(pPath);
+ if (0 == result) {
+ result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory);
+ result->map(pPath, pFlags);
+ f_KeyMap.insert(std::make_pair(pPath, result));
+ }
+ return result;
+}
+
+MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags, mode_t pMode)
+{
+ MemoryArea* result = find(pPath);
+ if (0 == result) {
+ result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory);
+ result->map(pPath, pFlags, pMode);
+ f_KeyMap.insert(std::make_pair(pPath, result));
+ }
+ return result;
+}
+
diff --git a/lib/Support/MemoryRegion.cpp b/lib/Support/MemoryRegion.cpp
new file mode 100644
index 0000000..3a35f4e
--- /dev/null
+++ b/lib/Support/MemoryRegion.cpp
@@ -0,0 +1,34 @@
+//===- MemoryRegion.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/MemoryRegion.h>
+
+using namespace mcld;
+
+//==========================
+// MemoryRegion
+MemoryRegion::MemoryRegion(MemoryArea::Space *pParentSpace,
+ const MemoryRegion::Address pVMAStart,
+ size_t pSize)
+ : m_pParentSpace(pParentSpace), m_VMAStart(pVMAStart), m_Length(pSize) {
+ m_pParentSpace->region_num++;
+}
+
+MemoryRegion::~MemoryRegion()
+{
+ drift();
+}
+
+void MemoryRegion::drift()
+{
+ if (NULL == m_pParentSpace)
+ return;
+ m_pParentSpace->region_num--;
+ m_pParentSpace = NULL;
+}
+
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
new file mode 100644
index 0000000..ffb449f
--- /dev/null
+++ b/lib/Support/Path.cpp
@@ -0,0 +1,211 @@
+//===- Path.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/Path.h"
+#include <llvm/ADT/StringRef.h>
+
+#include <locale>
+#include <stdio.h>
+#include <string.h>
+
+#include <iostream>
+
+using namespace mcld;
+using namespace mcld::sys::fs;
+
+//===--------------------------------------------------------------------===//
+// Path
+Path::Path()
+ : m_PathName() {
+}
+
+Path::Path(const Path::ValueType* s )
+ : m_PathName(s) {
+}
+
+Path::Path(const Path::StringType &s )
+ : m_PathName(s) {
+}
+
+Path::Path(const Path& pCopy)
+ : m_PathName(pCopy.m_PathName) {
+}
+
+Path::~Path()
+{
+}
+
+bool Path::isFromRoot() const
+{
+ if (m_PathName.empty())
+ return false;
+ return (separator == m_PathName[0]);
+}
+
+bool Path::isFromPWD() const
+{
+ if (2 > m_PathName.size())
+ return false;
+ return ('.' == m_PathName[0] && separator == m_PathName[1]);
+}
+
+Path& Path::assign(const Path::StringType &s)
+{
+ m_PathName.assign(s);
+ return *this;
+}
+
+Path& Path::assign(const Path::ValueType* s, unsigned int length)
+{
+ if (0 == s || 0 == length)
+ assert(0 && "assign a null or empty string to Path");
+ m_PathName.assign(s, length);
+ return *this;
+}
+
+//a,/b a/,b a/,b/ a,b is a/b
+Path& Path::append(const Path& pPath)
+{
+ //first path is a/,second path is /b
+ if(m_PathName[m_PathName.length()-1] == separator &&
+ pPath.native()[0] == separator) {
+ unsigned int old_size = m_PathName.size()-1;
+ unsigned int new_size = old_size + pPath.native().size();
+
+ m_PathName.resize(new_size);
+ strcpy(const_cast<char*>(m_PathName.data()+old_size), pPath.native().data());
+ }
+ //first path is a,second path is b
+ else if(this->string()[this->native().size()-1] != separator &&
+ pPath.string()[0] != separator) {
+ m_PathName.append("/");
+ m_PathName.append(pPath.native());
+ }
+ // a/,b or a,/b just append
+ else {
+ m_PathName.append(pPath.native());
+ }
+ return *this;
+}
+
+bool Path::empty() const
+{
+ return m_PathName.empty();
+}
+
+std::string Path::string() const
+{
+ return m_PathName;
+}
+
+Path::StringType Path::generic_string() const
+{
+ std::string result = m_PathName;
+ detail::canonicalize(result);
+ return result;
+}
+
+bool Path::canonicalize()
+{
+ return detail::canonicalize(m_PathName);
+}
+
+Path::StringType::size_type Path::m_append_separator_if_needed()
+{
+ if (!m_PathName.empty() &&
+#ifdef LLVM_ON_WIN32
+ *(m_PathName.end()-1) != colon &&
+#endif
+ !is_separator(*(m_PathName.end()-1))) {
+ StringType::size_type tmp(m_PathName.size());
+ m_PathName += preferred_separator;
+ return tmp;
+ }
+ return 0;
+}
+
+void Path::m_erase_redundant_separator(Path::StringType::size_type pSepPos)
+{
+ size_t begin=pSepPos;
+ // skip '/'
+ while(separator == m_PathName[pSepPos])
+ ++pSepPos;
+
+ if(begin!=pSepPos)
+ m_PathName.erase(begin+1,pSepPos-begin-1);
+}
+
+Path Path::stem() const
+{
+ size_t begin_pos = m_PathName.find_last_of(separator)+1;
+ size_t end_pos = m_PathName.find_first_of(".", begin_pos);
+ Path result_path(m_PathName.substr(begin_pos, end_pos - begin_pos));
+ return result_path;
+}
+
+Path Path::extension() const
+{
+ size_t begin_pos = m_PathName.find_last_of('.');
+ Path result_path(m_PathName.substr(begin_pos));
+ return result_path;
+}
+
+//===--------------------------------------------------------------------===//
+// non-member functions
+bool mcld::sys::fs::operator==(const Path& pLHS,const Path& pRHS)
+{
+ return (pLHS.generic_string()==pRHS.generic_string());
+}
+
+bool mcld::sys::fs::operator!=(const Path& pLHS,const Path& pRHS)
+{
+ return !(pLHS==pRHS);
+}
+
+bool mcld::sys::fs::is_separator(char value)
+{
+ return (value == separator
+#ifdef LLVM_ON_WIN32
+ || value == preferred_separator
+#endif
+ );
+}
+
+bool mcld::sys::fs::exists(const Path &pPath)
+{
+ FileStatus pFileStatus;
+ detail::status(pPath, pFileStatus);
+ return exists(pFileStatus);
+}
+
+bool mcld::sys::fs::is_directory(const Path &pPath)
+{
+ FileStatus pFileStatus;
+ detail::status(pPath, pFileStatus);
+ return is_directory(pFileStatus);
+}
+
+std::ostream &mcld::sys::fs::operator<<(std::ostream& pOS,
+ const Path& pPath)
+{
+ return pOS << pPath.native();
+}
+
+std::istream &mcld::sys::fs::operator>>(std::istream& pOS,
+ Path& pPath)
+{
+ return pOS >> pPath.native();
+}
+
+llvm::raw_ostream &mcld::sys::fs::operator<<(llvm::raw_ostream &pOS,
+ const Path &pPath)
+{
+ return pOS << pPath.native();
+}
+
diff --git a/lib/Support/RealPath.cpp b/lib/Support/RealPath.cpp
new file mode 100644
index 0000000..2b641e8
--- /dev/null
+++ b/lib/Support/RealPath.cpp
@@ -0,0 +1,59 @@
+//===- RealPath.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/RealPath.h"
+#include "mcld/Support/FileSystem.h"
+
+using namespace mcld::sys::fs;
+
+//==========================
+// RealPath
+RealPath::RealPath()
+ : Path() {
+}
+
+RealPath::RealPath(const RealPath::ValueType* s )
+ : Path(s) {
+ initialize();
+}
+
+RealPath::RealPath(const RealPath::StringType &s )
+ : Path(s) {
+ initialize();
+}
+
+RealPath::RealPath(const Path& pPath)
+ : Path(pPath) {
+ initialize();
+}
+
+RealPath::~RealPath()
+{
+}
+
+RealPath& RealPath::assign(const Path& pPath)
+{
+ Path::m_PathName.assign(pPath.native());
+ return (*this);
+}
+
+void RealPath::initialize()
+{
+ if (isFromRoot()) {
+ detail::canonicalize(m_PathName);
+ }
+ else if (isFromPWD()) {
+ std::string path_name;
+ detail::get_pwd(path_name);
+ path_name += '/';
+ path_name += m_PathName;
+ detail::canonicalize(path_name);
+ m_PathName = path_name;
+ }
+}
+
diff --git a/lib/Support/RegionFactory.cpp b/lib/Support/RegionFactory.cpp
new file mode 100644
index 0000000..e87d389
--- /dev/null
+++ b/lib/Support/RegionFactory.cpp
@@ -0,0 +1,39 @@
+//===- RegionFactory.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/RegionFactory.h"
+#include "mcld/Support/MemoryArea.h"
+
+using namespace mcld;
+
+//==========================
+// RegionFactory
+RegionFactory::RegionFactory(size_t pNum)
+ : GCFactory<MemoryRegion, 0>(pNum) {
+}
+
+RegionFactory::~RegionFactory()
+{
+}
+
+MemoryRegion* RegionFactory::produce(MemoryArea::Space* pSpace,
+ const sys::fs::detail::Address pVMAStart,
+ size_t pSize)
+{
+ MemoryRegion* result = Alloc::allocate();
+ new (result) MemoryRegion(pSpace, pVMAStart, pSize);
+ return result;
+}
+
+void RegionFactory::destruct(MemoryRegion* pRegion)
+{
+ pRegion->drift();
+ destroy(pRegion);
+ deallocate(pRegion);
+}
+
diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp
new file mode 100644
index 0000000..246cbe8
--- /dev/null
+++ b/lib/Support/TargetRegistry.cpp
@@ -0,0 +1,42 @@
+//===- TargetRegistry.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/TargetRegistry.h"
+
+
+mcld::TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
+
+/* ** */
+
+void mcld::TargetRegistry::RegisterTarget(mcld::Target &T)
+{
+ s_TargetList.push_back(&T);
+}
+
+const mcld::Target* mcld::TargetRegistry::lookupTarget(const llvm::Target &pTarget)
+{
+ mcld::Target *result = 0;
+ TargetListTy::const_iterator TIter, TEnd = s_TargetList.end();
+ for (TIter=s_TargetList.begin(); TIter!=TEnd; ++TIter) {
+ if ((*TIter)->get()==&pTarget) {
+ result = (*TIter);
+ break;
+ }
+ }
+ return result;
+}
+
+const mcld::Target *mcld::TargetRegistry::lookupTarget(const std::string &pTriple,
+ std::string &pError)
+{
+ const llvm::Target* target = llvm::TargetRegistry::lookupTarget( pTriple, pError );
+ if (!target)
+ return 0;
+ return lookupTarget( *target );
+}
+
diff --git a/lib/Support/UniqueGCFactory.cpp b/lib/Support/UniqueGCFactory.cpp
new file mode 100644
index 0000000..2352181
--- /dev/null
+++ b/lib/Support/UniqueGCFactory.cpp
@@ -0,0 +1,15 @@
+//===- UniqueGCFactory.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <UniqueGCFactory.h>
+
+using namespace mcld;
+
+//==========================
+// UniqueGCFactory
+
diff --git a/lib/Support/Unix/FileSystem.inc b/lib/Support/Unix/FileSystem.inc
new file mode 100644
index 0000000..6499d66
--- /dev/null
+++ b/lib/Support/Unix/FileSystem.inc
@@ -0,0 +1,45 @@
+//===- FileSystem.inc -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace mcld{
+namespace sys{
+namespace fs{
+namespace detail{
+
+std::string static_library_extension = ".a";
+std::string shared_library_extension = ".so";
+std::string executable_extension = "";
+std::string relocatable_extension = ".o";
+std::string assembly_extension = ".s";
+std::string bitcode_extension = ".bc";
+
+size_t pread(int pFD, Address pBuf, size_t pCount, off_t pOffset)
+{
+ return ::pread(pFD, (void*) pBuf, pCount, pOffset);
+}
+
+size_t pwrite(int pFD, const Address pBuf, size_t pCount, off_t pOffset)
+{
+ return ::pwrite(pFD, (const void*) pBuf, pCount, pOffset);
+}
+
+char *strerror(int errnum)
+{
+ return ::strerror(errnum);
+}
+
+} // namespace of detail
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/Unix/PathV3.inc b/lib/Support/Unix/PathV3.inc
new file mode 100644
index 0000000..2e8e6d0
--- /dev/null
+++ b/lib/Support/Unix/PathV3.inc
@@ -0,0 +1,299 @@
+//===- PathV3.inc ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/Directory.h>
+#include <mcld/Support/Path.h>
+#include <llvm/Support/ErrorHandling.h>
+
+#include <cerrno>
+#include <dirent.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string>
+#include <stack>
+#include <unistd.h>
+
+namespace mcld{
+namespace sys{
+namespace fs{
+namespace detail{
+
+const char separator = '/';
+const char preferred_separator = '/';
+
+// return the last charactor being handled.
+size_t canonicalize(std::string& pathname)
+{
+ // Variable Index //
+ // SepTable - stack of result separators
+ // LR(1) Algorithm //
+ // traverse pPathName
+ // if we meet '//', '///', '////', ...
+ // -> ignore it
+ // -> push current into stack
+ // -> jump to the next not '/'
+ // if we meet '/./'
+ // -> ignore
+ // -> jump to the next not '/'
+ // if we meet '/../'
+ // -> pop previous position of '/' P
+ // -> erase P+1 to now
+ // if we meet other else
+ // -> go go go
+ // if we meet '/.../', '/..../', ... -> illegal
+ if (pathname.empty())
+ return 0;
+
+ size_t handler = 0;
+ std::stack<size_t> slash_stack;
+ slash_stack.push(-1);
+ while (handler < pathname.size()) {
+ if (separator == pathname[handler]) { // handler = 1st '/'
+ size_t next = handler + 1;
+ if (next >= pathname.size())
+ return handler;
+ switch(pathname[next]) { // next = handler + 1;
+ case separator: { // '//'
+ while (next < pathname.size() && separator == pathname[next])
+ ++next;
+ // next is the last not '/'
+ pathname.erase(handler, next - handler - 1);
+ // handler is the first '/'
+ slash_stack.push(handler);
+ break;
+ }
+ case '.': { // '/.'
+ ++next; // next = handler + 2
+ if (next >= pathname.size()) // '/.'
+ return handler;
+ switch (pathname[next]) {
+ case separator: { // '/./'
+ pathname.erase(handler, 2);
+ break;
+ }
+ case '.': { // '/..'
+ ++next; // next = handler + 3;
+ if (next >= pathname.size()) // '/..?'
+ return handler;
+ switch(pathname[next]) {
+ case separator: { // '/../'
+ handler = slash_stack.top();
+ slash_stack.pop();
+ pathname.erase(handler+1, next-handler);
+ if (static_cast<size_t>(-1) == handler) {
+ slash_stack.push(-1);
+ handler = pathname.find_first_of(separator, handler);
+ }
+ break;
+ }
+ case '.': { // '/...', illegal
+ return handler;
+ break;
+ }
+ default : { // '/..a'
+ slash_stack.push(handler);
+ handler = pathname.find_first_of(separator, handler+3);
+ break;
+ }
+ }
+ break;
+ }
+ default : { // '/.a'
+ slash_stack.push(handler);
+ handler = pathname.find_first_of(separator, handler+2);
+ break;
+ }
+ }
+ break;
+ }
+ default : { // '/a
+ slash_stack.push(handler);
+ handler = pathname.find_first_of(separator, handler+1);
+ break;
+ }
+ }
+ }
+ else {
+ handler = pathname.find_first_of(separator, handler);
+ }
+ }
+ return handler;
+}
+
+bool not_found_error(int perrno)
+{
+ return perrno == ENOENT || perrno == ENOTDIR;
+}
+
+void status(const Path& p, FileStatus& pFileStatus)
+{
+ struct stat path_stat;
+ if(stat(p.c_str(), &path_stat)!= 0)
+ {
+ if(not_found_error(errno))
+ {
+ pFileStatus.setType(FileNotFound);
+ }
+ else
+ pFileStatus.setType(StatusError);
+ }
+ else if(S_ISDIR(path_stat.st_mode))
+ pFileStatus.setType(DirectoryFile);
+ else if(S_ISREG(path_stat.st_mode))
+ pFileStatus.setType(RegularFile);
+ else if(S_ISBLK(path_stat.st_mode))
+ pFileStatus.setType(BlockFile);
+ else if(S_ISCHR(path_stat.st_mode))
+ pFileStatus.setType(CharacterFile);
+ else if(S_ISFIFO(path_stat.st_mode))
+ pFileStatus.setType(FifoFile);
+ else if(S_ISSOCK(path_stat.st_mode))
+ pFileStatus.setType(SocketFile);
+ else
+ pFileStatus.setType(TypeUnknown);
+}
+
+void symlink_status(const Path& p, FileStatus& pFileStatus)
+{
+ struct stat path_stat;
+ if(lstat(p.c_str(), &path_stat)!= 0)
+ {
+ if(errno == ENOENT || errno == ENOTDIR) // these are not errors
+ {
+ pFileStatus.setType(FileNotFound);
+ }
+ else
+ pFileStatus.setType(StatusError);
+ }
+ if(S_ISREG(path_stat.st_mode))
+ pFileStatus.setType(RegularFile);
+ if(S_ISDIR(path_stat.st_mode))
+ pFileStatus.setType(DirectoryFile);
+ if(S_ISLNK(path_stat.st_mode))
+ pFileStatus.setType(SymlinkFile);
+ if(S_ISBLK(path_stat.st_mode))
+ pFileStatus.setType(BlockFile);
+ if(S_ISCHR(path_stat.st_mode))
+ pFileStatus.setType(CharacterFile);
+ if(S_ISFIFO(path_stat.st_mode))
+ pFileStatus.setType(FifoFile);
+ if(S_ISSOCK(path_stat.st_mode))
+ pFileStatus.setType(SocketFile);
+ else
+ pFileStatus.setType(TypeUnknown);
+}
+
+/// read_dir - return true if we read one entry
+// @return value -1: read error
+// 0: read the end
+// 1: success
+static int read_dir(intptr_t& pDir, std::string& pOutFilename)
+{
+ errno = 0;
+ dirent *cur_dir = ::readdir(reinterpret_cast<DIR*>(pDir));
+ if (0 == cur_dir && 0 != errno)
+ return -1;
+
+ // idx does not stay at the end, but all elements had beed put into cache.
+ if (NULL == cur_dir) {
+ return 0;
+ }
+
+ llvm::StringRef name(cur_dir->d_name, strlen(cur_dir->d_name));
+ if ((name.size() == 1 && name[0] == '.') ||
+ (name.size() == 2 && name[0] == '.' && name[1] == '.'))
+ return read_dir(pDir, pOutFilename);
+
+ // find a new directory
+ pOutFilename.append(name.data(), name.size());
+ return 1;
+}
+
+/// directory_iterator_increment - increment function implementation
+//
+// iterator will call this function in two situations:
+// 1. All elements have been put into cache, and iterator stays at the end
+// of cache. (a real end)
+// 2. Some but not all elements had beed put into cache, and we stoped.
+// An iterator now is staying at the end of cache. (a temporal end)
+mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter)
+{
+ mcld::sys::fs::PathCache::entry_type* entry = 0;
+ std::string path(pIter.m_pParent->m_Path.native());
+ switch (read_dir(pIter.m_pParent->m_Handler, path)) {
+ case 1: {
+ // read one
+ bool exist = false;
+ entry = pIter.m_pParent->m_Cache.insert(path, exist);
+ if (!exist)
+ entry->setValue(new Path(path));
+ break;
+ }
+ case 0:// meet real end
+ pIter.m_pParent->m_CacheFull = true;
+ break;
+ default:
+ case -1:
+ llvm::report_fatal_error(std::string("Can't read directory: ")+
+ pIter.m_pParent->path().native());
+ break;
+ }
+ return entry;
+}
+
+void open_dir(Directory& pDir)
+{
+ pDir.m_Handler = reinterpret_cast<intptr_t>(opendir(pDir.path().c_str()));
+ if (pDir.m_Handler == 0) {
+ errno = 0; // opendir() will set errno if it failed to open directory.
+ pDir.m_CacheFull = true;
+ return;
+ }
+ // read one entry for advance the end element of the cache.
+ std::string path(pDir.path().native());
+ switch (read_dir(pDir.m_Handler, path)) {
+ case 1: {
+ // find a new directory
+ bool exist = false;
+ mcld::sys::fs::PathCache::entry_type* entry = pDir.m_Cache.insert(path, exist);
+ if (!exist)
+ entry->setValue(new Path(path));
+ return;
+ }
+ case 0:
+ // FIXME: a warning function
+ pDir.m_CacheFull = true;
+ return;
+ default:
+ case -1:
+ llvm::report_fatal_error(std::string("Can't read directory: ")+
+ pDir.path().native());
+ }
+}
+
+void close_dir(Directory& pDir)
+{
+ if (pDir.m_Handler)
+ closedir(reinterpret_cast<DIR *>(pDir.m_Handler));
+ pDir.m_Handler = NULL;
+}
+
+void get_pwd(std::string& pPWD)
+{
+ char* pwd = (char*)malloc(PATH_MAX);
+ pPWD.assign(getcwd(pwd, PATH_MAX));
+ free(pwd);
+}
+
+} // namespace of detail
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/Windows/FileSystem.inc b/lib/Support/Windows/FileSystem.inc
new file mode 100644
index 0000000..4cacf4c
--- /dev/null
+++ b/lib/Support/Windows/FileSystem.inc
@@ -0,0 +1,28 @@
+//===- FileSystem.inc -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+
+namespace mcld{
+namespace sys{
+namespace fs{
+namespace detail{
+
+std::string static_library_extension = ".lib";
+std::string shared_library_extension = ".dll";
+std::string executable_extension = ".exe";
+std::string relocatable_extension = ".obj";
+std::string assembly_extension = ".s";
+std::string bitcode_extension = ".bc";
+
+
+} // namespace of detail
+} // namespace of fs
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/Windows/PathV3.inc b/lib/Support/Windows/PathV3.inc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/Support/Windows/PathV3.inc
diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h
new file mode 100644
index 0000000..a128998
--- /dev/null
+++ b/lib/Target/ARM/ARM.h
@@ -0,0 +1,24 @@
+//===- ARM.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_H
+#define MCLD_ARM_H
+#include <string>
+#include "mcld/Target/TargetMachine.h"
+
+namespace mcld {
+class TargetLDBackend;
+
+extern mcld::Target TheARMTarget;
+
+TargetLDBackend *createARMLDBackend(const llvm::Target&, const std::string&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.cpp b/lib/Target/ARM/ARMAndroidSectLinker.cpp
new file mode 100644
index 0000000..a704cfa
--- /dev/null
+++ b/lib/Target/ARM/ARMAndroidSectLinker.cpp
@@ -0,0 +1,35 @@
+//===- ARMAndroidSectLinker.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMAndroidSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+ARMAndroidSectLinker::ARMAndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : AndroidSectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attributes
+ info.attrFactory().constraint().disableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().unsetWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+ARMAndroidSectLinker::~ARMAndroidSectLinker()
+{
+}
+
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.h b/lib/Target/ARM/ARMAndroidSectLinker.h
new file mode 100644
index 0000000..8a47a94
--- /dev/null
+++ b/lib/Target/ARM/ARMAndroidSectLinker.h
@@ -0,0 +1,40 @@
+//===- ARMAndroidSectLinker.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ARM_ANDROIDSECTLINKER_H
+#define ARM_ANDROIDSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/AndroidSectLinker.h>
+
+namespace mcld
+{
+
+class MCLDInfo;
+
+/** \class ARMAndroidSectLinker
+ * \brief ARMAndroidSectLinker sets up the environment for linking.
+ *
+ * \see
+ * \author Anders Cheng <Anders.Cheng@mediatek.com>
+ */
+class ARMAndroidSectLinker : public AndroidSectLinker
+{
+public:
+ ARMAndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~ARMAndroidSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMELFArchiveReader.cpp b/lib/Target/ARM/ARMELFArchiveReader.cpp
new file mode 100644
index 0000000..4c6d775
--- /dev/null
+++ b/lib/Target/ARM/ARMELFArchiveReader.cpp
@@ -0,0 +1,14 @@
+//===- ARMELFArchiveReader.cpp --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMELFArchiveReader.h"
+
+using namespace mcld;
+
+//==========================
+// ARMELFArchiveReader
diff --git a/lib/Target/ARM/ARMELFArchiveReader.h b/lib/Target/ARM/ARMELFArchiveReader.h
new file mode 100644
index 0000000..b60a12d
--- /dev/null
+++ b/lib/Target/ARM/ARMELFArchiveReader.h
@@ -0,0 +1,29 @@
+//===- ARMELFArchiveReader.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ARMELFARCHIVEREADER_H
+#define ARMELFARCHIVEREADER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/MC/MCELFArchiveTargetReader.h"
+
+namespace mcld
+{
+
+/// ARMELFArchiveReader - ARMELFArchiveReader is
+/// a target-dependent reader for ELF archive files.
+class ARMELFArchiveReader : public MCELFArchiveTargetReader
+{
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMELFDynamic.cpp b/lib/Target/ARM/ARMELFDynamic.cpp
new file mode 100644
index 0000000..c81a6f3
--- /dev/null
+++ b/lib/Target/ARM/ARMELFDynamic.cpp
@@ -0,0 +1,37 @@
+//===- ARMELFDynamic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/LD/ELFFileFormat.h>
+#include "ARMELFDynamic.h"
+
+using namespace mcld;
+
+ARMELFDynamic::ARMELFDynamic(const GNULDBackend& pParent)
+ : ELFDynamic(pParent)
+{
+}
+
+ARMELFDynamic::~ARMELFDynamic()
+{
+}
+
+void ARMELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (pFormat.hasGOT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+}
+
+void ARMELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (pFormat.hasGOT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+}
+
diff --git a/lib/Target/ARM/ARMELFDynamic.h b/lib/Target/ARM/ARMELFDynamic.h
new file mode 100644
index 0000000..914dcc4
--- /dev/null
+++ b/lib/Target/ARM/ARMELFDynamic.h
@@ -0,0 +1,31 @@
+//===- ARMELFDynamic.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_ELFDYNAMIC_SECTION_H
+#define MCLD_ARM_ELFDYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class ARMELFDynamic : public ELFDynamic {
+public:
+ ARMELFDynamic(const GNULDBackend& pParent);
+ ~ARMELFDynamic();
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/ARM/ARMELFSectLinker.cpp b/lib/Target/ARM/ARMELFSectLinker.cpp
new file mode 100644
index 0000000..0395606
--- /dev/null
+++ b/lib/Target/ARM/ARMELFSectLinker.cpp
@@ -0,0 +1,34 @@
+//===- ARMELFSectLinker.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMELFSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+ARMELFSectLinker::ARMELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attributes
+ info.attrFactory().constraint().enableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().setWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+ARMELFSectLinker::~ARMELFSectLinker()
+{
+}
+
diff --git a/lib/Target/ARM/ARMELFSectLinker.h b/lib/Target/ARM/ARMELFSectLinker.h
new file mode 100644
index 0000000..7493d59
--- /dev/null
+++ b/lib/Target/ARM/ARMELFSectLinker.h
@@ -0,0 +1,36 @@
+//===- ARMELFSectLinker.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ARM_ELFSECTLINKER_H
+#define ARM_ELFSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+/** \class ARMELFSectLinker
+ * \brief ARMELFSectLinker sets up the environment for linking.
+ *
+ * \see
+ */
+class ARMELFSectLinker : public SectLinker
+{
+public:
+ ARMELFSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~ARMELFSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h
new file mode 100644
index 0000000..f42b940
--- /dev/null
+++ b/lib/Target/ARM/ARMFixupKinds.h
@@ -0,0 +1,98 @@
+//===- ARMFixupKinds.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LIB_TARGET_ARM_ARM_FIXUP_KINDS_H_
+#define MCLD_LIB_TARGET_ARM_ARM_FIXUP_KINDS_H_
+
+#include <llvm/MC/MCFixup.h>
+
+namespace mcld {
+namespace ARM {
+
+enum Fixups {
+ // fixup_arm_ldst_pcrel_12 - 12-bit PC relative relocation for symbol
+ // addresses
+ fixup_arm_ldst_pcrel_12 = FirstTargetFixupKind,
+
+ // fixup_t2_ldst_pcrel_12 - Equivalent to fixup_arm_ldst_pcrel_12, with
+ // the 16-bit halfwords reordered.
+ fixup_t2_ldst_pcrel_12,
+
+ // fixup_arm_pcrel_10 - 10-bit PC relative relocation for symbol addresses
+ // used in VFP instructions where the lower 2 bits are not encoded
+ // (so it's encoded as an 8-bit immediate).
+ fixup_arm_pcrel_10,
+ // fixup_t2_pcrel_10 - Equivalent to fixup_arm_pcrel_10, accounting for
+ // the short-swapped encoding of Thumb2 instructions.
+ fixup_t2_pcrel_10,
+ // fixup_thumb_adr_pcrel_10 - 10-bit PC relative relocation for symbol
+ // addresses where the lower 2 bits are not encoded (so it's encoded as an
+ // 8-bit immediate).
+ fixup_thumb_adr_pcrel_10,
+ // fixup_arm_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
+ // instruction.
+ fixup_arm_adr_pcrel_12,
+ // fixup_t2_adr_pcrel_12 - 12-bit PC relative relocation for the ADR
+ // instruction.
+ fixup_t2_adr_pcrel_12,
+ // fixup_arm_condbranch - 24-bit PC relative relocation for conditional branch
+ // instructions.
+ fixup_arm_condbranch,
+ // fixup_arm_uncondbranch - 24-bit PC relative relocation for
+ // branch instructions. (unconditional)
+ fixup_arm_uncondbranch,
+ // fixup_t2_condbranch - 20-bit PC relative relocation for Thumb2 direct
+ // unconditional branch instructions.
+ fixup_t2_condbranch,
+ // fixup_t2_uncondbranch - 20-bit PC relative relocation for Thumb2 direct
+ // branch unconditional branch instructions.
+ fixup_t2_uncondbranch,
+
+ // fixup_arm_thumb_br - 12-bit fixup for Thumb B instructions.
+ fixup_arm_thumb_br,
+
+ // fixup_arm_thumb_bl - Fixup for Thumb BL instructions.
+ fixup_arm_thumb_bl,
+
+ // fixup_arm_thumb_blx - Fixup for Thumb BLX instructions.
+ fixup_arm_thumb_blx,
+
+ // fixup_arm_thumb_cb - Fixup for Thumb branch instructions.
+ fixup_arm_thumb_cb,
+
+ // fixup_arm_thumb_cp - Fixup for Thumb load/store from constant pool instrs.
+ fixup_arm_thumb_cp,
+
+ // fixup_arm_thumb_bcc - Fixup for Thumb conditional branching instructions.
+ fixup_arm_thumb_bcc,
+
+ // The next two are for the movt/movw pair
+ // the 16bit imm field are split into imm{15-12} and imm{11-0}
+ fixup_arm_movt_hi16, // :upper16:
+ fixup_arm_movw_lo16, // :lower16:
+ fixup_t2_movt_hi16, // :upper16:
+ fixup_t2_movw_lo16, // :lower16:
+
+ // It is possible to create an "immediate" that happens to be pcrel.
+ // movw r0, :lower16:Foo-(Bar+8) and movt r0, :upper16:Foo-(Bar+8)
+ // result in different reloc tags than the above two.
+ // Needed to support ELF::R_ARM_MOVT_PREL and ELF::R_ARM_MOVW_PREL_NC
+ fixup_arm_movt_hi16_pcrel, // :upper16:
+ fixup_arm_movw_lo16_pcrel, // :lower16:
+ fixup_t2_movt_hi16_pcrel, // :upper16:
+ fixup_t2_movw_lo16_pcrel, // :lower16:
+
+ // Marker
+ LastTargetFixupKind,
+ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
+};
+
+} // namespace ARM
+} // namespace mcld
+
+#endif
diff --git a/lib/Target/ARM/ARMGOT.cpp b/lib/Target/ARM/ARMGOT.cpp
new file mode 100644
index 0000000..3eb8e4a
--- /dev/null
+++ b/lib/Target/ARM/ARMGOT.cpp
@@ -0,0 +1,185 @@
+//===- impl.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMGOT.h"
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <new>
+
+namespace {
+ const size_t ARMGOTEntrySize = 4;
+} // end of anonymous namespace
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ARMGOT
+ARMGOT::ARMGOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, ARMGOTEntrySize),
+ m_NormalGOTIterator(), m_GOTPLTIterator(),
+ m_GOTPLTBegin(), m_GOTPLTEnd()
+{
+ GOTEntry* Entry = 0;
+
+ // Create GOT0 entries.
+ for (int i = 0; i < 3; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (int i = 1; i < ARMGOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_NormalGOTIterator = it;
+ m_GOTPLTIterator = it;
+
+ m_GOTPLTBegin = it;
+ m_GOTPLTEnd = it;
+}
+
+ARMGOT::~ARMGOT()
+{
+}
+
+void ARMGOT::reserveEntry(size_t pNum)
+{
+ GOTEntry* Entry = 0;
+
+ for (size_t i = 0; i < pNum; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+
+ m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
+ }
+}
+
+void ARMGOT::reserveGOTPLTEntry()
+{
+ GOTEntry* got_entry = 0;
+
+ got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
+
+ if (!got_entry)
+ llvm::report_fatal_error("Allocating new memory for GOT failed!");
+
+ m_Section.setSize(m_Section.size() + getEntrySize());
+
+ ++m_GOTPLTEnd;
+ ++m_NormalGOTIterator;
+}
+
+GOTEntry* ARMGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
+{
+ GOTEntry *&Entry = m_NormalGOTMap[&pInfo];
+ pExist = 1;
+
+ if (!Entry) {
+ pExist = 0;
+
+ ++m_NormalGOTIterator;
+ assert(m_NormalGOTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+
+ Entry = llvm::cast<GOTEntry>(&(*m_NormalGOTIterator));
+ }
+
+ return Entry;
+}
+
+void ARMGOT::applyGOT0(uint64_t pAddress)
+{
+ llvm::cast<GOTEntry>
+ (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
+}
+
+void ARMGOT::applyAllGOTPLT(uint64_t pPLTBase)
+{
+ iterator begin = getGOTPLTBegin();
+ iterator end = getGOTPLTEnd();
+
+ for (;begin != end ;++begin)
+ llvm::cast<GOTEntry>(*begin).setContent(pPLTBase);
+}
+
+GOTEntry*& ARMGOT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
+{
+ return m_GOTPLTMap[&pSymbol];
+}
+
+ARMGOT::iterator ARMGOT::begin()
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+ARMGOT::const_iterator ARMGOT::begin() const
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+ARMGOT::iterator ARMGOT::end()
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+ARMGOT::const_iterator ARMGOT::end() const
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+ARMGOT::iterator ARMGOT::getNextGOTPLTEntry()
+{
+ return ++m_GOTPLTIterator;
+}
+
+ARMGOT::iterator ARMGOT::getGOTPLTBegin()
+{
+ // Move to the first GOTPLT entry from last GOT0 entry.
+ iterator begin = m_GOTPLTBegin;
+ return ++begin;
+}
+
+const ARMGOT::iterator ARMGOT::getGOTPLTEnd()
+{
+ // Move to end or the first normal GOT entry from the last GOTPLT entry.
+ iterator end = m_GOTPLTEnd;
+ return ++end;
+}
+
+uint64_t ARMGOT::emit(MemoryRegion& pRegion)
+{
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ GOTEntry* got = 0;
+ unsigned int entry_size = getEntrySize();
+ uint64_t result = 0x0;
+ for (iterator it = begin(), ie = end();
+ it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ result += entry_size;
+ }
+ return result;
+}
+
diff --git a/lib/Target/ARM/ARMGOT.h b/lib/Target/ARM/ARMGOT.h
new file mode 100644
index 0000000..90f0f53
--- /dev/null
+++ b/lib/Target/ARM/ARMGOT.h
@@ -0,0 +1,92 @@
+//===- ARMGOT.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_GOT_H
+#define MCLD_ARM_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/GOT.h>
+
+namespace mcld
+{
+class LDSection;
+class MemoryRegion;
+
+/** \class ARMGOT
+ * \brief ARM Global Offset Table.
+ */
+class ARMGOT : public GOT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+ enum {
+ ARMGOT0Num = 3
+ };
+
+public:
+ ARMGOT(LDSection &pSection, llvm::MCSectionData& pSectionData);
+
+ ~ARMGOT();
+
+ iterator begin();
+
+ const_iterator begin() const;
+
+ iterator end();
+
+ const_iterator end() const;
+
+ uint64_t emit(MemoryRegion& pRegion);
+// For GOT0
+public:
+ void applyGOT0(uint64_t pAddress);
+
+// For normal GOT
+public:
+ // Reserve normal GOT entries.
+ void reserveEntry(size_t pNum = 1);
+
+ GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+// For GOTPLT
+public:
+ void reserveGOTPLTEntry();
+
+ void applyAllGOTPLT(uint64_t pPLTBase);
+
+ GOTEntry*& lookupGOTPLTMap(const ResolveInfo& pSymbol);
+
+ iterator getNextGOTPLTEntry();
+
+ iterator getGOTPLTBegin();
+
+ const iterator getGOTPLTEnd();
+
+private:
+ // For normal GOT entries
+ iterator m_NormalGOTIterator;
+ SymbolIndexMapType m_NormalGOTMap;
+
+ // For GOTPLT entries
+ iterator m_GOTPLTIterator;
+ SymbolIndexMapType m_GOTPLTMap;
+
+ iterator m_GOTPLTBegin;
+ iterator m_GOTPLTEnd;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
new file mode 100644
index 0000000..105a957
--- /dev/null
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -0,0 +1,1018 @@
+//===- ARMLDBackend.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/Triple.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/ErrorHandling.h>
+
+#include <mcld/LD/SectionMap.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/TargetRegistry.h>
+
+#include <cstring>
+
+#include "ARM.h"
+#include "ARMELFDynamic.h"
+#include "ARMLDBackend.h"
+#include "ARMRelocationFactory.h"
+
+using namespace mcld;
+
+ARMGNULDBackend::ARMGNULDBackend()
+ : m_pRelocFactory(NULL),
+ m_pGOT(NULL),
+ m_pPLT(NULL),
+ m_pRelDyn(NULL),
+ m_pRelPLT(NULL),
+ m_pDynamic(NULL),
+ m_pEXIDX(NULL),
+ m_pEXTAB(NULL),
+ m_pAttributes(NULL) {
+}
+
+ARMGNULDBackend::~ARMGNULDBackend()
+{
+ if (m_pRelocFactory)
+ delete m_pRelocFactory;
+ if(m_pGOT)
+ delete m_pGOT;
+ if(m_pPLT)
+ delete m_pPLT;
+ if(m_pRelDyn)
+ delete m_pRelDyn;
+ if(m_pRelPLT)
+ delete m_pRelPLT;
+ if(m_pDynamic)
+ delete m_pDynamic;
+}
+
+bool ARMGNULDBackend::initRelocFactory(const MCLinker& pLinker)
+{
+ if (NULL == m_pRelocFactory) {
+ m_pRelocFactory = new ARMRelocationFactory(1024, *this);
+ m_pRelocFactory->setLayout(pLinker.getLayout());
+ }
+ return true;
+}
+
+RelocationFactory* ARMGNULDBackend::getRelocFactory()
+{
+ assert(NULL != m_pRelocFactory);
+ return m_pRelocFactory;
+}
+
+bool ARMGNULDBackend::initTargetSectionMap(SectionMap& pSectionMap)
+{
+ if (!pSectionMap.push_back(".ARM.exidx", ".ARM.exidx") ||
+ !pSectionMap.push_back(".ARM.extab", ".ARM.extab") ||
+ !pSectionMap.push_back(".ARM.attributes", ".ARM.attributes"))
+ return false;
+ return true;
+}
+
+void ARMGNULDBackend::initTargetSections(MCLinker& pLinker)
+{
+ // FIXME: Currently we set exidx and extab to "Exception" and directly emit
+ // them from input
+ m_pEXIDX = &pLinker.getOrCreateOutputSectHdr(".ARM.exidx",
+ LDFileFormat::Exception,
+ llvm::ELF::SHT_ARM_EXIDX,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_LINK_ORDER,
+ bitclass() / 8);
+ m_pEXTAB = &pLinker.getOrCreateOutputSectHdr(".ARM.extab",
+ LDFileFormat::Exception,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ m_pAttributes = &pLinker.getOrCreateOutputSectHdr(".ARM.attributes",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_ARM_ATTRIBUTES,
+ 0x0,
+ 0x1);
+}
+
+void ARMGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+{
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+}
+
+void ARMGNULDBackend::doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // when building shared object, the .got section is must.
+ if(pOutput.type() == Output::DynObj && (NULL == m_pGOT)) {
+ createARMGOT(pLinker, pOutput);
+ }
+}
+
+void ARMGNULDBackend::doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // emit program headers
+ if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
+ emitProgramHdrs(pLinker.getLDInfo().output());
+
+ ELFFileFormat *file_format = getOutputFormat(pOutput);
+
+ // apply PLT
+ if (file_format->hasPLT()) {
+ // Since we already have the size of LDSection PLT, m_pPLT should not be
+ // NULL.
+ assert(NULL != m_pPLT);
+ m_pPLT->applyPLT0();
+ m_pPLT->applyPLT1();
+ }
+
+ // apply GOT
+ if (file_format->hasGOT()) {
+ // Since we already have the size of GOT, m_pGOT should not be NULL.
+ assert(NULL != m_pGOT);
+ if (pOutput.type() == Output::DynObj)
+ m_pGOT->applyGOT0(file_format->getDynamic().addr());
+ else {
+ // executable file and object file? should fill with zero.
+ m_pGOT->applyGOT0(0);
+ }
+ }
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+ARMELFDynamic& ARMGNULDBackend::dynamic()
+{
+ if (NULL == m_pDynamic)
+ m_pDynamic = new ARMELFDynamic(*this);
+
+ return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const ARMELFDynamic& ARMGNULDBackend::dynamic() const
+{
+ assert( NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+bool ARMGNULDBackend::isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const
+{
+ return (pOutput.type() == Output::DynObj);
+}
+
+void ARMGNULDBackend::createARMGOT(MCLinker& pLinker, const Output& pOutput)
+{
+ // get .got LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new ARMGOT(got, pLinker.getOrCreateSectData(got));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+ if( m_pGOTSymbol != NULL ) {
+ pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+
+}
+
+void ARMGNULDBackend::createARMPLTandRelPLT(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // get .plt and .rel.plt LDSection
+ LDSection& plt = file_format->getPLT();
+ LDSection& relplt = file_format->getRelPlt();
+ // create MCSectionData and ARMPLT
+ m_pPLT = new ARMPLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOT);
+ // set info of .rel.plt to .plt
+ relplt.setLink(&plt);
+ // create MCSectionData and ARMRelDynSection
+ m_pRelPLT = new OutputRelocSection(relplt,
+ pLinker.getOrCreateSectData(relplt),
+ 8);
+}
+
+void ARMGNULDBackend::createARMRelDyn(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // get .rel.dyn LDSection and create MCSectionData
+ LDSection& reldyn = file_format->getRelDyn();
+ // create MCSectionData and ARMRelDynSection
+ m_pRelDyn = new OutputRelocSection(reldyn,
+ pLinker.getOrCreateSectData(reldyn),
+ 8);
+}
+
+ELFFileFormat* ARMGNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
+ llvm::Twine(pOutput.type()));
+ return NULL;
+ }
+}
+
+bool ARMGNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ return (Output::DynObj == pOutput.type() &&
+ ResolveInfo::Function == pSym.type() &&
+ (pSym.isDyn() || pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput)));
+}
+
+bool ARMGNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const
+{
+ if(pSym.isUndef() && (Output::Exec == pOutput.type()))
+ return false;
+ if(pSym.isAbsolute())
+ return false;
+ if(Output::DynObj == pOutput.type() && isAbsReloc)
+ return true;
+ if(pSym.isDyn() || pSym.isUndef())
+ return true;
+
+ return false;
+}
+
+bool ARMGNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if(pSym.other() != ResolveInfo::Default)
+ return false;
+
+ if(Output::DynObj != pOutput.type())
+ return false;
+
+ if(pLDInfo.options().Bsymbolic())
+ return false;
+
+ return true;
+}
+
+/// checkValidReloc - When we attempt to generate a dynamic relocation for
+/// ouput file, check if the relocation is supported by dynamic linker.
+void ARMGNULDBackend::checkValidReloc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ // If not building a PIC object, no relocation type is invalid
+ if (!isPIC(pLDInfo, pOutput))
+ return;
+
+ switch(pReloc.type()) {
+ case llvm::ELF::R_ARM_RELATIVE:
+ case llvm::ELF::R_ARM_COPY:
+ case llvm::ELF::R_ARM_GLOB_DAT:
+ case llvm::ELF::R_ARM_JUMP_SLOT:
+ case llvm::ELF::R_ARM_ABS32:
+ case llvm::ELF::R_ARM_ABS32_NOI:
+ case llvm::ELF::R_ARM_PC24:
+ case llvm::ELF::R_ARM_TLS_DTPMOD32:
+ case llvm::ELF::R_ARM_TLS_DTPOFF32:
+ case llvm::ELF::R_ARM_TLS_TPOFF32:
+ break;
+
+ default:
+ llvm::report_fatal_error(llvm::Twine("Attempt to generate unsupported") +
+ llvm::Twine(" relocation type ") +
+ llvm::Twine((int)pReloc.type()) +
+ llvm::Twine(" for symbol '") +
+ llvm::Twine(pReloc.symInfo()->name()) +
+ llvm::Twine("', recompile with -fPIC")
+ );
+ break;
+ }
+}
+
+void ARMGNULDBackend::updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const
+{
+ // Update value keep in addend if we meet a section symbol
+ if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ pReloc.setAddend(pLayout.getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.addend());
+ }
+}
+
+void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+
+ switch(pReloc.type()){
+
+ // Set R_ARM_TARGET1 to R_ARM_ABS32
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET1:
+ pReloc.setType(llvm::ELF::R_ARM_ABS32);
+ case llvm::ELF::R_ARM_ABS32:
+ case llvm::ELF::R_ARM_ABS32_NOI: {
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if(isPIC(pLDInfo, pOutput)) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+
+ case llvm::ELF::R_ARM_ABS16:
+ case llvm::ELF::R_ARM_ABS12:
+ case llvm::ELF::R_ARM_THM_ABS5:
+ case llvm::ELF::R_ARM_ABS8:
+ case llvm::ELF::R_ARM_BASE_ABS:
+ case llvm::ELF::R_ARM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_MOVT_ABS:
+ case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_ABS: {
+ // Update value keep in relocation place if we meet a section symbol
+ if(rsym->type() == ResolveInfo::Section) {
+ pReloc.target() = pLinker.getLayout().getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.target();
+ }
+
+ // If building PIC object (shared library or PIC executable),
+ // a dynamic relocation for this location is needed.
+ // Reserve an entry in .rel.dyn
+ if(isPIC(pLDInfo, pOutput)) {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+ case llvm::ELF::R_ARM_GOTOFF32:
+ case llvm::ELF::R_ARM_GOTOFF12: {
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ return;
+ }
+
+ // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET2:
+ pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
+ case llvm::ELF::R_ARM_GOT_BREL:
+ case llvm::ELF::R_ARM_GOT_PREL: {
+ // A GOT entry is needed for these relocation type.
+ // return if we already create GOT for this symbol
+ if(rsym->reserved() & 0x6u)
+ return;
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ m_pGOT->reserveEntry();
+ // If building PIC object, a dynamic relocation with
+ // type RELATIVE is needed to relocate this GOT entry.
+ // Reserve an entry in .rel.dyn
+ if(isPIC(pLDInfo, pOutput)) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | 0x4u);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | 0x2u);
+ return;
+ }
+
+ case llvm::ELF::R_ARM_BASE_PREL: {
+ // FIXME: Currently we only support R_ARM_BASE_PREL against
+ // symbol _GLOBAL_OFFSET_TABLE_
+ if(rsym != m_pGOTSymbol->resolveInfo()) {
+ llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
+ llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
+ llvm::Twine(rsym->name()) +
+ llvm::Twine(".'"));
+ }
+ return;
+ }
+ case llvm::ELF::R_ARM_COPY:
+ case llvm::ELF::R_ARM_GLOB_DAT:
+ case llvm::ELF::R_ARM_JUMP_SLOT:
+ case llvm::ELF::R_ARM_RELATIVE: {
+ // These are relocation type for dynamic linker, shold not
+ // appear in object file.
+ llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
+ llvm::Twine((int)pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ }
+ default: {
+ break;
+ }
+ } // end switch
+}
+
+void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ switch(pReloc.type()) {
+
+ // Set R_ARM_TARGET1 to R_ARM_ABS32
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET1:
+ pReloc.setType(llvm::ELF::R_ARM_ABS32);
+ case llvm::ELF::R_ARM_ABS32:
+ case llvm::ELF::R_ARM_ABS16:
+ case llvm::ELF::R_ARM_ABS12:
+ case llvm::ELF::R_ARM_THM_ABS5:
+ case llvm::ELF::R_ARM_ABS8:
+ case llvm::ELF::R_ARM_BASE_ABS:
+ case llvm::ELF::R_ARM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_MOVT_ABS:
+ case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_ABS:
+ case llvm::ELF::R_ARM_ABS32_NOI: {
+ // Absolute relocation type, symbol may needs PLT entry or
+ // dynamic relocation entry
+ if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ // create plt for this symbol if it does not have one
+ if(!(rsym->reserved() & 0x8u)){
+ // Create .got section if it doesn't exist
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createARMPLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling ARMPLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | 0x8u);
+ }
+ }
+
+ if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+
+ case llvm::ELF::R_ARM_GOTOFF32:
+ case llvm::ELF::R_ARM_GOTOFF12: {
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ return;
+ }
+
+ case llvm::ELF::R_ARM_BASE_PREL:
+ // FIXME: Currently we only support R_ARM_BASE_PREL against
+ // symbol _GLOBAL_OFFSET_TABLE_
+ if(rsym != m_pGOTSymbol->resolveInfo()) {
+ llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
+ llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
+ llvm::Twine(rsym->name()) +
+ llvm::Twine(".'"));
+ }
+ case llvm::ELF::R_ARM_REL32:
+ case llvm::ELF::R_ARM_LDR_PC_G0:
+ case llvm::ELF::R_ARM_SBREL32:
+ case llvm::ELF::R_ARM_THM_PC8:
+ case llvm::ELF::R_ARM_MOVW_PREL_NC:
+ case llvm::ELF::R_ARM_MOVT_PREL:
+ case llvm::ELF::R_ARM_THM_MOVW_PREL_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_PREL:
+ case llvm::ELF::R_ARM_THM_ALU_PREL_11_0:
+ case llvm::ELF::R_ARM_THM_PC12:
+ case llvm::ELF::R_ARM_REL32_NOI:
+ case llvm::ELF::R_ARM_ALU_PC_G0_NC:
+ case llvm::ELF::R_ARM_ALU_PC_G0:
+ case llvm::ELF::R_ARM_ALU_PC_G1_NC:
+ case llvm::ELF::R_ARM_ALU_PC_G1:
+ case llvm::ELF::R_ARM_ALU_PC_G2:
+ case llvm::ELF::R_ARM_LDR_PC_G1:
+ case llvm::ELF::R_ARM_LDR_PC_G2:
+ case llvm::ELF::R_ARM_LDRS_PC_G0:
+ case llvm::ELF::R_ARM_LDRS_PC_G1:
+ case llvm::ELF::R_ARM_LDRS_PC_G2:
+ case llvm::ELF::R_ARM_LDC_PC_G0:
+ case llvm::ELF::R_ARM_LDC_PC_G1:
+ case llvm::ELF::R_ARM_LDC_PC_G2:
+ case llvm::ELF::R_ARM_ALU_SB_G0_NC:
+ case llvm::ELF::R_ARM_ALU_SB_G0:
+ case llvm::ELF::R_ARM_ALU_SB_G1_NC:
+ case llvm::ELF::R_ARM_ALU_SB_G1:
+ case llvm::ELF::R_ARM_ALU_SB_G2:
+ case llvm::ELF::R_ARM_LDR_SB_G0:
+ case llvm::ELF::R_ARM_LDR_SB_G1:
+ case llvm::ELF::R_ARM_LDR_SB_G2:
+ case llvm::ELF::R_ARM_LDRS_SB_G0:
+ case llvm::ELF::R_ARM_LDRS_SB_G1:
+ case llvm::ELF::R_ARM_LDRS_SB_G2:
+ case llvm::ELF::R_ARM_LDC_SB_G0:
+ case llvm::ELF::R_ARM_LDC_SB_G1:
+ case llvm::ELF::R_ARM_LDC_SB_G2:
+ case llvm::ELF::R_ARM_MOVW_BREL_NC:
+ case llvm::ELF::R_ARM_MOVT_BREL:
+ case llvm::ELF::R_ARM_MOVW_BREL:
+ case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
+ case llvm::ELF::R_ARM_THM_MOVT_BREL:
+ case llvm::ELF::R_ARM_THM_MOVW_BREL: {
+ // Relative addressing relocation, may needs dynamic relocation
+ if(isSymbolNeedsDynRel(*rsym, pOutput, false)) {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | 0x1u);
+ }
+ return;
+ }
+
+ case llvm::ELF::R_ARM_THM_CALL:
+ case llvm::ELF::R_ARM_PLT32:
+ case llvm::ELF::R_ARM_CALL:
+ case llvm::ELF::R_ARM_JUMP24:
+ case llvm::ELF::R_ARM_THM_JUMP24:
+ case llvm::ELF::R_ARM_SBREL31:
+ case llvm::ELF::R_ARM_PREL31:
+ case llvm::ELF::R_ARM_THM_JUMP19:
+ case llvm::ELF::R_ARM_THM_JUMP6:
+ case llvm::ELF::R_ARM_THM_JUMP11:
+ case llvm::ELF::R_ARM_THM_JUMP8: {
+ // These are branch relocation (except PREL31)
+ // A PLT entry is needed when building shared library
+
+ // return if we already create plt for this symbol
+ if(rsym->reserved() & 0x8u)
+ return;
+
+ // if symbol is defined in the ouput file and it's not
+ // preemptible, no need plt
+ if(rsym->isDefine() && !rsym->isDyn() &&
+ !isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
+ return;
+ }
+
+ // Create .got section if it doesn't exist
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createARMPLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling ARMPLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | 0x8u);
+ return;
+ }
+
+ // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
+ // Ref: GNU gold 1.11 arm.cc, line 9892
+ case llvm::ELF::R_ARM_TARGET2:
+ pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
+ case llvm::ELF::R_ARM_GOT_BREL:
+ case llvm::ELF::R_ARM_GOT_ABS:
+ case llvm::ELF::R_ARM_GOT_PREL: {
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if(rsym->reserved() & 0x6u)
+ return;
+ if(NULL == m_pGOT)
+ createARMGOT(pLinker, pOutput);
+ m_pGOT->reserveEntry();
+ // If building shared object or the symbol is undefined, a dynamic
+ // relocation is needed to relocate this GOT entry. Reserve an
+ // entry in .rel.dyn
+ if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createARMRelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | 0x4u);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | 0x2u);
+ return;
+ }
+
+ case llvm::ELF::R_ARM_COPY:
+ case llvm::ELF::R_ARM_GLOB_DAT:
+ case llvm::ELF::R_ARM_JUMP_SLOT:
+ case llvm::ELF::R_ARM_RELATIVE: {
+ // These are relocation type for dynamic linker, shold not
+ // appear in object file.
+ llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
+ llvm::Twine((int)pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ }
+ default: {
+ break;
+ }
+ } // end switch
+}
+
+void ARMGNULDBackend::scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+
+ // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
+ // entries should be created.
+ // FIXME: Below judgements concern only .so is generated as output
+ // FIXME: Below judgements concern nothing about TLS related relocation
+
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
+ // is needed
+ if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if(rsym == m_pGOTSymbol->resolveInfo()) {
+ createARMGOT(pLinker, pOutput);
+ }
+ }
+
+ // rsym is local
+ if(rsym->isLocal())
+ scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+
+ // rsym is external
+ else
+ scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+
+}
+
+uint64_t ARMGNULDBackend::emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSection == m_pAttributes) {
+ // FIXME: Currently Emitting .ARM.attributes directly from the input file.
+ const llvm::MCSectionData* sect_data = pSection.getSectionData();
+ assert(sect_data &&
+ "Emit .ARM.attribute failed, MCSectionData doesn't exist!");
+
+ uint8_t* start =
+ llvm::cast<MCRegionFragment>(
+ sect_data->getFragmentList().front()).getRegion().start();
+
+ memcpy(pRegion.start(), start, pRegion.size());
+ return pRegion.size();
+ }
+
+ if (&pSection == &(file_format->getPLT())) {
+ assert(NULL != m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
+ uint64_t result = m_pPLT->emit(pRegion);
+ return result;
+ }
+
+ if (&pSection == &(file_format->getGOT())) {
+ assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+ uint64_t result = m_pGOT->emit(pRegion);
+ return result;
+ }
+
+ llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
+ pSection.name() +
+ llvm::Twine("'.\n"));
+ return 0x0;
+}
+
+/// finalizeSymbol - finalize the symbol value
+/// If the symbol's reserved field is not zero, MCLinker will call back this
+/// function to ask the final value of the symbol
+bool ARMGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+{
+ return false;
+}
+
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+bool
+ARMGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
+{
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
+
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ // addralign := max value of all common symbols
+ uint64_t addralign = 0x0;
+
+ // Due to the visibility, some common symbols may be forcefully local.
+ SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+ }
+
+ // global common symbols.
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // com_sym = symbol_list.commonBegin();
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+
+ // allocate all common symbols
+ uint64_t offset = bss_sect_hdr->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+
+ bss_sect_hdr->setSize(offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
+}
+
+bool ARMGNULDBackend::readSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr)
+{
+ LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
+ pInputSectHdr.kind(),
+ pInputSectHdr.type(),
+ pInputSectHdr.flag());
+ // FIXME: (Luba)
+ // Handle ARM attributes in the right way.
+ // In current milestone, MCLinker goes through the shortcut.
+ // It reads input's ARM attributes and copies the first ARM attributes
+ // into the output file. The correct way is merge these sections, not
+ // just copy.
+ if ((0 == out_sect.name().compare(".ARM.attributes")) &&
+ (0 != out_sect.size()))
+ return true;
+
+ MemoryRegion* region = pInput.memArea()->request(pInputSectHdr.offset(),
+ pInputSectHdr.size());
+
+ llvm::MCSectionData& sect_data = pLinker.getOrCreateSectData(pInputSectHdr);
+
+ new MCRegionFragment(*region, §_data);
+
+ out_sect.setSize(out_sect.size() + pInputSectHdr.size());
+ return true;
+}
+
+ARMGOT& ARMGNULDBackend::getGOT()
+{
+ assert(NULL != m_pGOT && "GOT section not exist");
+ return *m_pGOT;
+}
+
+const ARMGOT& ARMGNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT && "GOT section not exist");
+ return *m_pGOT;
+}
+
+ARMPLT& ARMGNULDBackend::getPLT()
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+const ARMPLT& ARMGNULDBackend::getPLT() const
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+OutputRelocSection& ARMGNULDBackend::getRelDyn()
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& ARMGNULDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+OutputRelocSection& ARMGNULDBackend::getRelPLT()
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+const OutputRelocSection& ARMGNULDBackend::getRelPLT() const
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+unsigned int
+ARMGNULDBackend::getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSectHdr == &file_format->getGOT())
+ return SHO_DATA;
+
+ if (&pSectHdr == &file_format->getPLT())
+ return SHO_PLT;
+
+ return SHO_UNDEFINED;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+/// createARMLDBackend - the help funtion to create corresponding ARMLDBackend
+///
+TargetLDBackend* createARMLDBackend(const llvm::Target& pTarget,
+ const std::string& pTriple)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ /**
+ return new ARMMachOLDBackend(createARMMachOArchiveReader,
+ createARMMachOObjectReader,
+ createARMMachOObjectWriter);
+ **/
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ /**
+ return new ARMCOFFLDBackend(createARMCOFFArchiveReader,
+ createARMCOFFObjectReader,
+ createARMCOFFObjectWriter);
+ **/
+ }
+ return new ARMGNULDBackend();
+}
+
+} // namespace of mcld
+
+//=============================
+// Force static initialization.
+extern "C" void LLVMInitializeARMLDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheARMTarget, createARMLDBackend);
+}
+
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
new file mode 100644
index 0000000..440d9ee
--- /dev/null
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -0,0 +1,297 @@
+//===- ARMLDBackend.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_LDBACKEND_H
+#define MCLD_ARM_LDBACKEND_H
+
+#include "ARMELFDynamic.h"
+#include "ARMGOT.h"
+#include "ARMPLT.h"
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+namespace mcld {
+
+class MCLDInfo;
+class MCLinker;
+class Output;
+class SectionMap;
+
+
+//===----------------------------------------------------------------------===//
+/// ARMGNULDBackend - linker backend of ARM target of GNU ELF format
+///
+class ARMGNULDBackend : public GNULDBackend
+{
+public:
+ ARMGNULDBackend();
+ ~ARMGNULDBackend();
+public:
+ typedef std::vector<llvm::ELF::Elf32_Dyn*> ELF32DynList;
+
+ /** \enum ReservedEntryType
+ * \brief The reserved entry type of reserved space in ResolveInfo.
+ *
+ * This is used for sacnRelocation to record what kinds of entries are
+ * reserved for this resolved symbol
+ *
+ * In ARM, there are three kinds of entries, GOT, PLT, and dynamic reloction.
+ * GOT may needs a corresponding relocation to relocate itself, so we
+ * separate GOT to two situations: GOT and GOTRel. Besides, for the same
+ * symbol, there might be two kinds of entries reserved for different location.
+ * For example, reference to the same symbol, one may use GOT and the other may
+ * use dynamic relocation.
+ *
+ * bit: 3 2 1 0
+ * | PLT | GOTRel | GOT | Rel |
+ *
+ * value Name - Description
+ *
+ * 0000 None - no reserved entry
+ * 0001 ReserveRel - reserve an dynamic relocation entry
+ * 0010 ReserveGOT - reserve an GOT entry
+ * 0011 GOTandRel - For different relocation, we've reserved GOT and
+ * Rel for different location.
+ * 0100 GOTRel - reserve an GOT entry and the corresponding Dyncamic
+ * relocation entry which relocate this GOT entry
+ * 0101 GOTRelandRel - For different relocation, we've reserved GOTRel
+ * and relocation entry for different location.
+ * 1000 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ * Dynamic relocation entries
+ * 1001 PLTandRel - For different relocation, we've reserved PLT and
+ * Rel for different location.
+ */
+ enum ReservedEntryType {
+ None = 0,
+ ReserveRel = 1,
+ ReserveGOT = 2,
+ GOTandRel = 3,
+ GOTRel = 4,
+ GOTRelandRel = 5,
+ ReservePLT = 8,
+ PLTandRel = 9
+ };
+
+public:
+ /// initTargetSectionMap - initialize target dependent section mapping
+ bool initTargetSectionMap(SectionMap& pSectionMap);
+
+ /// initTargetSections - initialize target dependent sections in output.
+ void initTargetSections(MCLinker& pLinker);
+
+ /// initTargetSymbols - initialize target dependent symbols in output.
+ void initTargetSymbols(MCLinker& pLinker);
+
+ /// initRelocFactory - create and initialize RelocationFactory
+ bool initRelocFactory(const MCLinker& pLinker);
+
+ /// getRelocFactory
+ RelocationFactory* getRelocFactory();
+
+ /// scanRelocation - determine the empty entries are needed or not and create
+ /// the empty entries if needed.
+ /// For ARM, following entries are check to create:
+ /// - GOT entry (for .got section)
+ /// - PLT entry (for .plt section)
+ /// - dynamin relocation entries (for .rel.plt and .rel.dyn sections)
+ void scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ uint32_t machine() const
+ { return llvm::ELF::EM_ARM; }
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ virtual uint8_t OSABI() const
+ { return llvm::ELF::ELFOSABI_NONE; }
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ virtual uint8_t ABIVersion() const
+ { return 0x0; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ virtual uint64_t flags() const
+ { return (llvm::ELF::EF_ARM_EABIMASK & 0x05000000); }
+
+ bool isLittleEndian() const
+ { return true; }
+
+ unsigned int bitclass() const
+ { return 32; }
+
+ /// doPreLayout - Backend can do any needed modification before layout
+ void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// doPostLayout -Backend can do any needed modification after layout
+ void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ ARMELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const ARMELFDynamic& dynamic() const;
+
+
+ /// emitSectionData - write out the section data into the memory region.
+ /// When writers get a LDSection whose kind is LDFileFormat::Target, writers
+ /// call back target backend to emit the data.
+ ///
+ /// Backends handle the target-special tables (plt, gp,...) by themselves.
+ /// Backend can put the data of the tables in MCSectionData directly
+ /// - LDSection.getSectionData can get the section data.
+ /// Or, backend can put the data into special data structure
+ /// - backend can maintain its own map<LDSection, table> to get the table
+ /// from given LDSection.
+ ///
+ /// @param pOutput - the output file
+ /// @param pSection - the given LDSection
+ /// @param pInfo - all options in the command line.
+ /// @param pRegion - the region to write out data
+ /// @return the size of the table in the file.
+ uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const;
+
+ ARMGOT& getGOT();
+
+ const ARMGOT& getGOT() const;
+
+ ARMPLT& getPLT();
+
+ const ARMPLT& getPLT() const;
+
+ OutputRelocSection& getRelDyn();
+
+ const OutputRelocSection& getRelDyn() const;
+
+ OutputRelocSection& getRelPLT();
+
+ const OutputRelocSection& getRelPLT() const;
+
+ /// getTargetSectionOrder - compute the layout order of ARM target sections
+ unsigned int getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// finalizeSymbol - finalize the symbol value
+ /// If the symbol's reserved field is not zero, MCLinker will call back this
+ /// function to ask the final value of the symbol
+ bool finalizeSymbol(LDSymbol& pSymbol) const;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+
+ /// readSection - read target dependent sections
+ bool readSection(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr);
+
+public:
+ bool isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ bool isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const;
+
+private:
+ void scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ bool isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const;
+
+
+ void checkValidReloc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ /// updateAddend - update addend value of the relocation if the
+ /// the target symbol is a section symbol. Addend is the offset
+ /// in the section. This value should be updated after section
+ /// merged.
+ void updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const;
+
+ void createARMGOT(MCLinker& pLinker, const Output& pOutput);
+
+ /// createARMPLTandRelPLT - create PLT and RELPLT sections.
+ /// Because in ELF sh_info in .rel.plt is the shndx of .plt, these two
+ /// sections should be create together.
+ void createARMPLTandRelPLT(MCLinker& pLinker, const Output& pOutput);
+
+ void createARMRelDyn(MCLinker& pLinker, const Output& pOutput);
+
+ ELFFileFormat* getOutputFormat(const Output& pOutput) const;
+
+private:
+ RelocationFactory* m_pRelocFactory;
+ ARMGOT* m_pGOT;
+ ARMPLT* m_pPLT;
+ /// m_RelDyn - dynamic relocation table of .rel.dyn
+ OutputRelocSection* m_pRelDyn;
+ /// m_RelPLT - dynamic relocation table of .rel.plt
+ OutputRelocSection* m_pRelPLT;
+
+ ARMELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+
+ // variable name : ELF
+ LDSection* m_pEXIDX; // .ARM.exidx
+ LDSection* m_pEXTAB; // .ARM.extab
+ LDSection* m_pAttributes; // .ARM.attributes
+// LDSection* m_pPreemptMap; // .ARM.preemptmap
+// LDSection* m_pDebugOverlay; // .ARM.debug_overlay
+// LDSection* m_pOverlayTable; // .ARM.overlay_table
+};
+
+//===----------------------------------------------------------------------===//
+/// ARMMachOLDBackend - linker backend of ARM target of MachO format
+///
+/**
+class ARMMachOLDBackend : public DarwinARMLDBackend
+{
+public:
+ ARMMachOLDBackend();
+ ~ARMMachOLDBackend();
+
+private:
+ MCMachOTargetArchiveReader *createTargetArchiveReader() const;
+ MCMachOTargetObjectReader *createTargetObjectReader() const;
+ MCMachOTargetObjectWriter *createTargetObjectWriter() const;
+
+};
+**/
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMPLT.cpp b/lib/Target/ARM/ARMPLT.cpp
new file mode 100644
index 0000000..3a79b52
--- /dev/null
+++ b/lib/Target/ARM/ARMPLT.cpp
@@ -0,0 +1,250 @@
+//===- ARMPLT.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMGOT.h"
+#include "ARMPLT.h"
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <new>
+
+namespace {
+
+const uint32_t arm_plt0[] = {
+ 0xe52de004, // str lr, [sp, #-4]!
+ 0xe59fe004, // ldr lr, [pc, #4]
+ 0xe08fe00e, // add lr, pc, lr
+ 0xe5bef008, // ldr pc, [lr, #8]!
+ 0x00000000, // &GOT[0] - .
+};
+
+const uint32_t arm_plt1[] = {
+ 0xe28fc600, // add ip, pc, #0xNN00000
+ 0xe28cca00, // add ip, ip, #0xNN000
+ 0xe5bcf000, // ldr pc, [ip, #0xNNN]!
+};
+
+} // anonymous namespace
+
+using namespace mcld;
+
+ARMPLT0::ARMPLT0(llvm::MCSectionData* pParent)
+ : PLTEntry(sizeof(arm_plt0), pParent) {}
+
+ARMPLT1::ARMPLT1(llvm::MCSectionData* pParent)
+ : PLTEntry(sizeof(arm_plt1), pParent) {}
+
+//===----------------------------------------------------------------------===//
+// ARMPLT
+
+ARMPLT::ARMPLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ ARMGOT &pGOTPLT)
+ : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator() {
+ ARMPLT0* plt0_entry = new ARMPLT0(&m_SectionData);
+
+ m_Section.setSize(m_Section.size() + plt0_entry->getEntrySize());
+
+ m_PLTEntryIterator = pSectionData.begin();
+}
+
+ARMPLT::~ARMPLT()
+{
+}
+
+void ARMPLT::reserveEntry(size_t pNum)
+{
+ ARMPLT1* plt1_entry = 0;
+
+ for (size_t i = 0; i < pNum; ++i) {
+ plt1_entry = new (std::nothrow) ARMPLT1(&m_SectionData);
+
+ if (!plt1_entry)
+ llvm::report_fatal_error("Allocating new memory for ARMPLT1 failed!");
+
+ m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
+
+ m_GOT.reserveGOTPLTEntry();
+ }
+}
+
+PLTEntry* ARMPLT::getPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+
+ pExist = 1;
+
+ if (!PLTEntry) {
+ GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
+ assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+
+ ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
+ ARMGOT::iterator got_ie = m_GOT.getGOTPLTEnd();
+ assert(got_it != got_ie && "The number of GOTPLT and PLT doesn't match");
+
+ PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
+ }
+
+ return PLTEntry;
+}
+
+GOTEntry* ARMPLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ GOTEntry *&GOTPLTEntry = m_GOT.lookupGOTPLTMap(pSymbol);
+
+ pExist = 1;
+
+ if (!GOTPLTEntry) {
+ ARMPLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+ assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+
+ ARMGOT::iterator got_it = m_GOT.getNextGOTPLTEntry();
+ ARMGOT::iterator got_ie = m_GOT.getGOTPLTEnd();
+ assert(got_it != got_ie && "The number of GOTPLT and PLT doesn't match");
+
+ PLTEntry = llvm::cast<ARMPLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*got_it));
+ }
+
+ return GOTPLTEntry;
+}
+
+ARMPLT0* ARMPLT::getPLT0() const {
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, getPLT0 failed!");
+
+ ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
+
+ return plt0;
+}
+
+void ARMPLT::applyPLT0() {
+
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+
+ uint32_t offset = 0;
+
+ if (got_base > plt_base)
+ offset = got_base - (plt_base + 16);
+ else
+ offset = (plt_base + 16) - got_base;
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, applyPLT0 failed!");
+
+ ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
+
+ uint32_t* data = 0;
+ data = static_cast<uint32_t*>(malloc(plt0->getEntrySize()));
+
+ if (!data)
+ llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+
+ memcpy(data, arm_plt0, plt0->getEntrySize());
+ data[4] = offset;
+
+ plt0->setContent(reinterpret_cast<unsigned char*>(data));
+}
+
+void ARMPLT::applyPLT1() {
+
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+
+ ARMPLT::iterator it = m_SectionData.begin();
+ ARMPLT::iterator ie = m_SectionData.end();
+ assert(it!=ie && "FragmentList is empty, applyPLT1 failed!");
+
+ uint32_t GOTEntrySize = m_GOT.getEntrySize();
+ uint32_t GOTEntryAddress =
+ got_base + GOTEntrySize * 3;
+
+ uint64_t PLTEntryAddress =
+ plt_base + llvm::cast<ARMPLT0>((*it)).getEntrySize(); //Offset of PLT0
+
+ ++it; //skip PLT0
+ uint64_t PLT1EntrySize = llvm::cast<ARMPLT1>((*it)).getEntrySize();
+ ARMPLT1* plt1 = NULL;
+
+ uint32_t* Out = NULL;
+ while (it != ie) {
+ plt1 = &(llvm::cast<ARMPLT1>(*it));
+ Out = static_cast<uint32_t*>(malloc(plt1->getEntrySize()));
+
+ if (!Out)
+ llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+
+ // Offset is the distance between the last PLT entry and the associated
+ // GOT entry.
+ int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8));
+
+ Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF);
+ Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF);
+ Out[2] = arm_plt1[2] | (Offset & 0xFFF);
+
+ plt1->setContent(reinterpret_cast<unsigned char*>(Out));
+ ++it;
+
+ GOTEntryAddress += GOTEntrySize;
+ PLTEntryAddress += PLT1EntrySize;
+ }
+
+ m_GOT.applyAllGOTPLT(plt_base);
+}
+
+uint64_t ARMPLT::emit(MemoryRegion& pRegion)
+{
+ uint64_t result = 0x0;
+ iterator it = begin();
+ unsigned int plt0_size = llvm::cast<ARMPLT0>((*it)).getEntrySize();
+
+ unsigned char* buffer = pRegion.getBuffer();
+ memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getContent(), plt0_size);
+ result += plt0_size;
+ ++it;
+
+ ARMPLT1* plt1 = 0;
+ ARMPLT::iterator ie = end();
+ unsigned int entry_size = 0;
+ while (it != ie) {
+ plt1 = &(llvm::cast<ARMPLT1>(*it));
+ entry_size = plt1->getEntrySize();
+ memcpy(buffer + result, plt1->getContent(), entry_size);
+ result += entry_size;
+ ++it;
+ }
+ return result;
+}
+
diff --git a/lib/Target/ARM/ARMPLT.h b/lib/Target/ARM/ARMPLT.h
new file mode 100644
index 0000000..f55aaa3
--- /dev/null
+++ b/lib/Target/ARM/ARMPLT.h
@@ -0,0 +1,87 @@
+//===- ARMPLT.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_PLT_H
+#define MCLD_ARM_PLT_H
+
+#include <mcld/Target/PLT.h>
+
+namespace mcld {
+
+class ARMGOT;
+class GOTEntry;
+class MemoryRegion;
+
+class ARMPLT0 : public PLTEntry {
+public:
+ ARMPLT0(llvm::MCSectionData* pParent);
+};
+
+class ARMPLT1 : public PLTEntry {
+public:
+ ARMPLT1(llvm::MCSectionData* pParent);
+};
+
+/** \class ARMPLT
+ * \brief ARM Procedure Linkage Table
+ */
+class ARMPLT : public PLT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, ARMPLT1*> SymbolIndexType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ ARMPLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ ARMGOT& pGOTPLT);
+ ~ARMPLT();
+
+// Override virtual function.
+public:
+
+ // reserveEntry is ARMGOT friend function.
+ void reserveEntry(size_t pNum = 1) ;
+
+ PLTEntry* getPLTEntry(const ResolveInfo& pSymbol, bool& pExist) ;
+
+ GOTEntry* getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+public:
+ iterator begin() { return m_SectionData.begin(); }
+
+ const_iterator begin() const { return m_SectionData.begin(); }
+
+ iterator end() { return m_SectionData.end(); }
+
+ const_iterator end() const { return m_SectionData.end(); }
+
+ ARMPLT0* getPLT0() const;
+
+ void applyPLT0();
+
+ void applyPLT1();
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+private:
+ ARMGOT& m_GOT;
+
+ // Used by getEntry() for mapping a ResolveInfo
+ // instance to a PLT1 Entry.
+ iterator m_PLTEntryIterator;
+
+ SymbolIndexType m_PLTEntryMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFactory.cpp b/lib/Target/ARM/ARMRelocationFactory.cpp
new file mode 100644
index 0000000..2763b3b
--- /dev/null
+++ b/lib/Target/ARM/ARMRelocationFactory.cpp
@@ -0,0 +1,861 @@
+//===- ARMRelocationFactory.cpp ----------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Layout.h>
+
+#include "ARMRelocationFactory.h"
+#include "ARMRelocationFunctions.h"
+
+using namespace mcld;
+
+DECL_ARM_APPLY_RELOC_FUNCS
+
+//===--------------------------------------------------------------------===//
+// ARMRelocationFactory
+ARMRelocationFactory::ARMRelocationFactory(size_t pNum,
+ ARMGNULDBackend& pParent)
+ : RelocationFactory(pNum),
+ m_Target(pParent) {
+}
+
+ARMRelocationFactory::~ARMRelocationFactory()
+{
+}
+
+void ARMRelocationFactory::applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo)
+{
+ Relocation::Type type = pRelocation.type();
+ if (type > 130) { // 131-255 doesn't noted in ARM spec
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
+ "To symbol `") +
+ pRelocation.symInfo()->name() +
+ llvm::Twine("'."));
+ return;
+ }
+
+ /// the prototype of applying function
+ typedef Result (*ApplyFunctionType)(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent);
+
+ // the table entry of applying functions
+ struct ApplyFunctionTriple {
+ ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+ };
+
+ // declare the table of applying functions
+ static ApplyFunctionTriple apply_functions[] = {
+ DECL_ARM_APPLY_RELOC_FUNC_PTRS
+ };
+
+ // apply the relocation
+ Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
+
+ // check result
+ if (OK == result) {
+ return;
+ }
+ if (Overflow == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' causes overflow. on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+
+ if (BadReloc == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' encounters unexpected opcode. "
+ "on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+ if (Unsupport == result) {
+ llvm::report_fatal_error(llvm::Twine("Encounter unsupported relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+}
+
+
+
+//===--------------------------------------------------------------------===//
+// non-member functions
+static RelocationFactory::DWord getThumbBit(const Relocation& pReloc)
+{
+ // Set thumb bit if
+ // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
+ RelocationFactory::DWord thumbBit =
+ ((pReloc.symInfo()->desc() != ResolveInfo::Undefined) &&
+ (pReloc.symInfo()->type() == ResolveInfo::Function) &&
+ ((pReloc.symValue() & 0x1) != 0))?
+ 1:0;
+ return thumbBit;
+}
+
+
+
+
+//=========================================//
+// Relocation helper function //
+//=========================================//
+
+// Using uint64_t to make sure those complicate operations won't cause
+// undefined behavior.
+static
+uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width)
+{
+ assert(pOri_width <= 64);
+ uint64_t sign_bit = 1 << (pOri_width - 1);
+ return (pVal ^ sign_bit) - sign_bit;
+ // Reverse sign bit, then subtract sign bit.
+}
+
+static
+uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask)
+{
+ return (pA & ~pMask) | (pB & pMask) ;
+}
+
+// Check if symbol can use relocation R_ARM_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const ARMRelocationFactory& pFactory)
+{
+ // if symbol is dynamic or undefine or preemptible
+ if(pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym,
+ pLDInfo,
+ pLDInfo.output()))
+ return false;
+ return true;
+}
+
+static
+GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+ if (!exist) {
+ // If we first get this GOT entry, we should initialize it.
+ if (rsym->reserved() & ARMGNULDBackend::ReserveGOT) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry.setContent(pReloc.symValue());
+ }
+ else if (rsym->reserved() & ARMGNULDBackend::GOTRel) {
+
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, true, exist);
+ assert(!exist && "GOT entry not exist, but DynRel entry exist!");
+ if( rsym->isLocal() ||
+ helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ // Initialize got entry to target symbol address
+ got_entry.setContent(pReloc.symValue());
+ rel_entry.setType(llvm::ELF::R_ARM_RELATIVE);
+ rel_entry.setSymInfo(0);
+ }
+ else {
+ // Initialize got entry to 0 for corresponding dynamic relocation.
+ got_entry.setContent(0);
+ rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT);
+ rel_entry.setSymInfo(rsym);
+ }
+ rel_entry.targetRef().assign(got_entry);
+ }
+ else {
+ llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ }
+ }
+ return got_entry;
+}
+
+static
+ARMRelocationFactory::Address helper_GOT_ORG(ARMRelocationFactory& pParent)
+{
+ return pParent.getTarget().getGOT().getSection().addr();
+}
+
+
+static
+ARMRelocationFactory::Address helper_GOT(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo, pParent);
+ return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
+}
+
+
+static
+PLTEntry& helper_get_PLT_and_init(Relocation& pReloc,
+ ARMRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist);
+ if (!exist) {
+ // If we first get this PLT entry, we should initialize it.
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ GOTEntry& gotplt_entry =
+ *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist);
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelPLT().getEntry(*rsym, true, exist);
+ assert(!exist && "PLT entry not exist, but DynRel entry exist!");
+ rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT);
+ rel_entry.targetRef().assign(gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ }
+ else {
+ llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ }
+ }
+ return plt_entry;
+}
+
+
+
+static
+ARMRelocationFactory::Address helper_PLT_ORG(ARMRelocationFactory& pParent)
+{
+ return pParent.getTarget().getPLT().getSection().addr();
+}
+
+
+static
+ARMRelocationFactory::Address helper_PLT(Relocation& pReloc,
+ ARMRelocationFactory& pParent)
+{
+ PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
+ return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry);
+}
+
+// Get an relocation entry in .rel.dyn and set its type to pType,
+// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
+static
+void helper_DynRel(Relocation& pReloc,
+ ARMRelocationFactory::Type pType,
+ ARMRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMGNULDBackend& ld_backend = pParent.getTarget();
+ bool exist;
+
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+ rel_entry.setType(pType);
+ rel_entry.targetRef() = pReloc.targetRef();
+
+ if(pType == llvm::ELF::R_ARM_RELATIVE)
+ rel_entry.setSymInfo(0);
+ else
+ rel_entry.setSymInfo(rsym);
+}
+
+static ARMRelocationFactory::DWord
+helper_extract_movw_movt_addend(ARMRelocationFactory::DWord pTarget)
+{
+ // imm16: [19-16][11-0]
+ return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU),
+ 16);
+}
+
+static ARMRelocationFactory::DWord
+helper_insert_val_movw_movt_inst(ARMRelocationFactory::DWord pTarget,
+ ARMRelocationFactory::DWord pImm)
+{
+ // imm16: [19-16][11-0]
+ pTarget &= 0xfff0f000U;
+ pTarget |= pImm & 0x0fffU;
+ pTarget |= (pImm & 0xf000U) << 4;
+ return pTarget;
+}
+
+static ARMRelocationFactory::DWord
+helper_extract_thumb_movw_movt_addend(ARMRelocationFactory::DWord pTarget)
+{
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. We'd better have a thumb instruction type.
+ // imm16: [19-16][26][14-12][7-0]
+ return helper_sign_extend((((pTarget >> 4) & 0xf000U) |
+ ((pTarget >> 15) & 0x0800U) |
+ ((pTarget >> 4) & 0x0700U) |
+ (pTarget & 0x00ffU)),
+ 16);
+}
+
+static ARMRelocationFactory::DWord
+helper_insert_val_thumb_movw_movt_inst(ARMRelocationFactory::DWord pTarget,
+ ARMRelocationFactory::DWord pImm)
+{
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. We'd better have a thumb instruction type.
+ // imm16: [19-16][26][14-12][7-0]
+ pTarget &= 0xfbf08f00U;
+ pTarget |= (pImm & 0xf000U) << 4;
+ pTarget |= (pImm & 0x0800U) << 15;
+ pTarget |= (pImm & 0x0700U) << 4;
+ pTarget |= (pImm & 0x00ffU);
+ return pTarget;
+}
+
+static ARMRelocationFactory::DWord
+helper_thumb32_branch_offset(ARMRelocationFactory::DWord pUpper16,
+ ARMRelocationFactory::DWord pLower16)
+{
+ ARMRelocationFactory::DWord s = (pUpper16 & (1U << 10)) >> 10, // 26 bit
+ u = pUpper16 & 0x3ffU, // 25-16
+ l = pLower16 & 0x7ffU, // 10-0
+ j1 = (pLower16 & (1U << 13)) >> 13, // 13
+ j2 = (pLower16 & (1U << 11)) >> 11; // 11
+ ARMRelocationFactory::DWord i1 = j1 ^ s? 0: 1,
+ i2 = j2 ^ s? 0: 1;
+
+ // [31-25][24][23][22][21-12][11-1][0]
+ // 0 s i1 i2 u l 0
+ return helper_sign_extend((s << 24) | (i1 << 23) | (i2 << 22) |
+ (u << 12) | (l << 1),
+ 25);
+}
+
+static ARMRelocationFactory::DWord
+helper_thumb32_branch_upper(ARMRelocationFactory::DWord pUpper16,
+ ARMRelocationFactory::DWord pOffset)
+{
+ uint32_t sign = ((pOffset & 0x80000000U) >> 31);
+ return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10);
+}
+
+static ARMRelocationFactory::DWord
+helper_thumb32_branch_lower(ARMRelocationFactory::DWord pLower16,
+ ARMRelocationFactory::DWord pOffset)
+{
+ uint32_t sign = ((pOffset & 0x80000000U) >> 31);
+ return ((pLower16 & ~0x2fffU) |
+ ((((pOffset >> 23) & 1) ^ !sign) << 13) |
+ ((((pOffset >> 22) & 1) ^ !sign) << 11) |
+ ((pOffset >> 1) & 0x7ffU));
+}
+
+// Return true if overflow
+static bool
+helper_check_signed_overflow(ARMRelocationFactory::DWord pValue,
+ unsigned bits)
+{
+ int32_t signed_val = static_cast<int32_t>(pValue);
+ int32_t max = (1 << (bits - 1)) - 1;
+ int32_t min = -(1 << (bits - 1));
+ if (signed_val > max || signed_val < min) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+//=========================================//
+// Each relocation function implementation //
+//=========================================//
+
+// R_ARM_NONE
+ARMRelocationFactory::Result none(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_ABS32: (S + A) | T
+ARMRelocationFactory::Result abs32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::DWord S = pReloc.symValue();
+
+ if(rsym->isLocal() && (rsym->reserved() & 0x1u)) {
+ helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
+ pReloc.target() = (S + A) | T ;
+ return ARMRelocationFactory::OK;
+ }
+ else if(!rsym->isLocal()) {
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0 ; // PLT is not thumb
+ pReloc.target() = (S + A) | T;
+ }
+ // If we generate a dynamic relocation (except R_ARM_RELATIVE)
+ // for a place, we should not perform static relocation on it
+ // in order to keep the addend store in the place correct.
+ if(rsym->reserved() & 0x1u) {
+ if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
+ }
+ else {
+ helper_DynRel(pReloc, pReloc.type(), pParent);
+ return ARMRelocationFactory::OK;
+ }
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = (S + A) | T;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_REL32: ((S + A) | T) - P
+ARMRelocationFactory::Result rel32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // perform static relocation
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ pReloc.target() = ((pReloc.symValue() + A) | T)
+ - pReloc.place(pParent.getLayout());
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_BASE_PREL: B(S) + A - P
+ARMRelocationFactory::Result base_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // perform static relocation
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ pReloc.target() = pReloc.symValue() + A - pReloc.place(pParent.getLayout());
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_GOTOFF32: ((S + A) | T) - GOT_ORG
+ARMRelocationFactory::Result gotoff32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ ARMRelocationFactory::Address S = pReloc.symValue();
+
+ pReloc.target() = ((S + A) | T) - GOT_ORG;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
+ARMRelocationFactory::Result got_brel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ return ARMRelocationFactory::BadReloc;
+ }
+ ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ // Apply relocation.
+ pReloc.target() = GOT_S + A - GOT_ORG;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_GOT_PREL: GOT(S) + A - P
+ARMRelocationFactory::Result got_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ return ARMRelocationFactory::BadReloc;
+ }
+ ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
+ ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
+ // Apply relocation.
+ pReloc.target() = GOT_S + A - P;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_PLT32: ((S + A) | T) - P
+// R_ARM_JUMP24: ((S + A) | T) - P
+// R_ARM_CALL: ((S + A) | T) - P
+ARMRelocationFactory::Result call(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // TODO: Some issue have not been considered, e.g. thumb, overflow?
+
+ // If target is undefined weak symbol, we only need to jump to the
+ // next instruction unless it has PLT entry.
+ if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
+ // change target to NOP : mov r0, r0
+ pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000;
+ return ARMRelocationFactory::OK;
+ }
+
+ ARMRelocationFactory::Address S; // S dependent on exist PLT or not.
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A =
+ helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26)
+ + pReloc.addend();
+ ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
+
+ S = pReloc.symValue();
+ if( pReloc.symInfo()->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb.
+ }
+
+ ARMRelocationFactory::DWord X = ((S + A) | T) - P;
+
+ if (X & 0x03u) { // Lowest two bit is not zero.
+ llvm::report_fatal_error("Target is thumb, need stub!");
+ }
+ // Check X is 24bit sign int. If not, we should use stub or PLT before apply.
+ assert(!helper_check_signed_overflow(X, 26) && "Jump or Call target too far!");
+ // Make sure the Imm is 0. Result Mask.
+ pReloc.target() = (pReloc.target() & 0xFF000000u) | ((X & 0x03FFFFFEu) >> 2);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_THM_CALL: ((S + A) | T) - P
+ARMRelocationFactory::Result thm_call(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ // If target is undefined weak symbol, we only need to jump to the
+ // next instruction unless it has PLT entry.
+ if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
+ pReloc.target() = (0xe000U << 16) | 0xbf00U;
+ return ARMRelocationFactory::OK;
+ }
+
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. Here is an ugly solution. We'd better have a thumb
+ // instruction type.
+ //uint16_t upper16 = *(
+ // reinterpret_cast<uint16_t*>(&pReloc.target())
+ // ),
+ // lower16 = *(
+ // reinterpret_cast<uint16_t*>(&pReloc.target()) + 1
+ // );
+ ARMRelocationFactory::DWord upper16 = ((pReloc.target() & 0xffff0000U) >> 16),
+ lower16 = (pReloc.target() & 0xffffU);
+
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = helper_thumb32_branch_offset(upper16,
+ lower16);
+ ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::Address S;
+
+ S = pReloc.symValue();
+ // if symbol has plt
+ if( pReloc.symInfo()->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb.
+ }
+
+ // TODO: If the target is not thumb, we should rewrite instruction to BLX.
+
+ ARMRelocationFactory::DWord X = ((S + A) | T) - P;
+ X >>= 1;
+
+ // FIXME: Check bit size is 24(thumb2) or 22?
+ if (helper_check_signed_overflow(X, 24)) {
+ assert(!"Offset is too far. We need stub or PLT for it.");
+ return ARMRelocationFactory::Overflow;
+ }
+
+ // For a BLX instruction, make sure that the relocation is rounded up
+ // to a word boundary. This follows the semantics of the instruction
+ // which specifies that bit 1 of the target address will come from bit
+ // 1 of the base address.
+ if ((X & 0x5000U) == 0x4000U) {
+ X = (X + 2) & ~0x3U;
+ }
+
+ upper16 = helper_thumb32_branch_upper(upper16, X);
+ lower16 = helper_thumb32_branch_lower(lower16, X);
+
+ // TODO: By the rsloader experience: If we use 32bit, we need to consider
+ // endianness problem. Here is an ugly solution. We'd better have a thumb
+ // instruction type.
+ //*(reinterpret_cast<uint16_t*>(&preloc.target())) = upper16;
+ //*(reinterpret_cast<uint16_t*>(&preloc.target()) + 1) = lower16;
+ pReloc.target() = (upper16 << 16);
+ pReloc.target() |= lower16;
+
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_MOVW_ABS_NC: (S + A) | T
+ARMRelocationFactory::Result movw_abs_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0 ; // PLT is not thumb
+ }
+ X = (S + A) | T ;
+ // perform static relocation
+ pReloc.target() = (S + A) | T;
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_MOVW_PREL_NC: ((S + A) | T) - P
+ARMRelocationFactory::Result movw_prel_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = ((S + A) | T) - P;
+
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_MOVT_ABS: S + A
+ARMRelocationFactory::Result movt_abs(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ }
+
+ X = S + A;
+ X >>= 16;
+ // perform static relocation
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_MOVT_PREL: S + A - P
+ARMRelocationFactory::Result movt_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = S + A - P;
+ X >>= 16;
+
+ pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_THM_MOVW_ABS_NC: (S + A) | T
+ARMRelocationFactory::Result thm_movw_abs_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb
+ }
+ X = (S + A) | T;
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P
+ARMRelocationFactory::Result thm_movw_prel_nc(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = ((S + A) | T) - P;
+
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_THM_MOVT_ABS: S + A
+ARMRelocationFactory::Result thm_movt_abs(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ // use plt
+ if(rsym->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ }
+ X = S + A;
+ X >>= 16;
+
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_THM_MOVT_PREL: S + A - P
+ARMRelocationFactory::Result thm_movt_prel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = S + A - P;
+ X >>= 16;
+
+ // check 16-bit overflow
+ if (helper_check_signed_overflow(X, 16)) {
+ return ARMRelocationFactory::Overflow;
+ } else {
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+ }
+}
+
+// R_ARM_PREL31: (S + A) | T
+ARMRelocationFactory::Result prel31(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::DWord target = pReloc.target();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord A = helper_sign_extend(target, 31) +
+ pReloc.addend();
+ ARMRelocationFactory::Address S;
+
+ S = pReloc.symValue();
+ // if symbol has plt
+ if( pReloc.symInfo()->reserved() & 0x8u) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb.
+ }
+
+ ARMRelocationFactory::DWord X = (S + A) | T ;
+ pReloc.target() = helper_bit_select(target, X, 0x7fffffffU);
+ if(helper_check_signed_overflow(X, 31))
+ return ARMRelocationFactory::Overflow;
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_TLS_GD32: GOT(S) + A - P
+// R_ARM_TLS_IE32: GOT(S) + A - P
+// R_ARM_TLS_LE32: S + A - tp
+ARMRelocationFactory::Result tls(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ llvm::report_fatal_error("We don't support TLS relocation yet.");
+ return ARMRelocationFactory::Unsupport;
+}
+
+ARMRelocationFactory::Result unsupport(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ return ARMRelocationFactory::Unsupport;
+}
diff --git a/lib/Target/ARM/ARMRelocationFactory.h b/lib/Target/ARM/ARMRelocationFactory.h
new file mode 100644
index 0000000..636dbee
--- /dev/null
+++ b/lib/Target/ARM/ARMRelocationFactory.h
@@ -0,0 +1,59 @@
+//===- ARMRelocationFactory.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ARM_RELOCATION_FACTORY_H
+#define ARM_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Target/GOT.h>
+#include "ARMLDBackend.h"
+
+namespace mcld
+{
+
+/** \class ARMRelocationFactory
+ * \brief ARMRelocationFactory creates and destroys the ARM relocations.
+ *
+ */
+class ARMRelocationFactory : public RelocationFactory
+{
+public:
+ /** \enum Reloc
+ * \brief Reloc is the result of applying functions.
+ */
+ enum Result
+ {
+ OK,
+ Overflow,
+ BadReloc,
+ Unsupport
+ };
+
+public:
+ ARMRelocationFactory(size_t pNum, ARMGNULDBackend& pParent);
+ ~ARMRelocationFactory();
+
+ void applyRelocation(Relocation& pRelocation, const MCLDInfo& pLDInfo);
+
+ ARMGNULDBackend& getTarget()
+ { return m_Target; }
+
+ const ARMGNULDBackend& getTarget() const
+ { return m_Target; }
+
+private:
+ ARMGNULDBackend& m_Target;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFunctions.h b/lib/Target/ARM/ARMRelocationFunctions.h
new file mode 100644
index 0000000..10d27a4
--- /dev/null
+++ b/lib/Target/ARM/ARMRelocationFunctions.h
@@ -0,0 +1,169 @@
+//===- ARMRelocationFunction.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DECL_ARM_APPLY_RELOC_FUNC(Name) \
+static ARMRelocationFactory::Result Name (Relocation& pEntry, \
+ const MCLDInfo& pLDInfo, \
+ ARMRelocationFactory& pParent);
+
+#define DECL_ARM_APPLY_RELOC_FUNCS \
+DECL_ARM_APPLY_RELOC_FUNC(none) \
+DECL_ARM_APPLY_RELOC_FUNC(abs32) \
+DECL_ARM_APPLY_RELOC_FUNC(rel32) \
+DECL_ARM_APPLY_RELOC_FUNC(gotoff32) \
+DECL_ARM_APPLY_RELOC_FUNC(base_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(got_brel) \
+DECL_ARM_APPLY_RELOC_FUNC(call) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_call) \
+DECL_ARM_APPLY_RELOC_FUNC(movw_prel_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(movw_abs_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(movt_abs) \
+DECL_ARM_APPLY_RELOC_FUNC(movt_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movw_abs_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movw_prel_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movt_abs) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movt_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(prel31) \
+DECL_ARM_APPLY_RELOC_FUNC(got_prel) \
+DECL_ARM_APPLY_RELOC_FUNC(tls) \
+DECL_ARM_APPLY_RELOC_FUNC(unsupport)
+
+
+#define DECL_ARM_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_ARM_NONE" }, \
+ { &unsupport, 1, "R_ARM_PC24" }, \
+ { &abs32, 2, "R_ARM_ABS32" }, \
+ { &rel32, 3, "R_ARM_REL32" }, \
+ { &unsupport, 4, "R_ARM_LDR_PC_G0" }, \
+ { &unsupport, 5, "R_ARM_ABS16" }, \
+ { &unsupport, 6, "R_ARM_ABS12" }, \
+ { &unsupport, 7, "R_ARM_THM_ABS5" }, \
+ { &unsupport, 8, "R_ARM_ABS8" }, \
+ { &unsupport, 9, "R_ARM_SBREL32" }, \
+ { &thm_call, 10, "R_ARM_THM_CALL" }, \
+ { &unsupport, 11, "R_ARM_THM_PC8" }, \
+ { &unsupport, 12, "R_ARM_BREL_ADJ" }, \
+ { &unsupport, 13, "R_ARM_TLS_DESC" }, \
+ { &unsupport, 14, "R_ARM_THM_SWI8" }, \
+ { &unsupport, 15, "R_ARM_XPC25" }, \
+ { &unsupport, 16, "R_ARM_THM_XPC22" }, \
+ { &unsupport, 17, "R_ARM_TLS_DTPMOD32" }, \
+ { &unsupport, 18, "R_ARM_TLS_DTPOFF32" }, \
+ { &unsupport, 19, "R_ARM_TLS_TPOFF32" }, \
+ { &unsupport, 20, "R_ARM_COPY" }, \
+ { &unsupport, 21, "R_ARM_GLOB_DAT" }, \
+ { &unsupport, 22, "R_ARM_JUMP_SLOT" }, \
+ { &unsupport, 23, "R_ARM_RELATIVE" }, \
+ { &gotoff32, 24, "R_ARM_GOTOFF32" }, \
+ { &base_prel, 25, "R_ARM_BASE_PREL" }, \
+ { &got_brel, 26, "R_ARM_GOT_BREL" }, \
+ { &call, 27, "R_ARM_PLT32" }, \
+ { &call, 28, "R_ARM_CALL" }, \
+ { &call, 29, "R_ARM_JUMP24" }, \
+ { &unsupport, 30, "R_ARM_THM_JUMP24" }, \
+ { &unsupport, 31, "R_ARM_BASE_ABS" }, \
+ { &unsupport, 32, "R_ARM_ALU_PCREL_7_0" }, \
+ { &unsupport, 33, "R_ARM_ALU_PCREL_15_8" }, \
+ { &unsupport, 34, "R_ARM_ALU_PCREL_23_15" }, \
+ { &unsupport, 35, "R_ARM_LDR_SBREL_11_0_NC" }, \
+ { &unsupport, 36, "R_ARM_ALU_SBREL_19_12_NC"}, \
+ { &unsupport, 37, "R_ARM_ALU_SBREL_27_20_CK"}, \
+ { &abs32, 38, "R_ARM_TARGET1" }, \
+ { &unsupport, 39, "R_ARM_SBREL31" }, \
+ { &unsupport, 40, "R_ARM_V4BX" }, \
+ { &got_prel, 41, "R_ARM_TARGET2" }, \
+ { &prel31, 42, "R_ARM_PREL31" }, \
+ { &movw_abs_nc, 43, "R_ARM_MOVW_ABS_NC" }, \
+ { &movt_abs, 44, "R_ARM_MOVT_ABS" }, \
+ { &movw_prel_nc, 45, "R_ARM_MOVW_PREL_NC" }, \
+ { &movt_prel, 46, "R_ARM_MOVT_PREL" }, \
+ { &thm_movw_abs_nc, 47, "R_ARM_THM_MOVW_ABS_NC" }, \
+ { &thm_movt_abs, 48, "R_ARM_THM_MOVT_ABS" }, \
+ { &thm_movw_prel_nc, 49, "R_ARM_THM_MOVW_PREL_NC" }, \
+ { &thm_movt_prel, 50, "R_ARM_THM_MOVT_PREL" }, \
+ { &unsupport, 51, "R_ARM_THM_JUMP19" }, \
+ { &unsupport, 52, "R_ARM_THM_JUMP6" }, \
+ { &unsupport, 53, "R_ARM_THM_ALU_PREL_11_0" }, \
+ { &unsupport, 54, "R_ARM_THM_PC12" }, \
+ { &unsupport, 55, "R_ARM_ABS32_NOI" }, \
+ { &unsupport, 56, "R_ARM_REL32_NOI" }, \
+ { &unsupport, 57, "R_ARM_ALU_PC_G0_NC" }, \
+ { &unsupport, 58, "R_ARM_ALU_PC_G0" }, \
+ { &unsupport, 59, "R_ARM_ALU_PC_G1_NC" }, \
+ { &unsupport, 60, "R_ARM_ALU_PC_G1" }, \
+ { &unsupport, 61, "R_ARM_ALU_PC_G2" }, \
+ { &unsupport, 62, "R_ARM_LDR_PC_G1" }, \
+ { &unsupport, 63, "R_ARM_LDR_PC_G2" }, \
+ { &unsupport, 64, "R_ARM_LDRS_PC_G0" }, \
+ { &unsupport, 65, "R_ARM_LDRS_PC_G1" }, \
+ { &unsupport, 66, "R_ARM_LDRS_PC_G2" }, \
+ { &unsupport, 67, "R_ARM_LDC_PC_G0" }, \
+ { &unsupport, 68, "R_ARM_LDC_PC_G1" }, \
+ { &unsupport, 69, "R_ARM_LDC_PC_G2" }, \
+ { &unsupport, 70, "R_ARM_ALU_SB_G0_NC" }, \
+ { &unsupport, 71, "R_ARM_ALU_SB_G0" }, \
+ { &unsupport, 72, "R_ARM_ALU_SB_G1_NC" }, \
+ { &unsupport, 73, "R_ARM_ALU_SB_G1" }, \
+ { &unsupport, 74, "R_ARM_ALU_SB_G2" }, \
+ { &unsupport, 75, "R_ARM_LDR_SB_G0" }, \
+ { &unsupport, 76, "R_ARM_LDR_SB_G1" }, \
+ { &unsupport, 77, "R_ARM_LDR_SB_G2" }, \
+ { &unsupport, 78, "R_ARM_LDRS_SB_G0" }, \
+ { &unsupport, 79, "R_ARM_LDRS_SB_G1" }, \
+ { &unsupport, 80, "R_ARM_LDRS_SB_G2" }, \
+ { &unsupport, 81, "R_ARM_LDC_SB_G0" }, \
+ { &unsupport, 82, "R_ARM_LDC_SB_G1" }, \
+ { &unsupport, 83, "R_ARM_LDC_SB_G2" }, \
+ { &unsupport, 84, "R_ARM_MOVW_BREL_NC" }, \
+ { &unsupport, 85, "R_ARM_MOVT_BREL" }, \
+ { &unsupport, 86, "R_ARM_MOVW_BREL" }, \
+ { &unsupport, 87, "R_ARM_THM_MOVW_BREL_NC" }, \
+ { &unsupport, 88, "R_ARM_THM_MOVT_BREL" }, \
+ { &unsupport, 89, "R_ARM_THM_MOVW_BREL" }, \
+ { &unsupport, 90, "R_ARM_TLS_GOTDESC" }, \
+ { &unsupport, 91, "R_ARM_TLS_CALL" }, \
+ { &unsupport, 92, "R_ARM_TLS_DESCSEQ" }, \
+ { &unsupport, 93, "R_ARM_THM_TLS_CALL" }, \
+ { &unsupport, 94, "R_ARM_PLT32_ABS" }, \
+ { &unsupport, 95, "R_ARM_GOT_ABS" }, \
+ { &got_prel, 96, "R_ARM_GOT_PREL" }, \
+ { &unsupport, 97, "R_ARM_GOT_PREL12" }, \
+ { &unsupport, 98, "R_ARM_GOTOFF12" }, \
+ { &unsupport, 99, "R_ARM_GOTRELAX" }, \
+ { &unsupport, 100, "R_ARM_GNU_VTENTRY" }, \
+ { &unsupport, 101, "R_ARM_GNU_VTINERIT" }, \
+ { &unsupport, 102, "R_ARM_THM_JUMP11" }, \
+ { &unsupport, 103, "R_ARM_THM_JUMP8" }, \
+ { &tls, 104, "R_ARM_TLS_GD32" }, \
+ { &unsupport, 105, "R_ARM_TLS_LDM32" }, \
+ { &unsupport, 106, "R_ARM_TLS_LDO32" }, \
+ { &tls, 107, "R_ARM_TLS_IE32" }, \
+ { &tls, 108, "R_ARM_TLS_LE32" }, \
+ { &unsupport, 109, "R_ARM_TLS_LDO12" }, \
+ { &unsupport, 110, "R_ARM_TLS_LE12" }, \
+ { &unsupport, 111, "R_ARM_TLS_IE12GP" }, \
+ { &unsupport, 112, "R_ARM_PRIVATE_0" }, \
+ { &unsupport, 113, "R_ARM_PRIVATE_1" }, \
+ { &unsupport, 114, "R_ARM_PRIVATE_2" }, \
+ { &unsupport, 115, "R_ARM_PRIVATE_3" }, \
+ { &unsupport, 116, "R_ARM_PRIVATE_4" }, \
+ { &unsupport, 117, "R_ARM_PRIVATE_5" }, \
+ { &unsupport, 118, "R_ARM_PRIVATE_6" }, \
+ { &unsupport, 119, "R_ARM_PRIVATE_7" }, \
+ { &unsupport, 120, "R_ARM_PRIVATE_8" }, \
+ { &unsupport, 121, "R_ARM_PRIVATE_9" }, \
+ { &unsupport, 122, "R_ARM_PRIVATE_10" }, \
+ { &unsupport, 123, "R_ARM_PRIVATE_11" }, \
+ { &unsupport, 124, "R_ARM_PRIVATE_12" }, \
+ { &unsupport, 125, "R_ARM_PRIVATE_13" }, \
+ { &unsupport, 126, "R_ARM_PRIVATE_14" }, \
+ { &unsupport, 127, "R_ARM_PRIVATE_15" }, \
+ { &unsupport, 128, "R_ARM_ME_TOO" }, \
+ { &unsupport, 129, "R_ARM_THM_TLS_DESCSEQ16" }, \
+ { &unsupport, 130, "R_ARM_THM_TLS_DESCSEQ32" }
diff --git a/lib/Target/ARM/ARMSectLinker.cpp b/lib/Target/ARM/ARMSectLinker.cpp
new file mode 100644
index 0000000..d686060
--- /dev/null
+++ b/lib/Target/ARM/ARMSectLinker.cpp
@@ -0,0 +1,47 @@
+//===- ARMSectLinker.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/TargetRegistry.h>
+#include "ARM.h"
+#include "ARMAndroidSectLinker.h"
+#include "ARMELFSectLinker.h"
+
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// createARMSectLinker - the help function to create corresponding ARMSectLinker
+//
+SectLinker* createARMSectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ }
+
+ // For now, use Android SectLinker directly
+ return new ARMAndroidSectLinker(pOption,
+ pLDBackend);
+}
+
+} // namespace of mcld
+
+//==========================
+// ARMSectLinker
+extern "C" void LLVMInitializeARMSectLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterSectLinker(TheARMTarget, createARMSectLinker);
+}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
new file mode 100644
index 0000000..530a610
--- /dev/null
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -0,0 +1,33 @@
+//===- ARMTargetMachine.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ARMTargetMachine.h"
+
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/MC/MCLDInfo.h"
+#include "ARM.h"
+
+extern "C" void LLVMInitializeARMLDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::ARMBaseTargetMachine> X(mcld::TheARMTarget);
+}
+
+mcld::ARMBaseTargetMachine::ARMBaseTargetMachine(llvm::TargetMachine& pPM,
+ const mcld::Target &pTarget,
+ const std::string& pTriple)
+ : mcld::LLVMTargetMachine(pPM, pTarget, pTriple) {
+ // arg1 - the number of total attributes
+ // arg2 - the most possible number of input files
+ m_pLDInfo = new MCLDInfo(pTriple, 32, 64);
+}
+
+mcld::ARMBaseTargetMachine::~ARMBaseTargetMachine()
+{
+ delete m_pLDInfo;
+}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h
new file mode 100644
index 0000000..19f8aa2
--- /dev/null
+++ b/lib/Target/ARM/ARMTargetMachine.h
@@ -0,0 +1,40 @@
+//===- ARMTargetMachine.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_ARM_TARGET_MACHINE_H
+#define MCLD_ARM_TARGET_MACHINE_H
+#include "mcld/Target/TargetMachine.h"
+#include "ARM.h"
+
+namespace mcld
+{
+
+class ARMBaseTargetMachine : public LLVMTargetMachine
+{
+protected:
+ MCLDInfo *m_pLDInfo;
+
+public:
+ ARMBaseTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+
+ virtual ~ARMBaseTargetMachine();
+
+ mcld::MCLDInfo& getLDInfo()
+ { return *m_pLDInfo; }
+
+ const mcld::MCLDInfo& getLDInfo() const
+ { return *m_pLDInfo; }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/ARM/Android.mk b/lib/Target/ARM/Android.mk
new file mode 100644
index 0000000..272e9f4
--- /dev/null
+++ b/lib/Target/ARM/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_arm_target_SRC_FILES := \
+ ARMAndroidSectLinker.cpp \
+ ARMELFDynamic.cpp \
+ ARMELFSectLinker.cpp \
+ ARMGOT.cpp \
+ ARMLDBackend.cpp \
+ ARMPLT.cpp \
+ ARMRelocationFactory.cpp \
+ ARMSectLinker.cpp \
+ ARMTargetMachine.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_target_SRC_FILES)
+LOCAL_MODULE:= libmcldARMTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),arm)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_target_SRC_FILES)
+LOCAL_MODULE:= libmcldARMTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/ARM/README b/lib/Target/ARM/README
new file mode 100644
index 0000000..ea88bfe
--- /dev/null
+++ b/lib/Target/ARM/README
@@ -0,0 +1,2 @@
+ARMLDBackend stands like ARMAsmBackend. It's a backend of linker,
+and all target-dependent behavior and data are here.
diff --git a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
new file mode 100644
index 0000000..7e6a41a
--- /dev/null
+++ b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
@@ -0,0 +1,22 @@
+//===- ARMTargetInfo.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Support/TargetRegistry.h"
+
+namespace mcld {
+
+mcld::Target TheARMTarget;
+
+extern "C" void LLVMInitializeARMLDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget X(TheARMTarget, "arm" );
+}
+
+} // namespace of mcld
+
diff --git a/lib/Target/ARM/TargetInfo/Android.mk b/lib/Target/ARM/TargetInfo/Android.mk
new file mode 100644
index 0000000..c4fffa3
--- /dev/null
+++ b/lib/Target/ARM/TargetInfo/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_arm_info_SRC_FILES := \
+ ARMTargetInfo.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_info_SRC_FILES)
+LOCAL_MODULE:= libmcldARMInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),arm)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_arm_info_SRC_FILES)
+LOCAL_MODULE:= libmcldARMInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/Android.mk b/lib/Target/Android.mk
new file mode 100644
index 0000000..8e6e260
--- /dev/null
+++ b/lib/Target/Android.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_target_SRC_FILES := \
+ AndroidSectLinker.cpp \
+ ELFDynamic.cpp \
+ GNULDBackend.cpp \
+ GOT.cpp \
+ OutputRelocSection.cpp \
+ PLT.cpp \
+ Stub.cpp \
+ Target.cpp \
+ TargetLDBackend.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_target_SRC_FILES)
+LOCAL_MODULE:= libmcldTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_target_SRC_FILES)
+LOCAL_MODULE:= libmcldTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/lib/Target/AndroidSectLinker.cpp b/lib/Target/AndroidSectLinker.cpp
new file mode 100644
index 0000000..8f3acbf
--- /dev/null
+++ b/lib/Target/AndroidSectLinker.cpp
@@ -0,0 +1,45 @@
+//===- AndroidSectLinker.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/Target/AndroidSectLinker.h>
+
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/MC/MCLDDirectory.h>
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+//==========================
+// AndroidSectLinker
+
+AndroidSectLinker::AndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption, pLDBackend) {
+}
+
+AndroidSectLinker::~AndroidSectLinker()
+{
+ // SectLinker will delete m_pLDBackend and m_pLDDriver;
+}
+
+void AndroidSectLinker::addTargetOptions(llvm::Module &pM,
+ SectLinkerOption &pOption)
+{
+ // ----- Set up General Options ----- //
+ MCLDInfo &info = pOption.info();
+ MCLDDirectory search_path("=/system/lib");
+ search_path.setSysroot(info.options().sysroot());
+ if (exists(search_path.path()) && is_directory(search_path.path()))
+ info.options().directories().add(search_path);
+ else {
+ // FIXME: need a warning function
+ llvm::errs() << "WARNING: can not open search directory: `-L" << search_path.name() << "'.\n";
+ }
+}
+
diff --git a/lib/Target/DarwinLDBackend.cpp b/lib/Target/DarwinLDBackend.cpp
new file mode 100644
index 0000000..5bd55c3
--- /dev/null
+++ b/lib/Target/DarwinLDBackend.cpp
@@ -0,0 +1,15 @@
+//===- DarwinLDBackend.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <DarwinLDBackend.h>
+
+using namespace mcld;
+
+//==========================
+// DarwinLDBackend
+
diff --git a/lib/Target/ELFDynamic.cpp b/lib/Target/ELFDynamic.cpp
new file mode 100644
index 0000000..b863ab1
--- /dev/null
+++ b/lib/Target/ELFDynamic.cpp
@@ -0,0 +1,257 @@
+//===- ELFDynamic.cpp ------------- ------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/Host.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Target/ELFDynamic.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/Support/MemoryRegion.h>
+
+using namespace mcld;
+using namespace elf_dynamic;
+
+//===----------------------------------------------------------------------===//
+// elf_dynamic::EntryIF
+EntryIF::EntryIF()
+{
+}
+
+EntryIF::~EntryIF()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// ELFDynamic
+ELFDynamic::ELFDynamic(const GNULDBackend& pParent)
+ : m_pEntryFactory(NULL), m_Idx(0) {
+ if (32 == pParent.bitclass() && pParent.isLittleEndian()) {
+ m_pEntryFactory = new Entry<32, true>();
+ }
+ // FIXME: support big-endian and 64-bit machine.
+}
+
+
+ELFDynamic::~ELFDynamic()
+{
+ if (NULL != m_pEntryFactory)
+ delete m_pEntryFactory;
+
+ EntryListType::iterator entry, entryEnd = m_EntryList.end();
+ for (entry = m_EntryList.begin(); entry != entryEnd; ++entry) {
+ if (NULL != *entry)
+ delete (*entry);
+ }
+
+ entryEnd = m_NeedList.end();
+ for (entry = m_NeedList.begin(); entry != entryEnd; ++entry) {
+ if (NULL != *entry)
+ delete (*entry);
+ }
+}
+
+size_t ELFDynamic::size() const
+{
+ return (m_NeedList.size() + m_EntryList.size());
+}
+
+size_t ELFDynamic::numOfBytes() const
+{
+ return size()*entrySize();
+}
+
+size_t ELFDynamic::entrySize() const
+{
+ return m_pEntryFactory->size();
+}
+
+void ELFDynamic::reserveOne(uint64_t pTag)
+{
+ assert(NULL != m_pEntryFactory);
+ m_EntryList.push_back(new elf_dynamic::Entry<32, true>());
+}
+
+void ELFDynamic::applyOne(uint64_t pTag, uint64_t pValue)
+{
+ assert(m_Idx < m_EntryList.size());
+ m_EntryList[m_Idx]->setValue(pTag, pValue);
+ ++m_Idx;
+}
+
+
+/// reserveEntries - reserve entries
+void ELFDynamic::reserveEntries(const MCLDInfo& pLDInfo,
+ const ELFFileFormat& pFormat)
+{
+ if (pLDInfo.output().type() == Output::DynObj) {
+ reserveOne(llvm::ELF::DT_SONAME); // DT_SONAME
+
+ if (pLDInfo.options().Bsymbolic())
+ reserveOne(llvm::ELF::DT_SYMBOLIC); // DT_SYMBOLIC
+ }
+
+ if (pFormat.hasInit())
+ reserveOne(llvm::ELF::DT_INIT); // DT_INIT
+
+ if (pFormat.hasFini())
+ reserveOne(llvm::ELF::DT_FINI); // DT_FINI
+
+ if (pFormat.hasInitArray()) {
+ reserveOne(llvm::ELF::DT_INIT_ARRAY); // DT_INIT_ARRAY
+ reserveOne(llvm::ELF::DT_INIT_ARRAYSZ); // DT_INIT_ARRAYSZ
+ }
+
+ if (pFormat.hasFiniArray()) {
+ reserveOne(llvm::ELF::DT_FINI_ARRAY); // DT_FINI_ARRAY
+ reserveOne(llvm::ELF::DT_FINI_ARRAYSZ); // DT_FINI_ARRAYSZ
+ }
+
+ if (pFormat.hasHashTab())
+ reserveOne(llvm::ELF::DT_HASH); // DT_HASH
+
+ if (pFormat.hasDynSymTab()) {
+ reserveOne(llvm::ELF::DT_SYMTAB); // DT_SYMTAB
+ reserveOne(llvm::ELF::DT_SYMENT); // DT_SYMENT
+ }
+
+ if (pFormat.hasDynStrTab()) {
+ reserveOne(llvm::ELF::DT_STRTAB); // DT_STRTAB
+ reserveOne(llvm::ELF::DT_STRSZ); // DT_STRSZ
+ }
+
+ reserveTargetEntries(pFormat); // DT_PLTGOT
+
+ if (pFormat.hasRelPlt() || pFormat.hasRelaPlt())
+ reserveOne(llvm::ELF::DT_PLTREL); // DT_PLTREL
+
+ if (pFormat.hasPLT()) {
+ reserveOne(llvm::ELF::DT_JMPREL); // DT_JMPREL
+ reserveOne(llvm::ELF::DT_PLTRELSZ); // DT_PLTRELSZ
+ }
+
+ if (pFormat.hasRelDyn()) {
+ reserveOne(llvm::ELF::DT_REL); // DT_REL
+ reserveOne(llvm::ELF::DT_RELSZ); // DT_RELSZ
+ reserveOne(llvm::ELF::DT_RELENT); // DT_RELENT
+ }
+
+ if (pFormat.hasRelaDyn()) {
+ reserveOne(llvm::ELF::DT_RELA); // DT_RELA
+ reserveOne(llvm::ELF::DT_RELASZ); // DT_RELASZ
+ reserveOne(llvm::ELF::DT_RELAENT); // DT_RELAENT
+ }
+ reserveOne(llvm::ELF::DT_NULL); // for DT_NULL
+}
+
+/// applyEntries - apply entries
+void ELFDynamic::applyEntries(const MCLDInfo& pInfo,
+ const ELFFileFormat& pFormat)
+{
+ if (pInfo.output().type() == Output::DynObj &&
+ pInfo.options().Bsymbolic()) {
+ applyOne(llvm::ELF::DT_SYMBOLIC, 0x0); // DT_SYMBOLIC
+ }
+
+ if (pFormat.hasInit())
+ applyOne(llvm::ELF::DT_INIT, pFormat.getInit().addr()); // DT_INIT
+
+ if (pFormat.hasFini())
+ applyOne(llvm::ELF::DT_FINI, pFormat.getFini().addr()); // DT_FINI
+
+ if (pFormat.hasInitArray()) {
+ // DT_INIT_ARRAY
+ applyOne(llvm::ELF::DT_INIT_ARRAY, pFormat.getInitArray().addr());
+
+ // DT_INIT_ARRAYSZ
+ applyOne(llvm::ELF::DT_INIT_ARRAYSZ, pFormat.getInitArray().size());
+ }
+
+ if (pFormat.hasFiniArray()) {
+ // DT_FINI_ARRAY
+ applyOne(llvm::ELF::DT_FINI_ARRAY, pFormat.getFiniArray().addr());
+
+ // DT_FINI_ARRAYSZ
+ applyOne(llvm::ELF::DT_FINI_ARRAYSZ, pFormat.getFiniArray().size());
+ }
+
+ if (pFormat.hasHashTab())
+ applyOne(llvm::ELF::DT_HASH, pFormat.getHashTab().addr()); // DT_HASH
+
+ if (pFormat.hasDynSymTab()) {
+ applyOne(llvm::ELF::DT_SYMTAB, pFormat.getDynSymTab().addr()); // DT_SYMTAB
+ applyOne(llvm::ELF::DT_SYMENT, symbolSize()); // DT_SYMENT
+ }
+
+ if (pFormat.hasDynStrTab()) {
+ applyOne(llvm::ELF::DT_STRTAB, pFormat.getDynStrTab().addr()); // DT_STRTAB
+ applyOne(llvm::ELF::DT_STRSZ, pFormat.getDynStrTab().size()); // DT_STRSZ
+ }
+
+ applyTargetEntries(pFormat); // DT_PLTGOT
+
+ if (pFormat.hasRelPlt())
+ applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_REL); // DT_PLTREL
+ else if (pFormat.hasRelaPlt())
+ applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_RELA); // DT_PLTREL
+
+ if (pFormat.hasRelPlt()) {
+ applyOne(llvm::ELF::DT_JMPREL, pFormat.getRelPlt().addr()); // DT_JMPREL
+ applyOne(llvm::ELF::DT_PLTRELSZ, pFormat.getRelPlt().size()); // DT_PLTRELSZ
+ }
+
+ if (pFormat.hasRelDyn()) {
+ applyOne(llvm::ELF::DT_REL, pFormat.getRelDyn().addr()); // DT_REL
+ applyOne(llvm::ELF::DT_RELSZ, pFormat.getRelDyn().size()); // DT_RELSZ
+ applyOne(llvm::ELF::DT_RELENT, m_pEntryFactory->relSize()); // DT_RELENT
+ }
+
+ if (pFormat.hasRelaDyn()) {
+ applyOne(llvm::ELF::DT_RELA, pFormat.getRelaDyn().addr()); // DT_RELA
+ applyOne(llvm::ELF::DT_RELASZ, pFormat.getRelaDyn().size()); // DT_RELASZ
+ applyOne(llvm::ELF::DT_RELAENT, m_pEntryFactory->relaSize()); // DT_RELAENT
+ }
+
+ applyOne(llvm::ELF::DT_NULL, 0x0); // for DT_NULL
+}
+
+/// symbolSize
+size_t ELFDynamic::symbolSize() const
+{
+ return m_pEntryFactory->symbolSize();
+}
+
+/// reserveNeedEntry - reserve on DT_NEED entry.
+void ELFDynamic::reserveNeedEntry()
+{
+ m_NeedList.push_back(m_pEntryFactory->clone());
+}
+
+/// emit
+void ELFDynamic::emit(const LDSection& pSection, MemoryRegion& pRegion) const
+{
+ if (pRegion.size() < pSection.size()) {
+ llvm::report_fatal_error(llvm::Twine("the given memory is smaller") +
+ llvm::Twine(" than the section's demaind.\n"));
+ }
+
+ uint8_t* address = (uint8_t*)pRegion.start();
+ EntryListType::const_iterator entry, entryEnd = m_NeedList.end();
+ for (entry = m_NeedList.begin(); entry != entryEnd; ++entry)
+ address += (*entry)->emit(address);
+
+ entryEnd = m_EntryList.end();
+ for (entry = m_EntryList.begin(); entry != entryEnd; ++entry)
+ address += (*entry)->emit(address);
+}
+
+void ELFDynamic::applySoname(uint64_t pStrTabIdx)
+{
+ applyOne(llvm::ELF::DT_SONAME, pStrTabIdx); // DT_SONAME
+}
+
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
new file mode 100644
index 0000000..b82af73
--- /dev/null
+++ b/lib/Target/GNULDBackend.cpp
@@ -0,0 +1,1021 @@
+//===- GNULDBackend.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/SymbolCategory.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <string>
+#include <cstring>
+#include <cassert>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// GNULDBackend
+GNULDBackend::GNULDBackend()
+ : m_pArchiveReader(0),
+ m_pObjectReader(0),
+ m_pDynObjReader(0),
+ m_pObjectWriter(0),
+ m_pDynObjWriter(0),
+ m_pDynObjFileFormat(0),
+ m_pExecFileFormat(0),
+ m_ELFSegmentTable(9)// magic number
+{
+ m_pSymIndexMap = new HashTableType(1024);
+}
+
+GNULDBackend::~GNULDBackend()
+{
+ if (m_pArchiveReader)
+ delete m_pArchiveReader;
+ if (m_pObjectReader)
+ delete m_pObjectReader;
+ if (m_pDynObjReader)
+ delete m_pDynObjReader;
+ if (m_pObjectWriter)
+ delete m_pObjectWriter;
+ if (m_pDynObjWriter)
+ delete m_pDynObjWriter;
+ if (m_pDynObjFileFormat)
+ delete m_pDynObjFileFormat;
+ if (m_pExecFileFormat)
+ delete m_pExecFileFormat;
+ if(m_pSymIndexMap)
+ delete m_pSymIndexMap;
+}
+
+size_t GNULDBackend::sectionStartOffset() const
+{
+ // FIXME: use fixed offset, we need 10 segments by default
+ return sizeof(llvm::ELF::Elf64_Ehdr)+10*sizeof(llvm::ELF::Elf64_Phdr);
+}
+
+bool GNULDBackend::initArchiveReader(MCLinker&, MCLDInfo &pInfo)
+{
+ if (0 == m_pArchiveReader)
+ {
+ LDReader::Endian isLittleEndian = LDReader::LittleEndian;
+ m_pArchiveReader = new GNUArchiveReader(pInfo, isLittleEndian);
+ }
+ return true;
+}
+
+bool GNULDBackend::initObjectReader(MCLinker& pLinker)
+{
+ if (0 == m_pObjectReader)
+ m_pObjectReader = new ELFObjectReader(*this, pLinker);
+ return true;
+}
+
+bool GNULDBackend::initDynObjReader(MCLinker& pLinker)
+{
+ if (0 == m_pDynObjReader)
+ m_pDynObjReader = new ELFDynObjReader(*this, pLinker);
+ return true;
+}
+
+bool GNULDBackend::initObjectWriter(MCLinker&)
+{
+ // TODO
+ return true;
+}
+
+bool GNULDBackend::initDynObjWriter(MCLinker& pLinker)
+{
+ if (0 == m_pDynObjWriter)
+ m_pDynObjWriter = new ELFDynObjWriter(*this, pLinker);
+ return true;
+}
+
+bool GNULDBackend::initExecSections(MCLinker& pMCLinker)
+{
+ if (0 == m_pExecFileFormat)
+ m_pExecFileFormat = new ELFExecFileFormat(*this);
+
+ // initialize standard sections
+ m_pExecFileFormat->initStdSections(pMCLinker);
+ return true;
+}
+
+bool GNULDBackend::initDynObjSections(MCLinker& pMCLinker)
+{
+ if (0 == m_pDynObjFileFormat)
+ m_pDynObjFileFormat = new ELFDynObjFileFormat(*this);
+
+ // initialize standard sections
+ m_pDynObjFileFormat->initStdSections(pMCLinker);
+ return true;
+}
+
+bool GNULDBackend::initStandardSymbols(MCLinker& pLinker)
+{
+ return true;
+}
+
+GNUArchiveReader *GNULDBackend::getArchiveReader()
+{
+ assert(0 != m_pArchiveReader);
+ return m_pArchiveReader;
+}
+
+GNUArchiveReader *GNULDBackend::getArchiveReader() const
+{
+ assert(0 != m_pArchiveReader);
+ return m_pArchiveReader;
+}
+
+ELFObjectReader *GNULDBackend::getObjectReader()
+{
+ assert(0 != m_pObjectReader);
+ return m_pObjectReader;
+}
+
+ELFObjectReader *GNULDBackend::getObjectReader() const
+{
+ assert(0 != m_pObjectReader);
+ return m_pObjectReader;
+}
+
+ELFDynObjReader *GNULDBackend::getDynObjReader()
+{
+ assert(0 != m_pDynObjReader);
+ return m_pDynObjReader;
+}
+
+ELFDynObjReader *GNULDBackend::getDynObjReader() const
+{
+ assert(0 != m_pDynObjReader);
+ return m_pDynObjReader;
+}
+
+ELFObjectWriter *GNULDBackend::getObjectWriter()
+{
+ // TODO
+ return NULL;
+}
+
+ELFObjectWriter *GNULDBackend::getObjectWriter() const
+{
+ // TODO
+ return NULL;
+}
+
+ELFDynObjWriter *GNULDBackend::getDynObjWriter()
+{
+ assert(0 != m_pDynObjWriter);
+ return m_pDynObjWriter;
+}
+
+ELFDynObjWriter *GNULDBackend::getDynObjWriter() const
+{
+ assert(0 != m_pDynObjWriter);
+ return m_pDynObjWriter;
+}
+
+ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat()
+{
+ assert(0 != m_pDynObjFileFormat);
+ return m_pDynObjFileFormat;
+}
+
+ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const
+{
+ assert(0 != m_pDynObjFileFormat);
+ return m_pDynObjFileFormat;
+}
+
+ELFExecFileFormat* GNULDBackend::getExecFileFormat()
+{
+ assert(0 != m_pExecFileFormat);
+ return m_pExecFileFormat;
+}
+
+ELFExecFileFormat* GNULDBackend::getExecFileFormat() const
+{
+ assert(0 != m_pExecFileFormat);
+ return m_pExecFileFormat;
+}
+
+/// sizeNamePools - compute the size of regular name pools
+/// In ELF executable files, regular name pools are .symtab, .strtab,
+/// .dynsym, .dynstr, and .hash
+void
+GNULDBackend::sizeNamePools(const Output& pOutput,
+ const SymbolCategory& pSymbols,
+ const MCLDInfo& pLDInfo)
+{
+ // size of string tables starts from 1 to hold the null character in their
+ // first byte
+ size_t symtab = 1;
+ size_t dynsym = 1;
+ // number of entries in symbol tables starts from 1 to hold the special entry
+ // at index 0 (STN_UNDEF). See ELF Spec Book I, p1-21.
+ size_t strtab = 1;
+ size_t dynstr = 1;
+ size_t hash = 0;
+
+ // compute size of .symtab, .dynsym and .strtab
+ SymbolCategory::const_iterator symbol;
+ SymbolCategory::const_iterator symEnd = pSymbols.end();
+ for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
+ size_t str_size = (*symbol)->nameSize() + 1;
+ if (isDynamicSymbol(**symbol, pOutput)) {
+ ++dynsym;
+ dynstr += str_size;
+ }
+ ++symtab;
+ strtab += str_size;
+ }
+
+ ELFFileFormat* file_format = NULL;
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // TODO: not support yet
+ return;
+ }
+
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ case Output::Exec: {
+ // add DT_NEED strings into .dynstr and .dynamic
+ // Rules:
+ // 1. ignore --no-add-needed
+ // 2. force count in --no-as-needed
+ // 3. judge --as-needed
+ InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
+ for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
+ if (Input::DynObj == (*input)->type()) {
+ // --add-needed
+ if ((*input)->attribute()->isAddNeeded()) {
+ // --no-as-needed
+ if (!(*input)->attribute()->isAsNeeded()) {
+ dynstr += (*input)->name().size() + 1;
+ dynamic().reserveNeedEntry();
+ }
+ // --as-needed
+ else if ((*input)->isNeeded()) {
+ dynstr += (*input)->name().size() + 1;
+ dynamic().reserveNeedEntry();
+ }
+ }
+ }
+ } // for
+
+ // compute .hash
+ // Both Elf32_Word and Elf64_Word are 4 bytes
+ hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
+ sizeof(llvm::ELF::Elf32_Word);
+
+ // set size
+ dynstr += pOutput.name().size() + 1;
+ if (32 == bitclass())
+ file_format->getDynSymTab().setSize(dynsym*sizeof(llvm::ELF::Elf32_Sym));
+ else
+ file_format->getDynSymTab().setSize(dynsym*sizeof(llvm::ELF::Elf64_Sym));
+ file_format->getDynStrTab().setSize(dynstr);
+ file_format->getHashTab().setSize(hash);
+
+ }
+ /* fall through */
+ case Output::Object: {
+ if (32 == bitclass())
+ file_format->getSymTab().setSize(symtab*sizeof(llvm::ELF::Elf32_Sym));
+ else
+ file_format->getSymTab().setSize(symtab*sizeof(llvm::ELF::Elf64_Sym));
+ file_format->getStrTab().setSize(strtab);
+ break;
+ }
+ } // end of switch
+
+ // reserve fixed entries in the .dynamic section.
+ if (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type()) {
+ // Because some entries in .dynamic section need information of .dynsym,
+ // .dynstr, .symtab, .strtab and .hash, we can not reserve non-DT_NEEDED
+ // entries until we get the size of the sections mentioned above
+ dynamic().reserveEntries(pLDInfo, *file_format);
+ file_format->getDynamic().setSize(dynamic().numOfBytes());
+ }
+}
+
+/// emitRegNamePools - emit regular name pools - .symtab, .strtab
+///
+/// the size of these tables should be computed before layout
+/// layout should computes the start offset of these tables
+void GNULDBackend::emitRegNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo)
+{
+
+ assert(pOutput.hasMemArea());
+
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+
+ ELFFileFormat* file_format = NULL;
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // add first symbol into m_pSymIndexMap
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(0);
+
+ // TODO: not support yet
+ return;
+ }
+
+ LDSection& symtab_sect = file_format->getSymTab();
+ LDSection& strtab_sect = file_format->getStrTab();
+
+ MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
+ strtab_sect.size());
+
+ // set up symtab_region
+ llvm::ELF::Elf32_Sym* symtab32 = NULL;
+ llvm::ELF::Elf64_Sym* symtab64 = NULL;
+ if (32 == bitclass())
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+ else if (64 == bitclass())
+ symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
+ else
+ llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") +
+ llvm::Twine(bitclass()) +
+ llvm::Twine(".\n"));
+ // set up strtab_region
+ char* strtab = (char*)strtab_region->start();
+ strtab[0] = '\0';
+
+ // initialize the first ELF symbol
+ if (32 == bitclass()) {
+ symtab32[0].st_name = 0;
+ symtab32[0].st_value = 0;
+ symtab32[0].st_size = 0;
+ symtab32[0].st_info = 0;
+ symtab32[0].st_other = 0;
+ symtab32[0].st_shndx = 0;
+ }
+ else { // must 64
+ symtab64[0].st_name = 0;
+ symtab64[0].st_value = 0;
+ symtab64[0].st_size = 0;
+ symtab64[0].st_info = 0;
+ symtab64[0].st_other = 0;
+ symtab64[0].st_shndx = 0;
+ }
+
+ size_t symtabIdx = 1;
+ size_t strtabsize = 1;
+ // compute size of .symtab, .dynsym and .strtab
+ SymbolCategory::iterator symbol;
+ SymbolCategory::iterator symEnd = pSymbols.end();
+ for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
+
+ // maintain output's symbol and index map if building .o file
+ if (Output::Object == pOutput.type()) {
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(symtabIdx);
+ }
+
+ // FIXME: check the endian between host and target
+ // write out symbol
+ if (32 == bitclass()) {
+ symtab32[symtabIdx].st_name = strtabsize;
+ symtab32[symtabIdx].st_value = getSymbolValue(**symbol);
+ symtab32[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab32[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab32[symtabIdx].st_other = (*symbol)->visibility();
+ symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ else { // must 64
+ symtab64[symtabIdx].st_name = strtabsize;
+ symtab64[symtabIdx].st_value = getSymbolValue(**symbol);
+ symtab64[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab64[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab64[symtabIdx].st_other = (*symbol)->visibility();
+ symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ // write out string
+ strcpy((strtab + strtabsize), (*symbol)->name());
+
+ // write out
+ // sum up counters
+ ++symtabIdx;
+ strtabsize += (*symbol)->nameSize() + 1;
+ }
+}
+
+/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+///
+/// the size of these tables should be computed before layout
+/// layout should computes the start offset of these tables
+void GNULDBackend::emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.hasMemArea());
+ ELFFileFormat* file_format = NULL;
+
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+
+ switch(pOutput.type()) {
+ // compute size of .dynstr and .hash
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // TODO: not support yet
+ return;
+ }
+
+ LDSection& symtab_sect = file_format->getDynSymTab();
+ LDSection& strtab_sect = file_format->getDynStrTab();
+ LDSection& hash_sect = file_format->getHashTab();
+ LDSection& dyn_sect = file_format->getDynamic();
+
+ MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
+ strtab_sect.size());
+ MemoryRegion* hash_region = pOutput.memArea()->request(hash_sect.offset(),
+ hash_sect.size());
+ MemoryRegion* dyn_region = pOutput.memArea()->request(dyn_sect.offset(),
+ dyn_sect.size());
+ // set up symtab_region
+ llvm::ELF::Elf32_Sym* symtab32 = NULL;
+ llvm::ELF::Elf64_Sym* symtab64 = NULL;
+ if (32 == bitclass())
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+ else if (64 == bitclass())
+ symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
+ else
+ llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") +
+ llvm::Twine(bitclass()) +
+ llvm::Twine(".\n"));
+
+ // initialize the first ELF symbol
+ if (32 == bitclass()) {
+ symtab32[0].st_name = 0;
+ symtab32[0].st_value = 0;
+ symtab32[0].st_size = 0;
+ symtab32[0].st_info = 0;
+ symtab32[0].st_other = 0;
+ symtab32[0].st_shndx = 0;
+ }
+ else { // must 64
+ symtab64[0].st_name = 0;
+ symtab64[0].st_value = 0;
+ symtab64[0].st_size = 0;
+ symtab64[0].st_info = 0;
+ symtab64[0].st_other = 0;
+ symtab64[0].st_shndx = 0;
+ }
+ // set up strtab_region
+ char* strtab = (char*)strtab_region->start();
+ strtab[0] = '\0';
+
+ // add the first symbol into m_pSymIndexMap
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(0);
+
+ size_t symtabIdx = 1;
+ size_t strtabsize = 1;
+
+ // emit of .dynsym, and .dynstr
+ SymbolCategory::iterator symbol;
+ SymbolCategory::iterator symEnd = pSymbols.end();
+ for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
+ if (!isDynamicSymbol(**symbol, pOutput))
+ continue;
+
+ // maintain output's symbol and index map
+ entry = m_pSymIndexMap->insert(*symbol, sym_exist);
+ entry->setValue(symtabIdx);
+
+ // FIXME: check the endian between host and target
+ // write out symbol
+ if (32 == bitclass()) {
+ symtab32[symtabIdx].st_name = strtabsize;
+ symtab32[symtabIdx].st_value = (*symbol)->value();
+ symtab32[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab32[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab32[symtabIdx].st_other = (*symbol)->visibility();
+ symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ else { // must 64
+ symtab64[symtabIdx].st_name = strtabsize;
+ symtab64[symtabIdx].st_value = (*symbol)->value();
+ symtab64[symtabIdx].st_size = getSymbolSize(**symbol);
+ symtab64[symtabIdx].st_info = getSymbolInfo(**symbol);
+ symtab64[symtabIdx].st_other = (*symbol)->visibility();
+ symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
+ }
+ // write out string
+ strcpy((strtab + strtabsize), (*symbol)->name());
+
+ // sum up counters
+ ++symtabIdx;
+ strtabsize += (*symbol)->nameSize() + 1;
+ }
+
+ // emit DT_NEED
+ // add DT_NEED strings into .dynstr
+ // Rules:
+ // 1. ignore --no-add-needed
+ // 2. force count in --no-as-needed
+ // 3. judge --as-needed
+ ELFDynamic::iterator dt_need = dynamic().needBegin();
+ InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
+ for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
+ if (Input::DynObj == (*input)->type()) {
+ // --add-needed
+ if ((*input)->attribute()->isAddNeeded()) {
+ // --no-as-needed
+ if (!(*input)->attribute()->isAsNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ // --as-needed
+ else if ((*input)->isNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ }
+ }
+ } // for
+
+ // emit soname
+ // initialize value of ELF .dynamic section
+ dynamic().applySoname(strtabsize);
+ dynamic().applyEntries(pLDInfo, *file_format);
+ dynamic().emit(dyn_sect, *dyn_region);
+
+ strcpy((strtab + strtabsize), pOutput.name().c_str());
+ strtabsize += pOutput.name().size() + 1;
+
+ // emit hash table
+ // FIXME: this verion only emit SVR4 hash section.
+ // Please add GNU new hash section
+
+ // both 32 and 64 bits hash table use 32-bit entry
+ // set up hash_region
+ uint32_t* word_array = (uint32_t*)hash_region->start();
+ uint32_t& nbucket = word_array[0];
+ uint32_t& nchain = word_array[1];
+
+ nbucket = getHashBucketCount(symtabIdx, false);
+ nchain = symtabIdx;
+
+ uint32_t* bucket = (word_array + 2);
+ uint32_t* chain = (bucket + nbucket);
+
+ // initialize bucket
+ bzero((void*)bucket, nbucket);
+
+ StringHash<ELF> hash_func;
+
+ if (32 == bitclass()) {
+ for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
+ llvm::StringRef name(strtab + symtab32[sym_idx].st_name);
+ size_t bucket_pos = hash_func(name) % nbucket;
+ chain[sym_idx] = bucket[bucket_pos];
+ bucket[bucket_pos] = sym_idx;
+ }
+ }
+ else if (64 == bitclass()) {
+ for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
+ llvm::StringRef name(strtab + symtab64[sym_idx].st_name);
+ size_t bucket_pos = hash_func(name) % nbucket;
+ chain[sym_idx] = bucket[bucket_pos];
+ bucket[bucket_pos] = sym_idx;
+ }
+ }
+}
+
+/// getSectionOrder
+unsigned int GNULDBackend::getSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ // NULL section should be the "1st" section
+ if (LDFileFormat::Null == pSectHdr.kind())
+ return 0;
+
+ // if the section is not ALLOC, lay it out until the last possible moment
+ if (0 == (pSectHdr.flag() & llvm::ELF::SHF_ALLOC))
+ return SHO_UNDEFINED;
+
+ bool is_write = (pSectHdr.flag() & llvm::ELF::SHF_WRITE) != 0;
+ bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0;
+ ELFFileFormat* file_format = NULL;
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ assert(0 && "Not support yet.\n");
+ break;
+ }
+
+ // TODO: need to take care other possible output sections
+ switch (pSectHdr.kind()) {
+ case LDFileFormat::Regular:
+ if (is_exec) {
+ if (&pSectHdr == &file_format->getInit())
+ return SHO_INIT;
+ if (&pSectHdr == &file_format->getFini())
+ return SHO_FINI;
+ return SHO_TEXT;
+ } else if (!is_write) {
+ return SHO_RO;
+ } else {
+ if (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY ||
+ &pSectHdr == &file_format->getCtors() ||
+ &pSectHdr == &file_format->getDtors())
+ return SHO_RELRO;
+
+ return SHO_DATA;
+ }
+
+ case LDFileFormat::BSS:
+ return SHO_BSS;
+
+ case LDFileFormat::NamePool:
+ if (&pSectHdr == &file_format->getDynamic())
+ return SHO_RELRO;
+ return SHO_NAMEPOOL;
+
+ case LDFileFormat::Relocation:
+ if (&pSectHdr == &file_format->getRelPlt() ||
+ &pSectHdr == &file_format->getRelaPlt())
+ return SHO_REL_PLT;
+ return SHO_RELOCATION;
+
+ // get the order from target for target specific sections
+ case LDFileFormat::Target:
+ return getTargetSectionOrder(pOutput, pSectHdr);
+
+ // handle .interp
+ case LDFileFormat::Note:
+ return SHO_INTERP;
+
+ case LDFileFormat::Exception:
+ return SHO_EHFRAME;
+
+ case LDFileFormat::MetaData:
+ case LDFileFormat::Debug:
+ default:
+ return SHO_UNDEFINED;
+ }
+}
+
+/// getSymbolSize
+uint64_t GNULDBackend::getSymbolSize(const LDSymbol& pSymbol) const
+{
+ // @ref Google gold linker: symtab.cc: 2780
+ // undefined and dynamic symbols should have zero size.
+ if (pSymbol.isDyn() || pSymbol.desc() == ResolveInfo::Undefined)
+ return 0x0;
+ return pSymbol.resolveInfo()->size();
+}
+
+/// getSymbolInfo
+uint64_t GNULDBackend::getSymbolInfo(const LDSymbol& pSymbol) const
+{
+ // set binding
+ uint8_t bind = 0x0;
+ if (pSymbol.resolveInfo()->isLocal())
+ bind = llvm::ELF::STB_LOCAL;
+ else if (pSymbol.resolveInfo()->isGlobal())
+ bind = llvm::ELF::STB_GLOBAL;
+ else if (pSymbol.resolveInfo()->isWeak())
+ bind = llvm::ELF::STB_WEAK;
+ else if (pSymbol.resolveInfo()->isAbsolute()) {
+ // (Luba) Is a absolute but not global (weak or local) symbol meaningful?
+ bind = llvm::ELF::STB_GLOBAL;
+ }
+
+ if (pSymbol.visibility() == llvm::ELF::STV_INTERNAL ||
+ pSymbol.visibility() == llvm::ELF::STV_HIDDEN)
+ bind = llvm::ELF::STB_LOCAL;
+
+ return (pSymbol.resolveInfo()->type() | (bind << 4));
+}
+
+/// getSymbolValue - this function is called after layout()
+uint64_t GNULDBackend::getSymbolValue(const LDSymbol& pSymbol) const
+{
+ if (pSymbol.isDyn())
+ return 0x0;
+
+ return pSymbol.value();
+}
+
+/// getSymbolShndx - this function is called after layout()
+uint64_t
+GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol, const Layout& pLayout) const
+{
+ if (pSymbol.resolveInfo()->isAbsolute())
+ return llvm::ELF::SHN_ABS;
+ if (pSymbol.resolveInfo()->isCommon())
+ return llvm::ELF::SHN_COMMON;
+ if (pSymbol.resolveInfo()->isUndef() || pSymbol.isDyn())
+ return llvm::ELF::SHN_UNDEF;
+
+ if (pSymbol.resolveInfo()->isLocal()) {
+ switch (pSymbol.type()) {
+ case ResolveInfo::NoType:
+ case ResolveInfo::File:
+ return llvm::ELF::SHN_ABS;
+ }
+ }
+
+ assert(pSymbol.hasFragRef());
+ return pLayout.getOutputLDSection(*pSymbol.fragRef()->frag())->index();
+}
+
+/// getSymbolIdx - called by emitRelocation to get the ouput symbol table index
+size_t GNULDBackend::getSymbolIdx(LDSymbol* pSymbol) const
+{
+ HashTableType::iterator entry = m_pSymIndexMap->find(pSymbol);
+ return entry.getEntry()->value();
+}
+
+/// emitProgramHdrs - emit ELF program headers
+void GNULDBackend::emitProgramHdrs(Output& pOutput)
+{
+ assert(NULL != pOutput.context());
+ createProgramHdrs(*pOutput.context());
+
+ if (32 == bitclass())
+ writeELF32ProgramHdrs(pOutput);
+ else
+ writeELF64ProgramHdrs(pOutput);
+}
+
+/// createProgramHdrs - base on output sections to create the program headers
+void GNULDBackend::createProgramHdrs(LDContext& pContext)
+{
+ // make PT_PHDR
+ m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR);
+
+ // make PT_INTERP
+ LDSection* interp = pContext.getSection(".interp");
+ if (NULL != interp) {
+ ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP);
+ interp_seg->addSection(interp);
+ interp_seg->setAlign(bitclass() / 8);
+ }
+
+ uint32_t cur_seg_flag, prev_seg_flag = getSegmentFlag(0);
+ uint64_t padding = 0;
+ ELFSegment* load_seg = NULL;
+ // make possible PT_LOAD segments
+ LDContext::sect_iterator sect, sect_end = pContext.sectEnd();
+ for (sect = pContext.sectBegin(); sect != sect_end; ++sect) {
+ if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) &&
+ LDFileFormat::Null != (*sect)->kind())
+ continue;
+
+ // FIXME: Now only separate writable and non-writable PT_LOAD
+ cur_seg_flag = getSegmentFlag((*sect)->flag());
+ if ((prev_seg_flag & llvm::ELF::PF_W) ^ (cur_seg_flag & llvm::ELF::PF_W) ||
+ LDFileFormat::Null == (*sect)->kind()) {
+ // create new PT_LOAD segment
+ load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD);
+ load_seg->setAlign(pagesize());
+
+ // check if this segment needs padding
+ padding = 0;
+ if (((*sect)->offset() & (load_seg->align() - 1)) != 0)
+ padding = load_seg->align();
+ }
+
+ assert(NULL != load_seg);
+ load_seg->addSection(*sect);
+ load_seg->updateFlag(cur_seg_flag);
+
+ // FIXME: set section's vma
+ // need to handle start vma for user-defined one or for executable.
+ (*sect)->setAddr((*sect)->offset() + padding);
+
+ prev_seg_flag = cur_seg_flag;
+ }
+
+ // make PT_DYNAMIC
+ LDSection* dynamic = pContext.getSection(".dynamic");
+ if (NULL != dynamic) {
+ ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC);
+ dyn_seg->setFlag(llvm::ELF::PF_R | llvm::ELF::PF_W);
+ dyn_seg->addSection(dynamic);
+ dyn_seg->setAlign(bitclass() / 8);
+ }
+
+ // update segment info
+ uint64_t file_size = 0;
+ ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end();
+ for (seg = m_ELFSegmentTable.begin(); seg != seg_end; ++seg) {
+ ELFSegment& segment = *seg;
+
+ // update PT_PHDR
+ if (llvm::ELF::PT_PHDR == segment.type()) {
+ uint64_t offset, phdr_size;
+ if (32 == bitclass()) {
+ offset = sizeof(llvm::ELF::Elf32_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
+ }
+ else {
+ offset = sizeof(llvm::ELF::Elf64_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
+ }
+ segment.setOffset(offset);
+ segment.setVaddr(offset);
+ segment.setPaddr(segment.vaddr());
+ segment.setFilesz(numOfSegments() * phdr_size);
+ segment.setMemsz(numOfSegments() * phdr_size);
+ segment.setAlign(bitclass() / 8);
+ continue;
+ }
+
+ assert(NULL != segment.getFirstSection());
+ segment.setOffset(segment.getFirstSection()->offset());
+ segment.setVaddr(segment.getFirstSection()->addr());
+ segment.setPaddr(segment.vaddr());
+
+ const LDSection* last_sect = segment.getLastSection();
+ assert(NULL != last_sect);
+ file_size = last_sect->offset() - segment.offset();
+ if (LDFileFormat::BSS != last_sect->kind())
+ file_size += last_sect->size();
+ segment.setFilesz(file_size);
+
+ segment.setMemsz(last_sect->addr() - segment.vaddr() + last_sect->size());
+ }
+}
+
+/// writeELF32ProgramHdrs - write out the ELF32 program headers
+void GNULDBackend::writeELF32ProgramHdrs(Output& pOutput)
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(llvm::ELF::Elf32_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ numOfSegments()*phdr_size);
+
+ llvm::ELF::Elf32_Phdr* phdr = (llvm::ELF::Elf32_Phdr*)region->start();
+
+ size_t index = 0;
+ ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
+ for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
+ phdr[index].p_type = (*seg).type();
+ phdr[index].p_flags = (*seg).flag();
+ phdr[index].p_offset = (*seg).offset();
+ phdr[index].p_vaddr = (*seg).vaddr();
+ phdr[index].p_paddr = (*seg).paddr();
+ phdr[index].p_filesz = (*seg).filesz();
+ phdr[index].p_memsz = (*seg).memsz();
+ phdr[index].p_align = (*seg).align();
+ }
+}
+
+/// writeELF64ProgramHdrs - write out the ELF64 program headers
+void GNULDBackend::writeELF64ProgramHdrs(Output& pOutput)
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(llvm::ELF::Elf64_Ehdr);
+ phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ numOfSegments() *phdr_size);
+ llvm::ELF::Elf64_Phdr* phdr = (llvm::ELF::Elf64_Phdr*)region->start();
+
+ size_t index = 0;
+ ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
+ for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
+ phdr[index].p_type = (*seg).type();
+ phdr[index].p_flags = (*seg).flag();
+ phdr[index].p_offset = (*seg).offset();
+ phdr[index].p_vaddr = (*seg).vaddr();
+ phdr[index].p_paddr = (*seg).paddr();
+ phdr[index].p_filesz = (*seg).filesz();
+ phdr[index].p_memsz = (*seg).memsz();
+ phdr[index].p_align = (*seg).align();
+ }
+}
+
+/// preLayout - Backend can do any needed modification before layout
+void GNULDBackend::preLayout(const Output& pOutput,
+ const MCLDInfo& pLDInfo,
+ MCLinker& pLinker)
+{
+ // prelayout target first
+ doPreLayout(pOutput, pLDInfo, pLinker);
+}
+
+/// postLayout -Backend can do any needed modification after layout
+void GNULDBackend::postLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // post layout target first
+ doPostLayout(pOutput, pInfo, pLinker);
+}
+
+/// getHashBucketCount - calculate hash bucket count.
+/// @ref Google gold linker, dynobj.cc:791
+unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols,
+ bool pIsGNUStyle)
+{
+ // @ref Google gold, dynobj.cc:loc 791
+ static const unsigned int buckets[] =
+ {
+ 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147
+ };
+ const unsigned buckets_count = sizeof buckets / sizeof buckets[0];
+
+ unsigned int result = 1;
+ for (unsigned i = 0; i < buckets_count; ++i) {
+ if (pNumOfSymbols < buckets[i])
+ break;
+ result = buckets[i];
+ }
+
+ if (pIsGNUStyle && result < 2)
+ result = 2;
+
+ return result;
+}
+
+/// isDynamicSymbol
+/// @ref Google gold linker: symtab.cc:311
+bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol,
+ const Output& pOutput)
+{
+ // If a local symbol is in the LDContext's symbol table, it's a real local
+ // symbol. We should not add it
+ if (pSymbol.binding() == ResolveInfo::Local)
+ return false;
+
+ // If we are building shared object, and the visibility is external, we
+ // need to add it.
+ if (Output::DynObj == pOutput.type())
+ if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default ||
+ pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected)
+ return true;
+
+ return false;
+}
diff --git a/lib/Target/GOT.cpp b/lib/Target/GOT.cpp
new file mode 100644
index 0000000..a05b574
--- /dev/null
+++ b/lib/Target/GOT.cpp
@@ -0,0 +1,45 @@
+//===- GOT.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/GOT.h>
+#include <cstring>
+#include <cstdlib>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// GOTEntry
+GOTEntry::GOTEntry(uint64_t pContent, size_t pEntrySize,
+ llvm::MCSectionData* pParent)
+ : MCTargetFragment(llvm::MCFragment::FT_Target, pParent),
+ f_Content(pContent), m_EntrySize(pEntrySize) {
+}
+
+GOTEntry::~GOTEntry()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// GOT
+GOT::GOT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ size_t pEntrySize)
+ : m_Section(pSection),
+ m_SectionData(pSectionData),
+ f_EntrySize(pEntrySize) {
+}
+
+GOT::~GOT()
+{
+}
+
+size_t GOT::getEntrySize() const
+{
+ return f_EntrySize;
+}
+
diff --git a/lib/Target/Mips/Android.mk b/lib/Target/Mips/Android.mk
new file mode 100644
index 0000000..cc5a211
--- /dev/null
+++ b/lib/Target/Mips/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_mips_target_SRC_FILES := \
+ MipsAndroidSectLinker.cpp \
+ MipsELFDynamic.cpp \
+ MipsELFSectLinker.cpp \
+ MipsGOT.cpp \
+ MipsLDBackend.cpp \
+ MipsRelocationFactory.cpp \
+ MipsSectLinker.cpp \
+ MipsTargetMachine.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_target_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),mips)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_target_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsTarget
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h
new file mode 100644
index 0000000..a63be45
--- /dev/null
+++ b/lib/Target/Mips/Mips.h
@@ -0,0 +1,20 @@
+//===- Mips.h -------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MIPS_H
+#define MCLD_MIPS_H
+
+#include "mcld/Support/TargetRegistry.h"
+
+namespace mcld {
+
+extern mcld::Target TheMipselTarget;
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.cpp b/lib/Target/Mips/MipsAndroidSectLinker.cpp
new file mode 100644
index 0000000..e697fbc
--- /dev/null
+++ b/lib/Target/Mips/MipsAndroidSectLinker.cpp
@@ -0,0 +1,33 @@
+//===- MipsAndroidSectLinker.cpp ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsAndroidSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+MipsAndroidSectLinker::MipsAndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : AndroidSectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().disableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().unsetWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+}
+
+MipsAndroidSectLinker::~MipsAndroidSectLinker()
+{
+}
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.h b/lib/Target/Mips/MipsAndroidSectLinker.h
new file mode 100644
index 0000000..ba216e4
--- /dev/null
+++ b/lib/Target/Mips/MipsAndroidSectLinker.h
@@ -0,0 +1,36 @@
+//===- MipsAndroidSectLinker.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_ANDROIDSECTLINKER_H
+#define MIPS_ANDROIDSECTLINKER_H
+
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Target/AndroidSectLinker.h"
+
+namespace mcld
+{
+
+/** \class MipsAndroidSectLinker
+ * \brief MipsAndroidSectLinker sets up the environment for linking.
+ *
+ */
+class MipsAndroidSectLinker : public AndroidSectLinker
+{
+public:
+ MipsAndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~MipsAndroidSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsELFDynamic.cpp b/lib/Target/Mips/MipsELFDynamic.cpp
new file mode 100644
index 0000000..cd692ac
--- /dev/null
+++ b/lib/Target/Mips/MipsELFDynamic.cpp
@@ -0,0 +1,90 @@
+//===- MipsELFDynamic.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/LD/ELFFileFormat.h>
+#include <mcld/Target/GNULDBackend.h>
+#include "MipsELFDynamic.h"
+#include "MipsLDBackend.h"
+
+using namespace mcld;
+
+// MIPS mandatory dynamic section entries
+enum {
+ MIPS_RLD_VERSION = 0x70000001,
+ MIPS_FLAGS = 0x70000005,
+ MIPS_BASE_ADDRESS = 0x70000006,
+ MIPS_LOCAL_GOTNO = 0x7000000a,
+ MIPS_SYMTABNO = 0x70000011,
+ MIPS_GOTSYM = 0x70000013,
+};
+
+MipsELFDynamic::MipsELFDynamic(const MipsGNULDBackend& pParent)
+ : ELFDynamic(pParent),
+ m_pParent(pParent)
+{
+}
+
+MipsELFDynamic::~MipsELFDynamic()
+{
+}
+
+void MipsELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (pFormat.hasGOT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+
+ reserveOne(MIPS_RLD_VERSION);
+ reserveOne(MIPS_FLAGS);
+ reserveOne(MIPS_BASE_ADDRESS);
+ reserveOne(MIPS_LOCAL_GOTNO);
+ reserveOne(MIPS_SYMTABNO);
+ reserveOne(MIPS_GOTSYM);
+}
+
+void MipsELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (pFormat.hasGOT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+
+ applyOne(MIPS_RLD_VERSION, 1);
+ applyOne(MIPS_FLAGS, 0);
+ applyOne(MIPS_BASE_ADDRESS, 0);
+ applyOne(MIPS_LOCAL_GOTNO, getLocalGotNum(pFormat));
+ applyOne(MIPS_SYMTABNO, getSymTabNum(pFormat));
+ applyOne(MIPS_GOTSYM, getGotSym(pFormat));
+}
+
+size_t MipsELFDynamic::getSymTabNum(const ELFFileFormat& pFormat) const
+{
+ if (!pFormat.hasDynSymTab())
+ return 0;
+
+ const LDSection& dynsym = pFormat.getDynSymTab();
+ return dynsym.size() / symbolSize();
+}
+
+size_t MipsELFDynamic::getGotSym(const ELFFileFormat& pFormat) const
+{
+ if (!pFormat.hasGOT())
+ return 0;
+
+ return getSymTabNum(pFormat) -
+ m_pParent.getGOT().getTotalNum() +
+ m_pParent.getGOT().getLocalNum();
+}
+
+size_t MipsELFDynamic::getLocalGotNum(const ELFFileFormat& pFormat) const
+{
+ if (!pFormat.hasGOT())
+ return 0;
+
+ return m_pParent.getGOT().getLocalNum();
+}
diff --git a/lib/Target/Mips/MipsELFDynamic.h b/lib/Target/Mips/MipsELFDynamic.h
new file mode 100644
index 0000000..118e4f9
--- /dev/null
+++ b/lib/Target/Mips/MipsELFDynamic.h
@@ -0,0 +1,41 @@
+//===- MipsELFDynamic.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_Mips_ELFDYNAMIC_SECTION_H
+#define MCLD_Mips_ELFDYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class MipsGNULDBackend;
+
+class MipsELFDynamic : public ELFDynamic
+{
+public:
+ MipsELFDynamic(const MipsGNULDBackend& pParent);
+ ~MipsELFDynamic();
+
+private:
+ const MipsGNULDBackend& m_pParent;
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+
+ size_t getSymTabNum(const ELFFileFormat& pFormat) const;
+ size_t getGotSym(const ELFFileFormat& pFormat) const;
+ size_t getLocalGotNum(const ELFFileFormat& pFormat) const;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsELFSectLinker.cpp b/lib/Target/Mips/MipsELFSectLinker.cpp
new file mode 100644
index 0000000..aa41f36
--- /dev/null
+++ b/lib/Target/Mips/MipsELFSectLinker.cpp
@@ -0,0 +1,33 @@
+//===- MipsELFSectLinker.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsELFSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+MipsELFSectLinker::MipsELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().enableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().setWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+}
+
+MipsELFSectLinker::~MipsELFSectLinker()
+{
+}
diff --git a/lib/Target/Mips/MipsELFSectLinker.h b/lib/Target/Mips/MipsELFSectLinker.h
new file mode 100644
index 0000000..82bec4c
--- /dev/null
+++ b/lib/Target/Mips/MipsELFSectLinker.h
@@ -0,0 +1,34 @@
+//===- MipsELFSectLinker.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_ELFSECTLINKER_H
+#define MIPS_ELFSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+/** \class MipsELFSectLinker
+ * \brief MipsELFSectLinker sets up the environment for linking.
+ */
+class MipsELFSectLinker : public SectLinker
+{
+public:
+ MipsELFSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~MipsELFSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Mips/MipsGOT.cpp b/lib/Target/Mips/MipsGOT.cpp
new file mode 100644
index 0000000..f9d5bb4
--- /dev/null
+++ b/lib/Target/Mips/MipsGOT.cpp
@@ -0,0 +1,148 @@
+//===- MipsGOT.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/Support/MemoryRegion.h>
+#include "MipsGOT.h"
+
+namespace {
+ const size_t MipsGOTEntrySize = 4;
+ const size_t MipsGOT0Num = 1;
+}
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// MipsGOT
+MipsGOT::MipsGOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, MipsGOTEntrySize),
+ m_pLocalNum(0)
+{
+ // Create GOT0 entries.
+ for (size_t i = 0; i < MipsGOT0Num; ++i) {
+ GOTEntry* entry =
+ new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
+
+ if (NULL == entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (size_t i = 1; i < MipsGOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_LocalGOTIterator = it;
+ m_GlobalGOTIterator = it;
+ m_pLocalNum = MipsGOT0Num;
+}
+
+MipsGOT::iterator MipsGOT::begin()
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+MipsGOT::iterator MipsGOT::end()
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+MipsGOT::const_iterator MipsGOT::begin() const
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+MipsGOT::const_iterator MipsGOT::end() const
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+uint64_t MipsGOT::emit(MemoryRegion& pRegion)
+{
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ size_t entry_size = getEntrySize();
+
+ uint64_t result = 0;
+ for (iterator it = begin(), ie = end();
+ it != ie; ++it, ++buffer) {
+ GOTEntry* got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ result += entry_size;
+ }
+ return result;
+}
+
+void MipsGOT::reserveEntry(size_t pNum)
+{
+ for (size_t i = 0; i < pNum; ++i) {
+ GOTEntry* entry =
+ new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
+
+ if (NULL == entry)
+ llvm::report_fatal_error("Allocating new GOTEntry failed");
+
+ m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
+ }
+}
+
+void MipsGOT::reserveLocalEntry()
+{
+ reserveEntry(1);
+ ++m_pLocalNum;
+
+ // Move global entries iterator forward.
+ // We need to put global GOT entries after all local ones.
+ ++m_GlobalGOTIterator;
+}
+
+void MipsGOT::reserveGlobalEntry()
+{
+ reserveEntry(1);
+}
+
+GOTEntry* MipsGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
+{
+ GOTEntry*& entry = m_GeneralGOTMap[&pInfo];
+
+ pExist = NULL != entry;
+
+ if (!pExist) {
+ iterator& it = pInfo.isLocal() ? m_LocalGOTIterator : m_GlobalGOTIterator;
+
+ ++it;
+
+ assert(it != m_SectionData.getFragmentList().end() &&
+ "The number of GOT Entries and ResolveInfo doesn't match");
+
+ entry = llvm::cast<GOTEntry>(&(*it));
+ }
+
+ return entry;
+}
+
+size_t MipsGOT::getTotalNum() const
+{
+ return m_SectionData.getFragmentList().size();
+}
+
+size_t MipsGOT::getLocalNum() const
+{
+ return m_pLocalNum;
+}
+
diff --git a/lib/Target/Mips/MipsGOT.h b/lib/Target/Mips/MipsGOT.h
new file mode 100644
index 0000000..dccc7ac
--- /dev/null
+++ b/lib/Target/Mips/MipsGOT.h
@@ -0,0 +1,67 @@
+//===- MipsGOT.h ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_MIPS_GOT_H
+#define MCLD_MIPS_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/GOT.h>
+
+namespace mcld
+{
+class LDSection;
+class MemoryRegion;
+
+/** \class MipsGOT
+ * \brief Mips Global Offset Table.
+ */
+class MipsGOT : public GOT
+{
+private:
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ MipsGOT(LDSection& pSection, llvm::MCSectionData& pSectionData);
+
+ iterator begin();
+ iterator end();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ uint64_t emit(MemoryRegion& pRegion);
+
+ void reserveLocalEntry();
+ void reserveGlobalEntry();
+
+ GOTEntry* getEntry(const ResolveInfo& pInfo, bool& pExist);
+
+ size_t getTotalNum() const;
+ size_t getLocalNum() const;
+
+private:
+ SymbolIndexMapType m_GeneralGOTMap;
+ iterator m_LocalGOTIterator; // last local GOT entries
+ iterator m_GlobalGOTIterator; // last global GOT entries
+ size_t m_pLocalNum;
+
+private:
+ // Use reserveLocalEntry()/reserveGlobalEntry() instead of this routine.
+ void reserveEntry(size_t pNum = 1);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
new file mode 100644
index 0000000..c7a6b23
--- /dev/null
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -0,0 +1,894 @@
+//===- MipsLDBackend.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/Support/ELF.h>
+
+#include <mcld/LD/SectionMap.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+#include "Mips.h"
+#include "MipsELFDynamic.h"
+#include "MipsLDBackend.h"
+#include "MipsRelocationFactory.h"
+
+enum {
+ // The original o32 abi.
+ E_MIPS_ABI_O32 = 0x00001000,
+ // O32 extended to work on 64 bit architectures.
+ E_MIPS_ABI_O64 = 0x00002000,
+ // EABI in 32 bit mode.
+ E_MIPS_ABI_EABI32 = 0x00003000,
+ // EABI in 64 bit mode.
+ E_MIPS_ABI_EABI64 = 0x00004000
+};
+
+namespace mcld {
+
+MipsGNULDBackend::MipsGNULDBackend()
+ : m_pRelocFactory(NULL),
+ m_pGOT(NULL),
+ m_pRelDyn(NULL),
+ m_pDynamic(NULL),
+ m_pGOTSymbol(NULL),
+ m_pGpDispSymbol(NULL)
+{
+}
+
+MipsGNULDBackend::~MipsGNULDBackend()
+{
+ if (NULL != m_pRelocFactory)
+ delete m_pRelocFactory;
+ if (NULL != m_pGOT)
+ delete m_pGOT;
+ if (NULL != m_pRelDyn)
+ delete m_pRelDyn;
+ if (NULL != m_pDynamic)
+ delete m_pDynamic;
+}
+
+bool MipsGNULDBackend::initTargetSectionMap(SectionMap& pSectionMap)
+{
+ // Nothing to do because we do not support
+ // any MIPS specific sections now.
+ return true;
+}
+
+void MipsGNULDBackend::initTargetSections(MCLinker& pLinker)
+{
+ // Nothing to do because we do not support
+ // any MIPS specific sections now.
+}
+
+void MipsGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+{
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+
+ m_pGpDispSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_gp_disp",
+ false,
+ ResolveInfo::Section,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ if (NULL != m_pGpDispSymbol) {
+ m_pGpDispSymbol->resolveInfo()->setReserved(ReserveGpDisp);
+ }
+}
+
+bool MipsGNULDBackend::initRelocFactory(const MCLinker& pLinker)
+{
+ if (NULL == m_pRelocFactory) {
+ m_pRelocFactory = new MipsRelocationFactory(1024, *this);
+ m_pRelocFactory->setLayout(pLinker.getLayout());
+ }
+ return true;
+}
+
+RelocationFactory* MipsGNULDBackend::getRelocFactory()
+{
+ assert(NULL != m_pRelocFactory);
+ return m_pRelocFactory;
+}
+
+void MipsGNULDBackend::scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies
+ // that a .got section is needed.
+ if (NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if (rsym == m_pGOTSymbol->resolveInfo()) {
+ createGOT(pLinker, pOutput);
+ }
+ }
+
+ if (rsym->isLocal())
+ scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+ else
+ scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+}
+
+uint32_t MipsGNULDBackend::machine() const
+{
+ return llvm::ELF::EM_MIPS;
+}
+
+uint8_t MipsGNULDBackend::OSABI() const
+{
+ return llvm::ELF::ELFOSABI_NONE;
+}
+
+uint8_t MipsGNULDBackend::ABIVersion() const
+{
+ return 0;
+}
+
+uint64_t MipsGNULDBackend::flags() const
+{
+ // TODO: (simon) The correct flag's set depend on command line
+ // arguments and flags from input .o files.
+ return llvm::ELF::EF_MIPS_ARCH_32R2 |
+ llvm::ELF::EF_MIPS_NOREORDER |
+ llvm::ELF::EF_MIPS_PIC |
+ llvm::ELF::EF_MIPS_CPIC |
+ E_MIPS_ABI_O32;
+}
+
+bool MipsGNULDBackend::isLittleEndian() const
+{
+ // Now we support little endian (mipsel) target only.
+ return true;
+}
+
+unsigned int MipsGNULDBackend::bitclass() const
+{
+ return 32;
+}
+
+void MipsGNULDBackend::doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // when building shared object, the .got section is must.
+ if (pOutput.type() == Output::DynObj && NULL == m_pGOT) {
+ createGOT(pLinker, pOutput);
+ }
+}
+
+void MipsGNULDBackend::doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // emit program headers
+ if (pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
+ emitProgramHdrs(pLinker.getLDInfo().output());
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+MipsELFDynamic& MipsGNULDBackend::dynamic()
+{
+ if (NULL == m_pDynamic)
+ m_pDynamic = new MipsELFDynamic(*this);
+
+ return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const MipsELFDynamic& MipsGNULDBackend::dynamic() const
+{
+ assert( NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+uint64_t MipsGNULDBackend::emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSection == &(file_format->getGOT())) {
+ assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+ uint64_t result = m_pGOT->emit(pRegion);
+ return result;
+ }
+
+ llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
+ pSection.name() +
+ llvm::Twine("'.\n"));
+ return 0;
+}
+/// isGOTSymbol - return true if the symbol is the GOT entry.
+bool MipsGNULDBackend::isGOTSymbol(const LDSymbol& pSymbol) const
+{
+ return std::find(m_LocalGOTSyms.begin(),
+ m_LocalGOTSyms.end(), &pSymbol) != m_LocalGOTSyms.end() ||
+ std::find(m_GlobalGOTSyms.begin(),
+ m_GlobalGOTSyms.end(), &pSymbol) != m_GlobalGOTSyms.end();
+}
+
+/// emitDynamicSymbol - emit dynamic symbol.
+void MipsGNULDBackend::emitDynamicSymbol(llvm::ELF::Elf32_Sym& sym32,
+ Output& pOutput,
+ LDSymbol& pSymbol,
+ const Layout& pLayout,
+ char* strtab,
+ size_t strtabsize,
+ size_t symtabIdx)
+{
+ // maintain output's symbol and index map
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+ entry = m_pSymIndexMap->insert(&pSymbol, sym_exist);
+ entry->setValue(symtabIdx);
+
+ // FIXME: check the endian between host and target
+ // write out symbol
+ sym32.st_name = strtabsize;
+ sym32.st_value = pSymbol.value();
+ sym32.st_size = getSymbolSize(pSymbol);
+ sym32.st_info = getSymbolInfo(pSymbol);
+ sym32.st_other = pSymbol.visibility();
+ sym32.st_shndx = getSymbolShndx(pSymbol, pLayout);
+ // write out string
+ strcpy((strtab + strtabsize), pSymbol.name());
+}
+
+/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+///
+/// the size of these tables should be computed before layout
+/// layout should computes the start offset of these tables
+void MipsGNULDBackend::emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.hasMemArea());
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& symtab_sect = file_format->getDynSymTab();
+ LDSection& strtab_sect = file_format->getDynStrTab();
+ LDSection& hash_sect = file_format->getHashTab();
+ LDSection& dyn_sect = file_format->getDynamic();
+
+ MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(),
+ symtab_sect.size());
+ MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
+ strtab_sect.size());
+ MemoryRegion* hash_region = pOutput.memArea()->request(hash_sect.offset(),
+ hash_sect.size());
+ MemoryRegion* dyn_region = pOutput.memArea()->request(dyn_sect.offset(),
+ dyn_sect.size());
+ // set up symtab_region
+ llvm::ELF::Elf32_Sym* symtab32 = NULL;
+ symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+
+ symtab32[0].st_name = 0;
+ symtab32[0].st_value = 0;
+ symtab32[0].st_size = 0;
+ symtab32[0].st_info = 0;
+ symtab32[0].st_other = 0;
+ symtab32[0].st_shndx = 0;
+
+ // set up strtab_region
+ char* strtab = (char*)strtab_region->start();
+ strtab[0] = '\0';
+
+ bool sym_exist = false;
+ HashTableType::entry_type* entry = 0;
+
+ // add index 0 symbol into SymIndexMap
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(0);
+
+ size_t symtabIdx = 1;
+ size_t strtabsize = 1;
+
+ // emit of .dynsym, and .dynstr except GOT entries
+ for (SymbolCategory::iterator symbol = pSymbols.begin(),
+ sym_end = pSymbols.end(); symbol != sym_end; ++symbol) {
+ if (!isDynamicSymbol(**symbol, pOutput))
+ continue;
+
+ if (isGOTSymbol(**symbol))
+ continue;
+
+ emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
+ strtabsize, symtabIdx);
+
+ // sum up counters
+ ++symtabIdx;
+ strtabsize += (*symbol)->nameSize() + 1;
+ }
+
+ // emit global GOT
+ for (std::vector<LDSymbol*>::const_iterator symbol = m_GlobalGOTSyms.begin(),
+ symbol_end = m_GlobalGOTSyms.end();
+ symbol != symbol_end; ++symbol) {
+
+ emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
+ strtabsize, symtabIdx);
+
+ // sum up counters
+ ++symtabIdx;
+ strtabsize += (*symbol)->nameSize() + 1;
+ }
+
+ // emit DT_NEED
+ // add DT_NEED strings into .dynstr
+ // Rules:
+ // 1. ignore --no-add-needed
+ // 2. force count in --no-as-needed
+ // 3. judge --as-needed
+ ELFDynamic::iterator dt_need = dynamic().needBegin();
+ InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
+ for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
+ if (Input::DynObj == (*input)->type()) {
+ // --add-needed
+ if ((*input)->attribute()->isAddNeeded()) {
+ // --no-as-needed
+ if (!(*input)->attribute()->isAsNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ // --as-needed
+ else if ((*input)->isNeeded()) {
+ strcpy((strtab + strtabsize), (*input)->name().c_str());
+ (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+ strtabsize += (*input)->name().size() + 1;
+ ++dt_need;
+ }
+ }
+ }
+ } // for
+
+ // emit soname
+ // initialize value of ELF .dynamic section
+ dynamic().applySoname(strtabsize);
+ dynamic().applyEntries(pLDInfo, *file_format);
+ dynamic().emit(dyn_sect, *dyn_region);
+
+ strcpy((strtab + strtabsize), pOutput.name().c_str());
+ strtabsize += pOutput.name().size() + 1;
+
+ // emit hash table
+ // FIXME: this verion only emit SVR4 hash section.
+ // Please add GNU new hash section
+
+ // both 32 and 64 bits hash table use 32-bit entry
+ // set up hash_region
+ uint32_t* word_array = (uint32_t*)hash_region->start();
+ uint32_t& nbucket = word_array[0];
+ uint32_t& nchain = word_array[1];
+
+ nbucket = getHashBucketCount(symtabIdx, false);
+ nchain = symtabIdx;
+
+ uint32_t* bucket = (word_array + 2);
+ uint32_t* chain = (bucket + nbucket);
+
+ // initialize bucket
+ bzero((void*)bucket, nbucket);
+
+ StringHash<ELF> hash_func;
+
+ for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
+ llvm::StringRef name(strtab + symtab32[sym_idx].st_name);
+ size_t bucket_pos = hash_func(name) % nbucket;
+ chain[sym_idx] = bucket[bucket_pos];
+ bucket[bucket_pos] = sym_idx;
+ }
+
+}
+
+MipsGOT& MipsGNULDBackend::getGOT()
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+const MipsGOT& MipsGNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+OutputRelocSection& MipsGNULDBackend::getRelDyn()
+{
+ assert(NULL != m_pRelDyn);
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& MipsGNULDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn);
+ return *m_pRelDyn;
+}
+
+unsigned int
+MipsGNULDBackend::getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ if (&pSectHdr == &file_format->getGOT())
+ return SHO_DATA;
+
+ return SHO_UNDEFINED;
+}
+
+/// finalizeSymbol - finalize the symbol value
+/// If the symbol's reserved field is not zero, MCLinker will call back this
+/// function to ask the final value of the symbol
+bool MipsGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+{
+ if (&pSymbol == m_pGpDispSymbol) {
+ m_pGpDispSymbol->setValue(m_pGOT->getSection().addr() + 0x7FF0);
+ return true;
+ }
+ return false;
+}
+
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+/// FIXME: Mips needs to allocate small common symbol
+bool
+MipsGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
+{
+ // SymbolCategory contains all symbols that must emit to the output files.
+ // We are not like Google gold linker, we don't remember symbols before symbol
+ // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
+ // don't need to care about some symbols may be changed its category due to symbol
+ // resolution.
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
+
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ // addralign := max value of all common symbols
+ uint64_t addralign = 0x0;
+
+ // Due to the visibility, some common symbols may be forcefully local.
+ SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+ }
+
+ // global common symbols.
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // com_sym = symbol_list.commonBegin();
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+
+ // allocate all common symbols
+ uint64_t offset = bss_sect_hdr->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ alignAddress(offset, (*com_sym)->value());
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ offset += (*com_sym)->size();
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ alignAddress(offset, (*com_sym)->value());
+
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ offset += (*com_sym)->size();
+ }
+
+ bss_sect_hdr->setSize(offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
+}
+
+void MipsGNULDBackend::updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const
+{
+ // Update value keep in addend if we meet a section symbol
+ if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ pReloc.setAddend(pLayout.getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.addend());
+ }
+}
+
+void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+
+ switch (pReloc.type()){
+ case llvm::ELF::R_MIPS_NONE:
+ case llvm::ELF::R_MIPS_16:
+ break;
+ case llvm::ELF::R_MIPS_32:
+ if (Output::DynObj == pOutput.type()) {
+ // TODO: (simon) The gold linker does not create an entry in .rel.dyn
+ // section if the symbol section flags contains SHF_EXECINSTR.
+ // 1. Find the reason of this condition.
+ // 2. Check this condition here.
+ if (NULL == m_pRelDyn)
+ createRelDyn(pLinker, pOutput);
+
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ break;
+ case llvm::ELF::R_MIPS_REL32:
+ case llvm::ELF::R_MIPS_26:
+ case llvm::ELF::R_MIPS_HI16:
+ case llvm::ELF::R_MIPS_LO16:
+ case llvm::ELF::R_MIPS_PC16:
+ case llvm::ELF::R_MIPS_SHIFT5:
+ case llvm::ELF::R_MIPS_SHIFT6:
+ case llvm::ELF::R_MIPS_64:
+ case llvm::ELF::R_MIPS_GOT_PAGE:
+ case llvm::ELF::R_MIPS_GOT_OFST:
+ case llvm::ELF::R_MIPS_SUB:
+ case llvm::ELF::R_MIPS_INSERT_A:
+ case llvm::ELF::R_MIPS_INSERT_B:
+ case llvm::ELF::R_MIPS_DELETE:
+ case llvm::ELF::R_MIPS_HIGHER:
+ case llvm::ELF::R_MIPS_HIGHEST:
+ case llvm::ELF::R_MIPS_SCN_DISP:
+ case llvm::ELF::R_MIPS_REL16:
+ case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
+ case llvm::ELF::R_MIPS_PJUMP:
+ case llvm::ELF::R_MIPS_RELGOT:
+ case llvm::ELF::R_MIPS_JALR:
+ case llvm::ELF::R_MIPS_GLOB_DAT:
+ case llvm::ELF::R_MIPS_COPY:
+ case llvm::ELF::R_MIPS_JUMP_SLOT:
+ break;
+ case llvm::ELF::R_MIPS_GOT16:
+ case llvm::ELF::R_MIPS_CALL16:
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+
+ if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
+ m_pGOT->reserveLocalEntry();
+ rsym->setReserved(rsym->reserved() | ReserveGot);
+ m_LocalGOTSyms.push_back(rsym->outSymbol());
+ }
+ break;
+ case llvm::ELF::R_MIPS_GPREL32:
+ case llvm::ELF::R_MIPS_GPREL16:
+ case llvm::ELF::R_MIPS_LITERAL:
+ break;
+ case llvm::ELF::R_MIPS_GOT_DISP:
+ case llvm::ELF::R_MIPS_GOT_HI16:
+ case llvm::ELF::R_MIPS_CALL_HI16:
+ case llvm::ELF::R_MIPS_GOT_LO16:
+ case llvm::ELF::R_MIPS_CALL_LO16:
+ break;
+ case llvm::ELF::R_MIPS_TLS_DTPMOD32:
+ case llvm::ELF::R_MIPS_TLS_DTPREL32:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+ case llvm::ELF::R_MIPS_TLS_DTPREL64:
+ case llvm::ELF::R_MIPS_TLS_GD:
+ case llvm::ELF::R_MIPS_TLS_LDM:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
+ case llvm::ELF::R_MIPS_TLS_GOTTPREL:
+ case llvm::ELF::R_MIPS_TLS_TPREL32:
+ case llvm::ELF::R_MIPS_TLS_TPREL64:
+ case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
+ break;
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine("for the local symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("'."));
+ }
+}
+
+void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ switch (pReloc.type()){
+ case llvm::ELF::R_MIPS_NONE:
+ case llvm::ELF::R_MIPS_INSERT_A:
+ case llvm::ELF::R_MIPS_INSERT_B:
+ case llvm::ELF::R_MIPS_DELETE:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+ case llvm::ELF::R_MIPS_TLS_DTPREL64:
+ case llvm::ELF::R_MIPS_REL16:
+ case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
+ case llvm::ELF::R_MIPS_PJUMP:
+ case llvm::ELF::R_MIPS_RELGOT:
+ case llvm::ELF::R_MIPS_TLS_TPREL64:
+ break;
+ case llvm::ELF::R_MIPS_32:
+ case llvm::ELF::R_MIPS_64:
+ case llvm::ELF::R_MIPS_HI16:
+ case llvm::ELF::R_MIPS_LO16:
+ if (isSymbolNeedsDynRel(*rsym, pOutput)) {
+ if (NULL == m_pRelDyn)
+ createRelDyn(pLinker, pOutput);
+
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ break;
+ case llvm::ELF::R_MIPS_GOT16:
+ case llvm::ELF::R_MIPS_CALL16:
+ case llvm::ELF::R_MIPS_GOT_DISP:
+ case llvm::ELF::R_MIPS_GOT_HI16:
+ case llvm::ELF::R_MIPS_CALL_HI16:
+ case llvm::ELF::R_MIPS_GOT_LO16:
+ case llvm::ELF::R_MIPS_CALL_LO16:
+ case llvm::ELF::R_MIPS_GOT_PAGE:
+ case llvm::ELF::R_MIPS_GOT_OFST:
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+
+ if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
+ m_pGOT->reserveGlobalEntry();
+ rsym->setReserved(rsym->reserved() | ReserveGot);
+ m_GlobalGOTSyms.push_back(rsym->outSymbol());
+ }
+ break;
+ case llvm::ELF::R_MIPS_LITERAL:
+ case llvm::ELF::R_MIPS_GPREL32:
+ llvm::report_fatal_error(llvm::Twine("Relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine(" is not defined for the "
+ "global symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("'."));
+ break;
+ case llvm::ELF::R_MIPS_GPREL16:
+ break;
+ case llvm::ELF::R_MIPS_26:
+ case llvm::ELF::R_MIPS_PC16:
+ break;
+ case llvm::ELF::R_MIPS_16:
+ case llvm::ELF::R_MIPS_SHIFT5:
+ case llvm::ELF::R_MIPS_SHIFT6:
+ case llvm::ELF::R_MIPS_SUB:
+ case llvm::ELF::R_MIPS_HIGHER:
+ case llvm::ELF::R_MIPS_HIGHEST:
+ case llvm::ELF::R_MIPS_SCN_DISP:
+ break;
+ case llvm::ELF::R_MIPS_TLS_DTPREL32:
+ case llvm::ELF::R_MIPS_TLS_GD:
+ case llvm::ELF::R_MIPS_TLS_LDM:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
+ case llvm::ELF::R_MIPS_TLS_GOTTPREL:
+ case llvm::ELF::R_MIPS_TLS_TPREL32:
+ case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
+ break;
+ case llvm::ELF::R_MIPS_REL32:
+ break;
+ case llvm::ELF::R_MIPS_JALR:
+ break;
+ case llvm::ELF::R_MIPS_COPY:
+ case llvm::ELF::R_MIPS_GLOB_DAT:
+ case llvm::ELF::R_MIPS_JUMP_SLOT:
+ llvm::report_fatal_error(llvm::Twine("Relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine("for the global symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("' should only be seen "
+ "by the dynamic linker"));
+ break;
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
+ llvm::Twine(pReloc.type()) +
+ llvm::Twine("for the global symbol `") +
+ pReloc.symInfo()->name() +
+ llvm::Twine("'."));
+ }
+}
+
+bool MipsGNULDBackend::isSymbolNeedsPLT(ResolveInfo& pSym,
+ const Output& pOutput) const
+{
+ return (Output::DynObj == pOutput.type() &&
+ ResolveInfo::Function == pSym.type() &&
+ (pSym.isDyn() || pSym.isUndef()));
+}
+
+bool MipsGNULDBackend::isSymbolNeedsDynRel(ResolveInfo& pSym,
+ const Output& pOutput) const
+{
+ if(pSym.isUndef() && Output::Exec == pOutput.type())
+ return false;
+ if(pSym.isAbsolute())
+ return false;
+ if(Output::DynObj == pOutput.type())
+ return true;
+ if(pSym.isDyn() || pSym.isUndef())
+ return true;
+
+ return false;
+}
+
+void MipsGNULDBackend::createGOT(MCLinker& pLinker, const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new MipsGOT(got, pLinker.getOrCreateSectData(got));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+ if( m_pGOTSymbol != NULL ) {
+ pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+}
+
+void MipsGNULDBackend::createRelDyn(MCLinker& pLinker, const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // get .rel.dyn LDSection and create MCSectionData
+ LDSection& reldyn = file_format->getRelDyn();
+ // create MCSectionData and ARMRelDynSection
+ m_pRelDyn = new OutputRelocSection(reldyn,
+ pLinker.getOrCreateSectData(reldyn),
+ 8);
+}
+
+ELFFileFormat* MipsGNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ case Output::Object:
+ return NULL;
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
+ llvm::Twine(pOutput.type()));
+ return NULL;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+/// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
+///
+static TargetLDBackend* createMipsLDBackend(const llvm::Target& pTarget,
+ const std::string& pTriple)
+{
+ llvm::Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ }
+ return new MipsGNULDBackend();
+}
+
+} // namespace of mcld
+
+//=============================
+// Force static initialization.
+extern "C" void LLVMInitializeMipsLDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMipselTarget,
+ mcld::createMipsLDBackend);
+}
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
new file mode 100644
index 0000000..cd9e3cd
--- /dev/null
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -0,0 +1,200 @@
+//===- MipsLDBackend.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_LDBACKEND_H
+#define MIPS_LDBACKEND_H
+#include "mcld/Target/GNULDBackend.h"
+#include "MipsELFDynamic.h"
+#include "MipsGOT.h"
+
+namespace mcld {
+
+class MCLinker;
+class OutputRelocSection;
+class SectionMap;
+
+//===----------------------------------------------------------------------===//
+/// MipsGNULDBackend - linker backend of Mips target of GNU ELF format
+///
+class MipsGNULDBackend : public GNULDBackend
+{
+public:
+ enum ReservedEntryType {
+ None = 0, // no reserved entry
+ ReserveRel = 1, // reserve a dynamic relocation entry
+ ReserveGot = 2, // reserve a GOT entry
+ ReserveGpDisp = 8 // reserve _gp_disp symbol
+ };
+
+public:
+ MipsGNULDBackend();
+ ~MipsGNULDBackend();
+
+public:
+ /// initTargetSectionMap - initialize target dependent section mapping.
+ bool initTargetSectionMap(SectionMap& pSectionMap);
+
+ /// initTargetSections - initialize target dependent sections in output
+ void initTargetSections(MCLinker& pLinker);
+
+ /// initTargetSymbols - initialize target dependent symbols in output.
+ void initTargetSymbols(MCLinker& pLinker);
+
+ /// initRelocFactory - create and initialize RelocationFactory.
+ bool initRelocFactory(const MCLinker& pLinker);
+
+ /// getRelocFactory - return relocation factory.
+ RelocationFactory* getRelocFactory();
+
+ /// scanRelocation - determine the empty entries are needed or not and
+ /// create the empty entries if needed.
+ /// For Mips, the GOT, GP, and dynamic relocation entries are check to create.
+ void scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ uint32_t machine() const;
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ uint8_t OSABI() const;
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ uint8_t ABIVersion() const;
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ uint64_t flags() const;
+
+ bool isLittleEndian() const;
+
+ unsigned int bitclass() const;
+
+ /// preLayout - Backend can do any needed modification before layout
+ void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// postLayout -Backend can do any needed modification after layout
+ void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ MipsELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const MipsELFDynamic& dynamic() const;
+
+ /// emitSectionData - write out the section data into the memory region.
+ /// When writers get a LDSection whose kind is LDFileFormat::Target, writers
+ /// call back target backend to emit the data.
+ ///
+ /// Backends handle the target-special tables (plt, gp,...) by themselves.
+ /// Backend can put the data of the tables in MCSectionData directly
+ /// - LDSection.getSectionData can get the section data.
+ /// Or, backend can put the data into special data structure
+ /// - backend can maintain its own map<LDSection, table> to get the table
+ /// from given LDSection.
+ ///
+ /// @param pOutput - the output file
+ /// @param pSection - the given LDSection
+ /// @param pInfo - all options in the command line.
+ /// @param pRegion - the region to write out data
+ /// @return the size of the table in the file.
+ uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const;
+
+ /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+ virtual void emitDynNamePools(Output& pOutput,
+ SymbolCategory& pSymbols,
+ const Layout& pLayout,
+ const MCLDInfo& pLDInfo);
+
+ MipsGOT& getGOT();
+ const MipsGOT& getGOT() const;
+
+ OutputRelocSection& getRelDyn();
+ const OutputRelocSection& getRelDyn() const;
+
+ /// getTargetSectionOrder - compute the layout order of ARM target sections
+ unsigned int getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// finalizeSymbol - finalize the symbol value
+ /// If the symbol's reserved field is not zero, MCLinker will call back this
+ /// function to ask the final value of the symbol
+ bool finalizeSymbol(LDSymbol& pSymbol) const;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+
+private:
+ void scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ bool isSymbolNeedsPLT(ResolveInfo& pSym, const Output& pOutput) const;
+ bool isSymbolNeedsDynRel(ResolveInfo& pSym, const Output& pOutput) const;
+
+ void createGOT(MCLinker& pLinker, const Output& pOutput);
+ void createRelDyn(MCLinker& pLinker, const Output& pOutput);
+
+ ELFFileFormat* getOutputFormat(const Output& pOutput) const;
+
+ /// updateAddend - update addend value of the relocation if the
+ /// the target symbol is a section symbol. Addend is the offset
+ /// in the section. This value should be updated after section
+ /// merged.
+ void updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const;
+
+private:
+ RelocationFactory* m_pRelocFactory;
+
+ MipsGOT* m_pGOT; // .got
+ OutputRelocSection* m_pRelDyn; // .rel.dyn
+
+ MipsELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+ LDSymbol* m_pGpDispSymbol;
+
+ std::vector<LDSymbol*> m_LocalGOTSyms;
+ std::vector<LDSymbol*> m_GlobalGOTSyms;
+
+private:
+ /// isGOTSymbol - return true if the symbol is the GOT entry.
+ bool isGOTSymbol(const LDSymbol& pSymbol) const;
+ /// emitDynamicSymbol - emit dynamic symbol.
+ void emitDynamicSymbol(llvm::ELF::Elf32_Sym& sym32,
+ Output& pOutput,
+ LDSymbol& pSymbol,
+ const Layout& pLayout,
+ char* strtab,
+ size_t strtabsize,
+ size_t symtabIdx);
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/Mips/MipsRelocationFactory.cpp b/lib/Target/Mips/MipsRelocationFactory.cpp
new file mode 100644
index 0000000..e3a7793
--- /dev/null
+++ b/lib/Target/Mips/MipsRelocationFactory.cpp
@@ -0,0 +1,363 @@
+//===- MipsRelocationFactory.cpp -----------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <mcld/LD/Layout.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+#include "MipsRelocationFactory.h"
+#include "MipsRelocationFunctions.h"
+
+using namespace mcld;
+
+DECL_MIPS_APPLY_RELOC_FUNCS
+
+//==========================
+// MipsRelocationFactory
+MipsRelocationFactory::MipsRelocationFactory(size_t pNum,
+ MipsGNULDBackend& pParent)
+ : RelocationFactory(pNum),
+ m_Target(pParent),
+ m_AHL(0)
+{
+}
+
+void MipsRelocationFactory::applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo)
+
+{
+ /// the prototype of applying function
+ typedef Result (*ApplyFunctionType)(Relocation&,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory&);
+
+ // the table entry of applying functions
+ struct ApplyFunctionTriple {
+ ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+ };
+
+ // declare the table of applying functions
+ static ApplyFunctionTriple apply_functions[] = {
+ DECL_MIPS_APPLY_RELOC_FUNC_PTRS
+ };
+
+ Relocation::Type type = pRelocation.type();
+
+ if (type >= sizeof(apply_functions) / sizeof(apply_functions[0])) {
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
+ "To symbol `") +
+ pRelocation.symInfo()->name() +
+ llvm::Twine("'."));
+ }
+
+ // apply the relocation
+ Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
+
+ // check result
+ if (Overflow == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' causes overflow. on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+
+ if (BadReloc == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' encounters unexpected opcode. "
+ "on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+}
+
+//=========================================//
+// Relocation helper function //
+//=========================================//
+
+static const char * const GP_DISP_NAME = "_gp_disp";
+
+// Get an relocation entry in .rel.dyn and set its type to R_MIPS_REL32,
+// its FragmentRef to pReloc->targetFrag() and its ResolveInfo
+// to pReloc->symInfo()
+static
+void helper_SetRelDynEntry(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ MipsGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+
+ rel_entry.setType(llvm::ELF::R_MIPS_REL32);
+ rel_entry.targetRef() = pReloc.targetRef();
+ rel_entry.setSymInfo(0);
+}
+
+// Find next R_MIPS_LO16 relocation paired to pReloc.
+static
+Relocation* helper_FindLo16Reloc(Relocation& pReloc)
+{
+ Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode());
+ while (NULL != reloc)
+ {
+ if (llvm::ELF::R_MIPS_LO16 == reloc->type() &&
+ reloc->symInfo() == pReloc.symInfo())
+ return reloc;
+
+ reloc = static_cast<Relocation*>(reloc->getNextNode());
+ }
+ return NULL;
+}
+
+// Check the symbol is _gp_disp.
+static
+bool helper_isGpDisp(const Relocation& pReloc)
+{
+ const ResolveInfo* rsym = pReloc.symInfo();
+ return 0 == strcmp(GP_DISP_NAME, rsym->name());
+}
+
+static
+RelocationFactory::Address helper_GetGP(MipsRelocationFactory& pParent)
+{
+ return pParent.getTarget().getGOT().getSection().addr() + 0x7FF0;
+}
+
+static
+GOTEntry& helper_GetGOTEntry(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ MipsGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+
+ if (exist)
+ return got_entry;
+
+ // If we first get this GOT entry, we should initialize it.
+ if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
+ got_entry.setContent(pReloc.symValue());
+ }
+ else {
+ llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ }
+
+ return got_entry;
+}
+
+static
+RelocationFactory::Address helper_GetGOTOffset(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
+ return pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
+}
+
+static
+int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc)
+{
+ assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 ||
+ pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) &&
+ pLoReloc.type() == llvm::ELF::R_MIPS_LO16 &&
+ "Incorrect type of relocation for AHL calculation");
+
+ // Note the addend is section symbol offset here
+ assert (pHiReloc.addend() == pLoReloc.addend());
+
+ int32_t AHI = pHiReloc.target();
+ int32_t ALO = pLoReloc.target();
+ int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) + pLoReloc.addend();
+ return AHL;
+}
+
+static
+void helper_DynRel(Relocation& pReloc,
+ MipsRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ MipsGNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+
+ rel_entry.setType(llvm::ELF::R_MIPS_REL32);
+ rel_entry.targetRef() = pReloc.targetRef();
+ rel_entry.setSymInfo(rsym->isLocal() ? NULL : rsym);
+}
+
+//=========================================//
+// Relocation functions implementation //
+//=========================================//
+
+// R_MIPS_NONE and those unsupported/deprecated relocation type
+static
+MipsRelocationFactory::Result none(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_32: S + A
+static
+MipsRelocationFactory::Result abs32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
+ helper_DynRel(pReloc, pParent);
+ }
+
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ RelocationFactory::DWord S = pReloc.symValue();
+
+ pReloc.target() |= (S + A);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_HI16:
+// local/external: ((AHL + S) - (short)(AHL + S)) >> 16
+// _gp_disp : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
+static
+MipsRelocationFactory::Result hi16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
+ assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16");
+
+ int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
+ int32_t res = 0;
+
+ pParent.setAHL(AHL);
+
+ if (helper_isGpDisp(pReloc)) {
+ int32_t P = pReloc.place(pParent.getLayout());
+ int32_t GP = helper_GetGP(pParent);
+ res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
+ }
+ else {
+ int32_t S = pReloc.symValue();
+ res = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
+ }
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (res & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_LO16:
+// local/external: AHL + S
+// _gp_disp : AHL + GP - P + 4
+static
+MipsRelocationFactory::Result lo16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ int32_t AHL = pParent.getAHL();
+ int32_t res = 0;
+
+ if (helper_isGpDisp(pReloc)) {
+ int32_t P = pReloc.place(pParent.getLayout());
+ int32_t GP = helper_GetGP(pParent);
+ res = AHL + GP - P + 4;
+ }
+ else {
+ int32_t S = pReloc.symValue();
+ res = AHL + S;
+ }
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (res & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_GOT16:
+// local : G (calculate AHL and put high 16 bit to GOT)
+// external: G
+static
+MipsRelocationFactory::Result got16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ if (rsym->isLocal()) {
+ Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
+ assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16");
+
+ int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
+ int32_t S = pReloc.symValue();
+
+ pParent.setAHL(AHL);
+
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
+
+ int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
+ got_entry.setContent(res);
+ }
+
+ RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent);
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (G & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_CALL16: G
+static
+MipsRelocationFactory::Result call16(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent);
+
+ pReloc.target() &= 0xFFFF0000;
+ pReloc.target() |= (G & 0xFFFF);
+
+ return MipsRelocationFactory::OK;
+}
+
+// R_MIPS_GPREL32: A + S + GP0 - GP
+static
+MipsRelocationFactory::Result gprel32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ MipsRelocationFactory& pParent)
+{
+ int32_t A = pReloc.target();
+ int32_t S = pReloc.symValue();
+ int32_t GP = helper_GetGP(pParent);
+
+ // llvm does not emits SHT_MIPS_REGINFO section.
+ // Assume that GP0 is zero.
+ pReloc.target() = (A + S - GP) & 0xFFFFFFFF;
+
+ return MipsRelocationFactory::OK;
+}
diff --git a/lib/Target/Mips/MipsRelocationFactory.h b/lib/Target/Mips/MipsRelocationFactory.h
new file mode 100644
index 0000000..8f3bf93
--- /dev/null
+++ b/lib/Target/Mips/MipsRelocationFactory.h
@@ -0,0 +1,64 @@
+//===- MipsRelocationFactory.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_RELOCATION_FACTORY_H
+#define MIPS_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Support/GCFactory.h>
+#include "MipsLDBackend.h"
+
+namespace mcld
+{
+
+/** \class MipsRelocationFactory
+ * \brief MipsRelocationFactory creates and destroys the Mips relocations.
+ */
+class MipsRelocationFactory : public RelocationFactory
+{
+public:
+ /** \enum Reloc
+ * \brief Reloc is the result of applying functions.
+ */
+ enum Result
+ {
+ OK,
+ Overflow,
+ BadReloc
+ };
+
+public:
+ MipsRelocationFactory(size_t pNum, MipsGNULDBackend& pParent);
+
+ void applyRelocation(Relocation& pRelocation, const MCLDInfo& pLDInfo);
+
+ MipsGNULDBackend& getTarget()
+ { return m_Target; }
+
+ const MipsGNULDBackend& getTarget() const
+ { return m_Target; }
+
+ // Get last calculated AHL.
+ int32_t getAHL() const
+ { return m_AHL; }
+
+ // Set last calculated AHL.
+ void setAHL(int32_t pAHL)
+ { m_AHL = pAHL; }
+
+private:
+ MipsGNULDBackend& m_Target;
+ int32_t m_AHL;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/MipsRelocationFunctions.h b/lib/Target/Mips/MipsRelocationFunctions.h
new file mode 100644
index 0000000..4b60d10
--- /dev/null
+++ b/lib/Target/Mips/MipsRelocationFunctions.h
@@ -0,0 +1,76 @@
+//===- MipsRelocationFunction.h -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DECL_MIPS_APPLY_RELOC_FUNC(Name) \
+static MipsRelocationFactory::Result Name(Relocation& pEntry, \
+ const MCLDInfo& pLDInfo, \
+ MipsRelocationFactory& pParent);
+
+#define DECL_MIPS_APPLY_RELOC_FUNCS \
+DECL_MIPS_APPLY_RELOC_FUNC(none) \
+DECL_MIPS_APPLY_RELOC_FUNC(abs32) \
+DECL_MIPS_APPLY_RELOC_FUNC(hi16) \
+DECL_MIPS_APPLY_RELOC_FUNC(lo16) \
+DECL_MIPS_APPLY_RELOC_FUNC(got16) \
+DECL_MIPS_APPLY_RELOC_FUNC(call16) \
+DECL_MIPS_APPLY_RELOC_FUNC(gprel32)
+
+#define DECL_MIPS_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_MIPS_NONE" }, \
+ { &none, 1, "R_MIPS_16" }, \
+ { &abs32, 2, "R_MIPS_32" }, \
+ { &none, 3, "R_MIPS_REL32" }, \
+ { &none, 4, "R_MIPS_26" }, \
+ { &hi16, 5, "R_MIPS_HI16" }, \
+ { &lo16, 6, "R_MIPS_LO16" }, \
+ { &none, 7, "R_MIPS_GPREL16" }, \
+ { &none, 8, "R_MIPS_LITERAL" }, \
+ { &got16, 9, "R_MIPS_GOT16" }, \
+ { &none, 10, "R_MIPS_PC16" }, \
+ { &call16, 11, "R_MIPS_CALL16" }, \
+ { &gprel32, 12, "R_MIPS_GPREL32" }, \
+ { &none, 13, "R_MIPS_UNUSED1" }, \
+ { &none, 14, "R_MIPS_UNUSED2" }, \
+ { &none, 15, "R_MIPS_UNUSED3" }, \
+ { &none, 16, "R_MIPS_SHIFT5" }, \
+ { &none, 17, "R_MIPS_SHIFT6" }, \
+ { &none, 18, "R_MIPS_64" }, \
+ { &none, 19, "R_MIPS_GOT_DISP" }, \
+ { &none, 20, "R_MIPS_GOT_PAGE" }, \
+ { &none, 21, "R_MIPS_GOT_OFST" }, \
+ { &none, 22, "R_MIPS_GOT_HI16" }, \
+ { &none, 23, "R_MIPS_GOT_LO16" }, \
+ { &none, 24, "R_MIPS_SUB" }, \
+ { &none, 25, "R_MIPS_INSERT_A" }, \
+ { &none, 26, "R_MIPS_INSERT_B" }, \
+ { &none, 27, "R_MIPS_DELETE" }, \
+ { &none, 28, "R_MIPS_HIGHER" }, \
+ { &none, 29, "R_MIPS_HIGHEST" }, \
+ { &none, 30, "R_MIPS_CALL_HI16" }, \
+ { &none, 31, "R_MIPS_CALL_LO16" }, \
+ { &none, 32, "R_MIPS_SCN_DISP" }, \
+ { &none, 33, "R_MIPS_REL16" }, \
+ { &none, 34, "R_MIPS_ADD_IMMEDIATE" }, \
+ { &none, 35, "R_MIPS_PJUMP" }, \
+ { &none, 36, "R_MIPS_RELGOT" }, \
+ { &none, 37, "R_MIPS_JALR" }, \
+ { &none, 38, "R_MIPS_TLS_DTPMOD32" }, \
+ { &none, 39, "R_MIPS_TLS_DTPREL32" }, \
+ { &none, 40, "R_MIPS_TLS_DTPMOD64" }, \
+ { &none, 41, "R_MIPS_TLS_DTPREL64" }, \
+ { &none, 42, "R_MIPS_TLS_GD" }, \
+ { &none, 43, "R_MIPS_TLS_LDM" }, \
+ { &none, 44, "R_MIPS_TLS_DTPREL_HI16" }, \
+ { &none, 45, "R_MIPS_TLS_DTPREL_LO16" }, \
+ { &none, 46, "R_MIPS_TLS_GOTTPREL" }, \
+ { &none, 47, "R_MIPS_TLS_TPREL32" }, \
+ { &none, 48, "R_MIPS_TLS_TPREL64" }, \
+ { &none, 49, "R_MIPS_TLS_TPREL_HI16" }, \
+ { &none, 50, "R_MIPS_TLS_TPREL_LO16" }, \
+ { &none, 51, "R_MIPS_GLOB_DAT" }
diff --git a/lib/Target/Mips/MipsSectLinker.cpp b/lib/Target/Mips/MipsSectLinker.cpp
new file mode 100644
index 0000000..af543c9
--- /dev/null
+++ b/lib/Target/Mips/MipsSectLinker.cpp
@@ -0,0 +1,47 @@
+//===- MipsSectLinker.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/TargetRegistry.h>
+#include "Mips.h"
+#include "MipsAndroidSectLinker.h"
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+/// createMipsSectLinker - the help funtion to create
+/// corresponding MipsSectLinker
+///
+SectLinker* createMipsSectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend)
+{
+ llvm::Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ }
+
+ // For now, use Android SectLinker directly
+ return new MipsAndroidSectLinker(pOption,
+ pLDBackend);
+}
+
+} // namespace of mcld
+
+//==========================
+// MipsSectLinker
+extern "C" void LLVMInitializeMipsSectLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterSectLinker(TheMipselTarget,
+ createMipsSectLinker);
+}
diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp
new file mode 100644
index 0000000..0987585
--- /dev/null
+++ b/lib/Target/Mips/MipsTargetMachine.cpp
@@ -0,0 +1,34 @@
+//===- MipsTargetMachine.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsTargetMachine.h"
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/MC/MCLDInfo.h"
+#include "Mips.h"
+
+extern "C" void LLVMInitializeMipsLDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::MipsBaseTargetMachine>
+ X(mcld::TheMipselTarget);
+}
+
+mcld::MipsBaseTargetMachine::MipsBaseTargetMachine(llvm::TargetMachine& pPM,
+ const mcld::Target &pTarget,
+ const std::string& pTriple)
+ : mcld::LLVMTargetMachine(pPM, pTarget, pTriple) {
+ // arg1 - the number of total attributes
+ // arg2 - the most possible number of input files
+ m_pLDInfo = new MCLDInfo(pTriple, 32, 64);
+}
+
+mcld::MipsBaseTargetMachine::~MipsBaseTargetMachine()
+{
+ delete m_pLDInfo;
+}
diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h
new file mode 100644
index 0000000..e9bd5da
--- /dev/null
+++ b/lib/Target/Mips/MipsTargetMachine.h
@@ -0,0 +1,38 @@
+//===- MipsTargetMachine.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MIPS_TARGET_MACHINE_H
+#define MIPS_TARGET_MACHINE_H
+#include "mcld/Target/TargetMachine.h"
+#include "Mips.h"
+
+namespace mcld
+{
+
+class MipsBaseTargetMachine : public LLVMTargetMachine
+{
+protected:
+ MCLDInfo *m_pLDInfo;
+
+public:
+ MipsBaseTargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+
+ virtual ~MipsBaseTargetMachine();
+
+ mcld::MCLDInfo& getLDInfo()
+ { return *m_pLDInfo; }
+
+ const mcld::MCLDInfo& getLDInfo() const
+ { return *m_pLDInfo; }
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/Mips/TargetInfo/Android.mk b/lib/Target/Mips/TargetInfo/Android.mk
new file mode 100644
index 0000000..cf8ae38
--- /dev/null
+++ b/lib/Target/Mips/TargetInfo/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_mips_info_SRC_FILES := \
+ MipsTargetInfo.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_info_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),mips)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_mips_info_SRC_FILES)
+LOCAL_MODULE:= libmcldMipsInfo
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
new file mode 100644
index 0000000..0889973
--- /dev/null
+++ b/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
@@ -0,0 +1,21 @@
+//===- MipsTargetInfo.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Support/TargetRegistry.h"
+
+namespace mcld {
+
+mcld::Target TheMipselTarget;
+
+extern "C" void LLVMInitializeMipsLDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget X(TheMipselTarget, "mipsel");
+}
+
+} // namespace of mcld
diff --git a/lib/Target/OutputRelocSection.cpp b/lib/Target/OutputRelocSection.cpp
new file mode 100644
index 0000000..89b4f52
--- /dev/null
+++ b/lib/Target/OutputRelocSection.cpp
@@ -0,0 +1,84 @@
+//===- OutputRelocSection.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+using namespace mcld;
+
+//==========================
+// OutputRelocSection
+
+
+OutputRelocSection::OutputRelocSection(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ unsigned int pEntrySize)
+ : m_pSection(&pSection),
+ m_pSectionData(&pSectionData),
+ m_EntryBytes(pEntrySize),
+ m_isVisit(false),
+ m_ValidEntryIterator(){
+}
+
+OutputRelocSection::~OutputRelocSection()
+{
+}
+
+void OutputRelocSection::reserveEntry(RelocationFactory& pRelFactory,
+ size_t pNum)
+{
+ for(size_t i=0; i<pNum; i++) {
+ m_pSectionData->getFragmentList().push_back(pRelFactory.produceEmptyEntry());
+ // update section size
+ m_pSection->setSize(m_pSection->size() + m_EntryBytes);
+ }
+}
+
+Relocation* OutputRelocSection::getEntry(const ResolveInfo& pSymbol,
+ bool isForGOT,
+ bool& pExist)
+{
+ // first time visit this function, set m_ValidEntryIterator to
+ // Fragments.begin()
+ if(!m_isVisit) {
+ assert( !m_pSectionData->getFragmentList().empty() &&
+ "DynRelSection contains no entries.");
+ m_ValidEntryIterator = m_pSectionData->getFragmentList().begin();
+ m_isVisit = true;
+ }
+
+ assert(m_ValidEntryIterator != m_pSectionData->end() &&
+ "No empty relocation entry for the incoming symbol.");
+
+ // if this relocation is used to relocate GOT (.got or .got.plt),
+ // check if we've gotten an entry for this symbol before. If yes,
+ // return the found entry in map.
+ // Otherwise, this relocation is used to relocate general section
+ // (data or text section), return an empty entry directly.
+ Relocation* result;
+
+ if(isForGOT) {
+ // get or create entry in m_SymRelMap
+ Relocation *&Entry = m_SymRelMap[&pSymbol];
+ pExist = 1;
+
+ if(!Entry) {
+ pExist = 0;
+ Entry = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
+ ++m_ValidEntryIterator;
+ }
+ result = Entry;
+ }
+ else {
+ pExist = 0;
+ result = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
+ ++m_ValidEntryIterator;
+ }
+ return result;
+}
+
diff --git a/lib/Target/PLT.cpp b/lib/Target/PLT.cpp
new file mode 100644
index 0000000..a29dfd8
--- /dev/null
+++ b/lib/Target/PLT.cpp
@@ -0,0 +1,42 @@
+//===- PLT.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/PLT.h>
+
+using namespace mcld;
+
+class GOT;
+
+//===--------------------------------------------------------------------===//
+// PLTEntry
+PLTEntry::PLTEntry(size_t pSize, llvm::MCSectionData* pParent)
+ : MCTargetFragment(llvm::MCFragment::FT_Target, pParent),
+ m_EntrySize(pSize), m_pContent(NULL)
+{
+}
+
+PLTEntry::~PLTEntry()
+{
+ if (m_pContent) {
+ free(m_pContent);
+ m_pContent = NULL;
+ }
+}
+
+//===--------------------------------------------------------------------===//
+// PLT
+PLT::PLT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ :m_Section(pSection),
+ m_SectionData(pSectionData)
+{
+}
+
+PLT::~PLT()
+{
+}
+
diff --git a/lib/Target/Stub.cpp b/lib/Target/Stub.cpp
new file mode 100644
index 0000000..4b59acf
--- /dev/null
+++ b/lib/Target/Stub.cpp
@@ -0,0 +1,15 @@
+//===- Stub.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Target/Stub.h"
+
+using namespace mcld;
+
+//==========================
+// Stub
+
diff --git a/lib/Target/Target.cpp b/lib/Target/Target.cpp
new file mode 100644
index 0000000..58178ec
--- /dev/null
+++ b/lib/Target/Target.cpp
@@ -0,0 +1,25 @@
+//===- Target.cpp ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/Target/TargetMachine.h"
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Target/TargetMachine.h>
+
+using namespace llvm;
+using namespace mcld;
+
+/* ** */
+mcld::Target::Target()
+ : TargetMachineCtorFn(0),
+ SectLinkerCtorFn(0),
+ TargetLDBackendCtorFn(0),
+ m_pT(0)
+{
+}
+
diff --git a/lib/Target/TargetLDBackend.cpp b/lib/Target/TargetLDBackend.cpp
new file mode 100644
index 0000000..1a8ab6b
--- /dev/null
+++ b/lib/Target/TargetLDBackend.cpp
@@ -0,0 +1,23 @@
+//===- TargetLDBackend.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/Relocation.h"
+#include "mcld/LD/Layout.h"
+#include "mcld/Target/TargetLDBackend.h"
+
+using namespace mcld;
+
+/* ** */
+TargetLDBackend::TargetLDBackend()
+{
+}
+
+TargetLDBackend::~TargetLDBackend()
+{
+}
+
diff --git a/lib/Target/X86/Android.mk b/lib/Target/X86/Android.mk
new file mode 100644
index 0000000..e9a051b
--- /dev/null
+++ b/lib/Target/X86/Android.mk
@@ -0,0 +1,41 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_x86_target_SRC_FILES := \
+ X86AndroidSectLinker.cpp \
+ X86ELFDynamic.cpp \
+ X86ELFSectLinker.cpp \
+ X86GOT.cpp \
+ X86GOTPLT.cpp \
+ X86LDBackend.cpp \
+ X86PLT.cpp \
+ X86RelocationFactory.cpp \
+ X86SectLinker.cpp \
+ X86TargetMachine.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_target_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Target
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),x86)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_target_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Target
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/X86/TargetInfo/Android.mk b/lib/Target/X86/TargetInfo/Android.mk
new file mode 100644
index 0000000..3664933
--- /dev/null
+++ b/lib/Target/X86/TargetInfo/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+mcld_x86_info_SRC_FILES := \
+ X86TargetInfo.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_info_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Info
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifeq ($(TARGET_ARCH),x86)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mcld_x86_info_SRC_FILES)
+LOCAL_MODULE:= libmcldX86Info
+
+LOCAL_MODULE_TAGS := optional
+
+include $(MCLD_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
new file mode 100644
index 0000000..afe349e
--- /dev/null
+++ b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
@@ -0,0 +1,22 @@
+//===- X86TargetInfo.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Support/TargetRegistry.h"
+
+namespace mcld {
+
+mcld::Target TheX86Target;
+
+extern "C" void LLVMInitializeX86LDTargetInfo() {
+ // register into mcld::TargetRegistry
+ mcld::RegisterTarget X(TheX86Target, "x86");
+}
+
+} // namespace of mcld
+
diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h
new file mode 100644
index 0000000..2d07314
--- /dev/null
+++ b/lib/Target/X86/X86.h
@@ -0,0 +1,24 @@
+//===- X86.h --------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_H
+#define MCLD_X86_H
+#include <string>
+#include "mcld/Target/TargetMachine.h"
+
+namespace mcld {
+class TargetLDBackend;
+
+extern mcld::Target TheX86Target;
+
+TargetLDBackend *createX86LDBackend(const llvm::Target&, const std::string&);
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86AndroidSectLinker.cpp b/lib/Target/X86/X86AndroidSectLinker.cpp
new file mode 100644
index 0000000..91b466c
--- /dev/null
+++ b/lib/Target/X86/X86AndroidSectLinker.cpp
@@ -0,0 +1,35 @@
+//===- X86AndroidSectLinker.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86AndroidSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+X86AndroidSectLinker::X86AndroidSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : AndroidSectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().disableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().unsetWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+X86AndroidSectLinker::~X86AndroidSectLinker()
+{
+}
+
diff --git a/lib/Target/X86/X86AndroidSectLinker.h b/lib/Target/X86/X86AndroidSectLinker.h
new file mode 100644
index 0000000..b275aca
--- /dev/null
+++ b/lib/Target/X86/X86AndroidSectLinker.h
@@ -0,0 +1,38 @@
+//===- X86AndroidSectLinker.h ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86_ANDROIDSECTLINKER_H
+#define X86_ANDROIDSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/Target/AndroidSectLinker.h>
+
+namespace mcld
+{
+
+/** \class X86AndroidSectLinker
+ * \brief X86AndroidSectLinker sets up the environment for linking.
+ *
+ * \see
+ * \author Anders Cheng <Anders.Cheng@mediatek.com>
+ */
+class X86AndroidSectLinker : public AndroidSectLinker
+{
+public:
+ X86AndroidSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~X86AndroidSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86ELFDynamic.cpp b/lib/Target/X86/X86ELFDynamic.cpp
new file mode 100644
index 0000000..c32cfa8
--- /dev/null
+++ b/lib/Target/X86/X86ELFDynamic.cpp
@@ -0,0 +1,41 @@
+//===- X86ELFDynamic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <mcld/LD/ELFFileFormat.h>
+#include "X86ELFDynamic.h"
+
+using namespace mcld;
+
+X86ELFDynamic::X86ELFDynamic(const GNULDBackend& pParent)
+ : ELFDynamic(pParent), m_HasGOTPLT(false)
+{
+}
+
+X86ELFDynamic::~X86ELFDynamic()
+{
+}
+
+void X86ELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
+ // reservePLTGOT
+ if (m_HasGOTPLT ? pFormat.hasGOTPLT() : pFormat.hasGOT())
+ reserveOne(llvm::ELF::DT_PLTGOT);
+}
+
+void X86ELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
+ // applyPLTGOT
+ if (m_HasGOTPLT) {
+ if (pFormat.hasGOTPLT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
+ }
+ else if (pFormat.hasGOT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+}
+
diff --git a/lib/Target/X86/X86ELFDynamic.h b/lib/Target/X86/X86ELFDynamic.h
new file mode 100644
index 0000000..b9e70ce
--- /dev/null
+++ b/lib/Target/X86/X86ELFDynamic.h
@@ -0,0 +1,38 @@
+//===- X86ELFDynamic.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_ELFDYNAMIC_SECTION_H
+#define MCLD_X86_ELFDYNAMIC_SECTION_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/Target/ELFDynamic.h>
+
+namespace mcld {
+
+class X86ELFDynamic : public ELFDynamic
+{
+public:
+ X86ELFDynamic(const GNULDBackend& pParent);
+ ~X86ELFDynamic();
+
+private:
+ void reserveTargetEntries(const ELFFileFormat& pFormat);
+ void applyTargetEntries(const ELFFileFormat& pFormat);
+
+private:
+ // True if we have .got.plt section, which will avoid GOT0 entries
+ // when PLT isn't used. To support .got.plt section, we must combine
+ // .got section and .got.plt section into a single GOT.
+ bool m_HasGOTPLT;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/X86/X86ELFSectLinker.cpp b/lib/Target/X86/X86ELFSectLinker.cpp
new file mode 100644
index 0000000..009293c
--- /dev/null
+++ b/lib/Target/X86/X86ELFSectLinker.cpp
@@ -0,0 +1,34 @@
+//===- X86ELFSectLinker.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86ELFSectLinker.h"
+
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+X86ELFSectLinker::X86ELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption,
+ pLDBackend) {
+ MCLDInfo &info = pOption.info();
+ // set up target-dependent constraints of attibutes
+ info.attrFactory().constraint().enableWholeArchive();
+ info.attrFactory().constraint().disableAsNeeded();
+ info.attrFactory().constraint().setSharedSystem();
+
+ // set up the predefined attributes
+ info.attrFactory().predefined().setWholeArchive();
+ info.attrFactory().predefined().setDynamic();
+
+}
+
+X86ELFSectLinker::~X86ELFSectLinker()
+{
+}
+
diff --git a/lib/Target/X86/X86ELFSectLinker.h b/lib/Target/X86/X86ELFSectLinker.h
new file mode 100644
index 0000000..5e7abfd
--- /dev/null
+++ b/lib/Target/X86/X86ELFSectLinker.h
@@ -0,0 +1,36 @@
+//===- X86ELFSectLinker.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_ELFSECTLINKER_H
+#define X86_ELFSECTLINKER_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+#include <mcld/CodeGen/SectLinker.h>
+
+namespace mcld
+{
+
+/** \class X86ELFSectLinker
+ * \brief X86ELFSectLinker sets up the environment for linking.
+ *
+ * \see
+ */
+class X86ELFSectLinker : public SectLinker
+{
+public:
+ X86ELFSectLinker(SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend);
+
+ ~X86ELFSectLinker();
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86GOT.cpp b/lib/Target/X86/X86GOT.cpp
new file mode 100644
index 0000000..2784989
--- /dev/null
+++ b/lib/Target/X86/X86GOT.cpp
@@ -0,0 +1,129 @@
+//===- impl.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86GOT.h"
+#include <mcld/LD/LDFileFormat.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <new>
+
+namespace {
+ const size_t X86GOTEntrySize = 4;
+}
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// X86GOT
+X86GOT::X86GOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, X86GOTEntrySize),
+ m_GeneralGOTNum(0), m_GOTPLTNum(0), m_GeneralGOTIterator(),
+ m_GOTPLTIterator(), m_LastGOT0()
+{
+ GOTEntry* Entry = 0;
+
+ // Create GOT0 entries.
+ for (unsigned int i = 0; i < X86GOT0Num; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, X86GOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + X86GOTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (unsigned int i = 1; i < X86GOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_LastGOT0 = it;
+ m_GeneralGOTIterator = it;
+ m_GOTPLTIterator = it;
+}
+
+X86GOT::~X86GOT()
+{
+}
+
+void X86GOT::reserveEntry(size_t pNum)
+{
+ GOTEntry* Entry = 0;
+
+ for (size_t i = 0; i < pNum; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, X86GOTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+
+ m_Section.setSize(m_Section.size() + X86GOTEntrySize);
+ ++m_GeneralGOTNum;
+ }
+}
+
+
+GOTEntry* X86GOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
+{
+ GOTEntry *&Entry = m_GeneralGOTMap[&pInfo];
+ pExist = 1;
+
+ if (!Entry) {
+ pExist = 0;
+
+ ++m_GeneralGOTIterator;
+ assert(m_GeneralGOTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+
+ Entry = llvm::cast<GOTEntry>(&(*m_GeneralGOTIterator));
+ }
+
+ return Entry;
+}
+
+void X86GOT::applyGOT0(uint64_t pAddress)
+{
+ llvm::cast<GOTEntry>
+ (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
+}
+
+X86GOT::iterator X86GOT::begin()
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+X86GOT::const_iterator X86GOT::begin() const
+{
+ return m_SectionData.getFragmentList().begin();
+}
+
+X86GOT::iterator X86GOT::end()
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+X86GOT::const_iterator X86GOT::end() const
+{
+ return m_SectionData.getFragmentList().end();
+}
+
+unsigned int X86GOT::getGOTPLTNum() const
+{ return m_GOTPLTNum; }
+
+X86GOT::iterator X86GOT::getLastGOT0()
+{ return m_LastGOT0; }
+
+const X86GOT::iterator X86GOT::getLastGOT0() const
+{ return m_LastGOT0; }
+
diff --git a/lib/Target/X86/X86GOT.h b/lib/Target/X86/X86GOT.h
new file mode 100644
index 0000000..018aa24
--- /dev/null
+++ b/lib/Target/X86/X86GOT.h
@@ -0,0 +1,91 @@
+//===- X86GOT.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_GOT_H
+#define MCLD_X86_GOT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "X86PLT.h"
+#include <mcld/Target/GOT.h>
+
+namespace mcld
+{
+class LDSection;
+
+/** \class X86GOT
+ * \brief X86 Global Offset Table.
+ */
+
+const unsigned int X86GOT0Num = 3;
+
+class X86GOT : public GOT
+{
+ friend void mcld::X86PLT::reserveEntry(size_t pNum);
+
+ friend mcld::PLTEntry* mcld::X86PLT::getPLTEntry(
+ const mcld::ResolveInfo& pSymbol,bool& pExist);
+
+ friend mcld::GOTEntry* mcld::X86PLT::getGOTPLTEntry(
+ const mcld::ResolveInfo& pSymbol,bool& pExist);
+
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ X86GOT(LDSection& pSection, llvm::MCSectionData& pSectionData);
+
+ ~X86GOT();
+
+ //Reserve general GOT entries.
+ void reserveEntry(size_t pNum = 1);
+
+ GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+ void applyGOT0(uint64_t pAddress);
+
+ iterator begin();
+
+ const_iterator begin() const;
+
+ iterator end();
+
+ const_iterator end() const;
+
+ unsigned int getGOTPLTNum() const;
+
+ iterator getLastGOT0();
+
+ const iterator getLastGOT0() const;
+
+private:
+
+ unsigned int m_GeneralGOTNum;
+ unsigned int m_GOTPLTNum;
+
+ // Used by getGeneralGOTEntry()
+ iterator m_GeneralGOTIterator;
+
+ // Used by getGOTPLTEntry()
+ iterator m_GOTPLTIterator;
+
+ // The last GOT0 entry
+ iterator m_LastGOT0;
+
+ SymbolIndexMapType m_GOTPLTMap;
+ SymbolIndexMapType m_GeneralGOTMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86GOTPLT.cpp b/lib/Target/X86/X86GOTPLT.cpp
new file mode 100644
index 0000000..55596e3
--- /dev/null
+++ b/lib/Target/X86/X86GOTPLT.cpp
@@ -0,0 +1,113 @@
+//===- X86GOTPLT.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86GOTPLT.h"
+#include "mcld/LD/LDFileFormat.h"
+#include <llvm/Support/ErrorHandling.h>
+#include <new>
+
+namespace {
+ const uint64_t X86GOTPLTEntrySize = 4;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+// X86GOTPLT
+X86GOTPLT::X86GOTPLT(LDSection& pSection, llvm::MCSectionData& pSectionData)
+ : GOT(pSection, pSectionData, X86GOTPLTEntrySize), m_GOTPLTIterator()
+{
+ GOTEntry* Entry = 0;
+
+ // Create GOT0 entries.
+ for (int i = 0; i < 3; i++) {
+ Entry = new (std::nothrow) GOTEntry(0, X86GOTPLTEntrySize,
+ &m_SectionData);
+
+ if (!Entry)
+ llvm::report_fatal_error("Allocating GOT0 entries failed!");
+
+ m_Section.setSize(m_Section.size() + X86GOTPLTEntrySize);
+ }
+
+ // Skip GOT0 entries.
+ iterator it = m_SectionData.begin();
+ iterator ie = m_SectionData.end();
+
+ for (size_t i = 1; i < X86GOT0Num; ++i) {
+ if (it == ie)
+ llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+
+ ++it;
+ }
+
+ m_GOTPLTIterator = it;
+}
+
+X86GOTPLT::~X86GOTPLT()
+{
+}
+
+X86GOTPLT::iterator X86GOTPLT::begin()
+{
+ return m_SectionData.begin();
+}
+
+X86GOTPLT::const_iterator X86GOTPLT::begin() const
+{
+ return m_SectionData.begin();
+}
+
+X86GOTPLT::iterator X86GOTPLT::end()
+{
+ return m_SectionData.end();
+}
+
+X86GOTPLT::const_iterator X86GOTPLT::end() const
+{
+ return m_SectionData.end();
+}
+
+void X86GOTPLT::applyGOT0(const uint64_t pAddress)
+{
+ llvm::cast<GOTEntry>
+ (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
+}
+
+void X86GOTPLT::reserveGOTPLTEntry()
+{
+ GOTEntry* got_entry = 0;
+
+ got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
+
+ if (!got_entry)
+ llvm::report_fatal_error("Allocating new memory for GOT failed!");
+
+ m_Section.setSize(m_Section.size() + getEntrySize());
+}
+
+void X86GOTPLT::applyAllGOTPLT(const uint64_t pPLTBase)
+{
+ iterator gotplt_it = begin();
+ iterator gotplt_ie = end();
+
+ for (; gotplt_it != gotplt_ie; ++gotplt_it)
+ llvm::cast<GOTEntry>(*gotplt_it).setContent(pPLTBase);
+}
+
+GOTEntry*& X86GOTPLT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
+{
+ return m_GOTPLTMap[&pSymbol];
+}
+
+X86GOTPLT::iterator X86GOTPLT::getNextGOTPLTEntry()
+{
+ return ++m_GOTPLTIterator;
+}
+
+} //end mcld namespace
diff --git a/lib/Target/X86/X86GOTPLT.h b/lib/Target/X86/X86GOTPLT.h
new file mode 100644
index 0000000..9882cc4
--- /dev/null
+++ b/lib/Target/X86/X86GOTPLT.h
@@ -0,0 +1,70 @@
+//===- X86GOTPLT.h --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_GOTPLT_H
+#define MCLD_X86_GOTPLT_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include "mcld/Target/GOT.h"
+
+namespace mcld
+{
+class LDSection;
+
+/** \class X86GOTPLT
+ * \brief X86 .got.plt section.
+ */
+
+const unsigned int X86GOT0Num = 3;
+
+class X86GOTPLT : public GOT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ X86GOTPLT(LDSection &pSection, llvm::MCSectionData& pSectionData);
+
+ ~X86GOTPLT();
+
+ iterator begin();
+
+ const_iterator begin() const;
+
+ iterator end();
+
+ const_iterator end() const;
+
+// For GOT0
+public:
+ void applyGOT0(const uint64_t pAddress);
+
+// For GOTPLT
+public:
+ void reserveGOTPLTEntry();
+
+ void applyAllGOTPLT(const uint64_t pPLTBase);
+
+ GOTEntry*& lookupGOTPLTMap(const ResolveInfo& pSymbol);
+
+ iterator getNextGOTPLTEntry();
+
+private:
+ iterator m_GOTPLTIterator;
+ SymbolIndexMapType m_GOTPLTMap;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
new file mode 100644
index 0000000..354cd51
--- /dev/null
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -0,0 +1,752 @@
+//===- X86LDBackend.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+#include "X86ELFDynamic.h"
+#include "X86LDBackend.h"
+#include "X86RelocationFactory.h"
+
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/LD/SectionMap.h>
+#include <mcld/MC/MCRegionFragment.h>
+
+#include <cstring>
+
+using namespace mcld;
+
+X86GNULDBackend::X86GNULDBackend()
+ : m_pRelocFactory(NULL),
+ m_pGOT(NULL),
+ m_pPLT(NULL),
+ m_pRelDyn(NULL),
+ m_pRelPLT(NULL),
+ m_pDynamic(NULL) {
+}
+
+X86GNULDBackend::~X86GNULDBackend()
+{
+ if (NULL != m_pRelocFactory)
+ delete m_pRelocFactory;
+ if (NULL != m_pGOT)
+ delete m_pGOT;
+ if (NULL != m_pPLT)
+ delete m_pPLT;
+ if (NULL !=m_pRelDyn)
+ delete m_pRelDyn;
+ if (NULL != m_pRelPLT)
+ delete m_pRelPLT;
+ if (NULL != m_pDynamic)
+ delete m_pDynamic;
+}
+
+RelocationFactory* X86GNULDBackend::getRelocFactory()
+{
+ assert(NULL != m_pRelocFactory);
+ return m_pRelocFactory;
+}
+
+bool X86GNULDBackend::initRelocFactory(const MCLinker& pLinker)
+{
+ if (NULL == m_pRelocFactory) {
+ m_pRelocFactory = new X86RelocationFactory(1024, *this);
+ m_pRelocFactory->setLayout(pLinker.getLayout());
+ }
+ return true;
+}
+
+void X86GNULDBackend::doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // when building shared object, the .got section is needed
+ if(pOutput.type() == Output::DynObj && (NULL == m_pGOT))
+ createX86GOT(pLinker, pOutput);
+}
+
+void X86GNULDBackend::doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ // emit program headers
+ if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
+ emitProgramHdrs(pLinker.getLDInfo().output());
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+X86ELFDynamic& X86GNULDBackend::dynamic()
+{
+ if (NULL == m_pDynamic)
+ m_pDynamic = new X86ELFDynamic(*this);
+
+ return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const X86ELFDynamic& X86GNULDBackend::dynamic() const
+{
+ assert( NULL != m_pDynamic);
+ return *m_pDynamic;
+}
+
+void X86GNULDBackend::createX86GOT(MCLinker& pLinker, const Output& pOutput)
+{
+ // get .got LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& got = file_format->getGOT();
+ m_pGOT = new X86GOT(got, pLinker.getOrCreateSectData(got));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+ if( m_pGOTSymbol != NULL ) {
+ pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+ else {
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ ResolveInfo::Hidden);
+ }
+}
+
+void X86GNULDBackend::createX86PLTandRelPLT(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& plt = file_format->getPLT();
+ LDSection& relplt = file_format->getRelPlt();
+ // create MCSectionData and X86PLT
+ m_pPLT = new X86PLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOT, pOutput);
+
+ // set info of .rel.plt to .plt
+ relplt.setLink(&plt);
+ // create MCSectionData and X86RelDynSection
+ m_pRelPLT = new OutputRelocSection(relplt,
+ pLinker.getOrCreateSectData(relplt),
+ 8);
+}
+
+void X86GNULDBackend::createX86RelDyn(MCLinker& pLinker,
+ const Output& pOutput)
+{
+ // get .rel.dyn LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& reldyn = file_format->getRelDyn();
+ // create MCSectionData and X86RelDynSection
+ m_pRelDyn = new OutputRelocSection(reldyn,
+ pLinker.getOrCreateSectData(reldyn),
+ 8);
+}
+
+ELFFileFormat* X86GNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
+ llvm::Twine(pOutput.type()));
+ return NULL;
+ }
+}
+
+bool X86GNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ return((Output::DynObj == pOutput.type())
+ &&(ResolveInfo::Function == pSym.type())
+ &&(pSym.isDyn() || pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput))
+ );
+}
+
+bool X86GNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const
+{
+ if(pSym.isUndef() && (pOutput.type()==Output::Exec))
+ return false;
+ if(pSym.isAbsolute())
+ return false;
+ if(pOutput.type()==Output::DynObj && isAbsReloc)
+ return true;
+ if(pSym.isDyn() || pSym.isUndef())
+ return true;
+
+ return false;
+}
+
+bool X86GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if(pSym.other() != ResolveInfo::Default)
+ return false;
+
+ if(pOutput.type() != Output::DynObj)
+ return false;
+
+ if(pLDInfo.options().Bsymbolic())
+ return false;
+
+ return true;
+}
+
+void X86GNULDBackend::updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const
+{
+ // Update value keep in addend if we meet a section symbol
+ if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ pReloc.setAddend(pLayout.getOutputOffset(
+ *pInputSym.fragRef()) + pReloc.addend());
+ }
+}
+
+void X86GNULDBackend::scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+
+ switch(pReloc.type()){
+
+ case llvm::ELF::R_386_32:
+ // If buiding PIC object (shared library or PIC executable),
+ // a dynamic relocations with RELATIVE type to this location is needed.
+ // Reserve an entry in .rel.dyn
+ if(Output::DynObj == pOutput.type()) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ return;
+
+ case llvm::ELF::R_386_GOTOFF:
+ case llvm::ELF::R_386_GOTPC:
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ return;
+
+ case llvm::ELF::R_386_PC32:
+ return;
+
+ default:
+ llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
+ llvm::Twine((int) pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ } // end switch
+}
+
+void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+
+ switch(pReloc.type()) {
+ case llvm::ELF::R_386_32:
+ // Absolute relocation type, symbol may needs PLT entry or
+ // dynamic relocation entry
+ if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ // create plt for this symbol if it does not have one
+ if(!(rsym->reserved() & ReservePLT)){
+ // Create .got section if it dosen't exist
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createX86PLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling X86PLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+
+ if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ return;
+
+ case llvm::ELF::R_386_GOTOFF:
+ case llvm::ELF::R_386_GOTPC: {
+ // A GOT section is needed
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ return;
+ }
+
+ case llvm::ELF::R_386_PLT32:
+ // A PLT entry is needed when building shared library
+
+ // return if we already create plt for this symbol
+ if(rsym->reserved() & ReservePLT)
+ return;
+
+ // if symbol is defined in the ouput file and it's not
+ // preemptible, no need plt
+ if(rsym->isDefine() && !rsym->isDyn() &&
+ !isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
+ return;
+ }
+
+ // Create .got section if it dosen't exist
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if(NULL == m_pPLT)
+ createX86PLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling X86PLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ return;
+
+ case llvm::ELF::R_386_GOT32:
+ // Symbol needs GOT entry, reserve entry in .got
+ // return if we already create GOT for this symbol
+ if(rsym->reserved() & (ReserveGOT | GOTRel))
+ return;
+ if(NULL == m_pGOT)
+ createX86GOT(pLinker, pOutput);
+ m_pGOT->reserveEntry();
+ // If building shared object or the symbol is undefined, a dynamic
+ // relocation is needed to relocate this GOT entry. Reserve an
+ // entry in .rel.dyn
+ if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ // create .rel.dyn section if not exist
+ if(NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ // set GOTRel bit
+ rsym->setReserved(rsym->reserved() | GOTRel);
+ return;
+ }
+ // set GOT bit
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
+ return;
+
+ case llvm::ELF::R_386_PC32:
+ // We allow R_386_PC32 only if it isn't preemptible. Otherwise
+ // we will generate writable text section in output.
+ if (!isSymbolPreemptible(*rsym, pLDInfo, pOutput))
+ return;
+
+ default: {
+ llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
+ llvm::Twine((int) pReloc.type()) +
+ llvm::Twine(" in object file"));
+ break;
+ }
+ } // end switch
+}
+
+void X86GNULDBackend::scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+
+ // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
+ // entries should be created.
+ // FIXME: Below judgements concern only .so is generated as output
+ // FIXME: Below judgements concren nothing about TLS related relocation
+
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
+ // is needed
+ if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if(rsym == m_pGOTSymbol->resolveInfo()) {
+ createX86GOT(pLinker, pOutput);
+ }
+ }
+
+ // rsym is local
+ if(rsym->isLocal())
+ scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+
+ // rsym is external
+ else
+ scanGlobalReloc(pReloc, pInputSym ,pLinker, pLDInfo, pOutput);
+
+}
+
+uint64_t X86GNULDBackend::emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const
+{
+ assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+ ELFFileFormat* FileFormat = getOutputFormat(pOutput);
+ assert(FileFormat &&
+ "ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!");
+
+ unsigned int EntrySize = 0;
+ uint64_t RegionSize = 0;
+
+ if (&pSection == &(FileFormat->getPLT())) {
+ assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
+
+ unsigned char* buffer = pRegion.getBuffer();
+
+ m_pPLT->applyPLT0();
+ m_pPLT->applyPLT1();
+
+ X86PLT::iterator it = m_pPLT->begin();
+ unsigned int plt0_size = llvm::cast<X86PLT0>((*it)).getEntrySize();
+
+ memcpy(buffer, llvm::cast<X86PLT0>((*it)).getContent(), plt0_size);
+ RegionSize += plt0_size;
+ ++it;
+
+ X86PLT1* plt1 = 0;
+ X86PLT::iterator ie = m_pPLT->end();
+ while (it != ie) {
+ plt1 = &(llvm::cast<X86PLT1>(*it));
+ EntrySize = plt1->getEntrySize();
+ memcpy(buffer + RegionSize, plt1->getContent(), EntrySize);
+ RegionSize += EntrySize;
+ ++it;
+ }
+ }
+
+ else if (&pSection == &(FileFormat->getGOT())) {
+ assert(m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+
+ m_pGOT->applyGOT0(FileFormat->getDynamic().addr());
+
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ GOTEntry* got = 0;
+ EntrySize = m_pGOT->getEntrySize();
+
+ for (X86GOT::iterator it = m_pGOT->begin(),
+ ie = m_pGOT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ RegionSize += EntrySize;
+ }
+ }
+
+ else
+ llvm::report_fatal_error("unsupported section name "
+ + pSection.name() + " !");
+
+ return RegionSize;
+}
+uint32_t X86GNULDBackend::machine() const
+{
+ return llvm::ELF::EM_386;
+}
+
+X86GOT& X86GNULDBackend::getGOT()
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+const X86GOT& X86GNULDBackend::getGOT() const
+{
+ assert(NULL != m_pGOT);
+ return *m_pGOT;
+}
+
+X86PLT& X86GNULDBackend::getPLT()
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+const X86PLT& X86GNULDBackend::getPLT() const
+{
+ assert(NULL != m_pPLT && "PLT section not exist");
+ return *m_pPLT;
+}
+
+OutputRelocSection& X86GNULDBackend::getRelDyn()
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+const OutputRelocSection& X86GNULDBackend::getRelDyn() const
+{
+ assert(NULL != m_pRelDyn && ".rel.dyn section not exist");
+ return *m_pRelDyn;
+}
+
+OutputRelocSection& X86GNULDBackend::getRelPLT()
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+const OutputRelocSection& X86GNULDBackend::getRelPLT() const
+{
+ assert(NULL != m_pRelPLT && ".rel.plt section not exist");
+ return *m_pRelPLT;
+}
+
+unsigned int
+X86GNULDBackend::getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // FIXME: if command line option, "-z now", is given, we can let the order of
+ // .got and .got.plt be the same as RELRO sections
+ if (&pSectHdr == &file_format->getGOT())
+ return SHO_RELRO_LAST;
+
+ if (&pSectHdr == &file_format->getGOTPLT())
+ return SHO_NON_RELRO_FIRST;
+
+ if (&pSectHdr == &file_format->getPLT())
+ return SHO_PLT;
+
+ return SHO_UNDEFINED;
+}
+
+unsigned int X86GNULDBackend::bitclass() const
+{
+ return 32;
+}
+
+bool X86GNULDBackend::initTargetSectionMap(SectionMap& pSectionMap)
+{
+ return true;
+}
+
+void X86GNULDBackend::initTargetSections(MCLinker& pLinker)
+{
+}
+
+void X86GNULDBackend::initTargetSymbols(MCLinker& pLinker)
+{
+ // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+ // same name in input
+ m_pGOTSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+ "_GLOBAL_OFFSET_TABLE_",
+ false,
+ ResolveInfo::Object,
+ ResolveInfo::Define,
+ ResolveInfo::Local,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+}
+
+/// finalizeSymbol - finalize the symbol value
+/// If the symbol's reserved field is not zero, MCLinker will call back this
+/// function to ask the final value of the symbol
+bool X86GNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+{
+ return false;
+}
+
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+bool
+X86GNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
+{
+ // SymbolCategory contains all symbols that must emit to the output files.
+ // We are not like Google gold linker, we don't remember symbols before symbol
+ // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
+ // don't need to care about some symbols may be changed its category due to symbol
+ // resolution.
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
+
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ // addralign := max value of all common symbols
+ uint64_t addralign = 0x0;
+
+ // Due to the visibility, some common symbols may be forcefully local.
+ SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+ }
+
+ // global common symbols.
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ if ((*com_sym)->value() > addralign)
+ addralign = (*com_sym)->value();
+ }
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // com_sym = symbol_list.commonBegin();
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
+
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+
+ // allocate all common symbols
+ uint64_t offset = bss_sect_hdr->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ (*com_sym)->value());
+ offset += size;
+ }
+
+ bss_sect_hdr->setSize(offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
+}
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+/// createX86LDBackend - the help funtion to create corresponding X86LDBackend
+///
+TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget,
+ const std::string& pTriple)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker is not supported yet");
+ /**
+ return new X86MachOLDBackend(createX86MachOArchiveReader,
+ createX86MachOObjectReader,
+ createX86MachOObjectWriter);
+ **/
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker is not supported yet");
+ /**
+ return new X86COFFLDBackend(createX86COFFArchiveReader,
+ createX86COFFObjectReader,
+ createX86COFFObjectWriter);
+ **/
+ }
+ return new X86GNULDBackend();
+}
+
+} // namespace of mcld
+
+//=============================
+// Force static initialization.
+extern "C" void LLVMInitializeX86LDBackend() {
+ // Register the linker backend
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheX86Target, createX86LDBackend);
+}
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
new file mode 100644
index 0000000..d9a4d56
--- /dev/null
+++ b/lib/Target/X86/X86LDBackend.h
@@ -0,0 +1,257 @@
+//===- X86LDBackend.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_LDBACKEND_H
+#define X86_LDBACKEND_H
+
+#include "X86ELFDynamic.h"
+#include "X86GOT.h"
+#include "X86PLT.h"
+#include <mcld/LD/LDSection.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+namespace mcld {
+
+//===----------------------------------------------------------------------===//
+/// X86GNULDBackend - linker backend of X86 target of GNU ELF format
+///
+class X86GNULDBackend : public GNULDBackend
+{
+public:
+ /** \enum ReservedEntryType
+ * \brief The reserved entry type of reserved space in ResolveInfo.
+ *
+ * This is used for sacnRelocation to record what kinds of entries are
+ * reserved for this resolved symbol
+ *
+ * In X86, there are three kinds of entries, GOT, PLT, and dynamic reloction.
+ * GOT may needs a corresponding relocation to relocate itself, so we
+ * separate GOT to two situations: GOT and GOTRel. Besides, for the same
+ * symbol, there might be two kinds of entries reserved for different location.
+ * For example, reference to the same symbol, one may use GOT and the other may
+ * use dynamic relocation.
+ *
+ * bit: 3 2 1 0
+ * | PLT | GOTRel | GOT | Rel |
+ *
+ * value Name - Description
+ *
+ * 0000 None - no reserved entry
+ * 0001 ReserveRel - reserve an dynamic relocation entry
+ * 0010 ReserveGOT - reserve an GOT entry
+ * 0011 GOTandRel - For different relocation, we've reserved GOT and
+ * Rel for different location.
+ * 0100 GOTRel - reserve an GOT entry and the corresponding Dyncamic
+ * relocation entry which relocate this GOT entry
+ * 0101 GOTRelandRel - For different relocation, we've reserved GOTRel
+ * and relocation entry for different location.
+ * 1000 ReservePLT - reserve an PLT entry and the corresponding GOT,
+ * Dynamic relocation entries
+ * 1001 PLTandRel - For different relocation, we've reserved PLT and
+ * Rel for different location.
+ */
+ enum ReservedEntryType {
+ None = 0,
+ ReserveRel = 1,
+ ReserveGOT = 2,
+ GOTandRel = 3,
+ GOTRel = 4,
+ GOTRelandRel = 5,
+ ReservePLT = 8,
+ PLTandRel = 9
+ };
+
+ X86GNULDBackend();
+
+ ~X86GNULDBackend();
+
+ RelocationFactory* getRelocFactory();
+
+ uint32_t machine() const;
+
+ bool isLittleEndian() const
+ { return true; }
+
+ X86GOT& getGOT();
+
+ const X86GOT& getGOT() const;
+
+ X86PLT& getPLT();
+
+ const X86PLT& getPLT() const;
+
+ unsigned int bitclass() const;
+
+ /// preLayout - Backend can do any needed modification before layout
+ void doPreLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// postLayout -Backend can do any needed modification after layout
+ void doPostLayout(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker);
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ X86ELFDynamic& dynamic();
+
+ /// dynamic - the dynamic section of the target machine.
+ /// Use co-variant return type to return its own dynamic section.
+ const X86ELFDynamic& dynamic() const;
+
+ /// emitSectionData - write out the section data into the memory region.
+ /// When writers get a LDSection whose kind is LDFileFormat::Target, writers
+ /// call back target backend to emit the data.
+ ///
+ /// Backends handle the target-special tables (plt, gp,...) by themselves.
+ /// Backend can put the data of the tables in MCSectionData directly
+ /// - LDSection.getSectionData can get the section data.
+ /// Or, backend can put the data into special data structure
+ /// - backend can maintain its own map<LDSection, table> to get the table
+ /// from given LDSection.
+ ///
+ /// @param pOutput - the output file
+ /// @param pSection - the given LDSection
+ /// @param pInfo - all options in the command line.
+ /// @param pRegion - the region to write out data
+ /// @return the size of the table in the file.
+ uint64_t emitSectionData(const Output& pOutput,
+ const LDSection& pSection,
+ const MCLDInfo& pInfo,
+ MemoryRegion& pRegion) const;
+
+ /// OSABI - the value of e_ident[EI_OSABI]
+ /// FIXME
+ uint8_t OSABI() const
+ { return llvm::ELF::ELFOSABI_NONE; }
+
+ /// ABIVersion - the value of e_ident[EI_ABIVRESION]
+ /// FIXME
+ uint8_t ABIVersion() const
+ { return 0x0; }
+
+ /// flags - the value of ElfXX_Ehdr::e_flags
+ /// FIXME
+ uint64_t flags() const
+ { return 0x0; }
+
+ /// initTargetSectionMap - initialize target dependent section mapping
+ bool initTargetSectionMap(SectionMap& pSectionMap);
+
+ // initRelocFactory - create and initialize RelocationFactory
+ bool initRelocFactory(const MCLinker& pLinker);
+
+ void initTargetSections(MCLinker& pLinker);
+
+ void initTargetSymbols(MCLinker& pLinker);
+
+ /// scanRelocation - determine the empty entries are needed or not and create
+ /// the empty entries if needed.
+ /// For X86, following entries are check to create:
+ /// - GOT entry (for .got and .got.plt sections)
+ /// - PLT entry (for .plt section)
+ /// - dynamin relocation entries (for .rel.plt and .rel.dyn sections)
+ void scanRelocation(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ OutputRelocSection& getRelDyn();
+
+ const OutputRelocSection& getRelDyn() const;
+
+ OutputRelocSection& getRelPLT();
+
+ const OutputRelocSection& getRelPLT() const;
+
+ /// getTargetSectionOrder - compute the layout order of X86 target sections
+ unsigned int getTargetSectionOrder(const Output& pOutput,
+ const LDSection& pSectHdr) const;
+
+ /// finalizeSymbol - finalize the symbol value
+ /// If the symbol's reserved field is not zero, MCLinker will call back this
+ /// function to ask the final value of the symbol
+ bool finalizeSymbol(LDSymbol& pSymbol) const;
+
+ /// allocateCommonSymbols - allocate common symbols in the corresponding
+ /// sections.
+ bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+
+public:
+ bool isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+private:
+ void scanLocalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ void scanGlobalReloc(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ MCLinker& pLinker,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput);
+
+ bool isSymbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const;
+
+ bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
+ const Output& pOutput,
+ bool isAbsReloc) const;
+
+ void updateAddend(Relocation& pReloc,
+ const LDSymbol& pInputSym,
+ const Layout& pLayout) const;
+
+ void createX86GOT(MCLinker& pLinker, const Output& pOutput);
+ void createX86PLTandRelPLT(MCLinker& pLinker, const Output& pOutput);
+ void createX86RelDyn(MCLinker& pLinker, const Output& pOutput);
+
+ ELFFileFormat* getOutputFormat(const Output& pOutput) const;
+
+private:
+ RelocationFactory* m_pRelocFactory;
+ X86GOT* m_pGOT;
+ X86PLT* m_pPLT;
+ /// m_RelDyn - dynamic relocation table of .rel.dyn
+ OutputRelocSection* m_pRelDyn;
+ /// m_RelPLT - dynamic relocation table of .rel.plt
+ OutputRelocSection* m_pRelPLT;
+
+ X86ELFDynamic* m_pDynamic;
+ LDSymbol* m_pGOTSymbol;
+};
+
+//===----------------------------------------------------------------------===//
+/// X86MachOLDBackend - linker backend of X86 target of MachO format
+///
+/**
+class X86MachOLDBackend : public DarwinX86LDBackend
+{
+public:
+ X86MachOLDBackend();
+ ~X86MachOLDBackend();
+
+private:
+ MCMachOTargetArchiveReader *createTargetArchiveReader() const;
+ MCMachOTargetObjectReader *createTargetObjectReader() const;
+ MCMachOTargetObjectWriter *createTargetObjectWriter() const;
+
+};
+**/
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86PLT.cpp b/lib/Target/X86/X86PLT.cpp
new file mode 100644
index 0000000..c5e05f9
--- /dev/null
+++ b/lib/Target/X86/X86PLT.cpp
@@ -0,0 +1,279 @@
+//===- X86PLT.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86GOT.h"
+#include "X86PLT.h"
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <new>
+
+namespace {
+
+const uint8_t x86_dyn_plt0[] = {
+ 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx)
+ 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx)
+ 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+};
+
+const uint8_t x86_dyn_plt1[] = {
+ 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
+};
+
+const uint8_t x86_exec_plt0[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8)
+ 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+};
+
+const uint8_t x86_exec_plt1[] = {
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
+};
+
+}
+
+namespace mcld {
+
+X86PLT0::X86PLT0(llvm::MCSectionData* pParent, unsigned int pSize)
+ : PLTEntry(pSize, pParent) { }
+
+X86PLT1::X86PLT1(llvm::MCSectionData* pParent, unsigned int pSize)
+ : PLTEntry(pSize, pParent) { }
+
+//===----------------------------------------------------------------------===//
+// X86PLT
+
+X86PLT::X86PLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ X86GOT &pGOTPLT,
+ const Output& pOutput)
+ : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator()
+{
+ assert (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type());
+ if (Output::DynObj == pOutput.type()) {
+ m_PLT0 = x86_dyn_plt0;
+ m_PLT1 = x86_dyn_plt1;
+ m_PLT0Size = sizeof (x86_dyn_plt0);
+ m_PLT1Size = sizeof (x86_dyn_plt1);
+ }
+ else {
+ m_PLT0 = x86_exec_plt0;
+ m_PLT1 = x86_exec_plt1;
+ m_PLT0Size = sizeof (x86_exec_plt0);
+ m_PLT1Size = sizeof (x86_exec_plt1);
+ }
+ X86PLT0* plt0_entry = new X86PLT0(&m_SectionData, m_PLT0Size);
+
+ m_Section.setSize(m_Section.size() + plt0_entry->getEntrySize());
+
+ m_PLTEntryIterator = pSectionData.begin();
+}
+
+X86PLT::~X86PLT()
+{
+}
+
+void X86PLT::reserveEntry(size_t pNum)
+{
+ X86PLT1* plt1_entry = 0;
+ GOTEntry* got_entry = 0;
+
+ for (size_t i = 0; i < pNum; ++i) {
+ plt1_entry = new (std::nothrow) X86PLT1(&m_SectionData, m_PLT1Size);
+
+ if (!plt1_entry)
+ llvm::report_fatal_error("Allocating new memory for X86PLT1 failed!");
+
+ m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
+
+ got_entry= new (std::nothrow) GOTEntry(0, m_GOT.getEntrySize(),
+ &(m_GOT.m_SectionData));
+
+ if (!got_entry)
+ llvm::report_fatal_error("Allocating new memory for GOT failed!");
+
+ m_GOT.m_Section.setSize(m_GOT.m_Section.size() + m_GOT.f_EntrySize);
+
+ ++(m_GOT.m_GOTPLTNum);
+ ++(m_GOT.m_GeneralGOTIterator);
+ }
+}
+
+PLTEntry* X86PLT::getPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ X86PLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+
+ pExist = 1;
+
+ if (!PLTEntry) {
+ GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
+ assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+ ++(m_GOT.m_GOTPLTIterator);
+
+ PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
+ }
+
+ return PLTEntry;
+}
+
+GOTEntry* X86PLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
+{
+ GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
+
+ pExist = 1;
+
+ if (!GOTPLTEntry) {
+ X86PLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
+ assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
+
+ pExist = 0;
+
+ // This will skip PLT0.
+ ++m_PLTEntryIterator;
+ assert(m_PLTEntryIterator != m_SectionData.end() &&
+ "The number of PLT Entries and ResolveInfo doesn't match");
+ ++(m_GOT.m_GOTPLTIterator);
+
+ PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
+ GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
+ }
+
+ return GOTPLTEntry;
+}
+
+X86PLT0* X86PLT::getPLT0() const {
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, getPLT0 failed!");
+
+ X86PLT0* plt0 = &(llvm::cast<X86PLT0>(*first));
+
+ return plt0;
+}
+
+// FIXME: It only works on little endian machine.
+void X86PLT::applyPLT0() {
+
+ iterator first = m_SectionData.getFragmentList().begin();
+ iterator end = m_SectionData.getFragmentList().end();
+
+ assert(first!=end && "FragmentList is empty, applyPLT0 failed!");
+
+ X86PLT0* plt0 = &(llvm::cast<X86PLT0>(*first));
+
+ unsigned char* data = 0;
+ data = static_cast<unsigned char*>(malloc(plt0->getEntrySize()));
+
+ if (!data)
+ llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+
+ memcpy(data, m_PLT0, plt0->getEntrySize());
+
+ if (m_PLT0 == x86_exec_plt0) {
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+ uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
+ *offset = got_base + 4;
+ offset = reinterpret_cast<uint32_t*>(data + 8);
+ *offset = got_base + 8;
+ }
+
+ plt0->setContent(data);
+}
+
+// FIXME: It only works on little endian machine.
+void X86PLT::applyPLT1() {
+
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.getSection().addr();
+ assert(got_base && ".got base address is NULL!");
+
+ X86PLT::iterator it = m_SectionData.begin();
+ X86PLT::iterator ie = m_SectionData.end();
+ assert(it!=ie && "FragmentList is empty, applyPLT1 failed!");
+
+ uint64_t GOTEntrySize = m_GOT.getEntrySize();
+
+ // Skip GOT0
+ uint64_t GOTEntryOffset = GOTEntrySize * X86GOT0Num;
+
+ //skip PLT0
+ uint64_t PLTEntryOffset = m_PLT0Size;
+ ++it;
+
+ X86PLT1* plt1 = 0;
+
+ uint64_t PLTRelOffset = 0;
+
+ while (it != ie) {
+ plt1 = &(llvm::cast<X86PLT1>(*it));
+ unsigned char *data;
+ data = static_cast<unsigned char*>(malloc(plt1->getEntrySize()));
+
+ if (!data)
+ llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+
+ memcpy(data, m_PLT1, plt1->getEntrySize());
+
+ uint32_t* offset;
+
+ offset = reinterpret_cast<uint32_t*>(data + 2);
+ *offset = GOTEntryOffset;
+ GOTEntryOffset += GOTEntrySize;
+
+ offset = reinterpret_cast<uint32_t*>(data + 7);
+ *offset = PLTRelOffset;
+ PLTRelOffset += sizeof (llvm::ELF::Elf32_Rel);
+
+ offset = reinterpret_cast<uint32_t*>(data + 12);
+ *offset = -(PLTEntryOffset + 12 + 4);
+ PLTEntryOffset += m_PLT1Size;
+
+ plt1->setContent(data);
+ ++it;
+ }
+
+ unsigned int GOTPLTNum = m_GOT.getGOTPLTNum();
+
+ if (GOTPLTNum != 0) {
+ X86GOT::iterator gotplt_it = m_GOT.getLastGOT0();
+ X86GOT::iterator list_ie = m_GOT.getSectionData().getFragmentList().end();
+
+ ++gotplt_it;
+ uint64_t PLTEntryAddress = plt_base + m_PLT0Size;
+ for (unsigned int i = 0; i < GOTPLTNum; ++i) {
+ if (gotplt_it == list_ie)
+ llvm::report_fatal_error(
+ "The number of got.plt entries is inconsistent!");
+
+ llvm::cast<GOTEntry>(*gotplt_it).setContent(PLTEntryAddress + 6);
+ PLTEntryAddress += m_PLT1Size;
+ ++gotplt_it;
+ }
+ }
+}
+
+} // end namespace mcld
+
diff --git a/lib/Target/X86/X86PLT.h b/lib/Target/X86/X86PLT.h
new file mode 100644
index 0000000..dd72f52
--- /dev/null
+++ b/lib/Target/X86/X86PLT.h
@@ -0,0 +1,91 @@
+//===- X86PLT.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_PLT_H
+#define X86_PLT_H
+
+#include <mcld/Target/PLT.h>
+
+namespace mcld {
+
+class X86GOT;
+class GOTEntry;
+class Output;
+
+class X86PLT0 : public PLTEntry {
+public:
+ X86PLT0(llvm::MCSectionData* pParent, unsigned int pSize);
+};
+
+class X86PLT1 : public PLTEntry {
+public:
+ X86PLT1(llvm::MCSectionData* pParent, unsigned int pSize);
+};
+
+/** \class X86PLT
+ * \brief X86 Procedure Linkage Table
+ */
+class X86PLT : public PLT
+{
+ typedef llvm::DenseMap<const ResolveInfo*, X86PLT1*> SymbolIndexType;
+
+public:
+ typedef llvm::MCSectionData::iterator iterator;
+ typedef llvm::MCSectionData::const_iterator const_iterator;
+
+public:
+ X86PLT(LDSection& pSection,
+ llvm::MCSectionData& pSectionData,
+ X86GOT& pGOTPLT,
+ const Output& pOutput);
+ ~X86PLT();
+
+// Override virtual function.
+public:
+
+ // reserveEntry is X86GOT friend function.
+ void reserveEntry(size_t pNum = 1) ;
+
+ PLTEntry* getPLTEntry(const ResolveInfo& pSymbol, bool& pExist) ;
+
+ GOTEntry* getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+public:
+
+ iterator begin() { return m_SectionData.begin(); }
+
+ const_iterator begin() const { return m_SectionData.begin(); }
+
+ iterator end() { return m_SectionData.end(); }
+
+ const_iterator end() const { return m_SectionData.end(); }
+
+ X86PLT0* getPLT0() const;
+
+ void applyPLT0();
+
+ void applyPLT1();
+
+private:
+ X86GOT& m_GOT;
+
+ // Used by getEntry() for mapping a ResolveInfo
+ // instance to a PLT1 Entry.
+ iterator m_PLTEntryIterator;
+
+ SymbolIndexType m_PLTEntryMap;
+
+ const uint8_t *m_PLT0;
+ const uint8_t *m_PLT1;
+ unsigned int m_PLT0Size;
+ unsigned int m_PLT1Size;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/lib/Target/X86/X86RelocationFactory.cpp b/lib/Target/X86/X86RelocationFactory.cpp
new file mode 100644
index 0000000..15b9a6b
--- /dev/null
+++ b/lib/Target/X86/X86RelocationFactory.cpp
@@ -0,0 +1,361 @@
+//===- X86RelocationFactory.cpp -------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/Support/ELF.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Layout.h>
+
+#include "X86RelocationFactory.h"
+#include "X86RelocationFunctions.h"
+
+using namespace mcld;
+
+DECL_X86_APPLY_RELOC_FUNCS
+
+//===--------------------------------------------------------------------===//
+// X86RelocationFactory
+X86RelocationFactory::X86RelocationFactory(size_t pNum,
+ X86GNULDBackend& pParent)
+ : RelocationFactory(pNum),
+ m_Target(pParent) {
+}
+
+X86RelocationFactory::~X86RelocationFactory()
+{
+}
+
+void X86RelocationFactory::applyRelocation(Relocation& pRelocation,
+ const MCLDInfo& pLDInfo)
+{
+ Relocation::Type type = pRelocation.type();
+
+ /// the prototype of applying function
+ typedef Result (*ApplyFunctionType)(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent);
+
+ // the table entry of applying functions
+ struct ApplyFunctionTriple {
+ ApplyFunctionType func;
+ unsigned int type;
+ const char* name;
+ };
+
+ // declare the table of applying functions
+ static ApplyFunctionTriple apply_functions[] = {
+ DECL_X86_APPLY_RELOC_FUNC_PTRS
+ };
+
+ if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) {
+ llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") +
+ llvm::Twine((int) type) +
+ llvm::Twine(" to symbol `") +
+ pRelocation.symInfo()->name() +
+ llvm::Twine("'."));
+ return;
+ }
+
+ // apply the relocation
+ Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
+
+ // check result
+ if (Overflow == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' causes overflow. on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+
+ if (BadReloc == result) {
+ llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
+ llvm::Twine(apply_functions[type].name) +
+ llvm::Twine("' encounters unexpected opcode. "
+ "on symbol: `") +
+ llvm::Twine(pRelocation.symInfo()->name()) +
+ llvm::Twine("'."));
+ return;
+ }
+}
+
+
+
+// non-member functions
+
+//=========================================//
+// Relocation helper function //
+//=========================================//
+
+// Check if symbol can use relocation R_386_RELATIVE
+static bool
+helper_use_relative_reloc(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const X86RelocationFactory& pFactory)
+
+{
+ // if symbol is dynamic or undefine or preemptible
+ if(pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output()))
+ return false;
+ return true;
+}
+
+static
+GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86GNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+ if (!exist) {
+ // If we first get this GOT entry, we should initialize it.
+ if (rsym->reserved() & X86GNULDBackend::ReserveGOT) {
+ // No corresponding dynamic relocation, initialize to the symbol value.
+ got_entry.setContent(pReloc.symValue());
+ }
+ else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, true, exist);
+ assert(!exist && "GOT entry not exist, but DynRel entry exist!");
+ if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ // Initialize got entry to target symbol address
+ got_entry.setContent(pReloc.symValue());
+ rel_entry.setType(llvm::ELF::R_386_RELATIVE);
+ rel_entry.setSymInfo(0);
+ }
+ else {
+ got_entry.setContent(0);
+ rel_entry.setType(llvm::ELF::R_386_GLOB_DAT);
+ rel_entry.setSymInfo(rsym);
+ }
+ rel_entry.targetRef().assign(got_entry);
+ }
+ else {
+ llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ }
+ }
+ return got_entry;
+}
+
+
+static
+X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent)
+{
+ return pParent.getTarget().getGOT().getSection().addr();
+}
+
+
+static
+X86RelocationFactory::Address helper_GOT(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo, pParent);
+ return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
+}
+
+
+static
+PLTEntry& helper_get_PLT_and_init(Relocation& pReloc,
+ X86RelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86GNULDBackend& ld_backend = pParent.getTarget();
+
+ bool exist;
+ PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist);
+ if (!exist) {
+ // If we first get this PLT entry, we should initialize it.
+ if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ GOTEntry& gotplt_entry =
+ *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist);
+ // Initialize corresponding dynamic relocation.
+ Relocation& rel_entry =
+ *ld_backend.getRelPLT().getEntry(*rsym, true, exist);
+ assert(!exist && "PLT entry not exist, but DynRel entry exist!");
+ rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT);
+ rel_entry.targetRef().assign(gotplt_entry);
+ rel_entry.setSymInfo(rsym);
+ }
+ else {
+ llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ }
+ }
+ return plt_entry;
+}
+
+
+
+static
+X86RelocationFactory::Address helper_PLT_ORG(X86RelocationFactory& pParent)
+{
+ return pParent.getTarget().getPLT().getSection().addr();
+}
+
+
+static
+X86RelocationFactory::Address helper_PLT(Relocation& pReloc,
+ X86RelocationFactory& pParent)
+{
+ PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
+ return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry);
+}
+
+// Get an relocation entry in .rel.dyn and set its type to pType,
+// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
+static
+void helper_DynRel(Relocation& pReloc,
+ X86RelocationFactory::Type pType,
+ X86RelocationFactory& pParent)
+{
+ // rsym - The relocation target symbol
+ ResolveInfo* rsym = pReloc.symInfo();
+ X86GNULDBackend& ld_backend = pParent.getTarget();
+ bool exist;
+
+ Relocation& rel_entry =
+ *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
+ rel_entry.setType(pType);
+ rel_entry.targetRef() = pReloc.targetRef();
+
+ if(pType == llvm::ELF::R_386_RELATIVE)
+ rel_entry.setSymInfo(0);
+ else
+ rel_entry.setSymInfo(rsym);
+}
+
+
+//=========================================//
+// Each relocation function implementation //
+//=========================================//
+
+// R_386_NONE
+X86RelocationFactory::Result none(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ return X86RelocationFactory::OK;
+}
+
+// R_386_32: S + A
+X86RelocationFactory::Result abs32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ ResolveInfo* rsym = pReloc.symInfo();
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ RelocationFactory::DWord S = pReloc.symValue();
+
+ if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
+ helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
+ pReloc.target() = S + A;
+ return X86RelocationFactory::OK;
+ }
+ else if(!rsym->isLocal()) {
+ if(rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ pReloc.target() = S + A;
+ }
+ if(rsym->reserved() & X86GNULDBackend::ReserveRel) {
+ if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
+ helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
+ }
+ else {
+ helper_DynRel(pReloc, pReloc.type(), pParent);
+ return X86RelocationFactory::OK;
+ }
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = S + A;
+ return X86RelocationFactory::OK;
+}
+
+// R_386_PC32: S + A - P
+X86RelocationFactory::Result rel32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ // perform static relocation
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ pReloc.target() = pReloc.symValue() + A
+ - pReloc.place(pParent.getLayout());
+ return X86RelocationFactory::OK;
+}
+
+// R_386_GOTOFF: S + A - GOT_ORG
+X86RelocationFactory::Result gotoff32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ X86RelocationFactory::Address S = pReloc.symValue();
+
+ pReloc.target() = S + A - GOT_ORG;
+ return X86RelocationFactory::OK;
+}
+
+// R_386_GOTPC: GOT_ORG + A - P
+X86RelocationFactory::Result gotpc32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ // Apply relocation.
+ pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout());
+ return X86RelocationFactory::OK;
+}
+
+// R_386_GOT32: GOT(S) + A - GOT_ORG
+X86RelocationFactory::Result got32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ if(!(pReloc.symInfo()->reserved()
+ & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
+ return X86RelocationFactory::BadReloc;
+ }
+ X86RelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
+ // Apply relocation.
+ pReloc.target() = GOT_S + A - GOT_ORG;
+ return X86RelocationFactory::OK;
+}
+
+// R_386_PLT32: PLT(S) + A - P
+X86RelocationFactory::Result plt32(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ X86RelocationFactory& pParent)
+{
+ // PLT_S depends on if there is a PLT entry.
+ X86RelocationFactory::Address PLT_S;
+ if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
+ PLT_S = helper_PLT(pReloc, pParent);
+ else
+ PLT_S = pReloc.symValue();
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ X86RelocationFactory::Address P = pReloc.place(pParent.getLayout());
+ pReloc.target() = PLT_S + A - P;
+ return X86RelocationFactory::OK;
+}
diff --git a/lib/Target/X86/X86RelocationFactory.h b/lib/Target/X86/X86RelocationFactory.h
new file mode 100644
index 0000000..6a6c372
--- /dev/null
+++ b/lib/Target/X86/X86RelocationFactory.h
@@ -0,0 +1,58 @@
+//===- X86RelocationFactory.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_RELOCATION_FACTORY_H
+#define X86_RELOCATION_FACTORY_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+#include <mcld/LD/RelocationFactory.h>
+#include <mcld/Target/GOT.h>
+#include "X86LDBackend.h"
+
+namespace mcld
+{
+
+/** \class X86RelocationFactory
+ * \brief X86RelocationFactory creates and destroys the X86 relocations.
+ *
+ */
+class X86RelocationFactory : public RelocationFactory
+{
+public:
+ /** \enum Reloc
+ * \brief Reloc is the result of applying functions.
+ */
+ enum Result
+ {
+ OK,
+ Overflow,
+ BadReloc
+ };
+
+public:
+ X86RelocationFactory(size_t pNum, X86GNULDBackend& pParent);
+ ~X86RelocationFactory();
+
+ void applyRelocation(Relocation& pRelocation, const MCLDInfo& pLDInfo);
+
+ X86GNULDBackend& getTarget()
+ { return m_Target; }
+
+ const X86GNULDBackend& getTarget() const
+ { return m_Target; }
+
+private:
+ X86GNULDBackend& m_Target;
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/lib/Target/X86/X86RelocationFunctions.h b/lib/Target/X86/X86RelocationFunctions.h
new file mode 100644
index 0000000..46d4f34
--- /dev/null
+++ b/lib/Target/X86/X86RelocationFunctions.h
@@ -0,0 +1,36 @@
+//===- X86RelocationFunction.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DECL_X86_APPLY_RELOC_FUNC(Name) \
+static X86RelocationFactory::Result Name (Relocation& pEntry, \
+ const MCLDInfo& pLDInfo, \
+ X86RelocationFactory& pParent);
+
+#define DECL_X86_APPLY_RELOC_FUNCS \
+DECL_X86_APPLY_RELOC_FUNC(none) \
+DECL_X86_APPLY_RELOC_FUNC(abs32) \
+DECL_X86_APPLY_RELOC_FUNC(rel32) \
+DECL_X86_APPLY_RELOC_FUNC(plt32) \
+DECL_X86_APPLY_RELOC_FUNC(got32) \
+DECL_X86_APPLY_RELOC_FUNC(gotoff32) \
+DECL_X86_APPLY_RELOC_FUNC(gotpc32)
+
+
+#define DECL_X86_APPLY_RELOC_FUNC_PTRS \
+ { &none, 0, "R_386_NONE" }, \
+ { &abs32, 1, "R_386_32" }, \
+ { &rel32, 2, "R_386_PC32" }, \
+ { &got32, 3, "R_386_GOT32" }, \
+ { &plt32, 4, "R_386_PLT32" }, \
+ { &none, 5, "R_386_COPY" }, \
+ { &none, 6, "R_386_GLOB_DAT" }, \
+ { &none, 7, "R_386_JMP_SLOT" }, \
+ { &none, 8, "R_386_RELATIVE" }, \
+ { &gotoff32, 9, "R_386_GOTOFF" }, \
+ { &gotpc32, 10, "R_386_GOTPC" }
diff --git a/lib/Target/X86/X86SectLinker.cpp b/lib/Target/X86/X86SectLinker.cpp
new file mode 100644
index 0000000..793b97b
--- /dev/null
+++ b/lib/Target/X86/X86SectLinker.cpp
@@ -0,0 +1,47 @@
+//===- X86SectLinker.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/TargetRegistry.h>
+
+#include "X86.h"
+#include "X86AndroidSectLinker.h"
+#include "X86ELFSectLinker.h"
+
+using namespace mcld;
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+/// createX86SectLinker - the help funtion to create corresponding X86SectLinker
+///
+SectLinker* createX86SectLinker(const std::string &pTriple,
+ SectLinkerOption &pOption,
+ mcld::TargetLDBackend &pLDBackend)
+{
+ Triple theTriple(pTriple);
+ if (theTriple.isOSDarwin()) {
+ assert(0 && "MachO linker has not supported yet");
+ }
+ if (theTriple.isOSWindows()) {
+ assert(0 && "COFF linker has not supported yet");
+ }
+
+ // For now, use Android SectLinker directly
+ return new X86AndroidSectLinker(pOption,
+ pLDBackend);
+}
+
+} // namespace of mcld
+
+//==========================
+// X86SectLinker
+extern "C" void LLVMInitializeX86SectLinker() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterSectLinker(TheX86Target, createX86SectLinker);
+}
+
diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp
new file mode 100644
index 0000000..b036137
--- /dev/null
+++ b/lib/Target/X86/X86TargetMachine.cpp
@@ -0,0 +1,34 @@
+//===- X86TargetMachine.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "X86TargetMachine.h"
+
+#include "mcld/Target/TargetMachine.h"
+#include "mcld/Support/TargetRegistry.h"
+#include "mcld/MC/MCLDInfo.h"
+#include "X86.h"
+
+extern "C" void LLVMInitializeX86LDTarget() {
+ // Register createTargetMachine function pointer to mcld::Target
+ mcld::RegisterTargetMachine<mcld::X86TargetMachine> X(mcld::TheX86Target);
+}
+
+mcld::X86TargetMachine::X86TargetMachine(llvm::TargetMachine& pPM,
+ const mcld::Target &pTarget,
+ const std::string& pTriple)
+ : mcld::LLVMTargetMachine(pPM, pTarget, pTriple) {
+ // arg1 - the number of total attributes
+ // arg2 - the most possible number of input files
+ m_pLDInfo = new MCLDInfo(pTriple, 32, 64);
+}
+
+mcld::X86TargetMachine::~X86TargetMachine()
+{
+ delete m_pLDInfo;
+}
+
diff --git a/lib/Target/X86/X86TargetMachine.h b/lib/Target/X86/X86TargetMachine.h
new file mode 100644
index 0000000..3ba9e59
--- /dev/null
+++ b/lib/Target/X86/X86TargetMachine.h
@@ -0,0 +1,40 @@
+//===- X86TargetMachine.h -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_X86_TARGET_MACHINE_H
+#define MCLD_X86_TARGET_MACHINE_H
+#include "mcld/Target/TargetMachine.h"
+#include "X86.h"
+
+namespace mcld
+{
+
+class X86TargetMachine : public LLVMTargetMachine
+{
+protected:
+ MCLDInfo *m_pLDInfo;
+
+public:
+ X86TargetMachine(llvm::TargetMachine &pTM,
+ const mcld::Target &pTarget,
+ const std::string &pTriple);
+
+ virtual ~X86TargetMachine();
+
+ mcld::MCLDInfo& getLDInfo()
+ { return *m_pLDInfo; }
+
+ const mcld::MCLDInfo& getLDInfo() const
+ { return *m_pLDInfo; }
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/m4/gtest.m4 b/m4/gtest.m4
new file mode 100644
index 0000000..6598ba7
--- /dev/null
+++ b/m4/gtest.m4
@@ -0,0 +1,74 @@
+dnl GTEST_LIB_CHECK([minimum version [,
+dnl action if found [,action if not found]]])
+dnl
+dnl Check for the presence of the Google Test library, optionally at a minimum
+dnl version, and indicate a viable version with the HAVE_GTEST flag. It defines
+dnl standard variables for substitution including GTEST_CPPFLAGS,
+dnl GTEST_CXXFLAGS, GTEST_LDFLAGS, and GTEST_LIBS. It also defines
+dnl GTEST_VERSION as the version of Google Test found. Finally, it provides
+dnl optional custom action slots in the event GTEST is found or not.
+AC_DEFUN([GTEST_LIB_CHECK],
+[
+dnl Provide a flag to enable or disable Google Test usage.
+AC_ARG_ENABLE([gtest],
+ [AS_HELP_STRING([--enable-gtest],
+ [Enable tests using the Google C++ Testing Framework.
+ (Default is enabled.)])],
+ [],
+ [enable_gtest=])
+AC_ARG_VAR([GTEST_CONFIG],
+ [The exact path of Google Test's 'gtest-config' script.])
+AC_ARG_VAR([GTEST_CPPFLAGS],
+ [C-like preprocessor flags for Google Test.])
+AC_ARG_VAR([GTEST_CXXFLAGS],
+ [C++ compile flags for Google Test.])
+AC_ARG_VAR([GTEST_LDFLAGS],
+ [Linker path and option flags for Google Test.])
+AC_ARG_VAR([GTEST_LIBS],
+ [Library linking flags for Google Test.])
+AC_ARG_VAR([GTEST_VERSION],
+ [The version of Google Test available.])
+HAVE_GTEST="no"
+AS_IF([test "x${enable_gtest}" != "xno"],
+ [AC_MSG_CHECKING([for 'gtest-config'])
+ AS_IF([test "x${enable_gtest}" != "xyes"],
+ [AS_IF([test -x "${enable_gtest}/scripts/gtest-config"],
+ [GTEST_CONFIG="${enable_gtest}/scripts/gtest-config"],
+ [GTEST_CONFIG="${enable_gtest}/bin/gtest-config"])
+ AS_IF([test -x "${GTEST_CONFIG}"], [],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([dnl
+Unable to locate either a built or installed Google Test.
+The specific location '${enable_gtest}' was provided for a built or installed
+Google Test, but no 'gtest-config' script could be found at this location.])
+ ])],
+ [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])])
+ AS_IF([test -x "${GTEST_CONFIG}"],
+ [AC_MSG_RESULT([${GTEST_CONFIG}])
+ m4_ifval([$1],
+ [_gtest_min_version="--min-version=$1"
+ AC_MSG_CHECKING([for Google Test at least version >= $1])],
+ [_gtest_min_version="--min-version=0"
+ AC_MSG_CHECKING([for Google Test])])
+ AS_IF([${GTEST_CONFIG} ${_gtest_min_version}],
+ [AC_MSG_RESULT([yes])
+ HAVE_GTEST='yes'],
+ [AC_MSG_RESULT([no])])],
+ [AC_MSG_RESULT([no])])
+ AS_IF([test "x${HAVE_GTEST}" = "xyes"],
+ [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags`
+ GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags`
+ GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags`
+ GTEST_LIBS=`${GTEST_CONFIG} --libs`
+ GTEST_VERSION=`${GTEST_CONFIG} --version`
+ AC_DEFINE([HAVE_GTEST],[1],[Defined when Google Test is available.])],
+ [AS_IF([test "x${enable_gtest}" = "xyes"],
+ [AC_MSG_ERROR([dnl
+Google Test was enabled, but no viable version could be found.])
+ ])])])
+AC_SUBST([HAVE_GTEST])
+AM_CONDITIONAL([HAVE_GTEST],[test "x$HAVE_GTEST" = "xyes"])
+AS_IF([test "x$HAVE_GTEST" = "xyes"],
+ [m4_ifval([$2], [$2])],
+ [m4_ifval([$3], [$3])])
+])
diff --git a/m4/llvm-target.m4 b/m4/llvm-target.m4
new file mode 100644
index 0000000..0dbcd51
--- /dev/null
+++ b/m4/llvm-target.m4
@@ -0,0 +1,65 @@
+dnl
+dnl @synopsis ENUM_LLVM_TARGETS
+dnl
+dnl @summary enumlate LLVM Targets, set up variables:
+dnl LLVM_ENUM_TARGETS
+dnl LLVM_ENUM_LINKERS
+dnl
+dnl Luba Tang <lubatang@mediatek.com>
+
+AC_DEFUN([ENUM_LLVM_TARGETS],
+[dnl
+ dnl from ${LLVM}/autoconf/configure.ac
+ dnl Allow specific targets to be specified for building (or not)
+ TARGETS_TO_BUILD="";
+
+ AC_ARG_ENABLE([targets],
+ [AS_HELP_STRING([--enable-targets],
+ [Build specific host targets: all or target1,target2,... Valid targets are:
+ host, x86, x86_64, sparc, powerpc, alpha, arm, mips, spu,
+ xcore, msp430, systemz, blackfin, ptx, cbe, and cpp (default=all)])],
+ [],
+ [enableval=all])
+
+ case "$enableval" in
+ all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha ARM Mips CellSPU XCore MSP430 SystemZ Blackfin CBackend CppBackend MBlaze PTX" ;;
+ *)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do
+ case "$a_target" in
+ x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;;
+ x86_64) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;;
+ sparc) TARGETS_TO_BUILD="Sparc $TARGETS_TO_BUILD" ;;
+ powerpc) TARGETS_TO_BUILD="PowerPC $TARGETS_TO_BUILD" ;;
+ alpha) TARGETS_TO_BUILD="Alpha $TARGETS_TO_BUILD" ;;
+ arm) TARGETS_TO_BUILD="ARM $TARGETS_TO_BUILD" ;;
+ mips) TARGETS_TO_BUILD="Mips $TARGETS_TO_BUILD" ;;
+ spu) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
+ xcore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
+ msp430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
+ systemz) TARGETS_TO_BUILD="SystemZ $TARGETS_TO_BUILD" ;;
+ blackfin) TARGETS_TO_BUILD="Blackfin $TARGETS_TO_BUILD" ;;
+ cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;;
+ cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;;
+ mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;;
+ ptx) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;;
+ *) AC_MSG_ERROR([Unrecognized target $a_target]) ;;
+ esac
+ done
+ ;;
+ esac
+ AC_SUBST(TARGETS_TO_BUILD,$TARGETS_TO_BUILD)
+
+ dnl Build the LLVM_TARGET and LLVM_... macros for Targets.def and the individual
+ dnl target feature def files.
+ LLVM_ENUM_TARGETS=""
+ LLVM_ENUM_LINKERS=""
+ for target_to_build in $TARGETS_TO_BUILD; do
+ if test -d ${srcdir}/lib/Target/${target_to_build} ; then
+ LLVM_ENUM_TARGETS="LLVM_TARGET($target_to_build) $LLVM_ENUM_TARGETS"
+ fi
+ if test -f ${srcdir}/lib/Target/${target_to_build}/*LDBackend.cpp ; then
+ LLVM_ENUM_LINKERS="LLVM_LINKER($target_to_build) $LLVM_ENUM_LINKERS";
+ fi
+ done
+ AC_SUBST(LLVM_ENUM_TARGETS)
+ AC_SUBST(LLVM_ENUM_LINKERS)
+])
diff --git a/m4/llvm.m4 b/m4/llvm.m4
new file mode 100644
index 0000000..018a7ce
--- /dev/null
+++ b/m4/llvm.m4
@@ -0,0 +1,140 @@
+dnl
+dnl @synopsis CHECK_LLVM([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl
+dnl @summary check LLVM, set up variables:
+dnl LLVM_CFLAGS="`${LLVM_CONFIG_BIN} --cflags`"
+dnl LLVM_CPPFLAGS="`${LLVM_CONFIG_BIN} --cxxflags`"
+dnl LLVM_LDFLAGS="`${LLVM_CONFIG_BIN} --ldflags --libs`"
+dnl
+dnl Luba Tang <lubatang@gmail.com>
+
+
+AC_DEFUN([CHECK_LLVM],
+[dnl
+
+ AC_ARG_WITH(
+ [llvm-config],
+ [AS_HELP_STRING([--with-llvm-config[[=PATH]]],
+ [path to llvm-config (by default, searching in $PATH)])],
+ [llvm_config_path="${withval}"],
+ [llvm_config_path="/usr/"])
+
+ #Set up ${LLVM_CONFIG_BIN}
+ AC_MSG_CHECKING(for llvm-config)
+
+ if test -x "${llvm_config_path}" -a ! -d "${llvm_config_path}"; then
+ LLVM_CONFIG_BIN=${llvm_config_path}
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ llvm_config_path=${PATH}
+ if test -d "${LLVM_BINDIR}"; then
+ llvm_config_path="${llvm_config_path}:${LLVM_BINDIR}"
+ fi
+ AC_PATH_PROG(LLVM_CONFIG_BIN, llvm-config, [no], ${llvm_config_path})
+ if test "${LLVM_CONFIG_BIN}" = "no"; then
+ ifelse([$3], , , [$3])
+ AC_MSG_NOTICE([*** The 'llvm-config' is not found!])
+ AC_MSG_ERROR([*** Please use --with-llvm-config option with the full path of 'llvm-config'.])
+ fi
+ fi
+
+ dnl Use llvm-config to do:
+ dnl 1. is the minimum version correct?
+ dnl 2. the includedir
+ dnl 3. the flags - cflags, cxxflags, cppflags, ldflags
+ dnl 4. the libs
+ AC_MSG_CHECKING(for llvm - version >= $1)
+ cur_version="`${LLVM_CONFIG_BIN} --version`";
+ tool_major="`${LLVM_CONFIG_BIN} --version | sed 's/svn//' | sed 's/\([[0-9]]*\).\([[0-9]]*\)/\1/'`"
+ tool_minor="`${LLVM_CONFIG_BIN} --version | sed 's/svn//'| sed 's/\([[0-9]]*\).\([[0-9]]*\)/\2/'`"
+
+ require_major="`echo $1 | sed 's/svn//' | sed 's/\([[0-9]]*\).\([[0-9]]*\)/\1/'`"
+ require_minor="`echo $1 | sed 's/svn//' | sed 's/\([[0-9]]*\).\([[0-9]]*\)/\2/'`"
+
+ if test "${tool_major}" -lt "${require_major}"; then
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([*** The version of LLVM is too low! (${cur_version}<$1)])
+ elif test "${tool_major}" -eq "${require_major}"; then
+ if test "${tool_minor}" -lt "${require_minor}"; then
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([*** The version of LLVM is too low! (${cur_version}<$1)])
+ fi
+ fi
+ AC_MSG_RESULT([yes])
+
+ LLVM_CFLAGS="`${LLVM_CONFIG_BIN} --cflags`"
+ LLVM_CPPFLAGS="`${LLVM_CONFIG_BIN} --cxxflags`"
+ LLVM_LDFLAGS="`${LLVM_CONFIG_BIN} --libs`"
+ LLVM_LDFLAGS="${LLVM_LDFLAGS} `${LLVM_CONFIG_BIN} --ldflags`"
+ LLVM_LDFLAGS="`echo ${LLVM_LDFLAGS} | sed 's/\n//g'`"
+ LLVM_LDFLAGS="`echo ${LLVM_LDFLAGS} | sed 's/-lgtest_main -lgtest//g'`"
+ LLVM_VERSION=${tool_major}
+
+ AC_SUBST(LLVM_CFLAGS)
+ AC_SUBST(LLVM_CPPFLAGS)
+ AC_SUBST(LLVM_LDFLAGS)
+ AC_SUBST(LLVM_VERSION)
+ ifelse([$2], , , [$2])
+
+ AC_CACHE_CHECK([type of operating system we're going to host on],
+ [llvm_cv_platform_type],
+ [case $host in
+ *-*-aix*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-irix*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-cygwin*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-darwin*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-minix*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-freebsd*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-openbsd*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-netbsd*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-dragonfly*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-hpux*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-interix*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-linux*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-solaris*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-auroraux*)
+ llvm_cv_platform_type="Unix" ;;
+ *-*-win32*)
+ llvm_cv_platform_type="Win32" ;;
+ *-*-mingw*)
+ llvm_cv_platform_type="Win32" ;;
+ *-*-haiku*)
+ llvm_cv_platform_type="Unix" ;;
+ *-unknown-eabi*)
+ llvm_cv_platform_type="Unix" ;;
+ *-unknown-elf*)
+ llvm_cv_platform_type="Unix" ;;
+ *)
+ llvm_cv_platform_type="Unknown" ;;
+ esac])
+
+ dnl Set the "LLVM_ON_*" variables based on llvm_cv_llvm_cv_platform_type
+ dnl This is used by lib/Support to determine the basic kind of implementation
+ dnl to use.
+ case $llvm_cv_platform_type in
+ Unix)
+ AC_DEFINE([LLVM_ON_UNIX],[1],[Define if this is Unixish platform])
+ AC_SUBST(LLVM_ON_UNIX,[1])
+ AC_SUBST(LLVM_ON_WIN32,[0])
+ ;;
+ Win32)
+ AC_DEFINE([LLVM_ON_WIN32],[1],[Define if this is Win32ish platform])
+ AC_SUBST(LLVM_ON_UNIX,[0])
+ AC_SUBST(LLVM_ON_WIN32,[1])
+ ;;
+ esac
+])
diff --git a/mcld-device-build.mk b/mcld-device-build.mk
new file mode 100644
index 0000000..9f445b3
--- /dev/null
+++ b/mcld-device-build.mk
@@ -0,0 +1,37 @@
+include $(LLVM_DEVICE_BUILD_MK)
+
+# The three inline options together reduce libbcc.so almost 1MB.
+# We move them from global build/core/combo/TARGET_linux-arm.mk
+# to here.
+LOCAL_CFLAGS := -DANDROID_TARGET_BUILD \
+ -finline-limit=64 \
+ -finline-functions \
+ -fno-inline-functions-called-once \
+ $(LOCAL_CFLAGS)
+
+LOCAL_CPPFLAGS := \
+ $(LOCAL_CPPFLAGS) \
+ -Wformat \
+ -Werror=format-security \
+ -Werror=return-type \
+ -Werror=non-virtual-dtor \
+ -Werror=address \
+ -Werror=sequence-point \
+ -Woverloaded-virtual \
+ -Wno-sign-promo
+
+ifeq ($(MCLD_ENABLE_ASSERTION),true)
+ LOCAL_CPPFLAGS += \
+ -D_DEBUG \
+ -UNDEBUG
+endif
+
+# Make sure bionic is first so we can include system headers.
+LOCAL_C_INCLUDES := \
+ bionic \
+ external/stlport/stlport \
+ $(MCLD_ROOT_PATH)/include \
+ $(LLVM_ROOT_PATH) \
+ $(LLVM_ROOT_PATH)/include \
+ $(LLVM_ROOT_PATH)/device/include \
+ $(LOCAL_C_INCLUDES)
diff --git a/mcld-host-build.mk b/mcld-host-build.mk
new file mode 100644
index 0000000..2bedf07
--- /dev/null
+++ b/mcld-host-build.mk
@@ -0,0 +1,27 @@
+include $(LLVM_HOST_BUILD_MK)
+
+LOCAL_CPPFLAGS := \
+ $(LOCAL_CPPFLAGS) \
+ -Wformat \
+ -Werror=format-security \
+ -Werror=return-type \
+ -Werror=non-virtual-dtor \
+ -Werror=address \
+ -Werror=sequence-point \
+ -Woverloaded-virtual \
+ -Wno-sign-promo
+
+ifeq ($(MCLD_ENABLE_ASSERTION),true)
+ LOCAL_CPPFLAGS += \
+ -D_DEBUG \
+ -UNDEBUG
+endif
+
+LOCAL_C_INCLUDES := \
+ $(MCLD_ROOT_PATH)/include \
+ $(LLVM_ROOT_PATH) \
+ $(LLVM_ROOT_PATH)/include \
+ $(LLVM_ROOT_PATH)/host/include \
+ $(LOCAL_C_INCLUDES)
+
+LOCAL_IS_HOST_MODULE := true
diff --git a/mcld.mk b/mcld.mk
new file mode 100644
index 0000000..3fa71f9
--- /dev/null
+++ b/mcld.mk
@@ -0,0 +1,12 @@
+ifeq ($(MCLD_ROOT_PATH),)
+$(error Must set variable MCLD_ROOT_PATH before including this! $(LOCAL_PATH))
+endif
+
+MCLD_HOST_BUILD_MK := $(MCLD_ROOT_PATH)/mcld-host-build.mk
+MCLD_DEVICE_BUILD_MK := $(MCLD_ROOT_PATH)/mcld-device-build.mk
+
+ifeq ($(LLVM_ROOT_PATH),)
+$(error Must set variable LLVM_ROOT_PATH before including this! $(LOCAL_PATH))
+endif
+
+include $(LLVM_ROOT_PATH)/llvm.mk
diff --git a/optimized/Makefile.am b/optimized/Makefile.am
new file mode 100644
index 0000000..62f2ed9
--- /dev/null
+++ b/optimized/Makefile.am
@@ -0,0 +1,233 @@
+BUILDTOP=..
+TOPLEVEL=${srcdir}/..
+TOOLDIR=${TOPLEVEL}/tools/llvm-mcld
+LIBDIR=${TOPLEVEL}/lib
+INCDIR=${TOPLEVEL}/include/mcld
+UNITTEST=${TOPLEVEL}/unittests
+
+ANDROID_CPPFLAGS=-Wformat -Werror=format-security -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point
+
+bin_PROGRAMS = llvm-mcld
+
+llvm_mcld_CPPFLAGS = -O2 -DTOPDIR=\"${abs_top_srcdir}\" -DLLVM_VERSION=${LLVM_VERSION} -I$(TOPLEVEL)/include -I$(BUILDTOP)/include ${LLVM_CPPFLAGS} ${ANDROID_CPPFLAGS}
+llvm_mcld_LDADD = ${LLVM_LDFLAGS}
+
+NORMAL_SOURCE = ${TOOLDIR}/llvm-mcld.cpp \
+ ${INCDIR}/ADT/Uncopyable.h \
+ ${INCDIR}/ADT/TypeTraits.h \
+ ${INCDIR}/ADT/TreeBase.h \
+ ${INCDIR}/ADT/Allocators.h \
+ ${INCDIR}/ADT/TreeAllocator.h \
+ ${INCDIR}/ADT/BinTree.h \
+ ${INCDIR}/Support/Path.h \
+ ${LIBDIR}/Support/Path.cpp \
+ ${INCDIR}/Support/RealPath.h \
+ ${LIBDIR}/Support/RealPath.cpp \
+ ${INCDIR}/Support/Directory.h \
+ ${LIBDIR}/Support/Directory.cpp \
+ ${INCDIR}/Support/FileSytem.h \
+ ${LIBDIR}/Support/FileSystem.cpp \
+ ${INCDIR}/Support/LEB128.h \
+ ${LIBDIR}/Support/LEB128.cpp \
+ ${INCDIR}/Support/MemoryArea.h \
+ ${LIBDIR}/Support/MemoryArea.cpp \
+ ${INCDIR}/Support/MemoryRegion.h \
+ ${LIBDIR}/Support/MemoryRegion.cpp \
+ ${INCDIR}/Support/RegionFactory.h \
+ ${LIBDIR}/Support/RegionFactory.cpp \
+ ${INCDIR}/Support/MemoryAreaFactory.h \
+ ${LIBDIR}/Support/MemoryAreaFactory.cpp \
+ ${INCDIR}/Support/CommandLine.h \
+ ${LIBDIR}/Support/CommandLine.cpp \
+ ${INCDIR}/Support/GCFactory.h \
+ ${INCDIR}/Support/UniqueGCFactory.h \
+ ${INCDIR}/Support/PositionDependentOption.h \
+ ${INCDIR}/Support/DerivedPositionDependentOptions.h \
+ ${LIBDIR}/CodeGen/LLVMTargetMachine.cpp \
+ ${INCDIR}/CodeGen/SectLinker.h \
+ ${LIBDIR}/CodeGen/SectLinker.cpp \
+ ${INCDIR}/CodeGen/SectLinkerOption.h \
+ ${LIBDIR}/CodeGen/SectLinkerOption.cpp \
+ ${INCDIR}/Target/PLT.h\
+ ${LIBDIR}/Target/PLT.cpp\
+ ${INCDIR}/Target/GOT.h \
+ ${LIBDIR}/Target/GOT.cpp \
+ ${INCDIR}/Target/TargetMachine.h \
+ ${INCDIR}/Target/TargetRegistry.h \
+ ${LIBDIR}/Support/TargetRegistry.cpp \
+ ${LIBDIR}/Target/Target.cpp \
+ ${INCDIR}/Target/TargetSelect.h \
+ ${INCDIR}/Target/TargetLDBackend.h \
+ ${LIBDIR}/Target/TargetLDBackend.cpp \
+ ${INCDIR}/Target/GNULDBackend.h \
+ ${LIBDIR}/Target/GNULDBackend.cpp \
+ ${INCDIR}/Target/AndroidSectLinker.h \
+ ${LIBDIR}/Target/AndroidSectLinker.cpp \
+ ${INCDIR}/Target/ELFDynamic.h \
+ ${LIBDIR}/Target/ELFDynamic.cpp \
+ ${INCDIR}/Target/OutputRelocSection.h \
+ ${LIBDIR}/Target/OutputRelocSection.cpp \
+ ${LIBDIR}/Target/ARM/ARMELFDynamic.h \
+ ${LIBDIR}/Target/ARM/ARMELFDynamic.cpp \
+ ${LIBDIR}/Target/ARM/ARMLDBackend.h \
+ ${LIBDIR}/Target/ARM/ARMLDBackend.cpp \
+ ${LIBDIR}/Target/ARM/ARMGOT.h \
+ ${LIBDIR}/Target/ARM/ARMGOT.cpp \
+ ${LIBDIR}/Target/ARM/ARMPLT.h \
+ ${LIBDIR}/Target/ARM/ARMPLT.cpp \
+ ${LIBDIR}/Target/ARM/ARMTargetMachine.h \
+ ${LIBDIR}/Target/ARM/ARMTargetMachine.cpp \
+ ${LIBDIR}/Target/ARM/ARMRelocationFactory.h \
+ ${LIBDIR}/Target/ARM/ARMRelocationFactory.cpp \
+ ${LIBDIR}/Target/ARM/ARMSectLinker.cpp \
+ ${LIBDIR}/Target/ARM/ARMELFSectLinker.h \
+ ${LIBDIR}/Target/ARM/ARMELFSectLinker.cpp \
+ ${LIBDIR}/Target/ARM/ARMAndroidSectLinker.h \
+ ${LIBDIR}/Target/ARM/ARMAndroidSectLinker.cpp \
+ ${LIBDIR}/Target/ARM/TargetInfo/ARMTargetInfo.cpp \
+ ${LIBDIR}/Target/Mips/MipsELFDynamic.h \
+ ${LIBDIR}/Target/Mips/MipsELFDynamic.cpp \
+ ${LIBDIR}/Target/Mips/MipsLDBackend.h \
+ ${LIBDIR}/Target/Mips/MipsLDBackend.cpp \
+ ${LIBDIR}/Target/Mips/MipsGOT.h \
+ ${LIBDIR}/Target/Mips/MipsGOT.cpp \
+ ${LIBDIR}/Target/Mips/MipsTargetMachine.h \
+ ${LIBDIR}/Target/Mips/MipsTargetMachine.cpp \
+ ${LIBDIR}/Target/Mips/MipsRelocationFactory.h \
+ ${LIBDIR}/Target/Mips/MipsRelocationFactory.cpp \
+ ${LIBDIR}/Target/Mips/MipsSectLinker.cpp \
+ ${LIBDIR}/Target/Mips/MipsELFSectLinker.h \
+ ${LIBDIR}/Target/Mips/MipsELFSectLinker.cpp \
+ ${LIBDIR}/Target/Mips/MipsAndroidSectLinker.h \
+ ${LIBDIR}/Target/Mips/MipsAndroidSectLinker.cpp \
+ ${LIBDIR}/Target/Mips/TargetInfo/MipsTargetInfo.cpp \
+ ${LIBDIR}/Target/X86/X86ELFDynamic.h \
+ ${LIBDIR}/Target/X86/X86ELFDynamic.cpp \
+ ${LIBDIR}/Target/X86/X86LDBackend.h \
+ ${LIBDIR}/Target/X86/X86LDBackend.cpp \
+ ${LIBDIR}/Target/X86/X86GOT.h \
+ ${LIBDIR}/Target/X86/X86GOT.cpp \
+ ${LIBDIR}/Target/X86/X86GOTPLT.h \
+ ${LIBDIR}/Target/X86/X86GOTPLT.cpp \
+ ${LIBDIR}/Target/X86/X86PLT.h \
+ ${LIBDIR}/Target/X86/X86PLT.cpp \
+ ${LIBDIR}/Target/X86/X86TargetMachine.h \
+ ${LIBDIR}/Target/X86/X86TargetMachine.cpp \
+ ${LIBDIR}/Target/X86/X86RelocationFactory.h \
+ ${LIBDIR}/Target/X86/X86RelocationFactory.cpp \
+ ${LIBDIR}/Target/X86/X86SectLinker.cpp \
+ ${LIBDIR}/Target/X86/X86ELFSectLinker.h \
+ ${LIBDIR}/Target/X86/X86ELFSectLinker.cpp \
+ ${LIBDIR}/Target/X86/X86AndroidSectLinker.h \
+ ${LIBDIR}/Target/X86/X86AndroidSectLinker.cpp \
+ ${LIBDIR}/Target/X86/TargetInfo/X86TargetInfo.cpp \
+ ${INCDIR}/MC/MCLDDriver.h \
+ ${LIBDIR}/MC/MCLDDriver.cpp \
+ ${INCDIR}/MC/SymbolCategory.h \
+ ${LIBDIR}/MC/SymbolCategory.cpp \
+ ${INCDIR}/MC/MCLinker.h \
+ ${LIBDIR}/MC/MCLinker.cpp \
+ ${INCDIR}/MC/MCBitcodeInterceptor.h \
+ ${LIBDIR}/MC/MCBitcodeInterceptor.cpp \
+ ${INCDIR}/MC/MCLDFile.h \
+ ${LIBDIR}/MC/MCLDFile.cpp \
+ ${INCDIR}/MC/MCLDInput.h \
+ ${LIBDIR}/MC/MCLDInput.cpp \
+ ${INCDIR}/MC/MCLDOutput.h \
+ ${LIBDIR}/MC/MCLDOutput.cpp \
+ ${INCDIR}/MC/InputFactory.h \
+ ${LIBDIR}/MC/InputFactory.cpp \
+ ${INCDIR}/MC/MCLDOptions.h \
+ ${LIBDIR}/MC/MCLDOptions.cpp \
+ ${INCDIR}/MC/MCLDInfo.h \
+ ${LIBDIR}/MC/MCLDInfo.cpp \
+ ${INCDIR}/MC/ContextFactory.h \
+ ${LIBDIR}/MC/ContextFactory.cpp \
+ ${INCDIR}/MC/SearchDirs.h \
+ ${LIBDIR}/MC/SearchDirs.cpp \
+ ${INCDIR}/MC/MCLDDirectory.h \
+ ${LIBDIR}/MC/MCLDDirectory.cpp \
+ ${INCDIR}/MC/MCLDAttribute.h \
+ ${LIBDIR}/MC/MCLDAttribute.cpp \
+ ${INCDIR}/MC/AttributeFactory.h \
+ ${LIBDIR}/MC/AttributeFactory.cpp \
+ ${INCDIR}/MC/MCLDInputTree.h \
+ ${LIBDIR}/MC/MCLDInputTree.cpp \
+ ${INCDIR}/MC/MCRegionFragment.h \
+ ${LIBDIR}/MC/MCRegionFragment.cpp \
+ ${INCDIR}/MC/MCTargetFragment.h \
+ ${INCDIR}/MC/MCFragmentRef.h \
+ ${LIBDIR}/MC/MCFragmentRef.cpp \
+ ${INCDIR}/LD/LDContext.h \
+ ${LIBDIR}/LD/LDContext.cpp \
+ ${INCDIR}/LD/LDSection.h \
+ ${LIBDIR}/LD/LDSection.cpp \
+ ${INCDIR}/LD/ResolveInfo.h \
+ ${LIBDIR}/LD/ResolveInfo.cpp \
+ ${INCDIR}/LD/ResolveInfoFactory.h \
+ ${LIBDIR}/LD/ResolveInfoFactory.cpp \
+ ${INCDIR}/LD/Resolver.h \
+ ${LIBDIR}/LD/Resolver.cpp \
+ ${INCDIR}/LD/LDSymbol.h \
+ ${LIBDIR}/LD/LDSymbol.cpp \
+ ${INCDIR}/LD/Layout.h \
+ ${LIBDIR}/LD/Layout.cpp\
+ ${INCDIR}/LD/Relocation.h \
+ ${LIBDIR}/LD/Relocation.cpp \
+ ${INCDIR}/LD/RelocationFactory.h \
+ ${LIBDIR}/LD/RelocationFactory.cpp \
+ ${INCDIR}/LD/StaticResolver.h \
+ ${LIBDIR}/LD/StaticResolver.cpp \
+ ${INCDIR}/LD/StrSymPool.h \
+ ${LIBDIR}/LD/StrSymPool.cpp \
+ ${INCDIR}/LD/LDReader.h \
+ ${LIBDIR}/LD/LDReader.cpp \
+ ${INCDIR}/LD/LDWriter.h \
+ ${LIBDIR}/LD/LDWriter.cpp \
+ ${INCDIR}/LD/ArchiveReader.h \
+ ${LIBDIR}/LD/ArchiveReader.cpp \
+ ${INCDIR}/LD/ObjectReader.h \
+ ${INCDIR}/LD/DynObjReader.h \
+ ${LIBDIR}/LD/DynObjReader.cpp \
+ ${INCDIR}/LD/ObjectWriter.h \
+ ${LIBDIR}/LD/ObjectWriter.cpp \
+ ${INCDIR}/LD/DynObjWriter.h \
+ ${LIBDIR}/LD/DynObjWriter.cpp \
+ ${INCDIR}/LD/ELFReader.h \
+ ${LIBDIR}/LD/ELFReader.cpp \
+ ${INCDIR}/LD/ELFWriter.h \
+ ${LIBDIR}/LD/ELFWriter.cpp \
+ ${INCDIR}/LD/GNUArchiveReader.h \
+ ${LIBDIR}/LD/GNUArchiveReader.cpp \
+ ${INCDIR}/LD/BSDArchiveReader.h \
+ ${LIBDIR}/LD/BSDArchiveReader.cpp \
+ ${INCDIR}/LD/ELFObjectReader.h \
+ ${LIBDIR}/LD/ELFObjectReader.cpp \
+ ${INCDIR}/LD/ELFDynObjReader.h \
+ ${LIBDIR}/LD/ELFDynObjReader.cpp \
+ ${INCDIR}/LD/ELFObjectWriter.h \
+ ${LIBDIR}/LD/ELFObjectWriter.cpp \
+ ${INCDIR}/LD/ELFDynObjWriter.h \
+ ${LIBDIR}/LD/ELFDynObjWriter.cpp \
+ ${INCDIR}/LD/LDFileFormat.h \
+ ${LIBDIR}/LD/LDFileFormat.cpp \
+ ${INCDIR}/LD/ELFFileFormat.h \
+ ${LIBDIR}/LD/ELFFileFormat.cpp \
+ ${INCDIR}/LD/ELFDynObjFileFormat.h \
+ ${LIBDIR}/LD/ELFDynObjFileFormat.cpp \
+ ${INCDIR}/LD/ELFExecFileFormat.h \
+ ${LIBDIR}/LD/ELFExecFileFormat.cpp \
+ ${INCDIR}/LD/LDSectionFactory.h \
+ ${LIBDIR}/LD/LDSectionFactory.cpp \
+ ${INCDIR}/LD/SectionMap.h \
+ ${LIBDIR}/LD/SectionMap.cpp \
+ ${INCDIR}/LD/SectionMerger.h \
+ ${LIBDIR}/LD/SectionMerger.cpp \
+ ${INCDIR}/LD/ELFSegment.h \
+ ${LIBDIR}/LD/ELFSegment.cpp \
+ ${INCDIR}/LD/ELFSegmentFactory.h \
+ ${LIBDIR}/LD/ELFSegmentFactory.cpp
+
+SOURCE = ${NORMAL_SOURCE}
+
+llvm_mcld_SOURCES = ${SOURCE}
diff --git a/patch/LLVM.patch b/patch/LLVM.patch
new file mode 100644
index 0000000..bf84562
--- /dev/null
+++ b/patch/LLVM.patch
@@ -0,0 +1,161 @@
+Index: include/llvm/MC/MCAssembler.h
+===================================================================
+--- include/llvm/MC/MCAssembler.h (revision 152063)
++++ include/llvm/MC/MCAssembler.h (working copy)
+@@ -21,6 +21,10 @@
+ #include "llvm/Support/DataTypes.h"
+ #include <vector> // FIXME: Shouldn't be needed.
+
++namespace mcld {
++class Layout;
++}
++
+ namespace llvm {
+ class raw_ostream;
+ class MCAsmLayout;
+@@ -40,6 +44,7 @@
+
+ class MCFragment : public ilist_node<MCFragment> {
+ friend class MCAsmLayout;
++ friend class mcld::Layout;
+
+ MCFragment(const MCFragment&); // DO NOT IMPLEMENT
+ void operator=(const MCFragment&); // DO NOT IMPLEMENT
+@@ -53,10 +58,13 @@
+ FT_Org,
+ FT_Dwarf,
+ FT_DwarfFrame,
+- FT_LEB
++ FT_LEB,
++ FT_Region,
++ FT_Reloc,
++ FT_Target
+ };
+
+-private:
++protected:
+ FragmentType Kind;
+
+ /// Parent - The data for the section this fragment is in.
+@@ -453,7 +461,7 @@
+ typedef FragmentListType::const_reverse_iterator const_reverse_iterator;
+ typedef FragmentListType::reverse_iterator reverse_iterator;
+
+-private:
++protected:
+ FragmentListType Fragments;
+ const MCSection *Section;
+
+@@ -481,6 +489,7 @@
+ // Only for use as sentinel.
+ MCSectionData();
+ MCSectionData(const MCSection &Section, MCAssembler *A = 0);
++ virtual ~MCSectionData() {}
+
+ const MCSection &getSection() const { return *Section; }
+
+@@ -679,7 +688,7 @@
+
+ MCCodeEmitter &Emitter;
+
+- MCObjectWriter &Writer;
++ MCObjectWriter *m_pWriter;
+
+ raw_ostream &OS;
+
+@@ -807,8 +816,10 @@
+
+ MCCodeEmitter &getEmitter() const { return Emitter; }
+
+- MCObjectWriter &getWriter() const { return Writer; }
++ MCObjectWriter &getWriter() const { return *m_pWriter; }
+
++ void setWriter(MCObjectWriter &pObjectWriter);
++
+ /// Finish - Do final processing and write the object to the output stream.
+ /// \arg Writer is used for custom object writer (as the MCJIT does),
+ /// if not specified it is automatically created from backend.
+Index: include/llvm/MC/MCSection.h
+===================================================================
+--- include/llvm/MC/MCSection.h (revision 152063)
++++ include/llvm/MC/MCSection.h (working copy)
+@@ -31,7 +31,8 @@
+ enum SectionVariant {
+ SV_COFF = 0,
+ SV_ELF,
+- SV_MachO
++ SV_MachO,
++ SV_LDContext
+ };
+
+ private:
+Index: include/llvm/Support/ELF.h
+===================================================================
+--- include/llvm/Support/ELF.h (revision 152063)
++++ include/llvm/Support/ELF.h (working copy)
+@@ -736,6 +736,13 @@
+ SHT_LOOS = 0x60000000, // Lowest operating system-specific type.
+ SHT_HIOS = 0x6fffffff, // Highest operating system-specific type.
+ SHT_LOPROC = 0x70000000, // Lowest processor architecture-specific type.
++
++ SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes.
++ SHT_GNU_HASH = 0x6ffffff6, // GNU style dynamic hash table.
++ SHT_GNU_verdef = 0x6ffffffd, // Versions defined by file.
++ SHT_GNU_verneed = 0x6ffffffe, // Versions needed by file.
++ SHT_GNU_versym = 0x6fffffff, // Symbol versions.
++
+ // Fixme: All this is duplicated in MCSectionELF. Why??
+ // Exception Index table
+ SHT_ARM_EXIDX = 0x70000001U,
+Index: include/llvm/Support/CommandLine.h
+===================================================================
+--- include/llvm/Support/CommandLine.h (revision 152063)
++++ include/llvm/Support/CommandLine.h (working copy)
+@@ -337,7 +337,11 @@
+
+ bool hasValue() const { return false; }
+
+- const DataType &getValue() const { llvm_unreachable("no default value"); }
++ const DataType &getValue() const {
++ assert(false && "no default value");
++ DataType *p = 0;
++ return *p;
++ }
+
+ // Some options may take their value from a different data type.
+ template<class DT>
+Index: lib/MC/MCAssembler.cpp
+===================================================================
+--- lib/MC/MCAssembler.cpp (revision 152063)
++++ lib/MC/MCAssembler.cpp (working copy)
+@@ -157,7 +157,8 @@
+ }
+
+ MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent)
+- : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0))
++ : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)),
++ LayoutOrder(~(0U))
+ {
+ if (Parent)
+ Parent->getFragmentList().push_back(this);
+@@ -197,7 +198,7 @@
+ MCAssembler::MCAssembler(MCContext &Context_, MCAsmBackend &Backend_,
+ MCCodeEmitter &Emitter_, MCObjectWriter &Writer_,
+ raw_ostream &OS_)
+- : Context(Context_), Backend(Backend_), Emitter(Emitter_), Writer(Writer_),
++ : Context(Context_), Backend(Backend_), Emitter(Emitter_), m_pWriter(&Writer_),
+ OS(OS_), RelaxAll(false), NoExecStack(false), SubsectionsViaSymbols(false)
+ {
+ }
+@@ -205,6 +206,11 @@
+ MCAssembler::~MCAssembler() {
+ }
+
++void MCAssembler::setWriter(MCObjectWriter &pObjectWriter) {
++ delete m_pWriter;
++ m_pWriter = &pObjectWriter;
++}
++
+ bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const {
+ // Non-temporary labels should always be visible to the linker.
+ if (!Symbol.isTemporary())
diff --git a/patch/README b/patch/README
new file mode 100644
index 0000000..04ac2b3
--- /dev/null
+++ b/patch/README
@@ -0,0 +1,24 @@
+
+------------------------------------------------------------
+For building MCLinker, it needs to build LLVM first.
+
+Before building LLVM,
+the patch "${MCLINKER_SRC}/patch/LLVM.patch" should be applied first.
+
+Following the steps below to apply the patch:
+1. cd $(LLVM_ROOT)
+2. patch -p0 < ${MCLINKER_SRC}/patch/LLVM.patch
+
+This patch is for LLVM trunk@152063.
+
+
+------------------------------------------------------------
+commit c3384c93c0e4c50da4ad093f08997507f9281c75
+Author: Jim Grosbach <grosbach@apple.com>
+Date: Mon Mar 5 21:43:40 2012 +0000
+
+ ARM Refactor VLD/VST spaced pair instructions.
+
+ Use the new composite physical registers.
+
+ git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152063
diff --git a/scripts/bin/add_class b/scripts/bin/add_class
new file mode 100755
index 0000000..5526e64
--- /dev/null
+++ b/scripts/bin/add_class
@@ -0,0 +1,150 @@
+#!/bin/bash
+# The MCLinker project
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+############################
+# Design Pattern - Builder, using BASH
+# 0. watch configuration
+# 1. ask name
+# 2. ask email
+# i. write back to configuration
+# 3. ask file type
+# i. ask deployment
+# 4. ask file name
+# 5. copy templates
+# 6. replace the keywords
+
+############################
+# Variable Dictionary
+MCLINKER_CONFIG_DIR=$HOME/.bold
+AUTHOR=
+EMAIL=
+CLASS_NAME=
+BRIEF=
+FILE_TYPE=
+
+# 0. watch configuration
+if [ -d "${MCLINKER_CONFIG_DIR}" ]; then
+ if [ -f "${MCLINKER_CONFIG_DIR}/config" ]; then
+ source ${MCLINKER_CONFIG_DIR}/config
+ fi
+else
+ mkdir ${MCLINKER_CONFIG_DIR}
+fi
+
+# 1. ask name
+# i. write back to configuration
+if [ -z "${AUTHOR}" ]; then
+ echo -n "name? ";
+ read AUTHOR
+ echo "AUTHOR=\"${AUTHOR}\"" >> ${MCLINKER_CONFIG_DIR}/config
+fi
+
+# 2. ask email
+# i. write back to configuration
+if [ -z "${EMAIL}" ]; then
+ echo -n "e-mail? ";
+ read EMAIL
+ echo "EMAIL=\"${EMAIL}\"" >> ${MCLINKER_CONFIG_DIR}/config
+fi
+
+# 3. ask file type
+echo "What type of files you want to create?";
+echo " 1) normal source code"
+echo " 2) test case"
+
+while [ -z "${FILE_TYPE}" ]; do
+ echo -n "your choice? ";
+ read FILE_TYPE
+
+ case "$FILE_TYPE" in
+ 1 ) source ${MCLINKERTOP}/scripts/normal_files.sh;
+ FILE_TYPE="normal";
+ ;;
+ 2 ) source ${MCLINKERTOP}/scripts/test_files.sh;
+ FILE_TYPE="testcase";
+ ;;
+ * ) FILE_TYPE="" ;;
+ esac
+done
+
+# 3.i ask deployment
+if [ "${FILE_TYPE}" = "normal" ]; then
+ echo "Where you what to deploy?";
+ echo " 1) ADT"
+ echo " 2) MC"
+ echo " 3) Target"
+ echo " 4) CodeGen"
+ echo " 5) Support"
+ echo " 6) LD"
+
+ while [ -z "${DEPLOYMENT}" ]; do
+ echo -n "your choice? ";
+ read DEPLOYMENT
+
+ case "${DEPLOYMENT}" in
+ 1 ) DEPLOYMENT="ADT";;
+ 2 ) DEPLOYMENT="MC";;
+ 3 ) DEPLOYMENT="Target";;
+ 4 ) DEPLOYMENT="CodeGen";;
+ 5 ) DEPLOYMENT="Support";;
+ 6 ) DEPLOYMENT="LD";;
+ * ) DEPLOYMENT="";;
+ esac
+ done
+fi
+
+# 3.ii ask Target
+if [ "${DEPLOYMENT}" = "Target" ]; then
+ echo "What is your Target?";
+ echo " 1) Target"
+ echo " 2) Target/ARM"
+ echo " 3) Target/X86"
+ echo " 4) Target/Mips"
+
+ while [ -z "${TARGET}" ]; do
+ echo -n "your choice? ";
+ read TARGET
+ case "${TARGET}" in
+ 1 ) TARGET=".";;
+ 2 ) TARGET="ARM"
+ source ${MCLINKERTOP}/scripts/target_files.sh;
+ ;;
+ 3 ) TARGET="X86"
+ source ${MCLINKERTOP}/scripts/target_files.sh;
+ ;;
+ 4 ) TARGET="Mips"
+ source ${MCLINKERTOP}/scripts/target_files.sh;
+ ;;
+ * ) TARGET="";;
+ esac
+ done
+ DEPLOYMENT="${DEPLOYMENT}/${TARGET}"
+fi
+
+# 4. ask file name
+ask_filename
+read CLASS_NAME
+
+ask_brief ${CLASS_NAME}
+read BRIEF
+
+# 5. copy the templates
+TARGET_FILE=$(copy_template_header ${CLASS_NAME} ${DEPLOYMENT})
+
+# 6. replace the keywords
+replace_author ${TARGET_FILE} ${AUTHOR}
+repalce_email ${TARGET_FILE} ${EMAIL}
+replace_class ${TARGET_FILE} ${CLASS_NAME}
+replace_brief ${TARGET_FILE} ${BRIEF}
+
+# 5. copy the templates
+TARGET_FILE=$(copy_template_impl ${CLASS_NAME} ${DEPLOYMENT})
+
+# 6. replace the keywords
+replace_author ${TARGET_FILE} ${AUTHOR}
+repalce_email ${TARGET_FILE} ${EMAIL}
+replace_class ${TARGET_FILE} ${CLASS_NAME}
+replace_brief ${TARGET_FILE} ${BRIEF}
diff --git a/scripts/envsetup.sh b/scripts/envsetup.sh
new file mode 100755
index 0000000..51a7bdb
--- /dev/null
+++ b/scripts/envsetup.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+# The MCLinker project
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+function gettop()
+{
+ local TOPFILE=tools/llvm-mcld/llvm-mcld.cpp
+ if [ -n "${MCLINKERTOP}" -a -f "${MCLINKERTOP}/${TOPFILE}" ]; then
+ echo ${MCLINKERTOP}
+ else
+ if [ -f "${TOPFILE}" ]; then
+ echo `pwd`;
+ else
+ local HERE=$PWD
+ T=
+ while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+ cd .. > /dev/null
+ T=`PWD= pwd`
+ done
+ cd $HERE > /dev/null
+ if [ -f "${T}/${TOPFILE}" ]; then
+ echo ${T}
+ fi
+ fi
+ fi
+
+}
+
+function wc_pndk()
+{
+ local H=`find ${MCLINKERTOP} | grep '\.h'`
+ local C=`find ${MCLINKERTOP} | grep '\.cpp'`
+ wc ${C} ${H}
+}
+
+#############################
+# Variable Dictionary
+export MCLINKERTOP=$(gettop)
+export PATH="${MCLINKERTOP}/scripts/bin:$PATH"
+if [ -x "${MCLINKERTOP}/debug/llvm-mcld" ]; then
+ ln -sf ${MCLINKERTOP}/debug/llvm-mcld ${MCLINKERTOP}/scripts/bin/MCLinker
+fi
+
+alias mk="make -C ${MCLINKERTOP}"
+
+SERVER=`grep mtksgt01 /etc/hosts`
+if [ ! -z "${SERVER}" ]; then
+ export PATH="/mtkoss/git/1.7.6-rhel-5.5/x86_64/bin:$PATH";
+fi
diff --git a/scripts/normal_files.sh b/scripts/normal_files.sh
new file mode 100644
index 0000000..aa50941
--- /dev/null
+++ b/scripts/normal_files.sh
@@ -0,0 +1,144 @@
+#!/bin/bash
+# The MCLinker project
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+function ask_filename
+{
+ echo -n "What is the class name? ";
+}
+
+function ask_brief
+{
+ CLASS_NAME=$1
+ echo "Please brief the class ${CLASS_NAME}: "
+}
+
+function copy_template_header
+{
+ local NAME=$1
+ local DEPLOYMENT=$2
+ local TARGET_FILE="${MCLINKERTOP}/include/mcld/${DEPLOYMENT}/${NAME}.h";
+ local SOURCE_FILE="${MCLINKERTOP}/templates/header.h";
+ mkdir -p ${MCLINKERTOP}/include/mcld/${DEPLOYMENT}
+ cp ${SOURCE_FILE} ${TARGET_FILE}
+ # replace the template name by target flie name and adjust the padding of '-'
+ local header_str="header";
+ PADDING_LEN=`expr ${#header_str} - ${#NAME}`;
+ ABS_PADDING_LEN=${PADDING_LEN};
+ PADDING="";
+
+ if [ "${PADDING_LEN}" -lt "0" ]; then
+ ABS_PADDING_LEN=`expr ${ABS_PADDING_LEN} \* -1`;
+ fi
+ for (( i=0; i < ${ABS_PADDING_LEN}; i = i + 1 )); do
+ PADDING="${PADDING}-";
+ done
+
+ if [ "${PADDING_LEN}" -gt "0" ]; then # replace and add padding
+ sed -e "s/header.h /${NAME}.h ${PADDING}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ elif [ "${PADDING_LEN}" -lt "0" ]; then # replace and strip padding
+ sed -e "s/header.h ${PADDING}/${NAME}.h /g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ else # replace directly
+ sed -e "s/header/${NAME}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ fi
+
+ echo "${TARGET_FILE}";
+}
+
+function copy_template_impl
+{
+ local NAME=$1
+ local DEPLOYMENT=$2
+ local TARGET_FILE="${MCLINKERTOP}/lib/${DEPLOYMENT}/${NAME}.cpp";
+ local SOURCE_FILE="${MCLINKERTOP}/templates/impl.cpp";
+ mkdir -p ${MCLINKERTOP}/lib/${DEPLOYMENT}
+ cp ${SOURCE_FILE} ${TARGET_FILE}
+ # replace the template name by target flie name and adjust the padding of '-'
+ local impl_str="impl";
+ PADDING_LEN=`expr ${#impl_str} - ${#NAME}`;
+ ABS_PADDING_LEN=${PADDING_LEN};
+ PADDING="";
+ if [ "${PADDING_LEN}" -lt "0" ]; then
+ ABS_PADDING_LEN=`expr ${ABS_PADDING_LEN} \* -1`;
+ fi
+
+ for (( i = 0; i < ${ABS_PADDING_LEN}; i = i + 1 )); do
+ PADDING="${PADDING}-";
+ done
+
+ if [ "${PADDING_LEN}" -gt "0" ]; then # replace and add padding
+ sed -e "s/impl.cpp /${NAME}.cpp ${PADDING}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ elif [ "${PADDING_LEN}" -lt "0" ]; then # replace and strip padding
+ sed -e "s/impl.cpp ${PADDING}/${NAME}.cpp /g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ else # replace directly
+ sed -e "s/impl/${NAME}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ fi
+
+ echo "${TARGET_FILE}";
+}
+
+function replace_author
+{
+ local TARGET_FILE=$1
+ shift
+ local AUTHOR=$*
+
+ sed -e "s/\${AUTHOR}/${AUTHOR}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+}
+
+function repalce_email
+{
+ local TARGET_FILE=$1
+ local EMAIL=$2
+ sed -e "s/\${EMAIL}/${EMAIL}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+
+ # adjust the length of header
+ NEW_SPACE=`grep '> *' ${TARGET_FILE} | wc -c`
+ NEW_SPACE=`expr 79 - ${NEW_SPACE}`
+ ADDEND=">";
+ if [ "${NEW_SPACE}" -gt "0" ]; then # add space
+ for (( i=0; i<${NEW_SPACE}; i=i+1 )); do
+ ADDEND="${ADDEND} ";
+ done
+ sed -e "s/${EMAIL}>/${EMAIL}${ADDEND}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ elif [ "${NEW_SPACE}" -lt "0" ]; then # strip space
+ for (( i=${NEW_SPACE}; i<0; i=i+1 )); do
+ ADDEND="${ADDEND} ";
+ done
+ sed -e "s/${EMAIL}${ADDEND}/${EMAIL}>/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ fi
+}
+
+function replace_class
+{
+ local TARGET_FILE=$1
+ local CLASS_NAME=$2
+ local UPCLASS_NAME=`echo ${CLASS_NAME} | tr [:lower:] [:upper:]`
+
+ sed -e "s/\${class_name}/${CLASS_NAME}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ sed -e "s/\${CLASS_NAME}/${UPCLASS_NAME}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+}
+
+function replace_brief
+{
+ local TARGET_FILE=$1
+ shift
+ local BRIEF=$*
+ sed -e "s/\${brief}/${BRIEF}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+}
+
diff --git a/scripts/target_files.sh b/scripts/target_files.sh
new file mode 100644
index 0000000..21fbeba
--- /dev/null
+++ b/scripts/target_files.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# The MCLinker project
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+function copy_template_header
+{
+ local NAME=$1
+ local DEPLOYMENT=$2
+ local TARGET_FILE="${MCLINKERTOP}/lib/${DEPLOYMENT}/${NAME}.h";
+ local SOURCE_FILE="${MCLINKERTOP}/templates/header.h";
+ cp ${SOURCE_FILE} ${TARGET_FILE}
+ echo "${TARGET_FILE}";
+}
+
+function copy_template_impl
+{
+ local NAME=$1
+ local DEPLOYMENT=$2
+ local TARGET_FILE="${MCLINKERTOP}/lib/${DEPLOYMENT}/${NAME}.cpp";
+ local SOURCE_FILE="${MCLINKERTOP}/templates/impl.cpp";
+ cp ${SOURCE_FILE} ${TARGET_FILE}
+ echo "${TARGET_FILE}";
+}
+
diff --git a/scripts/test_files.sh b/scripts/test_files.sh
new file mode 100644
index 0000000..2e609ba
--- /dev/null
+++ b/scripts/test_files.sh
@@ -0,0 +1,96 @@
+#!/bin/bash
+# The MCLinker project
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+function ask_filename
+{
+ echo -n "What is the class you what to test for? ";
+}
+
+function ask_brief
+{
+ CLASS_NAME=$1
+ echo "Please brief the testcase (optional):"
+}
+
+function copy_template_header
+{
+ local NAME=$1
+ local DEPLOYMENT=$2
+ local TARGET_FILE="${MCLINKERTOP}/unittests/${NAME}Test.h";
+ local SOURCE_FILE="${MCLINKERTOP}/templates/headerTest.h";
+ cp ${SOURCE_FILE} ${TARGET_FILE}
+ echo "${TARGET_FILE}";
+}
+
+function copy_template_impl
+{
+ local NAME=$1
+ local DEPLOYMENT=$2
+ local TARGET_FILE="${MCLINKERTOP}/unittests/${NAME}Test.cpp";
+ local SOURCE_FILE="${MCLINKERTOP}/templates/implTest.cpp";
+ cp ${SOURCE_FILE} ${TARGET_FILE}
+ echo "${TARGET_FILE}";
+}
+
+function replace_author
+{
+ local TARGET_FILE=$1
+ shift
+ local AUTHOR=$*
+
+ sed "s/\${AUTHOR}/${AUTHOR}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+}
+
+function repalce_email
+{
+ local TARGET_FILE=$1
+ local EMAIL=$2
+ sed "s/\${EMAIL}/${EMAIL}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+
+ # adjust the length of header
+ NEW_SPACE=`grep '> *' ${TARGET_FILE}.tmp | wc -c`
+ NEW_SPACE=`expr 79 - ${NEW_SPACE}`
+ ADDEND=">";
+ if [ "${NEW_SPACE}" -gt "0" ]; then # add space
+ for (( i=0; i<${NEW_SPACE}; i=i+1 )); do
+ ADDEND="${ADDEND} ";
+ done
+ sed "s/${EMAIL}>/${EMAIL}${ADDEND}/" ${TARGET_FILE}.tmp > ${TARGET_FILE}
+ elif [ "${NEW_SPACE}" -lt "0" ]; then # strip space
+ for (( i=${NEW_SPACE}; i<0; i=i+1 )); do
+ ADDEND="${ADDEND} ";
+ done
+ sed "s/${EMAIL}${ADDEND}/${EMAIL}>/g" ${TARGET_FILE}.tmp > ${TARGET_FILE}
+
+ else #do nothing
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+ fi
+
+ rm ${TARGET_FILE}.tmp
+ local EMAIL=$2
+}
+
+function replace_class
+{
+ local TARGET_FILE=$1
+ local CLASS_NAME=$2
+ local UPCLASS_NAME=`echo ${CLASS_NAME} | tr [:lower:] [:upper:]`
+
+ sed "s/\${class_name}/${CLASS_NAME}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ sed "s/\${CLASS_NAME}/${UPCLASS_NAME}/g" ${TARGET_FILE}.tmp > ${TARGET_FILE}
+ rm ${TARGET_FILE}.tmp
+}
+
+function replace_brief
+{
+ local TARGET_FILE=$1
+ shift
+ local BRIEF=$*
+ sed "s/\${brief}/${BRIEF}/g" ${TARGET_FILE} > ${TARGET_FILE}.tmp
+ mv ${TARGET_FILE}.tmp ${TARGET_FILE}
+}
+
diff --git a/templates/header.h b/templates/header.h
new file mode 100644
index 0000000..2b9acf7
--- /dev/null
+++ b/templates/header.h
@@ -0,0 +1,29 @@
+//===- header.h -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_${CLASS_NAME}_H
+#define MCLD_${CLASS_NAME}_H
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+#endif
+
+namespace mcld
+{
+
+/** \class ${class_name}
+ * \brief ${brief}
+ */
+class ${class_name}
+{
+
+};
+
+} // namespace of mcld
+
+#endif
+
diff --git a/templates/headerTest.h b/templates/headerTest.h
new file mode 100644
index 0000000..be55559
--- /dev/null
+++ b/templates/headerTest.h
@@ -0,0 +1,50 @@
+//===- headerTest.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_${CLASS_NAME}_TEST_H
+#define MCLD_${CLASS_NAME}_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class ${class_name};
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class ${class_name}Test
+ * \brief ${brief}
+ *
+ * \see ${class_name}
+ */
+class ${class_name}Test : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ ${class_name}Test();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~${class_name}Test();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::${class_name}* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/templates/impl.cpp b/templates/impl.cpp
new file mode 100644
index 0000000..a3d0df2
--- /dev/null
+++ b/templates/impl.cpp
@@ -0,0 +1,15 @@
+//===- impl.cpp -----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <${class_name}.h>
+
+using namespace mcld;
+
+//==========================
+// ${class_name}
+
diff --git a/templates/implTest.cpp b/templates/implTest.cpp
new file mode 100644
index 0000000..55ba332
--- /dev/null
+++ b/templates/implTest.cpp
@@ -0,0 +1,48 @@
+//===- implTest.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <${class_name}.h>
+#include "${class_name}Test.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+${class_name}Test::${class_name}Test()
+{
+ // create testee. modify it if need
+ m_pTestee = new ${class_name}();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+${class_name}Test::~${class_name}Test()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void ${class_name}Test::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void ${class_name}Test::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+/**
+TEST_F( ${class_name}Test, name of the testcase for ${class_name} ) {
+ Write you exercise here
+}
+**/
+
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/tools/llvm-mcld/llvm-mcld.cpp b/tools/llvm-mcld/llvm-mcld.cpp
new file mode 100644
index 0000000..835bb59
--- /dev/null
+++ b/tools/llvm-mcld/llvm-mcld.cpp
@@ -0,0 +1,908 @@
+//===- llvm-mcld.cpp ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/TargetMachine.h>
+#include <mcld/Support/TargetSelect.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Support/CommandLine.h>
+#include <mcld/Support/DerivedPositionDependentOptions.h>
+#include <mcld/Support/RealPath.h>
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include <llvm/Pass.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/MC/SubtargetFeature.h>
+#include <llvm/Support/CommandLine.h>
+#include <llvm/Support/Debug.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/Host.h>
+#include <llvm/Support/IRReader.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/ToolOutputFile.h>
+#include <llvm/Target/TargetData.h>
+#include <llvm/Target/TargetMachine.h>
+
+using namespace llvm;
+
+#ifdef ENABLE_UNITTEST
+#include <gtest.h>
+
+static cl::opt<bool>
+UnitTest("unittest", cl::desc("do unit test") );
+
+int unit_test( int argc, char* argv[] )
+{
+ testing::InitGoogleTest( &argc, argv );
+ return RUN_ALL_TESTS();
+}
+
+#endif
+
+
+// General options for llc. Other pass-specific options are specified
+// within the corresponding llc passes, and target-specific options
+// and back-end code generation options are specified with the target machine.
+//
+static cl::opt<std::string>
+InputFilename("dB",
+ cl::desc("set default bitcode"),
+ cl::value_desc("bitcode"));
+
+static cl::opt<std::string>
+OutputFilename("o",
+ cl::desc("Output filename"),
+ cl::value_desc("filename"));
+
+// Determine optimization level.
+static cl::opt<char>
+OptLevel("O",
+ cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+ "(default = '-O2')"),
+ cl::Prefix,
+ cl::ZeroOrMore,
+ cl::init(' '));
+
+static cl::opt<std::string>
+TargetTriple("mtriple", cl::desc("Override target triple for module"));
+
+static cl::opt<std::string>
+MArch("march", cl::desc("Architecture to generate code for (see --version)"));
+
+static cl::opt<std::string>
+MCPU("mcpu",
+ cl::desc("Target a specific cpu type (-mcpu=help for details)"),
+ cl::value_desc("cpu-name"),
+ cl::init(""));
+
+static cl::list<std::string>
+MAttrs("mattr",
+ cl::CommaSeparated,
+ cl::desc("Target specific attributes (-mattr=help for details)"),
+ cl::value_desc("a1,+a2,-a3,..."));
+
+static cl::opt<Reloc::Model>
+RelocModel("relocation-model",
+ cl::desc("Choose relocation model"),
+ cl::init(Reloc::Default),
+ cl::values(
+ clEnumValN(Reloc::Default, "default",
+ "Target default relocation model"),
+ clEnumValN(Reloc::Static, "static",
+ "Non-relocatable code"),
+ clEnumValN(Reloc::PIC_, "pic",
+ "Fully relocatable, position independent code"),
+ clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
+ "Relocatable external references, non-relocatable code"),
+ clEnumValEnd));
+
+static cl::opt<llvm::CodeModel::Model>
+CMModel("code-model",
+ cl::desc("Choose code model"),
+ cl::init(CodeModel::Default),
+ cl::values(clEnumValN(CodeModel::Default, "default",
+ "Target default code model"),
+ clEnumValN(CodeModel::Small, "small",
+ "Small code model"),
+ clEnumValN(CodeModel::Kernel, "kernel",
+ "Kernel code model"),
+ clEnumValN(CodeModel::Medium, "medium",
+ "Medium code model"),
+ clEnumValN(CodeModel::Large, "large",
+ "Large code model"),
+ clEnumValEnd));
+
+cl::opt<mcld::CodeGenFileType>
+FileType("filetype", cl::init(mcld::CGFT_EXEFile),
+ cl::desc("Choose a file type (not all types are supported by all targets):"),
+ cl::values(
+ clEnumValN(mcld::CGFT_ASMFile, "asm",
+ "Emit an assembly ('.s') file"),
+ clEnumValN(mcld::CGFT_OBJFile, "obj",
+ "Emit a relocatable object ('.o') file"),
+ clEnumValN(mcld::CGFT_ARCFile, "arc",
+ "Emit an archive ('.a') file"),
+ clEnumValN(mcld::CGFT_DSOFile, "dso",
+ "Emit an dynamic shared object ('.so') file"),
+ clEnumValN(mcld::CGFT_EXEFile, "exe",
+ "Emit a executable ('.exe') file"),
+ clEnumValN(mcld::CGFT_NULLFile, "null",
+ "Emit nothing, for performance testing"),
+ clEnumValEnd));
+
+cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
+ cl::desc("Do not verify input module"));
+
+static cl::opt<bool>
+EnableFPMAD("enable-fp-mad",
+ cl::desc("Enable less precise MAD instructions to be generated"),
+ cl::init(false));
+
+static cl::opt<bool>
+PrintCode("print-machineinstrs",
+ cl::desc("Print generated machine code"),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableFPElim("disable-fp-elim",
+ cl::desc("Disable frame pointer elimination optimization"),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableFPElimNonLeaf("disable-non-leaf-fp-elim",
+ cl::desc("Disable frame pointer elimination optimization for non-leaf funcs"),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableExcessPrecision("disable-excess-fp-precision",
+ cl::desc("Disable optimizations that may increase FP precision"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableUnsafeFPMath("enable-unsafe-fp-math",
+ cl::desc("Enable optimizations that may decrease FP precision"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableNoInfsFPMath("enable-no-infs-fp-math",
+ cl::desc("Enable FP math optimizations that assume no +-Infs"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableNoNaNsFPMath("enable-no-nans-fp-math",
+ cl::desc("Enable FP math optimizations that assume no NaNs"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
+ cl::Hidden,
+ cl::desc("Force codegen to assume rounding mode can change dynamically"),
+ cl::init(false));
+
+static cl::opt<bool>
+GenerateSoftFloatCalls("soft-float",
+ cl::desc("Generate software floating point library calls"),
+ cl::init(false));
+
+static cl::opt<llvm::FloatABI::ABIType>
+FloatABIForCalls("float-abi",
+ cl::desc("Choose float ABI type"),
+ cl::init(FloatABI::Default),
+ cl::values(
+ clEnumValN(FloatABI::Default, "default",
+ "Target default float ABI type"),
+ clEnumValN(FloatABI::Soft, "soft",
+ "Soft float ABI (implied by -soft-float)"),
+ clEnumValN(FloatABI::Hard, "hard",
+ "Hard float ABI (uses FP registers)"),
+ clEnumValEnd));
+
+static cl::opt<bool>
+DontPlaceZerosInBSS("nozero-initialized-in-bss",
+ cl::desc("Don't place zero-initialized symbols into bss section"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableJITExceptionHandling("jit-enable-eh",
+ cl::desc("Emit exception handling information"),
+ cl::init(false));
+
+// In debug builds, make this default to true.
+#ifdef NDEBUG
+#define EMIT_DEBUG false
+#else
+#define EMIT_DEBUG true
+#endif
+static cl::opt<bool>
+EmitJitDebugInfo("jit-emit-debug",
+ cl::desc("Emit debug information to debugger"),
+ cl::init(EMIT_DEBUG));
+#undef EMIT_DEBUG
+
+static cl::opt<bool>
+EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
+ cl::Hidden,
+ cl::desc("Emit debug info objfiles to disk"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableGuaranteedTailCallOpt("tailcallopt",
+ cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."),
+ cl::init(false));
+
+static cl::opt<unsigned>
+OverrideStackAlignment("stack-alignment",
+ cl::desc("Override default stack alignment"),
+ cl::init(0));
+
+static cl::opt<bool>
+EnableRealignStack("realign-stack",
+ cl::desc("Realign stack if needed"),
+ cl::init(true));
+
+static cl::opt<bool>
+DisableSwitchTables(cl::Hidden, "disable-jump-tables",
+ cl::desc("Do not generate jump tables."),
+ cl::init(false));
+
+static cl::opt<std::string>
+TrapFuncName("trap-func", cl::Hidden,
+ cl::desc("Emit a call to trap function rather than a trap instruction"),
+ cl::init(""));
+
+static cl::opt<bool>
+SegmentedStacks("segmented-stacks",
+ cl::desc("Use segmented stacks if possible."),
+ cl::init(false));
+
+//===----------------------------------------------------------------------===//
+// Command Line Options
+// There are four kinds of command line options:
+// 1. input, (may be a file, such as -m and /tmp/XXXX.o.)
+// 2. attribute of inputs, (describing the attributes of inputs, such as
+// --as-needed and --whole-archive. usually be positional.)
+// 3. scripting options, (represent a subset of link scripting language, such
+// as --defsym.)
+// 4. and general options. (the rest of options)
+//===----------------------------------------------------------------------===//
+// General Options
+static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
+ArgSysRoot("sysroot",
+ cl::desc("Use directory as the location of the sysroot, overriding the configure-time default."),
+ cl::value_desc("directory"),
+ cl::ValueRequired);
+
+static cl::list<mcld::MCLDDirectory, bool, llvm::cl::parser<mcld::MCLDDirectory> >
+ArgSearchDirList("L",
+ cl::ZeroOrMore,
+ cl::desc("Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts."),
+ cl::value_desc("searchdir"),
+ cl::Prefix);
+
+static cl::alias
+ArgSearchDirListAlias("library-path",
+ cl::desc("alias for -L"),
+ cl::aliasopt(ArgSearchDirList));
+
+static cl::opt<bool>
+ArgTrace("t",
+ cl::desc("Print the names of the input files as ld processes them."));
+
+static cl::alias
+ArgTraceAlias("trace",
+ cl::desc("alias for -t"),
+ cl::aliasopt(ArgTrace));
+
+static cl::opt<bool>
+ArgVerbose("V",
+ cl::desc("Display the version number for ld and list the linker emulations supported."));
+
+static cl::alias
+ArgVerboseAlias("verbose",
+ cl::desc("alias for -V"),
+ cl::aliasopt(ArgVerbose));
+
+static cl::opt<std::string>
+ArgEntry("e",
+ cl::desc("Use entry as the explicit symbol for beginning execution of your program."),
+ cl::value_desc("entry"),
+ cl::ValueRequired);
+
+static cl::alias
+ArgEntryAlias("entry",
+ cl::desc("alias for -e"),
+ cl::aliasopt(ArgEntry));
+
+static cl::opt<bool>
+ArgBsymbolic("Bsymbolic",
+ cl::desc("Bind references within the shared library."),
+ cl::init(false));
+
+static cl::opt<std::string>
+ArgSOName("soname",
+ cl::desc("Set internal name of shared library"),
+ cl::value_desc("name"));
+
+//===----------------------------------------------------------------------===//
+// Inputs
+static cl::list<mcld::sys::fs::Path>
+ArgInputObjectFiles(cl::Positional,
+ cl::desc("[input object files]"),
+ cl::ZeroOrMore);
+
+static cl::list<std::string>
+ArgNameSpecList("l",
+ cl::ZeroOrMore,
+ cl::desc("Add the archive or object file specified by namespec to the list of files to link."),
+ cl::value_desc("namespec"),
+ cl::Prefix);
+
+static cl::alias
+ArgNameSpecListAlias("library",
+ cl::desc("alias for -l"),
+ cl::aliasopt(ArgNameSpecList));
+
+static cl::list<bool>
+ArgStartGroupList("start-group",
+ cl::ValueDisallowed,
+ cl::desc("start to record a group of archives"));
+
+static cl::alias
+ArgStartGroupListAlias("(",
+ cl::desc("alias for --start-group"),
+ cl::aliasopt(ArgStartGroupList));
+
+static cl::list<bool>
+ArgEndGroupList("end-group",
+ cl::ValueDisallowed,
+ cl::desc("stop recording a group of archives"));
+
+static cl::alias
+ArgEndGroupListAlias(")",
+ cl::desc("alias for --end-group"),
+ cl::aliasopt(ArgEndGroupList));
+
+//===----------------------------------------------------------------------===//
+// Attributes of Inputs
+static cl::list<bool>
+ArgWholeArchiveList("whole-archive",
+ cl::ValueDisallowed,
+ cl::desc("For each archive mentioned on the command line after the --whole-archive option, include all object files in the archive."));
+
+static cl::list<bool>
+ArgNoWholeArchiveList("no-whole-archive",
+ cl::ValueDisallowed,
+ cl::desc("Turn off the effect of the --whole-archive option for subsequent archive files."));
+
+static cl::list<bool>
+ArgAsNeededList("as-needed",
+ cl::ValueDisallowed,
+ cl::desc("This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line after the --as-needed option."));
+
+static cl::list<bool>
+ArgNoAsNeededList("no-as-needed",
+ cl::ValueDisallowed,
+ cl::desc("Turn off the effect of the --as-needed option for subsequent dynamic libraries"));
+
+static cl::list<bool>
+ArgAddNeededList("add-needed",
+ cl::ValueDisallowed,
+ cl::desc("--add-needed causes DT_NEEDED tags are always emitted for those libraries from DT_NEEDED tags. This is the default behavior."));
+
+static cl::list<bool>
+ArgNoAddNeededList("no-add-needed",
+ cl::ValueDisallowed,
+ cl::desc("--no-add-needed causes DT_NEEDED tags will never be emitted for those libraries from DT_NEEDED tags"));
+
+static cl::list<bool>
+ArgBDynamicList("Bdynamic",
+ cl::ValueDisallowed,
+ cl::desc("Link against dynamic library"));
+
+static cl::alias
+ArgBDynamicListAlias1("dy",
+ cl::desc("alias for --Bdynamic"),
+ cl::aliasopt(ArgBDynamicList));
+
+static cl::alias
+ArgBDynamicListAlias2("call_shared",
+ cl::desc("alias for --Bdynamic"),
+ cl::aliasopt(ArgBDynamicList));
+
+static cl::list<bool>
+ArgBStaticList("Bstatic",
+ cl::ValueDisallowed,
+ cl::desc("Link against static library"));
+
+static cl::alias
+ArgBStaticListAlias1("dn",
+ cl::desc("alias for --Bstatic"),
+ cl::aliasopt(ArgBStaticList));
+
+static cl::alias
+ArgBStaticListAlias2("static",
+ cl::desc("alias for --Bstatic"),
+ cl::aliasopt(ArgBStaticList));
+
+static cl::alias
+ArgBStaticListAlias3("non_shared",
+ cl::desc("alias for --Bstatic"),
+ cl::aliasopt(ArgBStaticList));
+
+//===----------------------------------------------------------------------===//
+// Scripting Options
+
+
+//===----------------------------------------------------------------------===//
+/// non-member functions
+
+// GetFileNameRoot - Helper function to get the basename of a filename.
+static inline void
+GetFileNameRoot(const std::string &pInputFilename, std::string& pFileNameRoot)
+{
+ std::string outputFilename;
+ /* *** */
+ const std::string& IFN = pInputFilename;
+ int Len = IFN.length();
+ if ((Len > 2) &&
+ IFN[Len-3] == '.' &&
+ ((IFN[Len-2] == 'b' && IFN[Len-1] == 'c') ||
+ (IFN[Len-2] == 'l' && IFN[Len-1] == 'l')))
+ pFileNameRoot = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
+ else
+ pFileNameRoot = std::string(IFN);
+}
+
+static tool_output_file *GetOutputStream(const char* pTargetName,
+ Triple::OSType pOSType,
+ mcld::CodeGenFileType pFileType,
+ const std::string& pInputFilename,
+ std::string& pOutputFilename)
+{
+ // If we don't yet have an output filename, make one.
+ if (pOutputFilename.empty()) {
+ if (pInputFilename == "-")
+ pOutputFilename = "-";
+ else {
+ GetFileNameRoot(pInputFilename, pOutputFilename);
+
+ switch (pFileType) {
+ case mcld::CGFT_ASMFile:
+ if (pTargetName[0] == 'c') {
+ if (pTargetName[1] == 0)
+ pOutputFilename += ".cbe.c";
+ else if (pTargetName[1] == 'p' && pTargetName[2] == 'p')
+ pOutputFilename += ".cpp";
+ else
+ pOutputFilename += ".s";
+ }
+ else
+ pOutputFilename += ".s";
+ break;
+ case mcld::CGFT_OBJFile:
+ if (pOSType == Triple::Win32)
+ pOutputFilename += ".obj";
+ else
+ pOutputFilename += ".o";
+ break;
+ case mcld::CGFT_DSOFile:
+ if (pOSType == Triple::Win32)
+ pOutputFilename += ".dll";
+ else
+ pOutputFilename += ".so";
+ break;
+ case mcld::CGFT_ARCFile:
+ pOutputFilename += ".a";
+ break;
+ case mcld::CGFT_EXEFile:
+ case mcld::CGFT_NULLFile:
+ // do nothing
+ break;
+ default:
+ assert(0 && "Unknown file type");
+ }
+ }
+ }
+
+ // Decide if we need "binary" output.
+ bool Binary = false;
+ switch (pFileType) {
+ default: assert(0 && "Unknown file type");
+ case mcld::CGFT_ASMFile:
+ break;
+ case mcld::CGFT_ARCFile:
+ case mcld::CGFT_OBJFile:
+ case mcld::CGFT_DSOFile:
+ case mcld::CGFT_EXEFile:
+ case mcld::CGFT_NULLFile:
+ Binary = true;
+ break;
+ }
+
+ // Open the file.
+ std::string error;
+ unsigned OpenFlags = 0;
+ if (Binary) OpenFlags |= raw_fd_ostream::F_Binary;
+ tool_output_file *FDOut = new tool_output_file(pOutputFilename.c_str(), error,
+ OpenFlags);
+ if (!error.empty()) {
+ errs() << error << '\n';
+ delete FDOut;
+ return 0;
+ }
+
+ return FDOut;
+}
+
+static bool ProcessLinkerInputsFromCommand(mcld::SectLinkerOption &pOption) {
+ // ----- Set up General Options ----- //
+ // set up soname
+ pOption.info().output().setSOName(ArgSOName);
+
+ // set up sysroot
+ if (!ArgSysRoot.empty()) {
+ if (exists(ArgSysRoot) && is_directory(ArgSysRoot))
+ pOption.info().options().setSysroot(ArgSysRoot);
+ }
+
+ // add all search directories
+ cl::list<mcld::MCLDDirectory>::iterator sd;
+ cl::list<mcld::MCLDDirectory>::iterator sdEnd = ArgSearchDirList.end();
+ for (sd=ArgSearchDirList.begin(); sd!=sdEnd; ++sd) {
+ if (sd->isInSysroot())
+ sd->setSysroot(pOption.info().options().sysroot());
+ if (exists(sd->path()) && is_directory(sd->path())) {
+ pOption.info().options().directories().add(*sd);
+ }
+ else {
+ // FIXME: need a warning function
+ errs() << "WARNING: can not open search directory `-L"
+ << sd->name()
+ << "'.\n";
+ }
+ }
+
+ pOption.info().options().setTrace(ArgTrace);
+ pOption.info().options().setVerbose(ArgVerbose);
+ pOption.info().options().setEntry(ArgEntry);
+ pOption.info().options().setBsymbolic(ArgBsymbolic);
+
+ // ----- Set up Inputs ----- //
+ // add all start-group
+ cl::list<bool>::iterator sg;
+ cl::list<bool>::iterator sgEnd = ArgStartGroupList.end();
+ for (sg=ArgStartGroupList.begin(); sg!=sgEnd; ++sg) {
+ // calculate position
+ pOption.appendOption(new mcld::StartGroupOption(
+ ArgStartGroupList.getPosition(sg-ArgStartGroupList.begin())));
+ }
+
+ // add all end-group
+ cl::list<bool>::iterator eg;
+ cl::list<bool>::iterator egEnd = ArgEndGroupList.end();
+ for (eg=ArgEndGroupList.begin(); eg!=egEnd; ++eg) {
+ // calculate position
+ pOption.appendOption(new mcld::EndGroupOption(
+ ArgEndGroupList.getPosition(eg-ArgEndGroupList.begin())));
+ }
+
+ // add all namespecs
+ cl::list<std::string>::iterator ns;
+ cl::list<std::string>::iterator nsEnd = ArgNameSpecList.end();
+ for (ns=ArgNameSpecList.begin(); ns!=nsEnd; ++ns) {
+ // calculate position
+ pOption.appendOption(new mcld::NamespecOption(
+ ArgNameSpecList.getPosition(ns-ArgNameSpecList.begin()),
+ *ns));
+ }
+
+ // add all object files
+ cl::list<mcld::sys::fs::Path>::iterator obj;
+ cl::list<mcld::sys::fs::Path>::iterator objEnd = ArgInputObjectFiles.end();
+ for (obj=ArgInputObjectFiles.begin(); obj!=objEnd; ++obj) {
+ // calculate position
+ pOption.appendOption(new mcld::InputFileOption(
+ ArgInputObjectFiles.getPosition(obj-ArgInputObjectFiles.begin()),
+ *obj));
+ }
+
+ // ----- Set up Attributes of Inputs ----- //
+ // --whole-archive
+ cl::list<bool>::iterator attr = ArgWholeArchiveList.begin();
+ cl::list<bool>::iterator attrEnd = ArgWholeArchiveList.end();
+ for (; attr!=attrEnd; ++attr) {
+ pOption.appendOption(new mcld::WholeArchiveOption(
+ ArgWholeArchiveList.getPosition(attr-ArgWholeArchiveList.begin())));
+ }
+
+ // --no-whole-archive
+ attr = ArgNoWholeArchiveList.begin();
+ attrEnd = ArgNoWholeArchiveList.end();
+ for (; attr!=attrEnd; ++attr) {
+ pOption.appendOption(new mcld::NoWholeArchiveOption(
+ ArgNoWholeArchiveList.getPosition(attr-ArgNoWholeArchiveList.begin())));
+ }
+
+ // --as-needed
+ attr = ArgAsNeededList.begin();
+ attrEnd = ArgAsNeededList.end();
+ while(attr != attrEnd) {
+ pOption.appendOption(new mcld::AsNeededOption(
+ ArgAsNeededList.getPosition(attr-ArgAsNeededList.begin())));
+ ++attr;
+ }
+
+ // --no-as-needed
+ attr = ArgNoAsNeededList.begin();
+ attrEnd = ArgNoAsNeededList.end();
+ while(attr != attrEnd) {
+ pOption.appendOption(new mcld::NoAsNeededOption(
+ ArgNoAsNeededList.getPosition(attr-ArgNoAsNeededList.begin())));
+ ++attr;
+ }
+
+ // --add-needed
+ attr = ArgAddNeededList.begin();
+ attrEnd = ArgAddNeededList.end();
+ while(attr != attrEnd) {
+ pOption.appendOption(new mcld::AddNeededOption(
+ ArgAddNeededList.getPosition(attr-ArgAddNeededList.begin())));
+ ++attr;
+ }
+
+ // --no-add-needed
+ attr = ArgNoAddNeededList.begin();
+ attrEnd = ArgNoAddNeededList.end();
+ while(attr != attrEnd) {
+ pOption.appendOption(new mcld::NoAddNeededOption(
+ ArgNoAddNeededList.getPosition(attr-ArgNoAddNeededList.begin())));
+ ++attr;
+ }
+
+ // -Bdynamic
+ attr = ArgBDynamicList.begin();
+ attrEnd = ArgBDynamicList.end();
+ while(attr != attrEnd) {
+ pOption.appendOption(new mcld::BDynamicOption(
+ ArgBDynamicList.getPosition(attr-ArgBDynamicList.begin())));
+ }
+
+ // -Bstatic
+ attr = ArgBStaticList.begin();
+ attrEnd = ArgBStaticList.end();
+ while(attr != attrEnd) {
+ pOption.appendOption(new mcld::BStaticOption(
+ ArgBStaticList.getPosition(attr-ArgBStaticList.begin())));
+ ++attr;
+ }
+
+ // ----- Set up Scripting Options ----- //
+
+ return false;
+}
+
+int main( int argc, char* argv[] )
+{
+
+ LLVMContext &Context = getGlobalContext();
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ // Initialize targets first, so that --version shows registered targets.
+ InitializeAllTargets();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+ InitializeAllTargetMCs();
+ mcld::InitializeAllTargets();
+ mcld::InitializeAllLinkers();
+ cl::ParseCommandLineOptions(argc, argv, "llvm MCLinker\n");
+
+#ifdef ENABLE_UNITTEST
+ if (UnitTest) {
+ return unit_test( argc, argv );
+ }
+#endif
+
+ // Load the module to be compiled...
+ std::auto_ptr<Module> M;
+
+ if (InputFilename.empty() && (FileType != mcld::CGFT_DSOFile)) {
+ // Read from stdin
+ InputFilename = "-";
+ }
+
+ if (!InputFilename.empty()) {
+ SMDiagnostic Err;
+ M.reset(ParseIRFile(InputFilename, Err, Context));
+
+ if (M.get() == 0) {
+ Err.print(argv[0], errs());
+ errs() << "** Failed to to the given bitcode/llvm asm file '"
+ << InputFilename << "'. **\n";
+ return 1;
+ }
+ } else {
+ // If here, output must be dynamic shared object (mcld::CGFT_DSOFile).
+
+ // Create an empty Module
+ M.reset(new Module("Empty Module", Context));
+ }
+ Module &mod = *M.get();
+
+ // If we are supposed to override the target triple, do so now.
+ Triple TheTriple;
+ if (!TargetTriple.empty()) {
+ TheTriple.setTriple(TargetTriple);
+ mod.setTargetTriple(TargetTriple);
+ }
+
+ // User doesn't specify the triple from command.
+ if (TheTriple.getTriple().empty()) {
+ // Try to get one from the input Module.
+ const std::string &TripleStr = mod.getTargetTriple();
+
+ if (TripleStr.empty())
+ TheTriple.setTriple(sys::getDefaultTargetTriple());
+ else
+ TheTriple.setTriple(TripleStr);
+ }
+
+ // Allocate target machine. First, check whether the user has explicitly
+ // specified an architecture to compile for. If so we have to look it up by
+ // name, because it might be a backend that has no mapping to a target triple.
+ const mcld::Target *TheTarget = 0;
+ if (!MArch.empty()) {
+ for (mcld::TargetRegistry::iterator it = mcld::TargetRegistry::begin(),
+ ie = mcld::TargetRegistry::end(); it != ie; ++it) {
+ if (MArch == (*it)->get()->getName()) {
+ TheTarget = *it;
+ break;
+ }
+ }
+
+ if (!TheTarget) {
+ errs() << argv[0] << ": error: invalid target '" << MArch << "'.\n";
+ return 1;
+ }
+
+ // Adjust the triple to match (if known), otherwise stick with the
+ // module/host triple.
+ Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch);
+ if (Type != Triple::UnknownArch)
+ TheTriple.setArch(Type);
+ }
+ else {
+ std::string Err;
+ TheTarget = mcld::TargetRegistry::lookupTarget(TheTriple.getTriple(), Err);
+ if (TheTarget == 0) {
+ errs() << argv[0] << ": error auto-selecting target for module '"
+ << Err << "'. Please use the -march option to explicitly "
+ << "pick a target.\n";
+ return 1;
+ }
+ }
+
+ // Package up features to be passed to target/subtarget
+ std::string FeaturesStr;
+ if (MAttrs.size()) {
+ SubtargetFeatures Features;
+ for (unsigned i = 0; i != MAttrs.size(); ++i)
+ Features.AddFeature(MAttrs[i]);
+ FeaturesStr = Features.getString();
+ }
+
+ CodeGenOpt::Level OLvl = CodeGenOpt::Default;
+ switch (OptLevel) {
+ default:
+ errs() << argv[0] << ": invalid optimization level.\n";
+ return 1;
+ case ' ': break;
+ case '0': OLvl = CodeGenOpt::None; break;
+ case '1': OLvl = CodeGenOpt::Less; break;
+ case '2': OLvl = CodeGenOpt::Default; break;
+ case '3': OLvl = CodeGenOpt::Aggressive; break;
+ }
+
+ TargetOptions Options;
+ Options.LessPreciseFPMADOption = EnableFPMAD;
+ Options.PrintMachineCode = PrintCode;
+ Options.NoFramePointerElim = DisableFPElim;
+ Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf;
+ Options.NoExcessFPPrecision = DisableExcessPrecision;
+ Options.UnsafeFPMath = EnableUnsafeFPMath;
+ Options.NoInfsFPMath = EnableNoInfsFPMath;
+ Options.NoNaNsFPMath = EnableNoNaNsFPMath;
+ Options.HonorSignDependentRoundingFPMathOption =
+ EnableHonorSignDependentRoundingFPMath;
+ Options.UseSoftFloat = GenerateSoftFloatCalls;
+ if (FloatABIForCalls != FloatABI::Default)
+ Options.FloatABIType = FloatABIForCalls;
+ Options.NoZerosInBSS = DontPlaceZerosInBSS;
+ Options.JITExceptionHandling = EnableJITExceptionHandling;
+ Options.JITEmitDebugInfo = EmitJitDebugInfo;
+ Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
+ Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
+ Options.StackAlignmentOverride = OverrideStackAlignment;
+ Options.RealignStack = EnableRealignStack;
+ Options.DisableJumpTables = DisableSwitchTables;
+ Options.TrapFuncName = TrapFuncName;
+ Options.EnableSegmentedStacks = SegmentedStacks;
+
+ std::auto_ptr<mcld::LLVMTargetMachine> target_machine(
+ TheTarget->createTargetMachine(TheTriple.getTriple(),
+ MCPU, FeaturesStr, Options,
+ RelocModel, CMModel, OLvl));
+ assert(target_machine.get() && "Could not allocate target machine!");
+ mcld::LLVMTargetMachine &TheTargetMachine = *target_machine.get();
+
+ TheTargetMachine.getTM().setMCUseLoc(false);
+ TheTargetMachine.getTM().setMCUseCFI(false);
+
+ // Figure out where we are going to send the output...
+ OwningPtr<tool_output_file>
+ Out(GetOutputStream(TheTarget->get()->getName(),
+ TheTriple.getOS(),
+ FileType,
+ InputFilename,
+ OutputFilename));
+ if (!Out) return 1;
+
+ // Build up all of the passes that we want to do to the module.
+ PassManager PM;
+
+ // Add the target data from the target machine, if it exists, or the module.
+ if (const TargetData *TD = TheTargetMachine.getTM().getTargetData())
+ PM.add(new TargetData(*TD));
+ else
+ PM.add(new TargetData(&mod));
+
+ // Override default to generate verbose assembly.
+ TheTargetMachine.getTM().setAsmVerbosityDefault(true);
+
+ // Process the linker input from the command line
+ mcld::SectLinkerOption *LinkerOpt =
+ new mcld::SectLinkerOption(TheTargetMachine.getLDInfo());
+
+ if (ProcessLinkerInputsFromCommand(*LinkerOpt)) {
+ errs() << argv[0] << ": failed to process inputs from command line!\n";
+ return 1;
+ }
+
+ {
+ formatted_raw_ostream FOS(Out->os());
+
+ // Ask the target to add backend passes as necessary.
+ if( TheTargetMachine.addPassesToEmitFile(PM,
+ FOS,
+ OutputFilename,
+ FileType,
+ OLvl,
+ LinkerOpt,
+ NoVerify)) {
+ errs() << argv[0] << ": target does not support generation of this"
+ << " file type!\n";
+ return 1;
+ }
+
+ // Before executing passes, print the final values of the LLVM options.
+ cl::PrintOptionValues();
+
+ PM.run(mod);
+ }
+
+ // Declare success.
+ Out->keep();
+
+ // clean up
+ delete LinkerOpt;
+
+ return 0;
+}
+
diff --git a/unittests/BinTreeTest.cpp b/unittests/BinTreeTest.cpp
new file mode 100644
index 0000000..bce4b24
--- /dev/null
+++ b/unittests/BinTreeTest.cpp
@@ -0,0 +1,275 @@
+//===- BinTreeTest.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "BinTreeTest.h"
+
+#include "mcld/ADT/TypeTraits.h"
+#include "mcld/MC/MCLDInputTree.h"
+#include <string>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+BinTreeTest::BinTreeTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new BinaryTree<int>();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+BinTreeTest::~BinTreeTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void BinTreeTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void BinTreeTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+
+/// General
+TEST_F( BinTreeTest,Two_non_null_tree_merge)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+ m_pTestee->join<TreeIteratorBase::Rightward>(pos,0);
+ --pos;
+ m_pTestee->join<TreeIteratorBase::Rightward>(pos,1);
+ m_pTestee->join<TreeIteratorBase::Leftward>(pos,1);
+ --pos;
+ m_pTestee->join<TreeIteratorBase::Rightward>(pos,2);
+ m_pTestee->join<TreeIteratorBase::Leftward>(pos,2);
+
+ BinaryTree<int> *mergeTree = new BinaryTree<int>;
+ BinaryTree<int>::iterator pos2 = mergeTree->root();
+ mergeTree->join<TreeIteratorBase::Rightward>(pos2,1);
+ --pos2;
+ mergeTree->join<TreeIteratorBase::Rightward>(pos2,1);
+ mergeTree->join<TreeIteratorBase::Leftward>(pos2,1);
+
+ m_pTestee->merge<TreeIteratorBase::Rightward>(pos,*mergeTree);
+ delete mergeTree;
+ EXPECT_TRUE(m_pTestee->size()==8);
+}
+
+/// ---- TEST - 2 ----
+TEST_F( BinTreeTest, A_null_tree_merge_a_non_null_tree)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+
+ BinaryTree<int> *mergeTree = new BinaryTree<int>;
+ mergeTree->join<TreeIteratorBase::Rightward>(pos,0);
+ --pos;
+ mergeTree->join<TreeIteratorBase::Rightward>(pos,1);
+ mergeTree->join<TreeIteratorBase::Leftward>(pos,1);
+ --pos;
+ mergeTree->join<TreeIteratorBase::Rightward>(pos,2);
+ mergeTree->join<TreeIteratorBase::Leftward>(pos,2);
+
+ m_pTestee->merge<TreeIteratorBase::Rightward>(pos,*mergeTree);
+
+ delete mergeTree;
+ EXPECT_TRUE(m_pTestee->size()==5);
+}
+
+TEST_F( BinTreeTest, A_non_null_tree_merge_a_null_tree)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+ m_pTestee->join<TreeIteratorBase::Rightward>(pos,0);
+ --pos;
+ m_pTestee->join<TreeIteratorBase::Rightward>(pos,1);
+ m_pTestee->join<TreeIteratorBase::Leftward>(pos,1);
+ --pos;
+ m_pTestee->join<TreeIteratorBase::Rightward>(pos,2);
+ m_pTestee->join<TreeIteratorBase::Leftward>(pos,2);
+
+ BinaryTree<int> *mergeTree = new BinaryTree<int>;
+ BinaryTree<int>::iterator pos2 = mergeTree->root();
+ mergeTree->merge<TreeIteratorBase::Rightward>(pos2,*m_pTestee);
+
+ //delete m_pTestee;
+ EXPECT_TRUE(mergeTree->size()==5);
+ delete mergeTree;
+}
+
+TEST_F( BinTreeTest, Two_null_tree_merge)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+
+ BinaryTree<int> *mergeTree = new BinaryTree<int>;
+ BinaryTree<int>::iterator pos2 = mergeTree->root();
+
+ mergeTree->merge<TreeIteratorBase::Rightward>(pos2,*m_pTestee);
+
+ //delete m_pTestee;
+ EXPECT_TRUE(mergeTree->size()==0);
+ delete mergeTree;
+}
+
+TEST_F( BinTreeTest, DFSIterator_BasicTraversal)
+{
+ int a = 111;
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+
+ m_pTestee->join<InputTree::Inclusive>(pos,a);
+ pos.move<InputTree::Inclusive>();
+ m_pTestee->join<InputTree::Positional>(pos,10);
+ m_pTestee->join<InputTree::Inclusive>(pos,9);
+ pos.move<InputTree::Inclusive>();
+ m_pTestee->join<InputTree::Positional>(pos,8);
+ m_pTestee->join<InputTree::Inclusive>(pos,7);
+
+ BinaryTree<int>::dfs_iterator dfs_it = m_pTestee->dfs_begin();
+ BinaryTree<int>::dfs_iterator dfs_end = m_pTestee->dfs_end();
+
+ ASSERT_EQ(111, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(9, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(7, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(8, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(10, **dfs_it);
+ ++dfs_it;
+ ASSERT_TRUE( dfs_it == dfs_end);
+ BinaryTree<int>::bfs_iterator bfs_it = m_pTestee->bfs_begin();
+ BinaryTree<int>::bfs_iterator bfs_end = m_pTestee->bfs_end();
+}
+
+TEST_F( BinTreeTest, DFSIterator_RightMostTree)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+ m_pTestee->join<InputTree::Inclusive>(pos,0);
+ pos.move<InputTree::Inclusive>();
+ m_pTestee->join<InputTree::Positional>(pos,1);
+ pos.move<InputTree::Positional>();
+ m_pTestee->join<InputTree::Positional>(pos,2);
+ pos.move<InputTree::Positional>();
+ m_pTestee->join<InputTree::Positional>(pos,3);
+ pos.move<InputTree::Positional>();
+ m_pTestee->join<InputTree::Positional>(pos,4);
+
+ BinaryTree<int>::dfs_iterator dfs_it = m_pTestee->dfs_begin();
+ BinaryTree<int>::dfs_iterator dfs_end = m_pTestee->dfs_end();
+
+ ASSERT_EQ(0, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(1, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(2, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(3, **dfs_it);
+ ++dfs_it;
+ ASSERT_EQ(4, **dfs_it);
+ ++dfs_it;
+ ASSERT_TRUE( dfs_it == dfs_end);
+}
+
+
+TEST_F( BinTreeTest, DFSIterator_SingleNode)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+ m_pTestee->join<InputTree::Inclusive>(pos,0);
+ BinaryTree<int>::dfs_iterator dfs_it = m_pTestee->dfs_begin();
+ BinaryTree<int>::dfs_iterator dfs_end = m_pTestee->dfs_end();
+ int counter = 0;
+ while( dfs_it != dfs_end ) {
+ ++counter;
+ ++dfs_it;
+ }
+ ASSERT_EQ(1, counter);
+}
+
+TEST_F( BinTreeTest, BFSIterator_BasicTraversal)
+{
+ int a = 111;
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+
+ m_pTestee->join<InputTree::Inclusive>(pos,a);
+ pos.move<InputTree::Inclusive>();
+ m_pTestee->join<InputTree::Positional>(pos,10);
+ m_pTestee->join<InputTree::Inclusive>(pos,9);
+ pos.move<InputTree::Inclusive>();
+ m_pTestee->join<InputTree::Positional>(pos,8);
+ m_pTestee->join<InputTree::Inclusive>(pos,7);
+
+ BinaryTree<int>::bfs_iterator bfs_it = m_pTestee->bfs_begin();
+ BinaryTree<int>::bfs_iterator bfs_end = m_pTestee->bfs_end();
+
+ ASSERT_EQ(111, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(10, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(9, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(8, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(7, **bfs_it);
+ ++bfs_it;
+ ASSERT_TRUE(bfs_it == bfs_end);
+ bfs_it = m_pTestee->bfs_begin();
+ bfs_end = m_pTestee->bfs_end();
+}
+
+TEST_F( BinTreeTest, BFSIterator_RightMostTree)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+ m_pTestee->join<InputTree::Inclusive>(pos,0);
+ pos.move<InputTree::Inclusive>();
+ m_pTestee->join<InputTree::Positional>(pos,1);
+ pos.move<InputTree::Positional>();
+ m_pTestee->join<InputTree::Positional>(pos,2);
+ pos.move<InputTree::Positional>();
+ m_pTestee->join<InputTree::Positional>(pos,3);
+ pos.move<InputTree::Positional>();
+ m_pTestee->join<InputTree::Positional>(pos,4);
+
+ BinaryTree<int>::bfs_iterator bfs_it = m_pTestee->bfs_begin();
+ BinaryTree<int>::bfs_iterator bfs_end = m_pTestee->bfs_end();
+
+ ASSERT_EQ(0, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(1, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(2, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(3, **bfs_it);
+ ++bfs_it;
+ ASSERT_EQ(4, **bfs_it);
+ ++bfs_it;
+ ASSERT_TRUE( bfs_it == bfs_end);
+}
+
+
+TEST_F( BinTreeTest, BFSIterator_SingleNode)
+{
+ BinaryTree<int>::iterator pos = m_pTestee->root();
+ m_pTestee->join<InputTree::Inclusive>(pos,0);
+ BinaryTree<int>::bfs_iterator bfs_it = m_pTestee->bfs_begin();
+ BinaryTree<int>::bfs_iterator bfs_end = m_pTestee->bfs_end();
+ int counter = 0;
+ while( bfs_it != bfs_end ) {
+ ++counter;
+ ++bfs_it;
+ }
+ ASSERT_EQ(1, counter);
+}
+
+
diff --git a/unittests/BinTreeTest.h b/unittests/BinTreeTest.h
new file mode 100644
index 0000000..3e8fab4
--- /dev/null
+++ b/unittests/BinTreeTest.h
@@ -0,0 +1,52 @@
+//===- BinTreeTest.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef BINTREE_TEST_H
+#define BINTREE_TEST_H
+
+#include "mcld/ADT/BinTree.h"
+
+#include <gtest.h>
+
+namespace mcld
+{
+class BinTree;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class BinTreeTest
+ * \brief Make sure the interface of BinTree , such as insert , traversal , etc..
+ *
+ * \see BinTree
+ */
+class BinTreeTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ BinTreeTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~BinTreeTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::BinaryTree<int>* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/DirIteratorTest.cpp b/unittests/DirIteratorTest.cpp
new file mode 100644
index 0000000..f319172
--- /dev/null
+++ b/unittests/DirIteratorTest.cpp
@@ -0,0 +1,64 @@
+//===- DirIteratorTest.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/Directory.h"
+#include "DirIteratorTest.h"
+#include "errno.h"
+
+using namespace mcld;
+using namespace mcld::sys::fs;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+DirIteratorTest::DirIteratorTest()
+{
+ //FIXME:Some bugs modifies the global value "errno" to non-zero.
+ // This makes readir() failed when daily build system runs unittest
+ // Remove this after fixing those bugs
+ errno = 0;
+
+ // create testee. modify it if need
+ m_pDir = new mcld::sys::fs::Directory(".");
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+DirIteratorTest::~DirIteratorTest()
+{
+ delete m_pDir;
+}
+
+// SetUp() will be called immediately before each test.
+void DirIteratorTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void DirIteratorTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( DirIteratorTest, open_dir ) {
+ ASSERT_TRUE( m_pDir->isGood() );
+
+ Directory::iterator entry = m_pDir->begin();
+ Directory::iterator enEnd = m_pDir->end();
+
+ size_t size = 0;
+ while( entry!=enEnd ) {
+ if (0 != entry.path())
+ size = entry.path()->native().size();
+
+ ++entry;
+ }
+}
+
+
diff --git a/unittests/DirIteratorTest.h b/unittests/DirIteratorTest.h
new file mode 100644
index 0000000..1f6e616
--- /dev/null
+++ b/unittests/DirIteratorTest.h
@@ -0,0 +1,52 @@
+//===- DirIteratorTest.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_DIR_ITERATOR_TEST_H
+#define MCLD_DIR_ITERATOR_TEST_H
+
+#include <gtest.h>
+
+namespace mcld {
+namespace sys {
+namespace fs {
+class Directory;
+class DirIterator;
+}
+}
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class DirIteratorTest
+ * \brief
+ *
+ * \see DirIterator
+ */
+class DirIteratorTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ DirIteratorTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~DirIteratorTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+protected:
+ mcld::sys::fs::Directory *m_pDir;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/FactoriesTest.cpp b/unittests/FactoriesTest.cpp
new file mode 100644
index 0000000..9301fb9
--- /dev/null
+++ b/unittests/FactoriesTest.cpp
@@ -0,0 +1,220 @@
+//===- FactoriesTest.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <cstdlib>
+#include "FactoriesTest.h"
+#include <string>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+FactoriesTest::FactoriesTest()
+{
+ m_pNodeAlloc = new NodeAlloc();
+ m_pFileAlloc = new FileAlloc();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+FactoriesTest::~FactoriesTest()
+{
+ delete m_pNodeAlloc;
+ delete m_pFileAlloc;
+}
+
+// SetUp() will be called immediately before each test.
+void FactoriesTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void FactoriesTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( FactoriesTest, node_produce ) {
+ NodeAlloc::NodeType* node = m_pNodeAlloc->produce();
+ ASSERT_EQ(1, m_pNodeAlloc->size());
+ ASSERT_FALSE(m_pNodeAlloc->empty());
+ node = m_pNodeAlloc->produce();
+ ASSERT_EQ(2, m_pNodeAlloc->size());
+ ASSERT_FALSE(m_pNodeAlloc->empty());
+ node = m_pNodeAlloc->produce();
+ ASSERT_EQ(3, m_pNodeAlloc->size());
+ ASSERT_FALSE(m_pNodeAlloc->empty());
+}
+
+TEST_F( FactoriesTest, node_iterate ) {
+ NodeAlloc::NodeType* node = 0;
+ for (int i=0 ; i<100; ++i) {
+ node = m_pNodeAlloc->produce();
+ node->data = (int*)malloc(sizeof(int));
+ *(node->data) = i;
+ }
+
+ int counter = 0;
+ NodeAlloc::iterator data = m_pNodeAlloc->begin();
+ NodeAlloc::iterator dEnd = m_pNodeAlloc->end();
+ for (; data!=dEnd; ++data) {
+ ASSERT_EQ(counter, *(*data).data );
+ free((*data).data);
+ (*data).data = 0;
+ ++counter;
+ }
+}
+
+TEST_F( FactoriesTest, node_delegate_empty ) {
+ NodeAlloc::NodeType* node = 0;
+ for (int i=0 ; i<100; ++i) {
+ node = m_pNodeAlloc->produce();
+ node->data = (int*)malloc(sizeof(int));
+ *(node->data) = i;
+ }
+ NodeAlloc* delegatee = new NodeAlloc();
+ m_pNodeAlloc->delegate(*delegatee);
+ ASSERT_EQ(100, m_pNodeAlloc->size());
+ int counter = 0;
+ NodeAlloc::iterator data = m_pNodeAlloc->begin();
+ NodeAlloc::iterator dEnd = m_pNodeAlloc->end();
+ for (; data!=dEnd; ++data) {
+ ASSERT_EQ(counter, *(*data).data );
+ free((*data).data);
+ (*data).data = 0;
+ ++counter;
+ }
+ delete delegatee;
+}
+
+TEST_F( FactoriesTest, node_empty_delegate ) {
+ NodeAlloc::NodeType* node = 0;
+ NodeAlloc* delegatee = new NodeAlloc();
+ for (int i=0 ; i<100; ++i) {
+ node = delegatee->produce();
+ node->data = (int*)malloc(sizeof(int));
+ *(node->data) = i;
+ }
+ m_pNodeAlloc->delegate(*delegatee);
+ ASSERT_EQ(100, m_pNodeAlloc->size());
+ int counter = 0;
+ NodeAlloc::iterator data = m_pNodeAlloc->begin();
+ NodeAlloc::iterator dEnd = m_pNodeAlloc->end();
+ for (; data!=dEnd; ++data) {
+ ASSERT_EQ(counter, *(*data).data );
+ free((*data).data);
+ (*data).data = 0;
+ ++counter;
+ }
+ ASSERT_EQ(0, delegatee->size());
+ ASSERT_TRUE(delegatee->empty());
+ delete delegatee;
+}
+
+TEST_F( FactoriesTest, node_delegate ) {
+ NodeAlloc::NodeType* node = 0;
+ NodeAlloc* delegatee = new NodeAlloc();
+ int counter = 0;
+ // produce agent
+ for (int i=0 ; i<100; ++i) {
+ node = m_pNodeAlloc->produce();
+ node->data = (int*)malloc(sizeof(int));
+ *(node->data) = counter;
+ ++counter;
+ }
+
+ // produce delegatee
+ for (int i=0 ; i<100; ++i) {
+ node = delegatee->produce();
+ node->data = (int*)malloc(sizeof(int));
+ *(node->data) = counter;
+ ++counter;
+ }
+
+ m_pNodeAlloc->delegate(*delegatee);
+ ASSERT_EQ(200, m_pNodeAlloc->size());
+ ASSERT_FALSE(m_pNodeAlloc->empty());
+ NodeAlloc::iterator data = m_pNodeAlloc->begin();
+ NodeAlloc::iterator dEnd = m_pNodeAlloc->end();
+ for ( counter = 0; data!=dEnd; ++data) {
+ ASSERT_EQ(counter, *(*data).data );
+ free((*data).data);
+ (*data).data = 0;
+ ++counter;
+ }
+ ASSERT_EQ(0, delegatee->size());
+ ASSERT_TRUE(delegatee->empty());
+ delete delegatee;
+}
+
+TEST_F( FactoriesTest, node_delegate_self ) {
+ NodeAlloc::NodeType* node = 0;
+ for (int i=0 ; i<100; ++i) {
+ node = m_pNodeAlloc->produce();
+ node->data = (int*)malloc(sizeof(int));
+ *(node->data) = i;
+ }
+ ASSERT_EQ(100, m_pNodeAlloc->size());
+ m_pNodeAlloc->delegate(*m_pNodeAlloc);
+ ASSERT_EQ(100, m_pNodeAlloc->size());
+ ASSERT_FALSE(m_pNodeAlloc->empty());
+}
+
+TEST_F( FactoriesTest, file_produce ) {
+ int counter = 0;
+ for (counter=1; counter<1000; ++counter) {
+ MCLDFile* file = m_pFileAlloc->produce();
+ ASSERT_EQ(counter, m_pFileAlloc->size());
+ ASSERT_FALSE(m_pFileAlloc->empty());
+ }
+}
+
+TEST_F( FactoriesTest, file_produce_by_params ) {
+ int counter = 0;
+ for (counter=1; counter<1000; ++counter) {
+ char name[100];
+ sprintf(name, "file %d", counter);
+ char path_name[100];
+ sprintf(path_name, "/proj/mtk%d", counter);
+ MCLDFile* file = m_pFileAlloc->produce( string(name),
+ sys::fs::Path(string(path_name)),
+ MCLDFile::Archive);
+ ASSERT_EQ(counter, m_pFileAlloc->size());
+ ASSERT_FALSE(m_pFileAlloc->empty());
+ ASSERT_TRUE(file->isRecognized());
+ ASSERT_STREQ(name, file->name().data());
+ }
+}
+
+TEST_F( FactoriesTest, file_iterate ) {
+ int counter = 0;
+ for (counter=1; counter<1000; ++counter) {
+ char name[100];
+ sprintf(name, "file %d", counter);
+ char path_name[100];
+ sprintf(path_name, "/proj/mtk%d", counter);
+ MCLDFile* file = m_pFileAlloc->produce( string(name),
+ sys::fs::Path(string(path_name)),
+ MCLDFile::Archive);
+ }
+
+ ASSERT_EQ(counter-1, m_pFileAlloc->size());
+ ASSERT_FALSE(m_pFileAlloc->empty());
+
+ MCLDFileFactory::iterator file = m_pFileAlloc->begin();
+ MCLDFileFactory::iterator fEnd = m_pFileAlloc->end();
+
+ while (file!=fEnd) {
+ ASSERT_TRUE((*file).isRecognized());
+ ASSERT_FALSE((*file).name().empty());
+ ++file;
+ }
+}
+
diff --git a/unittests/FactoriesTest.h b/unittests/FactoriesTest.h
new file mode 100644
index 0000000..ee7badf
--- /dev/null
+++ b/unittests/FactoriesTest.h
@@ -0,0 +1,49 @@
+//===- FactoriesTest.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef FACTORIES_TEST_H
+#define FACTORIES_TEST_H
+#include <gtest.h>
+#include "mcld/ADT/TreeAllocator.h"
+#include "mcld/MC/MCLDFile.h"
+
+namespace mcldtest
+{
+
+/** \class FactoriesTest
+ * \brief Test cases for factories - NodeFactory and MCLDFileFactory.
+ *
+ * \see Factories
+ */
+class FactoriesTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ FactoriesTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~FactoriesTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ typedef mcld::NodeFactory<int> NodeAlloc;
+ typedef mcld::MCLDFileFactory FileAlloc;
+protected:
+ NodeAlloc* m_pNodeAlloc;
+ FileAlloc *m_pFileAlloc;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/GCFactoryListTraitsTest.cpp b/unittests/GCFactoryListTraitsTest.cpp
new file mode 100644
index 0000000..e99d42c
--- /dev/null
+++ b/unittests/GCFactoryListTraitsTest.cpp
@@ -0,0 +1,123 @@
+//===- GCFactoryListTraitsTest.cpp ----------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "GCFactoryListTraitsTest.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+// Constructor can do set-up work for all test here.
+GCFactoryListTraitsTest::GCFactoryListTraitsTest()
+{
+ // Allocate the nodes.
+ m_pNodesAlloc = new Node* [10];
+#define ALLOCATE_NODE(i) m_pNodesAlloc[(i)] = m_NodeFactory.produce(i);
+ ALLOCATE_NODE(0);
+ ALLOCATE_NODE(1);
+ ALLOCATE_NODE(2);
+ ALLOCATE_NODE(3);
+ ALLOCATE_NODE(4);
+ ALLOCATE_NODE(5);
+ ALLOCATE_NODE(6);
+ ALLOCATE_NODE(7);
+ ALLOCATE_NODE(8);
+ ALLOCATE_NODE(9);
+#undef ALLOCATE_NODE
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+GCFactoryListTraitsTest::~GCFactoryListTraitsTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void GCFactoryListTraitsTest::SetUp()
+{
+ // Reset the node value and (re)insert into the iplist.
+ for (unsigned i = 0; i < 10; i++) {
+ m_pNodesAlloc[i]->setValue(m_pNodesAlloc[i]->getInitialValue());
+ m_pNodeList.push_back(m_pNodesAlloc[i]);
+ }
+}
+
+// TearDown() will be called immediately after each test.
+void GCFactoryListTraitsTest::TearDown()
+{
+ // Erasing of llvm::iplist won't destroy the allocation of the nodes managed
+ // by the GCFactory (i.e., NodeFactory.)
+ m_pNodeList.clear();
+}
+
+//==========================================================================//
+// Testcases
+//
+
+#define CHECK_NODE_VALUE(v_) do { \
+ ASSERT_EQ(v_, it->getValue()); \
+ it++; \
+} while (false)
+
+#define CHECK_LIST_VALUE(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) do { \
+ llvm::iplist<Node>::const_iterator it = m_pNodeList.begin(); \
+ CHECK_NODE_VALUE(v1); \
+ CHECK_NODE_VALUE(v2); \
+ CHECK_NODE_VALUE(v3); \
+ CHECK_NODE_VALUE(v4); \
+ CHECK_NODE_VALUE(v5); \
+ CHECK_NODE_VALUE(v6); \
+ CHECK_NODE_VALUE(v7); \
+ CHECK_NODE_VALUE(v8); \
+ CHECK_NODE_VALUE(v9); \
+ CHECK_NODE_VALUE(v10); \
+} while (false)
+
+TEST_F( GCFactoryListTraitsTest, Basic) {
+ ASSERT_EQ(10, m_pNodeList.size());
+ CHECK_LIST_VALUE(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+}
+
+TEST_F( GCFactoryListTraitsTest, BasicAgain) {
+ ASSERT_EQ(10, m_pNodeList.size());
+ CHECK_LIST_VALUE(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+}
+
+TEST_F( GCFactoryListTraitsTest, Clear) {
+ m_pNodeList.clear();
+ ASSERT_EQ(0, m_pNodeList.size());
+}
+
+TEST_F( GCFactoryListTraitsTest, PushThenPop) {
+ Node *NewNode = m_NodeFactory.produce(11);
+ m_pNodeList.push_back(NewNode);
+ ASSERT_EQ(11, m_pNodeList.size());
+ m_pNodeList.pop_back();
+ ASSERT_EQ(10, m_pNodeList.size());
+}
+
+TEST_F( GCFactoryListTraitsTest, CodeIterator) {
+ // to test whether there's compilation error for const template
+ for (llvm::iplist<Node>::const_iterator I = m_pNodeList.begin(),
+ E = m_pNodeList.end(); I != E; I++)
+ I->getValue();
+}
+
+TEST_F( GCFactoryListTraitsTest, Empty) {
+ ASSERT_FALSE(m_pNodeList.empty());
+ m_pNodeList.clear();
+ ASSERT_TRUE(m_pNodeList.empty());
+}
+
+TEST_F( GCFactoryListTraitsTest, EraseAndSize) {
+ ASSERT_FALSE(m_pNodeList.empty());
+ m_pNodeList.erase(m_pNodeList.begin());
+ m_pNodeList.erase(m_pNodeList.begin());
+ ASSERT_TRUE(m_pNodeList.size() == 8);
+}
+
+#undef CHECK_LIST_VALUE
+#undef CHECK_NODE_VALUE
diff --git a/unittests/GCFactoryListTraitsTest.h b/unittests/GCFactoryListTraitsTest.h
new file mode 100644
index 0000000..7067907
--- /dev/null
+++ b/unittests/GCFactoryListTraitsTest.h
@@ -0,0 +1,98 @@
+//===- GCFactoryListTraitsTest.h ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_GC_FACTORY_LIST_TRAITS_TEST_H
+#define MCLD_GC_FACTORY_LIST_TRAITS_TEST_H
+
+#include <gtest.h>
+
+#include <mcld/Support/GCFactoryListTraits.h>
+
+#include <llvm/ADT/ilist_node.h>
+
+#include <mcld/Support/GCFactory.h>
+
+namespace mcldtest
+{
+
+/** \class GCFactoryListTraitsTest
+ * \brief
+ *
+ * \see GCFactoryListTraits
+ */
+class GCFactoryListTraitsTest : public ::testing::Test
+{
+public:
+ /** \class GCFactoryListTraitsTest
+ * \brief Node used in the test
+ *
+ */
+ class NodeFactory;
+
+ class Node : public llvm::ilist_node<Node>
+ {
+ friend class NodeFactory;
+ private:
+ unsigned m_Init;
+ unsigned m_Value;
+
+ private:
+ Node(unsigned pInit) : m_Init(pInit), m_Value(pInit) { }
+
+ public:
+ unsigned getInitialValue() const {
+ return m_Init;
+ }
+
+ inline unsigned getValue() const
+ { return m_Value; }
+
+ inline void setValue(unsigned pValue)
+ { m_Value = pValue; }
+ };
+
+ class NodeFactory : public mcld::GCFactory<Node, 0> {
+ public:
+ NodeFactory() : mcld::GCFactory<Node, 0>(16) { }
+
+ Node *produce(unsigned pInit) {
+ Node *result = allocate();
+ new (result) Node(pInit);
+ return result;
+ }
+ };
+
+ // Constructor can do set-up work for all test here.
+ GCFactoryListTraitsTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~GCFactoryListTraitsTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+ const llvm::iplist<Node, mcld::GCFactoryListTraits<Node> > &getNodeList() const
+ { return m_pNodeList; }
+
+ llvm::iplist<Node, mcld::GCFactoryListTraits<Node> > &getNodeList()
+ { return m_pNodeList; }
+
+protected:
+ NodeFactory m_NodeFactory;
+ Node **m_pNodesAlloc;
+
+ llvm::iplist<Node, mcld::GCFactoryListTraits<Node> > m_pNodeList;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/HashTableTest.cpp b/unittests/HashTableTest.cpp
new file mode 100644
index 0000000..4106641
--- /dev/null
+++ b/unittests/HashTableTest.cpp
@@ -0,0 +1,327 @@
+//===- HashTableTest.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HashTableTest.h"
+#include "mcld/ADT/HashEntry.h"
+#include "mcld/ADT/HashTable.h"
+#include <cstdlib>
+
+using namespace std;
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+HashTableTest::HashTableTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+HashTableTest::~HashTableTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void HashTableTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void HashTableTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+struct IntCompare
+{
+ bool operator()(int X, int Y) const
+ { return (X==Y); }
+};
+
+struct PtrCompare
+{
+ bool operator()(const int* X, const int* Y) const
+ { return (X==Y); }
+};
+
+struct PtrHash
+{
+ size_t operator()(const int* pKey) const
+ {
+ return (unsigned((uintptr_t)pKey) >> 4) ^
+ (unsigned((uintptr_t)pKey) >> 9);
+ }
+};
+
+struct IntHash
+{
+ size_t operator()(int pKey) const
+ { return pKey; }
+};
+
+struct IntMod3Hash
+{
+ size_t operator()(int pKey) const
+ { return pKey % 3; }
+};
+
+TEST_F( HashTableTest, ptr_entry ) {
+ int A = 1;
+ int* pA = &A;
+
+ typedef HashEntry<int*, int, PtrCompare> HashEntryType;
+ typedef HashTable<HashEntryType, PtrHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy(0);
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+
+ entry = hashTable->insert(pA, exist);
+
+ EXPECT_FALSE(hashTable->empty());
+
+ HashTableTy::iterator iter;
+ iter = hashTable->find(NULL);
+ EXPECT_TRUE(iter==hashTable->end());
+ delete hashTable;
+}
+
+TEST_F( HashTableTest, constructor ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > hashTable(16);
+ EXPECT_EQ(17, hashTable.numOfBuckets());
+ EXPECT_TRUE(hashTable.empty());
+ EXPECT_EQ(0, hashTable.numOfEntries());
+}
+
+TEST_F( HashTableTest, allocattion ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy(22);
+
+ bool exist;
+ int key = 100;
+ HashTableTy::entry_type* val = hashTable->insert(key, exist);
+ val->setValue(999);
+ EXPECT_FALSE(hashTable->empty());
+ EXPECT_FALSE(exist);
+ EXPECT_FALSE(NULL == val);
+ HashTableTy::iterator entry = hashTable->find(key);
+ EXPECT_EQ(999, entry.getEntry()->value());
+ delete hashTable;
+}
+
+TEST_F( HashTableTest, alloc100 ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy(22);
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<100; ++key) {
+ entry = hashTable->insert(key, exist);
+ EXPECT_FALSE(hashTable->empty());
+ EXPECT_FALSE(exist);
+ EXPECT_FALSE(NULL == entry);
+ EXPECT_EQ(key, entry->key());
+ entry->setValue(key+10);
+ }
+
+ EXPECT_FALSE(hashTable->empty());
+ EXPECT_EQ(100, hashTable->numOfEntries());
+ EXPECT_EQ(197, hashTable->numOfBuckets());
+ delete hashTable;
+}
+
+TEST_F( HashTableTest, erase100 ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy(0);
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<100; ++key)
+ entry = hashTable->insert(key, exist);
+
+ EXPECT_FALSE(hashTable->empty());
+
+ int count;
+ HashTableTy::iterator iter;
+ for (unsigned int key=0; key<100; ++key) {
+ count = hashTable->erase(key);
+ EXPECT_EQ(1, count);
+ iter = hashTable->find(key);
+ EXPECT_TRUE(iter == hashTable->end());
+ }
+
+ EXPECT_TRUE(hashTable->empty());
+ delete hashTable;
+}
+
+TEST_F( HashTableTest, clear) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy(22);
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<100; ++key) {
+ entry = hashTable->insert(key, exist);
+ }
+
+ hashTable->clear();
+
+ int count;
+ HashTableTy::iterator iter;
+ for (unsigned int key=0; key<100; ++key) {
+ iter = hashTable->find(key);
+ EXPECT_TRUE(iter == hashTable->end());
+ }
+
+ EXPECT_TRUE(hashTable->empty());
+ delete hashTable;
+}
+
+TEST_F( HashTableTest, tombstone ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntMod3Hash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy();
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<100; ++key) {
+ entry = hashTable->insert(key, exist);
+ }
+ EXPECT_FALSE(hashTable->empty());
+
+ int count;
+ HashTableTy::iterator iter;
+ for (unsigned int key=0; key<20; ++key) {
+ count = hashTable->erase(key);
+ EXPECT_EQ(1, count);
+ iter = hashTable->find(key);
+ EXPECT_TRUE(iter == hashTable->end());
+ }
+ EXPECT_EQ(80, hashTable->numOfEntries());
+
+ for (unsigned int key=20; key<100; ++key) {
+ iter = hashTable->find(key);
+ EXPECT_TRUE(iter != hashTable->end());
+ }
+
+ for (unsigned int key=0; key<20; ++key) {
+ entry = hashTable->insert(key, exist);
+ }
+ EXPECT_EQ(100, hashTable->numOfEntries());
+ EXPECT_EQ(197, hashTable->numOfBuckets());
+
+ delete hashTable;
+}
+
+TEST_F( HashTableTest, rehash_test ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy(0);
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<400000; ++key) {
+ entry = hashTable->insert(key, exist);
+ entry->setValue(key+10);
+ }
+
+ HashTableTy::iterator iter;
+ for (unsigned int key=0; key<400000; ++key) {
+ iter = hashTable->find(key);
+ EXPECT_EQ((key+10), iter.getEntry()->value());
+ }
+
+ delete hashTable;
+}
+
+TEST_F( HashTableTest, bucket_iterator ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy(0);
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<400000; ++key) {
+ entry = hashTable->insert(key, exist);
+ entry->setValue(key+10);
+ }
+
+ HashTableTy::iterator iter, iEnd = hashTable->end();
+ unsigned int counter = 0;
+ for (iter = hashTable->begin(); iter != iEnd; ++iter) {
+ EXPECT_EQ(iter.getEntry()->key()+10, iter.getEntry()->value());
+ ++counter;
+ }
+ EXPECT_EQ(400000, counter);
+ delete hashTable;
+}
+
+
+TEST_F( HashTableTest, chain_iterator_single ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, IntHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy();
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<16; ++key) {
+ entry = hashTable->insert(key*37, exist);
+ entry->setValue(key+10);
+ }
+ for (unsigned int key=0; key<16; ++key) {
+ unsigned int counter = 0;
+ HashTableTy::chain_iterator iter, iEnd = hashTable->end(key*37);
+ for (iter = hashTable->begin(key*37); iter != iEnd; ++iter) {
+ EXPECT_EQ(key+10, iter.getEntry()->value());
+ ++counter;
+ }
+ EXPECT_EQ(1, counter);
+ }
+ delete hashTable;
+}
+
+struct FixHash
+{
+ size_t operator()(int pKey) const {
+ return 10;
+ }
+};
+
+
+TEST_F( HashTableTest, chain_iterator_list ) {
+ typedef HashEntry<int, int, IntCompare> HashEntryType;
+ typedef HashTable<HashEntryType, FixHash, EntryFactory<HashEntryType> > HashTableTy;
+ HashTableTy *hashTable = new HashTableTy();
+
+ bool exist;
+ HashTableTy::entry_type* entry = 0;
+ for (unsigned int key=0; key<16; ++key) {
+ entry = hashTable->insert(key, exist);
+ ASSERT_FALSE(exist);
+ entry->setValue(key);
+ }
+ ASSERT_EQ(16, hashTable->numOfEntries());
+ ASSERT_EQ(37, hashTable->numOfBuckets());
+
+ unsigned int key = 0;
+ unsigned int count = 0;
+ HashTableTy::chain_iterator iter, iEnd = hashTable->end(key);
+ for (iter = hashTable->begin(key); iter != iEnd; ++iter) {
+ count++;
+ }
+ ASSERT_EQ(16, count);
+ delete hashTable;
+}
diff --git a/unittests/HashTableTest.h b/unittests/HashTableTest.h
new file mode 100644
index 0000000..4bf2c50
--- /dev/null
+++ b/unittests/HashTableTest.h
@@ -0,0 +1,42 @@
+//===- HashTableTest.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_HASH_TABLE_TEST_H
+#define MCLD_HASH_TABLE_TEST_H
+
+#include <gtest.h>
+
+namespace mcldtest
+{
+
+/** \class HashTableTest
+ * \brief Testcase for HashTable
+ *
+ * \see HashTable
+ */
+class HashTableTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ HashTableTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~HashTableTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/InputTreeTest.cpp b/unittests/InputTreeTest.cpp
new file mode 100644
index 0000000..060eaad
--- /dev/null
+++ b/unittests/InputTreeTest.cpp
@@ -0,0 +1,143 @@
+//===- InputTreeTest.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/MCLDInputTree.h"
+#include "mcld/MC/MCLDInfo.h"
+#include <InputTreeTest.h>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+InputTreeTest::InputTreeTest()
+{
+ // create testee. modify it if need
+ m_pAttr = new mcld::AttributeFactory(2);
+ m_pAlloc = new mcld::InputFactory(10, *m_pAttr);
+ m_pTestee = new InputTree(*m_pAlloc);
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+InputTreeTest::~InputTreeTest()
+{
+ delete m_pTestee;
+ delete m_pAlloc;
+ delete m_pAttr;
+}
+
+// SetUp() will be called immediately before each test.
+void InputTreeTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void InputTreeTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( InputTreeTest, Basic_operation ) {
+ InputTree::iterator node = m_pTestee->root();
+ m_pTestee->insert<InputTree::Inclusive>(node, "FileSpec", "path1");
+
+ InputTree::const_iterator const_node = node;
+
+ ASSERT_TRUE(isGroup(node));
+ ASSERT_TRUE(isGroup(const_node));
+ ASSERT_TRUE(m_pTestee->hasInput());
+ ASSERT_EQ(1, m_pTestee->numOfInputs());
+
+ --node;
+
+ m_pTestee->enterGroup(node, InputTree::Downward);
+
+ InputTree::const_iterator const_node2 = node;
+
+ ASSERT_FALSE(node.isRoot());
+
+ ASSERT_FALSE(isGroup(node));
+ ASSERT_FALSE(isGroup(const_node2));
+ ASSERT_TRUE(m_pTestee->hasInput());
+ ASSERT_FALSE(m_pTestee->numOfInputs()==0);
+
+ ASSERT_TRUE(m_pTestee->size()==2);
+}
+
+TEST_F( InputTreeTest, forLoop_TEST ) {
+ InputTree::iterator node = m_pTestee->root();
+
+
+ m_pTestee->insert<InputTree::Inclusive>(node, "FileSpec", "path1");
+ InputTree::const_iterator const_node = node;
+ --node;
+
+ for(int i=0 ; i<100 ; ++i)
+ {
+ m_pTestee->insert<InputTree::Inclusive>(node,"FileSpec", "path1");
+ ++node;
+ }
+
+ m_pTestee->enterGroup(node, InputTree::Downward);
+ --node;
+
+ ASSERT_FALSE(node.isRoot());
+ ASSERT_TRUE(isGroup(node));
+ ASSERT_TRUE(m_pTestee->hasInput());
+ ASSERT_FALSE(m_pTestee->numOfInputs()==100);
+
+ ASSERT_TRUE(m_pTestee->size()==102);
+}
+
+TEST_F( InputTreeTest, Nesting_Case ) {
+ InputTree::iterator node = m_pTestee->root();
+
+ for(int i=0 ; i<50 ; ++i)
+ {
+ m_pTestee->enterGroup(node, InputTree::Downward);
+ --node;
+
+ m_pTestee->insert(node, InputTree::Afterward, "FileSpec", "path1");
+ ++node;
+ }
+
+ ASSERT_FALSE(node.isRoot());
+ ASSERT_FALSE(isGroup(node));
+ ASSERT_TRUE(m_pTestee->hasInput());
+ ASSERT_TRUE(m_pTestee->numOfInputs()==50);
+ ASSERT_TRUE(m_pTestee->size()==100);
+}
+
+TEST_F( InputTreeTest, DFSIterator_BasicTraversal)
+{
+
+ InputTree::iterator node = m_pTestee->root();
+ m_pTestee->insert<InputTree::Inclusive>(node, "111", "/");
+ node.move<InputTree::Inclusive>();
+
+ m_pTestee->insert<InputTree::Positional>(node, "10", "/");
+ m_pTestee->enterGroup<InputTree::Inclusive>(node);
+ node.move<InputTree::Inclusive>();
+ m_pTestee->insert<InputTree::Inclusive>(node, "7", "/");
+ m_pTestee->insert<InputTree::Positional>(node, "8", "/");
+
+ InputTree::dfs_iterator dfs_it = m_pTestee->dfs_begin();
+ InputTree::dfs_iterator dfs_end = m_pTestee->dfs_end();
+ ASSERT_STREQ("111", (*dfs_it)->name().c_str());
+ ++dfs_it;
+ ASSERT_STREQ("7", (**dfs_it).name().c_str());
+ ++dfs_it;
+ ASSERT_STREQ("8", (**dfs_it).name().c_str());
+ ++dfs_it;
+ ASSERT_STREQ("10", (**dfs_it).name().c_str());
+ ++dfs_it;
+ ASSERT_TRUE(dfs_it == dfs_end);
+}
+
diff --git a/unittests/InputTreeTest.h b/unittests/InputTreeTest.h
new file mode 100644
index 0000000..2ffef9c
--- /dev/null
+++ b/unittests/InputTreeTest.h
@@ -0,0 +1,54 @@
+//===- InputTreeTest.h ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef INPUTTREE_TEST_H
+#define INPUTTREE_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class InputTree;
+class InputFactory;
+class AttributeFactory;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class InputTreeTest
+ * \brief
+ *
+ * \see InputTree
+ */
+class InputTreeTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ InputTreeTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~InputTreeTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::AttributeFactory *m_pAttr;
+ mcld::InputFactory *m_pAlloc;
+ mcld::InputTree* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/LDSymbolTest.cpp b/unittests/LDSymbolTest.cpp
new file mode 100644
index 0000000..c414fa0
--- /dev/null
+++ b/unittests/LDSymbolTest.cpp
@@ -0,0 +1,42 @@
+//===- LDSymbolTest.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mcld/LD/LDSymbol.h"
+#include "LDSymbolTest.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+LDSymbolTest::LDSymbolTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+LDSymbolTest::~LDSymbolTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void LDSymbolTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void LDSymbolTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( LDSymbolTest, produce ) {
+}
+
diff --git a/unittests/LDSymbolTest.h b/unittests/LDSymbolTest.h
new file mode 100644
index 0000000..43d6b8a
--- /dev/null
+++ b/unittests/LDSymbolTest.h
@@ -0,0 +1,46 @@
+//===- LDSymbolTest.h -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LDSYMBOL_TEST_H
+#define LDSYMBOL_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class LDSymbol;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class LDSymbolTest
+ */
+class LDSymbolTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ LDSymbolTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~LDSymbolTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/LEB128Test.cpp b/unittests/LEB128Test.cpp
new file mode 100644
index 0000000..1f1467f
--- /dev/null
+++ b/unittests/LEB128Test.cpp
@@ -0,0 +1,531 @@
+//===- implTest.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/LEB128.h>
+#include "LEB128Test.h"
+
+#include <ctime>
+#include <cstdlib>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+LEB128Test::LEB128Test()
+{
+ // Initialize the seed for random number generator using during the tests.
+ ::srandom(::time(NULL));
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+LEB128Test::~LEB128Test()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void LEB128Test::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void LEB128Test::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+TEST_F( LEB128Test, EncodeULEB_Example_from_Dwarf3_Figure22_Using_32bits) {
+ leb128::ByteType buffer[2];
+ leb128::ByteType *result;
+ size_t size;
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 2);
+ ASSERT_EQ(buffer[0], 2);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 127);
+ ASSERT_EQ(buffer[0], 127);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 128);
+ ASSERT_EQ(buffer[0], 0 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 129);
+ ASSERT_EQ(buffer[0], 1 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 130);
+ ASSERT_EQ(buffer[0], 2 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 12857);
+ ASSERT_EQ(buffer[0], 57 + 0x80);
+ ASSERT_EQ(buffer[1], 100);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+}
+
+TEST_F( LEB128Test, EncodeULEB_Example_from_Dwarf3_Figure22_Using_64bits) {
+ leb128::ByteType buffer[2];
+ leb128::ByteType *result;
+ size_t size;
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 2);
+ ASSERT_EQ(buffer[0], 2);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 127);
+ ASSERT_EQ(buffer[0], 127);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 128);
+ ASSERT_EQ(buffer[0], 0 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 129);
+ ASSERT_EQ(buffer[0], 1 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 130);
+ ASSERT_EQ(buffer[0], 2 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 12857);
+ ASSERT_EQ(buffer[0], 57 + 0x80);
+ ASSERT_EQ(buffer[1], 100);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+}
+
+TEST_F( LEB128Test, EncodeSLEB_Example_from_Dwarf3_Figure22) {
+ leb128::ByteType buffer[2];
+ leb128::ByteType *result;
+ size_t size;
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, 2);
+ ASSERT_EQ(buffer[0], 2);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, -2);
+ ASSERT_EQ(buffer[0], 0x7e);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, 127);
+ ASSERT_EQ(buffer[0], 127 + 0x80);
+ ASSERT_EQ(buffer[1], 0);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, -127);
+ ASSERT_EQ(buffer[0], 1 + 0x80);
+ ASSERT_EQ(buffer[1], 0x7f);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, 128);
+ ASSERT_EQ(buffer[0], 0 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, -128);
+ ASSERT_EQ(buffer[0], 0 + 0x80);
+ ASSERT_EQ(buffer[1], 0x7f);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, 129);
+ ASSERT_EQ(buffer[0], 1 + 0x80);
+ ASSERT_EQ(buffer[1], 1);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, -129);
+ ASSERT_EQ(buffer[0], 0x7f + 0x80);
+ ASSERT_EQ(buffer[1], 0x7e);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+}
+
+TEST_F( LEB128Test, DecodeULEB_Example_from_Dwarf3_Figure22) {
+ leb128::ByteType buffer[2];
+ size_t size;
+
+ buffer[0] = 2;
+ buffer[1] = 0;
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 2);
+ ASSERT_EQ(size, 1);
+
+ buffer[0] = 127;
+ buffer[1] = 0;
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 127);
+ ASSERT_EQ(size, 1);
+
+ buffer[0] = 0 + 0x80;
+ buffer[1] = 1;
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 128);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 1 + 0x80;
+ buffer[1] = 1;
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 129);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 2 + 0x80;
+ buffer[1] = 1;
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 130);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 57 + 0x80;
+ buffer[1] = 100;
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 12857);
+ ASSERT_EQ(size, 2);
+
+}
+
+TEST_F( LEB128Test, DecodeSLEB_Example_from_Dwarf3_Figure22) {
+ leb128::ByteType buffer[2];
+ size_t size;
+
+ buffer[0] = 2;
+ buffer[1] = 0;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), 2);
+ ASSERT_EQ(size, 1);
+
+ buffer[0] = 0x7e;
+ buffer[1] = 0;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), -2);
+ ASSERT_EQ(size, 1);
+
+ buffer[0] = 127 + 0x80;
+ buffer[1] = 0;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), 127);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 1 + 0x80;
+ buffer[1] = 0x7f;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), -127);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 0 + 0x80;
+ buffer[1] = 1;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), 128);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 0 + 0x80;
+ buffer[1] = 0x7f;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), -128);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 1 + 0x80;
+ buffer[1] = 1;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), 129);
+ ASSERT_EQ(size, 2);
+
+ buffer[0] = 0x7f + 0x80;
+ buffer[1] = 0x7e;
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, size), -129);
+ ASSERT_EQ(size, 2);
+}
+
+TEST_F( LEB128Test, DecodeULEB_Tests_Found_in_Android_dalvik_dx) {
+ leb128::ByteType content[2];
+ const leb128::ByteType *p;
+
+ content[0] = 0;
+ p = content;
+ ASSERT_EQ(leb128::decode<uint64_t>(p), 0);
+ ASSERT_EQ(p, content + 1);
+
+ content[0] = 1;
+ p = content;
+ ASSERT_EQ(leb128::decode<uint64_t>(p), 1);
+ ASSERT_EQ(p, content + 1);
+
+ content[0] = 0x80;
+ content[1] = 0x7f;
+ p = content;
+ ASSERT_EQ(leb128::decode<uint64_t>(p), 16256);
+ ASSERT_EQ(p, content + 2);
+}
+
+TEST_F( LEB128Test, EncodeULEB_Tests_Found_in_Android_dalvik_dx) {
+ leb128::ByteType buffer[5];
+ leb128::ByteType *result;
+ size_t size;
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 0);
+ ASSERT_EQ(buffer[0], 0);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 0);
+ ASSERT_EQ(buffer[0], 0);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 1);
+ ASSERT_EQ(buffer[0], 1);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 1);
+ ASSERT_EQ(buffer[0], 1);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 16256);
+ ASSERT_EQ(buffer[0], 0x80);
+ ASSERT_EQ(buffer[1], 0x7f);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 16256);
+ ASSERT_EQ(buffer[0], 0x80);
+ ASSERT_EQ(buffer[1], 0x7f);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 0x3b4);
+ ASSERT_EQ(buffer[0], 0xb4);
+ ASSERT_EQ(buffer[1], 0x07);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 0x3b4);
+ ASSERT_EQ(buffer[0], 0xb4);
+ ASSERT_EQ(buffer[1], 0x07);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 0x40c);
+ ASSERT_EQ(buffer[0], 0x8c);
+ ASSERT_EQ(buffer[1], 0x08);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 0x40c);
+ ASSERT_EQ(buffer[0], 0x8c);
+ ASSERT_EQ(buffer[1], 0x08);
+ ASSERT_EQ(result, buffer + 2);
+ ASSERT_EQ(size, 2);
+
+ result = buffer;
+ size = leb128::encode<uint32_t>(result, 0xffffffff);
+ ASSERT_EQ(buffer[0], 0xff);
+ ASSERT_EQ(buffer[1], 0xff);
+ ASSERT_EQ(buffer[2], 0xff);
+ ASSERT_EQ(buffer[3], 0xff);
+ ASSERT_EQ(buffer[4], 0xf);
+ ASSERT_EQ(result, buffer + 5);
+ ASSERT_EQ(size, 5);
+
+ result = buffer;
+ size = leb128::encode<uint64_t>(result, 0xffffffff);
+ ASSERT_EQ(buffer[0], 0xff);
+ ASSERT_EQ(buffer[1], 0xff);
+ ASSERT_EQ(buffer[2], 0xff);
+ ASSERT_EQ(buffer[3], 0xff);
+ ASSERT_EQ(buffer[4], 0xf);
+ ASSERT_EQ(result, buffer + 5);
+ ASSERT_EQ(size, 5);
+}
+
+TEST_F( LEB128Test, DecodeSLEB_Tests_Found_in_Android_dalvik_dx) {
+ leb128::ByteType content[2];
+ const leb128::ByteType *p;
+
+ content[0] = 0;
+ p = content;
+ ASSERT_EQ(leb128::decode<int64_t>(p), 0);
+ ASSERT_EQ(p, content + 1);
+
+ content[0] = 1;
+ p = content;
+ ASSERT_EQ(leb128::decode<int64_t>(p), 1);
+ ASSERT_EQ(p, content + 1);
+
+ content[0] = 0x7f;
+ p = content;
+ ASSERT_EQ(leb128::decode<int64_t>(p), -1);
+ ASSERT_EQ(p, content + 1);
+
+ content[0] = 0x3c;
+ p = content;
+ ASSERT_EQ(leb128::decode<int64_t>(p), 0x3c);
+ ASSERT_EQ(p, content + 1);
+}
+
+TEST_F( LEB128Test, EncodeSLEB_Tests_Found_in_Android_dalvik_dx) {
+ leb128::ByteType buffer[5];
+ leb128::ByteType *result;
+ size_t size;
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, 0);
+ ASSERT_EQ(buffer[0], 0);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<int64_t>(result, 0);
+ ASSERT_EQ(buffer[0], 0);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, 1);
+ ASSERT_EQ(buffer[0], 1);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<int64_t>(result, 1);
+ ASSERT_EQ(buffer[0], 1);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<int32_t>(result, -1);
+ ASSERT_EQ(buffer[0], 0x7f);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+
+ result = buffer;
+ size = leb128::encode<int64_t>(result, -1);
+ ASSERT_EQ(buffer[0], 0x7f);
+ ASSERT_EQ(result, buffer + 1);
+ ASSERT_EQ(size, 1);
+}
+
+TEST_F( LEB128Test, Random_Regression_Test) {
+ leb128::ByteType buffer[5];
+
+ for (int i = 0; i < 20; i++) {
+ long int value = random();
+ uint64_t value2 = value * value;
+ leb128::ByteType *result;
+ size_t encode_size, decode_size;
+
+ // Test encode<uint32_t> and decode<uint64_t> on value
+ result = buffer;
+ encode_size = leb128::encode<uint32_t>(result, value);
+ ASSERT_EQ(result, buffer + encode_size);
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, decode_size), value);
+ ASSERT_EQ(encode_size, decode_size);
+
+ // Test encode<uint64_t> and decode<uint64_t> on (value * value)
+ result = buffer;
+ encode_size = leb128::encode<uint64_t>(result, value2);
+ ASSERT_EQ(result, buffer + encode_size);
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, decode_size), value2);
+ ASSERT_EQ(encode_size, decode_size);
+
+ // Test encode<uint64_t> and decode<uint64_t> on (value * value)
+ result = buffer;
+ encode_size = leb128::encode<int64_t>(result, value2);
+ ASSERT_EQ(result, buffer + encode_size);
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, decode_size), value2);
+ ASSERT_EQ(encode_size, decode_size);
+
+ // Test encode<uint64_t> and decode<uint64_t> on -(value * value)
+ result = buffer;
+ encode_size = leb128::encode<int64_t>(result, -value2);
+ ASSERT_EQ(result, buffer + encode_size);
+ ASSERT_EQ(leb128::decode<int64_t>(buffer, decode_size), -value2);
+ ASSERT_EQ(encode_size, decode_size);
+ }
+}
+
+TEST_F( LEB128Test, Other_Test) {
+ leb128::ByteType buffer[5];
+ leb128::ByteType *result;
+ size_t size;
+
+ result = buffer;
+ leb128::encode<uint64_t>(result, 154452);
+ ASSERT_EQ(result, buffer + 3);
+ ASSERT_EQ(buffer[0], 0xd4);
+ ASSERT_EQ(buffer[1], 0xb6);
+ ASSERT_EQ(buffer[2], 0x9);
+
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 154452);
+ ASSERT_EQ(size, 3);
+}
+
+TEST_F( LEB128Test, Type_Conversion_Test) {
+ char buffer[5];
+ char *result;
+ size_t size;
+
+ result = buffer;
+ leb128::encode<uint64_t>(result, 154452);
+ ASSERT_EQ(result, buffer + 3);
+ ASSERT_EQ(buffer[0], '\xd4');
+ ASSERT_EQ(buffer[1], '\xb6');
+ ASSERT_EQ(buffer[2], '\x09');
+
+ ASSERT_EQ(leb128::decode<uint64_t>(buffer, size), 154452);
+ ASSERT_EQ(size, 3);
+
+ const char *p = buffer;
+ ASSERT_EQ(leb128::decode<uint64_t>(p), 154452);
+ ASSERT_EQ(p, buffer + 3);
+}
diff --git a/unittests/LEB128Test.h b/unittests/LEB128Test.h
new file mode 100644
index 0000000..f0a87e3
--- /dev/null
+++ b/unittests/LEB128Test.h
@@ -0,0 +1,41 @@
+//===- LEB128Test.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LEB128_TEST_H
+#define MCLD_LEB128_TEST_H
+
+#include <gtest.h>
+
+namespace mcldtest
+{
+
+/** \class LEB128Test
+ * \brief
+ *
+ * \see LEB
+ */
+class LEB128Test : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ LEB128Test();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~LEB128Test();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/LinearAllocatorTest.cpp b/unittests/LinearAllocatorTest.cpp
new file mode 100644
index 0000000..9100160
--- /dev/null
+++ b/unittests/LinearAllocatorTest.cpp
@@ -0,0 +1,139 @@
+//===- LinearAllocatorTest.cpp --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "LinearAllocatorTest.h"
+#include "mcld/Support/Allocators.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+LinearAllocatorTest::LinearAllocatorTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new LinearAllocator<Data, CHUNK_SIZE>();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+LinearAllocatorTest::~LinearAllocatorTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void LinearAllocatorTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void LinearAllocatorTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( LinearAllocatorTest, allocateN ) {
+ Data* pointer = m_pTestee->allocate(10);
+ ASSERT_FALSE(0 == pointer);
+ ASSERT_EQ(CHUNK_SIZE, m_pTestee->max_size());
+ ASSERT_FALSE(m_pTestee->empty());
+}
+
+TEST_F( LinearAllocatorTest, allocate ) {
+ Data* pointer = m_pTestee->allocate();
+ ASSERT_FALSE(0 == pointer);
+ ASSERT_EQ(CHUNK_SIZE, m_pTestee->max_size());
+ ASSERT_FALSE(m_pTestee->empty());
+}
+
+TEST_F( LinearAllocatorTest, allocateOver ) {
+ Data* pointer = m_pTestee->allocate(CHUNK_SIZE+1);
+ ASSERT_TRUE(0 == pointer);
+ ASSERT_EQ(0, m_pTestee->max_size());
+ ASSERT_TRUE(m_pTestee->empty());
+}
+
+TEST_F( LinearAllocatorTest, alloc_construct ) {
+ Data* pointer = m_pTestee->allocate();
+ m_pTestee->construct(pointer);
+ ASSERT_EQ(1, pointer->one);
+ ASSERT_EQ(2, pointer->two);
+ ASSERT_EQ(3, pointer->three);
+ ASSERT_EQ(4, pointer->four);
+}
+
+TEST_F( LinearAllocatorTest, alloc_constructCopy ) {
+ Data* pointer = m_pTestee->allocate();
+ Data data(7, 7, 7, 7);
+ m_pTestee->construct(pointer, data);
+
+ ASSERT_EQ(7, pointer->one);
+ ASSERT_EQ(7, pointer->two);
+ ASSERT_EQ(7, pointer->three);
+ ASSERT_EQ(7, pointer->four);
+}
+
+TEST_F( LinearAllocatorTest, allocN_construct ) {
+ Data* pointer = m_pTestee->allocate(10);
+ m_pTestee->construct(pointer);
+ ASSERT_EQ(1, pointer->one);
+ ASSERT_EQ(2, pointer->two);
+ ASSERT_EQ(3, pointer->three);
+ ASSERT_EQ(4, pointer->four);
+}
+
+TEST_F( LinearAllocatorTest, allocN_constructCopy ) {
+ Data* pointer = m_pTestee->allocate(10);
+ Data data(7, 7, 7, 7);
+ m_pTestee->construct(pointer, data);
+
+ ASSERT_EQ(7, pointer->one);
+ ASSERT_EQ(7, pointer->two);
+ ASSERT_EQ(7, pointer->three);
+ ASSERT_EQ(7, pointer->four);
+}
+
+TEST_F( LinearAllocatorTest, multi_alloc_ctor_iterate ) {
+ for (int i=0; i<101; ++i) {
+ Data* pointer = m_pTestee->allocate();
+ m_pTestee->construct(pointer);
+ pointer->one = i;
+ }
+/**
+ Alloc::iterator data, dEnd = m_pTestee->end();
+ int counter = 0;
+ for (data=m_pTestee->begin(); data!=dEnd; ++data) {
+ ASSERT_EQ(counter, (*data).one);
+ ++counter;
+ }
+**/
+}
+
+TEST_F( LinearAllocatorTest, multi_allocN_ctor_iterate ) {
+ int counter = 0;
+ for (int i=0; i<10000; ++i) {
+ Data* pointer = m_pTestee->allocate(10);
+ for (int j=0; j<10; ++j) {
+ m_pTestee->construct(pointer);
+ pointer->one = counter;
+ ++pointer;
+ ++counter;
+ }
+ }
+/**
+ Alloc::iterator data, dEnd = m_pTestee->end();
+ counter = 0;
+ for (data=m_pTestee->begin(); data!=dEnd; ++data) {
+ ASSERT_EQ(counter, (*data).one);
+ ++counter;
+ }
+**/
+}
+
diff --git a/unittests/LinearAllocatorTest.h b/unittests/LinearAllocatorTest.h
new file mode 100644
index 0000000..9e9b2ab
--- /dev/null
+++ b/unittests/LinearAllocatorTest.h
@@ -0,0 +1,75 @@
+//===- LinearAllocatorTest.h ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LINEAR_ALLOCATOR_TEST_H
+#define LINEAR_ALLOCATOR_TEST_H
+
+#include <gtest.h>
+#include "mcld/Support/Allocators.h"
+
+namespace mcldtest
+{
+
+/** \class LinearAllocatorTest
+ * \brief The testcase for LinearAllocator
+ *
+ * \see LinearAllocator
+ */
+class LinearAllocatorTest : public ::testing::Test
+{
+public:
+ struct Data {
+ Data()
+ : one(1), two(2), three(3), four(4)
+ { }
+
+ Data( unsigned int pOne, unsigned int pTwo, unsigned char pThree, unsigned char pFour)
+ {
+ one = pOne;
+ two = pTwo;
+ three = pThree;
+ four = pFour;
+ }
+
+ ~Data()
+ {
+ one = -1;
+ two = -2;
+ three = -3;
+ four = -4;
+ }
+
+ unsigned int one;
+ unsigned int two;
+ unsigned char three;
+ unsigned char four;
+ };
+public:
+ // Constructor can do set-up work for all test here.
+ LinearAllocatorTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~LinearAllocatorTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ enum { CHUNK_SIZE = 32 };
+ typedef mcld::LinearAllocator<Data, CHUNK_SIZE> Alloc;
+protected:
+ Alloc* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/MCFragmentRefTest.cpp b/unittests/MCFragmentRefTest.cpp
new file mode 100644
index 0000000..556fbdd
--- /dev/null
+++ b/unittests/MCFragmentRefTest.cpp
@@ -0,0 +1,70 @@
+//===- MCFragmentRefTest --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mcld/MC/MCFragmentRef.h"
+#include "mcld/MC/MCRegionFragment.h"
+#include "mcld/Support/MemoryAreaFactory.h"
+#include "mcld/Support/Path.h"
+#include "MCFragmentRefTest.h"
+
+using namespace mcld;
+using namespace mcld::sys::fs;
+using namespace mcld::sys::fs::detail;
+using namespace mcldtest;
+
+// Constructor can do set-up work for all test here.
+MCFragmentRefTest::MCFragmentRefTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+MCFragmentRefTest::~MCFragmentRefTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void MCFragmentRefTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void MCFragmentRefTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( MCFragmentRefTest, ) {
+ Path path(TOPDIR);
+ path.append("unittests/test3.txt");
+ MemoryAreaFactory* areaFactory = new MemoryAreaFactory(1);
+ MemoryArea* area = areaFactory->produce(path, MemoryArea::ReadWrite);
+
+ MemoryRegion* region = area->request(0, 4096);
+ MCRegionFragment *frag = new MCRegionFragment(*region);
+ MCFragmentRef *ref = new MCFragmentRef(*frag);
+
+ ASSERT_EQ('H', region->getBuffer()[0]);
+ ASSERT_EQ(4096, region->size());
+ ASSERT_EQ('H', frag->getRegion().getBuffer()[0]);
+ ASSERT_EQ(4096, frag->getRegion().size());
+ ASSERT_EQ(frag, ref->frag());
+ ASSERT_EQ('H', static_cast<MCRegionFragment*>(ref->frag())->getRegion().getBuffer()[0]);
+ ASSERT_EQ(4096, static_cast<MCRegionFragment*>(ref->frag())->getRegion().size());
+ ASSERT_EQ('H', ref->deref()[0]);
+
+ ASSERT_FALSE(llvm::MCDataFragment::classof(frag));
+ ASSERT_TRUE(MCRegionFragment::classof(frag));
+
+ delete ref;
+ delete frag;
+ delete areaFactory;
+}
+
diff --git a/unittests/MCFragmentRefTest.h b/unittests/MCFragmentRefTest.h
new file mode 100644
index 0000000..c0b23f3
--- /dev/null
+++ b/unittests/MCFragmentRefTest.h
@@ -0,0 +1,48 @@
+//===- MCFragmentRefTest.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCLD_MCFRAGMENT_REF_TEST_H
+#define MCLD_MCFRAGMENT_REF_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class MCFragmentRef;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class MCFragmentRefTest
+ * \brief Reference Test
+ *
+ * \see MCFragmentRef
+ */
+class MCFragmentRefTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ MCFragmentRefTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~MCFragmentRefTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/MCRegionFragmentTest.cpp b/unittests/MCRegionFragmentTest.cpp
new file mode 100644
index 0000000..842ddf9
--- /dev/null
+++ b/unittests/MCRegionFragmentTest.cpp
@@ -0,0 +1,74 @@
+//===- MCRegionFragmentTest.cpp - MCRegionFragment implementation ---------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCRegionFragmentTest.h"
+
+#include "mcld/MC/MCRegionFragment.h"
+#include "mcld/Support/MemoryAreaFactory.h"
+#include "mcld/Support/Path.h"
+
+using namespace mcld;
+using namespace mcldtest;
+using namespace mcld::sys::fs;
+
+
+// Constructor can do set-up work for all test here.
+MCRegionFragmentTest::MCRegionFragmentTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+MCRegionFragmentTest::~MCRegionFragmentTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void MCRegionFragmentTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void MCRegionFragmentTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+TEST_F( MCRegionFragmentTest, classof_explicit ) {
+ Path path(TOPDIR);
+ path.append("unittests/test3.txt");
+ MemoryAreaFactory* areaFactory = new MemoryAreaFactory(1);
+ MemoryArea* area = areaFactory->produce(path, MemoryArea::ReadWrite);
+
+ MemoryRegion* region = area->request(0, 4096);
+ MCRegionFragment *frag = new MCRegionFragment(*region);
+
+ ASSERT_FALSE(llvm::MCDataFragment::classof(frag));
+ ASSERT_TRUE(MCRegionFragment::classof(frag));
+ delete frag;
+ delete areaFactory;
+}
+
+TEST_F( MCRegionFragmentTest, classof_implicit ) {
+ Path path(TOPDIR);
+ path.append("unittests/test3.txt");
+ MemoryAreaFactory* areaFactory = new MemoryAreaFactory(1);
+ MemoryArea* area = areaFactory->produce(path, MemoryArea::ReadWrite);
+
+ MemoryRegion* region = area->request(0, 4096);
+ llvm::MCFragment *frag = new MCRegionFragment(*region);
+
+ ASSERT_FALSE(llvm::MCDataFragment::classof(frag));
+ ASSERT_TRUE(MCRegionFragment::classof(frag));
+ delete frag;
+ delete areaFactory;
+}
+
diff --git a/unittests/MCRegionFragmentTest.h b/unittests/MCRegionFragmentTest.h
new file mode 100644
index 0000000..15434fd
--- /dev/null
+++ b/unittests/MCRegionFragmentTest.h
@@ -0,0 +1,51 @@
+//===- MCRegionFragment.h - unittest for MCRegionFragment -----------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCREGIONFRAGMENT_TEST_H
+#define MCREGIONFRAGMENT_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class MCRegionFragment;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class MCRegionFragmentTest
+ * \brief The testcase of MCRegionFragment.
+ *
+ * \see MCRegionFragment
+ */
+class MCRegionFragmentTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ MCRegionFragmentTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~MCRegionFragmentTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::MCRegionFragment* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/MemoryAreaTest.cpp b/unittests/MemoryAreaTest.cpp
new file mode 100644
index 0000000..a2e631a
--- /dev/null
+++ b/unittests/MemoryAreaTest.cpp
@@ -0,0 +1,148 @@
+//===- MemoryAreaTest.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "mcld/Support/FileSystem.h"
+#include "mcld/Support/MemoryArea.h"
+#include "mcld/Support/MemoryRegion.h"
+#include "mcld/Support/MemoryAreaFactory.h"
+#include "mcld/Support/Path.h"
+
+#include "MemoryAreaTest.h"
+#include <fcntl.h>
+#include <cstdio>
+
+using namespace mcld;
+using namespace mcld::sys::fs;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+MemoryAreaTest::MemoryAreaTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+MemoryAreaTest::~MemoryAreaTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void MemoryAreaTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void MemoryAreaTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( MemoryAreaTest, read_by_malloc )
+{
+ Path path(TOPDIR);
+ path.append("unittests/test3.txt");
+ MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1);
+ MemoryArea* area = AreaFactory->produce(path, O_RDONLY);
+ MemoryRegion* region = area->request(3, 2);
+ ASSERT_EQ('L', region->getBuffer()[0]);
+ ASSERT_EQ('O', region->getBuffer()[1]);
+ delete AreaFactory;
+}
+
+TEST_F( MemoryAreaTest, write_by_malloc )
+{
+ Path path(TOPDIR);
+ path.append("unittests/test2.txt");
+ MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1);
+ MemoryArea* area = AreaFactory->produce(path, O_RDWR);
+ ASSERT_TRUE(area->isMapped());
+ ASSERT_TRUE(area->isGood());
+ MemoryRegion* region = area->request(3, 4);
+ region->getBuffer()[0] = 'L';
+ region->getBuffer()[1] = 'i';
+ region->getBuffer()[2] = 'n';
+ region->getBuffer()[3] = 'k';
+ area->sync();
+ area->unmap();
+ area->map(path, O_RDONLY);
+ ASSERT_TRUE(area->isMapped());
+ ASSERT_TRUE(area->isGood());
+ region = area->request(5, 2);
+ ASSERT_EQ('n', region->getBuffer()[0]);
+ ASSERT_EQ('k', region->getBuffer()[1]);
+ delete AreaFactory;
+}
+
+TEST_F( MemoryAreaTest, read_one_page )
+{
+ Path path(TOPDIR) ;
+ path.append("unittests/test3.txt") ;
+ MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
+ MemoryArea* area = AreaFactory->produce(path, O_RDWR) ;
+ ASSERT_TRUE(area->isMapped()) ;
+ ASSERT_TRUE(area->isGood()) ;
+ MemoryRegion* region = area->request(0, 4096) ;
+ ASSERT_EQ('H', region->getBuffer()[0]);
+ ASSERT_EQ('E', region->getBuffer()[1]);
+ delete AreaFactory ;
+}
+
+TEST_F( MemoryAreaTest, write_one_page )
+{
+ Path path(TOPDIR) ;
+ path.append("unittests/test2.txt") ;
+ MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
+ MemoryArea* area = AreaFactory->produce(path, O_RDWR) ;
+ ASSERT_TRUE(area->isMapped()) ;
+ ASSERT_TRUE(area->isGood()) ;
+ MemoryRegion* region = area->request(0, 4096) ;
+ region->getBuffer()[4000] = 'K' ;
+ region->getBuffer()[4001] = 'R' ;
+ area->sync() ;
+ area->unmap() ;
+ area->map(path, O_RDONLY) ;
+ region = area->request(4000, 4) ;
+ ASSERT_EQ('K', region->getBuffer()[0]);
+ ASSERT_EQ('R', region->getBuffer()[1]);
+ region->getBuffer()[0] = 'O' ;
+ region->getBuffer()[1] = 'H' ;
+ area->sync() ;
+ delete AreaFactory ;
+}
+
+TEST_F( MemoryAreaTest, write_sync )
+{
+ Path path(TOPDIR) ;
+ path.append("unittests/test2.txt") ;
+ MemoryAreaFactory *AreaFactory = new MemoryAreaFactory(1) ;
+ MemoryArea* area = AreaFactory->produce(path, O_RDWR) ;
+ ASSERT_TRUE(area->isMapped()) ;
+ ASSERT_TRUE(area->isGood()) ;
+ MemoryRegion* region1 = area->request(0, 4096) ;
+ MemoryRegion* region2 = area->request(512, 1024) ;
+ region1->getBuffer()[1000] = 'L' ;
+ region1->getBuffer()[1001] = 'L' ;
+ region2->getBuffer()[488] = 'V' ;
+ region2->getBuffer()[489] = 'M' ;
+ area->sync() ;
+ area->unmap();
+ area->map(path, O_RDWR) ;
+ region1 = area->request(0, 1024) ;
+ EXPECT_EQ('V', region1->getBuffer()[1000]) ;
+ EXPECT_EQ('M', region1->getBuffer()[1001]) ;
+ region1->getBuffer()[1000] = '@' ;
+ region1->getBuffer()[1001] = '@' ;
+ area->sync();
+ delete AreaFactory ;
+}
+
+
diff --git a/unittests/MemoryAreaTest.h b/unittests/MemoryAreaTest.h
new file mode 100644
index 0000000..86a5da0
--- /dev/null
+++ b/unittests/MemoryAreaTest.h
@@ -0,0 +1,50 @@
+//===- MemoryAreaTest.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MEMORYAREA_TEST_H
+#define MEMORYAREA_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class MemoryArea;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class MemoryAreaTest
+ * \brief
+ *
+ * \see MemoryArea
+ */
+class MemoryAreaTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ MemoryAreaTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~MemoryAreaTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::MemoryArea* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/PathSetTest.cpp b/unittests/PathSetTest.cpp
new file mode 100644
index 0000000..d735e9c
--- /dev/null
+++ b/unittests/PathSetTest.cpp
@@ -0,0 +1,45 @@
+//===- PathSetTest.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/PathSet.h"
+#include "PathSetTest.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+PathSetTest::PathSetTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new PathSet();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+PathSetTest::~PathSetTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void PathSetTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void PathSetTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+TEST_F( PathSetTest, ) {
+}
+
diff --git a/unittests/PathSetTest.h b/unittests/PathSetTest.h
new file mode 100644
index 0000000..d64b2a8
--- /dev/null
+++ b/unittests/PathSetTest.h
@@ -0,0 +1,50 @@
+//===- PathSetTest.h ------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef PATHSET_TEST_H
+#define PATHSET_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class PathSet;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class PathSetTest
+ * \brief The testcase of PathSet
+ *
+ * \see PathSet
+ */
+class PathSetTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ PathSetTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~PathSetTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::PathSet* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/PathTest.cpp b/unittests/PathTest.cpp
new file mode 100644
index 0000000..8906d02
--- /dev/null
+++ b/unittests/PathTest.cpp
@@ -0,0 +1,140 @@
+//===- PathTest.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "PathTest.h"
+#include "mcld/Support/FileSystem.h"
+#include <string>
+
+//
+using namespace mcld;
+using namespace mcld::sys::fs;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+PathTest::PathTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new Path();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+PathTest::~PathTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void PathTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void PathTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( PathTest, should_exist ) {
+ const std::string root = "/etc/hosts";
+ m_pTestee->assign(root);
+ EXPECT_TRUE(exists(*m_pTestee));
+
+ delete m_pTestee;
+ m_pTestee = new Path(root);
+ EXPECT_TRUE(exists(*m_pTestee));
+}
+
+TEST_F( PathTest, should_not_exist ) {
+ const std::string root = "/luck";
+ m_pTestee->assign(root);
+ EXPECT_FALSE(exists(*m_pTestee));
+
+ delete m_pTestee;
+ m_pTestee = new Path(root);
+ EXPECT_FALSE(exists(*m_pTestee));
+}
+
+TEST_F( PathTest, should_is_directory ) {
+// const std::string root = "/proj/mtk03931/temp/pndk-luba/../";
+ const std::string root = "../././..";
+ m_pTestee->assign(root);
+ EXPECT_TRUE(exists(*m_pTestee));
+ EXPECT_TRUE(is_directory(*m_pTestee));
+ delete m_pTestee;
+ m_pTestee = new Path(root);
+ EXPECT_TRUE(exists(*m_pTestee));
+ EXPECT_TRUE(is_directory(*m_pTestee));
+}
+
+TEST_F( PathTest, should_not_is_directory ) {
+ const std::string root = "/luck";
+ m_pTestee->assign(root);
+ EXPECT_FALSE(exists(*m_pTestee));
+ EXPECT_FALSE(is_directory(*m_pTestee));
+ delete m_pTestee;
+ m_pTestee = new Path(root);
+ EXPECT_FALSE(exists(*m_pTestee));
+ EXPECT_FALSE(is_directory(*m_pTestee));
+}
+
+TEST_F( PathTest, should_equal ) {
+ const std::string root = "aaa/bbb/../../ccc/";
+ m_pTestee->assign(root);
+
+ Path* p2 = new Path("ccc///////");
+
+ EXPECT_TRUE(*m_pTestee==*p2);
+
+ delete m_pTestee;
+ m_pTestee = new Path(root);
+ EXPECT_TRUE(*m_pTestee==*m_pTestee);
+ delete p2;
+}
+
+TEST_F( PathTest, should_not_equal ) {
+ const std::string root = "aa/";
+ Path* p2=new Path("aaa//");
+// p2->assign(root);
+ m_pTestee->assign(root);
+ EXPECT_TRUE(*m_pTestee!=*p2);
+
+ delete m_pTestee;
+ m_pTestee = new Path(root);
+ EXPECT_TRUE(*m_pTestee!=*p2);
+ delete p2;
+}
+
+TEST_F( PathTest, append_success ) {
+
+ const std::string root = "aa/";
+ m_pTestee->assign(root);
+ m_pTestee->append("aaa");
+ std::string a("aa/aaa");
+ EXPECT_TRUE(m_pTestee->native()=="aa/aaa");
+ delete m_pTestee;
+ m_pTestee = new Path("aa/");
+ m_pTestee->append("/aaa");
+ EXPECT_TRUE(m_pTestee->string()=="aa/aaa");
+ delete m_pTestee;
+ m_pTestee = new Path("aa");
+ m_pTestee->append("/aaa");
+ EXPECT_TRUE(m_pTestee->string()=="aa/aaa");
+ delete m_pTestee;
+ m_pTestee = new Path("aa");
+ m_pTestee->append("aaa");
+ EXPECT_TRUE(m_pTestee->string()=="aa/aaa");
+}
+
+TEST_F( PathTest, should_become_generic_string ) {
+ m_pTestee->assign("/etc/../dev/../usr//lib//");
+ EXPECT_STREQ("/usr/lib/", m_pTestee->generic_string().c_str());
+}
+
diff --git a/unittests/PathTest.h b/unittests/PathTest.h
new file mode 100644
index 0000000..968ce0e
--- /dev/null
+++ b/unittests/PathTest.h
@@ -0,0 +1,45 @@
+//===- PathTest.h ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef PATH_TEST_H
+#define PATH_TEST_H
+
+#include "mcld/Support/Path.h"
+#include <gtest.h>
+
+namespace mcldtest
+{
+
+/** \class PathTest
+ * \brief a testcase for mcld::Path and its non-member funtions.
+ *
+ * \see Path
+ */
+class PathTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ PathTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~PathTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::sys::fs::Path* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/RTLinearAllocatorTest.cpp b/unittests/RTLinearAllocatorTest.cpp
new file mode 100644
index 0000000..9ef31e5
--- /dev/null
+++ b/unittests/RTLinearAllocatorTest.cpp
@@ -0,0 +1,140 @@
+//===- RTLinearAllocatorTest.cpp ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/Support/Allocators.h"
+#include <RTLinearAllocatorTest.h>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+RTLinearAllocatorTest::RTLinearAllocatorTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new LinearAllocator<Data, 0>(CHUNK_SIZE);
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+RTLinearAllocatorTest::~RTLinearAllocatorTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void RTLinearAllocatorTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void RTLinearAllocatorTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+TEST_F(RTLinearAllocatorTest, AllocateN) {
+ Data* pointer = m_pTestee->allocate(10);
+ ASSERT_FALSE(0 == pointer);
+ ASSERT_EQ(CHUNK_SIZE, m_pTestee->max_size());
+ ASSERT_FALSE(m_pTestee->empty());
+}
+
+TEST_F(RTLinearAllocatorTest, allocate ) {
+ Data* pointer = m_pTestee->allocate();
+ ASSERT_FALSE(0 == pointer);
+ ASSERT_EQ(CHUNK_SIZE, m_pTestee->max_size());
+ ASSERT_FALSE(m_pTestee->empty());
+}
+
+TEST_F(RTLinearAllocatorTest, allocateOver ) {
+ Data* pointer = m_pTestee->allocate(CHUNK_SIZE+1);
+ ASSERT_TRUE(0 == pointer);
+ ASSERT_EQ(0, m_pTestee->max_size());
+ ASSERT_TRUE(m_pTestee->empty());
+}
+
+TEST_F(RTLinearAllocatorTest, alloc_construct ) {
+ Data* pointer = m_pTestee->allocate();
+ m_pTestee->construct(pointer);
+ ASSERT_EQ(1, pointer->one);
+ ASSERT_EQ(2, pointer->two);
+ ASSERT_EQ(3, pointer->three);
+ ASSERT_EQ(4, pointer->four);
+}
+
+TEST_F(RTLinearAllocatorTest, alloc_constructCopy ) {
+ Data* pointer = m_pTestee->allocate();
+ Data data(7, 7, 7, 7);
+ m_pTestee->construct(pointer, data);
+
+ ASSERT_EQ(7, pointer->one);
+ ASSERT_EQ(7, pointer->two);
+ ASSERT_EQ(7, pointer->three);
+ ASSERT_EQ(7, pointer->four);
+}
+
+TEST_F(RTLinearAllocatorTest, allocN_construct ) {
+ Data* pointer = m_pTestee->allocate(10);
+ m_pTestee->construct(pointer);
+ ASSERT_EQ(1, pointer->one);
+ ASSERT_EQ(2, pointer->two);
+ ASSERT_EQ(3, pointer->three);
+ ASSERT_EQ(4, pointer->four);
+}
+
+TEST_F(RTLinearAllocatorTest, allocN_constructCopy ) {
+ Data* pointer = m_pTestee->allocate(10);
+ Data data(7, 7, 7, 7);
+ m_pTestee->construct(pointer, data);
+
+ ASSERT_EQ(7, pointer->one);
+ ASSERT_EQ(7, pointer->two);
+ ASSERT_EQ(7, pointer->three);
+ ASSERT_EQ(7, pointer->four);
+}
+
+TEST_F(RTLinearAllocatorTest, multi_alloc_ctor_iterate ) {
+ for (int i=0; i<101; ++i) {
+ Data* pointer = m_pTestee->allocate();
+ m_pTestee->construct(pointer);
+ pointer->one = i;
+ }
+/**
+ Alloc::iterator data, dEnd = m_pTestee->end();
+ int counter = 0;
+ for (data=m_pTestee->begin(); data!=dEnd; ++data) {
+ ASSERT_EQ(counter, (*data).one);
+ ++counter;
+ }
+**/
+}
+
+TEST_F(RTLinearAllocatorTest, multi_allocN_ctor_iterate ) {
+ int counter = 0;
+ for (int i=0; i<10000; ++i) {
+ Data* pointer = m_pTestee->allocate(10);
+ for (int j=0; j<10; ++j) {
+ m_pTestee->construct(pointer);
+ pointer->one = counter;
+ ++pointer;
+ ++counter;
+ }
+ }
+/**
+ Alloc::iterator data, dEnd = m_pTestee->end();
+ counter = 0;
+ for (data=m_pTestee->begin(); data!=dEnd; ++data) {
+ ASSERT_EQ(counter, (*data).one);
+ ++counter;
+ }
+**/
+}
+
diff --git a/unittests/RTLinearAllocatorTest.h b/unittests/RTLinearAllocatorTest.h
new file mode 100644
index 0000000..d58442a
--- /dev/null
+++ b/unittests/RTLinearAllocatorTest.h
@@ -0,0 +1,74 @@
+//===- RTLinearAllocatorTest.h --------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef RTLINEARALLOCATOR_TEST_H
+#define RTLINEARALLOCATOR_TEST_H
+
+#include <gtest.h>
+#include "mcld/Support/Allocators.h"
+
+namespace mcldtest
+{
+
+/** \class RTLinearAllocatorTest
+ * \brief
+ *
+ * \see RTLinearAllocator
+ */
+class RTLinearAllocatorTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ RTLinearAllocatorTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~RTLinearAllocatorTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+public:
+ struct Data {
+ Data()
+ : one(1), two(2), three(3), four(4)
+ { }
+
+ Data( unsigned int pOne, unsigned int pTwo, unsigned char pThree, unsigned char pFour)
+ {
+ one = pOne;
+ two = pTwo;
+ three = pThree;
+ four = pFour;
+ }
+
+ ~Data()
+ {
+ one = -1;
+ two = -2;
+ three = -3;
+ four = -4;
+ }
+
+ unsigned int one;
+ unsigned int two;
+ unsigned char three;
+ unsigned char four;
+ };
+ enum { CHUNK_SIZE = 32 };
+
+protected:
+ mcld::LinearAllocator<Data,0>* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/StaticResolverTest.cpp b/unittests/StaticResolverTest.cpp
new file mode 100644
index 0000000..f9dfdf4
--- /dev/null
+++ b/unittests/StaticResolverTest.cpp
@@ -0,0 +1,436 @@
+//===- implTest.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/StaticResolver.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/ResolveInfoFactory.h>
+#include "StaticResolverTest.h"
+
+#include <iostream>
+
+using namespace std;
+using namespace mcld;
+using namespace mcldtest;
+
+// Constructor can do set-up work for all test here.
+StaticResolverTest::StaticResolverTest()
+{
+ // create testee. modify it if need
+ m_pResolver = new StaticResolver();
+ m_pFactory = new ResolveInfoFactory();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+StaticResolverTest::~StaticResolverTest()
+{
+ delete m_pResolver;
+ delete m_pFactory;
+}
+
+// SetUp() will be called immediately before each test.
+void StaticResolverTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void StaticResolverTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( StaticResolverTest, MDEF ) {
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+ new_sym->setDesc(ResolveInfo::Define);
+ old_sym->setDesc(ResolveInfo::Define);
+ ASSERT_EQ( mcld::ResolveInfo::Define, new_sym->desc());
+ ASSERT_EQ( mcld::ResolveInfo::Define, old_sym->desc());
+ ASSERT_TRUE( mcld::ResolveInfo::define_flag == new_sym->info());
+ ASSERT_TRUE( mcld::ResolveInfo::define_flag == old_sym->info());
+ bool override = true;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Abort, result);
+ ASSERT_FALSE( override );
+ ASSERT_STREQ( "multiple definitions of `abc'.", m_pResolver->mesg().c_str() );
+}
+
+TEST_F( StaticResolverTest, DynDefAfterDynUndef ) {
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ new_sym->setBinding(ResolveInfo::Global);
+ old_sym->setBinding(ResolveInfo::Global);
+ new_sym->setDesc(ResolveInfo::Undefined);
+ old_sym->setDesc(ResolveInfo::Define);
+ new_sym->setSource(true);
+ old_sym->setSource(true);
+
+ new_sym->setSize(0);
+
+ old_sym->setSize(1);
+
+ ASSERT_EQ( mcld::ResolveInfo::Global, new_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Global, old_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Undefined, new_sym->desc());
+ ASSERT_EQ( mcld::ResolveInfo::Define, old_sym->desc());
+
+ bool override = false;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Success, result);
+ ASSERT_FALSE( override );
+ ASSERT_EQ(1, old_sym->size());
+}
+
+TEST_F( StaticResolverTest, DynDefAfterDynDef ) {
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ new_sym->setBinding(ResolveInfo::Global);
+ old_sym->setBinding(ResolveInfo::Global);
+ new_sym->setDesc(ResolveInfo::Define);
+ old_sym->setDesc(ResolveInfo::Define);
+ new_sym->setSource(true);
+ old_sym->setSource(true);
+
+ new_sym->setSize(0);
+
+ old_sym->setSize(1);
+
+ ASSERT_EQ( mcld::ResolveInfo::Global, new_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Global, old_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Define, new_sym->desc());
+ ASSERT_EQ( mcld::ResolveInfo::Define, old_sym->desc());
+
+ bool override = false;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Success, result);
+ ASSERT_FALSE( override );
+ ASSERT_EQ(1, old_sym->size());
+}
+
+TEST_F( StaticResolverTest, DynUndefAfterDynUndef ) {
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ new_sym->setBinding(ResolveInfo::Global);
+ old_sym->setBinding(ResolveInfo::Global);
+ new_sym->setDesc(ResolveInfo::Undefined);
+ old_sym->setDesc(ResolveInfo::Undefined);
+ new_sym->setSource(true);
+ old_sym->setSource(true);
+
+ new_sym->setSize(0);
+
+ old_sym->setSize(1);
+
+ ASSERT_EQ( mcld::ResolveInfo::Global, new_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Global, old_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Undefined, new_sym->desc());
+ ASSERT_EQ( mcld::ResolveInfo::Undefined, old_sym->desc());
+
+ bool override = false;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Success, result);
+ ASSERT_FALSE( override );
+ ASSERT_EQ(1, old_sym->size());
+}
+
+TEST_F( StaticResolverTest, OverrideWeakByGlobal )
+{
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ new_sym->setBinding(ResolveInfo::Global);
+ old_sym->setBinding(ResolveInfo::Weak);
+ new_sym->setSize(0);
+ old_sym->setSize(1);
+
+ ASSERT_EQ( mcld::ResolveInfo::Global, new_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Weak, old_sym->binding());
+
+ ASSERT_TRUE( mcld::ResolveInfo::global_flag == new_sym->info());
+ ASSERT_TRUE( mcld::ResolveInfo::weak_flag == old_sym->info());
+ bool override = false;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Success, result);
+ ASSERT_TRUE( override );
+ ASSERT_EQ(0, old_sym->size());
+}
+
+TEST_F( StaticResolverTest, DynWeakAfterDynDef ) {
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ old_sym->setBinding(ResolveInfo::Weak);
+ new_sym->setBinding(ResolveInfo::Global);
+
+ new_sym->setSource(true);
+ old_sym->setSource(true);
+
+ old_sym->setDesc(ResolveInfo::Define);
+ new_sym->setDesc(ResolveInfo::Define);
+
+ new_sym->setSize(0);
+
+ old_sym->setSize(1);
+
+ ASSERT_EQ( mcld::ResolveInfo::Weak, old_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Global, new_sym->binding());
+ ASSERT_EQ( mcld::ResolveInfo::Define, old_sym->desc());
+ ASSERT_EQ( mcld::ResolveInfo::Define, new_sym->desc());
+
+ bool override = false;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Success, result);
+ ASSERT_FALSE( override );
+ ASSERT_EQ(1, old_sym->size());
+}
+
+TEST_F( StaticResolverTest, MarkByBiggerCommon )
+{
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ new_sym->setDesc(ResolveInfo::Common);
+ old_sym->setDesc(ResolveInfo::Common);
+ new_sym->setSize(999);
+ old_sym->setSize(0);
+
+ ASSERT_EQ( mcld::ResolveInfo::Common, new_sym->desc());
+ ASSERT_EQ( mcld::ResolveInfo::Common, old_sym->desc());
+
+ ASSERT_TRUE( mcld::ResolveInfo::common_flag == new_sym->info());
+ ASSERT_TRUE( mcld::ResolveInfo::common_flag == old_sym->info());
+ bool override = true;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Success, result);
+ ASSERT_FALSE( override );
+ ASSERT_EQ(999, old_sym->size());
+}
+
+TEST_F( StaticResolverTest, OverrideByBiggerCommon )
+{
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ new_sym->setDesc(ResolveInfo::Common);
+ old_sym->setDesc(ResolveInfo::Common);
+ old_sym->setBinding(ResolveInfo::Weak);
+ new_sym->setSize(999);
+ old_sym->setSize(0);
+
+ ASSERT_EQ( ResolveInfo::Common, new_sym->desc());
+ ASSERT_EQ( ResolveInfo::Common, old_sym->desc());
+ ASSERT_EQ( ResolveInfo::Weak, old_sym->binding());
+
+ ASSERT_TRUE( ResolveInfo::common_flag == new_sym->info());
+ ASSERT_TRUE( (ResolveInfo::weak_flag | ResolveInfo::common_flag) == old_sym->info());
+
+ bool override = false;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ( Resolver::Success, result);
+ ASSERT_TRUE( override );
+ ASSERT_EQ(999, old_sym->size());
+}
+
+TEST_F( StaticResolverTest, OverrideCommonByDefine)
+{
+ ResolveInfo* old_sym = m_pFactory->produce("abc");
+ ResolveInfo* new_sym = m_pFactory->produce("abc");
+
+ old_sym->setDesc(ResolveInfo::Common);
+ old_sym->setSize(0);
+
+ new_sym->setDesc(ResolveInfo::Define);
+ new_sym->setSize(999);
+
+ ASSERT_EQ( ResolveInfo::Define, new_sym->desc());
+ ASSERT_EQ( ResolveInfo::Common, old_sym->desc());
+
+ ASSERT_TRUE( ResolveInfo::define_flag == new_sym->info());
+ ASSERT_TRUE( ResolveInfo::common_flag == old_sym->info());
+
+ bool override = false;
+ unsigned int result = m_pResolver->resolve(*old_sym, *new_sym, override);
+ ASSERT_EQ(Resolver::Warning, result);
+ ASSERT_TRUE( override );
+ ASSERT_EQ(999, old_sym->size());
+
+ ASSERT_STREQ("definition of 'abc' is overriding common.", m_pResolver->mesg().c_str() );
+
+}
+
+TEST_F( StaticResolverTest, SetUpDesc)
+{
+ ResolveInfo* sym = m_pFactory->produce("abc");
+
+ sym->setIsSymbol(true);
+
+// ASSERT_FALSE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_TRUE( sym->isUndef() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( 0, sym->desc() );
+ ASSERT_EQ( 0, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setIsSymbol(false);
+ ASSERT_FALSE( sym->isSymbol() );
+// ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_TRUE( sym->isUndef() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( 0, sym->desc() );
+ ASSERT_EQ( 0, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setDesc(ResolveInfo::Define);
+ ASSERT_FALSE( sym->isSymbol() );
+// ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_TRUE( sym->isDefine() );
+ ASSERT_FALSE( sym->isUndef() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( ResolveInfo::Define, sym->desc() );
+ ASSERT_EQ( 0, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setDesc(ResolveInfo::Common);
+ ASSERT_FALSE( sym->isSymbol() );
+// ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_FALSE( sym->isUndef() );
+ ASSERT_TRUE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( ResolveInfo::Common, sym->desc() );
+ ASSERT_EQ( 0, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setDesc(ResolveInfo::Indirect);
+ ASSERT_FALSE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_FALSE( sym->isUndef() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_TRUE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( ResolveInfo::Indirect, sym->desc() );
+ ASSERT_EQ( 0, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setDesc(ResolveInfo::Undefined);
+ ASSERT_FALSE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_TRUE( sym->isUndef() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( 0, sym->desc() );
+ ASSERT_EQ( 0, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+}
+
+TEST_F( StaticResolverTest, SetUpBinding)
+{
+ ResolveInfo* sym = m_pFactory->produce("abc");
+
+ sym->setIsSymbol(true);
+
+// ASSERT_FALSE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_TRUE( sym->isUndef() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( 0, sym->desc() );
+ ASSERT_EQ( 0, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setBinding(ResolveInfo::Global);
+ ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_TRUE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_TRUE( sym->isUndef() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( 0, sym->desc() );
+ ASSERT_EQ( ResolveInfo::Global, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setBinding(ResolveInfo::Weak);
+ ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_FALSE( sym->isGlobal() );
+ ASSERT_TRUE( sym->isWeak() );
+ ASSERT_FALSE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_TRUE( sym->isUndef() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( 0, sym->desc() );
+ ASSERT_EQ( ResolveInfo::Weak, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+
+ sym->setBinding(ResolveInfo::Local);
+ ASSERT_TRUE( sym->isSymbol() );
+ ASSERT_FALSE( sym->isGlobal() );
+ ASSERT_FALSE( sym->isWeak() );
+ ASSERT_TRUE( sym->isLocal() );
+ ASSERT_FALSE( sym->isDyn() );
+ ASSERT_FALSE( sym->isDefine() );
+ ASSERT_TRUE( sym->isUndef() );
+ ASSERT_FALSE( sym->isCommon() );
+ ASSERT_FALSE( sym->isIndirect() );
+ ASSERT_EQ( ResolveInfo::NoType, sym->type());
+ ASSERT_EQ( 0, sym->desc() );
+ ASSERT_EQ( ResolveInfo::Local, sym->binding() );
+ ASSERT_EQ( 0, sym->other() );
+}
+
diff --git a/unittests/StaticResolverTest.h b/unittests/StaticResolverTest.h
new file mode 100644
index 0000000..8b8ba31
--- /dev/null
+++ b/unittests/StaticResolverTest.h
@@ -0,0 +1,52 @@
+//===- headerTest.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef STATICRESOLVER_TEST_H
+#define STATICRESOLVER_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class StaticResolver;
+class ResolveInfoFactory;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class StaticResolverTest
+ * \brief The testcases for static resolver
+ *
+ * \see StaticResolver
+ */
+class StaticResolverTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ StaticResolverTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~StaticResolverTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::StaticResolver* m_pResolver;
+ mcld::ResolveInfoFactory* m_pFactory;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/StrSymPoolTest.cpp b/unittests/StrSymPoolTest.cpp
new file mode 100644
index 0000000..a4ef558
--- /dev/null
+++ b/unittests/StrSymPoolTest.cpp
@@ -0,0 +1,259 @@
+//===- StrSymPoolTest.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/StrSymPool.h"
+#include "StrSymPoolTest.h"
+#include <string>
+#include <cstdio>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+StrSymPoolTest::StrSymPoolTest()
+{
+ // create testee. modify it if need
+ Resolver resolver;
+ m_pTestee = new StrSymPool(1, 1, resolver);
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+StrSymPoolTest::~StrSymPoolTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void StrSymPoolTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void StrSymPoolTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+
+TEST_F( StrSymPoolTest, insertString ) {
+ const char *s1 = "Hello MCLinker";
+ const char *result1 = m_pTestee->insertString(s1);
+ EXPECT_NE(s1, result1);
+ EXPECT_STREQ(s1, result1);
+}
+
+TEST_F( StrSymPoolTest, insertSameString ) {
+ const char *s1 = "Hello MCLinker";
+ std::string s2(s1);
+ const char *result1 = m_pTestee->insertString(s1);
+ const char *result2 = m_pTestee->insertString(s2.c_str());
+ EXPECT_STREQ(s1, result1);
+ EXPECT_STREQ(s2.c_str(), result2);
+ EXPECT_EQ(result1, result2);
+}
+
+TEST_F( StrSymPoolTest, insert_local_defined_Symbol ) {
+ const char *name = "Hello MCLinker";
+ bool isDyn = false;
+ LDSymbol::Type type = LDSymbol::Defined;
+ LDSymbol::Binding binding = LDSymbol::Local;
+ const llvm::MCSectionData *section = 0;
+ uint64_t value = 0;
+ uint64_t size = 0;
+ uint8_t other = 0;
+
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+ EXPECT_NE(name, sym->name());
+ EXPECT_STREQ(name, sym->name());
+ EXPECT_EQ(isDyn, sym->isDyn());
+ EXPECT_EQ(type, sym->type());
+ EXPECT_EQ(binding, sym->binding());
+ EXPECT_EQ(section, sym->section());
+ EXPECT_EQ(value, sym->value());
+ EXPECT_EQ(size, sym->size());
+ EXPECT_EQ(other, sym->other());
+
+ LDSymbol *sym2 = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+ EXPECT_NE(name, sym2->name());
+ EXPECT_STREQ(name, sym2->name());
+ EXPECT_EQ(isDyn, sym2->isDyn());
+ EXPECT_EQ(type, sym2->type());
+ EXPECT_EQ(binding, sym2->binding());
+ EXPECT_EQ(section, sym2->section());
+ EXPECT_EQ(value, sym2->value());
+ EXPECT_EQ(size, sym2->size());
+ EXPECT_EQ(other, sym2->other());
+
+
+ EXPECT_NE(sym, sym2);
+}
+
+TEST_F( StrSymPoolTest, insert_global_reference_Symbol ) {
+ const char *name = "Hello MCLinker";
+ bool isDyn = false;
+ LDSymbol::Type type = LDSymbol::Reference;
+ LDSymbol::Binding binding = LDSymbol::Global;
+ const llvm::MCSectionData *section = 0;
+ uint64_t value = 0;
+ uint64_t size = 0;
+ uint8_t other = 0;
+
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+ EXPECT_NE(name, sym->name());
+ EXPECT_STREQ(name, sym->name());
+ EXPECT_EQ(isDyn, sym->isDyn());
+ EXPECT_EQ(type, sym->type());
+ EXPECT_EQ(binding, sym->binding());
+ EXPECT_EQ(section, sym->section());
+ EXPECT_EQ(value, sym->value());
+ EXPECT_EQ(size, sym->size());
+ EXPECT_EQ(other, sym->other());
+
+
+ LDSymbol *sym2 = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+
+
+ EXPECT_EQ(sym, sym2);
+
+
+ LDSymbol *sym3 = m_pTestee->insertSymbol("Different symbol",
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+
+ EXPECT_NE(sym, sym3);
+}
+
+
+TEST_F( StrSymPoolTest, insertSymbol_after_insert_same_string ) {
+ const char *name = "Hello MCLinker";
+ bool isDyn = false;
+ LDSymbol::Type type = LDSymbol::Defined;
+ LDSymbol::Binding binding = LDSymbol::Global;
+ const llvm::MCSectionData *section = 0;
+ uint64_t value = 0;
+ uint64_t size = 0;
+ uint8_t other = 0;
+
+ const char *result1 = m_pTestee->insertString(name);
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+
+ EXPECT_STREQ(name, sym->name());
+ EXPECT_EQ(result1, sym->name());
+
+ char s[16];
+ strcpy(s, result1);
+ const char *result2 = m_pTestee->insertString(result1);
+ const char *result3 = m_pTestee->insertString(s);
+
+ EXPECT_EQ(result1, result2);
+ EXPECT_EQ(result1, result3);
+}
+
+
+TEST_F( StrSymPoolTest, insert_16384_weak_reference_symbols ) {
+ char name[16];
+ bool isDyn = false;
+ LDSymbol::Type type = LDSymbol::Reference;
+ LDSymbol::Binding binding = LDSymbol::Weak;
+ const llvm::MCSectionData *section = 0;
+ uint64_t value = 0;
+ uint64_t size = 0;
+ uint8_t other = 0;
+ strcpy(name, "Hello MCLinker");
+ LDSymbol *syms[128][128];
+ for(int i=0; i<128 ;++i) {
+ name[0] = i;
+ for(int j=0; j<128 ;++j) {
+ name[1] = j;
+ syms[i][j] = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+
+ ASSERT_STREQ(name, syms[i][j]->name());
+ }
+ }
+ for(int i=127; i>=0 ;--i) {
+ name[0] = i;
+ for(int j=0; j<128 ;++j) {
+ name[1] = j;
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+ ASSERT_EQ(sym, syms[i][j]);
+ }
+ }
+ for(int i=0; i<128 ;++i) {
+ name[0] = i;
+ for(int j=0; j<128 ;++j) {
+ name[1] = j;
+ LDSymbol *sym = m_pTestee->insertSymbol(name,
+ isDyn,
+ type,
+ binding,
+ section,
+ value,
+ size,
+ other);
+ ASSERT_EQ(sym, syms[i][j]);
+ }
+ }
+}
diff --git a/unittests/StrSymPoolTest.h b/unittests/StrSymPoolTest.h
new file mode 100644
index 0000000..041fafa
--- /dev/null
+++ b/unittests/StrSymPoolTest.h
@@ -0,0 +1,50 @@
+//===- StrSymPoolTest.h ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef STRSYMPOOL_TEST_H
+#define STRSYMPOOL_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class StrSymPool;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class StrSymPoolTest
+ * \brief
+ *
+ * \see StrSymPool
+ */
+class StrSymPoolTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ StrSymPoolTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~StrSymPoolTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::StrSymPool* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/StringTableTest.cpp b/unittests/StringTableTest.cpp
new file mode 100644
index 0000000..59a8e7b
--- /dev/null
+++ b/unittests/StringTableTest.cpp
@@ -0,0 +1,77 @@
+//===- StringTableTest.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "StringTableTest.h"
+#include "mcld/LD/StringTable.h"
+#include <cstring>
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+StringTableTest::StringTableTest()
+{
+ // create testee. modify it if need
+ Resolver* R = new Resolver();
+ StrSymPool* Pool = new StrSymPool(1, 1, *R);
+ m_pTestee = new StringTable(*Pool);
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+StringTableTest::~StringTableTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void StringTableTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void StringTableTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F(StringTableTest, different_string_size) {
+ int size = 127-32;
+ for (int i = 32; i < 127; ++i) {
+ char c[2];
+ c[0] = i;
+ c[1] = '\0';
+ ASSERT_NE(m_pTestee->insert(c), c);
+ }
+ ASSERT_EQ(m_pTestee->size(), size);
+}
+
+TEST_F(StringTableTest, traverse_begin_to_end) {
+ m_pTestee->insert("Hello");
+ m_pTestee->insert("World");
+ m_pTestee->insert("Media");
+ m_pTestee->insert("Tek");
+ StringTable::iterator it = m_pTestee->begin();
+ ASSERT_STREQ(*it, "Hello");
+ ++it;
+ ASSERT_STREQ(*it, "World");
+ ++it;
+ ASSERT_STREQ(*it, "Media");
+ ++it;
+ ASSERT_STREQ(*it, "Tek");
+ ++it;
+ ASSERT_EQ(it, m_pTestee->end());
+}
+
+TEST_F(StringTableTest, null_string) {
+ m_pTestee->insert("");
+ ASSERT_STREQ(*(m_pTestee->begin()), "");
+ ASSERT_EQ(m_pTestee->size(), 1);
+}
diff --git a/unittests/StringTableTest.h b/unittests/StringTableTest.h
new file mode 100644
index 0000000..0b397e8
--- /dev/null
+++ b/unittests/StringTableTest.h
@@ -0,0 +1,50 @@
+//===- StringTableTest.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef STRINGTABLE_TEST_H
+#define STRINGTABLE_TEST_H
+
+#include <gtest.h>
+
+namespace mcld
+{
+class StringTable;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class StringTableTest
+ * \brief
+ *
+ * \see StringTable
+ */
+class StringTableTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ StringTableTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~StringTableTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::StringTable* m_pTestee;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/SymbolCategoryTest.cpp b/unittests/SymbolCategoryTest.cpp
new file mode 100644
index 0000000..4233c3e
--- /dev/null
+++ b/unittests/SymbolCategoryTest.cpp
@@ -0,0 +1,94 @@
+//===- implTest.cpp -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/MC/SymbolCategory.h>
+#include <mcld/LD/ResolveInfo.h>
+#include <mcld/LD/LDSymbol.h>
+#include <iostream>
+#include "SymbolCategoryTest.h"
+
+using namespace std;
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+SymbolCategoryTest::SymbolCategoryTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new SymbolCategory();
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+SymbolCategoryTest::~SymbolCategoryTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void SymbolCategoryTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void SymbolCategoryTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+TEST_F(SymbolCategoryTest, upward_test) {
+ ResolveInfo* a = m_InfoFactory.produce("a");
+ ResolveInfo* b = m_InfoFactory.produce("b");
+ ResolveInfo* c = m_InfoFactory.produce("c");
+ ResolveInfo* d = m_InfoFactory.produce("d");
+ ResolveInfo* e = m_InfoFactory.produce("e");
+ e->setBinding(ResolveInfo::Global);
+ d->setBinding(ResolveInfo::Weak);
+ c->setDesc(ResolveInfo::Common);
+ c->setBinding(ResolveInfo::Global);
+ b->setBinding(ResolveInfo::Local);
+ a->setType(ResolveInfo::File);
+
+ LDSymbol aa;
+ LDSymbol bb;
+ LDSymbol cc;
+ LDSymbol dd;
+ LDSymbol ee;
+
+ aa.setResolveInfo(*a);
+ bb.setResolveInfo(*b);
+ cc.setResolveInfo(*c);
+ dd.setResolveInfo(*d);
+ ee.setResolveInfo(*e);
+
+ m_pTestee->add(ee);
+ m_pTestee->add(dd);
+ m_pTestee->add(cc);
+ m_pTestee->add(bb);
+ m_pTestee->add(aa);
+
+ SymbolCategory::iterator sym = m_pTestee->begin();
+ ASSERT_STREQ("a", (*sym)->name());
+ ++sym;
+ ASSERT_STREQ("b", (*sym)->name());
+ ++sym;
+ ASSERT_STREQ("c", (*sym)->name());
+ ++sym;
+ ASSERT_STREQ("d", (*sym)->name());
+ ++sym;
+ ASSERT_STREQ("e", (*sym)->name());
+
+ ASSERT_EQ(2, m_pTestee->numOfLocals());
+ ASSERT_EQ(1, m_pTestee->numOfCommons());
+ ASSERT_EQ(2, m_pTestee->numOfRegulars());
+ ASSERT_EQ(5, m_pTestee->numOfSymbols());
+}
+
diff --git a/unittests/SymbolCategoryTest.h b/unittests/SymbolCategoryTest.h
new file mode 100644
index 0000000..f721368
--- /dev/null
+++ b/unittests/SymbolCategoryTest.h
@@ -0,0 +1,52 @@
+//===- headerTest.h -------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SYMBOLCATEGORY_TEST_H
+#define MCLD_SYMBOLCATEGORY_TEST_H
+#include <mcld/LD/ResolveInfoFactory.h>
+
+#include <gtest.h>
+
+namespace mcld
+{
+class SymbolCategory;
+
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class SymbolCategoryTest
+ * \brief The testcases of symbol category.
+ *
+ * \see SymbolCategory
+ */
+class SymbolCategoryTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ SymbolCategoryTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~SymbolCategoryTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::SymbolCategory* m_pTestee;
+ mcld::ResolveInfoFactory m_InfoFactory;
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/SymbolTableTest.cpp b/unittests/SymbolTableTest.cpp
new file mode 100644
index 0000000..5b665f0
--- /dev/null
+++ b/unittests/SymbolTableTest.cpp
@@ -0,0 +1,45 @@
+//===- SymbolTableTest.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/SymbolTable.h"
+#include "SymbolTableTest.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+SymbolTableTest::SymbolTableTest()
+{
+ // create testee. modify it if need
+ m_pTestee = new SymbolTable<>(m_StrTable);
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+SymbolTableTest::~SymbolTableTest()
+{
+ delete m_pTestee;
+}
+
+// SetUp() will be called immediately before each test.
+void SymbolTableTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void SymbolTableTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+TEST_F(SymbolTableTest, init) {
+ mcld::SymbolTable<>::iterator it;
+ it = m_pTestee->begin();
+ ASSERT_EQ(it, m_pTestee->end());
+}
diff --git a/unittests/SymbolTableTest.h b/unittests/SymbolTableTest.h
new file mode 100644
index 0000000..9076ac9
--- /dev/null
+++ b/unittests/SymbolTableTest.h
@@ -0,0 +1,50 @@
+//===- SymbolTableTest.h --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LD_SYMBOLTABLE_TEST_H
+#define LD_SYMBOLTABLE_TEST_H
+#include "mcld/LD/StringTable.h"
+#include <gtest.h>
+
+namespace mcld
+{
+ template <template <class> class, class>
+ class SymbolTable;
+} // namespace for mcld
+
+namespace mcldtest
+{
+
+/** \class SymbolTableTest
+ * \brief
+ *
+ * \see SymbolTable
+ */
+class SymbolTableTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ SymbolTableTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~SymbolTableTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+
+protected:
+ mcld::SymbolTable<>* m_pTestee;
+ mcld::StringTable m_StrTable;
+};
+
+} // namespace of mcldtest
+
+#endif
diff --git a/unittests/TargetMachineTest.cpp b/unittests/TargetMachineTest.cpp
new file mode 100644
index 0000000..6258906
--- /dev/null
+++ b/unittests/TargetMachineTest.cpp
@@ -0,0 +1,42 @@
+//===- TargetMachineTest.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <TargetMachineTest.h>
+
+using namespace mcld;
+using namespace mcldTEST;
+
+
+// Constructor can do set-up work for all test here.
+TargetMachineTest::TargetMachineTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+TargetMachineTest::~TargetMachineTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void TargetMachineTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void TargetMachineTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+
+TEST_F( TargetMachineTest, addPassesToEmitFile ) {
+ mcld::addPassesToEmitFile();
+}
+
diff --git a/unittests/TargetMachineTest.h b/unittests/TargetMachineTest.h
new file mode 100644
index 0000000..3f77da7
--- /dev/null
+++ b/unittests/TargetMachineTest.h
@@ -0,0 +1,41 @@
+//===- TargetMachineTest.h ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TARGETMACHINE_TEST_H
+#define TARGETMACHINE_TEST_H
+#include "mcld/Target/TargetMachine.h"
+#include <gtest.h>
+
+namespace mcldTEST
+{
+
+/** \class TargetMachineTest
+ * \brief
+ *
+ * \see TargetMachine
+ */
+class TargetMachineTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ TargetMachineTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~TargetMachineTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of BOLDTEST
+
+#endif
+
diff --git a/unittests/UniqueGCFactoryBaseTest.cpp b/unittests/UniqueGCFactoryBaseTest.cpp
new file mode 100644
index 0000000..08f82ba
--- /dev/null
+++ b/unittests/UniqueGCFactoryBaseTest.cpp
@@ -0,0 +1,87 @@
+//===- UniqueGCFactoryBaseTest.cpp ----------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/MC/ContextFactory.h"
+#include "mcld/Support/MemoryAreaFactory.h"
+#include "UniqueGCFactoryBaseTest.h"
+
+using namespace mcld;
+using namespace mcldtest;
+
+
+// Constructor can do set-up work for all test here.
+UniqueGCFactoryBaseTest::UniqueGCFactoryBaseTest()
+{
+}
+
+// Destructor can do clean-up work that doesn't throw exceptions here.
+UniqueGCFactoryBaseTest::~UniqueGCFactoryBaseTest()
+{
+}
+
+// SetUp() will be called immediately before each test.
+void UniqueGCFactoryBaseTest::SetUp()
+{
+}
+
+// TearDown() will be called immediately after each test.
+void UniqueGCFactoryBaseTest::TearDown()
+{
+}
+
+//==========================================================================//
+// Testcases
+//
+TEST_F( UniqueGCFactoryBaseTest, number_constructor ) {
+ ContextFactory *contextFactory = new ContextFactory(10);
+ contextFactory->produce("/");
+ contextFactory->produce("ab/c");
+ ASSERT_EQ( 2, contextFactory->size());
+ delete contextFactory;
+}
+
+TEST_F( UniqueGCFactoryBaseTest, unique_produce ) {
+ ContextFactory *contextFactory = new ContextFactory(10);
+ LDContext* context1 = contextFactory->produce("/");
+ contextFactory->produce("ab/c");
+ ASSERT_EQ( 2, contextFactory->size());
+ LDContext* context2 = contextFactory->produce("/");
+ ASSERT_EQ( context1, context2 );
+ delete contextFactory;
+}
+
+TEST_F( UniqueGCFactoryBaseTest, unique_produce2 ) {
+ ContextFactory *contextFactory = new ContextFactory(10);
+ LDContext* context1 = contextFactory->produce("abc/def");
+ contextFactory->produce("ab/c");
+ ASSERT_EQ( 2, contextFactory->size());
+ LDContext* context2 = contextFactory->produce("ttt/../abc/def");
+ ASSERT_EQ( context1, context2 );
+ delete contextFactory;
+}
+
+TEST_F( UniqueGCFactoryBaseTest, iterator )
+{
+ MemoryAreaFactory* memFactory = new MemoryAreaFactory(10);
+ MemoryArea* area1 = memFactory->produce("/home/luba", O_RDONLY);
+ MemoryArea* area2 = memFactory->produce("/home/jush", O_RDONLY);
+ ASSERT_NE( area1, area2);
+ MemoryArea* area3 = memFactory->produce("/home/jush/../luba", O_RDONLY);
+ ASSERT_EQ( area1, area3);
+ ASSERT_FALSE( memFactory->empty());
+ ASSERT_EQ( 2, memFactory->size());
+ MemoryAreaFactory::iterator aIter = memFactory->begin();
+ ASSERT_EQ( area1, &(*aIter));
+ ++aIter;
+ ASSERT_EQ( area2, &(*aIter));
+ ++aIter;
+ MemoryAreaFactory::iterator aEnd = memFactory->end();
+ ASSERT_TRUE( aEnd == aIter);
+ delete memFactory;
+}
+
diff --git a/unittests/UniqueGCFactoryBaseTest.h b/unittests/UniqueGCFactoryBaseTest.h
new file mode 100644
index 0000000..a1558e7
--- /dev/null
+++ b/unittests/UniqueGCFactoryBaseTest.h
@@ -0,0 +1,42 @@
+//===- UniqueGCFactoryBaseTest.h ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UNIQUE_GCFACTORYBASE_TEST_H
+#define UNIQUE_GCFACTORYBASE_TEST_H
+
+#include "mcld/Support/UniqueGCFactory.h"
+#include <gtest.h>
+
+namespace mcldtest
+{
+
+/** \class UniqueGCFactoryBaseTest
+ * - check the unique of key.
+ * - make sure the key associates with the same storage of value.
+ * - check if all functions in the GCFactoryBase are available.
+ */
+class UniqueGCFactoryBaseTest : public ::testing::Test
+{
+public:
+ // Constructor can do set-up work for all test here.
+ UniqueGCFactoryBaseTest();
+
+ // Destructor can do clean-up work that doesn't throw exceptions here.
+ virtual ~UniqueGCFactoryBaseTest();
+
+ // SetUp() will be called immediately before each test.
+ virtual void SetUp();
+
+ // TearDown() will be called immediately after each test.
+ virtual void TearDown();
+};
+
+} // namespace of mcldtest
+
+#endif
+
diff --git a/unittests/test.txt b/unittests/test.txt
new file mode 100644
index 0000000..5b5a6a9
--- /dev/null
+++ b/unittests/test.txt
@@ -0,0 +1 @@
+This is a text for testing
diff --git a/unittests/test2.txt b/unittests/test2.txt
new file mode 100644
index 0000000..f1e9c6a
--- /dev/null
+++ b/unittests/test2.txt
Binary files differ
diff --git a/unittests/test3.txt b/unittests/test3.txt
new file mode 100644
index 0000000..2689bfd
--- /dev/null
+++ b/unittests/test3.txt
@@ -0,0 +1,296 @@
+HELLOopyright (C@@1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+# 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+# This Makefile contains release scripts for gdb, binutils, and other
+# packages which live in src. It used to be part of the top level Makefile,
+# but th@@ turned out to be very messy and hard to maintain.
+
+# This stuff really ought to be cleaned up and turned into something other
+# than a Makefile. As it is it's heavily recursive.
+
+# This is the name of this script (!). Needed due to horrible recursion.
+SELF = src-release
+
+SHELL = /bin/sh
+
+BZIPPROG = bzip2
+MD5PROG = md5sum
+
+# (Default to avoid splitting info files by setting the threshold high.)
+MAKEINFOFLAGS = --split-size=5000000
+
+# pwd command to use. Allow user to override default by setting PWDCMD in
+# the environment to account for automounters. The make variable must not
+# be called PWDCMD, otherwise the value set here is passed to make
+# subprocesses and overrides the setting from the user's environment.
+PWD = $${PWDCMD-pwd}
+
+#
+# Support for building net releases
+
+# Files in devo used in any net release.
+DEVO_SUPPORT= README Makefile.in configure configure.ac \
+ config.guess config.sub config move-if-change \
+ COPYING COPYING.LIB install-sh config-ml.in symlink-tree \
+ mkinstalldirs ltmain.sh missing ylwrap \
+ libtool.m4 ltsugar.m4 ltversion.m4 ltoptions.m4 \
+ Makefile.def Makefile.tpl src-release config.rpath \
+ ChangeLog MAINTAINERS README-maintainer-mode \
+ lt~obsolete.m4 ltgcc.m4 depcomp mkdep compile \
+ COPYING3 COPYING3.LIB
+
+# Files in devo/etc used in any net release.
+ETC_SUPPORT= Makefile.in configure configure.in standards.texi \
+ make-stds.texi standards.info* configure.texi configure.info* \
+ ChangeLog configbuild.* configdev.* fdl.texi texi2pod.pl gnu-oids.texi
+
+
+# When you use `make setup-dirs' or `make taz' you should always redefine
+# this macro.
+SUPPORT_FILES = list-of-support-files-for-tool-in-question
+
+# NOTE: No double quotes in the below. It is used within shell script
+# as VER="$(VER)"
+VER = ` if grep 'AM_INIT_AUTOMAKE.*BFD_VERSION' $(TOOL)/configure.in >/dev/null 2>&1; then \
+ sed < bfd/configure.in -n 's/AM_INIT_AUTOMAKE[^,]*, *\([^)]*\))/\1/p'; \
+ elif grep AM_INIT_AUTOMAKE $(TOOL)/configure.in >/dev/null 2>&1; then \
+ sed < $(TOOL)/configure.in -n 's/AM_INIT_AUTOMAKE[^,]*, *\([^)]*\))/\1/p'; \
+ elif test -f $(TOOL)/version.in; then \
+ head -1 $(TOOL)/version.in; \
+ elif grep VERSION $(TOOL)/Makefile.in > /dev/null 2>&1; then \
+ sed < $(TOOL)/Makefile.in -n 's/^VERSION *= *//p'; \
+ else \
+ echo VERSION; \
+ fi`
+PACKAGE = $(TOOL)
+
+.PHONY: taz
+taz: $(DEVO_SUPPORT) $(SUPPORT_FILES) texinfo/texinfo.tex
+ $(MAKE) -f $(SELF) do-proto-toplev \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-md5sum \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-tar \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-bz2 \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+
+.PHONY: gdb-tar
+gdb-tar: $(DEVO_SUPPORT)OH(SUPPORT_FILES) texinfo/texinfo.tex
+ $(MAKE) -f $(SELF) do-proto-toplev \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-md5sum \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-djunpack \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-tar \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+
+.PHONY: gdb-taz
+gdb-taz: gdb-tar $(DEVO_SUPPORT) $(SUPPORT_FILES) texinfo/texinfo.tex
+ $(MAKE) -f $(SELF) gdb-tar \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+ $(MAKE) -f $(SELF) do-bz2 \
+ TOOL=$(TOOL) PACKAGE="$(PACKAGE)" VER="$(VER)" \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(SUPPORT_FILES)"
+
+.PHONY: do-proto-toplev
+do-proto-toplev: $(DEVO_SUPPORT) $(SUPPORT_FILES) texinfo/texinfo.tex
+ echo "==> Making $(PACKAGE)-$(VER)/"
+ # Take out texinfo from a few places.
+ sed -e '/^all\.normal: /s/\all-texinfo //' \
+ -e '/^ install-texinfo /d' \
+ <Makefile.in >tmp
+ mv -f tmp Makefile.in
+ #
+ ./configure i686-pc-linux-gnu
+ $(MAKE) configure-host configure-target \
+ ALL_GCC="" ALL_GCC_C="" ALL_GCC_CXX="" \
+ CC_FOR_TARGET="$(CC)" CXX_FOR_TARGET="$(CXX)"
+ # Make links, and run "make diststuff" or "make info" when needed.
+ rm -rf proto-toplev ; mkdir proto-toplev
+ set -e ; dirs="$(DEVO_SUPPORT) $(SUPPORT_FILES) $(TOOL)" ; \
+ for d in $$dirs ; do \
+ if [ -d $$d ]; then \
+ if [ ! -f $$d/Makefile ] ; then true ; \
+ elif grep '^diststuff:' $$d/Makefile >/dev/null ; then \
+ (cd $$d ; $(MAKE) MAKEINFOFLAGS="$(MAKEINFOFLAGS)" \
+ diststuff ) || exit 1 ; \
+ elif grep '^info:' $$d/Makefile >/dev/null ; then \
+ (cd $$d ; $(MAKE) MAKEINFOFLAGS="$(MAKEINFOFLAGS)" \
+ info ) || exit 1 ; \
+ fi ; \
+ if [ -d $$d/proto-$$d.dir ]; then \
+ ln -s ../$$d/proto-$$d.dir proto-toplev/$$d ; \
+ else \
+ ln -s ../$$d proto-toplev/$$d ; \
+ fi ; \
+ else ln -s ../$$d proto-toplev/$$d ; fi ; \
+ done
+ cd etc && $(MAKE) MAKEINFOFLAGS="$(MAKEINFOFLAGS)" info
+ $(MAKE) distclean
+ # Kludge for pr gdb/857. intl/Makefile.in lacks a couple
+ # of files in the distclean rule. Zack W is planning to make
+ # the gcc version of intl/ the master version and then push
+ # that version to src soon. See:
+ # http://sources.redhat.com/ml/binutils/2003-07/msg00032.html
+ # After the src version of intl/ is upgraded, we can look at
+ # moving this logic into intl/Makefile.in distclean rule
+ # if it is still needed. -- chastain 2003-09-12
+ rm -f intl/config.cache
+ rm -f intl/config.status
+ rm -f intl/config.h
+ rm -f intl/stamp-h
+ #
+ mkdir proto-toplev/etc
+ (cd proto-toplev/etc; \
+ for i in $(ETC_SUPPORT); do \
+ ln -s ../../etc/$$i . ; \
+ done)
+ #
+ # Take out texinfo from configurable dirs
+ rm proto-toplev/configure.ac
+ sed -e '/^host_tools=/s/texinfo //' \
+ <configure.ac >proto-toplev/configure.ac
+ #
+ mkdir proto-toplev/texinfo
+ ln -s ../../texinfo/texinfo.tex proto-toplev/texinfo/
+ if test -r texinfo/util/tex3patch ; then \
+ mkdir proto-toplev/texinfo/util && \
+ ln -s ../../../texinfo/util/tex3patch proto-toplev/texinfo/util ; \
+ else true; fi
+ chmod -R og=u . || chmod og=u `find . -print`
+ #
+ # Create .gmo files from .po files.
+ for f in `find . -name '*.po' -type f -print`; do \
+ msgfmt -o `echo $$f | sed -e 's/\.po$$/.gmo/'` $$f ; \
+ done
+ #
+ -rm -f $(PACKAGE)-$(VER)
+ ln -s proto-toplev $(PACKAGE)-$(VER)
+
+CVS_NAMES= \( -name CVS -o -name '.cvsignore' \)
+
+.PHONY: do-tar
+do-tar:
+ echo "==> Making $(PACKAGE)-$(VER).tar"
+ -rm -f $(PACKAGE)-$(VER).tar
+ find $(PACKAGE)-$(VER) -follow $(CVS_NAMES) -prune \
+ -o -type f -print \
+ | tar cTfh - $(PACKAGE)-$(VER).tar
+
+.PHONY: do-bz2
+do-bz2:
+ echo "==> Bzipping $(PACKAGE)-$(VER).tar.bz2"
+ -rm -f $(PACKAGE)-$(VER).tar.bz2
+ $(BZIPPROG) -v -9 $(PACKAGE)-$(VER).tar
+
+.PHONY: do-md5sum
+do-md5sum:
+ echo "==> Adding md5 checksum to top-level directory"
+ cd proto-toplev && find * -follow $(CVS_NAMES) -prune \
+ -o -type f -print \
+ | xargs $(MD5PROG) > ../md5.new
+ -rm -f proto-toplev/md5.sum
+ mv md5.new proto-toplev/md5.sum
+
+.PHONY: do-djunpack
+do-djunpack:
+ echo "==> Adding updated djunpack.bat to top-level directory"
+ echo - 's /gdb-[0-9\.]*/$(PACKAGE)-'"$(VER)"'/'
+ sed < djunpack.bat > djunpack.new \
+ -e 's/gdb-[0-9][0-9\.]*/$(PACKAGE)-'"$(VER)"'/'
+ -rm -f proto-toplev/djunpack.bat
+ mv djunpack.new proto-toplev/djunpack.bat
+
+TEXINFO_SUPPORT= texinfo/texinfo.tex
+DIST_SUPPORT= $(DEVO_SUPPORT) $(TEXINFO_SUPPORT)
+
+.PHONY: gas.tar.bz2
+GAS_SUPPORT_DIRS= bfd include libiberty opcodes intl setup.com makefile.vms mkdep
+gas.tar.bz2: $(DIST_SUPPORT) $(GAS_SUPPORT_DIRS) gas
+ $(MAKE) -f $(SELF) taz TOOL=gas \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GAS_SUPPORT_DIRS)"
+
+# The FSF "binutils" release includes gprof and ld.
+.PHONY: binutils.tar.bz2
+BINUTILS_SUPPORT_DIRS= bfd gas include libiberty opcodes ld elfcpp gold gprof intl setup.com makefile.vms cpu
+binutils.tar.bz2: $(DIST_SUPPORT) $(BINUTILS_SUPPORT_DIRS) binutils
+ $(MAKE) -f $(SELF) taz TOOL=binutils \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(BINUTILS_SUPPORT_DIRS)"
+
+.PHONY: gas+binutils.tar.bz2
+GASB_SUPPORT_DIRS= $(GAS_SUPPORT_DIRS) binutils ld gprof
+gas+binutils.tar.bz2: $(DIST_SUPPORT) $(GASB_SUPPORT_DIRS) gas
+ $(MAKE) -f $(SELF) taz TOOL=gas \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GASB_SUPPORT_DIRS)"
+
+GNATS_SUPPORT_DIRS=include libiberty send-pr
+gnats.tar.bz2: $(DIST_SUPPORT) $(GNATS_SUPPORT_DIRS) gnats
+ $(MAKE) -f $(SELF) taz TOOL=gnats \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GNATS_SUPPORT_DIRS)"
+
+.PHONY: gdb.tar.bz2
+GDB_SUPPORT_DIRS= bfd include libiberty opcodes readline sim intl libdecnumber
+gdb.tar.bz2: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-taz TOOL=gdb \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GDB_SUPPORT_DIRS)"
+.PHONY: gdb.tar
+gdb.tar: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-tar TOOL=gdb \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(GDB_SUPPORT_DIRS)"
+
+.PHONY: insight.tar.bz2
+INSIGHT_SUPPORT_DIRS= $(GDB_SUPPORT_DIRS) tcl tk itcl libgui
+insight.tar.bz2: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-taz TOOL=gdb PACKAGE=insight \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(INSIGHT_SUPPORT_DIRS)"
+.PHONY: insight.tar
+insight.tar: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb
+ $(MAKE) -f $(SELF) gdb-tar TOOL=gdb PACKAGE=insight \
+ MD5PROG="$(MD5PROG)" \
+ SUPPORT_FILES="$(INSIGHT_SUPPORT_DIRS)"
+
+.NOEXPORT:
+MAKEOVERRIDES=
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644
index 0000000..b866042
--- /dev/null
+++ b/utils/Makefile.am
@@ -0,0 +1,3 @@
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = gtest
diff --git a/utils/README.MCLinker b/utils/README.MCLinker
new file mode 100644
index 0000000..6dc3185
--- /dev/null
+++ b/utils/README.MCLinker
@@ -0,0 +1,15 @@
+//=== ------------------------------------------------------------------ ===//
+// MCLinker Project //
+//=== ------------------------------------------------------------------ ===//
+
+ gtest/ contains Google Test 1.6.0. MCLinker removes the original building
+system and integrates gtest in MCLinker's building system.
+
+===========
+Enhancement
+===========
+=======
+Details
+=======
+ see [ticket:37]
+
diff --git a/utils/gtest/CONTRIBUTORS b/utils/gtest/CONTRIBUTORS
new file mode 100644
index 0000000..feae2fc
--- /dev/null
+++ b/utils/gtest/CONTRIBUTORS
@@ -0,0 +1,37 @@
+# This file contains a list of people who've made non-trivial
+# contribution to the Google C++ Testing Framework project. People
+# who commit code to the project are encouraged to add their names
+# here. Please keep the list sorted by first names.
+
+Ajay Joshi <jaj@google.com>
+Balázs Dán <balazs.dan@gmail.com>
+Bharat Mediratta <bharat@menalto.com>
+Chandler Carruth <chandlerc@google.com>
+Chris Prince <cprince@google.com>
+Chris Taylor <taylorc@google.com>
+Dan Egnor <egnor@google.com>
+Eric Roman <eroman@chromium.org>
+Hady Zalek <hady.zalek@gmail.com>
+Jeffrey Yasskin <jyasskin@google.com>
+Jói Sigurðsson <joi@google.com>
+Keir Mierle <mierle@gmail.com>
+Keith Ray <keith.ray@gmail.com>
+Kenton Varda <kenton@google.com>
+Manuel Klimek <klimek@google.com>
+Markus Heule <markus.heule@gmail.com>
+Mika Raento <mikie@iki.fi>
+Miklós Fazekas <mfazekas@szemafor.com>
+Pasi Valminen <pasi.valminen@gmail.com>
+Patrick Hanna <phanna@google.com>
+Patrick Riley <pfr@google.com>
+Peter Kaminski <piotrk@google.com>
+Preston Jackson <preston.a.jackson@gmail.com>
+Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
+Russ Cox <rsc@google.com>
+Russ Rufer <russ@pentad.com>
+Sean Mcafee <eefacm@gmail.com>
+Sigurður Ásgeirsson <siggi@google.com>
+Tracy Bialik <tracy@pentad.com>
+Vadim Berman <vadimb@google.com>
+Vlad Losev <vladl@google.com>
+Zhanyong Wan <wan@google.com>
diff --git a/utils/gtest/COPYING b/utils/gtest/COPYING
new file mode 100644
index 0000000..1941a11
--- /dev/null
+++ b/utils/gtest/COPYING
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/utils/gtest/Makefile.am b/utils/gtest/Makefile.am
new file mode 100644
index 0000000..7c7cdc7
--- /dev/null
+++ b/utils/gtest/Makefile.am
@@ -0,0 +1,3 @@
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = obj
diff --git a/utils/gtest/README b/utils/gtest/README
new file mode 100644
index 0000000..51a9376
--- /dev/null
+++ b/utils/gtest/README
@@ -0,0 +1,424 @@
+Google C++ Testing Framework
+============================
+
+http://code.google.com/p/googletest/
+
+Overview
+--------
+
+Google's framework for writing C++ tests on a variety of platforms
+(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the
+xUnit architecture. Supports automatic test discovery, a rich set of
+assertions, user-defined assertions, death tests, fatal and non-fatal
+failures, various options for running the tests, and XML test report
+generation.
+
+Please see the project page above for more information as well as the
+mailing list for questions, discussions, and development. There is
+also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
+join us!
+
+Requirements for End Users
+--------------------------
+
+Google Test is designed to have fairly minimal requirements to build
+and use with your projects, but there are some. Currently, we support
+Linux, Windows, Mac OS X, and Cygwin. We will also make our best
+effort to support other platforms (e.g. Solaris, AIX, and z/OS).
+However, since core members of the Google Test project have no access
+to these platforms, Google Test may have outstanding issues there. If
+you notice any problems on your platform, please notify
+googletestframework@googlegroups.com. Patches for fixing them are
+even more welcome!
+
+### Linux Requirements ###
+
+These are the base requirements to build and use Google Test from a source
+package (as described below):
+ * GNU-compatible Make or gmake
+ * POSIX-standard shell
+ * POSIX(-2) Regular Expressions (regex.h)
+ * A C++98-standard-compliant compiler
+
+### Windows Requirements ###
+
+ * Microsoft Visual C++ 7.1 or newer
+
+### Cygwin Requirements ###
+
+ * Cygwin 1.5.25-14 or newer
+
+### Mac OS X Requirements ###
+
+ * Mac OS X 10.4 Tiger or newer
+ * Developer Tools Installed
+
+Also, you'll need CMake 2.6.4 or higher if you want to build the
+samples using the provided CMake script, regardless of the platform.
+
+Requirements for Contributors
+-----------------------------
+
+We welcome patches. If you plan to contribute a patch, you need to
+build Google Test and its own tests from an SVN checkout (described
+below), which has further requirements:
+
+ * Python version 2.3 or newer (for running some of the tests and
+ re-generating certain source files from templates)
+ * CMake 2.6.4 or newer
+
+Getting the Source
+------------------
+
+There are two primary ways of getting Google Test's source code: you
+can download a stable source release in your preferred archive format,
+or directly check out the source from our Subversion (SVN) repositary.
+The SVN checkout requires a few extra steps and some extra software
+packages on your system, but lets you track the latest development and
+make patches much more easily, so we highly encourage it.
+
+### Source Package ###
+
+Google Test is released in versioned source packages which can be
+downloaded from the download page [1]. Several different archive
+formats are provided, but the only difference is the tools used to
+manipulate them, and the size of the resulting file. Download
+whichever you are most comfortable with.
+
+ [1] http://code.google.com/p/googletest/downloads/list
+
+Once the package is downloaded, expand it using whichever tools you
+prefer for that type. This will result in a new directory with the
+name "gtest-X.Y.Z" which contains all of the source code. Here are
+some examples on Linux:
+
+ tar -xvzf gtest-X.Y.Z.tar.gz
+ tar -xvjf gtest-X.Y.Z.tar.bz2
+ unzip gtest-X.Y.Z.zip
+
+### SVN Checkout ###
+
+To check out the main branch (also known as the "trunk") of Google
+Test, run the following Subversion command:
+
+ svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
+
+Setting up the Build
+--------------------
+
+To build Google Test and your tests that use it, you need to tell your
+build system where to find its headers and source files. The exact
+way to do it depends on which build system you use, and is usually
+straightforward.
+
+### Generic Build Instructions ###
+
+Suppose you put Google Test in directory ${GTEST_DIR}. To build it,
+create a library build target (or a project as called by Visual Studio
+and Xcode) to compile
+
+ ${GTEST_DIR}/src/gtest-all.cc
+
+with
+
+ ${GTEST_DIR}/include and ${GTEST_DIR}
+
+in the header search path. Assuming a Linux-like system and gcc,
+something like the following will do:
+
+ g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
+ ar -rv libgtest.a gtest-all.o
+
+Next, you should compile your test source file with
+${GTEST_DIR}/include in the header search path, and link it with gtest
+and any other necessary libraries:
+
+ g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test
+
+As an example, the make/ directory contains a Makefile that you can
+use to build Google Test on systems where GNU make is available
+(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
+Test's own tests. Instead, it just builds the Google Test library and
+a sample test. You can use it as a starting point for your own build
+script.
+
+If the default settings are correct for your environment, the
+following commands should succeed:
+
+ cd ${GTEST_DIR}/make
+ make
+ ./sample1_unittest
+
+If you see errors, try to tweak the contents of make/Makefile to make
+them go away. There are instructions in make/Makefile on how to do
+it.
+
+### Using CMake ###
+
+Google Test comes with a CMake build script (CMakeLists.txt) that can
+be used on a wide range of platforms ("C" stands for cross-platofrm.).
+If you don't have CMake installed already, you can download it for
+free from http://www.cmake.org/.
+
+CMake works by generating native makefiles or build projects that can
+be used in the compiler environment of your choice. The typical
+workflow starts with:
+
+ mkdir mybuild # Create a directory to hold the build output.
+ cd mybuild
+ cmake ${GTEST_DIR} # Generate native build scripts.
+
+If you want to build Google Test's samples, you should replace the
+last command with
+
+ cmake -Dgtest_build_samples=ON ${GTEST_DIR}
+
+If you are on a *nix system, you should now see a Makefile in the
+current directory. Just type 'make' to build gtest.
+
+If you use Windows and have Vistual Studio installed, a gtest.sln file
+and several .vcproj files will be created. You can then build them
+using Visual Studio.
+
+On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
+
+### Legacy Build Scripts ###
+
+Before settling on CMake, we have been providing hand-maintained build
+projects/scripts for Visual Studio, Xcode, and Autotools. While we
+continue to provide them for convenience, they are not actively
+maintained any more. We highly recommend that you follow the
+instructions in the previous two sections to integrate Google Test
+with your existing build system.
+
+If you still need to use the legacy build scripts, here's how:
+
+The msvc\ folder contains two solutions with Visual C++ projects.
+Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
+are ready to build Google Test the same way you build any Visual
+Studio project. Files that have names ending with -md use DLL
+versions of Microsoft runtime libraries (the /MD or the /MDd compiler
+option). Files without that suffix use static versions of the runtime
+libraries (the /MT or the /MTd option). Please note that one must use
+the same option to compile both gtest and the test code. If you use
+Visual Studio 2005 or above, we recommend the -md version as /MD is
+the default for new projects in these versions of Visual Studio.
+
+On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
+Xcode. Build the "gtest" target. The universal binary framework will
+end up in your selected build directory (selected in the Xcode
+"Preferences..." -> "Building" pane and defaults to xcode/build).
+Alternatively, at the command line, enter:
+
+ xcodebuild
+
+This will build the "Release" configuration of gtest.framework in your
+default build location. See the "xcodebuild" man page for more
+information about building different configurations and building in
+different locations.
+
+Tweaking Google Test
+--------------------
+
+Google Test can be used in diverse environments. The default
+configuration may not work (or may not work well) out of the box in
+some environments. However, you can easily tweak Google Test by
+defining control macros on the compiler command line. Generally,
+these macros are named like GTEST_XYZ and you define them to either 1
+or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below. For a complete list,
+see file include/gtest/internal/gtest-port.h.
+
+### Choosing a TR1 Tuple Library ###
+
+Some Google Test features require the C++ Technical Report 1 (TR1)
+tuple library, which is not yet available with all compilers. The
+good news is that Google Test implements a subset of TR1 tuple that's
+enough for its own need, and will automatically use this when the
+compiler doesn't provide TR1 tuple.
+
+Usually you don't need to care about which tuple library Google Test
+uses. However, if your project already uses TR1 tuple, you need to
+tell Google Test to use the same TR1 tuple library the rest of your
+project uses, or the two tuple implementations will clash. To do
+that, add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=0
+
+to the compiler flags while compiling Google Test and your tests. If
+you want to force Google Test to use its own tuple library, just add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=1
+
+to the compiler flags instead.
+
+If you don't want Google Test to use tuple at all, add
+
+ -DGTEST_HAS_TR1_TUPLE=0
+
+and all features using tuple will be disabled.
+
+### Multi-threaded Tests ###
+
+Google Test is thread-safe where the pthread library is available.
+After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE
+macro to see whether this is the case (yes if the macro is #defined to
+1, no if it's undefined.).
+
+If Google Test doesn't correctly detect whether pthread is available
+in your environment, you can force it with
+
+ -DGTEST_HAS_PTHREAD=1
+
+or
+
+ -DGTEST_HAS_PTHREAD=0
+
+When Google Test uses pthread, you may need to add flags to your
+compiler and/or linker to select the pthread library, or you'll get
+link errors. If you use the CMake script or the deprecated Autotools
+script, this is taken care of for you. If you use your own build
+script, you'll need to read your compiler and linker's manual to
+figure out what flags to add.
+
+### As a Shared Library (DLL) ###
+
+Google Test is compact, so most users can build and link it as a
+static library for the simplicity. You can choose to use Google Test
+as a shared library (known as a DLL on Windows) if you prefer.
+
+To compile *gtest* as a shared library, add
+
+ -DGTEST_CREATE_SHARED_LIBRARY=1
+
+to the compiler flags. You'll also need to tell the linker to produce
+a shared library instead - consult your linker's manual for how to do
+it.
+
+To compile your *tests* that use the gtest shared library, add
+
+ -DGTEST_LINKED_AS_SHARED_LIBRARY=1
+
+to the compiler flags.
+
+Note: while the above steps aren't technically necessary today when
+using some compilers (e.g. GCC), they may become necessary in the
+future, if we decide to improve the speed of loading the library (see
+http://gcc.gnu.org/wiki/Visibility for details). Therefore you are
+recommended to always add the above flags when using Google Test as a
+shared library. Otherwise a future release of Google Test may break
+your build script.
+
+### Avoiding Macro Name Clashes ###
+
+In C++, macros don't obey namespaces. Therefore two libraries that
+both define a macro of the same name will clash if you #include both
+definitions. In case a Google Test macro clashes with another
+library, you can force Google Test to rename its macro to avoid the
+conflict.
+
+Specifically, if both Google Test and some other code define macro
+FOO, you can add
+
+ -DGTEST_DONT_DEFINE_FOO=1
+
+to the compiler flags to tell Google Test to change the macro's name
+from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST.
+For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
+
+ GTEST_TEST(SomeTest, DoesThis) { ... }
+
+instead of
+
+ TEST(SomeTest, DoesThis) { ... }
+
+in order to define a test.
+
+Upgrating from an Earlier Version
+---------------------------------
+
+We strive to keep Google Test releases backward compatible.
+Sometimes, though, we have to make some breaking changes for the
+users' long-term benefits. This section describes what you'll need to
+do if you are upgrading from an earlier version of Google Test.
+
+### Upgrading from 1.3.0 or Earlier ###
+
+You may need to explicitly enable or disable Google Test's own TR1
+tuple library. See the instructions in section "Choosing a TR1 Tuple
+Library".
+
+### Upgrading from 1.4.0 or Earlier ###
+
+The Autotools build script (configure + make) is no longer officially
+supportted. You are encouraged to migrate to your own build system or
+use CMake. If you still need to use Autotools, you can find
+instructions in the README file from Google Test 1.4.0.
+
+On platforms where the pthread library is available, Google Test uses
+it in order to be thread-safe. See the "Multi-threaded Tests" section
+for what this means to your build script.
+
+If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
+Test will no longer compile. This should affect very few people, as a
+large portion of STL (including <string>) doesn't compile in this mode
+anyway. We decided to stop supporting it in order to greatly simplify
+Google Test's implementation.
+
+Developing Google Test
+----------------------
+
+This section discusses how to make your own changes to Google Test.
+
+### Testing Google Test Itself ###
+
+To make sure your changes work as intended and don't break existing
+functionality, you'll want to compile and run Google Test's own tests.
+For that you can use CMake:
+
+ mkdir mybuild
+ cd mybuild
+ cmake -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Make sure you have Python installed, as some of Google Test's tests
+are written in Python. If the cmake command complains about not being
+able to find Python ("Could NOT find PythonInterp (missing:
+PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
+executable can be found:
+
+ cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Next, you can build Google Test and all of its own tests. On *nix,
+this is usually done by 'make'. To run the tests, do
+
+ make test
+
+All tests should pass.
+
+### Regenerating Source Files ###
+
+Some of Google Test's source files are generated from templates (not
+in the C++ sense) using a script. A template file is named FOO.pump,
+where FOO is the name of the file it will generate. For example, the
+file include/gtest/internal/gtest-type-util.h.pump is used to generate
+gtest-type-util.h in the same directory.
+
+Normally you don't need to worry about regenerating the source files,
+unless you need to modify them. In that case, you should modify the
+corresponding .pump files instead and run the pump.py Python script to
+regenerate them. You can find pump.py in the scripts/ directory.
+Read the Pump manual [2] for how to use it.
+
+ [2] http://code.google.com/p/googletest/wiki/PumpManual
+
+### Contributing a Patch ###
+
+We welcome patches. Please read the Google Test developer's guide [3]
+for how you can contribute. In particular, make sure you have signed
+the Contributor License Agreement, or we won't be able to accept the
+patch.
+
+ [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
+
+Happy testing!
diff --git a/utils/gtest/include/gtest.h b/utils/gtest/include/gtest.h
new file mode 100644
index 0000000..3143bd6
--- /dev/null
+++ b/utils/gtest/include/gtest.h
@@ -0,0 +1,19537 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test. It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+#include <limits>
+#include <vector>
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms. They are subject to change without notice. DO NOT USE
+// THEM IN USER CODE.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior. If the user doesn't define a macro
+// in this list, Google Test will define it.
+//
+// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2)
+// is/isn't available.
+// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions
+// are enabled.
+// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::string, which is different to std::string).
+// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::wstring, which is different to std::wstring).
+// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular
+// expressions are/aren't available.
+// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h>
+// is/isn't available.
+// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
+// enabled.
+// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
+// std::wstring does/doesn't work (Google Test can
+// be used where std::wstring is unavailable).
+// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple
+// is/isn't available.
+// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the
+// compiler supports Microsoft's "Structured
+// Exception Handling".
+// GTEST_HAS_STREAM_REDIRECTION
+// - Define it to 1/0 to indicate whether the
+// platform supports I/O stream redirection using
+// dup() and dup2().
+// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google
+// Test's own tr1 tuple implementation should be
+// used. Unused when the user sets
+// GTEST_HAS_TR1_TUPLE to 0.
+// GTEST_LINKED_AS_SHARED_LIBRARY
+// - Define to 1 when compiling tests that use
+// Google Test as a shared library (known as
+// DLL on Windows).
+// GTEST_CREATE_SHARED_LIBRARY
+// - Define to 1 when compiling Google Test itself
+// as a shared library.
+
+// This header defines the following utilities:
+//
+// Macros indicating the current platform (defined to 1 if compiled on
+// the given platform; otherwise undefined):
+// GTEST_OS_AIX - IBM AIX
+// GTEST_OS_CYGWIN - Cygwin
+// GTEST_OS_HPUX - HP-UX
+// GTEST_OS_LINUX - Linux
+// GTEST_OS_LINUX_ANDROID - Google Android
+// GTEST_OS_MAC - Mac OS X
+// GTEST_OS_NACL - Google Native Client (NaCl)
+// GTEST_OS_SOLARIS - Sun Solaris
+// GTEST_OS_SYMBIAN - Symbian
+// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
+// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop
+// GTEST_OS_WINDOWS_MINGW - MinGW
+// GTEST_OS_WINDOWS_MOBILE - Windows Mobile
+// GTEST_OS_ZOS - z/OS
+//
+// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// most stable support. Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable. If you notice any problems on your platform, please notify
+// googletestframework@googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// Note that it is possible that none of the GTEST_OS_* macros are defined.
+//
+// Macros indicating available Google Test features (defined to 1 if
+// the corresponding feature is supported; otherwise undefined):
+// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized
+// tests)
+// GTEST_HAS_DEATH_TEST - death tests
+// GTEST_HAS_PARAM_TEST - value-parameterized tests
+// GTEST_HAS_TYPED_TEST - typed tests
+// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with
+// GTEST_HAS_POSIX_RE (see above) which users can
+// define themselves.
+// GTEST_USES_SIMPLE_RE - our own simple regex is used;
+// the above two are mutually exclusive.
+// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+//
+// Macros for basic C++ coding:
+// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a
+// variable don't have to be used.
+// GTEST_DISALLOW_ASSIGN_ - disables operator=.
+// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used.
+//
+// Synchronization:
+// Mutex, MutexLock, ThreadLocal, GetThreadCount()
+// - synchronization primitives.
+// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
+// synchronization primitives have real implementations
+// and Google Test is thread-safe; or 0 otherwise.
+//
+// Template meta programming:
+// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only.
+// IteratorTraits - partial implementation of std::iterator_traits, which
+// is not available in libCstd when compiled with Sun C++.
+//
+// Smart pointers:
+// scoped_ptr - as in TR2.
+//
+// Regular expressions:
+// RE - a simple regular expression class using the POSIX
+// Extended Regular Expression syntax on UNIX-like
+// platforms, or a reduced regular exception syntax on
+// other platforms, including Windows.
+//
+// Logging:
+// GTEST_LOG_() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+//
+// Stdout and stderr capturing:
+// CaptureStdout() - starts capturing stdout.
+// GetCapturedStdout() - stops capturing stdout and returns the captured
+// string.
+// CaptureStderr() - starts capturing stderr.
+// GetCapturedStderr() - stops capturing stderr and returns the captured
+// string.
+//
+// Integer types:
+// TypeWithSize - maps an integer to a int type.
+// Int32, UInt32, Int64, UInt64, TimeInMillis
+// - integers of known sizes.
+// BiggestInt - the biggest signed integer type.
+//
+// Command-line utilities:
+// GTEST_FLAG() - references a flag.
+// GTEST_DECLARE_*() - declares a flag.
+// GTEST_DEFINE_*() - defines a flag.
+// GetArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+// GetEnv() - gets the value of an environment variable.
+// BoolFromGTestEnv() - parses a bool environment variable.
+// Int32FromGTestEnv() - parses an Int32 environment variable.
+// StringFromGTestEnv() - parses a string environment variable.
+
+#include <ctype.h> // for isspace, etc
+#include <stddef.h> // for ptrdiff_t
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif // !_WIN32_WCE
+
+#include <iostream> // NOLINT
+#include <sstream> // NOLINT
+#include <string> // NOLINT
+
+#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+#define GTEST_FLAG_PREFIX_ "gtest_"
+#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+#define GTEST_NAME_ "Google Test"
+#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+# define GTEST_GCC_VER_ \
+ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif // __GNUC__
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+# define GTEST_OS_CYGWIN 1
+#elif defined __SYMBIAN32__
+# define GTEST_OS_SYMBIAN 1
+#elif defined _WIN32
+# define GTEST_OS_WINDOWS 1
+# ifdef _WIN32_WCE
+# define GTEST_OS_WINDOWS_MOBILE 1
+# elif defined(__MINGW__) || defined(__MINGW32__)
+# define GTEST_OS_WINDOWS_MINGW 1
+# else
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# endif // _WIN32_WCE
+#elif defined __APPLE__
+# define GTEST_OS_MAC 1
+#elif defined __linux__
+# define GTEST_OS_LINUX 1
+# ifdef ANDROID
+# define GTEST_OS_LINUX_ANDROID 1
+# endif // ANDROID
+#elif defined __MVS__
+# define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+# define GTEST_OS_SOLARIS 1
+#elif defined(_AIX)
+# define GTEST_OS_AIX 1
+#elif defined(__hpux)
+# define GTEST_OS_HPUX 1
+#elif defined __native_client__
+# define GTEST_OS_NACL 1
+#endif // __CYGWIN__
+
+// Brings in definitions for functions used in the testing::internal::posix
+// namespace (read, write, close, chdir, isatty, stat). We do not currently
+// use them on Windows Mobile.
+#if !GTEST_OS_WINDOWS
+// This assumes that non-Windows OSes provide unistd.h. For OSes where this
+// is not the case, we need to include headers that provide the functions
+// mentioned above.
+# include <unistd.h>
+# if !GTEST_OS_NACL
+// TODO(vladl@google.com): Remove this condition when Native Client SDK adds
+// strings.h (tracked in
+// http://code.google.com/p/nativeclient/issues/detail?id=1175).
+# include <strings.h> // Native Client doesn't provide strings.h.
+# endif
+#elif !GTEST_OS_WINDOWS_MOBILE
+# include <direct.h>
+# include <io.h>
+#endif
+
+// Defines this to true iff Google Test can use POSIX regular expressions.
+#ifndef GTEST_HAS_POSIX_RE
+# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
+#endif
+
+#if GTEST_HAS_POSIX_RE
+
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise. We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+# include <regex.h> // NOLINT
+
+# define GTEST_USES_POSIX_RE 1
+
+#elif GTEST_OS_WINDOWS
+
+// <regex.h> is not available on Windows. Use our own simple regex
+// implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#else
+
+// <regex.h> may not be available on this platform. Use our own
+// simple regex implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#endif // GTEST_HAS_POSIX_RE
+
+#ifndef GTEST_HAS_EXCEPTIONS
+// The user didn't tell us whether exceptions are enabled, so we need
+// to figure it out.
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
+// macro to enable exceptions, so we'll do the same.
+// Assumes that exceptions are enabled by default.
+# ifndef _HAS_EXCEPTIONS
+# define _HAS_EXCEPTIONS 1
+# endif // _HAS_EXCEPTIONS
+# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+# elif defined(__GNUC__) && __EXCEPTIONS
+// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__SUNPRO_CC)
+// Sun Pro CC supports exceptions. However, there is no compile-time way of
+// detecting whether they are enabled or not. Therefore, we assume that
+// they are enabled unless the user tells us otherwise.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__IBMCPP__) && __EXCEPTIONS
+// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__HP_aCC)
+// Exception handling is in effect by default in HP aCC compiler. It has to
+// be turned of by +noeh compiler option if desired.
+# define GTEST_HAS_EXCEPTIONS 1
+# else
+// For other compilers, we assume exceptions are disabled to be
+// conservative.
+# define GTEST_HAS_EXCEPTIONS 0
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+#endif // GTEST_HAS_EXCEPTIONS
+
+#if !defined(GTEST_HAS_STD_STRING)
+// Even though we don't use this macro any longer, we keep it in case
+// some clients still depend on it.
+# define GTEST_HAS_STD_STRING 1
+#elif !GTEST_HAS_STD_STRING
+// The user told us that ::std::string isn't available.
+# error "Google Test cannot be used where ::std::string isn't available."
+#endif // !defined(GTEST_HAS_STD_STRING)
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+# define GTEST_HAS_GLOBAL_STRING 0
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
+// is available.
+
+// Cygwin 1.7 and below doesn't support ::std::wstring.
+// Solaris' libc++ doesn't support it either. Android has
+// no support for it at least as recent as Froyo (2.2).
+# define GTEST_HAS_STD_WSTRING \
+ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
+
+#endif // GTEST_HAS_STD_WSTRING
+
+#ifndef GTEST_HAS_GLOBAL_WSTRING
+// The user didn't tell us whether ::wstring is available, so we need
+// to figure it out.
+# define GTEST_HAS_GLOBAL_WSTRING \
+ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+# ifdef _MSC_VER
+
+# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled.
+# define GTEST_HAS_RTTI 1
+# else
+# define GTEST_HAS_RTTI 0
+# endif
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
+
+# ifdef __GXX_RTTI
+# define GTEST_HAS_RTTI 1
+# else
+# define GTEST_HAS_RTTI 0
+# endif // __GXX_RTTI
+
+// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
+// both the typeid and dynamic_cast features are present.
+# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
+
+# ifdef __RTTI_ALL__
+# define GTEST_HAS_RTTI 1
+# else
+# define GTEST_HAS_RTTI 0
+# endif
+
+# else
+
+// For all other compilers, we assume RTTI is enabled.
+# define GTEST_HAS_RTTI 1
+
+# endif // _MSC_VER
+
+#endif // GTEST_HAS_RTTI
+
+// It's this header's responsibility to #include <typeinfo> when RTTI
+// is enabled.
+#if GTEST_HAS_RTTI
+# include <typeinfo>
+#endif
+
+// Determines whether Google Test can use the pthreads library.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us explicitly, so we assume pthreads support is
+// available on Linux and Mac.
+//
+// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
+// to your compiler flags.
+# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX)
+#endif // GTEST_HAS_PTHREAD
+
+#if GTEST_HAS_PTHREAD
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+# include <pthread.h> // NOLINT
+
+// For timespec and nanosleep, used below.
+# include <time.h> // NOLINT
+#endif
+
+// Determines whether Google Test can use tr1/tuple. You can define
+// this macro to 0 to prevent Google Test from using tuple (any
+// feature depending on tuple with be disabled in this mode).
+#ifndef GTEST_HAS_TR1_TUPLE
+// The user didn't tell us not to do it, so we assume it's OK.
+# define GTEST_HAS_TR1_TUPLE 1
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Determines whether Google Test's own tr1 tuple implementation
+// should be used.
+#ifndef GTEST_USE_OWN_TR1_TUPLE
+// The user didn't tell us, so we need to figure it out.
+
+// We use our own TR1 tuple if we aren't sure the user has an
+// implementation of it already. At this time, GCC 4.0.0+ and MSVC
+// 2010 are the only mainstream compilers that come with a TR1 tuple
+// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by
+// defining __GNUC__ and friends, but cannot compile GCC's tuple
+// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB
+// Feature Pack download, which we cannot assume the user has.
+# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \
+ || _MSC_VER >= 1600
+# define GTEST_USE_OWN_TR1_TUPLE 0
+# else
+# define GTEST_USE_OWN_TR1_TUPLE 1
+# endif
+
+#endif // GTEST_USE_OWN_TR1_TUPLE
+
+// To avoid conditional compilation everywhere, we make it
+// gtest-port.h's responsibility to #include the header implementing
+// tr1/tuple.
+#if GTEST_HAS_TR1_TUPLE
+
+# if GTEST_USE_OWN_TR1_TUPLE
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility> // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined). This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+ template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
+ private:
+#endif
+
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
+ void, void, void>
+#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
+ void, void, void>
+#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
+ void, void, void>
+#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
+ void, void, void>
+#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
+ void, void, void>
+#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
+ void, void, void>
+#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ void, void, void>
+#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, void, void>
+#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, T##8, void>
+#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, T##8, T##9>
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+#define GTEST_0_TYPENAMES_(T)
+#define GTEST_1_TYPENAMES_(T) typename T##0
+#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
+#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
+#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3
+#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4
+#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5
+#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6
+#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
+#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, \
+ typename T##7, typename T##8
+#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, \
+ typename T##7, typename T##8, typename T##9
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior. We can do this as we are playing the role of a standard
+// library vendor.
+namespace std {
+namespace tr1 {
+
+template <typename T0 = void, typename T1 = void, typename T2 = void,
+ typename T3 = void, typename T4 = void, typename T5 = void,
+ typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal {
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; }; // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>. kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 0, GTEST_10_TUPLE_(T)> { typedef T0 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 1, GTEST_10_TUPLE_(T)> { typedef T1 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 2, GTEST_10_TUPLE_(T)> { typedef T2 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 3, GTEST_10_TUPLE_(T)> { typedef T3 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 4, GTEST_10_TUPLE_(T)> { typedef T4 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 5, GTEST_10_TUPLE_(T)> { typedef T5 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 6, GTEST_10_TUPLE_(T)> { typedef T6 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 7, GTEST_10_TUPLE_(T)> { typedef T7 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 8, GTEST_10_TUPLE_(T)> { typedef T8 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 9, GTEST_10_TUPLE_(T)> { typedef T9 type; };
+
+} // namespace gtest_internal
+
+template <>
+class tuple<> {
+ public:
+ tuple() {}
+ tuple(const tuple& /* t */) {}
+ tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+class GTEST_1_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}
+
+ tuple(const tuple& t) : f0_(t.f0_) {}
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ return *this;
+ }
+
+ T0 f0_;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+class GTEST_2_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
+ f1_(f1) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
+ template <typename U0, typename U1>
+ tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+ template <typename U0, typename U1>
+ tuple& operator=(const ::std::pair<U0, U1>& p) {
+ f0_ = p.first;
+ f1_ = p.second;
+ return *this;
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+class GTEST_3_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+class GTEST_4_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+class GTEST_5_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
+ GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_) {}
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+class GTEST_6_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_) {}
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+class GTEST_7_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+class GTEST_8_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
+ GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5), f6_(f6), f7_(f7) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+class GTEST_9_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+ GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ f8_ = t.f8_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+ T8 f8_;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+class tuple {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
+ f9_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+ GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
+ f9_(t.f9_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ f8_ = t.f8_;
+ f9_ = t.f9_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+ T8 f8_;
+ T9 f9_;
+};
+
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+template <GTEST_1_TYPENAMES_(T)>
+inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) {
+ return GTEST_1_TUPLE_(T)(f0);
+}
+
+template <GTEST_2_TYPENAMES_(T)>
+inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) {
+ return GTEST_2_TUPLE_(T)(f0, f1);
+}
+
+template <GTEST_3_TYPENAMES_(T)>
+inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) {
+ return GTEST_3_TUPLE_(T)(f0, f1, f2);
+}
+
+template <GTEST_4_TYPENAMES_(T)>
+inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3) {
+ return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
+}
+
+template <GTEST_5_TYPENAMES_(T)>
+inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4) {
+ return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
+}
+
+template <GTEST_6_TYPENAMES_(T)>
+inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5) {
+ return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
+}
+
+template <GTEST_7_TYPENAMES_(T)>
+inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6) {
+ return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
+}
+
+template <GTEST_8_TYPENAMES_(T)>
+inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) {
+ return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
+}
+
+template <GTEST_9_TYPENAMES_(T)>
+inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+ const T8& f8) {
+ return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
+}
+
+template <GTEST_10_TYPENAMES_(T)>
+inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+ const T8& f8, const T9& f9) {
+ return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
+}
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+template <GTEST_0_TYPENAMES_(T)>
+struct tuple_size<GTEST_0_TUPLE_(T)> { static const int value = 0; };
+
+template <GTEST_1_TYPENAMES_(T)>
+struct tuple_size<GTEST_1_TUPLE_(T)> { static const int value = 1; };
+
+template <GTEST_2_TYPENAMES_(T)>
+struct tuple_size<GTEST_2_TUPLE_(T)> { static const int value = 2; };
+
+template <GTEST_3_TYPENAMES_(T)>
+struct tuple_size<GTEST_3_TUPLE_(T)> { static const int value = 3; };
+
+template <GTEST_4_TYPENAMES_(T)>
+struct tuple_size<GTEST_4_TUPLE_(T)> { static const int value = 4; };
+
+template <GTEST_5_TYPENAMES_(T)>
+struct tuple_size<GTEST_5_TUPLE_(T)> { static const int value = 5; };
+
+template <GTEST_6_TYPENAMES_(T)>
+struct tuple_size<GTEST_6_TUPLE_(T)> { static const int value = 6; };
+
+template <GTEST_7_TYPENAMES_(T)>
+struct tuple_size<GTEST_7_TUPLE_(T)> { static const int value = 7; };
+
+template <GTEST_8_TYPENAMES_(T)>
+struct tuple_size<GTEST_8_TUPLE_(T)> { static const int value = 8; };
+
+template <GTEST_9_TYPENAMES_(T)>
+struct tuple_size<GTEST_9_TUPLE_(T)> { static const int value = 9; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct tuple_size<GTEST_10_TUPLE_(T)> { static const int value = 10; };
+
+template <int k, class Tuple>
+struct tuple_element {
+ typedef typename gtest_internal::TupleElement<
+ k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal {
+
+template <>
+class Get<0> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+ Field(Tuple& t) { return t.f0_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+ ConstField(const Tuple& t) { return t.f0_; }
+};
+
+template <>
+class Get<1> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+ Field(Tuple& t) { return t.f1_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+ ConstField(const Tuple& t) { return t.f1_; }
+};
+
+template <>
+class Get<2> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+ Field(Tuple& t) { return t.f2_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+ ConstField(const Tuple& t) { return t.f2_; }
+};
+
+template <>
+class Get<3> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+ Field(Tuple& t) { return t.f3_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+ ConstField(const Tuple& t) { return t.f3_; }
+};
+
+template <>
+class Get<4> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+ Field(Tuple& t) { return t.f4_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+ ConstField(const Tuple& t) { return t.f4_; }
+};
+
+template <>
+class Get<5> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+ Field(Tuple& t) { return t.f5_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+ ConstField(const Tuple& t) { return t.f5_; }
+};
+
+template <>
+class Get<6> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+ Field(Tuple& t) { return t.f6_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+ ConstField(const Tuple& t) { return t.f6_; }
+};
+
+template <>
+class Get<7> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+ Field(Tuple& t) { return t.f7_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+ ConstField(const Tuple& t) { return t.f7_; }
+};
+
+template <>
+class Get<8> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+ Field(Tuple& t) { return t.f8_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+ ConstField(const Tuple& t) { return t.f8_; }
+};
+
+template <>
+class Get<9> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+ Field(Tuple& t) { return t.f9_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+ ConstField(const Tuple& t) { return t.f9_; }
+};
+
+} // namespace gtest_internal
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(GTEST_10_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(const GTEST_10_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal {
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+ return true;
+ }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+ return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+ ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+ }
+};
+
+} // namespace gtest_internal
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator==(const GTEST_10_TUPLE_(T)& t,
+ const GTEST_10_TUPLE_(U)& u) {
+ return gtest_internal::SameSizeTuplePrefixComparator<
+ tuple_size<GTEST_10_TUPLE_(T)>::value,
+ tuple_size<GTEST_10_TUPLE_(U)>::value>::Eq(t, u);
+}
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_10_TUPLE_(T)& t,
+ const GTEST_10_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+} // namespace tr1
+} // namespace std
+
+#undef GTEST_0_TUPLE_
+#undef GTEST_1_TUPLE_
+#undef GTEST_2_TUPLE_
+#undef GTEST_3_TUPLE_
+#undef GTEST_4_TUPLE_
+#undef GTEST_5_TUPLE_
+#undef GTEST_6_TUPLE_
+#undef GTEST_7_TUPLE_
+#undef GTEST_8_TUPLE_
+#undef GTEST_9_TUPLE_
+#undef GTEST_10_TUPLE_
+
+#undef GTEST_0_TYPENAMES_
+#undef GTEST_1_TYPENAMES_
+#undef GTEST_2_TYPENAMES_
+#undef GTEST_3_TYPENAMES_
+#undef GTEST_4_TYPENAMES_
+#undef GTEST_5_TYPENAMES_
+#undef GTEST_6_TYPENAMES_
+#undef GTEST_7_TYPENAMES_
+#undef GTEST_8_TYPENAMES_
+#undef GTEST_9_TYPENAMES_
+#undef GTEST_10_TYPENAMES_
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+# elif GTEST_OS_SYMBIAN
+
+// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
+// use STLport's tuple implementation, which unfortunately doesn't
+// work as the copy of STLport distributed with Symbian is incomplete.
+// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
+// use its own tuple implementation.
+# ifdef BOOST_HAS_TR1_TUPLE
+# undef BOOST_HAS_TR1_TUPLE
+# endif // BOOST_HAS_TR1_TUPLE
+
+// This prevents <boost/tr1/detail/config.hpp>, which defines
+// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
+# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
+# include <tuple>
+
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does
+// not conform to the TR1 spec, which requires the header to be <tuple>.
+
+# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
+// which is #included by <tr1/tuple>, to not compile when RTTI is
+// disabled. _TR1_FUNCTIONAL is the header guard for
+// <tr1/functional>. Hence the following #define is a hack to prevent
+// <tr1/functional> from being included.
+# define _TR1_FUNCTIONAL 1
+# include <tr1/tuple>
+# undef _TR1_FUNCTIONAL // Allows the user to #include
+ // <tr1/functional> if he chooses to.
+# else
+# include <tr1/tuple> // NOLINT
+# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+
+# else
+// If the compiler is not GCC 4.0+, we assume the user is using a
+// spec-conforming TR1 implementation.
+# include <tuple> // NOLINT
+# endif // GTEST_USE_OWN_TR1_TUPLE
+
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+# if GTEST_OS_LINUX && !defined(__ia64__)
+# define GTEST_HAS_CLONE 1
+# else
+# define GTEST_HAS_CLONE 0
+# endif // GTEST_OS_LINUX && !defined(__ia64__)
+
+#endif // GTEST_HAS_CLONE
+
+// Determines whether to support stream redirection. This is used to test
+// output correctness and to implement death tests.
+#ifndef GTEST_HAS_STREAM_REDIRECTION
+// By default, we assume that stream redirection is supported on all
+// platforms except known mobile ones.
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN
+# define GTEST_HAS_STREAM_REDIRECTION 0
+# else
+# define GTEST_HAS_STREAM_REDIRECTION 1
+# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+// Determines whether to support death tests.
+// Google Test does not support death tests for VC 7.1 and earlier as
+// abort() in a VC 7.1 application compiled as GUI in debug config
+// pops up a dialog window that cannot be suppressed programmatically.
+#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
+ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX)
+# define GTEST_HAS_DEATH_TEST 1
+# include <vector> // NOLINT
+#endif
+
+// We don't support MSVC 7.1 with exceptions disabled now. Therefore
+// all the compilers we care about are adequate for supporting
+// value-parameterized tests.
+#define GTEST_HAS_PARAM_TEST 1
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
+// Sun Pro CC, IBM Visual Age, and HP aCC support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
+ defined(__IBMCPP__) || defined(__HP_aCC)
+# define GTEST_HAS_TYPED_TEST 1
+# define GTEST_HAS_TYPED_TEST_P 1
+#endif
+
+// Determines whether to support Combine(). This only makes sense when
+// value-parameterized tests are enabled. The implementation doesn't
+// work on Sun Studio since it doesn't understand templated conversion
+// operators.
+#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
+# define GTEST_HAS_COMBINE 1
+#endif
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#define GTEST_WIDE_STRING_USES_UTF16_ \
+ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)
+
+// Determines whether test results can be streamed to a socket.
+#if GTEST_OS_LINUX
+# define GTEST_CAN_STREAM_RESULTS_ 1
+#endif
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding. This leads to problems with code like:
+//
+// if (gate)
+// ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT
+#endif
+
+// Use this annotation at the end of a struct/class definition to
+// prevent the compiler from optimizing away instances that are never
+// used. This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor. Example:
+//
+// struct Foo {
+// Foo() { ... }
+// } GTEST_ATTRIBUTE_UNUSED_;
+//
+// Also use it after a variable or parameter declaration to tell the
+// compiler the variable/parameter does not have to be used.
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#else
+# define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// A macro to disallow operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_ASSIGN_(type)\
+ void operator=(type const &)
+
+// A macro to disallow copy constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
+ type(type const &);\
+ GTEST_DISALLOW_ASSIGN_(type)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro. The macro should be used on function declarations
+// following the argument list:
+//
+// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+# define GTEST_MUST_USE_RESULT_
+#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+
+// Determine whether the compiler supports Microsoft's Structured Exception
+// Handling. This is supported by several Windows compilers but generally
+// does not exist on any other system.
+#ifndef GTEST_HAS_SEH
+// The user didn't tell us, so we need to figure it out.
+
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// These two compilers are known to support SEH.
+# define GTEST_HAS_SEH 1
+# else
+// Assume no SEH.
+# define GTEST_HAS_SEH 0
+# endif
+
+#endif // GTEST_HAS_SEH
+
+#ifdef _MSC_VER
+
+# if GTEST_LINKED_AS_SHARED_LIBRARY
+# define GTEST_API_ __declspec(dllimport)
+# elif GTEST_CREATE_SHARED_LIBRARY
+# define GTEST_API_ __declspec(dllexport)
+# endif
+
+#endif // _MSC_VER
+
+#ifndef GTEST_API_
+# define GTEST_API_
+#endif
+
+#ifdef __GNUC__
+// Ask the compiler to never inline a given function.
+# define GTEST_NO_INLINE_ __attribute__((noinline))
+#else
+# define GTEST_NO_INLINE_
+#endif
+
+namespace testing {
+
+class Message;
+
+namespace internal {
+
+class String;
+
+// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+// content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define GTEST_COMPILE_ASSERT_(expr, msg) \
+ typedef ::testing::internal::CompileAssert<(bool(expr))> \
+ msg[bool(expr) ? 1 : -1]
+
+// Implementation details of GTEST_COMPILE_ASSERT_:
+//
+// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
+// elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+// does not work, as gcc supports variable-length arrays whose sizes
+// are determined at run-time (this is gcc's extension and not part
+// of the C++ standard). As a result, gcc fails to reject the
+// following code with the simple definition:
+//
+// int foo;
+// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
+// // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// expr is a compile-time constant. (Template arguments must be
+// determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
+//
+// CompileAssert<bool(expr)>
+//
+// instead, these compilers will refuse to compile
+//
+// GTEST_COMPILE_ASSERT_(5 > 0, some_message);
+//
+// (They seem to think the ">" in "5 > 0" marks the end of the
+// template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+// ((expr) ? 1 : -1).
+//
+// This is to avoid running into a bug in MS VC 7.1, which
+// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
+//
+// This template is declared, but intentionally undefined.
+template <typename T1, typename T2>
+struct StaticAssertTypeEqHelper;
+
+template <typename T>
+struct StaticAssertTypeEqHelper<T, T> {};
+
+#if GTEST_HAS_GLOBAL_STRING
+typedef ::string string;
+#else
+typedef ::std::string string;
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+typedef ::wstring wstring;
+#elif GTEST_HAS_STD_WSTRING
+typedef ::std::wstring wstring;
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// A helper for suppressing warnings on constant condition. It just
+// returns 'condition'.
+GTEST_API_ bool IsTrue(bool condition);
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr {
+ public:
+ typedef T element_type;
+
+ explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+ ~scoped_ptr() { reset(); }
+
+ T& operator*() const { return *ptr_; }
+ T* operator->() const { return ptr_; }
+ T* get() const { return ptr_; }
+
+ T* release() {
+ T* const ptr = ptr_;
+ ptr_ = NULL;
+ return ptr;
+ }
+
+ void reset(T* p = NULL) {
+ if (p != ptr_) {
+ if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type.
+ delete ptr_;
+ }
+ ptr_ = p;
+ }
+ }
+ private:
+ T* ptr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
+};
+
+// Defines RE.
+
+// A simple C++ wrapper for <regex.h>. It uses the POSIX Extended
+// Regular Expression syntax.
+class GTEST_API_ RE {
+ public:
+ // A copy constructor is required by the Standard to initialize object
+ // references from r-values.
+ RE(const RE& other) { Init(other.pattern()); }
+
+ // Constructs an RE from a string.
+ RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
+
+#if GTEST_HAS_GLOBAL_STRING
+
+ RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ RE(const char* regex) { Init(regex); } // NOLINT
+ ~RE();
+
+ // Returns the string representation of the regex.
+ const char* pattern() const { return pattern_; }
+
+ // FullMatch(str, re) returns true iff regular expression re matches
+ // the entire str.
+ // PartialMatch(str, re) returns true iff regular expression re
+ // matches a substring of str (including str itself).
+ //
+ // TODO(wan@google.com): make FullMatch() and PartialMatch() work
+ // when str contains NUL characters.
+ static bool FullMatch(const ::std::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::std::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+
+#if GTEST_HAS_GLOBAL_STRING
+
+ static bool FullMatch(const ::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ static bool FullMatch(const char* str, const RE& re);
+ static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+ void Init(const char* regex);
+
+ // We use a const char* instead of a string, as Google Test may be used
+ // where string is not available. We also do not use Google Test's own
+ // String type here, in order to simplify dependencies between the
+ // files.
+ const char* pattern_;
+ bool is_valid_;
+
+#if GTEST_USES_POSIX_RE
+
+ regex_t full_regex_; // For FullMatch().
+ regex_t partial_regex_; // For PartialMatch().
+
+#else // GTEST_USES_SIMPLE_RE
+
+ const char* full_pattern_; // For FullMatch();
+
+#endif
+
+ GTEST_DISALLOW_ASSIGN_(RE);
+};
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line);
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file,
+ int line);
+
+// Defines logging utilities:
+// GTEST_LOG_(severity) - logs messages at the specified severity level. The
+// message itself is streamed into the macro.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+ GTEST_INFO,
+ GTEST_WARNING,
+ GTEST_ERROR,
+ GTEST_FATAL
+};
+
+// Formats log entry severity, provides a stream object for streaming the
+// log message, and terminates the message with a newline when going out of
+// scope.
+class GTEST_API_ GTestLog {
+ public:
+ GTestLog(GTestLogSeverity severity, const char* file, int line);
+
+ // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+ ~GTestLog();
+
+ ::std::ostream& GetStream() { return ::std::cerr; }
+
+ private:
+ const GTestLogSeverity severity_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
+};
+
+#define GTEST_LOG_(severity) \
+ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
+ __FILE__, __LINE__).GetStream()
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+// Synopsys:
+// GTEST_CHECK_(boolean_condition);
+// or
+// GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+// This checks the condition and if the condition is not satisfied
+// it prints message about the condition violation, including the
+// condition itself, plus additional message streamed into it, if any,
+// and then it aborts the program. It aborts the program irrespective of
+// whether it is built in the debug mode or not.
+#define GTEST_CHECK_(condition) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::IsTrue(condition)) \
+ ; \
+ else \
+ GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+
+// An all-mode assert to verify that the given POSIX-style function
+// call returns 0 (indicating success). Known limitation: this
+// doesn't expand to a balanced 'if' statement, so enclose the macro
+// in {} if you need to use it as the only statement in an 'if'
+// branch.
+#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
+ if (const int gtest_error = (posix_call)) \
+ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
+ << gtest_error
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Use ImplicitCast_ as a safe version of static_cast for upcasting in
+// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
+// const Foo*). When you use ImplicitCast_, the compiler checks that
+// the cast is safe. Such explicit ImplicitCast_s are necessary in
+// surprisingly many situations where C++ demands an exact type match
+// instead of an argument type convertable to a target type.
+//
+// The syntax for using ImplicitCast_ is the same as for static_cast:
+//
+// ImplicitCast_<ToType>(expr)
+//
+// ImplicitCast_ would have been part of the C++ standard library,
+// but the proposal was submitted too late. It will probably make
+// its way into the language in the future.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., implicit_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To>
+inline To ImplicitCast_(To x) { return x; }
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts
+// always succeed. When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo? It
+// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
+// when you downcast, you should use this macro. In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not). In normal mode, we do the efficient static_cast<>
+// instead. Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+// This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., down_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To, typename From> // use like this: DownCast_<T*>(foo);
+inline To DownCast_(From* f) { // so we only accept pointers
+ // Ensures that To is a sub-type of From *. This test is here only
+ // for compile-time type checking, and has no overhead in an
+ // optimized build at run-time, as it will be optimized away
+ // completely.
+ if (false) {
+ const To to = NULL;
+ ::testing::internal::ImplicitCast_<From*>(to);
+ }
+
+#if GTEST_HAS_RTTI
+ // RTTI: debug mode only!
+ GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL);
+#endif
+ return static_cast<To>(f);
+}
+
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+ GTEST_CHECK_(typeid(*base) == typeid(Derived));
+ return dynamic_cast<Derived*>(base); // NOLINT
+#else
+ return static_cast<Derived*>(base); // Poor man's downcast.
+#endif
+}
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Defines the stderr capturer:
+// CaptureStdout - starts capturing stdout.
+// GetCapturedStdout - stops capturing stdout and returns the captured string.
+// CaptureStderr - starts capturing stderr.
+// GetCapturedStderr - stops capturing stderr and returns the captured string.
+//
+GTEST_API_ void CaptureStdout();
+GTEST_API_ String GetCapturedStdout();
+GTEST_API_ void CaptureStderr();
+GTEST_API_ String GetCapturedStderr();
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+extern ::std::vector<String> g_argvs;
+
+// GTEST_HAS_DEATH_TEST implies we have ::std::string.
+const ::std::vector<String>& GetArgvs();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+#if GTEST_HAS_PTHREAD
+
+// Sleeps for (roughly) n milli-seconds. This function is only for
+// testing Google Test's own constructs. Don't use it in user tests,
+// either directly or indirectly.
+inline void SleepMilliseconds(int n) {
+ const timespec time = {
+ 0, // 0 seconds.
+ n * 1000L * 1000L, // And n ms.
+ };
+ nanosleep(&time, NULL);
+}
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified. Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class Notification {
+ public:
+ Notification() : notified_(false) {}
+
+ // Notifies all threads created with this notification to start. Must
+ // be called from the controller thread.
+ void Notify() { notified_ = true; }
+
+ // Blocks until the controller thread notifies. Must be called from a test
+ // thread.
+ void WaitForNotification() {
+ while(!notified_) {
+ SleepMilliseconds(10);
+ }
+ }
+
+ private:
+ volatile bool notified_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+
+// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
+// Consequently, it cannot select a correct instantiation of ThreadWithParam
+// in order to call its Run(). Introducing ThreadWithParamBase as a
+// non-templated base class for ThreadWithParam allows us to bypass this
+// problem.
+class ThreadWithParamBase {
+ public:
+ virtual ~ThreadWithParamBase() {}
+ virtual void Run() = 0;
+};
+
+// pthread_create() accepts a pointer to a function type with the C linkage.
+// According to the Standard (7.5/1), function types with different linkages
+// are different even if they are otherwise identical. Some compilers (for
+// example, SunStudio) treat them as different types. Since class methods
+// cannot be defined with C-linkage we need to define a free C-function to
+// pass into pthread_create().
+extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
+ static_cast<ThreadWithParamBase*>(thread)->Run();
+ return NULL;
+}
+
+// Helper class for testing Google Test's multi-threading constructs.
+// To use it, write:
+//
+// void ThreadFunc(int param) { /* Do things with param */ }
+// Notification thread_can_start;
+// ...
+// // The thread_can_start parameter is optional; you can supply NULL.
+// ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
+// thread_can_start.Notify();
+//
+// These classes are only for testing Google Test's own constructs. Do
+// not use them in user tests, either directly or indirectly.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+ typedef void (*UserThreadFunc)(T);
+
+ ThreadWithParam(
+ UserThreadFunc func, T param, Notification* thread_can_start)
+ : func_(func),
+ param_(param),
+ thread_can_start_(thread_can_start),
+ finished_(false) {
+ ThreadWithParamBase* const base = this;
+ // The thread can be created only after all fields except thread_
+ // have been initialized.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
+ }
+ ~ThreadWithParam() { Join(); }
+
+ void Join() {
+ if (!finished_) {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
+ finished_ = true;
+ }
+ }
+
+ virtual void Run() {
+ if (thread_can_start_ != NULL)
+ thread_can_start_->WaitForNotification();
+ func_(param_);
+ }
+
+ private:
+ const UserThreadFunc func_; // User-supplied thread function.
+ const T param_; // User-supplied parameter to the thread function.
+ // When non-NULL, used to block execution until the controller thread
+ // notifies.
+ Notification* const thread_can_start_;
+ bool finished_; // true iff we know that the thread function has finished.
+ pthread_t thread_; // The native thread object.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms. They
+// are used in conjunction with class MutexLock:
+//
+// Mutex mutex;
+// ...
+// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end
+// // of the current scope.
+//
+// MutexBase implements behavior for both statically and dynamically
+// allocated mutexes. Do not use MutexBase directly. Instead, write
+// the following to define a static mutex:
+//
+// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+//
+// You can forward declare a static mutex like this:
+//
+// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// To create a dynamic mutex, just define an object of type Mutex.
+class MutexBase {
+ public:
+ // Acquires this mutex.
+ void Lock() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
+ owner_ = pthread_self();
+ }
+
+ // Releases this mutex.
+ void Unlock() {
+ // We don't protect writing to owner_ here, as it's the caller's
+ // responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ owner_ = 0;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
+ }
+
+ // Does nothing if the current thread holds the mutex. Otherwise, crashes
+ // with high probability.
+ void AssertHeld() const {
+ GTEST_CHECK_(owner_ == pthread_self())
+ << "The current thread is not holding the mutex @" << this;
+ }
+
+ // A static mutex may be used before main() is entered. It may even
+ // be used before the dynamic initialization stage. Therefore we
+ // must be able to initialize a static mutex object at link time.
+ // This means MutexBase has to be a POD and its member variables
+ // have to be public.
+ public:
+ pthread_mutex_t mutex_; // The underlying pthread mutex.
+ pthread_t owner_; // The thread holding the mutex; 0 means no one holds it.
+};
+
+// Forward-declares a static mutex.
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::MutexBase mutex
+
+// Defines and statically (i.e. at link time) initializes a static mutex.
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 }
+
+// The Mutex class can only be used for mutexes created at runtime. It
+// shares its API with MutexBase otherwise.
+class Mutex : public MutexBase {
+ public:
+ Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+ owner_ = 0;
+ }
+ ~Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+// We cannot name this class MutexLock as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(MutexBase* mutex)
+ : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ MutexBase* const mutex_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Helpers for ThreadLocal.
+
+// pthread_key_create() requires DeleteThreadLocalValue() to have
+// C-linkage. Therefore it cannot be templatized to access
+// ThreadLocal<T>. Hence the need for class
+// ThreadLocalValueHolderBase.
+class ThreadLocalValueHolderBase {
+ public:
+ virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Called by pthread to delete thread-local data stored by
+// pthread_setspecific().
+extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
+ delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
+}
+
+// Implements thread-local storage on pthreads-based systems.
+//
+// // Thread 1
+// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
+//
+// // Thread 2
+// tl.set(150); // Changes the value for thread 2 only.
+// EXPECT_EQ(150, tl.get());
+//
+// // Thread 1
+// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
+// tl.set(200);
+// EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// An object managed for a thread by a ThreadLocal instance is deleted
+// when the thread exits. Or, if the ThreadLocal instance dies in
+// that thread, when the ThreadLocal dies. It's the user's
+// responsibility to ensure that all other threads using a ThreadLocal
+// have exited when it dies, or the per-thread objects for those
+// threads will not be deleted.
+//
+// Google Test only uses global ThreadLocal objects. That means they
+// will die after main() has returned. Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal {
+ public:
+ ThreadLocal() : key_(CreateKey()),
+ default_() {}
+ explicit ThreadLocal(const T& value) : key_(CreateKey()),
+ default_(value) {}
+
+ ~ThreadLocal() {
+ // Destroys the managed object for the current thread, if any.
+ DeleteThreadLocalValue(pthread_getspecific(key_));
+
+ // Releases resources associated with the key. This will *not*
+ // delete managed objects for other threads.
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
+ }
+
+ T* pointer() { return GetOrCreateValue(); }
+ const T* pointer() const { return GetOrCreateValue(); }
+ const T& get() const { return *pointer(); }
+ void set(const T& value) { *pointer() = value; }
+
+ private:
+ // Holds a value of type T.
+ class ValueHolder : public ThreadLocalValueHolderBase {
+ public:
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+ };
+
+ static pthread_key_t CreateKey() {
+ pthread_key_t key;
+ // When a thread exits, DeleteThreadLocalValue() will be called on
+ // the object managed for that thread.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_key_create(&key, &DeleteThreadLocalValue));
+ return key;
+ }
+
+ T* GetOrCreateValue() const {
+ ThreadLocalValueHolderBase* const holder =
+ static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
+ if (holder != NULL) {
+ return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
+ }
+
+ ValueHolder* const new_holder = new ValueHolder(default_);
+ ThreadLocalValueHolderBase* const holder_base = new_holder;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
+ return new_holder->pointer();
+ }
+
+ // A key pthreads uses for looking up per-thread values.
+ const pthread_key_t key_;
+ const T default_; // The default value for each thread.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+# define GTEST_IS_THREADSAFE 1
+
+#else // GTEST_HAS_PTHREAD
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable). Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+ Mutex() {}
+ void AssertHeld() const {}
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex*) {} // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal {
+ public:
+ ThreadLocal() : value_() {}
+ explicit ThreadLocal(const T& value) : value_(value) {}
+ T* pointer() { return &value_; }
+ const T* pointer() const { return &value_; }
+ const T& get() const { return value_; }
+ void set(const T& value) { value_ = value; }
+ private:
+ T value_;
+};
+
+// The above synchronization primitives have dummy implementations.
+// Therefore Google Test is not thread-safe.
+# define GTEST_IS_THREADSAFE 0
+
+#endif // GTEST_HAS_PTHREAD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+GTEST_API_ size_t GetThreadCount();
+
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler and generates a warning in Sun Studio. The Nokia Symbian
+// and the IBM XL C/C++ compiler try to instantiate a copy constructor
+// for objects passed through ellipsis (...), failing for uncopyable
+// objects. We define this to ensure that only POD is passed through
+// ellipsis on these systems.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_ELLIPSIS_NEEDS_POD_ 1
+#else
+# define GTEST_CAN_COMPARE_NULL 1
+#endif
+
+// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
+// const T& and const T* in a function template. These compilers
+// _can_ decide between class template specializations for T and T*,
+// so a tr1::type_traits-like is_pointer works.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
+# define GTEST_NEEDS_IS_POINTER_ 1
+#endif
+
+template <bool bool_value>
+struct bool_constant {
+ typedef bool_constant<bool_value> type;
+ static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+template <typename Iterator>
+struct IteratorTraits {
+ typedef typename Iterator::value_type value_type;
+};
+
+template <typename T>
+struct IteratorTraits<T*> {
+ typedef T value_type;
+};
+
+template <typename T>
+struct IteratorTraits<const T*> {
+ typedef T value_type;
+};
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_SEP_ "\\"
+# define GTEST_HAS_ALT_PATH_SEP_ 1
+// The biggest signed integer type the compiler supports.
+typedef __int64 BiggestInt;
+#else
+# define GTEST_PATH_SEP_ "/"
+# define GTEST_HAS_ALT_PATH_SEP_ 0
+typedef long long BiggestInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+// Utilities for char.
+
+// isspace(int ch) and friends accept an unsigned char or EOF. char
+// may be signed, depending on the compiler (or compiler flags).
+// Therefore we need to cast a char to unsigned char before calling
+// isspace(), etc.
+
+inline bool IsAlpha(char ch) {
+ return isalpha(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsAlNum(char ch) {
+ return isalnum(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsDigit(char ch) {
+ return isdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsLower(char ch) {
+ return islower(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsSpace(char ch) {
+ return isspace(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsUpper(char ch) {
+ return isupper(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(char ch) {
+ return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+
+inline char ToLower(char ch) {
+ return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
+}
+inline char ToUpper(char ch) {
+ return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
+}
+
+// The testing::internal::posix namespace holds wrappers for common
+// POSIX functions. These wrappers hide the differences between
+// Windows/MSVC and POSIX systems. Since some compilers define these
+// standard functions as macros, the wrapper cannot have the same name
+// as the wrapped function.
+
+namespace posix {
+
+// Functions with a different name on Windows.
+
+#if GTEST_OS_WINDOWS
+
+typedef struct _stat StatStruct;
+
+# ifdef __BORLANDC__
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+# else // !__BORLANDC__
+# if GTEST_OS_WINDOWS_MOBILE
+inline int IsATTY(int /* fd */) { return 0; }
+# else
+inline int IsATTY(int fd) { return _isatty(fd); }
+# endif // GTEST_OS_WINDOWS_MOBILE
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return _stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return _strdup(src); }
+# endif // __BORLANDC__
+
+# if GTEST_OS_WINDOWS_MOBILE
+inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
+// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
+// time and thus not defined there.
+# else
+inline int FileNo(FILE* file) { return _fileno(file); }
+inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
+inline int RmDir(const char* dir) { return _rmdir(dir); }
+inline bool IsDir(const StatStruct& st) {
+ return (_S_IFDIR & st.st_mode) != 0;
+}
+# endif // GTEST_OS_WINDOWS_MOBILE
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#endif // GTEST_OS_WINDOWS
+
+// Functions deprecated by MSVC 8.0.
+
+#ifdef _MSC_VER
+// Temporarily disable warning 4996 (deprecated function).
+# pragma warning(push)
+# pragma warning(disable:4996)
+#endif
+
+inline const char* StrNCpy(char* dest, const char* src, size_t n) {
+ return strncpy(dest, src, n);
+}
+
+// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
+// StrError() aren't needed on Windows CE at this time and thus not
+// defined there.
+
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int ChDir(const char* dir) { return chdir(dir); }
+#endif
+inline FILE* FOpen(const char* path, const char* mode) {
+ return fopen(path, mode);
+}
+#if !GTEST_OS_WINDOWS_MOBILE
+inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
+ return freopen(path, mode, stream);
+}
+inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
+#endif
+inline int FClose(FILE* fp) { return fclose(fp); }
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int Read(int fd, void* buf, unsigned int count) {
+ return static_cast<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count) {
+ return static_cast<int>(write(fd, buf, count));
+}
+inline int Close(int fd) { return close(fd); }
+inline const char* StrError(int errnum) { return strerror(errnum); }
+#endif
+inline const char* GetEnv(const char* name) {
+#if GTEST_OS_WINDOWS_MOBILE
+ // We are on Windows CE, which has no environment variables.
+ return NULL;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+ // Environment variables which we programmatically clear will be set to the
+ // empty string rather than unset (NULL). Handle that case.
+ const char* const env = getenv(name);
+ return (env != NULL && env[0] != '\0') ? env : NULL;
+#else
+ return getenv(name);
+#endif
+}
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+void Abort();
+#else
+inline void Abort() { abort(); }
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+} // namespace posix
+
+// The maximum number a BiggestInt can represent. This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+ ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type. It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+// TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs. Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+ // This prevents the user from using TypeWithSize<N> with incorrect
+ // values of N.
+ typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+ // unsigned int has size 4 in both gcc and MSVC.
+ //
+ // As base/basictypes.h doesn't compile on Windows, we cannot use
+ // uint32, uint64, and etc here.
+ typedef int Int;
+ typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+
+#if GTEST_OS_WINDOWS
+ typedef __int64 Int;
+ typedef unsigned __int64 UInt;
+#else
+ typedef long long Int; // NOLINT
+ typedef unsigned long long UInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32_(name) \
+ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string_(name) \
+ GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+ GTEST_API_ bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+ GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val)
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+#if GTEST_OS_LINUX
+# include <stdlib.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <unistd.h>
+#endif // GTEST_OS_LINUX
+
+#include <ctype.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test. They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by <gtest/internal/gtest-internal.h>.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+# include <mem.h>
+#endif
+
+#include <string.h>
+
+#include <string>
+
+namespace testing {
+namespace internal {
+
+// String - a UTF-8 string class.
+//
+// For historic reasons, we don't use std::string.
+//
+// TODO(wan@google.com): replace this class with std::string or
+// implement it in terms of the latter.
+//
+// Note that String can represent both NULL and the empty string,
+// while std::string cannot represent NULL.
+//
+// NULL and the empty string are considered different. NULL is less
+// than anything (including the empty string) except itself.
+//
+// This class only provides minimum functionality necessary for
+// implementing Google Test. We do not intend to implement a full-fledged
+// string class here.
+//
+// Since the purpose of this class is to provide a substitute for
+// std::string on platforms where it cannot be used, we define a copy
+// constructor and assignment operators such that we don't need
+// conditional compilation in a lot of places.
+//
+// In order to make the representation efficient, the d'tor of String
+// is not virtual. Therefore DO NOT INHERIT FROM String.
+class GTEST_API_ String {
+ public:
+ // Static utility methods
+
+ // Returns the input enclosed in double quotes if it's not NULL;
+ // otherwise returns "(null)". For example, "\"Hello\"" is returned
+ // for input "Hello".
+ //
+ // This is useful for printing a C string in the syntax of a literal.
+ //
+ // Known issue: escape sequences are not handled yet.
+ static String ShowCStringQuoted(const char* c_str);
+
+ // Clones a 0-terminated C string, allocating memory using new. The
+ // caller is responsible for deleting the return value using
+ // delete[]. Returns the cloned string, or NULL if the input is
+ // NULL.
+ //
+ // This is different from strdup() in string.h, which allocates
+ // memory using malloc().
+ static const char* CloneCString(const char* c_str);
+
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+ // able to pass strings to Win32 APIs on CE we need to convert them
+ // to 'Unicode', UTF-16.
+
+ // Creates a UTF-16 wide string from the given ANSI string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the wide string, or NULL if the
+ // input is NULL.
+ //
+ // The wide string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static LPCWSTR AnsiToUtf16(const char* c_str);
+
+ // Creates an ANSI string from the given wide string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the ANSI string, or NULL if the
+ // input is NULL.
+ //
+ // The returned string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+ // Compares two C strings. Returns true iff they have the same content.
+ //
+ // Unlike strcmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CStringEquals(const char* lhs, const char* rhs);
+
+ // Converts a wide C string to a String using the UTF-8 encoding.
+ // NULL will be converted to "(null)". If an error occurred during
+ // the conversion, "(failed to convert from wide string)" is
+ // returned.
+ static String ShowWideCString(const wchar_t* wide_c_str);
+
+ // Similar to ShowWideCString(), except that this function encloses
+ // the converted string in double quotes.
+ static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
+
+ // Compares two wide C strings. Returns true iff they have the same
+ // content.
+ //
+ // Unlike wcscmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+ // Compares two C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike strcasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CaseInsensitiveCStringEquals(const char* lhs,
+ const char* rhs);
+
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+ static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs);
+
+ // Formats a list of arguments to a String, using the same format
+ // spec string as for printf.
+ //
+ // We do not use the StringPrintf class as it is not universally
+ // available.
+ //
+ // The result is limited to 4096 characters (including the tailing
+ // 0). If 4096 characters are not enough to format the input,
+ // "<buffer exceeded>" is returned.
+ static String Format(const char* format, ...);
+
+ // C'tors
+
+ // The default c'tor constructs a NULL string.
+ String() : c_str_(NULL), length_(0) {}
+
+ // Constructs a String by cloning a 0-terminated C string.
+ String(const char* a_c_str) { // NOLINT
+ if (a_c_str == NULL) {
+ c_str_ = NULL;
+ length_ = 0;
+ } else {
+ ConstructNonNull(a_c_str, strlen(a_c_str));
+ }
+ }
+
+ // Constructs a String by copying a given number of chars from a
+ // buffer. E.g. String("hello", 3) creates the string "hel",
+ // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "",
+ // and String(NULL, 1) results in access violation.
+ String(const char* buffer, size_t a_length) {
+ ConstructNonNull(buffer, a_length);
+ }
+
+ // The copy c'tor creates a new copy of the string. The two
+ // String objects do not share content.
+ String(const String& str) : c_str_(NULL), length_(0) { *this = str; }
+
+ // D'tor. String is intended to be a final class, so the d'tor
+ // doesn't need to be virtual.
+ ~String() { delete[] c_str_; }
+
+ // Allows a String to be implicitly converted to an ::std::string or
+ // ::string, and vice versa. Converting a String containing a NULL
+ // pointer to ::std::string or ::string is undefined behavior.
+ // Converting a ::std::string or ::string containing an embedded NUL
+ // character to a String will result in the prefix up to the first
+ // NUL character.
+ String(const ::std::string& str) {
+ ConstructNonNull(str.c_str(), str.length());
+ }
+
+ operator ::std::string() const { return ::std::string(c_str(), length()); }
+
+#if GTEST_HAS_GLOBAL_STRING
+ String(const ::string& str) {
+ ConstructNonNull(str.c_str(), str.length());
+ }
+
+ operator ::string() const { return ::string(c_str(), length()); }
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ // Returns true iff this is an empty string (i.e. "").
+ bool empty() const { return (c_str() != NULL) && (length() == 0); }
+
+ // Compares this with another String.
+ // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+ // if this is greater than rhs.
+ int Compare(const String& rhs) const;
+
+ // Returns true iff this String equals the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; }
+
+ // Returns true iff this String is less than the given String. A
+ // NULL string is considered less than "".
+ bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
+
+ // Returns true iff this String doesn't equal the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); }
+
+ // Returns true iff this String ends with the given suffix. *Any*
+ // String is considered to end with a NULL or empty suffix.
+ bool EndsWith(const char* suffix) const;
+
+ // Returns true iff this String ends with the given suffix, not considering
+ // case. Any String is considered to end with a NULL or empty suffix.
+ bool EndsWithCaseInsensitive(const char* suffix) const;
+
+ // Returns the length of the encapsulated string, or 0 if the
+ // string is NULL.
+ size_t length() const { return length_; }
+
+ // Gets the 0-terminated C string this String object represents.
+ // The String object still owns the string. Therefore the caller
+ // should NOT delete the return value.
+ const char* c_str() const { return c_str_; }
+
+ // Assigns a C string to this object. Self-assignment works.
+ const String& operator=(const char* a_c_str) {
+ return *this = String(a_c_str);
+ }
+
+ // Assigns a String object to this object. Self-assignment works.
+ const String& operator=(const String& rhs) {
+ if (this != &rhs) {
+ delete[] c_str_;
+ if (rhs.c_str() == NULL) {
+ c_str_ = NULL;
+ length_ = 0;
+ } else {
+ ConstructNonNull(rhs.c_str(), rhs.length());
+ }
+ }
+
+ return *this;
+ }
+
+ private:
+ // Constructs a non-NULL String from the given content. This
+ // function can only be called when c_str_ has not been allocated.
+ // ConstructNonNull(NULL, 0) results in an empty string ("").
+ // ConstructNonNull(NULL, non_zero) is undefined behavior.
+ void ConstructNonNull(const char* buffer, size_t a_length) {
+ char* const str = new char[a_length + 1];
+ memcpy(str, buffer, a_length);
+ str[a_length] = '\0';
+ c_str_ = str;
+ length_ = a_length;
+ }
+
+ const char* c_str_;
+ size_t length_;
+}; // class String
+
+// Streams a String to an ostream. Each '\0' character in the String
+// is replaced with "\\0".
+inline ::std::ostream& operator<<(::std::ostream& os, const String& str) {
+ if (str.c_str() == NULL) {
+ os << "(null)";
+ } else {
+ const char* const c_str = str.c_str();
+ for (size_t i = 0; i != str.length(); i++) {
+ if (c_str[i] == '\0') {
+ os << "\\0";
+ } else {
+ os << c_str[i];
+ }
+ }
+ }
+ return os;
+}
+
+// Gets the content of the stringstream's buffer as a String. Each '\0'
+// character in the buffer is replaced with "\\0".
+GTEST_API_ String StringStreamToString(::std::stringstream* stream);
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included in <gtest/internal/gtest-internal.h>.
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class GTEST_API_ FilePath {
+ public:
+ FilePath() : pathname_("") { }
+ FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+ explicit FilePath(const char* pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ explicit FilePath(const String& pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ FilePath& operator=(const FilePath& rhs) {
+ Set(rhs);
+ return *this;
+ }
+
+ void Set(const FilePath& rhs) {
+ pathname_ = rhs.pathname_;
+ }
+
+ String ToString() const { return pathname_; }
+ const char* c_str() const { return pathname_.c_str(); }
+
+ // Returns the current working directory, or "" if unsuccessful.
+ static FilePath GetCurrentDir();
+
+ // Given directory = "dir", base_name = "test", number = 0,
+ // extension = "xml", returns "dir/test.xml". If number is greater
+ // than zero (e.g., 12), returns "dir/test_12.xml".
+ // On Windows platform, uses \ as the separator rather than /.
+ static FilePath MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension);
+
+ // Given directory = "dir", relative_path = "test.xml",
+ // returns "dir/test.xml".
+ // On Windows, uses \ as the separator rather than /.
+ static FilePath ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path);
+
+ // Returns a pathname for a file that does not currently exist. The pathname
+ // will be directory/base_name.extension or
+ // directory/base_name_<number>.extension if directory/base_name.extension
+ // already exists. The number will be incremented until a pathname is found
+ // that does not already exist.
+ // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+ // There could be a race condition if two or more processes are calling this
+ // function at the same time -- they could both pick the same filename.
+ static FilePath GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension);
+
+ // Returns true iff the path is NULL or "".
+ bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
+
+ // If input name has a trailing separator character, removes it and returns
+ // the name, otherwise return the name string unmodified.
+ // On Windows platform, uses \ as the separator, other platforms use /.
+ FilePath RemoveTrailingPathSeparator() const;
+
+ // Returns a copy of the FilePath with the directory part removed.
+ // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+ // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+ // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+ // returns an empty FilePath ("").
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveDirectoryName() const;
+
+ // RemoveFileName returns the directory path with the filename removed.
+ // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+ // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+ // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+ // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveFileName() const;
+
+ // Returns a copy of the FilePath with the case-insensitive extension removed.
+ // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+ // FilePath("dir/file"). If a case-insensitive extension is not
+ // found, returns a copy of the original FilePath.
+ FilePath RemoveExtension(const char* extension) const;
+
+ // Creates directories so that path exists. Returns true if successful or if
+ // the directories already exist; returns false if unable to create
+ // directories for any reason. Will also return false if the FilePath does
+ // not represent a directory (that is, it doesn't end with a path separator).
+ bool CreateDirectoriesRecursively() const;
+
+ // Create the directory so that path exists. Returns true if successful or
+ // if the directory already exists; returns false if unable to create the
+ // directory for any reason, including if the parent directory does not
+ // exist. Not named "CreateDirectory" because that's a macro on Windows.
+ bool CreateFolder() const;
+
+ // Returns true if FilePath describes something in the file-system,
+ // either a file, directory, or whatever, and that something exists.
+ bool FileOrDirectoryExists() const;
+
+ // Returns true if pathname describes a directory in the file-system
+ // that exists.
+ bool DirectoryExists() const;
+
+ // Returns true if FilePath ends with a path separator, which indicates that
+ // it is intended to represent a directory. Returns false otherwise.
+ // This does NOT check that a directory (or file) actually exists.
+ bool IsDirectory() const;
+
+ // Returns true if pathname describes a root directory. (Windows has one
+ // root directory per disk drive.)
+ bool IsRootDirectory() const;
+
+ // Returns true if pathname describes an absolute path.
+ bool IsAbsolutePath() const;
+
+ private:
+ // Replaces multiple consecutive separators with a single separator.
+ // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+ // redundancies that might be in a pathname involving "." or "..".
+ //
+ // A pathname with multiple consecutive separators may occur either through
+ // user error or as a result of some scripts or APIs that generate a pathname
+ // with a trailing separator. On other platforms the same API or script
+ // may NOT generate a pathname with a trailing "/". Then elsewhere that
+ // pathname may have another "/" and pathname components added to it,
+ // without checking for the separator already being there.
+ // The script language and operating system may allow paths like "foo//bar"
+ // but some of the functions in FilePath will not handle that correctly. In
+ // particular, RemoveTrailingPathSeparator() only removes one separator, and
+ // it is called in CreateDirectoriesRecursively() assuming that it will change
+ // a pathname from directory syntax (trailing separator) to filename syntax.
+ //
+ // On Windows this method also replaces the alternate path separator '/' with
+ // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
+ // "bar\\foo".
+
+ void Normalize();
+
+ // Returns a pointer to the last occurence of a valid path separator in
+ // the FilePath. On Windows, for example, both '/' and '\' are valid path
+ // separators. Returns NULL if no path separator was found.
+ const char* FindLastPathSeparator() const;
+
+ String pathname_;
+}; // class FilePath
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+// This file was GENERATED by command:
+// pump.py gtest-type-util.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently we support at most 50 types in a list, and at most 50
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework@googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+
+// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+# ifdef __GLIBCXX__
+# include <cxxabi.h>
+# elif defined(__HP_aCC)
+# include <acxx_demangle.h>
+# endif // __GLIBCXX__
+
+namespace testing {
+namespace internal {
+
+// GetTypeName<T>() returns a human-readable name of type T.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+String GetTypeName() {
+# if GTEST_HAS_RTTI
+
+ const char* const name = typeid(T).name();
+# if defined(__GLIBCXX__) || defined(__HP_aCC)
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+# ifdef __GLIBCXX__
+ using abi::__cxa_demangle;
+# endif // __GLIBCXX__
+ char* const readable_name = __cxa_demangle(name, 0, 0, &status);
+ const String name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return name_str;
+# else
+ return name;
+# endif // __GLIBCXX__ || __HP_aCC
+
+# else
+
+ return "<type>";
+
+# endif // GTEST_HAS_RTTI
+}
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type. This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+ typedef bool type;
+};
+
+// A unique type used as the default value for the arguments of class
+// template Types. This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists. In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+ typedef T1 Head;
+ typedef Types0 Tail;
+};
+template <typename T1, typename T2>
+struct Types2 {
+ typedef T1 Head;
+ typedef Types1<T2> Tail;
+};
+
+template <typename T1, typename T2, typename T3>
+struct Types3 {
+ typedef T1 Head;
+ typedef Types2<T2, T3> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types4 {
+ typedef T1 Head;
+ typedef Types3<T2, T3, T4> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types5 {
+ typedef T1 Head;
+ typedef Types4<T2, T3, T4, T5> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types6 {
+ typedef T1 Head;
+ typedef Types5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types7 {
+ typedef T1 Head;
+ typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types8 {
+ typedef T1 Head;
+ typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types9 {
+ typedef T1 Head;
+ typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types10 {
+ typedef T1 Head;
+ typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types11 {
+ typedef T1 Head;
+ typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types12 {
+ typedef T1 Head;
+ typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types13 {
+ typedef T1 Head;
+ typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types14 {
+ typedef T1 Head;
+ typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types15 {
+ typedef T1 Head;
+ typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types16 {
+ typedef T1 Head;
+ typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types17 {
+ typedef T1 Head;
+ typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types18 {
+ typedef T1 Head;
+ typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types19 {
+ typedef T1 Head;
+ typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types20 {
+ typedef T1 Head;
+ typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types21 {
+ typedef T1 Head;
+ typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types22 {
+ typedef T1 Head;
+ typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types23 {
+ typedef T1 Head;
+ typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types24 {
+ typedef T1 Head;
+ typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types25 {
+ typedef T1 Head;
+ typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types26 {
+ typedef T1 Head;
+ typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types27 {
+ typedef T1 Head;
+ typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types28 {
+ typedef T1 Head;
+ typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types29 {
+ typedef T1 Head;
+ typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types30 {
+ typedef T1 Head;
+ typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types31 {
+ typedef T1 Head;
+ typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types32 {
+ typedef T1 Head;
+ typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types33 {
+ typedef T1 Head;
+ typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types34 {
+ typedef T1 Head;
+ typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types35 {
+ typedef T1 Head;
+ typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types36 {
+ typedef T1 Head;
+ typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types37 {
+ typedef T1 Head;
+ typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types38 {
+ typedef T1 Head;
+ typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types39 {
+ typedef T1 Head;
+ typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types40 {
+ typedef T1 Head;
+ typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types41 {
+ typedef T1 Head;
+ typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types42 {
+ typedef T1 Head;
+ typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types43 {
+ typedef T1 Head;
+ typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types44 {
+ typedef T1 Head;
+ typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types45 {
+ typedef T1 Head;
+ typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types46 {
+ typedef T1 Head;
+ typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types47 {
+ typedef T1 Head;
+ typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types48 {
+ typedef T1 Head;
+ typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types49 {
+ typedef T1 Head;
+ typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct Types50 {
+ typedef T1 Head;
+ typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+} // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length. Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Types template.
+template <typename T1 = internal::None, typename T2 = internal::None,
+ typename T3 = internal::None, typename T4 = internal::None,
+ typename T5 = internal::None, typename T6 = internal::None,
+ typename T7 = internal::None, typename T8 = internal::None,
+ typename T9 = internal::None, typename T10 = internal::None,
+ typename T11 = internal::None, typename T12 = internal::None,
+ typename T13 = internal::None, typename T14 = internal::None,
+ typename T15 = internal::None, typename T16 = internal::None,
+ typename T17 = internal::None, typename T18 = internal::None,
+ typename T19 = internal::None, typename T20 = internal::None,
+ typename T21 = internal::None, typename T22 = internal::None,
+ typename T23 = internal::None, typename T24 = internal::None,
+ typename T25 = internal::None, typename T26 = internal::None,
+ typename T27 = internal::None, typename T28 = internal::None,
+ typename T29 = internal::None, typename T30 = internal::None,
+ typename T31 = internal::None, typename T32 = internal::None,
+ typename T33 = internal::None, typename T34 = internal::None,
+ typename T35 = internal::None, typename T36 = internal::None,
+ typename T37 = internal::None, typename T38 = internal::None,
+ typename T39 = internal::None, typename T40 = internal::None,
+ typename T41 = internal::None, typename T42 = internal::None,
+ typename T43 = internal::None, typename T44 = internal::None,
+ typename T45 = internal::None, typename T46 = internal::None,
+ typename T47 = internal::None, typename T48 = internal::None,
+ typename T49 = internal::None, typename T50 = internal::None>
+struct Types {
+ typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Types<internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types0 type;
+};
+template <typename T1>
+struct Types<T1, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types1<T1> type;
+};
+template <typename T1, typename T2>
+struct Types<T1, T2, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types2<T1, T2> type;
+};
+template <typename T1, typename T2, typename T3>
+struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types3<T1, T2, T3> type;
+};
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types4<T1, T2, T3, T4> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types5<T1, T2, T3, T4, T5> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, internal::None, internal::None, internal::None> {
+ typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, internal::None, internal::None> {
+ typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, T49, internal::None> {
+ typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+namespace internal {
+
+# define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+# define GTEST_BIND_(TmplSel, T) \
+ TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates. This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists. In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN). Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates0 Tail;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates2 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates1<T2> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates3 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates2<T2, T3> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates4 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates3<T2, T3, T4> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates5 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates4<T2, T3, T4, T5> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates6 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates7 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates8 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates9 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates10 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates11 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates12 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates13 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates14 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates15 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates16 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates17 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates18 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates19 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates20 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates21 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates22 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates23 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates24 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates25 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates26 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates27 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates28 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates29 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates30 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates31 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates32 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates33 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates34 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates35 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates36 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates37 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates38 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates39 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates40 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates41 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates42 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates43 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates44 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates45 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates46 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates47 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates48 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates49 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
+struct Templates50 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length. Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Templates template.
+template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
+ GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
+ GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
+ GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
+ GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
+ GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
+ GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
+ GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
+ GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
+ GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
+ GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
+ GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
+ GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
+ GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
+ GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
+ GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
+ GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
+ GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
+ GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
+ GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
+ GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
+ GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
+ GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
+ GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
+ GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+struct Templates {
+ typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates0 type;
+};
+template <GTEST_TEMPLATE_ T1>
+struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates1<T1> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates2<T1, T2> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates3<T1, T2, T3> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates4<T1, T2, T3, T4> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates5<T1, T2, T3, T4, T5> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates6<T1, T2, T3, T4, T5, T6> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, NoneT, NoneT, NoneT> {
+ typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, NoneT, NoneT> {
+ typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, T49, NoneT> {
+ typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList { typedef Types1<T> type; };
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> > {
+ typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__. Writing
+//
+// foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number. For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+// Google Test defines the testing::Message class to allow construction of
+// test messages via the << operator. The idea is that anything
+// streamable to std::ostream can be streamed to a testing::Message.
+// This allows a user to use his own types in Google Test assertions by
+// overloading the << operator.
+//
+// util/gtl/stl_logging-inl.h overloads << for STL containers. These
+// overloads cannot be defined in the std namespace, as that will be
+// undefined behavior. Therefore, they are defined in the global
+// namespace instead.
+//
+// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+// overloads are visible in either the std namespace or the global
+// namespace, but not other namespaces, including the testing
+// namespace which Google Test's Message class is in.
+//
+// To allow STL containers (and other types that has a << operator
+// defined in the global namespace) to be used in Google Test assertions,
+// testing::Message must access the custom << operator from the global
+// namespace. Hence this helper function.
+//
+// Note: Jeffrey Yasskin suggested an alternative fix by "using
+// ::operator<<;" in the definition of Message's operator<<. That fix
+// doesn't require a helper function, but unfortunately doesn't
+// compile with MSVC.
+template <typename T>
+inline void GTestStreamToHelper(std::ostream* os, const T& val) {
+ *os << val;
+}
+
+class ProtocolMessage;
+namespace proto2 { class Message; }
+
+namespace testing {
+
+// Forward declarations.
+
+class AssertionResult; // Result of an assertion.
+class Message; // Represents a failure message.
+class Test; // Represents a test.
+class TestInfo; // Information about a test.
+class TestPartResult; // Result of a test part.
+class UnitTest; // A collection of test cases.
+
+template <typename T>
+::std::string PrintToString(const T& value);
+
+namespace internal {
+
+struct TraceInfo; // Information about a trace point.
+class ScopedTrace; // Implements scoped trace.
+class TestInfoImpl; // Opaque implementation of TestInfo
+class UnitTestImpl; // Opaque implementation of UnitTest
+
+// How many times InitGoogleTest() has been called.
+extern int g_init_gtest_count;
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+GTEST_API_ extern const char kStackTraceMarker[];
+
+// A secret type that Google Test users don't know about. It has no
+// definition on purpose. Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant). Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler. These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise. Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal. Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char (&IsNullLiteralHelper(...))[2]; // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef GTEST_ELLIPSIS_NEEDS_POD_
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_IS_NULL_LITERAL_(x) false
+#else
+# define GTEST_IS_NULL_LITERAL_(x) \
+ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif // GTEST_ELLIPSIS_NEEDS_POD_
+
+// Appends the user-supplied message to the Google-Test-generated message.
+GTEST_API_ String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg);
+
+// A helper class for creating scoped traces in user programs.
+class GTEST_API_ ScopedTrace {
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+ ScopedTrace(const char* file, int line, const Message& message);
+
+ // The d'tor pops the info pushed by the c'tor.
+ //
+ // Note that the d'tor is not virtual in order to be efficient.
+ // Don't inherit from ScopedTrace!
+ ~ScopedTrace();
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
+ // c'tor and d'tor. Therefore it doesn't
+ // need to be used otherwise.
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+// The Symbian compiler has a bug that prevents it from selecting the
+// correct overload of FormatForComparisonFailureMessage (see below)
+// unless we pass the first argument by reference. If we do that,
+// however, Visual Age C++ 10.1 generates a compiler error. Therefore
+// we only apply the work-around for Symbian.
+#if defined(__SYMBIAN32__)
+# define GTEST_CREF_WORKAROUND_ const&
+#else
+# define GTEST_CREF_WORKAROUND_
+#endif
+
+// When this operand is a const char* or char*, if the other operand
+// is a ::std::string or ::string, we print this operand as a C string
+// rather than a pointer (we do the same for wide strings); otherwise
+// we print it as a pointer to be safe.
+
+// This internal macro is used to avoid duplicated code.
+#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
+inline String FormatForComparisonFailureMessage(\
+ operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
+ const operand2_type& /*operand2*/) {\
+ return operand1_printer(str);\
+}\
+inline String FormatForComparisonFailureMessage(\
+ const operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
+ const operand2_type& /*operand2*/) {\
+ return operand1_printer(str);\
+}
+
+GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
+#if GTEST_HAS_STD_WSTRING
+GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_STRING
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#undef GTEST_FORMAT_IMPL_
+
+// The next four overloads handle the case where the operand being
+// printed is a char/wchar_t pointer and the other operand is not a
+// string/wstring object. In such cases, we just print the operand as
+// a pointer to be safe.
+#define GTEST_FORMAT_CHAR_PTR_IMPL_(CharType) \
+ template <typename T> \
+ String FormatForComparisonFailureMessage(CharType* GTEST_CREF_WORKAROUND_ p, \
+ const T&) { \
+ return PrintToString(static_cast<const void*>(p)); \
+ }
+
+GTEST_FORMAT_CHAR_PTR_IMPL_(char)
+GTEST_FORMAT_CHAR_PTR_IMPL_(const char)
+GTEST_FORMAT_CHAR_PTR_IMPL_(wchar_t)
+GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t)
+
+#undef GTEST_FORMAT_CHAR_PTR_IMPL_
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case);
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+GTEST_API_ String GetBoolAssertionFailureMessage(
+ const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value);
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison. (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly. Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+// The most-significant bit being the leftmost, an IEEE
+// floating-point looks like
+//
+// sign_bit exponent_bits fraction_bits
+//
+// Here, sign_bit is a single bit that designates the sign of the
+// number.
+//
+// For float, there are 8 exponent bits and 23 fraction bits.
+//
+// For double, there are 11 exponent bits and 52 fraction bits.
+//
+// More details can be found at
+// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+ // Defines the unsigned integer type that has the same size as the
+ // floating point number.
+ typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+ // Constants.
+
+ // # of bits in a number.
+ static const size_t kBitCount = 8*sizeof(RawType);
+
+ // # of fraction bits in a number.
+ static const size_t kFractionBitCount =
+ std::numeric_limits<RawType>::digits - 1;
+
+ // # of exponent bits in a number.
+ static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+ // The mask for the sign bit.
+ static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+ // The mask for the fraction bits.
+ static const Bits kFractionBitMask =
+ ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+ // The mask for the exponent bits.
+ static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+ // How many ULP's (Units in the Last Place) we want to tolerate when
+ // comparing two numbers. The larger the value, the more error we
+ // allow. A 0 value means that two numbers must be exactly the same
+ // to be considered equal.
+ //
+ // The maximum error of a single floating-point operation is 0.5
+ // units in the last place. On Intel CPU's, all floating-point
+ // calculations are done with 80-bit precision, while double has 64
+ // bits. Therefore, 4 should be enough for ordinary use.
+ //
+ // See the following article for more details on ULP:
+ // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
+ static const size_t kMaxUlps = 4;
+
+ // Constructs a FloatingPoint from a raw floating-point number.
+ //
+ // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+ // around may change its bits, although the new value is guaranteed
+ // to be also a NAN. Therefore, don't expect this constructor to
+ // preserve the bits in x when x is a NAN.
+ explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
+
+ // Static methods
+
+ // Reinterprets a bit pattern as a floating-point number.
+ //
+ // This function is needed to test the AlmostEquals() method.
+ static RawType ReinterpretBits(const Bits bits) {
+ FloatingPoint fp(0);
+ fp.u_.bits_ = bits;
+ return fp.u_.value_;
+ }
+
+ // Returns the floating-point number that represent positive infinity.
+ static RawType Infinity() {
+ return ReinterpretBits(kExponentBitMask);
+ }
+
+ // Non-static methods
+
+ // Returns the bits that represents this number.
+ const Bits &bits() const { return u_.bits_; }
+
+ // Returns the exponent bits of this number.
+ Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
+
+ // Returns the fraction bits of this number.
+ Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
+
+ // Returns the sign bit of this number.
+ Bits sign_bit() const { return kSignBitMask & u_.bits_; }
+
+ // Returns true iff this is NAN (not a number).
+ bool is_nan() const {
+ // It's a NAN if the exponent bits are all ones and the fraction
+ // bits are not entirely zeros.
+ return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+ }
+
+ // Returns true iff this number is at most kMaxUlps ULP's away from
+ // rhs. In particular, this function:
+ //
+ // - returns false if either number is (or both are) NAN.
+ // - treats really large numbers as almost equal to infinity.
+ // - thinks +0.0 and -0.0 are 0 DLP's apart.
+ bool AlmostEquals(const FloatingPoint& rhs) const {
+ // The IEEE standard says that any comparison operation involving
+ // a NAN must return false.
+ if (is_nan() || rhs.is_nan()) return false;
+
+ return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
+ <= kMaxUlps;
+ }
+
+ private:
+ // The data type used to store the actual floating-point number.
+ union FloatingPointUnion {
+ RawType value_; // The raw floating-point number.
+ Bits bits_; // The bits that represent the number.
+ };
+
+ // Converts an integer from the sign-and-magnitude representation to
+ // the biased representation. More precisely, let N be 2 to the
+ // power of (kBitCount - 1), an integer x is represented by the
+ // unsigned number x + N.
+ //
+ // For instance,
+ //
+ // -N + 1 (the most negative number representable using
+ // sign-and-magnitude) is represented by 1;
+ // 0 is represented by N; and
+ // N - 1 (the biggest number representable using
+ // sign-and-magnitude) is represented by 2N - 1.
+ //
+ // Read http://en.wikipedia.org/wiki/Signed_number_representations
+ // for more details on signed number representations.
+ static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+ if (kSignBitMask & sam) {
+ // sam represents a negative number.
+ return ~sam + 1;
+ } else {
+ // sam represents a positive number.
+ return kSignBitMask | sam;
+ }
+ }
+
+ // Given two numbers in the sign-and-magnitude representation,
+ // returns the distance between them as an unsigned number.
+ static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+ const Bits &sam2) {
+ const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+ const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+ return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+ }
+
+ FloatingPointUnion u_;
+};
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them. The TypeId type is
+// used to hold such IDs. The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper {
+ public:
+ // dummy_ must not have a const type. Otherwise an overly eager
+ // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+ // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+ static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T. Different values will be
+// returned for different types. Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId() {
+ // The compiler is required to allocate a different
+ // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+ // the template. Therefore, the address of dummy_ is guaranteed to
+ // be unique.
+ return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test. Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+GTEST_API_ TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase {
+ public:
+ virtual ~TestFactoryBase() {}
+
+ // Creates a test instance to run. The instance is both created and destroyed
+ // within TestInfoImpl::Run()
+ virtual Test* CreateTest() = 0;
+
+ protected:
+ TestFactoryBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+ virtual Test* CreateTest() { return new TestClass; }
+};
+
+#if GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
+ long hr); // NOLINT
+GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
+ long hr); // NOLINT
+
+#endif // GTEST_OS_WINDOWS
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// type_param the name of the test's type parameter, or NULL if
+// this is not a typed or a type-parameterized test.
+// value_param text representation of the test's value parameter,
+// or NULL if this is not a type-parameterized test.
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* type_param,
+ const char* value_param,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory);
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// State of the definition of a type-parameterized test case.
+class GTEST_API_ TypedTestCasePState {
+ public:
+ TypedTestCasePState() : registered_(false) {}
+
+ // Adds the given test name to defined_test_names_ and return true
+ // if the test case hasn't been registered; otherwise aborts the
+ // program.
+ bool AddTestName(const char* file, int line, const char* case_name,
+ const char* test_name) {
+ if (registered_) {
+ fprintf(stderr, "%s Test %s must be defined before "
+ "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+ FormatFileLocation(file, line).c_str(), test_name, case_name);
+ fflush(stderr);
+ posix::Abort();
+ }
+ defined_test_names_.insert(test_name);
+ return true;
+ }
+
+ // Verifies that registered_tests match the test names in
+ // defined_test_names_; returns registered_tests if successful, or
+ // aborts the program otherwise.
+ const char* VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests);
+
+ private:
+ bool registered_;
+ ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ if (comma == NULL) {
+ return NULL;
+ }
+ while (IsSpace(*(++comma))) {}
+ return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline String GetPrefixUntilComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ return comma == NULL ? String(str) : String(str, comma - str);
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test. The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter. It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+ // 'index' is the index of the test in the type list 'Types'
+ // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+ // Types). Valid values for 'index' are [0, N - 1] where N is the
+ // length of Types.
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names, int index) {
+ typedef typename Types::Head Type;
+ typedef Fixture<Type> FixtureClass;
+ typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+ // First, registers the first type-parameterized test in the type
+ // list.
+ MakeAndRegisterTestInfo(
+ String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",
+ case_name, index).c_str(),
+ GetPrefixUntilComma(test_names).c_str(),
+ GetTypeName<Type>().c_str(),
+ NULL, // No value parameter.
+ GetTypeId<FixtureClass>(),
+ TestClass::SetUpTestCase,
+ TestClass::TearDownTestCase,
+ new TestFactoryImpl<TestClass>);
+
+ // Next, recurses (at compile time) with the tail of the type list.
+ return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
+ ::Register(prefix, case_name, test_names, index + 1);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0> {
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/, int /*index*/) {
+ return true;
+ }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test. The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase {
+ public:
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names) {
+ typedef typename Tests::Head Head;
+
+ // First, register the first test in 'Test' for each type in 'Types'.
+ TypeParameterizedTest<Fixture, Head, Types>::Register(
+ prefix, case_name, test_names, 0);
+
+ // Next, recurses (at compile time) with the tail of the test list.
+ return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+ ::Register(prefix, case_name, SkipComma(test_names));
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/) {
+ return true;
+ }
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test,
+ int skip_count);
+
+// Helpers for suppressing warnings on unreachable code or constant
+// condition.
+
+// Always returns true.
+GTEST_API_ bool AlwaysTrue();
+
+// Always returns false.
+inline bool AlwaysFalse() { return !AlwaysTrue(); }
+
+// Helper for suppressing false warning from Clang on a const char*
+// variable declared in a conditional expression always being NULL in
+// the else branch.
+struct GTEST_API_ ConstCharPtr {
+ ConstCharPtr(const char* str) : value(str) {}
+ operator bool() const { return true; }
+ const char* value;
+};
+
+// A simple Linear Congruential Generator for generating random
+// numbers with a uniform distribution. Unlike rand() and srand(), it
+// doesn't use global state (and therefore can't interfere with user
+// code). Unlike rand_r(), it's portable. An LCG isn't very random,
+// but it's good enough for our purposes.
+class GTEST_API_ Random {
+ public:
+ static const UInt32 kMaxRange = 1u << 31;
+
+ explicit Random(UInt32 seed) : state_(seed) {}
+
+ void Reseed(UInt32 seed) { state_ = seed; }
+
+ // Generates a random number from [0, range). Crashes if 'range' is
+ // 0 or greater than kMaxRange.
+ UInt32 Generate(UInt32 range);
+
+ private:
+ UInt32 state_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
+};
+
+// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
+// compiler error iff T1 and T2 are different types.
+template <typename T1, typename T2>
+struct CompileAssertTypesEqual;
+
+template <typename T>
+struct CompileAssertTypesEqual<T, T> {
+};
+
+// Removes the reference from a type if it is a reference type,
+// otherwise leaves it unchanged. This is the same as
+// tr1::remove_reference, which is not widely available yet.
+template <typename T>
+struct RemoveReference { typedef T type; }; // NOLINT
+template <typename T>
+struct RemoveReference<T&> { typedef T type; }; // NOLINT
+
+// A handy wrapper around RemoveReference that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_REFERENCE_(T) \
+ typename ::testing::internal::RemoveReference<T>::type
+
+// Removes const from a type if it is a const type, otherwise leaves
+// it unchanged. This is the same as tr1::remove_const, which is not
+// widely available yet.
+template <typename T>
+struct RemoveConst { typedef T type; }; // NOLINT
+template <typename T>
+struct RemoveConst<const T> { typedef T type; }; // NOLINT
+
+// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
+// definition to fail to remove the const in 'const int[3]' and 'const
+// char[3][4]'. The following specialization works around the bug.
+// However, it causes trouble with GCC and thus needs to be
+// conditionally compiled.
+#if defined(_MSC_VER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
+template <typename T, size_t N>
+struct RemoveConst<const T[N]> {
+ typedef typename RemoveConst<T>::type type[N];
+};
+#endif
+
+// A handy wrapper around RemoveConst that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_CONST_(T) \
+ typename ::testing::internal::RemoveConst<T>::type
+
+// Turns const U&, U&, const U, and U all into U.
+#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
+ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))
+
+// Adds reference to a type if it is not a reference type,
+// otherwise leaves it unchanged. This is the same as
+// tr1::add_reference, which is not widely available yet.
+template <typename T>
+struct AddReference { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddReference<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper around AddReference that works when the argument T
+// depends on template parameters.
+#define GTEST_ADD_REFERENCE_(T) \
+ typename ::testing::internal::AddReference<T>::type
+
+// Adds a reference to const on top of T as necessary. For example,
+// it transforms
+//
+// char ==> const char&
+// const char ==> const char&
+// char& ==> const char&
+// const char& ==> const char&
+//
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T))
+
+// ImplicitlyConvertible<From, To>::value is a compile-time bool
+// constant that's true iff type From can be implicitly converted to
+// type To.
+template <typename From, typename To>
+class ImplicitlyConvertible {
+ private:
+ // We need the following helper functions only for their types.
+ // They have no implementations.
+
+ // MakeFrom() is an expression whose type is From. We cannot simply
+ // use From(), as the type From may not have a public default
+ // constructor.
+ static From MakeFrom();
+
+ // These two functions are overloaded. Given an expression
+ // Helper(x), the compiler will pick the first version if x can be
+ // implicitly converted to type To; otherwise it will pick the
+ // second version.
+ //
+ // The first version returns a value of size 1, and the second
+ // version returns a value of size 2. Therefore, by checking the
+ // size of Helper(x), which can be done at compile time, we can tell
+ // which version of Helper() is used, and hence whether x can be
+ // implicitly converted to type To.
+ static char Helper(To);
+ static char (&Helper(...))[2]; // NOLINT
+
+ // We have to put the 'public' section after the 'private' section,
+ // or MSVC refuses to compile the code.
+ public:
+ // MSVC warns about implicitly converting from double to int for
+ // possible loss of data, so we need to temporarily disable the
+ // warning.
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4244) // Temporarily disables warning 4244.
+
+ static const bool value =
+ sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+# pragma warning(pop) // Restores the warning state.
+#elif defined(__BORLANDC__)
+ // C++Builder cannot use member overload resolution during template
+ // instantiation. The simplest workaround is to use its C++0x type traits
+ // functions (C++Builder 2009 and above only).
+ static const bool value = __is_convertible(From, To);
+#else
+ static const bool value =
+ sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+#endif // _MSV_VER
+};
+template <typename From, typename To>
+const bool ImplicitlyConvertible<From, To>::value;
+
+// IsAProtocolMessage<T>::value is a compile-time bool constant that's
+// true iff T is type ProtocolMessage, proto2::Message, or a subclass
+// of those.
+template <typename T>
+struct IsAProtocolMessage
+ : public bool_constant<
+ ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
+ ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
+};
+
+// When the compiler sees expression IsContainerTest<C>(0), if C is an
+// STL-style container class, the first overload of IsContainerTest
+// will be viable (since both C::iterator* and C::const_iterator* are
+// valid types and NULL can be implicitly converted to them). It will
+// be picked over the second overload as 'int' is a perfect match for
+// the type of argument 0. If C::iterator or C::const_iterator is not
+// a valid type, the first overload is not viable, and the second
+// overload will be picked. Therefore, we can determine whether C is
+// a container class by checking the type of IsContainerTest<C>(0).
+// The value of the expression is insignificant.
+//
+// Note that we look for both C::iterator and C::const_iterator. The
+// reason is that C++ injects the name of a class as a member of the
+// class itself (e.g. you can refer to class iterator as either
+// 'iterator' or 'iterator::iterator'). If we look for C::iterator
+// only, for example, we would mistakenly think that a class named
+// iterator is an STL container.
+//
+// Also note that the simpler approach of overloading
+// IsContainerTest(typename C::const_iterator*) and
+// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
+typedef int IsContainer;
+template <class C>
+IsContainer IsContainerTest(int /* dummy */,
+ typename C::iterator* /* it */ = NULL,
+ typename C::const_iterator* /* const_it */ = NULL) {
+ return 0;
+}
+
+typedef char IsNotContainer;
+template <class C>
+IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
+
+// EnableIf<condition>::type is void when 'Cond' is true, and
+// undefined when 'Cond' is false. To use SFINAE to make a function
+// overload only apply when a particular expression is true, add
+// "typename EnableIf<expression>::type* = 0" as the last parameter.
+template<bool> struct EnableIf;
+template<> struct EnableIf<true> { typedef void type; }; // NOLINT
+
+// Utilities for native arrays.
+
+// ArrayEq() compares two k-dimensional native arrays using the
+// elements' operator==, where k can be any integer >= 0. When k is
+// 0, ArrayEq() degenerates into comparing a single pair of values.
+
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
+ return internal::ArrayEq(lhs, N, rhs);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous ArrayEq() function, arrays with different sizes would
+// lead to different copies of the template code.
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
+ for (size_t i = 0; i != size; i++) {
+ if (!internal::ArrayEq(lhs[i], rhs[i]))
+ return false;
+ }
+ return true;
+}
+
+// Finds the first element in the iterator range [begin, end) that
+// equals elem. Element may be a native array type itself.
+template <typename Iter, typename Element>
+Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
+ for (Iter it = begin; it != end; ++it) {
+ if (internal::ArrayEq(*it, elem))
+ return it;
+ }
+ return end;
+}
+
+// CopyArray() copies a k-dimensional native array using the elements'
+// operator=, where k can be any integer >= 0. When k is 0,
+// CopyArray() degenerates into copying a single value.
+
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline void CopyArray(const T& from, U* to) { *to = from; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline void CopyArray(const T(&from)[N], U(*to)[N]) {
+ internal::CopyArray(from, N, *to);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous CopyArray() function, arrays with different sizes
+// would lead to different copies of the template code.
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to) {
+ for (size_t i = 0; i != size; i++) {
+ internal::CopyArray(from[i], to + i);
+ }
+}
+
+// The relation between an NativeArray object (see below) and the
+// native array it represents.
+enum RelationToSource {
+ kReference, // The NativeArray references the native array.
+ kCopy // The NativeArray makes a copy of the native array and
+ // owns the copy.
+};
+
+// Adapts a native array to a read-only STL-style container. Instead
+// of the complete STL container concept, this adaptor only implements
+// members useful for Google Mock's container matchers. New members
+// should be added as needed. To simplify the implementation, we only
+// support Element being a raw type (i.e. having no top-level const or
+// reference modifier). It's the client's responsibility to satisfy
+// this requirement. Element can be an array type itself (hence
+// multi-dimensional arrays are supported).
+template <typename Element>
+class NativeArray {
+ public:
+ // STL-style container typedefs.
+ typedef Element value_type;
+ typedef Element* iterator;
+ typedef const Element* const_iterator;
+
+ // Constructs from a native array.
+ NativeArray(const Element* array, size_t count, RelationToSource relation) {
+ Init(array, count, relation);
+ }
+
+ // Copy constructor.
+ NativeArray(const NativeArray& rhs) {
+ Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
+ }
+
+ ~NativeArray() {
+ // Ensures that the user doesn't instantiate NativeArray with a
+ // const or reference type.
+ static_cast<void>(StaticAssertTypeEqHelper<Element,
+ GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
+ if (relation_to_source_ == kCopy)
+ delete[] array_;
+ }
+
+ // STL-style container methods.
+ size_t size() const { return size_; }
+ const_iterator begin() const { return array_; }
+ const_iterator end() const { return array_ + size_; }
+ bool operator==(const NativeArray& rhs) const {
+ return size() == rhs.size() &&
+ ArrayEq(begin(), size(), rhs.begin());
+ }
+
+ private:
+ // Initializes this object; makes a copy of the input array if
+ // 'relation' is kCopy.
+ void Init(const Element* array, size_t a_size, RelationToSource relation) {
+ if (relation == kReference) {
+ array_ = array;
+ } else {
+ Element* const copy = new Element[a_size];
+ CopyArray(array, a_size, copy);
+ array_ = copy;
+ }
+ size_ = a_size;
+ relation_to_source_ = relation;
+ }
+
+ const Element* array_;
+ size_t size_;
+ RelationToSource relation_to_source_;
+
+ GTEST_DISALLOW_ASSIGN_(NativeArray);
+};
+
+} // namespace internal
+} // namespace testing
+
+#define GTEST_MESSAGE_AT_(file, line, message, result_type) \
+ ::testing::internal::AssertHelper(result_type, file, line, message) \
+ = ::testing::Message()
+
+#define GTEST_MESSAGE_(message, result_type) \
+ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type)
+
+#define GTEST_FATAL_FAILURE_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
+
+#define GTEST_SUCCESS_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
+
+// Suppresses MSVC warnings 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
+ if (::testing::internal::AlwaysTrue()) { statement; }
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::ConstCharPtr gtest_msg = "") { \
+ bool gtest_caught_expected = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (expected_exception const&) { \
+ gtest_caught_expected = true; \
+ } \
+ catch (...) { \
+ gtest_msg.value = \
+ "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws a different type."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ if (!gtest_caught_expected) { \
+ gtest_msg.value = \
+ "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws nothing."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+ fail(gtest_msg.value)
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (...) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+ fail("Expected: " #statement " doesn't throw an exception.\n" \
+ " Actual: it throws.")
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ bool gtest_caught_any = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (...) { \
+ gtest_caught_any = true; \
+ } \
+ if (!gtest_caught_any) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+ fail("Expected: " #statement " throws an exception.\n" \
+ " Actual: it doesn't.")
+
+
+// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
+// either a boolean expression or an AssertionResult. text is a textual
+// represenation of expression as it was passed into the EXPECT_TRUE.
+#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar_ = \
+ ::testing::AssertionResult(expression)) \
+ ; \
+ else \
+ fail(::testing::internal::GetBoolAssertionFailureMessage(\
+ gtest_ar_, text, #actual, #expected).c_str())
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+ fail("Expected: " #statement " doesn't generate new fatal " \
+ "failures in the current thread.\n" \
+ " Actual: it does.")
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ test_case_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ private:\
+ virtual void TestBody();\
+ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+ ::test_info_ =\
+ ::testing::internal::MakeAndRegisterTestInfo(\
+ #test_case_name, #test_name, NULL, NULL, \
+ (parent_id), \
+ parent_class::SetUpTestCase, \
+ parent_class::TearDownTestCase, \
+ new ::testing::internal::TestFactoryImpl<\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests. It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+
+#include <stdio.h>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kDeathTestUseFork[] = "death_test_use_fork";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#if GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status: The integer exit information in the format specified
+// by wait(2)
+// exit code: The integer code passed to exit(3), _exit(2), or
+// returned from main()
+class GTEST_API_ DeathTest {
+ public:
+ // Create returns false if there was an error determining the
+ // appropriate action to take for the current death test; for example,
+ // if the gtest_death_test_style flag is set to an invalid value.
+ // The LastMessage method will return a more detailed message in that
+ // case. Otherwise, the DeathTest pointer pointed to by the "test"
+ // argument is set. If the death test should be skipped, the pointer
+ // is set to NULL; otherwise, it is set to the address of a new concrete
+ // DeathTest object that controls the execution of the current test.
+ static bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+ DeathTest();
+ virtual ~DeathTest() { }
+
+ // A helper class that aborts a death test when it's deleted.
+ class ReturnSentinel {
+ public:
+ explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+ ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+ private:
+ DeathTest* const test_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+ } GTEST_ATTRIBUTE_UNUSED_;
+
+ // An enumeration of possible roles that may be taken when a death
+ // test is encountered. EXECUTE means that the death test logic should
+ // be executed immediately. OVERSEE means that the program should prepare
+ // the appropriate environment for a child process to execute the death
+ // test, then wait for it to complete.
+ enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+ // An enumeration of the three reasons that a test might be aborted.
+ enum AbortReason {
+ TEST_ENCOUNTERED_RETURN_STATEMENT,
+ TEST_THREW_EXCEPTION,
+ TEST_DID_NOT_DIE
+ };
+
+ // Assumes one of the above roles.
+ virtual TestRole AssumeRole() = 0;
+
+ // Waits for the death test to finish and returns its status.
+ virtual int Wait() = 0;
+
+ // Returns true if the death test passed; that is, the test process
+ // exited during the test, its exit status matches a user-supplied
+ // predicate, and its stderr output matches a user-supplied regular
+ // expression.
+ // The user-supplied predicate may be a macro expression rather
+ // than a function pointer or functor, or else Wait and Passed could
+ // be combined.
+ virtual bool Passed(bool exit_status_ok) = 0;
+
+ // Signals that the death test did not die as expected.
+ virtual void Abort(AbortReason reason) = 0;
+
+ // Returns a human-readable outcome message regarding the outcome of
+ // the last death test.
+ static const char* LastMessage();
+
+ static void set_last_death_test_message(const String& message);
+
+ private:
+ // A string containing a description of the outcome of the last death test.
+ static String last_death_test_message_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+// Factory interface for death tests. May be mocked out for testing.
+class DeathTestFactory {
+ public:
+ virtual ~DeathTestFactory() { }
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
+
+// Traps C++ exceptions escaping statement and reports them as test
+// failures. Note that trapping SEH exceptions is not implemented here.
+# if GTEST_HAS_EXCEPTIONS
+# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (const ::std::exception& gtest_exception) { \
+ fprintf(\
+ stderr, \
+ "\n%s: Caught std::exception-derived exception escaping the " \
+ "death test statement. Exception message: %s\n", \
+ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
+ gtest_exception.what()); \
+ fflush(stderr); \
+ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+ } catch (...) { \
+ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+ }
+
+# else
+# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+
+# endif
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ const ::testing::internal::RE& gtest_regex = (regex); \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
+ __FILE__, __LINE__, >est_dt)) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != NULL) { \
+ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+ gtest_dt_ptr(gtest_dt); \
+ switch (gtest_dt->AssumeRole()) { \
+ case ::testing::internal::DeathTest::OVERSEE_TEST: \
+ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ break; \
+ case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+ ::testing::internal::DeathTest::ReturnSentinel \
+ gtest_sentinel(gtest_dt); \
+ GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
+ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+ break; \
+ } \
+ default: \
+ break; \
+ } \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
+ fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// A class representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+class InternalRunDeathTestFlag {
+ public:
+ InternalRunDeathTestFlag(const String& a_file,
+ int a_line,
+ int an_index,
+ int a_write_fd)
+ : file_(a_file), line_(a_line), index_(an_index),
+ write_fd_(a_write_fd) {}
+
+ ~InternalRunDeathTestFlag() {
+ if (write_fd_ >= 0)
+ posix::Close(write_fd_);
+ }
+
+ String file() const { return file_; }
+ int line() const { return line_; }
+ int index() const { return index_; }
+ int write_fd() const { return write_fd_; }
+
+ private:
+ String file_;
+ int line_;
+ int index_;
+ int write_fd_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#else // GTEST_HAS_DEATH_TEST
+
+// This macro is used for implementing macros such as
+// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
+// death tests are not supported. Those macros must compile on such systems
+// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
+// systems that support death tests. This allows one to write such a macro
+// on a system that does not support death tests and be sure that it will
+// compile on a death-test supporting system.
+//
+// Parameters:
+// statement - A statement that a macro such as EXPECT_DEATH would test
+// for program termination. This macro has to make sure this
+// statement is compiled but not executed, to ensure that
+// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
+// parameter iff EXPECT_DEATH compiles with it.
+// regex - A regex that a macro such as EXPECT_DEATH would use to test
+// the output of statement. This parameter has to be
+// compiled but not evaluated by this macro, to ensure that
+// this macro only accepts expressions that a macro such as
+// EXPECT_DEATH would accept.
+// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
+// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
+// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
+// compile inside functions where ASSERT_DEATH doesn't
+// compile.
+//
+// The branch that has an always false condition is used to ensure that
+// statement and regex are compiled (and thus syntactically correct) but
+// never executed. The unreachable code macro protects the terminator
+// statement from generating an 'unreachable code' warning in case
+// statement unconditionally returns or throws. The Message constructor at
+// the end allows the syntax of streaming additional messages into the
+// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
+# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_LOG_(WARNING) \
+ << "Death tests are not supported on this platform.\n" \
+ << "Statement '" #statement "' cannot be verified."; \
+ } else if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::RE::PartialMatch(".*", (regex)); \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ terminator; \
+ } else \
+ ::testing::Message()
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+namespace testing {
+
+// This flag controls the style of death tests. Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#if GTEST_HAS_DEATH_TEST
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+// 1. It generates a warning if there is more than one active
+// thread. This is because it's safe to fork() or clone() only
+// when there is a single thread.
+//
+// 2. The parent process clone()s a sub-process and runs the death
+// test in it; the sub-process exits with code 0 at the end of the
+// death test, if it hasn't exited already.
+//
+// 3. The parent process waits for the sub-process to terminate.
+//
+// 4. The parent process checks the exit code and error message of
+// the sub-process.
+//
+// Examples:
+//
+// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+// for (int i = 0; i < 5; i++) {
+// EXPECT_DEATH(server.ProcessRequest(i),
+// "Invalid request .* in ProcessRequest()")
+// << "Failed to die on request " << i);
+// }
+//
+// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+// bool KilledBySIGHUP(int exit_code) {
+// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+// }
+//
+// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// On the regular expressions used in death tests:
+//
+// On POSIX-compliant systems (*nix), we use the <regex.h> library,
+// which uses the POSIX extended regex syntax.
+//
+// On other platforms (e.g. Windows), we only support a simple regex
+// syntax implemented as part of Google Test. This limited
+// implementation should be enough most of the time when writing
+// death tests; though it lacks many features you can find in PCRE
+// or POSIX extended regex syntax. For example, we don't support
+// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
+// repetition count ("x{5,7}"), among others.
+//
+// Below is the syntax that we do support. We chose it to be a
+// subset of both PCRE and POSIX extended regex, so it's easy to
+// learn wherever you come from. In the following: 'A' denotes a
+// literal character, period (.), or a single \\ escape sequence;
+// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
+// natural numbers.
+//
+// c matches any literal character c
+// \\d matches any decimal digit
+// \\D matches any character that's not a decimal digit
+// \\f matches \f
+// \\n matches \n
+// \\r matches \r
+// \\s matches any ASCII whitespace, including \n
+// \\S matches any character that's not a whitespace
+// \\t matches \t
+// \\v matches \v
+// \\w matches any letter, _, or decimal digit
+// \\W matches any character that \\w doesn't match
+// \\c matches any literal character c, which must be a punctuation
+// . matches any single character except \n
+// A? matches 0 or 1 occurrences of A
+// A* matches 0 or many occurrences of A
+// A+ matches 1 or many occurrences of A
+// ^ matches the beginning of a string (not that of each line)
+// $ matches the end of a string (not that of each line)
+// xy matches x followed by y
+//
+// If you accidentally use PCRE or POSIX extended regex features
+// not implemented by us, you will get a run-time failure. In that
+// case, please try to rewrite your regular expression within the
+// above syntax.
+//
+// This implementation is *not* meant to be as highly tuned or robust
+// as a compiled regex library, but should perform well enough for a
+// death test, which already incurs significant overhead by launching
+// a child process.
+//
+// Known caveats:
+//
+// A "threadsafe" style death test obtains the path to the test
+// program from argv[0] and re-executes it in the sub-process. For
+// simplicity, the current implementation doesn't search the PATH
+// when launching the sub-process. This means that the user must
+// invoke the test program via a path that contains at least one
+// path separator (e.g. path/to/foo_test and
+// /absolute/path/to/bar_test are fine, but foo_test is not). This
+// is rarely a problem as people usually don't put the test binary
+// directory in PATH.
+//
+// TODO(wan@google.com): make thread-safe death tests search the PATH.
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+# define ASSERT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+# define ASSERT_DEATH(statement, regex) \
+ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_DEATH(statement, regex) \
+ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class GTEST_API_ ExitedWithCode {
+ public:
+ explicit ExitedWithCode(int exit_code);
+ bool operator()(int exit_status) const;
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ExitedWithCode& other);
+
+ const int exit_code_;
+};
+
+# if !GTEST_OS_WINDOWS
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class GTEST_API_ KilledBySignal {
+ public:
+ explicit KilledBySignal(int signum);
+ bool operator()(int exit_status) const;
+ private:
+ const int signum_;
+};
+# endif // !GTEST_OS_WINDOWS
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+// if (sideeffect) {
+// *sideeffect = 12;
+// }
+// LOG(DFATAL) << "death";
+// return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+// int sideeffect = 0;
+// // Only asserts in dbg.
+// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+// // opt-mode has sideeffect visible.
+// EXPECT_EQ(12, sideeffect);
+// #else
+// // dbg-mode no visible sideeffect.
+// EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects. A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+// // Side-effects here will have an effect after this statement in
+// // opt mode, but none in debug mode.
+// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+# ifdef NDEBUG
+
+# define EXPECT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (::testing::internal::AlwaysFalse())
+
+# define ASSERT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (::testing::internal::AlwaysFalse())
+
+# else
+
+# define EXPECT_DEBUG_DEATH(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+
+# define ASSERT_DEBUG_DEATH(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+
+# endif // NDEBUG for EXPECT_DEBUG_DEATH
+#endif // GTEST_HAS_DEATH_TEST
+
+// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
+// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
+// death tests are supported; otherwise they just issue a warning. This is
+// useful when you are combining death test assertions with normal test
+// assertions in one test.
+#if GTEST_HAS_DEATH_TEST
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+#else
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
+#endif
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <limits>
+
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+// 1. You stream a bunch of values to a Message object.
+// It will remember the text in a stringstream.
+// 2. Then you stream the Message object to an ostream.
+// This causes the text in the Message to be streamed
+// to the ostream.
+//
+// For example;
+//
+// testing::Message foo;
+// foo << 1 << " != " << 2;
+// std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from. In particular, its
+// destructor is not virtual.
+//
+// Note that stringstream behaves differently in gcc and in MSVC. You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do). The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class GTEST_API_ Message {
+ private:
+ // The type of basic IO manipulators (endl, ends, and flush) for
+ // narrow streams.
+ typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+ // Constructs an empty Message.
+ // We allocate the stringstream separately because otherwise each use of
+ // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+ // stack frame leading to huge stack frames in some cases; gcc does not reuse
+ // the stack space.
+ Message() : ss_(new ::std::stringstream) {
+ // By default, we want there to be enough precision when printing
+ // a double to a Message.
+ *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
+ }
+
+ // Copy constructor.
+ Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
+ *ss_ << msg.GetString();
+ }
+
+ // Constructs a Message from a C-string.
+ explicit Message(const char* str) : ss_(new ::std::stringstream) {
+ *ss_ << str;
+ }
+
+#if GTEST_OS_SYMBIAN
+ // Streams a value (either a pointer or not) to this object.
+ template <typename T>
+ inline Message& operator <<(const T& value) {
+ StreamHelper(typename internal::is_pointer<T>::type(), value);
+ return *this;
+ }
+#else
+ // Streams a non-pointer value to this object.
+ template <typename T>
+ inline Message& operator <<(const T& val) {
+ ::GTestStreamToHelper(ss_.get(), val);
+ return *this;
+ }
+
+ // Streams a pointer value to this object.
+ //
+ // This function is an overload of the previous one. When you
+ // stream a pointer to a Message, this definition will be used as it
+ // is more specialized. (The C++ Standard, section
+ // [temp.func.order].) If you stream a non-pointer, then the
+ // previous definition will be used.
+ //
+ // The reason for this overload is that streaming a NULL pointer to
+ // ostream is undefined behavior. Depending on the compiler, you
+ // may get "0", "(nil)", "(null)", or an access violation. To
+ // ensure consistent result across compilers, we always treat NULL
+ // as "(null)".
+ template <typename T>
+ inline Message& operator <<(T* const& pointer) { // NOLINT
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_.get(), pointer);
+ }
+ return *this;
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // Since the basic IO manipulators are overloaded for both narrow
+ // and wide streams, we have to provide this specialized definition
+ // of operator <<, even though its body is the same as the
+ // templatized version above. Without this definition, streaming
+ // endl or other basic IO manipulators to Message will confuse the
+ // compiler.
+ Message& operator <<(BasicNarrowIoManip val) {
+ *ss_ << val;
+ return *this;
+ }
+
+ // Instead of 1/0, we want to see true/false for bool values.
+ Message& operator <<(bool b) {
+ return *this << (b ? "true" : "false");
+ }
+
+ // These two overloads allow streaming a wide C string to a Message
+ // using the UTF-8 encoding.
+ Message& operator <<(const wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+ Message& operator <<(wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+
+#if GTEST_HAS_STD_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::std::wstring& wstr);
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::wstring& wstr);
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+ // Gets the text streamed to this object so far as a String.
+ // Each '\0' character in the buffer is replaced with "\\0".
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::String GetString() const {
+ return internal::StringStreamToString(ss_.get());
+ }
+
+ private:
+
+#if GTEST_OS_SYMBIAN
+ // These are needed as the Nokia Symbian Compiler cannot decide between
+ // const T& and const T* in a function template. The Nokia compiler _can_
+ // decide between class template specializations for T and T*, so a
+ // tr1::type_traits-like is_pointer works, and we can overload on that.
+ template <typename T>
+ inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) {
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_.get(), pointer);
+ }
+ }
+ template <typename T>
+ inline void StreamHelper(internal::false_type /*dummy*/, const T& value) {
+ ::GTestStreamToHelper(ss_.get(), value);
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // We'll hold the text streamed to this object here.
+ const internal::scoped_ptr< ::std::stringstream> ss_;
+
+ // We declare (but don't implement) this to prevent the compiler
+ // from implementing the assignment operator.
+ void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+ return os << sb.GetString();
+}
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+// This file was GENERATED by command:
+// pump.py gtest-param-test.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It is usually derived from testing::TestWithParam<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> is itself derived from testing::Test. T can be any
+// copyable type. If it's a raw pointer, you are responsible for managing the
+// lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+ // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+ // Inside a test, access the test parameter with the GetParam() method
+ // of the TestWithParam<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a summary of them, which
+// are all in the testing namespace:
+//
+//
+// Range(begin, end [, step]) - Yields values {begin, begin+step,
+// begin+step+step, ...}. The values do not
+// include end. step defaults to 1.
+// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
+// ValuesIn(container) - Yields values from a C-style array, an STL
+// ValuesIn(begin,end) container, or an iterator range [begin, end).
+// Bool() - Yields sequence {false, true}.
+// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
+// for the math savvy) of the values generated
+// by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+// * InstantiationName/FooTest.DoesBlah/1 for "miny"
+// * InstantiationName/FooTest.DoesBlah/2 for "moe"
+// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+//
+//
+// A parameterized test fixture must be derived from testing::Test and from
+// testing::WithParamInterface<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> inherits from both Test and WithParamInterface. In more
+// complicated hierarchies, however, it is occasionally useful to inherit
+// separately from Test and WithParamInterface. For example:
+
+class BaseTest : public ::testing::Test {
+ // You can inherit all the usual members for a non-parameterized test
+ // fixture here.
+};
+
+class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
+ // The usual test fixture members go here too.
+};
+
+TEST_F(BaseTest, HasFoo) {
+ // This is an ordinary non-parameterized test.
+}
+
+TEST_P(DerivedTest, DoesBlah) {
+ // GetParam works just the same here as if you inherit from TestWithParam.
+ EXPECT_TRUE(foo.Blah(GetParam()));
+}
+
+#endif // 0
+
+
+#if !GTEST_OS_SYMBIAN
+# include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+// Copyright 2003 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor@google.com)
+//
+// A "smart" pointer type with reference tracking. Every pointer to a
+// particular object is kept on a circular linked list. When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is assigned, the entire list of pointers to that
+// object is traversed. This class is therefore NOT SUITABLE when there
+// will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+// will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Bill Gibbons suggested we use something like this.
+//
+// Thread Safety:
+// Unlike other linked_ptr implementations, in this implementation
+// a linked_ptr object is thread-safe in the sense that:
+// - it's safe to copy linked_ptr objects concurrently,
+// - it's safe to copy *from* a linked_ptr and read its underlying
+// raw pointer (e.g. via get()) concurrently, and
+// - it's safe to write to two linked_ptrs that point to the same
+// shared object concurrently.
+// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
+// confusion with normal linked_ptr.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+
+namespace testing {
+namespace internal {
+
+// Protects copying of all linked_ptr objects.
+GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// This is used internally by all instances of linked_ptr<>. It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+ // Create a new circle that includes only this instance.
+ void join_new() {
+ next_ = this;
+ }
+
+ // Many linked_ptr operations may change p.link_ for some linked_ptr
+ // variable p in the same circle as this object. Therefore we need
+ // to prevent two such operations from occurring concurrently.
+ //
+ // Note that different types of linked_ptr objects can coexist in a
+ // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
+ // linked_ptr<Derived2>). Therefore we must use a single mutex to
+ // protect all linked_ptr objects. This can create serious
+ // contention in production code, but is acceptable in a testing
+ // framework.
+
+ // Join an existing circle.
+ // L < g_linked_ptr_mutex
+ void join(linked_ptr_internal const* ptr) {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ linked_ptr_internal const* p = ptr;
+ while (p->next_ != ptr) p = p->next_;
+ p->next_ = this;
+ next_ = ptr;
+ }
+
+ // Leave whatever circle we're part of. Returns true if we were the
+ // last member of the circle. Once this is done, you can join() another.
+ // L < g_linked_ptr_mutex
+ bool depart() {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ if (next_ == this) return true;
+ linked_ptr_internal const* p = next_;
+ while (p->next_ != this) p = p->next_;
+ p->next_ = next_;
+ return false;
+ }
+
+ private:
+ mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+ typedef T element_type;
+
+ // Take over ownership of a raw pointer. This should happen as soon as
+ // possible after the object is created.
+ explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+ ~linked_ptr() { depart(); }
+
+ // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+ template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+ linked_ptr(linked_ptr const& ptr) { // NOLINT
+ assert(&ptr != this);
+ copy(&ptr);
+ }
+
+ // Assignment releases the old value and acquires the new.
+ template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+ depart();
+ copy(&ptr);
+ return *this;
+ }
+
+ linked_ptr& operator=(linked_ptr const& ptr) {
+ if (&ptr != this) {
+ depart();
+ copy(&ptr);
+ }
+ return *this;
+ }
+
+ // Smart pointer members.
+ void reset(T* ptr = NULL) {
+ depart();
+ capture(ptr);
+ }
+ T* get() const { return value_; }
+ T* operator->() const { return value_; }
+ T& operator*() const { return *value_; }
+
+ bool operator==(T* p) const { return value_ == p; }
+ bool operator!=(T* p) const { return value_ != p; }
+ template <typename U>
+ bool operator==(linked_ptr<U> const& ptr) const {
+ return value_ == ptr.get();
+ }
+ template <typename U>
+ bool operator!=(linked_ptr<U> const& ptr) const {
+ return value_ != ptr.get();
+ }
+
+ private:
+ template <typename U>
+ friend class linked_ptr;
+
+ T* value_;
+ linked_ptr_internal link_;
+
+ void depart() {
+ if (link_.depart()) delete value_;
+ }
+
+ void capture(T* ptr) {
+ value_ = ptr;
+ link_.join_new();
+ }
+
+ template <typename U> void copy(linked_ptr<U> const* ptr) {
+ value_ = ptr->get();
+ if (value_)
+ link_.join(&ptr->link_);
+ else
+ link_.join_new();
+ }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+ return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+ return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+ return linked_ptr<T>(ptr);
+}
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// A user can teach this function how to print a class type T by
+// defining either operator<<() or PrintTo() in the namespace that
+// defines T. More specifically, the FIRST defined function in the
+// following list will be used (assuming T is defined in namespace
+// foo):
+//
+// 1. foo::PrintTo(const T&, ostream*)
+// 2. operator<<(ostream&, const T&) defined in either foo or the
+// global namespace.
+//
+// If none of the above is defined, it will print the debug string of
+// the value if it is a protocol buffer, or print the raw bytes in the
+// value otherwise.
+//
+// To aid debugging: when T is a reference type, the address of the
+// value is also printed; when T is a (const) char pointer, both the
+// pointer value and the NUL-terminated string it points to are
+// printed.
+//
+// We also provide some convenient wrappers:
+//
+// // Prints a value to a string. For a (const or not) char
+// // pointer, the NUL-terminated string (but not the pointer) is
+// // printed.
+// std::string ::testing::PrintToString(const T& value);
+//
+// // Prints a value tersely: for a reference type, the referenced
+// // value (but not the address) is printed; for a (const or not) char
+// // pointer, the NUL-terminated string (but not the pointer) is
+// // printed.
+// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
+//
+// // Prints value using the type inferred by the compiler. The difference
+// // from UniversalTersePrint() is that this function prints both the
+// // pointer and the NUL-terminated string for a (const or not) char pointer.
+// void ::testing::internal::UniversalPrint(const T& value, ostream*);
+//
+// // Prints the fields of a tuple tersely to a string vector, one
+// // element for each field. Tuple support must be enabled in
+// // gtest-port.h.
+// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
+// const Tuple& value);
+//
+// Known limitation:
+//
+// The print primitives print the elements of an STL-style container
+// using the compiler-inferred type of *iter where iter is a
+// const_iterator of the container. When const_iterator is an input
+// iterator but not a forward iterator, this inferred type may not
+// match value_type, and the print output may be incorrect. In
+// practice, this is rarely a problem as for most containers
+// const_iterator is a forward iterator. We'll fix this if there's an
+// actual need for it. Note that this fix cannot rely on value_type
+// being defined as many user-defined container types don't have
+// value_type.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#include <ostream> // NOLINT
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace testing {
+
+// Definitions in the 'internal' and 'internal2' name spaces are
+// subject to change without notice. DO NOT USE THEM IN USER CODE!
+namespace internal2 {
+
+// Prints the given number of bytes in the given object to the given
+// ostream.
+GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
+ size_t count,
+ ::std::ostream* os);
+
+// For selecting which printer to use when a given type has neither <<
+// nor PrintTo().
+enum TypeKind {
+ kProtobuf, // a protobuf type
+ kConvertibleToInteger, // a type implicitly convertible to BiggestInt
+ // (e.g. a named or unnamed enum type)
+ kOtherType // anything else
+};
+
+// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
+// by the universal printer to print a value of type T when neither
+// operator<< nor PrintTo() is defined for T, where kTypeKind is the
+// "kind" of T as defined by enum TypeKind.
+template <typename T, TypeKind kTypeKind>
+class TypeWithoutFormatter {
+ public:
+ // This default version is called when kTypeKind is kOtherType.
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
+ sizeof(value), os);
+ }
+};
+
+// We print a protobuf using its ShortDebugString() when the string
+// doesn't exceed this many characters; otherwise we print it using
+// DebugString() for better readability.
+const size_t kProtobufOneLinerMaxLength = 50;
+
+template <typename T>
+class TypeWithoutFormatter<T, kProtobuf> {
+ public:
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ const ::testing::internal::string short_str = value.ShortDebugString();
+ const ::testing::internal::string pretty_str =
+ short_str.length() <= kProtobufOneLinerMaxLength ?
+ short_str : ("\n" + value.DebugString());
+ *os << ("<" + pretty_str + ">");
+ }
+};
+
+template <typename T>
+class TypeWithoutFormatter<T, kConvertibleToInteger> {
+ public:
+ // Since T has no << operator or PrintTo() but can be implicitly
+ // converted to BiggestInt, we print it as a BiggestInt.
+ //
+ // Most likely T is an enum type (either named or unnamed), in which
+ // case printing it as an integer is the desired behavior. In case
+ // T is not an enum, printing it as an integer is the best we can do
+ // given that it has no user-defined printer.
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ const internal::BiggestInt kBigInt = value;
+ *os << kBigInt;
+ }
+};
+
+// Prints the given value to the given ostream. If the value is a
+// protocol message, its debug string is printed; if it's an enum or
+// of a type implicitly convertible to BiggestInt, it's printed as an
+// integer; otherwise the bytes in the value are printed. This is
+// what UniversalPrinter<T>::Print() does when it knows nothing about
+// type T and T has neither << operator nor PrintTo().
+//
+// A user can override this behavior for a class type Foo by defining
+// a << operator in the namespace where Foo is defined.
+//
+// We put this operator in namespace 'internal2' instead of 'internal'
+// to simplify the implementation, as much code in 'internal' needs to
+// use << in STL, which would conflict with our own << were it defined
+// in 'internal'.
+//
+// Note that this operator<< takes a generic std::basic_ostream<Char,
+// CharTraits> type instead of the more restricted std::ostream. If
+// we define it to take an std::ostream instead, we'll get an
+// "ambiguous overloads" compiler error when trying to print a type
+// Foo that supports streaming to std::basic_ostream<Char,
+// CharTraits>, as the compiler cannot tell whether
+// operator<<(std::ostream&, const T&) or
+// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
+// specific.
+template <typename Char, typename CharTraits, typename T>
+::std::basic_ostream<Char, CharTraits>& operator<<(
+ ::std::basic_ostream<Char, CharTraits>& os, const T& x) {
+ TypeWithoutFormatter<T,
+ (internal::IsAProtocolMessage<T>::value ? kProtobuf :
+ internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
+ kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
+ return os;
+}
+
+} // namespace internal2
+} // namespace testing
+
+// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
+// magic needed for implementing UniversalPrinter won't work.
+namespace testing_internal {
+
+// Used to print a value that is not an STL-style container when the
+// user doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
+ // With the following statement, during unqualified name lookup,
+ // testing::internal2::operator<< appears as if it was declared in
+ // the nearest enclosing namespace that contains both
+ // ::testing_internal and ::testing::internal2, i.e. the global
+ // namespace. For more details, refer to the C++ Standard section
+ // 7.3.4-1 [namespace.udir]. This allows us to fall back onto
+ // testing::internal2::operator<< in case T doesn't come with a <<
+ // operator.
+ //
+ // We cannot write 'using ::testing::internal2::operator<<;', which
+ // gcc 3.3 fails to compile due to a compiler bug.
+ using namespace ::testing::internal2; // NOLINT
+
+ // Assuming T is defined in namespace foo, in the next statement,
+ // the compiler will consider all of:
+ //
+ // 1. foo::operator<< (thanks to Koenig look-up),
+ // 2. ::operator<< (as the current namespace is enclosed in ::),
+ // 3. testing::internal2::operator<< (thanks to the using statement above).
+ //
+ // The operator<< whose type matches T best will be picked.
+ //
+ // We deliberately allow #2 to be a candidate, as sometimes it's
+ // impossible to define #1 (e.g. when foo is ::std, defining
+ // anything in it is undefined behavior unless you are a compiler
+ // vendor.).
+ *os << value;
+}
+
+} // namespace testing_internal
+
+namespace testing {
+namespace internal {
+
+// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
+// value to the given ostream. The caller must ensure that
+// 'ostream_ptr' is not NULL, or the behavior is undefined.
+//
+// We define UniversalPrinter as a class template (as opposed to a
+// function template), as we need to partially specialize it for
+// reference types, which cannot be done with function templates.
+template <typename T>
+class UniversalPrinter;
+
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os);
+
+// Used to print an STL-style container when the user doesn't define
+// a PrintTo() for it.
+template <typename C>
+void DefaultPrintTo(IsContainer /* dummy */,
+ false_type /* is not a pointer */,
+ const C& container, ::std::ostream* os) {
+ const size_t kMaxCount = 32; // The maximum number of elements to print.
+ *os << '{';
+ size_t count = 0;
+ for (typename C::const_iterator it = container.begin();
+ it != container.end(); ++it, ++count) {
+ if (count > 0) {
+ *os << ',';
+ if (count == kMaxCount) { // Enough has been printed.
+ *os << " ...";
+ break;
+ }
+ }
+ *os << ' ';
+ // We cannot call PrintTo(*it, os) here as PrintTo() doesn't
+ // handle *it being a native array.
+ internal::UniversalPrint(*it, os);
+ }
+
+ if (count > 0) {
+ *os << ' ';
+ }
+ *os << '}';
+}
+
+// Used to print a pointer that is neither a char pointer nor a member
+// pointer, when the user doesn't define PrintTo() for it. (A member
+// variable pointer or member function pointer doesn't really point to
+// a location in the address space. Their representation is
+// implementation-defined. Therefore they will be printed as raw
+// bytes.)
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+ true_type /* is a pointer */,
+ T* p, ::std::ostream* os) {
+ if (p == NULL) {
+ *os << "NULL";
+ } else {
+ // C++ doesn't allow casting from a function pointer to any object
+ // pointer.
+ //
+ // IsTrue() silences warnings: "Condition is always true",
+ // "unreachable code".
+ if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
+ // T is not a function type. We just call << to print p,
+ // relying on ADL to pick up user-defined << for their pointer
+ // types, if any.
+ *os << p;
+ } else {
+ // T is a function type, so '*os << p' doesn't do what we want
+ // (it just prints p as bool). We want to print p as a const
+ // void*. However, we cannot cast it to const void* directly,
+ // even using reinterpret_cast, as earlier versions of gcc
+ // (e.g. 3.4.5) cannot compile the cast when p is a function
+ // pointer. Casting to UInt64 first solves the problem.
+ *os << reinterpret_cast<const void*>(
+ reinterpret_cast<internal::UInt64>(p));
+ }
+ }
+}
+
+// Used to print a non-container, non-pointer value when the user
+// doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+ false_type /* is not a pointer */,
+ const T& value, ::std::ostream* os) {
+ ::testing_internal::DefaultPrintNonContainerTo(value, os);
+}
+
+// Prints the given value using the << operator if it has one;
+// otherwise prints the bytes in it. This is what
+// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
+// or overloaded for type T.
+//
+// A user can override this behavior for a class type Foo by defining
+// an overload of PrintTo() in the namespace where Foo is defined. We
+// give the user this option as sometimes defining a << operator for
+// Foo is not desirable (e.g. the coding style may prevent doing it,
+// or there is already a << operator but it doesn't do what the user
+// wants).
+template <typename T>
+void PrintTo(const T& value, ::std::ostream* os) {
+ // DefaultPrintTo() is overloaded. The type of its first two
+ // arguments determine which version will be picked. If T is an
+ // STL-style container, the version for container will be called; if
+ // T is a pointer, the pointer version will be called; otherwise the
+ // generic version will be called.
+ //
+ // Note that we check for container types here, prior to we check
+ // for protocol message types in our operator<<. The rationale is:
+ //
+ // For protocol messages, we want to give people a chance to
+ // override Google Mock's format by defining a PrintTo() or
+ // operator<<. For STL containers, other formats can be
+ // incompatible with Google Mock's format for the container
+ // elements; therefore we check for container types here to ensure
+ // that our format is used.
+ //
+ // The second argument of DefaultPrintTo() is needed to bypass a bug
+ // in Symbian's C++ compiler that prevents it from picking the right
+ // overload between:
+ //
+ // PrintTo(const T& x, ...);
+ // PrintTo(T* x, ...);
+ DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
+}
+
+// The following list of PrintTo() overloads tells
+// UniversalPrinter<T>::Print() how to print standard types (built-in
+// types, strings, plain arrays, and pointers).
+
+// Overloads for various char types.
+GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
+GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
+inline void PrintTo(char c, ::std::ostream* os) {
+ // When printing a plain char, we always treat it as unsigned. This
+ // way, the output won't be affected by whether the compiler thinks
+ // char is signed or not.
+ PrintTo(static_cast<unsigned char>(c), os);
+}
+
+// Overloads for other simple built-in types.
+inline void PrintTo(bool x, ::std::ostream* os) {
+ *os << (x ? "true" : "false");
+}
+
+// Overload for wchar_t type.
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its decimal code (except for L'\0').
+// The L'\0' char is printed as "L'\\0'". The decimal code is printed
+// as signed integer when wchar_t is implemented by the compiler
+// as a signed type and is printed as an unsigned integer when wchar_t
+// is implemented as an unsigned type.
+GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
+
+// Overloads for C strings.
+GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
+inline void PrintTo(char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char*>(s), os);
+}
+
+// signed/unsigned char is often used for representing binary data, so
+// we print pointers to it as void* to be safe.
+inline void PrintTo(const signed char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(signed char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(unsigned char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+
+// MSVC can be configured to define wchar_t as a typedef of unsigned
+// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
+// type. When wchar_t is a typedef, defining an overload for const
+// wchar_t* would cause unsigned short* be printed as a wide string,
+// possibly causing invalid memory accesses.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Overloads for wide C strings
+GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
+inline void PrintTo(wchar_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const wchar_t*>(s), os);
+}
+#endif
+
+// Overload for C arrays. Multi-dimensional arrays are printed
+// properly.
+
+// Prints the given number of elements in an array, without printing
+// the curly braces.
+template <typename T>
+void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
+ UniversalPrint(a[0], os);
+ for (size_t i = 1; i != count; i++) {
+ *os << ", ";
+ UniversalPrint(a[i], os);
+ }
+}
+
+// Overloads for ::string and ::std::string.
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
+inline void PrintTo(const ::string& s, ::std::ostream* os) {
+ PrintStringTo(s, os);
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+
+GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
+inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
+ PrintStringTo(s, os);
+}
+
+// Overloads for ::wstring and ::std::wstring.
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
+inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
+ PrintWideStringTo(s, os);
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
+inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
+ PrintWideStringTo(s, os);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_TR1_TUPLE
+// Overload for ::std::tr1::tuple. Needed for printing function arguments,
+// which are packed as tuples.
+
+// Helper function for printing a tuple. T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os);
+
+// Overloaded PrintTo() for tuples of various arities. We support
+// tuples of up-to 10 fields. The following implementation works
+// regardless of whether tr1::tuple is implemented using the
+// non-standard variadic template feature or not.
+
+inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1>
+void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2>
+void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
+ ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
+ ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
+ ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
+ ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
+ ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+void PrintTo(
+ const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
+ ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Overload for std::pair.
+template <typename T1, typename T2>
+void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
+ *os << '(';
+ // We cannot use UniversalPrint(value.first, os) here, as T1 may be
+ // a reference type. The same for printing value.second.
+ UniversalPrinter<T1>::Print(value.first, os);
+ *os << ", ";
+ UniversalPrinter<T2>::Print(value.second, os);
+ *os << ')';
+}
+
+// Implements printing a non-reference type T by letting the compiler
+// pick the right overload of PrintTo() for T.
+template <typename T>
+class UniversalPrinter {
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4180) // Temporarily disables warning 4180.
+#endif // _MSC_VER
+
+ // Note: we deliberately don't call this PrintTo(), as that name
+ // conflicts with ::testing::internal::PrintTo in the body of the
+ // function.
+ static void Print(const T& value, ::std::ostream* os) {
+ // By default, ::testing::internal::PrintTo() is used for printing
+ // the value.
+ //
+ // Thanks to Koenig look-up, if T is a class and has its own
+ // PrintTo() function defined in its namespace, that function will
+ // be visible here. Since it is more specific than the generic ones
+ // in ::testing::internal, it will be picked by the compiler in the
+ // following statement - exactly what we want.
+ PrintTo(value, os);
+ }
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif // _MSC_VER
+};
+
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
+ if (len == 0) {
+ *os << "{}";
+ } else {
+ *os << "{ ";
+ const size_t kThreshold = 18;
+ const size_t kChunkSize = 8;
+ // If the array has more than kThreshold elements, we'll have to
+ // omit some details by printing only the first and the last
+ // kChunkSize elements.
+ // TODO(wan@google.com): let the user control the threshold using a flag.
+ if (len <= kThreshold) {
+ PrintRawArrayTo(begin, len, os);
+ } else {
+ PrintRawArrayTo(begin, kChunkSize, os);
+ *os << ", ..., ";
+ PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
+ }
+ *os << " }";
+ }
+}
+// This overload prints a (const) char array compactly.
+GTEST_API_ void UniversalPrintArray(const char* begin,
+ size_t len,
+ ::std::ostream* os);
+
+// Implements printing an array type T[N].
+template <typename T, size_t N>
+class UniversalPrinter<T[N]> {
+ public:
+ // Prints the given array, omitting some elements when there are too
+ // many.
+ static void Print(const T (&a)[N], ::std::ostream* os) {
+ UniversalPrintArray(a, N, os);
+ }
+};
+
+// Implements printing a reference type T&.
+template <typename T>
+class UniversalPrinter<T&> {
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4180) // Temporarily disables warning 4180.
+#endif // _MSC_VER
+
+ static void Print(const T& value, ::std::ostream* os) {
+ // Prints the address of the value. We use reinterpret_cast here
+ // as static_cast doesn't compile when T is a function type.
+ *os << "@" << reinterpret_cast<const void*>(&value) << " ";
+
+ // Then prints the value itself.
+ UniversalPrint(value, os);
+ }
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif // _MSC_VER
+};
+
+// Prints a value tersely: for a reference type, the referenced value
+// (but not the address) is printed; for a (const) char pointer, the
+// NUL-terminated string (but not the pointer) is printed.
+template <typename T>
+void UniversalTersePrint(const T& value, ::std::ostream* os) {
+ UniversalPrint(value, os);
+}
+inline void UniversalTersePrint(const char* str, ::std::ostream* os) {
+ if (str == NULL) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(string(str), os);
+ }
+}
+inline void UniversalTersePrint(char* str, ::std::ostream* os) {
+ UniversalTersePrint(static_cast<const char*>(str), os);
+}
+
+// Prints a value using the type inferred by the compiler. The
+// difference between this and UniversalTersePrint() is that for a
+// (const) char pointer, this prints both the pointer and the
+// NUL-terminated string.
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os) {
+ UniversalPrinter<T>::Print(value, os);
+}
+
+#if GTEST_HAS_TR1_TUPLE
+typedef ::std::vector<string> Strings;
+
+// This helper template allows PrintTo() for tuples and
+// UniversalTersePrintTupleFieldsToStrings() to be defined by
+// induction on the number of tuple fields. The idea is that
+// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
+// fields in tuple t, and can be defined in terms of
+// TuplePrefixPrinter<N - 1>.
+
+// The inductive case.
+template <size_t N>
+struct TuplePrefixPrinter {
+ // Prints the first N fields of a tuple.
+ template <typename Tuple>
+ static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+ TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
+ *os << ", ";
+ UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
+ ::Print(::std::tr1::get<N - 1>(t), os);
+ }
+
+ // Tersely prints the first N fields of a tuple to a string vector,
+ // one element for each field.
+ template <typename Tuple>
+ static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+ TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
+ ::std::stringstream ss;
+ UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
+ strings->push_back(ss.str());
+ }
+};
+
+// Base cases.
+template <>
+struct TuplePrefixPrinter<0> {
+ template <typename Tuple>
+ static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
+
+ template <typename Tuple>
+ static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
+};
+// We have to specialize the entire TuplePrefixPrinter<> class
+// template here, even though the definition of
+// TersePrintPrefixToStrings() is the same as the generic version, as
+// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
+// support specializing a method template of a class template.
+template <>
+struct TuplePrefixPrinter<1> {
+ template <typename Tuple>
+ static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+ UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
+ Print(::std::tr1::get<0>(t), os);
+ }
+
+ template <typename Tuple>
+ static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+ ::std::stringstream ss;
+ UniversalTersePrint(::std::tr1::get<0>(t), &ss);
+ strings->push_back(ss.str());
+ }
+};
+
+// Helper function for printing a tuple. T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os) {
+ *os << "(";
+ TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
+ PrintPrefixTo(t, os);
+ *os << ")";
+}
+
+// Prints the fields of a tuple tersely to a string vector, one
+// element for each field. See the comment before
+// UniversalTersePrint() for how we define "tersely".
+template <typename Tuple>
+Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
+ Strings result;
+ TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
+ TersePrintPrefixToStrings(value, &result);
+ return result;
+}
+#endif // GTEST_HAS_TR1_TUPLE
+
+} // namespace internal
+
+template <typename T>
+::std::string PrintToString(const T& value) {
+ ::std::stringstream ss;
+ internal::UniversalTersePrint(value, &ss);
+ return ss.str();
+}
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test case. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line);
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface {
+ public:
+ virtual ~ParamIteratorInterface() {}
+ // A pointer to the base generator instance.
+ // Used only for the purposes of iterator comparison
+ // to make sure that two iterators belong to the same generator.
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+ // Advances iterator to point to the next element
+ // provided by the generator. The caller is responsible
+ // for not calling Advance() on an iterator equal to
+ // BaseGenerator()->End().
+ virtual void Advance() = 0;
+ // Clones the iterator object. Used for implementing copy semantics
+ // of ParamIterator<T>.
+ virtual ParamIteratorInterface* Clone() const = 0;
+ // Dereferences the current iterator and provides (read-only) access
+ // to the pointed value. It is the caller's responsibility not to call
+ // Current() on an iterator equal to BaseGenerator()->End().
+ // Used for implementing ParamGenerator<T>::operator*().
+ virtual const T* Current() const = 0;
+ // Determines whether the given iterator and other point to the same
+ // element in the sequence generated by the generator.
+ // Used for implementing ParamGenerator<T>::operator==().
+ virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator {
+ public:
+ typedef T value_type;
+ typedef const T& reference;
+ typedef ptrdiff_t difference_type;
+
+ // ParamIterator assumes ownership of the impl_ pointer.
+ ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+ ParamIterator& operator=(const ParamIterator& other) {
+ if (this != &other)
+ impl_.reset(other.impl_->Clone());
+ return *this;
+ }
+
+ const T& operator*() const { return *impl_->Current(); }
+ const T* operator->() const { return impl_->Current(); }
+ // Prefix version of operator++.
+ ParamIterator& operator++() {
+ impl_->Advance();
+ return *this;
+ }
+ // Postfix version of operator++.
+ ParamIterator operator++(int /*unused*/) {
+ ParamIteratorInterface<T>* clone = impl_->Clone();
+ impl_->Advance();
+ return ParamIterator(clone);
+ }
+ bool operator==(const ParamIterator& other) const {
+ return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+ }
+ bool operator!=(const ParamIterator& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ friend class ParamGenerator<T>;
+ explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+ scoped_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+ typedef T ParamType;
+
+ virtual ~ParamGeneratorInterface() {}
+
+ // Generator interface definition
+ virtual ParamIteratorInterface<T>* Begin() const = 0;
+ virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInterface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator {
+ public:
+ typedef ParamIterator<T> iterator;
+
+ explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+ ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+ ParamGenerator& operator=(const ParamGenerator& other) {
+ impl_ = other.impl_;
+ return *this;
+ }
+
+ iterator begin() const { return iterator(impl_->Begin()); }
+ iterator end() const { return iterator(impl_->End()); }
+
+ private:
+ linked_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ RangeGenerator(T begin, T end, IncrementT step)
+ : begin_(begin), end_(end),
+ step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+ virtual ~RangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, begin_, 0, step_);
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, end_, end_index_, step_);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+ IncrementT step)
+ : base_(base), value_(value), index_(index), step_(step) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ value_ = value_ + step_;
+ index_++;
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const T* Current() const { return &value_; }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const int other_index =
+ CheckedDowncastToActualType<const Iterator>(&other)->index_;
+ return index_ == other_index;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : ParamIteratorInterface<T>(),
+ base_(other.base_), value_(other.value_), index_(other.index_),
+ step_(other.step_) {}
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<T>* const base_;
+ T value_;
+ int index_;
+ const IncrementT step_;
+ }; // class RangeGenerator::Iterator
+
+ static int CalculateEndIndex(const T& begin,
+ const T& end,
+ const IncrementT& step) {
+ int end_index = 0;
+ for (T i = begin; i < end; i = i + step)
+ end_index++;
+ return end_index;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const RangeGenerator& other);
+
+ const T begin_;
+ const T end_;
+ const IncrementT step_;
+ // The index for the end() iterator. All the elements in the generated
+ // sequence are indexed (0-based) to aid iterator comparison.
+ const int end_index_;
+}; // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ template <typename ForwardIterator>
+ ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+ : container_(begin, end) {}
+ virtual ~ValuesInIteratorRangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, container_.begin());
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, container_.end());
+ }
+
+ private:
+ typedef typename ::std::vector<T> ContainerType;
+
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base,
+ typename ContainerType::const_iterator iterator)
+ : base_(base), iterator_(iterator) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ ++iterator_;
+ value_.reset();
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ // We need to use cached value referenced by iterator_ because *iterator_
+ // can return a temporary object (and of type other then T), so just
+ // having "return &*iterator_;" doesn't work.
+ // value_ is updated here and not in Advance() because Advance()
+ // can advance iterator_ beyond the end of the range, and we cannot
+ // detect that fact. The client code, on the other hand, is
+ // responsible for not calling Current() on an out-of-range iterator.
+ virtual const T* Current() const {
+ if (value_.get() == NULL)
+ value_.reset(new T(*iterator_));
+ return value_.get();
+ }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ return iterator_ ==
+ CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ // The explicit constructor call suppresses a false warning
+ // emitted by gcc when supplied with the -Wextra option.
+ : ParamIteratorInterface<T>(),
+ base_(other.base_),
+ iterator_(other.iterator_) {}
+
+ const ParamGeneratorInterface<T>* const base_;
+ typename ContainerType::const_iterator iterator_;
+ // A cached value of *iterator_. We keep it here to allow access by
+ // pointer in the wrapping iterator's operator->().
+ // value_ needs to be mutable to be accessed in Current().
+ // Use of scoped_ptr helps manage cached value's lifetime,
+ // which is bound by the lifespan of the iterator itself.
+ mutable scoped_ptr<const T> value_;
+ }; // class ValuesInIteratorRangeGenerator::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const ValuesInIteratorRangeGenerator& other);
+
+ const ContainerType container_;
+}; // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+ typedef typename TestClass::ParamType ParamType;
+ explicit ParameterizedTestFactory(ParamType parameter) :
+ parameter_(parameter) {}
+ virtual Test* CreateTest() {
+ TestClass::SetParam(¶meter_);
+ return new TestClass();
+ }
+
+ private:
+ const ParamType parameter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase {
+ public:
+ virtual ~TestMetaFactoryBase() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestCaseInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestCase>
+class TestMetaFactory
+ : public TestMetaFactoryBase<typename TestCase::ParamType> {
+ public:
+ typedef typename TestCase::ParamType ParamType;
+
+ TestMetaFactory() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
+ return new ParameterizedTestFactory<TestCase>(parameter);
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfoBase is a generic interface
+// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
+// a collection of pointers to the ParameterizedTestCaseInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestCaseInfoBase {
+ public:
+ virtual ~ParameterizedTestCaseInfoBase() {}
+
+ // Base part of test case name for display purposes.
+ virtual const string& GetTestCaseName() const = 0;
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const = 0;
+ // UnitTest class invokes this method to register tests in this
+ // test case right before running them in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ virtual void RegisterTests() = 0;
+
+ protected:
+ ParameterizedTestCaseInfoBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test case and generators
+// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
+// test case. It registers tests with all values generated by all
+// generators when asked.
+template <class TestCase>
+class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
+ public:
+ // ParamType and GeneratorCreationFunc are private types but are required
+ // for declarations of public methods AddTestPattern() and
+ // AddTestCaseInstantiation().
+ typedef typename TestCase::ParamType ParamType;
+ // A function that returns an instance of appropriate generator type.
+ typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+
+ explicit ParameterizedTestCaseInfo(const char* name)
+ : test_case_name_(name) {}
+
+ // Test case base name for display purposes.
+ virtual const string& GetTestCaseName() const { return test_case_name_; }
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+ // TEST_P macro uses AddTestPattern() to record information
+ // about a single test in a LocalTestInfo structure.
+ // test_case_name is the base name of the test case (without invocation
+ // prefix). test_base_name is the name of an individual test without
+ // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+ // test case base name and DoBar is test base name.
+ void AddTestPattern(const char* test_case_name,
+ const char* test_base_name,
+ TestMetaFactoryBase<ParamType>* meta_factory) {
+ tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
+ test_base_name,
+ meta_factory)));
+ }
+ // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+ // about a generator.
+ int AddTestCaseInstantiation(const string& instantiation_name,
+ GeneratorCreationFunc* func,
+ const char* /* file */,
+ int /* line */) {
+ instantiations_.push_back(::std::make_pair(instantiation_name, func));
+ return 0; // Return value used only to run this method in namespace scope.
+ }
+ // UnitTest class invokes this method to register tests in this test case
+ // test cases right before running tests in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ // UnitTest has a guard to prevent from calling this method more then once.
+ virtual void RegisterTests() {
+ for (typename TestInfoContainer::iterator test_it = tests_.begin();
+ test_it != tests_.end(); ++test_it) {
+ linked_ptr<TestInfo> test_info = *test_it;
+ for (typename InstantiationContainer::iterator gen_it =
+ instantiations_.begin(); gen_it != instantiations_.end();
+ ++gen_it) {
+ const string& instantiation_name = gen_it->first;
+ ParamGenerator<ParamType> generator((*gen_it->second)());
+
+ Message test_case_name_stream;
+ if ( !instantiation_name.empty() )
+ test_case_name_stream << instantiation_name << "/";
+ test_case_name_stream << test_info->test_case_base_name;
+
+ int i = 0;
+ for (typename ParamGenerator<ParamType>::iterator param_it =
+ generator.begin();
+ param_it != generator.end(); ++param_it, ++i) {
+ Message test_name_stream;
+ test_name_stream << test_info->test_base_name << "/" << i;
+ MakeAndRegisterTestInfo(
+ test_case_name_stream.GetString().c_str(),
+ test_name_stream.GetString().c_str(),
+ NULL, // No type parameter.
+ PrintToString(*param_it).c_str(),
+ GetTestCaseTypeId(),
+ TestCase::SetUpTestCase,
+ TestCase::TearDownTestCase,
+ test_info->test_meta_factory->CreateTestFactory(*param_it));
+ } // for param_it
+ } // for gen_it
+ } // for test_it
+ } // RegisterTests
+
+ private:
+ // LocalTestInfo structure keeps information about a single test registered
+ // with TEST_P macro.
+ struct TestInfo {
+ TestInfo(const char* a_test_case_base_name,
+ const char* a_test_base_name,
+ TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
+ test_case_base_name(a_test_case_base_name),
+ test_base_name(a_test_base_name),
+ test_meta_factory(a_test_meta_factory) {}
+
+ const string test_case_base_name;
+ const string test_base_name;
+ const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+ };
+ typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
+ // Keeps pairs of <Instantiation name, Sequence generator creation function>
+ // received from INSTANTIATE_TEST_CASE_P macros.
+ typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
+ InstantiationContainer;
+
+ const string test_case_name_;
+ TestInfoContainer tests_;
+ InstantiationContainer instantiations_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
+}; // class ParameterizedTestCaseInfo
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
+// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
+// macros use it to locate their corresponding ParameterizedTestCaseInfo
+// descriptors.
+class ParameterizedTestCaseRegistry {
+ public:
+ ParameterizedTestCaseRegistry() {}
+ ~ParameterizedTestCaseRegistry() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ // Looks up or creates and returns a structure containing information about
+ // tests and instantiations of a particular test case.
+ template <class TestCase>
+ ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+ const char* test_case_name,
+ const char* file,
+ int line) {
+ ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ if ((*it)->GetTestCaseName() == test_case_name) {
+ if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+ // Complain about incorrect usage of Google Test facilities
+ // and terminate the program since we cannot guaranty correct
+ // test case setup and tear-down in this case.
+ ReportInvalidTestCaseType(test_case_name, file, line);
+ posix::Abort();
+ } else {
+ // At this point we are sure that the object we found is of the same
+ // type we are looking for, so we downcast it to that type
+ // without further checks.
+ typed_test_info = CheckedDowncastToActualType<
+ ParameterizedTestCaseInfo<TestCase> >(*it);
+ }
+ break;
+ }
+ }
+ if (typed_test_info == NULL) {
+ typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+ test_case_infos_.push_back(typed_test_info);
+ }
+ return typed_test_info;
+ }
+ void RegisterTests() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ (*it)->RegisterTests();
+ }
+ }
+
+ private:
+ typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+
+ TestCaseInfoContainer test_case_infos_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+// This file was GENERATED by command:
+// pump.py gtest-param-util-generated.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most 50 arguments in Values,
+// and at most 10 arguments in Combine. Please contact
+// googletestframework@googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at 10.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+ explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray1& other);
+
+ const T1 v1_;
+};
+
+template <typename T1, typename T2>
+class ValueArray2 {
+ public:
+ ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray2& other);
+
+ const T1 v1_;
+ const T2 v2_;
+};
+
+template <typename T1, typename T2, typename T3>
+class ValueArray3 {
+ public:
+ ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray3& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+class ValueArray4 {
+ public:
+ ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray4& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class ValueArray5 {
+ public:
+ ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray5& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class ValueArray6 {
+ public:
+ ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray6& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class ValueArray7 {
+ public:
+ ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray7& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class ValueArray8 {
+ public:
+ ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray8& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class ValueArray9 {
+ public:
+ ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray9& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class ValueArray10 {
+ public:
+ ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray10& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+class ValueArray11 {
+ public:
+ ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray11& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+class ValueArray12 {
+ public:
+ ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray12& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+class ValueArray13 {
+ public:
+ ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray13& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+class ValueArray14 {
+ public:
+ ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray14& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+class ValueArray15 {
+ public:
+ ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray15& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+class ValueArray16 {
+ public:
+ ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray16& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+class ValueArray17 {
+ public:
+ ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray17& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+class ValueArray18 {
+ public:
+ ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray18& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+class ValueArray19 {
+ public:
+ ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray19& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+class ValueArray20 {
+ public:
+ ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray20& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+class ValueArray21 {
+ public:
+ ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray21& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+class ValueArray22 {
+ public:
+ ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray22& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+class ValueArray23 {
+ public:
+ ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_,
+ v23_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray23& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+class ValueArray24 {
+ public:
+ ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray24& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+class ValueArray25 {
+ public:
+ ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray25& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+class ValueArray26 {
+ public:
+ ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray26& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+class ValueArray27 {
+ public:
+ ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray27& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+class ValueArray28 {
+ public:
+ ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray28& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+class ValueArray29 {
+ public:
+ ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray29& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+class ValueArray30 {
+ public:
+ ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray30& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+class ValueArray31 {
+ public:
+ ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray31& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+class ValueArray32 {
+ public:
+ ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray32& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+class ValueArray33 {
+ public:
+ ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray33& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+class ValueArray34 {
+ public:
+ ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray34& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+class ValueArray35 {
+ public:
+ ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_,
+ v35_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray35& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+class ValueArray36 {
+ public:
+ ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray36& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+class ValueArray37 {
+ public:
+ ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray37& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+class ValueArray38 {
+ public:
+ ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray38& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+class ValueArray39 {
+ public:
+ ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray39& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+class ValueArray40 {
+ public:
+ ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray40& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+class ValueArray41 {
+ public:
+ ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray41& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+class ValueArray42 {
+ public:
+ ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray42& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+class ValueArray43 {
+ public:
+ ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
+ v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray43& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+class ValueArray44 {
+ public:
+ ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
+ v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
+ v43_(v43), v44_(v44) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray44& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+class ValueArray45 {
+ public:
+ ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
+ v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray45& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+class ValueArray46 {
+ public:
+ ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray46& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+class ValueArray47 {
+ public:
+ ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
+ v47_(v47) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_,
+ v47_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray47& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+class ValueArray48 {
+ public:
+ ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
+ v46_(v46), v47_(v47), v48_(v48) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray48& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+class ValueArray49 {
+ public:
+ ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
+ T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_, v49_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray49& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+class ValueArray50 {
+ public:
+ ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
+ T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_, v49_, v50_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray50& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+ const T50 v50_;
+};
+
+# if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+template <typename T1, typename T2>
+class CartesianProductGenerator2
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2> ParamType;
+
+ CartesianProductGenerator2(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2)
+ : g1_(g1), g2_(g2) {}
+ virtual ~CartesianProductGenerator2() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current2_;
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator2::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator2& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+}; // class CartesianProductGenerator2
+
+
+template <typename T1, typename T2, typename T3>
+class CartesianProductGenerator3
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+
+ CartesianProductGenerator3(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ virtual ~CartesianProductGenerator3() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current3_;
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator3::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator3& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+}; // class CartesianProductGenerator3
+
+
+template <typename T1, typename T2, typename T3, typename T4>
+class CartesianProductGenerator4
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+
+ CartesianProductGenerator4(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ virtual ~CartesianProductGenerator4() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current4_;
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator4::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator4& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+}; // class CartesianProductGenerator4
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class CartesianProductGenerator5
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+
+ CartesianProductGenerator5(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ virtual ~CartesianProductGenerator5() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current5_;
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator5::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator5& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+}; // class CartesianProductGenerator5
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class CartesianProductGenerator6
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+ T6> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+
+ CartesianProductGenerator6(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ virtual ~CartesianProductGenerator6() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current6_;
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator6::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator6& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+}; // class CartesianProductGenerator6
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class CartesianProductGenerator7
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+
+ CartesianProductGenerator7(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ virtual ~CartesianProductGenerator7() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current7_;
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator7::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator7& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+}; // class CartesianProductGenerator7
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class CartesianProductGenerator8
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+
+ CartesianProductGenerator8(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ virtual ~CartesianProductGenerator8() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current8_;
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator8::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator8& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+}; // class CartesianProductGenerator8
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class CartesianProductGenerator9
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+
+ CartesianProductGenerator9(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ virtual ~CartesianProductGenerator9() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current9_;
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator9::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator9& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+}; // class CartesianProductGenerator9
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class CartesianProductGenerator10
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9, T10> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+
+ CartesianProductGenerator10(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
+ const ParamGenerator<T10>& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ virtual ~CartesianProductGenerator10() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end(), g10_, g10_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9,
+ const ParamGenerator<T10>& g10,
+ const typename ParamGenerator<T10>::iterator& current10)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
+ begin10_(g10.begin()), end10_(g10.end()), current10_(current10) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current10_;
+ if (current10_ == end10_) {
+ current10_ = begin10_;
+ ++current9_;
+ }
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_ &&
+ current10_ == typed_other->current10_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_),
+ begin10_(other.begin10_),
+ end10_(other.end10_),
+ current10_(other.current10_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_, *current10_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_ ||
+ current10_ == end10_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ const typename ParamGenerator<T10>::iterator begin10_;
+ const typename ParamGenerator<T10>::iterator end10_;
+ typename ParamGenerator<T10>::iterator current10_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator10::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator10& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+ const ParamGenerator<T10> g10_;
+}; // class CartesianProductGenerator10
+
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+template <class Generator1, class Generator2>
+class CartesianProductHolder2 {
+ public:
+CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
+ : g1_(g1), g2_(g2) {}
+ template <typename T1, typename T2>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+ new CartesianProductGenerator2<T1, T2>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder2& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+}; // class CartesianProductHolder2
+
+template <class Generator1, class Generator2, class Generator3>
+class CartesianProductHolder3 {
+ public:
+CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ template <typename T1, typename T2, typename T3>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+ new CartesianProductGenerator3<T1, T2, T3>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder3& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+}; // class CartesianProductHolder3
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4>
+class CartesianProductHolder4 {
+ public:
+CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ template <typename T1, typename T2, typename T3, typename T4>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+ new CartesianProductGenerator4<T1, T2, T3, T4>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder4& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+}; // class CartesianProductHolder4
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5>
+class CartesianProductHolder5 {
+ public:
+CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+ new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder5& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+}; // class CartesianProductHolder5
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6>
+class CartesianProductHolder6 {
+ public:
+CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+ new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder6& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+}; // class CartesianProductHolder6
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7>
+class CartesianProductHolder7 {
+ public:
+CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+ new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder7& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+}; // class CartesianProductHolder7
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8>
+class CartesianProductHolder8 {
+ public:
+CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+ T8> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+ new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder8& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+}; // class CartesianProductHolder8
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9>
+class CartesianProductHolder9 {
+ public:
+CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >(
+ new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder9& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+}; // class CartesianProductHolder9
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9, class Generator10>
+class CartesianProductHolder10 {
+ public:
+CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9, const Generator10& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >(
+ new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+ T10>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_),
+ static_cast<ParamGenerator<T10> >(g10_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder10& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+ const Generator10 g10_;
+}; // class CartesianProductHolder10
+
+# endif // GTEST_HAS_COMBINE
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+// - returns a generator producing a sequence of values {start, start+1,
+// start+2, ..., }.
+// Range(start, end, step)
+// - returns a generator producing a sequence of values {start, start+step,
+// start+step+step, ..., }.
+// Notes:
+// * The generated sequences never include end. For example, Range(1, 5)
+// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+// returns a generator producing {1, 3, 5, 7}.
+// * start and end must have the same type. That type may be any integral or
+// floating-point type or a user defined type satisfying these conditions:
+// * It must be assignable (have operator=() defined).
+// * It must have operator+() (operator+(int-compatible type) for
+// two-operand version).
+// * It must have operator<() defined.
+// Elements in the resulting sequences will also have that type.
+// * Condition start < end must be satisfied in order for resulting sequences
+// to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+ return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+// - returns a generator producing sequences with elements from
+// a C-style array.
+// ValuesIn(const Container& container)
+// - returns a generator producing sequences with elements from
+// an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+// - returns a generator producing sequences with elements from
+// a range [begin, end) defined by a pair of STL-style iterators. These
+// iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+// ::std::vector< ::std::string> v;
+// v.push_back("a");
+// v.push_back("b");
+// return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end) {
+ typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
+ ::value_type ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container) {
+ return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+// - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to 50 parameters.
+//
+template <typename T1>
+internal::ValueArray1<T1> Values(T1 v1) {
+ return internal::ValueArray1<T1>(v1);
+}
+
+template <typename T1, typename T2>
+internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
+ return internal::ValueArray2<T1, T2>(v1, v2);
+}
+
+template <typename T1, typename T2, typename T3>
+internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
+ return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
+ return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5) {
+ return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6) {
+ return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7) {
+ return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
+ v6, v7);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
+ return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
+ v5, v6, v7, v8);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
+ return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
+ return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11) {
+ return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12) {
+ return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13) {
+ return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
+ return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
+ return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16) {
+ return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17) {
+ return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18) {
+ return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
+ return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
+ return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
+ return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22) {
+ return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23) {
+ return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24) {
+ return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
+ return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26) {
+ return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27) {
+ return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28) {
+ return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29) {
+ return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
+ return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
+ return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32) {
+ return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33) {
+ return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34) {
+ return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
+ return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
+ return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37) {
+ return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38) {
+ return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
+ v33, v34, v35, v36, v37, v38);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38, T39 v39) {
+ return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+ v32, v33, v34, v35, v36, v37, v38, v39);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
+ T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
+ T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
+ return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
+ v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
+ return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
+ v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42) {
+ return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
+ v42);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43) {
+ return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+ v41, v42, v43);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44) {
+ return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
+ v40, v41, v42, v43, v44);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
+ return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
+ v39, v40, v41, v42, v43, v44, v45);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
+ return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
+ return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
+ T48 v48) {
+ return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
+ v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
+ T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
+ T47 v47, T48 v48, T49 v49) {
+ return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
+ v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
+ T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
+ T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
+ return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
+ v48, v49, v50);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+// - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+ return Values(false, true);
+}
+
+# if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+// - returns a generator producing sequences with elements coming from
+// the Cartesian product of elements from the sequences generated by
+// gen1, gen2, ..., genN. The sequence elements will have a type of
+// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to 10 arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+// : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+// : public testing::TestWithParam<tuple(bool, bool)> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// tie(external_flag_1, external_flag_2) = GetParam();
+// }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+// // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+template <typename Generator1, typename Generator2>
+internal::CartesianProductHolder2<Generator1, Generator2> Combine(
+ const Generator1& g1, const Generator2& g2) {
+ return internal::CartesianProductHolder2<Generator1, Generator2>(
+ g1, g2);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3>
+internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3) {
+ return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
+ g1, g2, g3);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4>
+internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4) {
+ return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4>(
+ g1, g2, g3, g4);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5>
+internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5) {
+ return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5>(
+ g1, g2, g3, g4, g5);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6>
+internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6) {
+ return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6>(
+ g1, g2, g3, g4, g5, g6);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7>
+internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7) {
+ return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7>(
+ g1, g2, g3, g4, g5, g6, g7);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8>
+internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8) {
+ return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8>(
+ g1, g2, g3, g4, g5, g6, g7, g8);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8, typename Generator9>
+internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8,
+ Generator9> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9) {
+ return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8, typename Generator9,
+ typename Generator10>
+internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9,
+ const Generator10& g10) {
+ return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
+}
+# endif // GTEST_HAS_COMBINE
+
+
+
+# define TEST_P(test_case_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ : public test_case_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+ virtual void TestBody(); \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+ #test_case_name, \
+ #test_name, \
+ new ::testing::internal::TestMetaFactory< \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_case_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+ ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+ int gtest_##prefix##test_case_name##_dummy_ = \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+ #prefix, \
+ >est_##prefix##test_case_name##_EvalGenerator_, \
+ __FILE__, __LINE__)
+
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class. For example:
+//
+// class MyClass {
+// private:
+// void MyMethod();
+// FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+// // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+// // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+
+namespace testing {
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class GTEST_API_ TestPartResult {
+ public:
+ // The possible outcomes of a test part (i.e. an assertion or an
+ // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+ enum Type {
+ kSuccess, // Succeeded.
+ kNonFatalFailure, // Failed but the test can continue.
+ kFatalFailure // Failed and the test should be terminated.
+ };
+
+ // C'tor. TestPartResult does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestPartResult object.
+ TestPartResult(Type a_type,
+ const char* a_file_name,
+ int a_line_number,
+ const char* a_message)
+ : type_(a_type),
+ file_name_(a_file_name),
+ line_number_(a_line_number),
+ summary_(ExtractSummary(a_message)),
+ message_(a_message) {
+ }
+
+ // Gets the outcome of the test part.
+ Type type() const { return type_; }
+
+ // Gets the name of the source file where the test part took place, or
+ // NULL if it's unknown.
+ const char* file_name() const { return file_name_.c_str(); }
+
+ // Gets the line in the source file where the test part took place,
+ // or -1 if it's unknown.
+ int line_number() const { return line_number_; }
+
+ // Gets the summary of the failure message.
+ const char* summary() const { return summary_.c_str(); }
+
+ // Gets the message associated with the test part.
+ const char* message() const { return message_.c_str(); }
+
+ // Returns true iff the test part passed.
+ bool passed() const { return type_ == kSuccess; }
+
+ // Returns true iff the test part failed.
+ bool failed() const { return type_ != kSuccess; }
+
+ // Returns true iff the test part non-fatally failed.
+ bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+ // Returns true iff the test part fatally failed.
+ bool fatally_failed() const { return type_ == kFatalFailure; }
+ private:
+ Type type_;
+
+ // Gets the summary of the failure message by omitting the stack
+ // trace in it.
+ static internal::String ExtractSummary(const char* message);
+
+ // The name of the source file where the test part took place, or
+ // NULL if the source file is unknown.
+ internal::String file_name_;
+ // The line in the source file where the test part took place, or -1
+ // if the line number is unknown.
+ int line_number_;
+ internal::String summary_; // The test failure summary.
+ internal::String message_; // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class GTEST_API_ TestPartResultArray {
+ public:
+ TestPartResultArray() {}
+
+ // Appends the given TestPartResult to the array.
+ void Append(const TestPartResult& result);
+
+ // Returns the TestPartResult at the given index (0-based).
+ const TestPartResult& GetTestPartResult(int index) const;
+
+ // Returns the number of TestPartResult objects in the array.
+ int size() const;
+
+ private:
+ std::vector<TestPartResult> array_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface {
+ public:
+ virtual ~TestPartResultReporterInterface() {}
+
+ virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class GTEST_API_ HasNewFatalFailureHelper
+ : public TestPartResultReporterInterface {
+ public:
+ HasNewFatalFailureHelper();
+ virtual ~HasNewFatalFailureHelper();
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+ bool has_new_fatal_failure_;
+ TestPartResultReporterInterface* original_reporter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list. You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ public:
+ ...
+ typedef std::list<T> List;
+ static T shared_;
+ T value_;
+};
+
+// Next, associate a list of types with the test case, which will be
+// repeated for each type in the list. The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_CASE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// TYPED_TEST_CASE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test case as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+ // Inside a test, refer to TypeParam to get the type parameter.
+ // Since we are inside a derived class template, C++ requires use to
+ // visit the members of FooTest via 'this'.
+ TypeParam n = this->value_;
+
+ // To visit static members of the fixture, add the TestFixture::
+ // prefix.
+ n += TestFixture::shared_;
+
+ // To refer to typedefs in the fixture, add the "typename
+ // TestFixture::" prefix.
+ typename TestFixture::List values;
+ values.push_back(n);
+ ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+#endif // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type. Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are. The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have. Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly. Here's an example:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ ...
+};
+
+// Next, declare that you will define a type-parameterized test case
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_CASE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test case as you want.
+TYPED_TEST_P(FooTest, DoesBlah) {
+ // Inside a test, refer to TypeParam to get the type parameter.
+ TypeParam n = 0;
+ ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them. The first argument of the macro is the
+// test case name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_CASE_P(FooTest,
+ DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want. If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test case name. Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+
+#endif // 0
+
+
+// Implements typed tests.
+
+#if GTEST_HAS_TYPED_TEST
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test case.
+# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define TYPED_TEST_CASE(CaseName, Types) \
+ typedef ::testing::internal::TypeList< Types >::type \
+ GTEST_TYPE_PARAMS_(CaseName)
+
+# define TYPED_TEST(CaseName, TestName) \
+ template <typename gtest_TypeParam_> \
+ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+ : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTest< \
+ CaseName, \
+ ::testing::internal::TemplateSel< \
+ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
+ GTEST_TYPE_PARAMS_(CaseName)>::Register(\
+ "", #CaseName, #TestName, 0); \
+ template <typename gtest_TypeParam_> \
+ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// Implements type-parameterized tests.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test case are defined in. The exact
+// name of the namespace is subject to change without notice.
+# define GTEST_CASE_NAMESPACE_(TestCaseName) \
+ gtest_case_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test case.
+# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
+ gtest_typed_test_case_p_state_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test case.
+# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
+ gtest_registered_test_names_##TestCaseName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+# define TYPED_TEST_CASE_P(CaseName) \
+ static ::testing::internal::TypedTestCasePState \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
+
+# define TYPED_TEST_P(CaseName, TestName) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ template <typename gtest_TypeParam_> \
+ class TestName : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
+ __FILE__, __LINE__, #CaseName, #TestName); \
+ } \
+ template <typename gtest_TypeParam_> \
+ void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
+
+# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+ } \
+ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+ __FILE__, __LINE__, #__VA_ARGS__)
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
+ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTestCase<CaseName, \
+ GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
+ ::testing::internal::TypeList< Types >::type>::Register(\
+ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// Depending on the platform, different string classes are available.
+// On Linux, in addition to ::std::string, Google also makes use of
+// class ::string, which has the same interface as ::std::string, but
+// has a different implementation.
+//
+// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
+// ::string is available AND is a distinct type to ::std::string, or
+// define it to 0 to indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
+// heuristically.
+
+namespace testing {
+
+// Declares the flags.
+
+// This flag temporary enables the disabled tests.
+GTEST_DECLARE_bool_(also_run_disabled_tests);
+
+// This flag brings the debugger on an assertion failure.
+GTEST_DECLARE_bool_(break_on_failure);
+
+// This flag controls whether Google Test catches all test-thrown exceptions
+// and logs them as failures.
+GTEST_DECLARE_bool_(catch_exceptions);
+
+// This flag enables using colors in terminal output. Available values are
+// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
+// to let Google Test decide.
+GTEST_DECLARE_string_(color);
+
+// This flag sets up the filter to select by name using a glob pattern
+// the tests to run. If the filter is not given all tests are executed.
+GTEST_DECLARE_string_(filter);
+
+// This flag causes the Google Test to list tests. None of the tests listed
+// are actually run if the flag is provided.
+GTEST_DECLARE_bool_(list_tests);
+
+// This flag controls whether Google Test emits a detailed XML report to a file
+// in addition to its normal textual output.
+GTEST_DECLARE_string_(output);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flag specifies the random number seed.
+GTEST_DECLARE_int32_(random_seed);
+
+// This flag sets how many times the tests are repeated. The default value
+// is 1. If the value is -1 the tests are repeating forever.
+GTEST_DECLARE_int32_(repeat);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+// When this flag is specified, tests' order is randomized on every iteration.
+GTEST_DECLARE_bool_(shuffle);
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// When this flag is specified, a failed assertion will throw an
+// exception if exceptions are enabled, or exit the program with a
+// non-zero code otherwise.
+GTEST_DECLARE_bool_(throw_on_failure);
+
+// When this flag is set with a "host:port" string, on supported
+// platforms test results are streamed to the specified port on
+// the specified host machine.
+GTEST_DECLARE_string_(stream_result_to);
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+namespace internal {
+
+class AssertHelper;
+class DefaultGlobalTestPartResultReporter;
+class ExecDeathTest;
+class NoExecDeathTest;
+class FinalSuccessChecker;
+class GTestFlagSaver;
+class TestResultAccessor;
+class TestEventListenersAccessor;
+class TestEventRepeater;
+class WindowsDeathTest;
+class UnitTestImpl* GetUnitTestImpl();
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const String& message);
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared in gtest-internal.h but defined here, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable) {
+ return (Message() << streamable).GetString();
+}
+
+} // namespace internal
+
+// The friend relationship of some of these classes is cyclic.
+// If we don't forward declare them the compiler might confuse the classes
+// in friendship clauses with same named classes on the scope.
+class Test;
+class TestCase;
+class TestInfo;
+class UnitTest;
+
+// A class for indicating whether an assertion was successful. When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that describes how it failed.
+//
+// To create an instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// This class is useful for two purposes:
+// 1. Defining predicate functions to be used with Boolean test assertions
+// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
+// 2. Defining predicate-format functions to be
+// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// For example, if you define IsEven predicate:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
+// will print the message
+//
+// Value of: IsEven(Fib(5))
+// Actual: false (5 is odd)
+// Expected: true
+//
+// instead of a more opaque
+//
+// Value of: IsEven(Fib(5))
+// Actual: false
+// Expected: true
+//
+// in case IsEven is a simple Boolean predicate.
+//
+// If you expect your predicate to be reused and want to support informative
+// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
+// about half as often as positive ones in our tests), supply messages for
+// both success and failure cases:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess() << n << " is even";
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
+//
+// Value of: IsEven(Fib(6))
+// Actual: true (8 is even)
+// Expected: false
+//
+// NB: Predicates that support negative Boolean assertions have reduced
+// performance in positive ones so be careful not to use them in tests
+// that have lots (tens of thousands) of positive Boolean assertions.
+//
+// To use this class with EXPECT_PRED_FORMAT assertions such as:
+//
+// // Verifies that Foo() returns an even number.
+// EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you need to define:
+//
+// testing::AssertionResult IsEven(const char* expr, int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure()
+// << "Expected: " << expr << " is even\n Actual: it's " << n;
+// }
+//
+// If Foo() returns 5, you will see the following message:
+//
+// Expected: Foo() is even
+// Actual: it's 5
+//
+class GTEST_API_ AssertionResult {
+ public:
+ // Copy constructor.
+ // Used in EXPECT_TRUE/FALSE(assertion_result).
+ AssertionResult(const AssertionResult& other);
+ // Used in the EXPECT_TRUE/FALSE(bool_expression).
+ explicit AssertionResult(bool success) : success_(success) {}
+
+ // Returns true iff the assertion succeeded.
+ operator bool() const { return success_; } // NOLINT
+
+ // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+ AssertionResult operator!() const;
+
+ // Returns the text streamed into this AssertionResult. Test assertions
+ // use it when they fail (i.e., the predicate's outcome doesn't match the
+ // assertion's expectation). When nothing has been streamed into the
+ // object, returns an empty string.
+ const char* message() const {
+ return message_.get() != NULL ? message_->c_str() : "";
+ }
+ // TODO(vladl@google.com): Remove this after making sure no clients use it.
+ // Deprecated; please use message() instead.
+ const char* failure_message() const { return message(); }
+
+ // Streams a custom failure message into this object.
+ template <typename T> AssertionResult& operator<<(const T& value) {
+ AppendMessage(Message() << value);
+ return *this;
+ }
+
+ // Allows streaming basic output manipulators such as endl or flush into
+ // this object.
+ AssertionResult& operator<<(
+ ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) {
+ AppendMessage(Message() << basic_manipulator);
+ return *this;
+ }
+
+ private:
+ // Appends the contents of message to message_.
+ void AppendMessage(const Message& a_message) {
+ if (message_.get() == NULL)
+ message_.reset(new ::std::string);
+ message_->append(a_message.GetString().c_str());
+ }
+
+ // Stores result of the assertion predicate.
+ bool success_;
+ // Stores the message describing the condition in case the expectation
+ // construct is not satisfied with the predicate's outcome.
+ // Referenced via a pointer to avoid taking too much stack frame space
+ // with test assertions.
+ internal::scoped_ptr< ::std::string> message_;
+
+ GTEST_DISALLOW_ASSIGN_(AssertionResult);
+};
+
+// Makes a successful assertion result.
+GTEST_API_ AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result.
+GTEST_API_ AssertionResult AssertionFailure();
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << msg.
+GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F. For example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { ... }
+// virtual void TearDown() { ... }
+// ...
+// };
+//
+// TEST_F(FooTest, Bar) { ... }
+// TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class GTEST_API_ Test {
+ public:
+ friend class TestInfo;
+
+ // Defines types for pointers to functions that set up and tear down
+ // a test case.
+ typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+ typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
+
+ // The d'tor is virtual as we intend to inherit from Test.
+ virtual ~Test();
+
+ // Sets up the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::SetUpTestCase() before running the first
+ // test in test case Foo. Hence a sub-class can define its own
+ // SetUpTestCase() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestCase() {}
+
+ // Tears down the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::TearDownTestCase() after running the last
+ // test in test case Foo. Hence a sub-class can define its own
+ // TearDownTestCase() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestCase() {}
+
+ // Returns true iff the current test has a fatal failure.
+ static bool HasFatalFailure();
+
+ // Returns true iff the current test has a non-fatal failure.
+ static bool HasNonfatalFailure();
+
+ // Returns true iff the current test has a (either fatal or
+ // non-fatal) failure.
+ static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+ // Logs a property for the current test. Only the last value for a given
+ // key is remembered.
+ // These are public static so they can be called from utility functions
+ // that are not members of the test fixture.
+ // The arguments are const char* instead strings, as Google Test is used
+ // on platforms where string doesn't compile.
+ //
+ // Note that a driving consideration for these RecordProperty methods
+ // was to produce xml output suited to the Greenspan charting utility,
+ // which at present will only chart values that fit in a 32-bit int. It
+ // is the user's responsibility to restrict their values to 32-bit ints
+ // if they intend them to be used with Greenspan.
+ static void RecordProperty(const char* key, const char* value);
+ static void RecordProperty(const char* key, int value);
+
+ protected:
+ // Creates a Test object.
+ Test();
+
+ // Sets up the test fixture.
+ virtual void SetUp();
+
+ // Tears down the test fixture.
+ virtual void TearDown();
+
+ private:
+ // Returns true iff the current test has the same fixture class as
+ // the first test in the current test case.
+ static bool HasSameFixtureClass();
+
+ // Runs the test after the test fixture has been set up.
+ //
+ // A sub-class must implement this to define the test logic.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+ // Instead, use the TEST or TEST_F macro.
+ virtual void TestBody() = 0;
+
+ // Sets up, executes, and tears down the test.
+ void Run();
+
+ // Deletes self. We deliberately pick an unusual name for this
+ // internal method to avoid clashing with names used in user TESTs.
+ void DeleteSelf_() { delete this; }
+
+ // Uses a GTestFlagSaver to save and restore all Google Test flags.
+ const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+ // Often a user mis-spells SetUp() as Setup() and spends a long time
+ // wondering why it is never called by Google Test. The declaration of
+ // the following method is solely for catching such an error at
+ // compile time:
+ //
+ // - The return type is deliberately chosen to be not void, so it
+ // will be a conflict if a user declares void Setup() in his test
+ // fixture.
+ //
+ // - This method is private, so it will be another compiler error
+ // if a user calls it from his test fixture.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION.
+ //
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+ // We disallow copying Tests.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+typedef internal::TimeInMillis TimeInMillis;
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+ // C'tor. TestProperty does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestProperty object.
+ TestProperty(const char* a_key, const char* a_value) :
+ key_(a_key), value_(a_value) {
+ }
+
+ // Gets the user supplied key.
+ const char* key() const {
+ return key_.c_str();
+ }
+
+ // Gets the user supplied value.
+ const char* value() const {
+ return value_.c_str();
+ }
+
+ // Sets a new value, overriding the one supplied in the constructor.
+ void SetValue(const char* new_value) {
+ value_ = new_value;
+ }
+
+ private:
+ // The key supplied by the user.
+ internal::String key_;
+ // The value supplied by the user.
+ internal::String value_;
+};
+
+// The result of a single Test. This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class GTEST_API_ TestResult {
+ public:
+ // Creates an empty TestResult.
+ TestResult();
+
+ // D'tor. Do not inherit from TestResult.
+ ~TestResult();
+
+ // Gets the number of all test parts. This is the sum of the number
+ // of successful test parts and the number of failed test parts.
+ int total_part_count() const;
+
+ // Returns the number of the test properties.
+ int test_property_count() const;
+
+ // Returns true iff the test passed (i.e. no test part failed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test failed.
+ bool Failed() const;
+
+ // Returns true iff the test fatally failed.
+ bool HasFatalFailure() const;
+
+ // Returns true iff the test has a non-fatal failure.
+ bool HasNonfatalFailure() const;
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns the i-th test part result among all the results. i can range
+ // from 0 to test_property_count() - 1. If i is not in that range, aborts
+ // the program.
+ const TestPartResult& GetTestPartResult(int i) const;
+
+ // Returns the i-th test property. i can range from 0 to
+ // test_property_count() - 1. If i is not in that range, aborts the
+ // program.
+ const TestProperty& GetTestProperty(int i) const;
+
+ private:
+ friend class TestInfo;
+ friend class UnitTest;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::ExecDeathTest;
+ friend class internal::TestResultAccessor;
+ friend class internal::UnitTestImpl;
+ friend class internal::WindowsDeathTest;
+
+ // Gets the vector of TestPartResults.
+ const std::vector<TestPartResult>& test_part_results() const {
+ return test_part_results_;
+ }
+
+ // Gets the vector of TestProperties.
+ const std::vector<TestProperty>& test_properties() const {
+ return test_properties_;
+ }
+
+ // Sets the elapsed time.
+ void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+ // Adds a test property to the list. The property is validated and may add
+ // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+ // key names). If a property is already recorded for the same key, the
+ // value will be updated, rather than storing multiple values for the same
+ // key.
+ void RecordProperty(const TestProperty& test_property);
+
+ // Adds a failure if the key is a reserved attribute of Google Test
+ // testcase tags. Returns true if the property is valid.
+ // TODO(russr): Validate attribute names are legal and human readable.
+ static bool ValidateTestProperty(const TestProperty& test_property);
+
+ // Adds a test part result to the list.
+ void AddTestPartResult(const TestPartResult& test_part_result);
+
+ // Returns the death test count.
+ int death_test_count() const { return death_test_count_; }
+
+ // Increments the death test count, returning the new count.
+ int increment_death_test_count() { return ++death_test_count_; }
+
+ // Clears the test part results.
+ void ClearTestPartResults();
+
+ // Clears the object.
+ void Clear();
+
+ // Protects mutable state of the property vector and of owned
+ // properties, whose values may be updated.
+ internal::Mutex test_properites_mutex_;
+
+ // The vector of TestPartResults
+ std::vector<TestPartResult> test_part_results_;
+ // The vector of TestProperties
+ std::vector<TestProperty> test_properties_;
+ // Running count of death tests.
+ int death_test_count_;
+ // The elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestResult.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+}; // class TestResult
+
+// A TestInfo object stores the following information about a test:
+//
+// Test case name
+// Test name
+// Whether the test should be run
+// A function pointer that creates the test object when invoked
+// Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class GTEST_API_ TestInfo {
+ public:
+ // Destructs a TestInfo object. This function is not virtual, so
+ // don't inherit from TestInfo.
+ ~TestInfo();
+
+ // Returns the test case name.
+ const char* test_case_name() const { return test_case_name_.c_str(); }
+
+ // Returns the test name.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the name of the parameter type, or NULL if this is not a typed
+ // or a type-parameterized test.
+ const char* type_param() const {
+ if (type_param_.get() != NULL)
+ return type_param_->c_str();
+ return NULL;
+ }
+
+ // Returns the text representation of the value parameter, or NULL if this
+ // is not a value-parameterized test.
+ const char* value_param() const {
+ if (value_param_.get() != NULL)
+ return value_param_->c_str();
+ return NULL;
+ }
+
+ // Returns true if this test should run, that is if the test is not disabled
+ // (or it is disabled but the also_run_disabled_tests flag has been specified)
+ // and its full name matches the user-specified filter.
+ //
+ // Google Test allows the user to filter the tests by their full names.
+ // The full name of a test Bar in test case Foo is defined as
+ // "Foo.Bar". Only the tests that match the filter will run.
+ //
+ // A filter is a colon-separated list of glob (not regex) patterns,
+ // optionally followed by a '-' and a colon-separated list of
+ // negative patterns (tests to exclude). A test is run if it
+ // matches one of the positive patterns and does not match any of
+ // the negative patterns.
+ //
+ // For example, *A*:Foo.* is a filter that matches any string that
+ // contains the character 'A' or starts with "Foo.".
+ bool should_run() const { return should_run_; }
+
+ // Returns the result of the test.
+ const TestResult* result() const { return &result_; }
+
+ private:
+
+#if GTEST_HAS_DEATH_TEST
+ friend class internal::DefaultDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+ friend class Test;
+ friend class TestCase;
+ friend class internal::UnitTestImpl;
+ friend TestInfo* internal::MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* type_param,
+ const char* value_param,
+ internal::TypeId fixture_class_id,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ internal::TestFactoryBase* factory);
+
+ // Constructs a TestInfo object. The newly constructed instance assumes
+ // ownership of the factory object.
+ TestInfo(const char* test_case_name, const char* name,
+ const char* a_type_param,
+ const char* a_value_param,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory);
+
+ // Increments the number of death tests encountered in this test so
+ // far.
+ int increment_death_test_count() {
+ return result_.increment_death_test_count();
+ }
+
+ // Creates the test object, runs it, records its result, and then
+ // deletes it.
+ void Run();
+
+ static void ClearTestResult(TestInfo* test_info) {
+ test_info->result_.Clear();
+ }
+
+ // These fields are immutable properties of the test.
+ const std::string test_case_name_; // Test case name
+ const std::string name_; // Test name
+ // Name of the parameter type, or NULL if this is not a typed or a
+ // type-parameterized test.
+ const internal::scoped_ptr<const ::std::string> type_param_;
+ // Text representation of the value parameter, or NULL if this is not a
+ // value-parameterized test.
+ const internal::scoped_ptr<const ::std::string> value_param_;
+ const internal::TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True iff this test should run
+ bool is_disabled_; // True iff this test is disabled
+ bool matches_filter_; // True if this test matches the
+ // user-specified filter.
+ internal::TestFactoryBase* const factory_; // The factory that creates
+ // the test object
+
+ // This field is mutable and needs to be reset before running the
+ // test for the second time.
+ TestResult result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// A test case, which consists of a vector of TestInfos.
+//
+// TestCase is not copyable.
+class GTEST_API_ TestCase {
+ public:
+ // Creates a TestCase with the given name.
+ //
+ // TestCase does NOT have a default constructor. Always use this
+ // constructor to create a TestCase object.
+ //
+ // Arguments:
+ //
+ // name: name of the test case
+ // a_type_param: the name of the test's type parameter, or NULL if
+ // this is not a type-parameterized test.
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase(const char* name, const char* a_type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Destructor of TestCase.
+ virtual ~TestCase();
+
+ // Gets the name of the TestCase.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the name of the parameter type, or NULL if this is not a
+ // type-parameterized test case.
+ const char* type_param() const {
+ if (type_param_.get() != NULL)
+ return type_param_->c_str();
+ return NULL;
+ }
+
+ // Returns true if any test in this test case should run.
+ bool should_run() const { return should_run_; }
+
+ // Gets the number of successful tests in this test case.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests in this test case.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests in this test case.
+ int disabled_test_count() const;
+
+ // Get the number of tests in this test case that should run.
+ int test_to_run_count() const;
+
+ // Gets the number of all tests in this test case.
+ int total_test_count() const;
+
+ // Returns true iff the test case passed.
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test case failed.
+ bool Failed() const { return failed_test_count() > 0; }
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ const TestInfo* GetTestInfo(int i) const;
+
+ private:
+ friend class Test;
+ friend class internal::UnitTestImpl;
+
+ // Gets the (mutable) vector of TestInfos in this TestCase.
+ std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
+
+ // Gets the (immutable) vector of TestInfos in this TestCase.
+ const std::vector<TestInfo*>& test_info_list() const {
+ return test_info_list_;
+ }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ TestInfo* GetMutableTestInfo(int i);
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Adds a TestInfo to this test case. Will delete the TestInfo upon
+ // destruction of the TestCase object.
+ void AddTestInfo(TestInfo * test_info);
+
+ // Clears the results of all tests in this test case.
+ void ClearResult();
+
+ // Clears the results of all tests in the given test case.
+ static void ClearTestCaseResult(TestCase* test_case) {
+ test_case->ClearResult();
+ }
+
+ // Runs every test in this TestCase.
+ void Run();
+
+ // Runs SetUpTestCase() for this TestCase. This wrapper is needed
+ // for catching exceptions thrown from SetUpTestCase().
+ void RunSetUpTestCase() { (*set_up_tc_)(); }
+
+ // Runs TearDownTestCase() for this TestCase. This wrapper is
+ // needed for catching exceptions thrown from TearDownTestCase().
+ void RunTearDownTestCase() { (*tear_down_tc_)(); }
+
+ // Returns true iff test passed.
+ static bool TestPassed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Passed();
+ }
+
+ // Returns true iff test failed.
+ static bool TestFailed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Failed();
+ }
+
+ // Returns true iff test is disabled.
+ static bool TestDisabled(const TestInfo* test_info) {
+ return test_info->is_disabled_;
+ }
+
+ // Returns true if the given test should run.
+ static bool ShouldRunTest(const TestInfo* test_info) {
+ return test_info->should_run();
+ }
+
+ // Shuffles the tests in this test case.
+ void ShuffleTests(internal::Random* random);
+
+ // Restores the test order to before the first shuffle.
+ void UnshuffleTests();
+
+ // Name of the test case.
+ internal::String name_;
+ // Name of the parameter type, or NULL if this is not a typed or a
+ // type-parameterized test.
+ const internal::scoped_ptr<const ::std::string> type_param_;
+ // The vector of TestInfos in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestInfo*> test_info_list_;
+ // Provides a level of indirection for the test list to allow easy
+ // shuffling and restoring the test order. The i-th element in this
+ // vector is the index of the i-th test in the shuffled test list.
+ std::vector<int> test_indices_;
+ // Pointer to the function that sets up the test case.
+ Test::SetUpTestCaseFunc set_up_tc_;
+ // Pointer to the function that tears down the test case.
+ Test::TearDownTestCaseFunc tear_down_tc_;
+ // True iff any test in this test case should run.
+ bool should_run_;
+ // Elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestCases.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment. The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+// 1. You cannot safely throw from a destructor. This is a problem
+// as in some cases Google Test is used where exceptions are enabled, and
+// we may want to implement ASSERT_* using exceptions where they are
+// available.
+// 2. You cannot use ASSERT_* directly in a constructor or
+// destructor.
+class Environment {
+ public:
+ // The d'tor is virtual as we need to subclass Environment.
+ virtual ~Environment() {}
+
+ // Override this to define how to set up the environment.
+ virtual void SetUp() {}
+
+ // Override this to define how to tear down the environment.
+ virtual void TearDown() {}
+ private:
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// The interface for tracing execution of tests. The methods are organized in
+// the order the corresponding events are fired.
+class TestEventListener {
+ public:
+ virtual ~TestEventListener() {}
+
+ // Fired before any test activity starts.
+ virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
+
+ // Fired before each iteration of tests starts. There may be more than
+ // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
+ // index, starting from 0.
+ virtual void OnTestIterationStart(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired before environment set-up for each iteration of tests starts.
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment set-up for each iteration of tests ends.
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
+
+ // Fired before the test case starts.
+ virtual void OnTestCaseStart(const TestCase& test_case) = 0;
+
+ // Fired before the test starts.
+ virtual void OnTestStart(const TestInfo& test_info) = 0;
+
+ // Fired after a failed assertion or a SUCCEED() invocation.
+ virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
+
+ // Fired after the test ends.
+ virtual void OnTestEnd(const TestInfo& test_info) = 0;
+
+ // Fired after the test case ends.
+ virtual void OnTestCaseEnd(const TestCase& test_case) = 0;
+
+ // Fired before environment tear-down for each iteration of tests starts.
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment tear-down for each iteration of tests ends.
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;
+
+ // Fired after each iteration of tests finishes.
+ virtual void OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired after all test activities have ended.
+ virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
+};
+
+// The convenience class for users who need to override just one or two
+// methods and are not concerned that a possible change to a signature of
+// the methods they override will not be caught during the build. For
+// comments about each method please see the definition of TestEventListener
+// above.
+class EmptyTestEventListener : public TestEventListener {
+ public:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {}
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+ virtual void OnTestStart(const TestInfo& /*test_info*/) {}
+ virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
+ virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {}
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+};
+
+// TestEventListeners lets users add listeners to track events in Google Test.
+class GTEST_API_ TestEventListeners {
+ public:
+ TestEventListeners();
+ ~TestEventListeners();
+
+ // Appends an event listener to the end of the list. Google Test assumes
+ // the ownership of the listener (i.e. it will delete the listener when
+ // the test program finishes).
+ void Append(TestEventListener* listener);
+
+ // Removes the given event listener from the list and returns it. It then
+ // becomes the caller's responsibility to delete the listener. Returns
+ // NULL if the listener is not found in the list.
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Returns the standard listener responsible for the default console
+ // output. Can be removed from the listeners list to shut down default
+ // console output. Note that removing this object from the listener list
+ // with Release transfers its ownership to the caller and makes this
+ // function return NULL the next time.
+ TestEventListener* default_result_printer() const {
+ return default_result_printer_;
+ }
+
+ // Returns the standard listener responsible for the default XML output
+ // controlled by the --gtest_output=xml flag. Can be removed from the
+ // listeners list by users who want to shut down the default XML output
+ // controlled by this flag and substitute it with custom one. Note that
+ // removing this object from the listener list with Release transfers its
+ // ownership to the caller and makes this function return NULL the next
+ // time.
+ TestEventListener* default_xml_generator() const {
+ return default_xml_generator_;
+ }
+
+ private:
+ friend class TestCase;
+ friend class TestInfo;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::NoExecDeathTest;
+ friend class internal::TestEventListenersAccessor;
+ friend class internal::UnitTestImpl;
+
+ // Returns repeater that broadcasts the TestEventListener events to all
+ // subscribers.
+ TestEventListener* repeater();
+
+ // Sets the default_result_printer attribute to the provided listener.
+ // The listener is also added to the listener list and previous
+ // default_result_printer is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultResultPrinter(TestEventListener* listener);
+
+ // Sets the default_xml_generator attribute to the provided listener. The
+ // listener is also added to the listener list and previous
+ // default_xml_generator is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultXmlGenerator(TestEventListener* listener);
+
+ // Controls whether events will be forwarded by the repeater to the
+ // listeners in the list.
+ bool EventForwardingEnabled() const;
+ void SuppressEventForwarding();
+
+ // The actual list of listeners.
+ internal::TestEventRepeater* repeater_;
+ // Listener responsible for the standard result output.
+ TestEventListener* default_result_printer_;
+ // Listener responsible for the creation of the XML output file.
+ TestEventListener* default_xml_generator_;
+
+ // We disallow copying TestEventListeners.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
+};
+
+// A UnitTest consists of a vector of TestCases.
+//
+// This is a singleton class. The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called. This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class GTEST_API_ UnitTest {
+ public:
+ // Gets the singleton UnitTest object. The first time this method
+ // is called, a UnitTest object is constructed and returned.
+ // Consecutive calls will return the same object.
+ static UnitTest* GetInstance();
+
+ // Runs all tests in this UnitTest object and prints the result.
+ // Returns 0 if successful, or 1 otherwise.
+ //
+ // This method can only be called from the main thread.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ int Run() GTEST_MUST_USE_RESULT_;
+
+ // Returns the working directory when the first TEST() or TEST_F()
+ // was executed. The UnitTest object owns the string.
+ const char* original_working_dir() const;
+
+ // Returns the TestCase object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestCase* current_test_case() const;
+
+ // Returns the TestInfo object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestInfo* current_test_info() const;
+
+ // Returns the random seed used at the start of the current test run.
+ int random_seed() const;
+
+#if GTEST_HAS_PARAM_TEST
+ // Returns the ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry();
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const;
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const;
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const;
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ const TestCase* GetTestCase(int i) const;
+
+ // Returns the list of event listeners that can be used to track events
+ // inside Google Test.
+ TestEventListeners& listeners();
+
+ private:
+ // Registers and returns a global test environment. When a test
+ // program is run, all global test environments will be set-up in
+ // the order they were registered. After all tests in the program
+ // have finished, all global test environments will be torn-down in
+ // the *reverse* order they were registered.
+ //
+ // The UnitTest object takes ownership of the given environment.
+ //
+ // This method can only be called from the main thread.
+ Environment* AddEnvironment(Environment* env);
+
+ // Adds a TestPartResult to the current TestResult object. All
+ // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+ // eventually call this to report their results. The user code
+ // should use the assertion macros instead of calling this directly.
+ void AddTestPartResult(TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace);
+
+ // Adds a TestProperty to the current TestResult object. If the result already
+ // contains a property with the same key, the value will be updated.
+ void RecordPropertyForCurrentTest(const char* key, const char* value);
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ TestCase* GetMutableTestCase(int i);
+
+ // Accessors for the implementation object.
+ internal::UnitTestImpl* impl() { return impl_; }
+ const internal::UnitTestImpl* impl() const { return impl_; }
+
+ // These classes and funcions are friends as they need to access private
+ // members of UnitTest.
+ friend class Test;
+ friend class internal::AssertHelper;
+ friend class internal::ScopedTrace;
+ friend Environment* AddGlobalTestEnvironment(Environment* env);
+ friend internal::UnitTestImpl* internal::GetUnitTestImpl();
+ friend void internal::ReportFailureInUnknownLocation(
+ TestPartResult::Type result_type,
+ const internal::String& message);
+
+ // Creates an empty UnitTest.
+ UnitTest();
+
+ // D'tor
+ virtual ~UnitTest();
+
+ // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+ // Google Test trace stack.
+ void PushGTestTrace(const internal::TraceInfo& trace);
+
+ // Pops a trace from the per-thread Google Test trace stack.
+ void PopGTestTrace();
+
+ // Protects mutable state in *impl_. This is mutable as some const
+ // methods need to lock it too.
+ mutable internal::Mutex mutex_;
+
+ // Opaque implementation object. This field is never changed once
+ // the object is constructed. We don't mark it as const here, as
+ // doing so will cause a warning in the constructor of UnitTest.
+ // Mutable state in *impl_ is protected by mutex_.
+ internal::UnitTestImpl* impl_;
+
+ // We disallow copying UnitTest.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main(). If you use gtest_main, you need to call this before main()
+// starts for it to take effect. For example, you can define a global
+// variable like this:
+//
+// testing::Environment* const foo_env =
+// testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+ return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+GTEST_API_ void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
+
+namespace internal {
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message. The type (but not value)
+// of the other operand may affect the format. This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char*, and print it as a C string when it is compared against an
+// std::string object, for example.
+//
+// The default implementation ignores the type of the other operand.
+// Some specialized versions are used to handle formatting wide or
+// narrow C strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+String FormatForComparisonFailureMessage(const T1& value,
+ const T2& /* other_operand */) {
+ // C++Builder compiles this incorrectly if the namespace isn't explicitly
+ // given.
+ return ::testing::PrintToString(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4389) // Temporarily disables warning on
+ // signed/unsigned mismatch.
+#endif
+
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ. The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal. The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper {
+ public:
+ // This templatized version is for the general case.
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // With this overloaded version, we allow anonymous enums to be used
+ // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+ // enums can be implicitly cast to BiggestInt.
+ //
+ // Even though its body looks the same as the above version, we
+ // cannot merge the two, as it will make anonymous enums unhappy.
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal, like NULL, false, or 0.
+template <>
+class EqHelper<true> {
+ public:
+ // We define two overloaded versions of Compare(). The first
+ // version will be picked when the second argument to ASSERT_EQ() is
+ // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+ // EXPECT_EQ(false, a_bool).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(
+ const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual,
+ // The following line prevents this overload from being considered if T2
+ // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr)
+ // expands to Compare("", "", NULL, my_ptr), which requires a conversion
+ // to match the Secret* in the other overload, which would otherwise make
+ // this template match better.
+ typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // This version will be picked when the second argument to ASSERT_EQ() is a
+ // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+ template <typename T>
+ static AssertionResult Compare(
+ const char* expected_expression,
+ const char* actual_expression,
+ // We used to have a second template parameter instead of Secret*. That
+ // template parameter would deduce to 'long', making this a better match
+ // than the first overload even without the first overload's EnableIf.
+ // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
+ // non-pointer argument" (even a deduced integral argument), so the old
+ // implementation caused warnings in user code.
+ Secret* /* expected (NULL) */,
+ T* actual) {
+ // We already know that 'expected' is a null pointer.
+ return CmpHelperEQ(expected_expression, actual_expression,
+ static_cast<T*>(NULL), actual);
+ }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ const T1& val1, const T2& val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ return AssertionFailure() \
+ << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ }\
+}\
+GTEST_API_ AssertionResult CmpHelper##op_name(\
+ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=);
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=);
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, < );
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=);
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, > );
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
+
+} // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves. They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+ const char* actual_expression,
+ RawType expected,
+ RawType actual) {
+ const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ ::std::stringstream expected_ss;
+ expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << expected;
+
+ ::std::stringstream actual_ss;
+ actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << actual;
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ StringStreamToString(&expected_ss),
+ StringStreamToString(&actual_ss),
+ false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class GTEST_API_ AssertHelper {
+ public:
+ // Constructor.
+ AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message);
+ ~AssertHelper();
+
+ // Message assignment is a semantic trick to enable assertion
+ // streaming; see the GTEST_MESSAGE_ macro below.
+ void operator=(const Message& message) const;
+
+ private:
+ // We put our data in a struct so that the size of the AssertHelper class can
+ // be as small as possible. This is important because gcc is incapable of
+ // re-using stack space even for temporary variables, so every EXPECT_EQ
+ // reserves stack space for another AssertHelper.
+ struct AssertHelperData {
+ AssertHelperData(TestPartResult::Type t,
+ const char* srcfile,
+ int line_num,
+ const char* msg)
+ : type(t), file(srcfile), line(line_num), message(msg) { }
+
+ TestPartResult::Type const type;
+ const char* const file;
+ int const line;
+ String const message;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
+ };
+
+ AssertHelperData* const data_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+} // namespace internal
+
+#if GTEST_HAS_PARAM_TEST
+// The pure interface class that all value-parameterized tests inherit from.
+// A value-parameterized class must inherit from both ::testing::Test and
+// ::testing::WithParamInterface. In most cases that just means inheriting
+// from ::testing::TestWithParam, but more complicated test hierarchies
+// may need to inherit from Test and WithParamInterface at different levels.
+//
+// This interface has support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+// protected:
+// FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual ~FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual void SetUp() {
+// // Can use GetParam() here.
+// }
+// virtual void TearDown {
+// // Can use GetParam() here.
+// }
+// };
+// TEST_P(FooTest, DoesBar) {
+// // Can use GetParam() method here.
+// Foo foo;
+// ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class WithParamInterface {
+ public:
+ typedef T ParamType;
+ virtual ~WithParamInterface() {}
+
+ // The current parameter value. Is also available in the test fixture's
+ // constructor. This member function is non-static, even though it only
+ // references static data, to reduce the opportunity for incorrect uses
+ // like writing 'WithParamInterface<bool>::GetParam()' for a test that
+ // uses a fixture whose parameter type is int.
+ const ParamType& GetParam() const { return *parameter_; }
+
+ private:
+ // Sets parameter value. The caller is responsible for making sure the value
+ // remains alive and unchanged throughout the current test.
+ static void SetParam(const ParamType* parameter) {
+ parameter_ = parameter;
+ }
+
+ // Static value used for accessing parameter during a test lifetime.
+ static const ParamType* parameter_;
+
+ // TestClass must be a subclass of WithParamInterface<T> and Test.
+ template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* WithParamInterface<T>::parameter_ = NULL;
+
+// Most value-parameterized classes can ignore the existence of
+// WithParamInterface, and can just inherit from ::testing::TestWithParam.
+
+template <typename T>
+class TestWithParam : public Test, public WithParamInterface<T> {
+};
+
+#endif // GTEST_HAS_PARAM_TEST
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied. If not,
+// it behaves like ADD_FAILURE. In particular:
+//
+// EXPECT_TRUE verifies that a Boolean condition is true.
+// EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure. People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+//
+// Examples:
+//
+// EXPECT_TRUE(server.StatusIsOK());
+// ASSERT_FALSE(server.HasPendingRequest(port))
+// << "There are still pending requests " << "on port " << port;
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a nonfatal failure at the given source file location with
+// a generic message.
+#define ADD_FAILURE_AT(file, line) \
+ GTEST_MESSAGE_AT_(file, line, "Failed", \
+ ::testing::TestPartResult::kNonFatalFailure)
+
+// Generates a fatal failure with a generic message.
+#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Define this macro to 1 to omit the definition of FAIL(), which is a
+// generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_FAIL
+# define FAIL() GTEST_FAIL()
+#endif
+
+// Generates a success with a generic message.
+#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Define this macro to 1 to omit the definition of SUCCEED(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_SUCCEED
+# define SUCCEED() GTEST_SUCCEED()
+#endif
+
+// Macros for testing exceptions.
+//
+// * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+// Tests that the statement throws the expected exception.
+// * {ASSERT|EXPECT}_NO_THROW(statement):
+// Tests that the statement doesn't throw any exception.
+// * {ASSERT|EXPECT}_ANY_THROW(statement):
+// Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions. Condition can be either a Boolean expression or an
+// AssertionResult. For more information on how to use AssertionResult with
+// these macros see comments on that class.
+#define EXPECT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE_)
+#define EXPECT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE_)
+#define ASSERT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_FATAL_FAILURE_)
+#define ASSERT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_FATAL_FAILURE_)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \
+ ; \
+ else \
+ on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+ const char* e1,
+ Pred pred,
+ const T1& v1) {
+ if (pred(v1)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, v1),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+ #v1, \
+ pred, \
+ v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ Pred pred,
+ const T1& v1,
+ const T2& v2) {
+ if (pred(v1, v2)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+ #v1, \
+ #v2, \
+ pred, \
+ v1, \
+ v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ if (pred(v1, v2, v3)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ pred, \
+ v1, \
+ v2, \
+ v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ", "
+ << e5 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4
+ << "\n" << e5 << " evaluates to " << v5;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ #v5, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4, \
+ v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Macros for testing equalities and inequalities.
+//
+// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values. The values must be compatible built-in types,
+// or you will get a compiler error. By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+// 1. It is possible to make a user-defined type work with
+// {ASSERT|EXPECT}_??(), but that requires overloading the
+// comparison operators and is thus discouraged by the Google C++
+// Usage Guide. Therefore, you are advised to use the
+// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+// equal.
+//
+// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+// pointers (in particular, C strings). Therefore, if you use it
+// with two C strings, you are testing how their locations in memory
+// are related, not how their content is related. To compare two C
+// strings by content, use {ASSERT|EXPECT}_STR*().
+//
+// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+// what the actual value is when it fails, and similarly for the
+// other comparisons.
+//
+// 4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+// evaluate their arguments, which is undefined.
+//
+// 5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+// EXPECT_NE(5, Foo());
+// EXPECT_EQ(NULL, a_pointer);
+// ASSERT_LT(i, array_size);
+// ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define EXPECT_NE(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define GTEST_ASSERT_EQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define GTEST_ASSERT_NE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define GTEST_ASSERT_LE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define GTEST_ASSERT_LT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define GTEST_ASSERT_GE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define GTEST_ASSERT_GT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of
+// ASSERT_XY(), which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_ASSERT_EQ
+# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_NE
+# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LE
+# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LT
+# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GE
+# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GT
+# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
+#endif
+
+// C String Comparisons. All tests treat NULL and any non-NULL string
+// as different. Two NULLs are equal.
+//
+// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
+// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2
+// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+// Tests that two float values are almost equal.
+// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+// Tests that two double values are almost equal.
+// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+// Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands. See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2);
+GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2);
+
+
+#if GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+# define EXPECT_HRESULT_SUCCEEDED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define ASSERT_HRESULT_SUCCEEDED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define EXPECT_HRESULT_FAILED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+# define ASSERT_HRESULT_FAILED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+// EXPECT_NO_FATAL_FAILURE(Process());
+// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope. The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+ __FILE__, __LINE__, ::testing::Message() << (message))
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
+// the same type. The value it returns is not interesting.
+//
+// Instead of making StaticAssertTypeEq a class template, we make it a
+// function template that invokes a helper class template. This
+// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated. For example, given:
+//
+// template <typename T> class Foo {
+// public:
+// void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+// };
+//
+// the code:
+//
+// void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated. Instead, you need:
+//
+// void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+bool StaticAssertTypeEq() {
+ (void)internal::StaticAssertTypeEqHelper<T1, T2>();
+ return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test". For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro. Example:
+//
+// TEST(FooTest, InitializesCorrectly) {
+// Foo foo;
+// EXPECT_TRUE(foo.StatusIsOK());
+// }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test. This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X. The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code. GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define GTEST_TEST(test_case_name, test_name)\
+ GTEST_TEST_(test_case_name, test_name, \
+ ::testing::Test, ::testing::internal::GetTestTypeId())
+
+// Define this macro to 1 to omit the definition of TEST(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_TEST
+# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
+#endif
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name. The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier. The user should put
+// his test code between braces after using this macro. Example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { b_.AddElement(3); }
+//
+// Foo a_;
+// Foo b_;
+// };
+//
+// TEST_F(FooTest, InitializesCorrectly) {
+// EXPECT_TRUE(a_.StatusIsOK());
+// }
+//
+// TEST_F(FooTest, ReturnsElementCountCorrectly) {
+// EXPECT_EQ(0, a_.size());
+// EXPECT_EQ(1, b_.size());
+// }
+
+#define TEST_F(test_fixture, test_name)\
+ GTEST_TEST_(test_fixture, test_name, test_fixture, \
+ ::testing::internal::GetTypeId<test_fixture>())
+
+// Use this macro in main() to run all tests. It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+
+#define RUN_ALL_TESTS()\
+ (::testing::UnitTest::GetInstance()->Run())
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/utils/gtest/obj/Makefile.am b/utils/gtest/obj/Makefile.am
new file mode 100644
index 0000000..4e80759
--- /dev/null
+++ b/utils/gtest/obj/Makefile.am
@@ -0,0 +1,20 @@
+# Automake file
+
+ACLOCAL_AMFLAGS = -I m4
+
+# We define the global AM_CPPFLAGS as everything we compile includes from these
+# directories.
+AM_CPPFLAGS = -I$(srcdir)/../include/
+
+# Modifies compiler and linker flags for pthreads compatibility.
+if HAVE_PTHREADS
+ AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1
+ AM_LIBS = @PTHREAD_LIBS@
+else
+ AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0
+endif
+
+# Build rules for libraries.
+noinst_LTLIBRARIES = ../lib/libgtest.la
+___lib_libgtest_la_SOURCES = ../src/gtest-all.cpp
+
diff --git a/utils/gtest/src/gtest-all.cpp b/utils/gtest/src/gtest-all.cpp
new file mode 100644
index 0000000..f8a58ae
--- /dev/null
+++ b/utils/gtest/src/gtest-all.cpp
@@ -0,0 +1,9118 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build Google Test by compiling a single file.
+// This file serves this purpose.
+
+// This line ensures that gtest.h can be compiled on its own, even
+// when it's fused.
+#include <gtest.h>
+
+// The following lines pull in the real gtest *.cc files.
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+
+namespace testing {
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class GTEST_API_ ScopedFakeTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ // The two possible mocking modes of this object.
+ enum InterceptMode {
+ INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
+ INTERCEPT_ALL_THREADS // Intercepts all failures.
+ };
+
+ // The c'tor sets this object as the test part result reporter used
+ // by Google Test. The 'result' parameter specifies where to report the
+ // results. This reporter will only catch failures generated in the current
+ // thread. DEPRECATED
+ explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+ // Same as above, but you can choose the interception scope of this object.
+ ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+ TestPartResultArray* result);
+
+ // The d'tor restores the previous test part result reporter.
+ virtual ~ScopedFakeTestPartResultReporter();
+
+ // Appends the TestPartResult object to the TestPartResultArray
+ // received in the constructor.
+ //
+ // This method is from the TestPartResultReporterInterface
+ // interface.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+ void Init();
+
+ const InterceptMode intercept_mode_;
+ TestPartResultReporterInterface* old_reporter_;
+ TestPartResultArray* const result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+class GTEST_API_ SingleFailureChecker {
+ public:
+ // The constructor remembers the arguments.
+ SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const string& substr);
+ ~SingleFailureChecker();
+ private:
+ const TestPartResultArray* const results_;
+ const TestPartResult::Type type_;
+ const string substr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures. It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - 'statement' cannot reference local non-static variables or
+// non-static members of the current object.
+// - 'statement' cannot return a value.
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ALL_THREADS, >est_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures. It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. If we do that, the code won't compile when the user gives
+// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
+// expands to code containing an unprotected comma. The
+// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
+// catches that.
+//
+// For the same reason, we have to write
+// if (::testing::internal::AlwaysTrue()) { statement; }
+// instead of
+// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+// to avoid an MSVC warning on unreachable code.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
+ >est_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <vector>
+
+#if GTEST_OS_LINUX
+
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+# include <fcntl.h> // NOLINT
+# include <limits.h> // NOLINT
+# include <sched.h> // NOLINT
+// Declares vsnprintf(). This header is not available on Windows.
+# include <strings.h> // NOLINT
+# include <sys/mman.h> // NOLINT
+# include <sys/time.h> // NOLINT
+# include <unistd.h> // NOLINT
+# include <string>
+
+#elif GTEST_OS_SYMBIAN
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h> // NOLINT
+
+#elif GTEST_OS_ZOS
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h> // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+# include <strings.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE.
+
+# include <windows.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS // We are on Windows proper.
+
+# include <io.h> // NOLINT
+# include <sys/timeb.h> // NOLINT
+# include <sys/types.h> // NOLINT
+# include <sys/stat.h> // NOLINT
+
+# if GTEST_OS_WINDOWS_MINGW
+// MinGW has gettimeofday() but not _ftime64().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+// TODO(kenton@google.com): There are other ways to get the time on
+// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW
+// supports these. consider using them instead.
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h> // NOLINT
+# endif // GTEST_OS_WINDOWS_MINGW
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <windows.h> // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <sys/time.h> // NOLINT
+# include <unistd.h> // NOLINT
+
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h> // NOLINT
+# include <netdb.h> // NOLINT
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation. Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
+// part of Google Test's implementation; otherwise it's undefined.
+#if !GTEST_IMPLEMENTATION_
+// A user is trying to include this from his code - just say no.
+# error "gtest-internal-inl.h is part of Google Test's internal implementation."
+# error "It must not be included except by Google Test itself."
+#endif // GTEST_IMPLEMENTATION_
+
+#ifndef _WIN32_WCE
+# include <errno.h>
+#endif // !_WIN32_WCE
+#include <stddef.h>
+#include <stdlib.h> // For strtoll/_strtoul64/malloc/free.
+#include <string.h> // For memmove.
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+
+#if GTEST_OS_WINDOWS
+# include <windows.h> // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify this flag in the code, but want
+// Google Test's own unit tests to be able to access it. Therefore we
+// declare it here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(death_test_use_fork);
+
+namespace internal {
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kPrintTimeFlag[] = "print_time";
+const char kRandomSeedFlag[] = "random_seed";
+const char kRepeatFlag[] = "repeat";
+const char kShuffleFlag[] = "shuffle";
+const char kStackTraceDepthFlag[] = "stack_trace_depth";
+const char kStreamResultToFlag[] = "stream_result_to";
+const char kThrowOnFailureFlag[] = "throw_on_failure";
+
+// A valid random seed must be in [1, kMaxRandomSeed].
+const int kMaxRandomSeed = 99999;
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+GTEST_API_ extern bool g_help_flag;
+
+// Returns the current time in milliseconds.
+GTEST_API_ TimeInMillis GetTimeInMillis();
+
+// Returns true iff Google Test should use colors in the output.
+GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
+
+// Formats the given time in milliseconds as seconds.
+GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
+
+// Parses a string for an Int32 flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+GTEST_API_ bool ParseInt32Flag(
+ const char* str, const char* flag, Int32* value);
+
+// Returns a random seed in range [1, kMaxRandomSeed] based on the
+// given --gtest_random_seed flag value.
+inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
+ const unsigned int raw_seed = (random_seed_flag == 0) ?
+ static_cast<unsigned int>(GetTimeInMillis()) :
+ static_cast<unsigned int>(random_seed_flag);
+
+ // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
+ // it's easy to type.
+ const int normalized_seed =
+ static_cast<int>((raw_seed - 1U) %
+ static_cast<unsigned int>(kMaxRandomSeed)) + 1;
+ return normalized_seed;
+}
+
+// Returns the first valid random seed after 'seed'. The behavior is
+// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is
+// considered to be 1.
+inline int GetNextRandomSeed(int seed) {
+ GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
+ << "Invalid random seed " << seed << " - must be in [1, "
+ << kMaxRandomSeed << "].";
+ const int next_seed = seed + 1;
+ return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
+}
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+ // The c'tor.
+ GTestFlagSaver() {
+ also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
+ break_on_failure_ = GTEST_FLAG(break_on_failure);
+ catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+ color_ = GTEST_FLAG(color);
+ death_test_style_ = GTEST_FLAG(death_test_style);
+ death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+ filter_ = GTEST_FLAG(filter);
+ internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+ list_tests_ = GTEST_FLAG(list_tests);
+ output_ = GTEST_FLAG(output);
+ print_time_ = GTEST_FLAG(print_time);
+ random_seed_ = GTEST_FLAG(random_seed);
+ repeat_ = GTEST_FLAG(repeat);
+ shuffle_ = GTEST_FLAG(shuffle);
+ stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
+ stream_result_to_ = GTEST_FLAG(stream_result_to);
+ throw_on_failure_ = GTEST_FLAG(throw_on_failure);
+ }
+
+ // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
+ ~GTestFlagSaver() {
+ GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
+ GTEST_FLAG(break_on_failure) = break_on_failure_;
+ GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+ GTEST_FLAG(color) = color_;
+ GTEST_FLAG(death_test_style) = death_test_style_;
+ GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
+ GTEST_FLAG(filter) = filter_;
+ GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+ GTEST_FLAG(list_tests) = list_tests_;
+ GTEST_FLAG(output) = output_;
+ GTEST_FLAG(print_time) = print_time_;
+ GTEST_FLAG(random_seed) = random_seed_;
+ GTEST_FLAG(repeat) = repeat_;
+ GTEST_FLAG(shuffle) = shuffle_;
+ GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
+ GTEST_FLAG(stream_result_to) = stream_result_to_;
+ GTEST_FLAG(throw_on_failure) = throw_on_failure_;
+ }
+ private:
+ // Fields for saving the original values of flags.
+ bool also_run_disabled_tests_;
+ bool break_on_failure_;
+ bool catch_exceptions_;
+ String color_;
+ String death_test_style_;
+ bool death_test_use_fork_;
+ String filter_;
+ String internal_run_death_test_;
+ bool list_tests_;
+ String output_;
+ bool print_time_;
+ bool pretty_;
+ internal::Int32 random_seed_;
+ internal::Int32 repeat_;
+ bool shuffle_;
+ internal::Int32 stack_trace_depth_;
+ String stream_result_to_;
+ bool throw_on_failure_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded();
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (e.g., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+GTEST_API_ bool ShouldShard(const char* total_shards_str,
+ const char* shard_index_str,
+ bool in_subprocess_for_death_test);
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error and
+// and aborts.
+GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+GTEST_API_ bool ShouldRunTestOnShard(
+ int total_shards, int shard_index, int test_id);
+
+// STL container utilities.
+
+// Returns the number of elements in the given container that satisfy
+// the given predicate.
+template <class Container, typename Predicate>
+inline int CountIf(const Container& c, Predicate predicate) {
+ // Implemented as an explicit loop since std::count_if() in libCstd on
+ // Solaris has a non-standard signature.
+ int count = 0;
+ for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) {
+ if (predicate(*it))
+ ++count;
+ }
+ return count;
+}
+
+// Applies a function/functor to each element in the container.
+template <class Container, typename Functor>
+void ForEach(const Container& c, Functor functor) {
+ std::for_each(c.begin(), c.end(), functor);
+}
+
+// Returns the i-th element of the vector, or default_value if i is not
+// in range [0, v.size()).
+template <typename E>
+inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
+ return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
+}
+
+// Performs an in-place shuffle of a range of the vector's elements.
+// 'begin' and 'end' are element indices as an STL-style range;
+// i.e. [begin, end) are shuffled, where 'end' == size() means to
+// shuffle to the end of the vector.
+template <typename E>
+void ShuffleRange(internal::Random* random, int begin, int end,
+ std::vector<E>* v) {
+ const int size = static_cast<int>(v->size());
+ GTEST_CHECK_(0 <= begin && begin <= size)
+ << "Invalid shuffle range start " << begin << ": must be in range [0, "
+ << size << "].";
+ GTEST_CHECK_(begin <= end && end <= size)
+ << "Invalid shuffle range finish " << end << ": must be in range ["
+ << begin << ", " << size << "].";
+
+ // Fisher-Yates shuffle, from
+ // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ for (int range_width = end - begin; range_width >= 2; range_width--) {
+ const int last_in_range = begin + range_width - 1;
+ const int selected = begin + random->Generate(range_width);
+ std::swap((*v)[selected], (*v)[last_in_range]);
+ }
+}
+
+// Performs an in-place shuffle of the vector's elements.
+template <typename E>
+inline void Shuffle(internal::Random* random, std::vector<E>* v) {
+ ShuffleRange(random, 0, static_cast<int>(v->size()), v);
+}
+
+// A function for deleting an object. Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T* x) {
+ delete x;
+}
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+ // Constructor.
+ //
+ // TestPropertyKeyIs has NO default constructor.
+ explicit TestPropertyKeyIs(const char* key)
+ : key_(key) {}
+
+ // Returns true iff the test name of test property matches on key_.
+ bool operator()(const TestProperty& test_property) const {
+ return String(test_property.key()).Compare(key_) == 0;
+ }
+
+ private:
+ String key_;
+};
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests. It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag. E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter. If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class GTEST_API_ UnitTestOptions {
+ public:
+ // Functions for processing the gtest_output flag.
+
+ // Returns the output format, or "" for normal printed output.
+ static String GetOutputFormat();
+
+ // Returns the absolute path of the requested output file, or the
+ // default (test_detail.xml in the original working directory) if
+ // none was explicitly specified.
+ static String GetAbsolutePathToOutputFile();
+
+ // Functions for processing the gtest_filter flag.
+
+ // Returns true iff the wildcard pattern matches the string. The
+ // first ':' or '\0' character in pattern marks the end of it.
+ //
+ // This recursive algorithm isn't very efficient, but is clear and
+ // works well enough for matching test names, which are short.
+ static bool PatternMatchesString(const char *pattern, const char *str);
+
+ // Returns true iff the user-specified filter matches the test case
+ // name and the test name.
+ static bool FilterMatchesTest(const String &test_case_name,
+ const String &test_name);
+
+#if GTEST_OS_WINDOWS
+ // Function for supporting the gtest_catch_exception flag.
+
+ // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+ // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+ // This function is useful as an __except condition.
+ static int GTestShouldProcessSEH(DWORD exception_code);
+#endif // GTEST_OS_WINDOWS
+
+ // Returns true if "name" matches the ':' separated list of glob-style
+ // filters in "filter".
+ static bool MatchesFilter(const String& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present. Used by UnitTestOptions::GetOutputFile.
+GTEST_API_ FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetterInterface() {}
+ virtual ~OsStackTraceGetterInterface() {}
+
+ // Returns the current OS stack trace as a String. Parameters:
+ //
+ // max_depth - the maximum number of stack frames to be included
+ // in the trace.
+ // skip_count - the number of top frames to be skipped; doesn't count
+ // against max_depth.
+ virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+ // UponLeavingGTest() should be called immediately before Google Test calls
+ // user code. It saves some information about the current stack that
+ // CurrentStackTrace() will use to find and hide Google Test stack frames.
+ virtual void UponLeavingGTest() = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetter() : caller_frame_(NULL) {}
+ virtual String CurrentStackTrace(int max_depth, int skip_count);
+ virtual void UponLeavingGTest();
+
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
+ private:
+ Mutex mutex_; // protects all internal state
+
+ // We save the stack frame below the frame that calls user code.
+ // We do this because the address of the frame immediately below
+ // the user code changes between the call to UponLeavingGTest()
+ // and any calls to CurrentStackTrace() from within the user code.
+ void* caller_frame_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+ const char* file;
+ int line;
+ String message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. Reports the test part
+ // result in the current test.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. The implementation just
+ // delegates to the current global test part result reporter of *unit_test_.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
+};
+
+// The private implementation of the UnitTest class. We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class GTEST_API_ UnitTestImpl {
+ public:
+ explicit UnitTestImpl(UnitTest* parent);
+ virtual ~UnitTestImpl();
+
+ // There are two different ways to register your own TestPartResultReporter.
+ // You can register your own repoter to listen either only for test results
+ // from the current thread or for results from all threads.
+ // By default, each per-thread test result repoter just passes a new
+ // TestPartResult to the global test result reporter, which registers the
+ // test part result for the currently running test.
+
+ // Returns the global test part result reporter.
+ TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+ // Sets the global test part result reporter.
+ void SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter);
+
+ // Returns the test part result reporter for the current thread.
+ TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+ // Sets the test part result reporter for the current thread.
+ void SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter);
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const {
+ return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+ }
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ const TestCase* GetTestCase(int i) const {
+ const int index = GetElementOr(test_case_indices_, i, -1);
+ return index < 0 ? NULL : test_cases_[i];
+ }
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ TestCase* GetMutableTestCase(int i) {
+ const int index = GetElementOr(test_case_indices_, i, -1);
+ return index < 0 ? NULL : test_cases_[index];
+ }
+
+ // Provides access to the event listener list.
+ TestEventListeners* listeners() { return &listeners_; }
+
+ // Returns the TestResult for the test that's currently running, or
+ // the TestResult for the ad hoc test if no test is running.
+ TestResult* current_test_result();
+
+ // Returns the TestResult for the ad hoc test.
+ const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
+
+ // Sets the OS stack trace getter.
+ //
+ // Does nothing if the input and the current OS stack trace getter
+ // are the same; otherwise, deletes the old getter and makes the
+ // input the current getter.
+ void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+ // Returns the current OS stack trace getter if it is not NULL;
+ // otherwise, creates an OsStackTraceGetter, makes it the current
+ // getter, and returns it.
+ OsStackTraceGetterInterface* os_stack_trace_getter();
+
+ // Returns the current OS stack trace as a String.
+ //
+ // The maximum number of stack frames to be included is specified by
+ // the gtest_stack_trace_depth flag. The skip_count parameter
+ // specifies the number of top frames to be skipped, which doesn't
+ // count against the number of frames to be included.
+ //
+ // For example, if Foo() calls Bar(), which in turn calls
+ // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+ // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+ String CurrentOsStackTraceExceptTop(int skip_count);
+
+ // Finds and returns a TestCase with the given name. If one doesn't
+ // exist, creates one and returns it.
+ //
+ // Arguments:
+ //
+ // test_case_name: name of the test case
+ // type_param: the name of the test's type parameter, or NULL if
+ // this is not a typed or a type-parameterized test.
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase* GetTestCase(const char* test_case_name,
+ const char* type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Adds a TestInfo to the unit test.
+ //
+ // Arguments:
+ //
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ // test_info: the TestInfo object
+ void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ TestInfo* test_info) {
+ // In order to support thread-safe death tests, we need to
+ // remember the original working directory when the test program
+ // was first invoked. We cannot do this in RUN_ALL_TESTS(), as
+ // the user may have changed the current directory before calling
+ // RUN_ALL_TESTS(). Therefore we capture the current directory in
+ // AddTestInfo(), which is called to register a TEST or TEST_F
+ // before main() is reached.
+ if (original_working_dir_.IsEmpty()) {
+ original_working_dir_.Set(FilePath::GetCurrentDir());
+ GTEST_CHECK_(!original_working_dir_.IsEmpty())
+ << "Failed to get the current working directory.";
+ }
+
+ GetTestCase(test_info->test_case_name(),
+ test_info->type_param(),
+ set_up_tc,
+ tear_down_tc)->AddTestInfo(test_info);
+ }
+
+#if GTEST_HAS_PARAM_TEST
+ // Returns ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+ return parameterized_test_registry_;
+ }
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Sets the TestCase object for the test that's currently running.
+ void set_current_test_case(TestCase* a_current_test_case) {
+ current_test_case_ = a_current_test_case;
+ }
+
+ // Sets the TestInfo object for the test that's currently running. If
+ // current_test_info is NULL, the assertion results will be stored in
+ // ad_hoc_test_result_.
+ void set_current_test_info(TestInfo* a_current_test_info) {
+ current_test_info_ = a_current_test_info;
+ }
+
+ // Registers all parameterized tests defined using TEST_P and
+ // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter
+ // combination. This method can be called more then once; it has guards
+ // protecting from registering the tests more then once. If
+ // value-parameterized tests are disabled, RegisterParameterizedTests is
+ // present but does nothing.
+ void RegisterParameterizedTests();
+
+ // Runs all tests in this UnitTest object, prints the result, and
+ // returns true if all tests are successful. If any exception is
+ // thrown during a test, this test is considered to be failed, but
+ // the rest of the tests will still be run.
+ bool RunAllTests();
+
+ // Clears the results of all tests, except the ad hoc tests.
+ void ClearNonAdHocTestResult() {
+ ForEach(test_cases_, TestCase::ClearTestCaseResult);
+ }
+
+ // Clears the results of ad-hoc test assertions.
+ void ClearAdHocTestResult() {
+ ad_hoc_test_result_.Clear();
+ }
+
+ enum ReactionToSharding {
+ HONOR_SHARDING_PROTOCOL,
+ IGNORE_SHARDING_PROTOCOL
+ };
+
+ // Matches the full name of each test against the user-specified
+ // filter to decide whether the test should run, then records the
+ // result in each TestCase and TestInfo object.
+ // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
+ // based on sharding variables in the environment.
+ // Returns the number of tests that should run.
+ int FilterTests(ReactionToSharding shard_tests);
+
+ // Prints the names of the tests matching the user-specified filter flag.
+ void ListTestsMatchingFilter();
+
+ const TestCase* current_test_case() const { return current_test_case_; }
+ TestInfo* current_test_info() { return current_test_info_; }
+ const TestInfo* current_test_info() const { return current_test_info_; }
+
+ // Returns the vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*>& environments() { return environments_; }
+
+ // Getters for the per-thread Google Test trace stack.
+ std::vector<TraceInfo>& gtest_trace_stack() {
+ return *(gtest_trace_stack_.pointer());
+ }
+ const std::vector<TraceInfo>& gtest_trace_stack() const {
+ return gtest_trace_stack_.get();
+ }
+
+#if GTEST_HAS_DEATH_TEST
+ void InitDeathTestSubprocessControlInfo() {
+ internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+ }
+ // Returns a pointer to the parsed --gtest_internal_run_death_test
+ // flag, or NULL if that flag was not specified.
+ // This information is useful only in a death test child process.
+ // Must not be called before a call to InitGoogleTest.
+ const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+ return internal_run_death_test_flag_.get();
+ }
+
+ // Returns a pointer to the current death test factory.
+ internal::DeathTestFactory* death_test_factory() {
+ return death_test_factory_.get();
+ }
+
+ void SuppressTestEventsIfInSubprocess();
+
+ friend class ReplaceDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Initializes the event listener performing XML output as specified by
+ // UnitTestOptions. Must not be called before InitGoogleTest.
+ void ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+ // Initializes the event listener for streaming test results to a socket.
+ // Must not be called before InitGoogleTest.
+ void ConfigureStreamingOutput();
+#endif
+
+ // Performs initialization dependent upon flag values obtained in
+ // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+ // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+ // this function is also called from RunAllTests. Since this function can be
+ // called more than once, it has to be idempotent.
+ void PostFlagParsingInit();
+
+ // Gets the random seed used at the start of the current test iteration.
+ int random_seed() const { return random_seed_; }
+
+ // Gets the random number generator.
+ internal::Random* random() { return &random_; }
+
+ // Shuffles all test cases, and the tests within each test case,
+ // making sure that death tests are still run first.
+ void ShuffleTests();
+
+ // Restores the test cases and tests to their order before the first shuffle.
+ void UnshuffleTests();
+
+ // Returns the value of GTEST_FLAG(catch_exceptions) at the moment
+ // UnitTest::Run() starts.
+ bool catch_exceptions() const { return catch_exceptions_; }
+
+ private:
+ friend class ::testing::UnitTest;
+
+ // Used by UnitTest::Run() to capture the state of
+ // GTEST_FLAG(catch_exceptions) at the moment it starts.
+ void set_catch_exceptions(bool value) { catch_exceptions_ = value; }
+
+ // The UnitTest object that owns this implementation object.
+ UnitTest* const parent_;
+
+ // The working directory when the first TEST() or TEST_F() was
+ // executed.
+ internal::FilePath original_working_dir_;
+
+ // The default test part result reporters.
+ DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+ DefaultPerThreadTestPartResultReporter
+ default_per_thread_test_part_result_reporter_;
+
+ // Points to (but doesn't own) the global test part result reporter.
+ TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+ // Protects read and write access to global_test_part_result_reporter_.
+ internal::Mutex global_test_part_result_reporter_mutex_;
+
+ // Points to (but doesn't own) the per-thread test part result reporter.
+ internal::ThreadLocal<TestPartResultReporterInterface*>
+ per_thread_test_part_result_reporter_;
+
+ // The vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*> environments_;
+
+ // The vector of TestCases in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestCase*> test_cases_;
+
+ // Provides a level of indirection for the test case list to allow
+ // easy shuffling and restoring the test case order. The i-th
+ // element of this vector is the index of the i-th test case in the
+ // shuffled order.
+ std::vector<int> test_case_indices_;
+
+#if GTEST_HAS_PARAM_TEST
+ // ParameterizedTestRegistry object used to register value-parameterized
+ // tests.
+ internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+
+ // Indicates whether RegisterParameterizedTests() has been called already.
+ bool parameterized_tests_registered_;
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Index of the last death test case registered. Initially -1.
+ int last_death_test_case_;
+
+ // This points to the TestCase for the currently running test. It
+ // changes as Google Test goes through one test case after another.
+ // When no test is running, this is set to NULL and Google Test
+ // stores assertion results in ad_hoc_test_result_. Initially NULL.
+ TestCase* current_test_case_;
+
+ // This points to the TestInfo for the currently running test. It
+ // changes as Google Test goes through one test after another. When
+ // no test is running, this is set to NULL and Google Test stores
+ // assertion results in ad_hoc_test_result_. Initially NULL.
+ TestInfo* current_test_info_;
+
+ // Normally, a user only writes assertions inside a TEST or TEST_F,
+ // or inside a function called by a TEST or TEST_F. Since Google
+ // Test keeps track of which test is current running, it can
+ // associate such an assertion with the test it belongs to.
+ //
+ // If an assertion is encountered when no TEST or TEST_F is running,
+ // Google Test attributes the assertion result to an imaginary "ad hoc"
+ // test, and records the result in ad_hoc_test_result_.
+ TestResult ad_hoc_test_result_;
+
+ // The list of event listeners that can be used to track events inside
+ // Google Test.
+ TestEventListeners listeners_;
+
+ // The OS stack trace getter. Will be deleted when the UnitTest
+ // object is destructed. By default, an OsStackTraceGetter is used,
+ // but the user can set this field to use a custom getter if that is
+ // desired.
+ OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+ // True iff PostFlagParsingInit() has been called.
+ bool post_flag_parse_init_performed_;
+
+ // The random number seed used at the beginning of the test run.
+ int random_seed_;
+
+ // Our random number generator.
+ internal::Random random_;
+
+ // How long the test took to run, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+#if GTEST_HAS_DEATH_TEST
+ // The decomposed components of the gtest_internal_run_death_test flag,
+ // parsed when RUN_ALL_TESTS is called.
+ internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+ internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
+
+ // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
+ // starts.
+ bool catch_exceptions_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+}; // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+ return UnitTest::GetInstance()->impl();
+}
+
+#if GTEST_USES_SIMPLE_RE
+
+// Internal helper functions for implementing the simple regular
+// expression matcher.
+GTEST_API_ bool IsInSet(char ch, const char* str);
+GTEST_API_ bool IsAsciiDigit(char ch);
+GTEST_API_ bool IsAsciiPunct(char ch);
+GTEST_API_ bool IsRepeat(char ch);
+GTEST_API_ bool IsAsciiWhiteSpace(char ch);
+GTEST_API_ bool IsAsciiWordChar(char ch);
+GTEST_API_ bool IsValidEscape(char ch);
+GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
+GTEST_API_ bool ValidateRegex(const char* regex);
+GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
+GTEST_API_ bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char ch, char repeat, const char* regex, const char* str);
+GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);
+
+#endif // GTEST_USES_SIMPLE_RE
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+#if GTEST_HAS_DEATH_TEST
+
+// Returns the message describing the last system error, regardless of the
+// platform.
+GTEST_API_ String GetLastErrnoDescription();
+
+# if GTEST_OS_WINDOWS
+// Provides leak-safe Windows kernel handle ownership.
+class AutoHandle {
+ public:
+ AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
+ explicit AutoHandle(HANDLE handle) : handle_(handle) {}
+
+ ~AutoHandle() { Reset(); }
+
+ HANDLE Get() const { return handle_; }
+ void Reset() { Reset(INVALID_HANDLE_VALUE); }
+ void Reset(HANDLE handle) {
+ if (handle != handle_) {
+ if (handle_ != INVALID_HANDLE_VALUE)
+ ::CloseHandle(handle_);
+ handle_ = handle;
+ }
+ }
+
+ private:
+ HANDLE handle_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+# endif // GTEST_OS_WINDOWS
+
+// Attempts to parse a string into a positive integer pointed to by the
+// number parameter. Returns true if that is possible.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
+// it here.
+template <typename Integer>
+bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
+ // Fail fast if the given string does not begin with a digit;
+ // this bypasses strtoXXX's "optional leading whitespace and plus
+ // or minus sign" semantics, which are undesirable here.
+ if (str.empty() || !IsDigit(str[0])) {
+ return false;
+ }
+ errno = 0;
+
+ char* end;
+ // BiggestConvertible is the largest integer type that system-provided
+ // string-to-number conversion routines can return.
+
+# if GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+ // MSVC and C++ Builder define __int64 instead of the standard long long.
+ typedef unsigned __int64 BiggestConvertible;
+ const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
+
+# else
+
+ typedef unsigned long long BiggestConvertible; // NOLINT
+ const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
+
+# endif // GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+ const bool parse_success = *end == '\0' && errno == 0;
+
+ // TODO(vladl@google.com): Convert this to compile time assertion when it is
+ // available.
+ GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+ const Integer result = static_cast<Integer>(parsed);
+ if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
+ *number = result;
+ return true;
+ }
+ return false;
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// TestResult contains some private methods that should be hidden from
+// Google Test user but are required for testing. This class allow our tests
+// to access them.
+//
+// This class is supplied only for the purpose of testing Google Test's own
+// constructs. Do not use it in user tests, either directly or indirectly.
+class TestResultAccessor {
+ public:
+ static void RecordProperty(TestResult* test_result,
+ const TestProperty& property) {
+ test_result->RecordProperty(property);
+ }
+
+ static void ClearTestPartResults(TestResult* test_result) {
+ test_result->ClearTestPartResults();
+ }
+
+ static const std::vector<testing::TestPartResult>& test_part_results(
+ const TestResult& test_result) {
+ return test_result.test_part_results();
+ }
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS
+# define vsnprintf _vsnprintf
+#endif // GTEST_OS_WINDOWS
+
+namespace testing {
+
+using internal::CountIf;
+using internal::ForEach;
+using internal::GetElementOr;
+using internal::Shuffle;
+
+// Constants.
+
+// A test whose test case name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test case whose name matches this filter is considered a death
+// test case and will be run before test cases whose name doesn't
+// match this filter.
+static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+// The environment variable name for the test shard index.
+static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+// The environment variable name for the total number of test shards.
+static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard status file.
+static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
+
+namespace internal {
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+bool g_help_flag = false;
+
+} // namespace internal
+
+GTEST_DEFINE_bool_(
+ also_run_disabled_tests,
+ internal::BoolFromGTestEnv("also_run_disabled_tests", false),
+ "Run disabled tests too, in addition to the tests normally being run.");
+
+GTEST_DEFINE_bool_(
+ break_on_failure,
+ internal::BoolFromGTestEnv("break_on_failure", false),
+ "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool_(
+ catch_exceptions,
+ internal::BoolFromGTestEnv("catch_exceptions", true),
+ "True iff " GTEST_NAME_
+ " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+ color,
+ internal::StringFromGTestEnv("color", "auto"),
+ "Whether to use colors in the output. Valid values: yes, no, "
+ "and auto. 'auto' means to use colors if the output is "
+ "being sent to a terminal and the TERM environment variable "
+ "is set to xterm, xterm-color, xterm-256color, linux or cygwin.");
+
+GTEST_DEFINE_string_(
+ filter,
+ internal::StringFromGTestEnv("filter", kUniversalFilter),
+ "A colon-separated list of glob (not regex) patterns "
+ "for filtering the tests to run, optionally followed by a "
+ "'-' and a : separated list of negative patterns (tests to "
+ "exclude). A test is run if it matches one of the positive "
+ "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+ "List all tests without running them.");
+
+GTEST_DEFINE_string_(
+ output,
+ internal::StringFromGTestEnv("output", ""),
+ "A format (currently must be \"xml\"), optionally followed "
+ "by a colon and an output file name or directory. A directory "
+ "is indicated by a trailing pathname separator. "
+ "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+ "If a directory is specified, output files will be created "
+ "within that directory, with file-names based on the test "
+ "executable's name and, if necessary, made unique by adding "
+ "digits.");
+
+GTEST_DEFINE_bool_(
+ print_time,
+ internal::BoolFromGTestEnv("print_time", true),
+ "True iff " GTEST_NAME_
+ " should display elapsed time in text output.");
+
+GTEST_DEFINE_int32_(
+ random_seed,
+ internal::Int32FromGTestEnv("random_seed", 0),
+ "Random number seed to use when shuffling test orders. Must be in range "
+ "[1, 99999], or 0 to use a seed based on the current time.");
+
+GTEST_DEFINE_int32_(
+ repeat,
+ internal::Int32FromGTestEnv("repeat", 1),
+ "How many times to repeat each test. Specify a negative number "
+ "for repeating forever. Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_bool_(
+ show_internal_stack_frames, false,
+ "True iff " GTEST_NAME_ " should include internal stack frames when "
+ "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(
+ shuffle,
+ internal::BoolFromGTestEnv("shuffle", false),
+ "True iff " GTEST_NAME_
+ " should randomize tests' order on every run.");
+
+GTEST_DEFINE_int32_(
+ stack_trace_depth,
+ internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+ "The maximum number of stack frames to print when an "
+ "assertion fails. The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_string_(
+ stream_result_to,
+ internal::StringFromGTestEnv("stream_result_to", ""),
+ "This flag specifies the host name and the port number on which to stream "
+ "test results. Example: \"localhost:555\". The flag is effective only on "
+ "Linux.");
+
+GTEST_DEFINE_bool_(
+ throw_on_failure,
+ internal::BoolFromGTestEnv("throw_on_failure", false),
+ "When this flag is specified, a failed assertion will throw an exception "
+ "if exceptions are enabled or exit the program with a non-zero code "
+ "otherwise.");
+
+namespace internal {
+
+// Generates a random number from [0, range), using a Linear
+// Congruential Generator (LCG). Crashes if 'range' is 0 or greater
+// than kMaxRange.
+UInt32 Random::Generate(UInt32 range) {
+ // These constants are the same as are used in glibc's rand(3).
+ state_ = (1103515245U*state_ + 12345U) % kMaxRange;
+
+ GTEST_CHECK_(range > 0)
+ << "Cannot generate a number in the range [0, 0).";
+ GTEST_CHECK_(range <= kMaxRange)
+ << "Generation of a number in [0, " << range << ") was requested, "
+ << "but this can only generate numbers in [0, " << kMaxRange << ").";
+
+ // Converting via modulus introduces a bit of downward bias, but
+ // it's simple, and a linear congruential generator isn't too good
+ // to begin with.
+ return state_ % range;
+}
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test. Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+//
+// A user must call testing::InitGoogleTest() to initialize Google
+// Test. g_init_gtest_count is set to the number of times
+// InitGoogleTest() has been called. We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+int g_init_gtest_count = 0;
+static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+
+// Iterates over a vector of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
+ int (TestCase::*method)() const) {
+ int sum = 0;
+ for (size_t i = 0; i < case_list.size(); i++) {
+ sum += (case_list[i]->*method)();
+ }
+ return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case) {
+ return test_case->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message)
+ : data_(new AssertHelperData(type, file, line, message)) {
+}
+
+AssertHelper::~AssertHelper() {
+ delete data_;
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+ UnitTest::GetInstance()->
+ AddTestPartResult(data_->type, data_->file, data_->line,
+ AppendUserMessage(data_->message, message),
+ UnitTest::GetInstance()->impl()
+ ->CurrentOsStackTraceExceptTop(1)
+ // Skips the stack frame for this function itself.
+ ); // NOLINT
+}
+
+// Mutex for linked pointers.
+GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// Application pathname gotten in InitGoogleTest.
+String g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+ FilePath result;
+
+#if GTEST_OS_WINDOWS
+ result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+ result.Set(FilePath(g_executable_path));
+#endif // GTEST_OS_WINDOWS
+
+ return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+String UnitTestOptions::GetOutputFormat() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL) return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ return (colon == NULL) ?
+ String(gtest_output_flag) :
+ String(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+String UnitTestOptions::GetAbsolutePathToOutputFile() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL)
+ return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ if (colon == NULL)
+ return String(internal::FilePath::ConcatPaths(
+ internal::FilePath(
+ UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(kDefaultOutputFile)).ToString() );
+
+ internal::FilePath output_name(colon + 1);
+ if (!output_name.IsAbsolutePath())
+ // TODO(wan@google.com): on Windows \some\path is not an absolute
+ // path (as its meaning depends on the current drive), yet the
+ // following logic for turning it into an absolute path is wrong.
+ // Fix it.
+ output_name = internal::FilePath::ConcatPaths(
+ internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(colon + 1));
+
+ if (!output_name.IsDirectory())
+ return output_name.ToString();
+
+ internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+ output_name, internal::GetCurrentExecutableName(),
+ GetOutputFormat().c_str()));
+ return result.ToString();
+}
+
+// Returns true iff the wildcard pattern matches the string. The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char *pattern,
+ const char *str) {
+ switch (*pattern) {
+ case '\0':
+ case ':': // Either ':' or '\0' marks the end of the pattern.
+ return *str == '\0';
+ case '?': // Matches any single character.
+ return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+ case '*': // Matches any string (possibly empty) of characters.
+ return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+ PatternMatchesString(pattern + 1, str);
+ default: // Non-special character. Matches itself.
+ return *pattern == *str &&
+ PatternMatchesString(pattern + 1, str + 1);
+ }
+}
+
+bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) {
+ const char *cur_pattern = filter;
+ for (;;) {
+ if (PatternMatchesString(cur_pattern, name.c_str())) {
+ return true;
+ }
+
+ // Finds the next pattern in the filter.
+ cur_pattern = strchr(cur_pattern, ':');
+
+ // Returns if no more pattern can be found.
+ if (cur_pattern == NULL) {
+ return false;
+ }
+
+ // Skips the pattern separater (the ':' character).
+ cur_pattern++;
+ }
+}
+
+// TODO(keithray): move String function implementations to gtest-string.cc.
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
+ const String &test_name) {
+ const String& full_name = String::Format("%s.%s",
+ test_case_name.c_str(),
+ test_name.c_str());
+
+ // Split --gtest_filter at '-', if there is one, to separate into
+ // positive filter and negative filter portions
+ const char* const p = GTEST_FLAG(filter).c_str();
+ const char* const dash = strchr(p, '-');
+ String positive;
+ String negative;
+ if (dash == NULL) {
+ positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
+ negative = String("");
+ } else {
+ positive = String(p, dash - p); // Everything up to the dash
+ negative = String(dash+1); // Everything after the dash
+ if (positive.empty()) {
+ // Treat '-test1' as the same as '*-test1'
+ positive = kUniversalFilter;
+ }
+ }
+
+ // A filter is a colon-separated list of patterns. It matches a
+ // test if any pattern in it matches the test.
+ return (MatchesFilter(full_name, positive.c_str()) &&
+ !MatchesFilter(full_name, negative.c_str()));
+}
+
+#if GTEST_HAS_SEH
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+ // Google Test should handle a SEH exception if:
+ // 1. the user wants it to, AND
+ // 2. this is not a breakpoint exception, AND
+ // 3. this is not a C++ exception (VC++ implements them via SEH,
+ // apparently).
+ //
+ // SEH exception code for C++ exceptions.
+ // (see http://support.microsoft.com/kb/185294 for more information).
+ const DWORD kCxxExceptionCode = 0xe06d7363;
+
+ bool should_handle = true;
+
+ if (!GTEST_FLAG(catch_exceptions))
+ should_handle = false;
+ else if (exception_code == EXCEPTION_BREAKPOINT)
+ should_handle = false;
+ else if (exception_code == kCxxExceptionCode)
+ should_handle = false;
+
+ return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+#endif // GTEST_HAS_SEH
+
+} // namespace internal
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ TestPartResultArray* result)
+ : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+ result_(result) {
+ Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ InterceptMode intercept_mode, TestPartResultArray* result)
+ : intercept_mode_(intercept_mode),
+ result_(result) {
+ Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ old_reporter_ = impl->GetGlobalTestPartResultReporter();
+ impl->SetGlobalTestPartResultReporter(this);
+ } else {
+ old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+ impl->SetTestPartResultReporterForCurrentThread(this);
+ }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ impl->SetGlobalTestPartResultReporter(old_reporter_);
+ } else {
+ impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+ }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ result_->Append(result);
+}
+
+namespace internal {
+
+// Returns the type ID of ::testing::Test. We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test. This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X. The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code. GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId() {
+ return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResult::Type type,
+ const string& substr) {
+ const String expected(type == TestPartResult::kFatalFailure ?
+ "1 fatal failure" :
+ "1 non-fatal failure");
+ Message msg;
+ if (results.size() != 1) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual: " << results.size() << " failures";
+ for (int i = 0; i < results.size(); i++) {
+ msg << "\n" << results.GetTestPartResult(i);
+ }
+ return AssertionFailure() << msg;
+ }
+
+ const TestPartResult& r = results.GetTestPartResult(0);
+ if (r.type() != type) {
+ return AssertionFailure() << "Expected: " << expected << "\n"
+ << " Actual:\n"
+ << r;
+ }
+
+ if (strstr(r.message(), substr.c_str()) == NULL) {
+ return AssertionFailure() << "Expected: " << expected << " containing \""
+ << substr << "\"\n"
+ << " Actual:\n"
+ << r;
+ }
+
+ return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+ const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const string& substr)
+ : results_(results),
+ type_(type),
+ substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+ EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_);
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->current_test_result()->AddTestPartResult(result);
+ unit_test_->listeners()->repeater()->OnTestPartResult(result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter() {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter) {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
+ return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter) {
+ per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const {
+ return CountIf(test_cases_, TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const {
+ return CountIf(test_cases_, TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const {
+ return static_cast<int>(test_cases_.size());
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const {
+ return CountIf(test_cases_, ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+ (void)skip_count;
+ return String("");
+}
+
+// Returns the current time in milliseconds.
+TimeInMillis GetTimeInMillis() {
+#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
+ // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
+ // http://analogous.blogspot.com/2005/04/epoch.html
+ const TimeInMillis kJavaEpochToWinFileTimeDelta =
+ static_cast<TimeInMillis>(116444736UL) * 100000UL;
+ const DWORD kTenthMicrosInMilliSecond = 10000;
+
+ SYSTEMTIME now_systime;
+ FILETIME now_filetime;
+ ULARGE_INTEGER now_int64;
+ // TODO(kenton@google.com): Shouldn't this just use
+ // GetSystemTimeAsFileTime()?
+ GetSystemTime(&now_systime);
+ if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+ now_int64.LowPart = now_filetime.dwLowDateTime;
+ now_int64.HighPart = now_filetime.dwHighDateTime;
+ now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+ kJavaEpochToWinFileTimeDelta;
+ return now_int64.QuadPart;
+ }
+ return 0;
+#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
+ __timeb64 now;
+
+# ifdef _MSC_VER
+
+ // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+ // (deprecated function) there.
+ // TODO(kenton@google.com): Use GetTickCount()? Or use
+ // SystemTimeToFileTime()
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4996) // Temporarily disables warning 4996.
+ _ftime64(&now);
+# pragma warning(pop) // Restores the warning state.
+# else
+
+ _ftime64(&now);
+
+# endif // _MSC_VER
+
+ return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif GTEST_HAS_GETTIMEOFDAY_
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+# error "Don't know how to get the current time on your system."
+#endif
+}
+
+// Utilities
+
+// class String
+
+// Returns the input enclosed in double quotes if it's not NULL;
+// otherwise returns "(null)". For example, "\"Hello\"" is returned
+// for input "Hello".
+//
+// This is useful for printing a C string in the syntax of a literal.
+//
+// Known issue: escape sequences are not handled yet.
+String String::ShowCStringQuoted(const char* c_str) {
+ return c_str ? String::Format("\"%s\"", c_str) : String("(null)");
+}
+
+// Copies at most length characters from str into a newly-allocated
+// piece of memory of size length+1. The memory is allocated with new[].
+// A terminating null byte is written to the memory, and a pointer to it
+// is returned. If str is NULL, NULL is returned.
+static char* CloneString(const char* str, size_t length) {
+ if (str == NULL) {
+ return NULL;
+ } else {
+ char* const clone = new char[length + 1];
+ posix::StrNCpy(clone, str, length);
+ clone[length] = '\0';
+ return clone;
+ }
+}
+
+// Clones a 0-terminated C string, allocating memory using new. The
+// caller is responsible for deleting[] the return value. Returns the
+// cloned string, or NULL if the input is NULL.
+const char * String::CloneCString(const char* c_str) {
+ return (c_str == NULL) ?
+ NULL : CloneString(c_str, strlen(c_str));
+}
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi) {
+ if (!ansi) return NULL;
+ const int length = strlen(ansi);
+ const int unicode_length =
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ NULL, 0);
+ WCHAR* unicode = new WCHAR[unicode_length + 1];
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ unicode, unicode_length);
+ unicode[unicode_length] = 0;
+ return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str) {
+ if (!utf16_str) return NULL;
+ const int ansi_length =
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ NULL, 0, NULL, NULL);
+ char* ansi = new char[ansi_length + 1];
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ ansi, ansi_length, NULL, NULL);
+ ansi[ansi_length] = 0;
+ return ansi;
+}
+
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Compares two C strings. Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+ return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
+ Message* msg) {
+ // TODO(wan): consider allowing a testing::String object to
+ // contain '\0'. This will make it behave more like std::string,
+ // and will allow ToUtf8String() to return the correct encoding
+ // for '\0' s.t. we can get rid of the conditional here (and in
+ // several other places).
+ for (size_t i = 0; i != length; ) { // NOLINT
+ if (wstr[i] != L'\0') {
+ *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
+ while (i != length && wstr[i] != L'\0')
+ i++;
+ } else {
+ *msg << '\0';
+ i++;
+ }
+ }
+}
+
+#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+} // namespace internal
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// AssertionResult constructors.
+// Used in EXPECT_TRUE/FALSE(assertion_result).
+AssertionResult::AssertionResult(const AssertionResult& other)
+ : success_(other.success_),
+ message_(other.message_.get() != NULL ?
+ new ::std::string(*other.message_) :
+ static_cast< ::std::string*>(NULL)) {
+}
+
+// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+AssertionResult AssertionResult::operator!() const {
+ AssertionResult negation(!success_);
+ if (message_.get() != NULL)
+ negation << *message_;
+ return negation;
+}
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+ return AssertionResult(true);
+}
+
+// Makes a failed assertion result.
+AssertionResult AssertionFailure() {
+ return AssertionResult(false);
+}
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << message.
+AssertionResult AssertionFailure(const Message& message) {
+ return AssertionFailure() << message;
+}
+
+namespace internal {
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case) {
+ Message msg;
+ msg << "Value of: " << actual_expression;
+ if (actual_value != actual_expression) {
+ msg << "\n Actual: " << actual_value;
+ }
+
+ msg << "\nExpected: " << expected_expression;
+ if (ignoring_case) {
+ msg << " (ignoring case)";
+ }
+ if (expected_value != expected_expression) {
+ msg << "\nWhich is: " << expected_value;
+ }
+
+ return AssertionFailure() << msg;
+}
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value) {
+ const char* actual_message = assertion_result.message();
+ Message msg;
+ msg << "Value of: " << expression_text
+ << "\n Actual: " << actual_predicate_value;
+ if (actual_message[0] != '\0')
+ msg << " (" << actual_message << ")";
+ msg << "\nExpected: " << expected_predicate_value;
+ return msg.GetString();
+}
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error) {
+ const double diff = fabs(val1 - val2);
+ if (diff <= abs_error) return AssertionSuccess();
+
+ // TODO(wan): do not print the value of an expression if it's
+ // already a literal.
+ return AssertionFailure()
+ << "The difference between " << expr1 << " and " << expr2
+ << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ", and\n"
+ << abs_error_expr << " evaluates to " << abs_error << ".";
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+ const char* expr2,
+ RawType val1,
+ RawType val2) {
+ // Returns success if val1 is less than val2,
+ if (val1 < val2) {
+ return AssertionSuccess();
+ }
+
+ // or if val1 is almost equal to val2.
+ const FloatingPoint<RawType> lhs(val1), rhs(val2);
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ // Note that the above two checks will both fail if either val1 or
+ // val2 is NaN, as the IEEE floating-point standard requires that
+ // any predicate involving a NaN must return false.
+
+ ::std::stringstream val1_ss;
+ val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val1;
+
+ ::std::stringstream val2_ss;
+ val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val2;
+
+ return AssertionFailure()
+ << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+ << " Actual: " << StringStreamToString(&val1_ss) << " vs "
+ << StringStreamToString(&val2_ss);
+}
+
+} // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2) {
+ return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2) {
+ return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ BiggestInt val1, BiggestInt val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ return AssertionFailure() \
+ << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ return AssertionFailure()
+ << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << ") (ignoring case), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ }
+}
+
+} // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack. NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+ const StringType& haystack) {
+ return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+ bool expected_to_be_substring,
+ const char* needle_expr, const char* haystack_expr,
+ const StringType& needle, const StringType& haystack) {
+ if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+ return AssertionSuccess();
+
+ const bool is_wide_string = sizeof(needle[0]) > 1;
+ const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+ return AssertionFailure()
+ << "Value of: " << needle_expr << "\n"
+ << " Actual: " << begin_string_quote << needle << "\"\n"
+ << "Expected: " << (expected_to_be_substring ? "" : "not ")
+ << "a substring of " << haystack_expr << "\n"
+ << "Which is: " << begin_string_quote << haystack << "\"";
+}
+
+} // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+ const char* expected,
+ long hr) { // NOLINT
+# if GTEST_OS_WINDOWS_MOBILE
+
+ // Windows CE doesn't support FormatMessage.
+ const char error_text[] = "";
+
+# else
+
+ // Looks up the human-readable system message for the HRESULT code
+ // and since we're not passing any params to FormatMessage, we don't
+ // want inserts expanded.
+ const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS;
+ const DWORD kBufSize = 4096; // String::Format can't exceed this length.
+ // Gets the system's human readable message string for this HRESULT.
+ char error_text[kBufSize] = { '\0' };
+ DWORD message_length = ::FormatMessageA(kFlags,
+ 0, // no source, we're asking system
+ hr, // the error
+ 0, // no line width restrictions
+ error_text, // output buffer
+ kBufSize, // buf size
+ NULL); // no arguments for inserts
+ // Trims tailing white space (FormatMessage leaves a trailing cr-lf)
+ for (; message_length && IsSpace(error_text[message_length - 1]);
+ --message_length) {
+ error_text[message_length - 1] = '\0';
+ }
+
+# endif // GTEST_OS_WINDOWS_MOBILE
+
+ const String error_hex(String::Format("0x%08X ", hr));
+ return ::testing::AssertionFailure()
+ << "Expected: " << expr << " " << expected << ".\n"
+ << " Actual: " << error_hex << error_text << "\n";
+}
+
+} // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT
+ if (SUCCEEDED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT
+ if (FAILED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length Encoding
+// 0 - 7 bits 0xxxxxxx
+// 8 - 11 bits 110xxxxx 10xxxxxx
+// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx
+// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) << 7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern. Returns the n
+// lowest bits. As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n) {
+ const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+ *bits >>= n;
+ return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+char* CodePointToUtf8(UInt32 code_point, char* str) {
+ if (code_point <= kMaxCodePoint1) {
+ str[1] = '\0';
+ str[0] = static_cast<char>(code_point); // 0xxxxxxx
+ } else if (code_point <= kMaxCodePoint2) {
+ str[2] = '\0';
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xC0 | code_point); // 110xxxxx
+ } else if (code_point <= kMaxCodePoint3) {
+ str[3] = '\0';
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xE0 | code_point); // 1110xxxx
+ } else if (code_point <= kMaxCodePoint4) {
+ str[4] = '\0';
+ str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xF0 | code_point); // 11110xxx
+ } else {
+ // The longest string String::Format can produce when invoked
+ // with these parameters is 28 character long (not including
+ // the terminating nul character). We are asking for 32 character
+ // buffer just in case. This is also enough for strncpy to
+ // null-terminate the destination string.
+ posix::StrNCpy(
+ str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32);
+ str[31] = '\0'; // Makes sure no change in the format to strncpy leaves
+ // the result unterminated.
+ }
+ return str;
+}
+
+// The following two functions only make sense if the the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
+ return sizeof(wchar_t) == 2 &&
+ (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+ wchar_t second) {
+ const UInt32 mask = (1 << 10) - 1;
+ return (sizeof(wchar_t) == 2) ?
+ (((first & mask) << 10) | (second & mask)) + 0x10000 :
+ // This function should not be called when the condition is
+ // false, but we provide a sensible default in case it is.
+ static_cast<UInt32>(first);
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+String WideStringToUtf8(const wchar_t* str, int num_chars) {
+ if (num_chars == -1)
+ num_chars = static_cast<int>(wcslen(str));
+
+ ::std::stringstream stream;
+ for (int i = 0; i < num_chars; ++i) {
+ UInt32 unicode_code_point;
+
+ if (str[i] == L'\0') {
+ break;
+ } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+ unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+ str[i + 1]);
+ i++;
+ } else {
+ unicode_code_point = static_cast<UInt32>(str[i]);
+ }
+
+ char buffer[32]; // CodePointToUtf8 requires a buffer this big.
+ stream << CodePointToUtf8(unicode_code_point, buffer);
+ }
+ return StringStreamToString(&stream);
+}
+
+// Converts a wide C string to a String using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+String String::ShowWideCString(const wchar_t * wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ return String(internal::WideStringToUtf8(wide_c_str, -1).c_str());
+}
+
+// Similar to ShowWideCString(), except that this function encloses
+// the converted string in double quotes.
+String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ return String::Format("L\"%s\"",
+ String::ShowWideCString(wide_c_str).c_str());
+}
+
+// Compares two wide C strings. Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+ return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual) {
+ if (String::WideCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowWideCStringQuoted(expected),
+ String::ShowWideCStringQuoted(actual),
+ false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2) {
+ if (!String::WideCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ }
+
+ return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: "
+ << String::ShowWideCStringQuoted(s1)
+ << " vs " << String::ShowWideCStringQuoted(s2);
+}
+
+// Compares two C strings, ignoring case. Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s). A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+ if (lhs == NULL)
+ return rhs == NULL;
+ if (rhs == NULL)
+ return false;
+ return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs) {
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+#if GTEST_OS_WINDOWS
+ return _wcsicmp(lhs, rhs) == 0;
+#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID
+ return wcscasecmp(lhs, rhs) == 0;
+#else
+ // Android, Mac OS X and Cygwin don't define wcscasecmp.
+ // Other unknown OSes may not define it either.
+ wint_t left, right;
+ do {
+ left = towlower(*lhs++);
+ right = towlower(*rhs++);
+ } while (left && left == right);
+ return left == right;
+#endif // OS selector
+}
+
+// Compares this with another String.
+// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+// if this is greater than rhs.
+int String::Compare(const String & rhs) const {
+ const char* const lhs_c_str = c_str();
+ const char* const rhs_c_str = rhs.c_str();
+
+ if (lhs_c_str == NULL) {
+ return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL
+ } else if (rhs_c_str == NULL) {
+ return 1;
+ }
+
+ const size_t shorter_str_len =
+ length() <= rhs.length() ? length() : rhs.length();
+ for (size_t i = 0; i != shorter_str_len; i++) {
+ if (lhs_c_str[i] < rhs_c_str[i]) {
+ return -1;
+ } else if (lhs_c_str[i] > rhs_c_str[i]) {
+ return 1;
+ }
+ }
+ return (length() < rhs.length()) ? -1 :
+ (length() > rhs.length()) ? 1 : 0;
+}
+
+// Returns true iff this String ends with the given suffix. *Any*
+// String is considered to end with a NULL or empty suffix.
+bool String::EndsWith(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str() == NULL) return false;
+
+ const size_t this_len = strlen(c_str());
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CStringEquals(c_str() + this_len - suffix_len, suffix);
+}
+
+// Returns true iff this String ends with the given suffix, ignoring case.
+// Any String is considered to end with a NULL or empty suffix.
+bool String::EndsWithCaseInsensitive(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str() == NULL) return false;
+
+ const size_t this_len = strlen(c_str());
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix);
+}
+
+// Formats a list of arguments to a String, using the same format
+// spec string as for printf.
+//
+// We do not use the StringPrintf class as it is not universally
+// available.
+//
+// The result is limited to 4096 characters (including the tailing 0).
+// If 4096 characters are not enough to format the input, or if
+// there's an error, "<formatting error or buffer exceeded>" is
+// returned.
+String String::Format(const char * format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ char buffer[4096];
+ const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]);
+
+ // MSVC 8 deprecates vsnprintf(), so we want to suppress warning
+ // 4996 (deprecated function) there.
+#ifdef _MSC_VER // We are using MSVC.
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4996) // Temporarily disables warning 4996.
+
+ const int size = vsnprintf(buffer, kBufferSize, format, args);
+
+# pragma warning(pop) // Restores the warning state.
+#else // We are not using MSVC.
+ const int size = vsnprintf(buffer, kBufferSize, format, args);
+#endif // _MSC_VER
+ va_end(args);
+
+ // vsnprintf()'s behavior is not portable. When the buffer is not
+ // big enough, it returns a negative value in MSVC, and returns the
+ // needed buffer size on Linux. When there is an output error, it
+ // always returns a negative value. For simplicity, we lump the two
+ // error cases together.
+ if (size < 0 || size >= kBufferSize) {
+ return String("<formatting error or buffer exceeded>");
+ } else {
+ return String(buffer, size);
+ }
+}
+
+// Converts the buffer in a stringstream to a String, converting NUL
+// bytes to "\\0" along the way.
+String StringStreamToString(::std::stringstream* ss) {
+ const ::std::string& str = ss->str();
+ const char* const start = str.c_str();
+ const char* const end = start + str.length();
+
+ // We need to use a helper stringstream to do this transformation
+ // because String doesn't support push_back().
+ ::std::stringstream helper;
+ for (const char* ch = start; ch != end; ++ch) {
+ if (*ch == '\0') {
+ helper << "\\0"; // Replaces NUL with "\\0";
+ } else {
+ helper.put(*ch);
+ }
+ }
+
+ return String(helper.str().c_str());
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg) {
+ // Appends the user message if it's non-empty.
+ const String user_msg_string = user_msg.GetString();
+ if (user_msg_string.empty()) {
+ return gtest_msg;
+ }
+
+ Message msg;
+ msg << gtest_msg << "\n" << user_msg_string;
+
+ return msg.GetString();
+}
+
+} // namespace internal
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+ : death_test_count_(0),
+ elapsed_time_(0) {
+}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Returns the i-th test part result among all the results. i can
+// range from 0 to total_part_count() - 1. If i is not in that range,
+// aborts the program.
+const TestPartResult& TestResult::GetTestPartResult(int i) const {
+ if (i < 0 || i >= total_part_count())
+ internal::posix::Abort();
+ return test_part_results_.at(i);
+}
+
+// Returns the i-th test property. i can range from 0 to
+// test_property_count() - 1. If i is not in that range, aborts the
+// program.
+const TestProperty& TestResult::GetTestProperty(int i) const {
+ if (i < 0 || i >= test_property_count())
+ internal::posix::Abort();
+ return test_properties_.at(i);
+}
+
+// Clears the test part results.
+void TestResult::ClearTestPartResults() {
+ test_part_results_.clear();
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+ test_part_results_.push_back(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const TestProperty& test_property) {
+ if (!ValidateTestProperty(test_property)) {
+ return;
+ }
+ internal::MutexLock lock(&test_properites_mutex_);
+ const std::vector<TestProperty>::iterator property_with_matching_key =
+ std::find_if(test_properties_.begin(), test_properties_.end(),
+ internal::TestPropertyKeyIs(test_property.key()));
+ if (property_with_matching_key == test_properties_.end()) {
+ test_properties_.push_back(test_property);
+ return;
+ }
+ property_with_matching_key->SetValue(test_property.value());
+}
+
+// Adds a failure if the key is a reserved attribute of Google Test
+// testcase tags. Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
+ internal::String key(test_property.key());
+ if (key == "name" || key == "status" || key == "time" || key == "classname") {
+ ADD_FAILURE()
+ << "Reserved key used in RecordProperty(): "
+ << key
+ << " ('name', 'status', 'time', and 'classname' are reserved by "
+ << GTEST_NAME_ << ")";
+ return false;
+ }
+ return true;
+}
+
+// Clears the object.
+void TestResult::Clear() {
+ test_part_results_.clear();
+ test_properties_.clear();
+ death_test_count_ = 0;
+ elapsed_time_ = 0;
+}
+
+// Returns true iff the test failed.
+bool TestResult::Failed() const {
+ for (int i = 0; i < total_part_count(); ++i) {
+ if (GetTestPartResult(i).failed())
+ return true;
+ }
+ return false;
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result) {
+ return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+ return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
+}
+
+// Returns true iff the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result) {
+ return result.nonfatally_failed();
+}
+
+// Returns true iff the test has a non-fatal failure.
+bool TestResult::HasNonfatalFailure() const {
+ return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
+}
+
+// Gets the number of all test parts. This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+ return static_cast<int>(test_part_results_.size());
+}
+
+// Returns the number of the test properties.
+int TestResult::test_property_count() const {
+ return static_cast<int>(test_properties_.size());
+}
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+ : gtest_flag_saver_(new internal::GTestFlagSaver) {
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test() {
+ delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, const char* value) {
+ UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, int value) {
+ Message value_message;
+ value_message << value;
+ RecordProperty(key, value_message.GetString().c_str());
+}
+
+namespace internal {
+
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const String& message) {
+ // This function is a friend of UnitTest and as such has access to
+ // AddTestPartResult.
+ UnitTest::GetInstance()->AddTestPartResult(
+ result_type,
+ NULL, // No info about the source file where the exception occurred.
+ -1, // We have no info on which line caused the exception.
+ message,
+ String()); // No stack trace, either.
+}
+
+} // namespace internal
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class. This function checks if the current test has the
+// same fixture class as the first test in the current test case. If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ const TestCase* const test_case = impl->current_test_case();
+
+ // Info about the first test in the current test case.
+ const TestInfo* const first_test_info = test_case->test_info_list()[0];
+ const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
+ const char* const first_test_name = first_test_info->name();
+
+ // Info about the current test.
+ const TestInfo* const this_test_info = impl->current_test_info();
+ const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_;
+ const char* const this_test_name = this_test_info->name();
+
+ if (this_fixture_id != first_fixture_id) {
+ // Is the first test defined using TEST?
+ const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+ // Is this test defined using TEST?
+ const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+ if (first_is_TEST || this_is_TEST) {
+ // The user mixed TEST and TEST_F in this test case - we'll tell
+ // him/her how to fix it.
+
+ // Gets the name of the TEST and the name of the TEST_F. Note
+ // that first_is_TEST and this_is_TEST cannot both be true, as
+ // the fixture IDs are different for the two tests.
+ const char* const TEST_name =
+ first_is_TEST ? first_test_name : this_test_name;
+ const char* const TEST_F_name =
+ first_is_TEST ? this_test_name : first_test_name;
+
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test case is\n"
+ << "illegal. In test case " << this_test_info->test_case_name()
+ << ",\n"
+ << "test " << TEST_F_name << " is defined using TEST_F but\n"
+ << "test " << TEST_name << " is defined using TEST. You probably\n"
+ << "want to change the TEST to TEST_F or move it to another test\n"
+ << "case.";
+ } else {
+ // The user defined two fixture classes with the same name in
+ // two namespaces - we'll tell him/her how to fix it.
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case "
+ << this_test_info->test_case_name() << ",\n"
+ << "you defined test " << first_test_name
+ << " and test " << this_test_name << "\n"
+ << "using two different test fixture classes. This can happen if\n"
+ << "the two classes are from different namespaces or translation\n"
+ << "units and have the same name. You should probably rename one\n"
+ << "of the classes to put the tests into different test cases.";
+ }
+ return false;
+ }
+
+ return true;
+}
+
+#if GTEST_HAS_SEH
+
+// Adds an "exception thrown" fatal failure to the current test. This
+// function returns its result via an output parameter pointer because VC++
+// prohibits creation of objects with destructors on stack in functions
+// using __try (see error C2712).
+static internal::String* FormatSehExceptionMessage(DWORD exception_code,
+ const char* location) {
+ Message message;
+ message << "SEH exception with code 0x" << std::setbase(16) <<
+ exception_code << std::setbase(10) << " thrown in " << location << ".";
+
+ return new internal::String(message.GetString());
+}
+
+#endif // GTEST_HAS_SEH
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Adds an "exception thrown" fatal failure to the current test.
+static internal::String FormatCxxExceptionMessage(const char* description,
+ const char* location) {
+ Message message;
+ if (description != NULL) {
+ message << "C++ exception with description \"" << description << "\"";
+ } else {
+ message << "Unknown C++ exception";
+ }
+ message << " thrown in " << location << ".";
+
+ return message.GetString();
+}
+
+static internal::String PrintTestPartResultToString(
+ const TestPartResult& test_part_result);
+
+// A failed Google Test assertion will throw an exception of this type when
+// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We
+// derive it from std::runtime_error, which is for errors presumably
+// detectable only at run time. Since std::runtime_error inherits from
+// std::exception, many testing frameworks know how to extract and print the
+// message inside it.
+class GoogleTestFailureException : public ::std::runtime_error {
+ public:
+ explicit GoogleTestFailureException(const TestPartResult& failure)
+ : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+};
+#endif // GTEST_HAS_EXCEPTIONS
+
+namespace internal {
+// We put these helper functions in the internal namespace as IBM's xlC
+// compiler rejects the code if they were declared static.
+
+// Runs the given method and handles SEH exceptions it throws, when
+// SEH is supported; returns the 0-value for type Result in case of an
+// SEH exception. (Microsoft compilers cannot handle SEH and C++
+// exceptions in the same function. Therefore, we provide a separate
+// wrapper function for handling SEH exceptions.)
+template <class T, typename Result>
+Result HandleSehExceptionsInMethodIfSupported(
+ T* object, Result (T::*method)(), const char* location) {
+#if GTEST_HAS_SEH
+ __try {
+ return (object->*method)();
+ } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT
+ GetExceptionCode())) {
+ // We create the exception message on the heap because VC++ prohibits
+ // creation of objects with destructors on stack in functions using __try
+ // (see error C2712).
+ internal::String* exception_message = FormatSehExceptionMessage(
+ GetExceptionCode(), location);
+ internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+ *exception_message);
+ delete exception_message;
+ return static_cast<Result>(0);
+ }
+#else
+ (void)location;
+ return (object->*method)();
+#endif // GTEST_HAS_SEH
+}
+
+// Runs the given method and catches and reports C++ and/or SEH-style
+// exceptions, if they are supported; returns the 0-value for type
+// Result in case of an SEH exception.
+template <class T, typename Result>
+Result HandleExceptionsInMethodIfSupported(
+ T* object, Result (T::*method)(), const char* location) {
+ // NOTE: The user code can affect the way in which Google Test handles
+ // exceptions by setting GTEST_FLAG(catch_exceptions), but only before
+ // RUN_ALL_TESTS() starts. It is technically possible to check the flag
+ // after the exception is caught and either report or re-throw the
+ // exception based on the flag's value:
+ //
+ // try {
+ // // Perform the test method.
+ // } catch (...) {
+ // if (GTEST_FLAG(catch_exceptions))
+ // // Report the exception as failure.
+ // else
+ // throw; // Re-throws the original exception.
+ // }
+ //
+ // However, the purpose of this flag is to allow the program to drop into
+ // the debugger when the exception is thrown. On most platforms, once the
+ // control enters the catch block, the exception origin information is
+ // lost and the debugger will stop the program at the point of the
+ // re-throw in this function -- instead of at the point of the original
+ // throw statement in the code under test. For this reason, we perform
+ // the check early, sacrificing the ability to affect Google Test's
+ // exception handling in the method where the exception is thrown.
+ if (internal::GetUnitTestImpl()->catch_exceptions()) {
+#if GTEST_HAS_EXCEPTIONS
+ try {
+ return HandleSehExceptionsInMethodIfSupported(object, method, location);
+ } catch (const GoogleTestFailureException&) { // NOLINT
+ // This exception doesn't originate in code under test. It makes no
+ // sense to report it as a test failure.
+ throw;
+ } catch (const std::exception& e) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(e.what(), location));
+ } catch (...) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(NULL, location));
+ }
+ return static_cast<Result>(0);
+#else
+ return HandleSehExceptionsInMethodIfSupported(object, method, location);
+#endif // GTEST_HAS_EXCEPTIONS
+ } else {
+ return (object->*method)();
+ }
+}
+
+} // namespace internal
+
+// Runs the test and updates the test result.
+void Test::Run() {
+ if (!HasSameFixtureClass()) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
+ // We will run the test only if SetUp() was successful.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &Test::TestBody, "the test body");
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &Test::TearDown, "TearDown()");
+}
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true iff the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->
+ HasNonfatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object.
+// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s
+// to signify they cannot be NULLs.
+TestInfo::TestInfo(const char* a_test_case_name,
+ const char* a_name,
+ const char* a_type_param,
+ const char* a_value_param,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory)
+ : test_case_name_(a_test_case_name),
+ name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+ value_param_(a_value_param ? new std::string(a_value_param) : NULL),
+ fixture_class_id_(fixture_class_id),
+ should_run_(false),
+ is_disabled_(false),
+ matches_filter_(false),
+ factory_(factory),
+ result_() {}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() { delete factory_; }
+
+namespace internal {
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// type_param: the name of the test's type parameter, or NULL if
+// this is not a typed or a type-parameterized test.
+// value_param: text representation of the test's value parameter,
+// or NULL if this is not a value-parameterized test.
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* type_param,
+ const char* value_param,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory) {
+ TestInfo* const test_info =
+ new TestInfo(test_case_name, name, type_param, value_param,
+ fixture_class_id, factory);
+ GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+ return test_info;
+}
+
+#if GTEST_HAS_PARAM_TEST
+void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line) {
+ Message errors;
+ errors
+ << "Attempted redefinition of test case " << test_case_name << ".\n"
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case " << test_case_name << ", you tried\n"
+ << "to define a test using a fixture class different from the one\n"
+ << "used earlier. This can happen if the two fixture classes are\n"
+ << "from different namespaces and have the same name. You should\n"
+ << "probably rename one of the classes to put the tests into different\n"
+ << "test cases.";
+
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors.GetString().c_str());
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+} // namespace internal
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+ // Constructor.
+ //
+ // TestNameIs has NO default constructor.
+ explicit TestNameIs(const char* name)
+ : name_(name) {}
+
+ // Returns true iff the test name of test_info matches name_.
+ bool operator()(const TestInfo * test_info) const {
+ return test_info && internal::String(test_info->name()).Compare(name_) == 0;
+ }
+
+ private:
+ internal::String name_;
+};
+
+} // namespace
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+#if GTEST_HAS_PARAM_TEST
+ if (!parameterized_tests_registered_) {
+ parameterized_test_registry_.RegisterTests();
+ parameterized_tests_registered_ = true;
+ }
+#endif
+}
+
+} // namespace internal
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfo::Run() {
+ if (!should_run_) return;
+
+ // Tells UnitTest where to store test result.
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Notifies the unit test event listeners that a test is about to start.
+ repeater->OnTestStart(*this);
+
+ const TimeInMillis start = internal::GetTimeInMillis();
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+
+ // Creates the test object.
+ Test* const test = internal::HandleExceptionsInMethodIfSupported(
+ factory_, &internal::TestFactoryBase::CreateTest,
+ "the test fixture's constructor");
+
+ // Runs the test only if the test object was created and its
+ // constructor didn't generate a fatal failure.
+ if ((test != NULL) && !Test::HasFatalFailure()) {
+ // This doesn't throw as all user code that can throw are wrapped into
+ // exception handling code.
+ test->Run();
+ }
+
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ test, &Test::DeleteSelf_, "the test fixture's destructor");
+
+ result_.set_elapsed_time(internal::GetTimeInMillis() - start);
+
+ // Notifies the unit test event listener that a test has just finished.
+ repeater->OnTestEnd(*this);
+
+ // Tells UnitTest to stop associating assertion results to this
+ // test.
+ impl->set_current_test_info(NULL);
+}
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const {
+ return CountIf(test_info_list_, TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const {
+ return CountIf(test_info_list_, TestFailed);
+}
+
+int TestCase::disabled_test_count() const {
+ return CountIf(test_info_list_, TestDisabled);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const {
+ return CountIf(test_info_list_, ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const {
+ return static_cast<int>(test_info_list_.size());
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+// name: name of the test case
+// a_type_param: the name of the test case's type parameter, or NULL if
+// this is not a typed or a type-parameterized test case.
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* a_name, const char* a_type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc)
+ : name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+ set_up_tc_(set_up_tc),
+ tear_down_tc_(tear_down_tc),
+ should_run_(false),
+ elapsed_time_(0) {
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase() {
+ // Deletes every Test in the collection.
+ ForEach(test_info_list_, internal::Delete<TestInfo>);
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+const TestInfo* TestCase::GetTestInfo(int i) const {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+TestInfo* TestCase::GetMutableTestInfo(int i) {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Adds a test to this test case. Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo * test_info) {
+ test_info_list_.push_back(test_info);
+ test_indices_.push_back(static_cast<int>(test_indices_.size()));
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_case(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ repeater->OnTestCaseStart(*this);
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
+
+ const internal::TimeInMillis start = internal::GetTimeInMillis();
+ for (int i = 0; i < total_test_count(); i++) {
+ GetMutableTestInfo(i)->Run();
+ }
+ elapsed_time_ = internal::GetTimeInMillis() - start;
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
+
+ repeater->OnTestCaseEnd(*this);
+ impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult() {
+ ForEach(test_info_list_, TestInfo::ClearTestResult);
+}
+
+// Shuffles the tests in this test case.
+void TestCase::ShuffleTests(internal::Random* random) {
+ Shuffle(random, &test_indices_);
+}
+
+// Restores the test order to before the first shuffle.
+void TestCase::UnshuffleTests() {
+ for (size_t i = 0; i < test_indices_.size(); i++) {
+ test_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Formats a countable noun. Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static internal::String FormatCountableNoun(int count,
+ const char * singular_form,
+ const char * plural_form) {
+ return internal::String::Format("%d %s", count,
+ count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static internal::String FormatTestCount(int test_count) {
+ return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static internal::String FormatTestCaseCount(int test_case_count) {
+ return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResult::Type enum to human-friendly string
+// representation. Both kNonFatalFailure and kFatalFailure are translated
+// to "Failure", as the user usually doesn't care about the difference
+// between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResult::Type type) {
+ switch (type) {
+ case TestPartResult::kSuccess:
+ return "Success";
+
+ case TestPartResult::kNonFatalFailure:
+ case TestPartResult::kFatalFailure:
+#ifdef _MSC_VER
+ return "error: ";
+#else
+ return "Failure\n";
+#endif
+ default:
+ return "Unknown result type";
+ }
+}
+
+// Prints a TestPartResult to a String.
+static internal::String PrintTestPartResultToString(
+ const TestPartResult& test_part_result) {
+ return (Message()
+ << internal::FormatFileLocation(test_part_result.file_name(),
+ test_part_result.line_number())
+ << " " << TestPartResultTypeToString(test_part_result.type())
+ << test_part_result.message()).GetString();
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(const TestPartResult& test_part_result) {
+ const internal::String& result =
+ PrintTestPartResultToString(test_part_result);
+ printf("%s\n", result.c_str());
+ fflush(stdout);
+ // If the test program runs in Visual Studio or a debugger, the
+ // following statements add the test part result message to the Output
+ // window such that the user can double-click on it to jump to the
+ // corresponding source code location; otherwise they do nothing.
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ // We don't call OutputDebugString*() on Windows Mobile, as printing
+ // to stdout is done by OutputDebugString() there already - we don't
+ // want the same message printed twice.
+ ::OutputDebugStringA(result.c_str());
+ ::OutputDebugStringA("\n");
+#endif
+}
+
+// class PrettyUnitTestResultPrinter
+
+namespace internal {
+
+enum GTestColor {
+ COLOR_DEFAULT,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW
+};
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return FOREGROUND_RED;
+ case COLOR_GREEN: return FOREGROUND_GREEN;
+ case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+ default: return 0;
+ }
+}
+
+#else
+
+// Returns the ANSI color code for the given color. COLOR_DEFAULT is
+// an invalid input.
+const char* GetAnsiColorCode(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return "1";
+ case COLOR_GREEN: return "2";
+ case COLOR_YELLOW: return "3";
+ default: return NULL;
+ };
+}
+
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+ const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+ if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS
+ // On Windows the TERM variable is usually not set, but the
+ // console there does support colors.
+ return stdout_is_tty;
+#else
+ // On non-Windows platforms, we rely on the TERM variable.
+ const char* const term = posix::GetEnv("TERM");
+ const bool term_supports_color =
+ String::CStringEquals(term, "xterm") ||
+ String::CStringEquals(term, "xterm-color") ||
+ String::CStringEquals(term, "xterm-256color") ||
+ String::CStringEquals(term, "screen") ||
+ String::CStringEquals(term, "linux") ||
+ String::CStringEquals(term, "cygwin");
+ return stdout_is_tty && term_supports_color;
+#endif // GTEST_OS_WINDOWS
+ }
+
+ return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+ String::CStringEquals(gtest_color, "1");
+ // We take "yes", "true", "t", and "1" as meaning "yes". If the
+ // value is neither one of these nor "auto", we treat it as "no" to
+ // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+ const bool use_color = false;
+#else
+ static const bool in_color_mode =
+ ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+ const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
+#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+ // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+ if (!use_color) {
+ vprintf(fmt, args);
+ va_end(args);
+ return;
+ }
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // Gets the current text color.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+ GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+ const WORD old_color_attrs = buffer_info.wAttributes;
+
+ // We need to flush the stream buffers into the console before each
+ // SetConsoleTextAttribute call lest it affect the text that is already
+ // printed but has not yet reached the console.
+ fflush(stdout);
+ SetConsoleTextAttribute(stdout_handle,
+ GetColorAttribute(color) | FOREGROUND_INTENSITY);
+ vprintf(fmt, args);
+
+ fflush(stdout);
+ // Restores the text color.
+ SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+ printf("\033[0;3%sm", GetAnsiColorCode(color));
+ vprintf(fmt, args);
+ printf("\033[m"); // Resets the terminal to default.
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ va_end(args);
+}
+
+void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
+ const char* const type_param = test_info.type_param();
+ const char* const value_param = test_info.value_param();
+
+ if (type_param != NULL || value_param != NULL) {
+ printf(", where ");
+ if (type_param != NULL) {
+ printf("TypeParam = %s", type_param);
+ if (value_param != NULL)
+ printf(" and ");
+ }
+ if (value_param != NULL) {
+ printf("GetParam() = %s", value_param);
+ }
+ }
+}
+
+// This class implements the TestEventListener interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public TestEventListener {
+ public:
+ PrettyUnitTestResultPrinter() {}
+ static void PrintTestName(const char * test_case, const char * test) {
+ printf("%s.%s", test_case, test);
+ }
+
+ // The following methods override what's in the TestEventListener class.
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestCaseStart(const TestCase& test_case);
+ virtual void OnTestStart(const TestInfo& test_info);
+ virtual void OnTestPartResult(const TestPartResult& result);
+ virtual void OnTestEnd(const TestInfo& test_info);
+ virtual void OnTestCaseEnd(const TestCase& test_case);
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+
+ private:
+ static void PrintFailedTests(const UnitTest& unit_test);
+
+ internal::String test_case_name_;
+};
+
+ // Fired before each iteration of tests starts.
+void PrettyUnitTestResultPrinter::OnTestIterationStart(
+ const UnitTest& unit_test, int iteration) {
+ if (GTEST_FLAG(repeat) != 1)
+ printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
+
+ const char* const filter = GTEST_FLAG(filter).c_str();
+
+ // Prints the filter if it's not *. This reminds the user that some
+ // tests may be skipped.
+ if (!internal::String::CStringEquals(filter, kUniversalFilter)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: %s filter = %s\n", GTEST_NAME_, filter);
+ }
+
+ if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+ const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: This is test shard %d of %s.\n",
+ static_cast<int>(shard_index) + 1,
+ internal::posix::GetEnv(kTestTotalShards));
+ }
+
+ if (GTEST_FLAG(shuffle)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: Randomizing tests' orders with a seed of %d .\n",
+ unit_test.random_seed());
+ }
+
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("Running %s from %s.\n",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment set-up.\n");
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
+ test_case_name_ = test_case.name();
+ const internal::String counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_case_name_.c_str());
+ if (test_case.type_param() == NULL) {
+ printf("\n");
+ } else {
+ printf(", where TypeParam = %s\n", test_case.type_param());
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
+ ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
+ PrintTestName(test_case_name_.c_str(), test_info.name());
+ printf("\n");
+ fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnTestPartResult(
+ const TestPartResult& result) {
+ // If the test part succeeded, we don't need to do anything.
+ if (result.type() == TestPartResult::kSuccess)
+ return;
+
+ // Print failure message from the assertion (e.g. expected this and got that).
+ PrintTestPartResult(result);
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+ if (test_info.result()->Passed()) {
+ ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ } else {
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ }
+ PrintTestName(test_case_name_.c_str(), test_info.name());
+ if (test_info.result()->Failed())
+ PrintFullTestCommentIfPresent(test_info);
+
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms)\n", internal::StreamableToString(
+ test_info.result()->elapsed_time()).c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
+ if (!GTEST_FLAG(print_time)) return;
+
+ test_case_name_ = test_case.name();
+ const internal::String counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n",
+ counts.c_str(), test_case_name_.c_str(),
+ internal::StreamableToString(test_case.elapsed_time()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment tear-down\n");
+ fflush(stdout);
+}
+
+// Internal helper for printing the list of failed tests.
+void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
+ const int failed_test_count = unit_test.failed_test_count();
+ if (failed_test_count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ const TestCase& test_case = *unit_test.GetTestCase(i);
+ if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_case.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_case.GetTestInfo(j);
+ if (!test_info.should_run() || test_info.result()->Passed()) {
+ continue;
+ }
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s.%s", test_case.name(), test_info.name());
+ PrintFullTestCommentIfPresent(test_info);
+ printf("\n");
+ }
+ }
+}
+
+void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(unit_test.elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(COLOR_GREEN, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+ int num_failures = unit_test.failed_test_count();
+ if (!unit_test.Passed()) {
+ const int failed_test_count = unit_test.failed_test_count();
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+ PrintFailedTests(unit_test);
+ printf("\n%2d FAILED %s\n", num_failures,
+ num_failures == 1 ? "TEST" : "TESTS");
+ }
+
+ int num_disabled = unit_test.disabled_test_count();
+ if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+ if (!num_failures) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(COLOR_YELLOW,
+ " YOU HAVE %d DISABLED %s\n\n",
+ num_disabled,
+ num_disabled == 1 ? "TEST" : "TESTS");
+ }
+ // Ensure that Google Test output is printed before, e.g., heapchecker output.
+ fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class TestEventRepeater
+//
+// This class forwards events to other event listeners.
+class TestEventRepeater : public TestEventListener {
+ public:
+ TestEventRepeater() : forwarding_enabled_(true) {}
+ virtual ~TestEventRepeater();
+ void Append(TestEventListener *listener);
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled() const { return forwarding_enabled_; }
+ void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
+
+ virtual void OnTestProgramStart(const UnitTest& unit_test);
+ virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
+ virtual void OnTestCaseStart(const TestCase& test_case);
+ virtual void OnTestStart(const TestInfo& test_info);
+ virtual void OnTestPartResult(const TestPartResult& result);
+ virtual void OnTestEnd(const TestInfo& test_info);
+ virtual void OnTestCaseEnd(const TestCase& test_case);
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ virtual void OnTestProgramEnd(const UnitTest& unit_test);
+
+ private:
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled_;
+ // The list of listeners that receive events.
+ std::vector<TestEventListener*> listeners_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
+};
+
+TestEventRepeater::~TestEventRepeater() {
+ ForEach(listeners_, Delete<TestEventListener>);
+}
+
+void TestEventRepeater::Append(TestEventListener *listener) {
+ listeners_.push_back(listener);
+}
+
+// TODO(vladl@google.com): Factor the search functionality into Vector::Find.
+TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
+ for (size_t i = 0; i < listeners_.size(); ++i) {
+ if (listeners_[i] == listener) {
+ listeners_.erase(listeners_.begin() + i);
+ return listener;
+ }
+ }
+
+ return NULL;
+}
+
+// Since most methods are very similar, use macros to reduce boilerplate.
+// This defines a member that forwards the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (size_t i = 0; i < listeners_.size(); i++) { \
+ listeners_[i]->Name(parameter); \
+ } \
+ } \
+}
+// This defines a member that forwards the call to all listeners in reverse
+// order.
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
+ listeners_[i]->Name(parameter); \
+ } \
+ } \
+}
+
+GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
+GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
+
+#undef GTEST_REPEATER_METHOD_
+#undef GTEST_REVERSE_REPEATER_METHOD_
+
+void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
+ int iteration) {
+ if (forwarding_enabled_) {
+ for (size_t i = 0; i < listeners_.size(); i++) {
+ listeners_[i]->OnTestIterationStart(unit_test, iteration);
+ }
+ }
+}
+
+void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration) {
+ if (forwarding_enabled_) {
+ for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
+ listeners_[i]->OnTestIterationEnd(unit_test, iteration);
+ }
+ }
+}
+
+// End TestEventRepeater
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+ explicit XmlUnitTestResultPrinter(const char* output_file);
+
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+
+ private:
+ // Is c a whitespace character that is normalized to a space character
+ // when it appears in an XML attribute value?
+ static bool IsNormalizableWhitespace(char c) {
+ return c == 0x9 || c == 0xA || c == 0xD;
+ }
+
+ // May c appear in a well-formed XML document?
+ static bool IsValidXmlCharacter(char c) {
+ return IsNormalizableWhitespace(c) || c >= 0x20;
+ }
+
+ // Returns an XML-escaped copy of the input string str. If
+ // is_attribute is true, the text is meant to appear as an attribute
+ // value, and normalizable whitespace is preserved by replacing it
+ // with character references.
+ static String EscapeXml(const char* str, bool is_attribute);
+
+ // Returns the given string with all characters invalid in XML removed.
+ static string RemoveInvalidXmlCharacters(const string& str);
+
+ // Convenience wrapper around EscapeXml when str is an attribute value.
+ static String EscapeXmlAttribute(const char* str) {
+ return EscapeXml(str, true);
+ }
+
+ // Convenience wrapper around EscapeXml when str is not an attribute value.
+ static String EscapeXmlText(const char* str) { return EscapeXml(str, false); }
+
+ // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+ static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
+
+ // Streams an XML representation of a TestInfo object.
+ static void OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_case_name,
+ const TestInfo& test_info);
+
+ // Prints an XML representation of a TestCase object
+ static void PrintXmlTestCase(FILE* out, const TestCase& test_case);
+
+ // Prints an XML summary of unit_test to output stream out.
+ static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test);
+
+ // Produces a string representing the test properties in a result as space
+ // delimited XML attributes based on the property key="value" pairs.
+ // When the String is not empty, it includes a space at the beginning,
+ // to delimit this attribute from prior attributes.
+ static String TestPropertiesAsXmlAttributes(const TestResult& result);
+
+ // The output file.
+ const String output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.c_str() == NULL || output_file_.empty()) {
+ fprintf(stderr, "XML output file may not be null\n");
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ FILE* xmlout = NULL;
+ FilePath output_file(output_file_);
+ FilePath output_dir(output_file.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ xmlout = posix::FOpen(output_file_.c_str(), "w");
+ }
+ if (xmlout == NULL) {
+ // TODO(wan): report the reason of the failure.
+ //
+ // We don't do it for now as:
+ //
+ // 1. There is no urgent need for it.
+ // 2. It's a bit involved to make the errno variable thread-safe on
+ // all three operating systems (Linux, Windows, and Mac OS).
+ // 3. To interpret the meaning of errno in a thread-safe way,
+ // we need the strerror_r() function, which is not available on
+ // Windows.
+ fprintf(stderr,
+ "Unable to open file \"%s\"\n",
+ output_file_.c_str());
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ PrintXmlUnitTest(xmlout, unit_test);
+ fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str. If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) {
+ Message m;
+
+ if (str != NULL) {
+ for (const char* src = str; *src; ++src) {
+ switch (*src) {
+ case '<':
+ m << "<";
+ break;
+ case '>':
+ m << ">";
+ break;
+ case '&':
+ m << "&";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "'";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << """;
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(*src)) {
+ if (is_attribute && IsNormalizableWhitespace(*src))
+ m << String::Format("&#x%02X;", unsigned(*src));
+ else
+ m << *src;
+ }
+ break;
+ }
+ }
+ }
+
+ return m.GetString();
+}
+
+// Returns the given string with all characters invalid in XML removed.
+// Currently invalid characters are dropped from the string. An
+// alternative is to replace them with certain characters such as . or ?.
+string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) {
+ string output;
+ output.reserve(str.size());
+ for (string::const_iterator it = str.begin(); it != str.end(); ++it)
+ if (IsValidXmlCharacter(*it))
+ output.push_back(*it);
+
+ return output;
+}
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
+// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
+// <testcase name="test-name"> <-- corresponds to a TestInfo object
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <-- individual assertion failures
+// </testcase>
+// </testsuite>
+// </testsuites>
+
+// Formats the given time in milliseconds as seconds.
+std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+ ::std::stringstream ss;
+ ss << ms/1000.0;
+ return ss.str();
+}
+
+// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
+ const char* data) {
+ const char* segment = data;
+ *stream << "<![CDATA[";
+ for (;;) {
+ const char* const next_segment = strstr(segment, "]]>");
+ if (next_segment != NULL) {
+ stream->write(
+ segment, static_cast<std::streamsize>(next_segment - segment));
+ *stream << "]]>]]><![CDATA[";
+ segment = next_segment + strlen("]]>");
+ } else {
+ *stream << segment;
+ break;
+ }
+ }
+ *stream << "]]>";
+}
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_case_name,
+ const TestInfo& test_info) {
+ const TestResult& result = *test_info.result();
+ *stream << " <testcase name=\""
+ << EscapeXmlAttribute(test_info.name()).c_str() << "\"";
+
+ if (test_info.value_param() != NULL) {
+ *stream << " value_param=\"" << EscapeXmlAttribute(test_info.value_param())
+ << "\"";
+ }
+ if (test_info.type_param() != NULL) {
+ *stream << " type_param=\"" << EscapeXmlAttribute(test_info.type_param())
+ << "\"";
+ }
+
+ *stream << " status=\""
+ << (test_info.should_run() ? "run" : "notrun")
+ << "\" time=\""
+ << FormatTimeInMillisAsSeconds(result.elapsed_time())
+ << "\" classname=\"" << EscapeXmlAttribute(test_case_name).c_str()
+ << "\"" << TestPropertiesAsXmlAttributes(result).c_str();
+
+ int failures = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ if (++failures == 1)
+ *stream << ">\n";
+ *stream << " <failure message=\""
+ << EscapeXmlAttribute(part.summary()).c_str()
+ << "\" type=\"\">";
+ const string location = internal::FormatCompilerIndependentFileLocation(
+ part.file_name(), part.line_number());
+ const string message = location + "\n" + part.message();
+ OutputXmlCDataSection(stream,
+ RemoveInvalidXmlCharacters(message).c_str());
+ *stream << "</failure>\n";
+ }
+ }
+
+ if (failures == 0)
+ *stream << " />\n";
+ else
+ *stream << " </testcase>\n";
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
+ const TestCase& test_case) {
+ fprintf(out,
+ " <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "
+ "disabled=\"%d\" ",
+ EscapeXmlAttribute(test_case.name()).c_str(),
+ test_case.total_test_count(),
+ test_case.failed_test_count(),
+ test_case.disabled_test_count());
+ fprintf(out,
+ "errors=\"0\" time=\"%s\">\n",
+ FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str());
+ for (int i = 0; i < test_case.total_test_count(); ++i) {
+ ::std::stringstream stream;
+ OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i));
+ fprintf(out, "%s", StringStreamToString(&stream).c_str());
+ }
+ fprintf(out, " </testsuite>\n");
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
+ const UnitTest& unit_test) {
+ fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(out,
+ "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
+ "errors=\"0\" time=\"%s\" ",
+ unit_test.total_test_count(),
+ unit_test.failed_test_count(),
+ unit_test.disabled_test_count(),
+ FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str());
+ if (GTEST_FLAG(shuffle)) {
+ fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed());
+ }
+ fprintf(out, "name=\"AllTests\">\n");
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i)
+ PrintXmlTestCase(out, *unit_test.GetTestCase(i));
+ fprintf(out, "</testsuites>\n");
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+ const TestResult& result) {
+ Message attributes;
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ attributes << " " << property.key() << "="
+ << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Streams test results to the given port on the given host machine.
+class StreamingListener : public EmptyTestEventListener {
+ public:
+ // Escapes '=', '&', '%', and '\n' characters in str as "%xx".
+ static string UrlEncode(const char* str);
+
+ StreamingListener(const string& host, const string& port)
+ : sockfd_(-1), host_name_(host), port_num_(port) {
+ MakeConnection();
+ Send("gtest_streaming_protocol_version=1.0\n");
+ }
+
+ virtual ~StreamingListener() {
+ if (sockfd_ != -1)
+ CloseConnection();
+ }
+
+ void OnTestProgramStart(const UnitTest& /* unit_test */) {
+ Send("event=TestProgramStart\n");
+ }
+
+ void OnTestProgramEnd(const UnitTest& unit_test) {
+ // Note that Google Test current only report elapsed time for each
+ // test iteration, not for the entire test program.
+ Send(String::Format("event=TestProgramEnd&passed=%d\n",
+ unit_test.Passed()));
+
+ // Notify the streaming server to stop.
+ CloseConnection();
+ }
+
+ void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
+ Send(String::Format("event=TestIterationStart&iteration=%d\n",
+ iteration));
+ }
+
+ void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
+ Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n",
+ unit_test.Passed(),
+ StreamableToString(unit_test.elapsed_time()).c_str()));
+ }
+
+ void OnTestCaseStart(const TestCase& test_case) {
+ Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name()));
+ }
+
+ void OnTestCaseEnd(const TestCase& test_case) {
+ Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n",
+ test_case.Passed(),
+ StreamableToString(test_case.elapsed_time()).c_str()));
+ }
+
+ void OnTestStart(const TestInfo& test_info) {
+ Send(String::Format("event=TestStart&name=%s\n", test_info.name()));
+ }
+
+ void OnTestEnd(const TestInfo& test_info) {
+ Send(String::Format(
+ "event=TestEnd&passed=%d&elapsed_time=%sms\n",
+ (test_info.result())->Passed(),
+ StreamableToString((test_info.result())->elapsed_time()).c_str()));
+ }
+
+ void OnTestPartResult(const TestPartResult& test_part_result) {
+ const char* file_name = test_part_result.file_name();
+ if (file_name == NULL)
+ file_name = "";
+ Send(String::Format("event=TestPartResult&file=%s&line=%d&message=",
+ UrlEncode(file_name).c_str(),
+ test_part_result.line_number()));
+ Send(UrlEncode(test_part_result.message()) + "\n");
+ }
+
+ private:
+ // Creates a client socket and connects to the server.
+ void MakeConnection();
+
+ // Closes the socket.
+ void CloseConnection() {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "CloseConnection() can be called only when there is a connection.";
+
+ close(sockfd_);
+ sockfd_ = -1;
+ }
+
+ // Sends a string to the socket.
+ void Send(const string& message) {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "Send() can be called only when there is a connection.";
+
+ const int len = static_cast<int>(message.length());
+ if (write(sockfd_, message.c_str(), len) != len) {
+ GTEST_LOG_(WARNING)
+ << "stream_result_to: failed to stream to "
+ << host_name_ << ":" << port_num_;
+ }
+ }
+
+ int sockfd_; // socket file descriptor
+ const string host_name_;
+ const string port_num_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
+}; // class StreamingListener
+
+// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
+// replaces them by "%xx" where xx is their hexadecimal value. For
+// example, replaces "=" with "%3D". This algorithm is O(strlen(str))
+// in both time and space -- important as the input str may contain an
+// arbitrarily long test failure message and stack trace.
+string StreamingListener::UrlEncode(const char* str) {
+ string result;
+ result.reserve(strlen(str) + 1);
+ for (char ch = *str; ch != '\0'; ch = *++str) {
+ switch (ch) {
+ case '%':
+ case '=':
+ case '&':
+ case '\n':
+ result.append(String::Format("%%%02x", static_cast<unsigned char>(ch)));
+ break;
+ default:
+ result.push_back(ch);
+ break;
+ }
+ }
+ return result;
+}
+
+void StreamingListener::MakeConnection() {
+ GTEST_CHECK_(sockfd_ == -1)
+ << "MakeConnection() can't be called when there is already a connection.";
+
+ addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses.
+ hints.ai_socktype = SOCK_STREAM;
+ addrinfo* servinfo = NULL;
+
+ // Use the getaddrinfo() to get a linked list of IP addresses for
+ // the given host name.
+ const int error_num = getaddrinfo(
+ host_name_.c_str(), port_num_.c_str(), &hints, &servinfo);
+ if (error_num != 0) {
+ GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: "
+ << gai_strerror(error_num);
+ }
+
+ // Loop through all the results and connect to the first we can.
+ for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL;
+ cur_addr = cur_addr->ai_next) {
+ sockfd_ = socket(
+ cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol);
+ if (sockfd_ != -1) {
+ // Connect the client socket to the server socket.
+ if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) {
+ close(sockfd_);
+ sockfd_ = -1;
+ }
+ }
+ }
+
+ freeaddrinfo(servinfo); // all done with this structure
+
+ if (sockfd_ == -1) {
+ GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to "
+ << host_name_ << ":" << port_num_;
+ }
+}
+
+// End of class Streaming Listener
+#endif // GTEST_CAN_STREAM_RESULTS__
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+// L < UnitTest::mutex_
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {
+ TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message = message.GetString();
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+// L < UnitTest::mutex_
+ScopedTrace::~ScopedTrace() {
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as a String. Parameters:
+//
+// max_depth - the maximum number of stack frames to be included
+// in the trace.
+// skip_count - the number of top frames to be skipped; doesn't count
+// against max_depth.
+//
+// L < mutex_
+// We use "L < mutex_" to denote that the function may acquire mutex_.
+String OsStackTraceGetter::CurrentStackTrace(int, int) {
+ return String("");
+}
+
+// L < mutex_
+void OsStackTraceGetter::UponLeavingGTest() {
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+ "... " GTEST_NAME_ " internal frames ...";
+
+} // namespace internal
+
+// class TestEventListeners
+
+TestEventListeners::TestEventListeners()
+ : repeater_(new internal::TestEventRepeater()),
+ default_result_printer_(NULL),
+ default_xml_generator_(NULL) {
+}
+
+TestEventListeners::~TestEventListeners() { delete repeater_; }
+
+// Returns the standard listener responsible for the default console
+// output. Can be removed from the listeners list to shut down default
+// console output. Note that removing this object from the listener list
+// with Release transfers its ownership to the user.
+void TestEventListeners::Append(TestEventListener* listener) {
+ repeater_->Append(listener);
+}
+
+// Removes the given event listener from the list and returns it. It then
+// becomes the caller's responsibility to delete the listener. Returns
+// NULL if the listener is not found in the list.
+TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
+ if (listener == default_result_printer_)
+ default_result_printer_ = NULL;
+ else if (listener == default_xml_generator_)
+ default_xml_generator_ = NULL;
+ return repeater_->Release(listener);
+}
+
+// Returns repeater that broadcasts the TestEventListener events to all
+// subscribers.
+TestEventListener* TestEventListeners::repeater() { return repeater_; }
+
+// Sets the default_result_printer attribute to the provided listener.
+// The listener is also added to the listener list and previous
+// default_result_printer is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
+ if (default_result_printer_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_result_printer_);
+ default_result_printer_ = listener;
+ if (listener != NULL)
+ Append(listener);
+ }
+}
+
+// Sets the default_xml_generator attribute to the provided listener. The
+// listener is also added to the listener list and previous
+// default_xml_generator is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
+ if (default_xml_generator_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_xml_generator_);
+ default_xml_generator_ = listener;
+ if (listener != NULL)
+ Append(listener);
+ }
+}
+
+// Controls whether events will be forwarded by the repeater to the
+// listeners in the list.
+bool TestEventListeners::EventForwardingEnabled() const {
+ return repeater_->forwarding_enabled();
+}
+
+void TestEventListeners::SuppressEventForwarding() {
+ repeater_->set_forwarding_enabled(false);
+}
+
+// class UnitTest
+
+// Gets the singleton UnitTest object. The first time this method is
+// called, a UnitTest object is constructed and returned. Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest * UnitTest::GetInstance() {
+ // When compiled with MSVC 7.1 in optimized mode, destroying the
+ // UnitTest object upon exiting the program messes up the exit code,
+ // causing successful tests to appear failed. We have to use a
+ // different implementation in this case to bypass the compiler bug.
+ // This implementation makes the compiler happy, at the cost of
+ // leaking the UnitTest object.
+
+ // CodeGear C++Builder insists on a public destructor for the
+ // default implementation. Use this implementation to keep good OO
+ // design with private destructor.
+
+#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+ static UnitTest* const instance = new UnitTest;
+ return instance;
+#else
+ static UnitTest instance;
+ return &instance;
+#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+}
+
+// Gets the number of successful test cases.
+int UnitTest::successful_test_case_count() const {
+ return impl()->successful_test_case_count();
+}
+
+// Gets the number of failed test cases.
+int UnitTest::failed_test_case_count() const {
+ return impl()->failed_test_case_count();
+}
+
+// Gets the number of all test cases.
+int UnitTest::total_test_case_count() const {
+ return impl()->total_test_case_count();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTest::test_case_to_run_count() const {
+ return impl()->test_case_to_run_count();
+}
+
+// Gets the number of successful tests.
+int UnitTest::successful_test_count() const {
+ return impl()->successful_test_count();
+}
+
+// Gets the number of failed tests.
+int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
+
+// Gets the number of disabled tests.
+int UnitTest::disabled_test_count() const {
+ return impl()->disabled_test_count();
+}
+
+// Gets the number of all tests.
+int UnitTest::total_test_count() const { return impl()->total_test_count(); }
+
+// Gets the number of tests that should run.
+int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
+
+// Gets the elapsed time, in milliseconds.
+internal::TimeInMillis UnitTest::elapsed_time() const {
+ return impl()->elapsed_time();
+}
+
+// Returns true iff the unit test passed (i.e. all test cases passed).
+bool UnitTest::Passed() const { return impl()->Passed(); }
+
+// Returns true iff the unit test failed (i.e. some test case failed
+// or something outside of all tests failed).
+bool UnitTest::Failed() const { return impl()->Failed(); }
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+const TestCase* UnitTest::GetTestCase(int i) const {
+ return impl()->GetTestCase(i);
+}
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+TestCase* UnitTest::GetMutableTestCase(int i) {
+ return impl()->GetMutableTestCase(i);
+}
+
+// Returns the list of event listeners that can be used to track events
+// inside Google Test.
+TestEventListeners& UnitTest::listeners() {
+ return *impl()->listeners();
+}
+
+// Registers and returns a global test environment. When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered. After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+ if (env == NULL) {
+ return NULL;
+ }
+
+ impl_->environments().push_back(env);
+ return env;
+}
+
+// Adds a TestPartResult to the current TestResult object. All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results. The user code should use the
+// assertion macros instead of calling this directly.
+// L < mutex_
+void UnitTest::AddTestPartResult(TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace) {
+ Message msg;
+ msg << message;
+
+ internal::MutexLock lock(&mutex_);
+ if (impl_->gtest_trace_stack().size() > 0) {
+ msg << "\n" << GTEST_NAME_ << " trace:";
+
+ for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
+ i > 0; --i) {
+ const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
+ msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
+ << " " << trace.message;
+ }
+ }
+
+ if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+ msg << internal::kStackTraceMarker << os_stack_trace;
+ }
+
+ const TestPartResult result =
+ TestPartResult(result_type, file_name, line_number,
+ msg.GetString().c_str());
+ impl_->GetTestPartResultReporterForCurrentThread()->
+ ReportTestPartResult(result);
+
+ if (result_type != TestPartResult::kSuccess) {
+ // gtest_break_on_failure takes precedence over
+ // gtest_throw_on_failure. This allows a user to set the latter
+ // in the code (perhaps in order to use Google Test assertions
+ // with another testing framework) and specify the former on the
+ // command line for debugging.
+ if (GTEST_FLAG(break_on_failure)) {
+#if GTEST_OS_WINDOWS
+ // Using DebugBreak on Windows allows gtest to still break into a debugger
+ // when a failure happens and both the --gtest_break_on_failure and
+ // the --gtest_catch_exceptions flags are specified.
+ DebugBreak();
+#else
+ // Dereference NULL through a volatile pointer to prevent the compiler
+ // from removing. We use this rather than abort() or __builtin_trap() for
+ // portability: Symbian doesn't implement abort() well, and some debuggers
+ // don't correctly trap abort().
+ *static_cast<volatile int*>(NULL) = 1;
+#endif // GTEST_OS_WINDOWS
+ } else if (GTEST_FLAG(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+ throw GoogleTestFailureException(result);
+#else
+ // We cannot call abort() as it generates a pop-up in debug mode
+ // that cannot be suppressed in VC 7.1 or below.
+ exit(1);
+#endif
+ }
+ }
+}
+
+// Creates and adds a property to the current TestResult. If a property matching
+// the supplied value already exists, updates its value instead.
+void UnitTest::RecordPropertyForCurrentTest(const char* key,
+ const char* value) {
+ const TestProperty test_property(key, value);
+ impl_->current_test_result()->RecordProperty(test_property);
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+ // Captures the value of GTEST_FLAG(catch_exceptions). This value will be
+ // used for the duration of the program.
+ impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
+
+#if GTEST_HAS_SEH
+ const bool in_death_test_child_process =
+ internal::GTEST_FLAG(internal_run_death_test).length() > 0;
+
+ // Either the user wants Google Test to catch exceptions thrown by the
+ // tests or this is executing in the context of death test child
+ // process. In either case the user does not want to see pop-up dialogs
+ // about crashes - they are expected.
+ if (impl()->catch_exceptions() || in_death_test_child_process) {
+
+# if !GTEST_OS_WINDOWS_MOBILE
+ // SetErrorMode doesn't exist on CE.
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+# endif // !GTEST_OS_WINDOWS_MOBILE
+
+# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
+ // Death test children can be terminated with _abort(). On Windows,
+ // _abort() can show a dialog with a warning message. This forces the
+ // abort message to go to stderr instead.
+ _set_error_mode(_OUT_TO_STDERR);
+# endif
+
+# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+ // In the debug version, Visual Studio pops up a separate dialog
+ // offering a choice to debug the aborted program. We need to suppress
+ // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
+ // executed. Google Test will notify the user of any unexpected
+ // failure via stderr.
+ //
+ // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
+ // Users of prior VC versions shall suffer the agony and pain of
+ // clicking through the countless debug dialogs.
+ // TODO(vladl@google.com): find a way to suppress the abort dialog() in the
+ // debug mode when compiled with VC 7.1 or lower.
+ if (!GTEST_FLAG(break_on_failure))
+ _set_abort_behavior(
+ 0x0, // Clear the following flags:
+ _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
+# endif
+
+ }
+#endif // GTEST_HAS_SEH
+
+ return internal::HandleExceptionsInMethodIfSupported(
+ impl(),
+ &internal::UnitTestImpl::RunAllTests,
+ "auxiliary test code (environments or event listeners)") ? 0 : 1;
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+ return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestCase* UnitTest::current_test_case() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestInfo* UnitTest::current_test_info() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_info();
+}
+
+// Returns the random seed used at the start of the current test run.
+int UnitTest::random_seed() const { return impl_->random_seed(); }
+
+#if GTEST_HAS_PARAM_TEST
+// Returns ParameterizedTestCaseRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+// L < mutex_
+internal::ParameterizedTestCaseRegistry&
+ UnitTest::parameterized_test_registry() {
+ return impl_->parameterized_test_registry();
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+ impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+ delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+// L < mutex_
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().push_back(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+// L < mutex_
+void UnitTest::PopGTestTrace() {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().pop_back();
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+ : parent_(parent),
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4355) // Temporarily disables warning 4355
+ // (using this in initializer).
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+# pragma warning(pop) // Restores the warning state again.
+#else
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+#endif // _MSC_VER
+ global_test_part_result_repoter_(
+ &default_global_test_part_result_reporter_),
+ per_thread_test_part_result_reporter_(
+ &default_per_thread_test_part_result_reporter_),
+#if GTEST_HAS_PARAM_TEST
+ parameterized_test_registry_(),
+ parameterized_tests_registered_(false),
+#endif // GTEST_HAS_PARAM_TEST
+ last_death_test_case_(-1),
+ current_test_case_(NULL),
+ current_test_info_(NULL),
+ ad_hoc_test_result_(),
+ os_stack_trace_getter_(NULL),
+ post_flag_parse_init_performed_(false),
+ random_seed_(0), // Will be overridden by the flag before first use.
+ random_(0), // Will be reseeded before first use.
+ elapsed_time_(0),
+#if GTEST_HAS_DEATH_TEST
+ internal_run_death_test_flag_(NULL),
+ death_test_factory_(new DefaultDeathTestFactory),
+#endif
+ // Will be overridden by the flag before first use.
+ catch_exceptions_(false) {
+ listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
+}
+
+UnitTestImpl::~UnitTestImpl() {
+ // Deletes every TestCase.
+ ForEach(test_cases_, internal::Delete<TestCase>);
+
+ // Deletes every Environment.
+ ForEach(environments_, internal::Delete<Environment>);
+
+ delete os_stack_trace_getter_;
+}
+
+#if GTEST_HAS_DEATH_TEST
+// Disables event forwarding if the control is currently in a death test
+// subprocess. Must not be called before InitGoogleTest.
+void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
+ if (internal_run_death_test_flag_.get() != NULL)
+ listeners()->SuppressEventForwarding();
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// Initializes event listeners performing XML output as specified by
+// UnitTestOptions. Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureXmlOutput() {
+ const String& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml") {
+ listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format != "") {
+ printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+ output_format.c_str());
+ fflush(stdout);
+ }
+}
+
+#if GTEST_CAN_STREAM_RESULTS_
+// Initializes event listeners for streaming test results in String form.
+// Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureStreamingOutput() {
+ const string& target = GTEST_FLAG(stream_result_to);
+ if (!target.empty()) {
+ const size_t pos = target.find(':');
+ if (pos != string::npos) {
+ listeners()->Append(new StreamingListener(target.substr(0, pos),
+ target.substr(pos+1)));
+ } else {
+ printf("WARNING: unrecognized streaming target \"%s\" ignored.\n",
+ target.c_str());
+ fflush(stdout);
+ }
+ }
+}
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+// Performs initialization dependent upon flag values obtained in
+// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+// this function is also called from RunAllTests. Since this function can be
+// called more than once, it has to be idempotent.
+void UnitTestImpl::PostFlagParsingInit() {
+ // Ensures that this function does not execute more than once.
+ if (!post_flag_parse_init_performed_) {
+ post_flag_parse_init_performed_ = true;
+
+#if GTEST_HAS_DEATH_TEST
+ InitDeathTestSubprocessControlInfo();
+ SuppressTestEventsIfInSubprocess();
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Registers parameterized tests. This makes parameterized tests
+ // available to the UnitTest reflection API without running
+ // RUN_ALL_TESTS.
+ RegisterParameterizedTests();
+
+ // Configures listeners for XML output. This makes it possible for users
+ // to shut down the default XML output before invoking RUN_ALL_TESTS.
+ ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+ // Configures listeners for streaming test results to the specified server.
+ ConfigureStreamingOutput();
+#endif // GTEST_CAN_STREAM_RESULTS_
+ }
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs {
+ public:
+ // Constructor.
+ explicit TestCaseNameIs(const String& name)
+ : name_(name) {}
+
+ // Returns true iff the name of test_case matches name_.
+ bool operator()(const TestCase* test_case) const {
+ return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+ }
+
+ private:
+ String name_;
+};
+
+// Finds and returns a TestCase with the given name. If one doesn't
+// exist, creates one and returns it. It's the CALLER'S
+// RESPONSIBILITY to ensure that this function is only called WHEN THE
+// TESTS ARE NOT SHUFFLED.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// type_param: the name of the test case's type parameter, or NULL if
+// this is not a typed or a type-parameterized test case.
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+ const char* type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc) {
+ // Can we find a TestCase with the given name?
+ const std::vector<TestCase*>::const_iterator test_case =
+ std::find_if(test_cases_.begin(), test_cases_.end(),
+ TestCaseNameIs(test_case_name));
+
+ if (test_case != test_cases_.end())
+ return *test_case;
+
+ // No. Let's create one.
+ TestCase* const new_test_case =
+ new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc);
+
+ // Is this a death test case?
+ if (internal::UnitTestOptions::MatchesFilter(String(test_case_name),
+ kDeathTestCaseFilter)) {
+ // Yes. Inserts the test case after the last death test case
+ // defined so far. This only works when the test cases haven't
+ // been shuffled. Otherwise we may end up running a death test
+ // after a non-death test.
+ ++last_death_test_case_;
+ test_cases_.insert(test_cases_.begin() + last_death_test_case_,
+ new_test_case);
+ } else {
+ // No. Appends to the end of the list.
+ test_cases_.push_back(new_test_case);
+ }
+
+ test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
+ return new_test_case;
+}
+
+// Helpers for setting up / tearing down the given environment. They
+// are for use in the ForEach() function.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns true if all tests are successful. If any exception is
+// thrown during a test, the test is considered to be failed, but the
+// rest of the tests will still be run.
+//
+// When parameterized tests are enabled, it expands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+bool UnitTestImpl::RunAllTests() {
+ // Makes sure InitGoogleTest() was called.
+ if (!GTestIsInitialized()) {
+ printf("%s",
+ "\nThis test program did NOT call ::testing::InitGoogleTest "
+ "before calling RUN_ALL_TESTS(). Please fix it.\n");
+ return false;
+ }
+
+ // Do not run any test if the --help flag was specified.
+ if (g_help_flag)
+ return true;
+
+ // Repeats the call to the post-flag parsing initialization in case the
+ // user didn't call InitGoogleTest.
+ PostFlagParsingInit();
+
+ // Even if sharding is not on, test runners may want to use the
+ // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
+ // protocol.
+ internal::WriteToShardStatusFileIfNeeded();
+
+ // True iff we are in a subprocess for running a thread-safe-style
+ // death test.
+ bool in_subprocess_for_death_test = false;
+
+#if GTEST_HAS_DEATH_TEST
+ in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif // GTEST_HAS_DEATH_TEST
+
+ const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
+ in_subprocess_for_death_test);
+
+ // Compares the full test names with the filter to decide which
+ // tests to run.
+ const bool has_tests_to_run = FilterTests(should_shard
+ ? HONOR_SHARDING_PROTOCOL
+ : IGNORE_SHARDING_PROTOCOL) > 0;
+
+ // Lists the tests and exits if the --gtest_list_tests flag was specified.
+ if (GTEST_FLAG(list_tests)) {
+ // This must be called *after* FilterTests() has been called.
+ ListTestsMatchingFilter();
+ return true;
+ }
+
+ random_seed_ = GTEST_FLAG(shuffle) ?
+ GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
+
+ // True iff at least one test has failed.
+ bool failed = false;
+
+ TestEventListener* repeater = listeners()->repeater();
+
+ repeater->OnTestProgramStart(*parent_);
+
+ // How many times to repeat the tests? We don't want to repeat them
+ // when we are inside the subprocess of a death test.
+ const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+ // Repeats forever if the repeat count is negative.
+ const bool forever = repeat < 0;
+ for (int i = 0; forever || i != repeat; i++) {
+ // We want to preserve failures generated by ad-hoc test
+ // assertions executed before RUN_ALL_TESTS().
+ ClearNonAdHocTestResult();
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ // Shuffles test cases and tests if requested.
+ if (has_tests_to_run && GTEST_FLAG(shuffle)) {
+ random()->Reseed(random_seed_);
+ // This should be done before calling OnTestIterationStart(),
+ // such that a test event listener can see the actual test order
+ // in the event.
+ ShuffleTests();
+ }
+
+ // Tells the unit test event listeners that the tests are about to start.
+ repeater->OnTestIterationStart(*parent_, i);
+
+ // Runs each test case if there is at least one test to run.
+ if (has_tests_to_run) {
+ // Sets up all environments beforehand.
+ repeater->OnEnvironmentsSetUpStart(*parent_);
+ ForEach(environments_, SetUpEnvironment);
+ repeater->OnEnvironmentsSetUpEnd(*parent_);
+
+ // Runs the tests only if there was no fatal failure during global
+ // set-up.
+ if (!Test::HasFatalFailure()) {
+ for (int test_index = 0; test_index < total_test_case_count();
+ test_index++) {
+ GetMutableTestCase(test_index)->Run();
+ }
+ }
+
+ // Tears down all environments in reverse order afterwards.
+ repeater->OnEnvironmentsTearDownStart(*parent_);
+ std::for_each(environments_.rbegin(), environments_.rend(),
+ TearDownEnvironment);
+ repeater->OnEnvironmentsTearDownEnd(*parent_);
+ }
+
+ elapsed_time_ = GetTimeInMillis() - start;
+
+ // Tells the unit test event listener that the tests have just finished.
+ repeater->OnTestIterationEnd(*parent_, i);
+
+ // Gets the result and clears it.
+ if (!Passed()) {
+ failed = true;
+ }
+
+ // Restores the original test order after the iteration. This
+ // allows the user to quickly repro a failure that happens in the
+ // N-th iteration without repeating the first (N - 1) iterations.
+ // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
+ // case the user somehow changes the value of the flag somewhere
+ // (it's always safe to unshuffle the tests).
+ UnshuffleTests();
+
+ if (GTEST_FLAG(shuffle)) {
+ // Picks a new random seed for each iteration.
+ random_seed_ = GetNextRandomSeed(random_seed_);
+ }
+ }
+
+ repeater->OnTestProgramEnd(*parent_);
+
+ return !failed;
+}
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded() {
+ const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
+ if (test_shard_file != NULL) {
+ FILE* const file = posix::FOpen(test_shard_file, "w");
+ if (file == NULL) {
+ ColoredPrintf(COLOR_RED,
+ "Could not write to the test shard status file \"%s\" "
+ "specified by the %s environment variable.\n",
+ test_shard_file, kTestShardStatusFile);
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+ fclose(file);
+ }
+}
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (i.e., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_env,
+ const char* shard_index_env,
+ bool in_subprocess_for_death_test) {
+ if (in_subprocess_for_death_test) {
+ return false;
+ }
+
+ const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+ const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+
+ if (total_shards == -1 && shard_index == -1) {
+ return false;
+ } else if (total_shards == -1 && shard_index != -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestShardIndex << " = " << shard_index
+ << ", but have left " << kTestTotalShards << " unset.\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (total_shards != -1 && shard_index == -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestTotalShards << " = " << total_shards
+ << ", but have left " << kTestShardIndex << " unset.\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (shard_index < 0 || shard_index >= total_shards) {
+ const Message msg = Message()
+ << "Invalid environment variables: we require 0 <= "
+ << kTestShardIndex << " < " << kTestTotalShards
+ << ", but you have " << kTestShardIndex << "=" << shard_index
+ << ", " << kTestTotalShards << "=" << total_shards << ".\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+
+ return total_shards > 1;
+}
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error
+// and aborts.
+Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) {
+ const char* str_val = posix::GetEnv(var);
+ if (str_val == NULL) {
+ return default_val;
+ }
+
+ Int32 result;
+ if (!ParseInt32(Message() << "The value of environment variable " << var,
+ str_val, &result)) {
+ exit(EXIT_FAILURE);
+ }
+ return result;
+}
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
+ return (test_id % total_shards) == shard_index;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
+ const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
+ const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
+
+ // num_runnable_tests are the number of tests that will
+ // run across all shards (i.e., match filter and are not disabled).
+ // num_selected_tests are the number of tests to be run on
+ // this shard.
+ int num_runnable_tests = 0;
+ int num_selected_tests = 0;
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ TestCase* const test_case = test_cases_[i];
+ const String &test_case_name = test_case->name();
+ test_case->set_should_run(false);
+
+ for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+ TestInfo* const test_info = test_case->test_info_list()[j];
+ const String test_name(test_info->name());
+ // A test is disabled if test case name or test name matches
+ // kDisableTestFilter.
+ const bool is_disabled =
+ internal::UnitTestOptions::MatchesFilter(test_case_name,
+ kDisableTestFilter) ||
+ internal::UnitTestOptions::MatchesFilter(test_name,
+ kDisableTestFilter);
+ test_info->is_disabled_ = is_disabled;
+
+ const bool matches_filter =
+ internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+ test_name);
+ test_info->matches_filter_ = matches_filter;
+
+ const bool is_runnable =
+ (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
+ matches_filter;
+
+ const bool is_selected = is_runnable &&
+ (shard_tests == IGNORE_SHARDING_PROTOCOL ||
+ ShouldRunTestOnShard(total_shards, shard_index,
+ num_runnable_tests));
+
+ num_runnable_tests += is_runnable;
+ num_selected_tests += is_selected;
+
+ test_info->should_run_ = is_selected;
+ test_case->set_should_run(test_case->should_run() || is_selected);
+ }
+ }
+ return num_selected_tests;
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter() {
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ const TestCase* const test_case = test_cases_[i];
+ bool printed_test_case_name = false;
+
+ for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+ const TestInfo* const test_info =
+ test_case->test_info_list()[j];
+ if (test_info->matches_filter_) {
+ if (!printed_test_case_name) {
+ printed_test_case_name = true;
+ printf("%s.\n", test_case->name());
+ }
+ printf(" %s\n", test_info->name());
+ }
+ }
+ }
+ fflush(stdout);
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+ OsStackTraceGetterInterface* getter) {
+ if (os_stack_trace_getter_ != getter) {
+ delete os_stack_trace_getter_;
+ os_stack_trace_getter_ = getter;
+ }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+ if (os_stack_trace_getter_ == NULL) {
+ os_stack_trace_getter_ = new OsStackTraceGetter;
+ }
+
+ return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+TestResult* UnitTestImpl::current_test_result() {
+ return current_test_info_ ?
+ &(current_test_info_->result_) : &ad_hoc_test_result_;
+}
+
+// Shuffles all test cases, and the tests within each test case,
+// making sure that death tests are still run first.
+void UnitTestImpl::ShuffleTests() {
+ // Shuffles the death test cases.
+ ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);
+
+ // Shuffles the non-death test cases.
+ ShuffleRange(random(), last_death_test_case_ + 1,
+ static_cast<int>(test_cases_.size()), &test_case_indices_);
+
+ // Shuffles the tests inside each test case.
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ test_cases_[i]->ShuffleTests(random());
+ }
+}
+
+// Restores the test cases and tests to their order before the first shuffle.
+void UnitTestImpl::UnshuffleTests() {
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ // Unshuffles the tests in each test case.
+ test_cases_[i]->UnshuffleTests();
+ // Resets the index of each test case.
+ test_case_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
+ int skip_count) {
+ // We pass skip_count + 1 to skip this wrapper function in addition
+ // to what the user really wants to skip.
+ return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to
+// suppress unreachable code warnings.
+namespace {
+class ClassUniqueToAlwaysTrue {};
+}
+
+bool IsTrue(bool condition) { return condition; }
+
+bool AlwaysTrue() {
+#if GTEST_HAS_EXCEPTIONS
+ // This condition is always false so AlwaysTrue() never actually throws,
+ // but it makes the compiler think that it may throw.
+ if (IsTrue(false))
+ throw ClassUniqueToAlwaysTrue();
+#endif // GTEST_HAS_EXCEPTIONS
+ return true;
+}
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+bool SkipPrefix(const char* prefix, const char** pstr) {
+ const size_t prefix_len = strlen(prefix);
+ if (strncmp(*pstr, prefix, prefix_len) == 0) {
+ *pstr += prefix_len;
+ return true;
+ }
+ return false;
+}
+
+// Parses a string as a command line flag. The string should have
+// the format "--flag=value". When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+ const char* flag,
+ bool def_optional) {
+ // str and flag must not be NULL.
+ if (str == NULL || flag == NULL) return NULL;
+
+ // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+ const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag);
+ const size_t flag_len = flag_str.length();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+ // Skips the flag name.
+ const char* flag_end = str + flag_len;
+
+ // When def_optional is true, it's OK to not have a "=value" part.
+ if (def_optional && (flag_end[0] == '\0')) {
+ return flag_end;
+ }
+
+ // If def_optional is true and there are more characters after the
+ // flag name, or if def_optional is false, there must be a '=' after
+ // the flag name.
+ if (flag_end[0] != '=') return NULL;
+
+ // Returns the string after "=".
+ return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Converts the string value to a bool.
+ *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+ return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag,
+ value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, String* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ *value = value_str;
+ return true;
+}
+
+// Determines whether a string has a prefix that Google Test uses for its
+// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
+// If Google Test detects that a command line flag has its prefix but is not
+// recognized, it will print its help message. Flags starting with
+// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
+// internal flags and do not trigger the help message.
+static bool HasGoogleTestFlagPrefix(const char* str) {
+ return (SkipPrefix("--", &str) ||
+ SkipPrefix("-", &str) ||
+ SkipPrefix("/", &str)) &&
+ !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
+ (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
+ SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
+}
+
+// Prints a string containing code-encoded text. The following escape
+// sequences can be used in the string to control the text color:
+//
+// @@ prints a single '@' character.
+// @R changes the color to red.
+// @G changes the color to green.
+// @Y changes the color to yellow.
+// @D changes to the default terminal text color.
+//
+// TODO(wan@google.com): Write tests for this once we add stdout
+// capturing to Google Test.
+static void PrintColorEncoded(const char* str) {
+ GTestColor color = COLOR_DEFAULT; // The current color.
+
+ // Conceptually, we split the string into segments divided by escape
+ // sequences. Then we print one segment at a time. At the end of
+ // each iteration, the str pointer advances to the beginning of the
+ // next segment.
+ for (;;) {
+ const char* p = strchr(str, '@');
+ if (p == NULL) {
+ ColoredPrintf(color, "%s", str);
+ return;
+ }
+
+ ColoredPrintf(color, "%s", String(str, p - str).c_str());
+
+ const char ch = p[1];
+ str = p + 2;
+ if (ch == '@') {
+ ColoredPrintf(color, "@");
+ } else if (ch == 'D') {
+ color = COLOR_DEFAULT;
+ } else if (ch == 'R') {
+ color = COLOR_RED;
+ } else if (ch == 'G') {
+ color = COLOR_GREEN;
+ } else if (ch == 'Y') {
+ color = COLOR_YELLOW;
+ } else {
+ --str;
+ }
+ }
+}
+
+static const char kColorEncodedHelpMessage[] =
+"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
+"following command line flags to control its behavior:\n"
+"\n"
+"Test Selection:\n"
+" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"
+" List the names of all tests instead of running them. The name of\n"
+" TEST(Foo, Bar) is \"Foo.Bar\".\n"
+" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
+ "[@G-@YNEGATIVE_PATTERNS]@D\n"
+" Run only the tests whose name matches one of the positive patterns but\n"
+" none of the negative patterns. '?' matches any single character; '*'\n"
+" matches any substring; ':' separates two patterns.\n"
+" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"
+" Run all disabled tests too.\n"
+"\n"
+"Test Execution:\n"
+" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
+" Run the tests repeatedly; use a negative count to repeat forever.\n"
+" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n"
+" Randomize tests' orders on every iteration.\n"
+" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
+" Random number seed to use for shuffling test orders (between 1 and\n"
+" 99999, or 0 to use a seed based on the current time).\n"
+"\n"
+"Test Output:\n"
+" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
+" Enable/disable colored output. The default is @Gauto@D.\n"
+" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
+" Don't print the elapsed time of each test.\n"
+" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"
+ GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
+" Generate an XML report in the given directory or with the given file\n"
+" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"
+#if GTEST_CAN_STREAM_RESULTS_
+" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n"
+" Stream test results to the given server.\n"
+#endif // GTEST_CAN_STREAM_RESULTS_
+"\n"
+"Assertion Behavior:\n"
+#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
+" Set the default death test style.\n"
+#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
+" Turn assertion failures into debugger break-points.\n"
+" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
+" Turn assertion failures into C++ exceptions.\n"
+" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n"
+" Do not report exceptions as test failures. Instead, allow them\n"
+" to crash the program or throw a pop-up (on Windows).\n"
+"\n"
+"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "
+ "the corresponding\n"
+"environment variable of a flag (all letters in upper-case). For example, to\n"
+"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
+ "color=no@D or set\n"
+"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"
+"\n"
+"For more information, please read the " GTEST_NAME_ " documentation at\n"
+"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
+"(not one in your own code or tests), please report it to\n"
+"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test. The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+ for (int i = 1; i < *argc; i++) {
+ const String arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ using internal::ParseBoolFlag;
+ using internal::ParseInt32Flag;
+ using internal::ParseStringFlag;
+
+ // Do we see a Google Test flag?
+ if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+ >EST_FLAG(also_run_disabled_tests)) ||
+ ParseBoolFlag(arg, kBreakOnFailureFlag,
+ >EST_FLAG(break_on_failure)) ||
+ ParseBoolFlag(arg, kCatchExceptionsFlag,
+ >EST_FLAG(catch_exceptions)) ||
+ ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) ||
+ ParseStringFlag(arg, kDeathTestStyleFlag,
+ >EST_FLAG(death_test_style)) ||
+ ParseBoolFlag(arg, kDeathTestUseFork,
+ >EST_FLAG(death_test_use_fork)) ||
+ ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) ||
+ ParseStringFlag(arg, kInternalRunDeathTestFlag,
+ >EST_FLAG(internal_run_death_test)) ||
+ ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) ||
+ ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) ||
+ ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) ||
+ ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) ||
+ ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) ||
+ ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) ||
+ ParseInt32Flag(arg, kStackTraceDepthFlag,
+ >EST_FLAG(stack_trace_depth)) ||
+ ParseStringFlag(arg, kStreamResultToFlag,
+ >EST_FLAG(stream_result_to)) ||
+ ParseBoolFlag(arg, kThrowOnFailureFlag,
+ >EST_FLAG(throw_on_failure))
+ ) {
+ // Yes. Shift the remainder of the argv list left by one. Note
+ // that argv has (*argc + 1) elements, the last one always being
+ // NULL. The following loop moves the trailing NULL element as
+ // well.
+ for (int j = i; j != *argc; j++) {
+ argv[j] = argv[j + 1];
+ }
+
+ // Decrements the argument count.
+ (*argc)--;
+
+ // We also need to decrement the iterator as we just removed
+ // an element.
+ i--;
+ } else if (arg_string == "--help" || arg_string == "-h" ||
+ arg_string == "-?" || arg_string == "/?" ||
+ HasGoogleTestFlagPrefix(arg)) {
+ // Both help flag and unrecognized Google Test flags (excluding
+ // internal ones) trigger help display.
+ g_help_flag = true;
+ }
+ }
+
+ if (g_help_flag) {
+ // We print the help here instead of in RUN_ALL_TESTS(), as the
+ // latter may not be called at all if the user is using Google
+ // Test with another testing framework.
+ PrintColorEncoded(kColorEncodedHelpMessage);
+ }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+ g_init_gtest_count++;
+
+ // We don't want to run the initialization code twice.
+ if (g_init_gtest_count != 1) return;
+
+ if (*argc <= 0) return;
+
+ internal::g_executable_path = internal::StreamableToString(argv[0]);
+
+#if GTEST_HAS_DEATH_TEST
+
+ g_argvs.clear();
+ for (int i = 0; i != *argc; i++) {
+ g_argvs.push_back(StreamableToString(argv[i]));
+ }
+
+#endif // GTEST_HAS_DEATH_TEST
+
+ ParseGoogleTestFlagsOnly(argc, argv);
+ GetUnitTestImpl()->PostFlagParsingInit();
+}
+
+} // namespace internal
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv) {
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+} // namespace testing
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
+//
+// This file implements death tests.
+
+
+#if GTEST_HAS_DEATH_TEST
+
+# if GTEST_OS_MAC
+# include <crt_externs.h>
+# endif // GTEST_OS_MAC
+
+# include <errno.h>
+# include <fcntl.h>
+# include <limits.h>
+# include <stdarg.h>
+
+# if GTEST_OS_WINDOWS
+# include <windows.h>
+# else
+# include <sys/mman.h>
+# include <sys/wait.h>
+# endif // GTEST_OS_WINDOWS
+
+#endif // GTEST_HAS_DEATH_TEST
+
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string_(
+ death_test_style,
+ internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+ "Indicates how to run a death test in a forked child process: "
+ "\"threadsafe\" (child process re-executes the test binary "
+ "from the beginning, running only the specific death test) or "
+ "\"fast\" (child process runs the death test immediately "
+ "after forking).");
+
+GTEST_DEFINE_bool_(
+ death_test_use_fork,
+ internal::BoolFromGTestEnv("death_test_use_fork", false),
+ "Instructs to use fork()/_exit() instead of clone() in death tests. "
+ "Ignored and always uses fork() on POSIX systems where clone() is not "
+ "implemented. Useful when running under valgrind or similar tools if "
+ "those do not support clone(). Valgrind 3.3.1 will just fail if "
+ "it sees an unsupported combination of clone() flags. "
+ "It is not recommended to use this flag w/o valgrind though it will "
+ "work in 99% of the cases. Once valgrind is fixed, this flag will "
+ "most likely be removed.");
+
+namespace internal {
+GTEST_DEFINE_string_(
+ internal_run_death_test, "",
+ "Indicates the file, line number, temporal index of "
+ "the single death test to run, and a file descriptor to "
+ "which a success code may be sent, all separated by "
+ "colons. This flag is specified if and only if the current "
+ "process is a sub-process launched for running a thread-safe "
+ "death test. FOR INTERNAL USE ONLY.");
+} // namespace internal
+
+#if GTEST_HAS_DEATH_TEST
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+# if GTEST_OS_WINDOWS
+
+ return exit_status == exit_code_;
+
+# else
+
+ return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+
+# endif // GTEST_OS_WINDOWS
+}
+
+# if !GTEST_OS_WINDOWS
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+ return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+# endif // !GTEST_OS_WINDOWS
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static String ExitSummary(int exit_code) {
+ Message m;
+
+# if GTEST_OS_WINDOWS
+
+ m << "Exited with exit status " << exit_code;
+
+# else
+
+ if (WIFEXITED(exit_code)) {
+ m << "Exited with exit status " << WEXITSTATUS(exit_code);
+ } else if (WIFSIGNALED(exit_code)) {
+ m << "Terminated by signal " << WTERMSIG(exit_code);
+ }
+# ifdef WCOREDUMP
+ if (WCOREDUMP(exit_code)) {
+ m << " (core dumped)";
+ }
+# endif
+# endif // GTEST_OS_WINDOWS
+
+ return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+ return !ExitedWithCode(0)(exit_status);
+}
+
+# if !GTEST_OS_WINDOWS
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement. It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static String DeathTestThreadWarning(size_t thread_count) {
+ Message msg;
+ msg << "Death tests use fork(), which is unsafe particularly"
+ << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
+ if (thread_count == 0)
+ msg << "couldn't detect the number of threads.";
+ else
+ msg << "detected " << thread_count << " threads.";
+ return msg.GetString();
+}
+# endif // !GTEST_OS_WINDOWS
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestThrew = 'T';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test can
+// conclude. DIED means that the process died while executing the test
+// code; LIVED means that process lived beyond the end of the test code;
+// RETURNED means that the test statement attempted to execute a return
+// statement, which is not allowed; THREW means that the test statement
+// returned control by throwing an exception. IN_PROGRESS means the test
+// has not yet concluded.
+// TODO(vladl@google.com): Unify names and possibly values for
+// AbortReason, DeathTestOutcome, and flag characters above.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the error
+// message is propagated back to the parent process. Otherwise, the
+// message is simply printed to stderr. In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const String& message) {
+ // On a POSIX system, this function may be called from a threadsafe-style
+ // death test child process, which operates on a very small stack. Use
+ // the heap for any additional non-minuscule memory requirements.
+ const InternalRunDeathTestFlag* const flag =
+ GetUnitTestImpl()->internal_run_death_test_flag();
+ if (flag != NULL) {
+ FILE* parent = posix::FDOpen(flag->write_fd(), "w");
+ fputc(kDeathTestInternalError, parent);
+ fprintf(parent, "%s", message.c_str());
+ fflush(parent);
+ _exit(1);
+ } else {
+ fprintf(stderr, "%s", message.c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+# define GTEST_DEATH_TEST_CHECK_(expression) \
+ do { \
+ if (!::testing::internal::IsTrue(expression)) { \
+ DeathTestAbort(::testing::internal::String::Format( \
+ "CHECK failed: File %s, line %d: %s", \
+ __FILE__, __LINE__, #expression)); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again. The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR. If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+ do { \
+ int gtest_retval; \
+ do { \
+ gtest_retval = (expression); \
+ } while (gtest_retval == -1 && errno == EINTR); \
+ if (gtest_retval == -1) { \
+ DeathTestAbort(::testing::internal::String::Format( \
+ "CHECK failed: File %s, line %d: %s != -1", \
+ __FILE__, __LINE__, #expression)); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+String GetLastErrnoDescription() {
+ return String(errno == 0 ? "" : posix::StrError(errno));
+}
+
+// This is called from a death test parent process to read a failure
+// message from the death test child process and log it with the FATAL
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd) {
+ Message error;
+ char buffer[256];
+ int num_read;
+
+ do {
+ while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+ buffer[num_read] = '\0';
+ error << buffer;
+ }
+ } while (num_read == -1 && errno == EINTR);
+
+ if (num_read == 0) {
+ GTEST_LOG_(FATAL) << error.GetString();
+ } else {
+ const int last_error = errno;
+ GTEST_LOG_(FATAL) << "Error while reading death test internal: "
+ << GetLastErrnoDescription() << " [" << last_error << "]";
+ }
+}
+
+// Death test constructor. Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+ TestInfo* const info = GetUnitTestImpl()->current_test_info();
+ if (info == NULL) {
+ DeathTestAbort("Cannot run a death test outside of a TEST or "
+ "TEST_F construct");
+ }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) {
+ return GetUnitTestImpl()->death_test_factory()->Create(
+ statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+ return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const String& message) {
+ last_death_test_message_ = message;
+}
+
+String DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
+ protected:
+ DeathTestImpl(const char* a_statement, const RE* a_regex)
+ : statement_(a_statement),
+ regex_(a_regex),
+ spawned_(false),
+ status_(-1),
+ outcome_(IN_PROGRESS),
+ read_fd_(-1),
+ write_fd_(-1) {}
+
+ // read_fd_ is expected to be closed and cleared by a derived class.
+ ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+ void Abort(AbortReason reason);
+ virtual bool Passed(bool status_ok);
+
+ const char* statement() const { return statement_; }
+ const RE* regex() const { return regex_; }
+ bool spawned() const { return spawned_; }
+ void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
+ int status() const { return status_; }
+ void set_status(int a_status) { status_ = a_status; }
+ DeathTestOutcome outcome() const { return outcome_; }
+ void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
+ int read_fd() const { return read_fd_; }
+ void set_read_fd(int fd) { read_fd_ = fd; }
+ int write_fd() const { return write_fd_; }
+ void set_write_fd(int fd) { write_fd_ = fd; }
+
+ // Called in the parent process only. Reads the result code of the death
+ // test child process via a pipe, interprets it to set the outcome_
+ // member, and closes read_fd_. Outputs diagnostics and terminates in
+ // case of unexpected codes.
+ void ReadAndInterpretStatusByte();
+
+ private:
+ // The textual content of the code this object is testing. This class
+ // doesn't own this string and should not attempt to delete it.
+ const char* const statement_;
+ // The regular expression which test output must match. DeathTestImpl
+ // doesn't own this object and should not attempt to delete it.
+ const RE* const regex_;
+ // True if the death test child process has been successfully spawned.
+ bool spawned_;
+ // The exit status of the child process.
+ int status_;
+ // How the death test concluded.
+ DeathTestOutcome outcome_;
+ // Descriptor to the read end of the pipe to the child process. It is
+ // always -1 in the child process. The child keeps its write end of the
+ // pipe in write_fd_.
+ int read_fd_;
+ // Descriptor to the child's write end of the pipe to the parent process.
+ // It is always -1 in the parent process. The parent keeps its end of the
+ // pipe in read_fd_.
+ int write_fd_;
+};
+
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_. Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte() {
+ char flag;
+ int bytes_read;
+
+ // The read() here blocks until data is available (signifying the
+ // failure of the death test) or until the pipe is closed (signifying
+ // its success), so it's okay to call this in the parent before
+ // the child process has exited.
+ do {
+ bytes_read = posix::Read(read_fd(), &flag, 1);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0) {
+ set_outcome(DIED);
+ } else if (bytes_read == 1) {
+ switch (flag) {
+ case kDeathTestReturned:
+ set_outcome(RETURNED);
+ break;
+ case kDeathTestThrew:
+ set_outcome(THREW);
+ break;
+ case kDeathTestLived:
+ set_outcome(LIVED);
+ break;
+ case kDeathTestInternalError:
+ FailFromInternalError(read_fd()); // Does not return.
+ break;
+ default:
+ GTEST_LOG_(FATAL) << "Death test child process reported "
+ << "unexpected status byte ("
+ << static_cast<unsigned int>(flag) << ")";
+ }
+ } else {
+ GTEST_LOG_(FATAL) << "Read from death test child process failed: "
+ << GetLastErrnoDescription();
+ }
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+ set_read_fd(-1);
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file descriptor, then
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason) {
+ // The parent process considers the death test to be a failure if
+ // it finds any data in our pipe. So, here we write a single flag byte
+ // to the pipe, then exit.
+ const char status_ch =
+ reason == TEST_DID_NOT_DIE ? kDeathTestLived :
+ reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned;
+
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+ // We are leaking the descriptor here because on some platforms (i.e.,
+ // when built as Windows DLL), destructors of global objects will still
+ // run after calling _exit(). On such systems, write_fd_ will be
+ // indirectly closed from the destructor of UnitTestImpl, causing double
+ // close if it is also closed here. On debug configurations, double close
+ // may assert. As there are no in-process buffers to flush here, we are
+ // relying on the OS to close the descriptor after the process terminates
+ // when the destructors are not run.
+ _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// Returns an indented copy of stderr output for a death test.
+// This makes distinguishing death test output lines from regular log lines
+// much easier.
+static ::std::string FormatDeathTestOutput(const ::std::string& output) {
+ ::std::string ret;
+ for (size_t at = 0; ; ) {
+ const size_t line_end = output.find('\n', at);
+ ret += "[ DEATH ] ";
+ if (line_end == ::std::string::npos) {
+ ret += output.substr(at);
+ break;
+ }
+ ret += output.substr(at, line_end + 1 - at);
+ at = line_end + 1;
+ }
+ return ret;
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+// outcome: An enumeration describing how the death test
+// concluded: DIED, LIVED, THREW, or RETURNED. The death test
+// fails in the latter three cases.
+// status: The exit status of the child process. On *nix, it is in the
+// in the format specified by wait(2). On Windows, this is the
+// value supplied to the ExitProcess() API or a numeric code
+// of the exception that terminated the program.
+// regex: A regular expression object to be applied to
+// the test's captured standard error output; the death test
+// fails if it does not match.
+//
+// Argument:
+// status_ok: true if exit_status is acceptable in the context of
+// this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met. Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok) {
+ if (!spawned())
+ return false;
+
+ const String error_message = GetCapturedStderr();
+
+ bool success = false;
+ Message buffer;
+
+ buffer << "Death test: " << statement() << "\n";
+ switch (outcome()) {
+ case LIVED:
+ buffer << " Result: failed to die.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case THREW:
+ buffer << " Result: threw an exception.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case RETURNED:
+ buffer << " Result: illegal return in test statement.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case DIED:
+ if (status_ok) {
+ const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
+ if (matched) {
+ success = true;
+ } else {
+ buffer << " Result: died but not with expected error.\n"
+ << " Expected: " << regex()->pattern() << "\n"
+ << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+ }
+ } else {
+ buffer << " Result: died but not with expected exit code:\n"
+ << " " << ExitSummary(status()) << "\n"
+ << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+ }
+ break;
+ case IN_PROGRESS:
+ default:
+ GTEST_LOG_(FATAL)
+ << "DeathTest::Passed somehow called before conclusion of test";
+ }
+
+ DeathTest::set_last_death_test_message(buffer.GetString());
+ return success;
+}
+
+# if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes: Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+// ends of it.
+// 2. The parent starts the child and provides it with the information
+// necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+// using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+// this is done before step 3, the object's reference count goes down to
+// 0 and it is destroyed, preventing the child from acquiring it. The
+// parent now has to release it, or read operations on the read end of
+// the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+// any possible error messages) from the pipe, and its stderr and then
+// determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl {
+ public:
+ WindowsDeathTest(const char* a_statement,
+ const RE* a_regex,
+ const char* file,
+ int line)
+ : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual TestRole AssumeRole();
+
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+ // Handle to the write end of the pipe to the child process.
+ AutoHandle write_handle_;
+ // Child process handle.
+ AutoHandle child_handle_;
+ // Event the child process uses to signal the parent that it has
+ // acquired the handle to the write end of the pipe. After seeing this
+ // event the parent can release its own handles to make sure its
+ // ReadFile() calls return when the child terminates.
+ AutoHandle event_handle_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int WindowsDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ // Wait until the child either signals that it has acquired the write end
+ // of the pipe or it dies.
+ const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+ switch (::WaitForMultipleObjects(2,
+ wait_handles,
+ FALSE, // Waits for any of the handles.
+ INFINITE)) {
+ case WAIT_OBJECT_0:
+ case WAIT_OBJECT_0 + 1:
+ break;
+ default:
+ GTEST_DEATH_TEST_CHECK_(false); // Should not get here.
+ }
+
+ // The child has acquired the write end of the pipe or exited.
+ // We release the handle on our side and continue.
+ write_handle_.Reset();
+ event_handle_.Reset();
+
+ ReadAndInterpretStatusByte();
+
+ // Waits for the child process to exit if it haven't already. This
+ // returns immediately if the child has already exited, regardless of
+ // whether previous calls to WaitForMultipleObjects synchronized on this
+ // handle or not.
+ GTEST_DEATH_TEST_CHECK_(
+ WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+ INFINITE));
+ DWORD status_code;
+ GTEST_DEATH_TEST_CHECK_(
+ ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE);
+ child_handle_.Reset();
+ set_status(static_cast<int>(status_code));
+ return status();
+}
+
+// The AssumeRole process for a Windows death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole WindowsDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ // WindowsDeathTest uses an anonymous pipe to communicate results of
+ // a death test.
+ SECURITY_ATTRIBUTES handles_are_inheritable = {
+ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ HANDLE read_handle, write_handle;
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
+ 0) // Default buffer size.
+ != FALSE);
+ set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+ O_RDONLY));
+ write_handle_.Reset(write_handle);
+ event_handle_.Reset(::CreateEvent(
+ &handles_are_inheritable,
+ TRUE, // The event will automatically reset to non-signaled state.
+ FALSE, // The initial state is non-signalled.
+ NULL)); // The even is unnamed.
+ GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
+ const String filter_flag = String::Format("--%s%s=%s.%s",
+ GTEST_FLAG_PREFIX_, kFilterFlag,
+ info->test_case_name(),
+ info->name());
+ const String internal_flag = String::Format(
+ "--%s%s=%s|%d|%d|%u|%Iu|%Iu",
+ GTEST_FLAG_PREFIX_,
+ kInternalRunDeathTestFlag,
+ file_, line_,
+ death_test_index,
+ static_cast<unsigned int>(::GetCurrentProcessId()),
+ // size_t has the same with as pointers on both 32-bit and 64-bit
+ // Windows platforms.
+ // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+ reinterpret_cast<size_t>(write_handle),
+ reinterpret_cast<size_t>(event_handle_.Get()));
+
+ char executable_path[_MAX_PATH + 1]; // NOLINT
+ GTEST_DEATH_TEST_CHECK_(
+ _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
+ executable_path,
+ _MAX_PATH));
+
+ String command_line = String::Format("%s %s \"%s\"",
+ ::GetCommandLineA(),
+ filter_flag.c_str(),
+ internal_flag.c_str());
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // The child process will share the standard handles with the parent.
+ STARTUPINFOA startup_info;
+ memset(&startup_info, 0, sizeof(STARTUPINFO));
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+ startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+ PROCESS_INFORMATION process_info;
+ GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
+ executable_path,
+ const_cast<char*>(command_line.c_str()),
+ NULL, // Retuned process handle is not inheritable.
+ NULL, // Retuned thread handle is not inheritable.
+ TRUE, // Child inherits all inheritable handles (for write_handle_).
+ 0x0, // Default creation flags.
+ NULL, // Inherit the parent's environment.
+ UnitTest::GetInstance()->original_working_dir(),
+ &startup_info,
+ &process_info) != FALSE);
+ child_handle_.Reset(process_info.hProcess);
+ ::CloseHandle(process_info.hThread);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+# else // We are not on Windows.
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface. Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTestImpl {
+ public:
+ ForkingDeathTest(const char* statement, const RE* regex);
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+
+ protected:
+ void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+ // PID of child process during death test; 0 in the child process itself.
+ pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
+ : DeathTestImpl(a_statement, a_regex),
+ child_pid_(-1) {}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ ReadAndInterpretStatusByte();
+
+ int status_value;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
+ set_status(status_value);
+ return status_value;
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+ NoExecDeathTest(const char* a_statement, const RE* a_regex) :
+ ForkingDeathTest(a_statement, a_regex) { }
+ virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test. It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+ const size_t thread_count = GetThreadCount();
+ if (thread_count != 1) {
+ GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+ DeathTest::set_last_death_test_message("");
+ CaptureStderr();
+ // When we fork the process below, the log file buffers are copied, but the
+ // file descriptors are shared. We flush all log files here so that closing
+ // the file descriptors in the child process doesn't throw off the
+ // synchronization between descriptors and buffers in the parent process.
+ // This is as close to the fork as possible to avoid a race condition in case
+ // there are multiple threads running before the death test, and another
+ // thread writes to the log file.
+ FlushInfoLog();
+
+ const pid_t child_pid = fork();
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ set_child_pid(child_pid);
+ if (child_pid == 0) {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+ set_write_fd(pipe_fd[1]);
+ // Redirects all logging to stderr in the child process to prevent
+ // concurrent writes to the log files. We capture stderr in the parent
+ // process and append the child process' output to a log.
+ LogToStderr();
+ // Event forwarding to the listeners of event listener API mush be shut
+ // down in death test subprocesses.
+ GetUnitTestImpl()->listeners()->SuppressEventForwarding();
+ return EXECUTE_TEST;
+ } else {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+ }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+ ExecDeathTest(const char* a_statement, const RE* a_regex,
+ const char* file, int line) :
+ ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
+ virtual TestRole AssumeRole();
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() {
+ args_.push_back(NULL);
+ }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+ private:
+ std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+ char* const* argv; // Command-line arguments for the child's call to exec
+ int close_fd; // File descriptor to close; the read end of a pipe
+};
+
+# if GTEST_OS_MAC
+inline char** GetEnviron() {
+ // When Google Test is built as a framework on MacOS X, the environ variable
+ // is unavailable. Apple's documentation (man environ) recommends using
+ // _NSGetEnviron() instead.
+ return *_NSGetEnviron();
+}
+# else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+# endif // GTEST_OS_MAC
+
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg) {
+ ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ UnitTest::GetInstance()->original_working_dir();
+ // We can safely call chdir() as it's a direct system call.
+ if (chdir(original_dir) != 0) {
+ DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
+ original_dir,
+ GetLastErrnoDescription().c_str()));
+ return EXIT_FAILURE;
+ }
+
+ // We can safely call execve() as it's a direct system call. We
+ // cannot use execvp() as it's a libc function and thus potentially
+ // unsafe. Since execve() doesn't search the PATH, the user must
+ // invoke the test program via a valid path that contains at least
+ // one path separator.
+ execve(args->argv[0], args->argv, GetEnviron());
+ DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",
+ args->argv[0],
+ original_dir,
+ GetLastErrnoDescription().c_str()));
+ return EXIT_FAILURE;
+}
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+//
+// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
+// StackLowerThanAddress into StackGrowsDown, which then doesn't give
+// correct answer.
+bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_;
+bool StackLowerThanAddress(const void* ptr) {
+ int dummy;
+ return &dummy < ptr;
+}
+
+bool StackGrowsDown() {
+ int dummy;
+ return StackLowerThanAddress(&dummy);
+}
+
+// A threadsafe implementation of fork(2) for threadsafe-style death tests
+// that uses clone(2). It dies with an error message if anything goes
+// wrong.
+static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
+ ExecDeathTestArgs args = { argv, close_fd };
+ pid_t child_pid = -1;
+
+# if GTEST_HAS_CLONE
+ const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+ if (!use_fork) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const size_t stack_size = getpagesize();
+ // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+ void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+ void* const stack_top =
+ static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
+
+ child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+ GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+ }
+# else
+ const bool use_fork = true;
+# endif // GTEST_HAS_CLONE
+
+ if (use_fork && (child_pid = fork()) == 0) {
+ ExecDeathTestChildMain(&args);
+ _exit(0);
+ }
+
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test. It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+ // Clear the close-on-exec flag on the write end of the pipe, lest
+ // it be closed when the child process does an exec:
+ GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+ const String filter_flag =
+ String::Format("--%s%s=%s.%s",
+ GTEST_FLAG_PREFIX_, kFilterFlag,
+ info->test_case_name(), info->name());
+ const String internal_flag =
+ String::Format("--%s%s=%s|%d|%d|%d",
+ GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
+ file_, line_, death_test_index, pipe_fd[1]);
+ Arguments args;
+ args.AddArguments(GetArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // See the comment in NoExecDeathTest::AssumeRole for why the next line
+ // is necessary.
+ FlushInfoLog();
+
+ const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_child_pid(child_pid);
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+# endif // !GTEST_OS_WINDOWS
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address. If the test should be
+// skipped, sets that pointer to NULL. Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+ const char* file, int line,
+ DeathTest** test) {
+ UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const int death_test_index = impl->current_test_info()
+ ->increment_death_test_count();
+
+ if (flag != NULL) {
+ if (death_test_index > flag->index()) {
+ DeathTest::set_last_death_test_message(String::Format(
+ "Death test count (%d) somehow exceeded expected maximum (%d)",
+ death_test_index, flag->index()));
+ return false;
+ }
+
+ if (!(flag->file() == file && flag->line() == line &&
+ flag->index() == death_test_index)) {
+ *test = NULL;
+ return true;
+ }
+ }
+
+# if GTEST_OS_WINDOWS
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new WindowsDeathTest(statement, regex, file, line);
+ }
+
+# else
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe") {
+ *test = new ExecDeathTest(statement, regex, file, line);
+ } else if (GTEST_FLAG(death_test_style) == "fast") {
+ *test = new NoExecDeathTest(statement, regex);
+ }
+
+# endif // GTEST_OS_WINDOWS
+
+ else { // NOLINT - this is more readable than unbalanced brackets inside #if.
+ DeathTest::set_last_death_test_message(String::Format(
+ "Unknown death test style \"%s\" encountered",
+ GTEST_FLAG(death_test_style).c_str()));
+ return false;
+ }
+
+ return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest) {
+ ::std::vector< ::std::string> parsed;
+ ::std::string::size_type pos = 0;
+ while (::testing::internal::AlwaysTrue()) {
+ const ::std::string::size_type colon = str.find(delimiter, pos);
+ if (colon == ::std::string::npos) {
+ parsed.push_back(str.substr(pos));
+ break;
+ } else {
+ parsed.push_back(str.substr(pos, colon - pos));
+ pos = colon + 1;
+ }
+ }
+ dest->swap(parsed);
+}
+
+# if GTEST_OS_WINDOWS
+// Recreates the pipe and event handles from the provided parameters,
+// signals the event, and returns a file descriptor wrapped around the pipe
+// handle. This function is called in the child process only.
+int GetStatusFileDescriptor(unsigned int parent_process_id,
+ size_t write_handle_as_size_t,
+ size_t event_handle_as_size_t) {
+ AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+ FALSE, // Non-inheritable.
+ parent_process_id));
+ if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+ DeathTestAbort(String::Format("Unable to open parent process %u",
+ parent_process_id));
+ }
+
+ // TODO(vladl@google.com): Replace the following check with a
+ // compile-time assertion when available.
+ GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+ const HANDLE write_handle =
+ reinterpret_cast<HANDLE>(write_handle_as_size_t);
+ HANDLE dup_write_handle;
+
+ // The newly initialized handle is accessible only in in the parent
+ // process. To obtain one accessible within the child, we need to use
+ // DuplicateHandle.
+ if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+ ::GetCurrentProcess(), &dup_write_handle,
+ 0x0, // Requested privileges ignored since
+ // DUPLICATE_SAME_ACCESS is used.
+ FALSE, // Request non-inheritable handler.
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort(String::Format(
+ "Unable to duplicate the pipe handle %Iu from the parent process %u",
+ write_handle_as_size_t, parent_process_id));
+ }
+
+ const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+ HANDLE dup_event_handle;
+
+ if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+ ::GetCurrentProcess(), &dup_event_handle,
+ 0x0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort(String::Format(
+ "Unable to duplicate the event handle %Iu from the parent process %u",
+ event_handle_as_size_t, parent_process_id));
+ }
+
+ const int write_fd =
+ ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+ if (write_fd == -1) {
+ DeathTestAbort(String::Format(
+ "Unable to convert pipe handle %Iu to a file descriptor",
+ write_handle_as_size_t));
+ }
+
+ // Signals the parent that the write end of the pipe has been acquired
+ // so the parent can release its own write end.
+ ::SetEvent(dup_event_handle);
+
+ return write_fd;
+}
+# endif // GTEST_OS_WINDOWS
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+ if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ int line = -1;
+ int index = -1;
+ ::std::vector< ::std::string> fields;
+ SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+ int write_fd = -1;
+
+# if GTEST_OS_WINDOWS
+
+ unsigned int parent_process_id = 0;
+ size_t write_handle_as_size_t = 0;
+ size_t event_handle_as_size_t = 0;
+
+ if (fields.size() != 6
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &parent_process_id)
+ || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+ || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+ DeathTestAbort(String::Format(
+ "Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str()));
+ }
+ write_fd = GetStatusFileDescriptor(parent_process_id,
+ write_handle_as_size_t,
+ event_handle_as_size_t);
+# else
+
+ if (fields.size() != 4
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &write_fd)) {
+ DeathTestAbort(String::Format(
+ "Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str()));
+ }
+
+# endif // GTEST_OS_WINDOWS
+
+ return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+} // namespace internal
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+
+
+#include <stdlib.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>
+#elif GTEST_OS_WINDOWS
+# include <direct.h>
+# include <io.h>
+#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL
+// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h
+# include <sys/syslimits.h>
+#else
+# include <limits.h>
+# include <climits> // Some Linux distributions define PATH_MAX here.
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+# define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif // GTEST_OS_WINDOWS
+
+
+namespace testing {
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+// On Windows, '\\' is the standard path separator, but many tools and the
+// Windows API also accept '/' as an alternate path separator. Unless otherwise
+// noted, a file path can contain either kind of path separators, or a mixture
+// of them.
+const char kPathSeparator = '\\';
+const char kAlternatePathSeparator = '/';
+const char kPathSeparatorString[] = "\\";
+const char kAlternatePathSeparatorString[] = "/";
+# if GTEST_OS_WINDOWS_MOBILE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+# else
+const char kCurrentDirectoryString[] = ".\\";
+# endif // GTEST_OS_WINDOWS_MOBILE
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif // GTEST_OS_WINDOWS
+
+// Returns whether the given character is a valid path separator.
+static bool IsPathSeparator(char c) {
+#if GTEST_HAS_ALT_PATH_SEP_
+ return (c == kPathSeparator) || (c == kAlternatePathSeparator);
+#else
+ return c == kPathSeparator;
+#endif
+}
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE doesn't have a current directory, so we just return
+ // something reasonable.
+ return FilePath(kCurrentDirectoryString);
+#elif GTEST_OS_WINDOWS
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+ String dot_extension(String::Format(".%s", extension));
+ if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
+ return FilePath(String(pathname_.c_str(), pathname_.length() - 4));
+ }
+ return *this;
+}
+
+// Returns a pointer to the last occurence of a valid path separator in
+// the FilePath. On Windows, for example, both '/' and '\' are valid path
+// separators. Returns NULL if no path separator was found.
+const char* FilePath::FindLastPathSeparator() const {
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+#if GTEST_HAS_ALT_PATH_SEP_
+ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
+ // Comparing two pointers of which only one is NULL is undefined.
+ if (last_alt_sep != NULL &&
+ (last_sep == NULL || last_alt_sep > last_sep)) {
+ return last_alt_sep;
+ }
+#endif
+ return last_sep;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+ const char* const last_sep = FindLastPathSeparator();
+ return last_sep ? FilePath(String(last_sep + 1)) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+ const char* const last_sep = FindLastPathSeparator();
+ String dir;
+ if (last_sep) {
+ dir = String(c_str(), last_sep + 1 - c_str());
+ } else {
+ dir = kCurrentDirectoryString;
+ }
+ return FilePath(dir);
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension) {
+ String file;
+ if (number == 0) {
+ file = String::Format("%s.%s", base_name.c_str(), extension);
+ } else {
+ file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);
+ }
+ return ConcatPaths(directory, FilePath(file));
+}
+
+// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
+// On Windows, uses \ as the separator rather than /.
+FilePath FilePath::ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path) {
+ if (directory.IsEmpty())
+ return relative_path;
+ const FilePath dir(directory.RemoveTrailingPathSeparator());
+ return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,
+ relative_path.c_str()));
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ return attributes != kInvalidFileAttributes;
+#else
+ posix::StatStruct file_stat;
+ return posix::Stat(pathname_.c_str(), &file_stat) == 0;
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+ bool result = false;
+#if GTEST_OS_WINDOWS
+ // Don't strip off trailing separator if path is a root directory on
+ // Windows (like "C:\\").
+ const FilePath& path(IsRootDirectory() ? *this :
+ RemoveTrailingPathSeparator());
+#else
+ const FilePath& path(*this);
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ if ((attributes != kInvalidFileAttributes) &&
+ (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ result = true;
+ }
+#else
+ posix::StatStruct file_stat;
+ result = posix::Stat(path.c_str(), &file_stat) == 0 &&
+ posix::IsDir(file_stat);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const {
+#if GTEST_OS_WINDOWS
+ // TODO(wan@google.com): on Windows a network share like
+ // \\server\share can be a root directory, although it cannot be the
+ // current directory. Handle this properly.
+ return pathname_.length() == 3 && IsAbsolutePath();
+#else
+ return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
+#endif
+}
+
+// Returns true if pathname describes an absolute path.
+bool FilePath::IsAbsolutePath() const {
+ const char* const name = pathname_.c_str();
+#if GTEST_OS_WINDOWS
+ return pathname_.length() >= 3 &&
+ ((name[0] >= 'a' && name[0] <= 'z') ||
+ (name[0] >= 'A' && name[0] <= 'Z')) &&
+ name[1] == ':' &&
+ IsPathSeparator(name[2]);
+#else
+ return IsPathSeparator(name[0]);
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension) {
+ FilePath full_pathname;
+ int number = 0;
+ do {
+ full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+ } while (full_pathname.FileOrDirectoryExists());
+ return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+ return !pathname_.empty() &&
+ IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+ if (!this->IsDirectory()) {
+ return false;
+ }
+
+ if (pathname_.length() == 0 || this->DirectoryExists()) {
+ return true;
+ }
+
+ const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+ return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ FilePath removed_sep(this->RemoveTrailingPathSeparator());
+ LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+ int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+ delete [] unicode;
+#elif GTEST_OS_WINDOWS
+ int result = _mkdir(pathname_.c_str());
+#else
+ int result = mkdir(pathname_.c_str(), 0777);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ if (result == -1) {
+ return this->DirectoryExists(); // An error is OK if the directory exists.
+ }
+ return true; // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+ return IsDirectory()
+ ? FilePath(String(pathname_.c_str(), pathname_.length() - 1))
+ : *this;
+}
+
+// Removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
+void FilePath::Normalize() {
+ if (pathname_.c_str() == NULL) {
+ pathname_ = "";
+ return;
+ }
+ const char* src = pathname_.c_str();
+ char* const dest = new char[pathname_.length() + 1];
+ char* dest_ptr = dest;
+ memset(dest_ptr, 0, pathname_.length() + 1);
+
+ while (*src != '\0') {
+ *dest_ptr = *src;
+ if (!IsPathSeparator(*src)) {
+ src++;
+ } else {
+#if GTEST_HAS_ALT_PATH_SEP_
+ if (*dest_ptr == kAlternatePathSeparator) {
+ *dest_ptr = kPathSeparator;
+ }
+#endif
+ while (IsPathSeparator(*src))
+ src++;
+ }
+ dest_ptr++;
+ }
+ *dest_ptr = '\0';
+ pathname_ = dest;
+ delete[] dest;
+}
+
+} // namespace internal
+} // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h> // For TerminateProcess()
+#elif GTEST_OS_WINDOWS
+# include <io.h>
+# include <sys/stat.h>
+#else
+# include <unistd.h>
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_MAC
+# include <mach/mach_init.h>
+# include <mach/task.h>
+# include <mach/vm_map.h>
+#endif // GTEST_OS_MAC
+
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+namespace internal {
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
+const int kStdOutFileno = 1;
+const int kStdErrFileno = 2;
+#else
+const int kStdOutFileno = STDOUT_FILENO;
+const int kStdErrFileno = STDERR_FILENO;
+#endif // _MSC_VER
+
+#if GTEST_OS_MAC
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ const task_t task = mach_task_self();
+ mach_msg_type_number_t thread_count;
+ thread_act_array_t thread_list;
+ const kern_return_t status = task_threads(task, &thread_list, &thread_count);
+ if (status == KERN_SUCCESS) {
+ // task_threads allocates resources in thread_list and we need to free them
+ // to avoid leaks.
+ vm_deallocate(task,
+ reinterpret_cast<vm_address_t>(thread_list),
+ sizeof(thread_t) * thread_count);
+ return static_cast<size_t>(thread_count);
+ } else {
+ return 0;
+ }
+}
+
+#else
+
+size_t GetThreadCount() {
+ // There's no portable way to detect the number of threads, so we just
+ // return 0 to indicate that we cannot detect it.
+ return 0;
+}
+
+#endif // GTEST_OS_MAC
+
+#if GTEST_USES_POSIX_RE
+
+// Implements RE. Currently only needed for death tests.
+
+RE::~RE() {
+ if (is_valid_) {
+ // regfree'ing an invalid regex might crash because the content
+ // of the regex is undefined. Since the regex's are essentially
+ // the same, one cannot be valid (or invalid) without the other
+ // being so too.
+ regfree(&partial_regex_);
+ regfree(&full_regex_);
+ }
+ free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = posix::StrDup(regex);
+
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match.
+ const size_t full_regex_len = strlen(regex) + 10;
+ char* const full_pattern = new char[full_regex_len];
+
+ snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+ is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+ // We want to call regcomp(&partial_regex_, ...) even if the
+ // previous expression returns false. Otherwise partial_regex_ may
+ // not be properly initialized can may cause trouble when it's
+ // freed.
+ //
+ // Some implementation of POSIX regex (e.g. on at least some
+ // versions of Cygwin) doesn't accept the empty string as a valid
+ // regex. We change it to an equivalent form "()" to be safe.
+ if (is_valid_) {
+ const char* const partial_regex = (*regex == '\0') ? "()" : regex;
+ is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
+ }
+ EXPECT_TRUE(is_valid_)
+ << "Regular expression \"" << regex
+ << "\" is not a valid POSIX Extended regular expression.";
+
+ delete[] full_pattern;
+}
+
+#elif GTEST_USES_SIMPLE_RE
+
+// Returns true iff ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str) {
+ return ch != '\0' && strchr(str, ch) != NULL;
+}
+
+// Returns true iff ch belongs to the given classification. Unlike
+// similar functions in <ctype.h>, these aren't affected by the
+// current locale.
+bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
+bool IsAsciiPunct(char ch) {
+ return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
+}
+bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
+bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
+bool IsAsciiWordChar(char ch) {
+ return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9') || ch == '_';
+}
+
+// Returns true iff "\\c" is a supported escape sequence.
+bool IsValidEscape(char c) {
+ return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true iff the given atom (specified by escaped and pattern)
+// matches ch. The result is undefined if the atom is invalid.
+bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
+ if (escaped) { // "\\p" where p is pattern_char.
+ switch (pattern_char) {
+ case 'd': return IsAsciiDigit(ch);
+ case 'D': return !IsAsciiDigit(ch);
+ case 'f': return ch == '\f';
+ case 'n': return ch == '\n';
+ case 'r': return ch == '\r';
+ case 's': return IsAsciiWhiteSpace(ch);
+ case 'S': return !IsAsciiWhiteSpace(ch);
+ case 't': return ch == '\t';
+ case 'v': return ch == '\v';
+ case 'w': return IsAsciiWordChar(ch);
+ case 'W': return !IsAsciiWordChar(ch);
+ }
+ return IsAsciiPunct(pattern_char) && pattern_char == ch;
+ }
+
+ return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
+}
+
+// Helper function used by ValidateRegex() to format error messages.
+String FormatRegexSyntaxError(const char* regex, int index) {
+ return (Message() << "Syntax error at index " << index
+ << " in simple regular expression \"" << regex << "\": ").GetString();
+}
+
+// Generates non-fatal failures and returns false if regex is invalid;
+// otherwise returns true.
+bool ValidateRegex(const char* regex) {
+ if (regex == NULL) {
+ // TODO(wan@google.com): fix the source file location in the
+ // assertion failures to match where the regex is used in user
+ // code.
+ ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+ return false;
+ }
+
+ bool is_valid = true;
+
+ // True iff ?, *, or + can follow the previous atom.
+ bool prev_repeatable = false;
+ for (int i = 0; regex[i]; i++) {
+ if (regex[i] == '\\') { // An escape sequence
+ i++;
+ if (regex[i] == '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "'\\' cannot appear at the end.";
+ return false;
+ }
+
+ if (!IsValidEscape(regex[i])) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "invalid escape sequence \"\\" << regex[i] << "\".";
+ is_valid = false;
+ }
+ prev_repeatable = true;
+ } else { // Not an escape sequence.
+ const char ch = regex[i];
+
+ if (ch == '^' && i > 0) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'^' can only appear at the beginning.";
+ is_valid = false;
+ } else if (ch == '$' && regex[i + 1] != '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'$' can only appear at the end.";
+ is_valid = false;
+ } else if (IsInSet(ch, "()[]{}|")) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' is unsupported.";
+ is_valid = false;
+ } else if (IsRepeat(ch) && !prev_repeatable) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' can only follow a repeatable token.";
+ is_valid = false;
+ }
+
+ prev_repeatable = !IsInSet(ch, "^$?*+");
+ }
+ }
+
+ return is_valid;
+}
+
+// Matches a repeated regex atom followed by a valid simple regular
+// expression. The regex atom is defined as c if escaped is false,
+// or \c otherwise. repeat is the repetition meta character (?, *,
+// or +). The behavior is undefined if str contains too many
+// characters to be indexable by size_t, in which case the test will
+// probably time out anyway. We are fine with this limitation as
+// std::string has it too.
+bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char c, char repeat, const char* regex,
+ const char* str) {
+ const size_t min_count = (repeat == '+') ? 1 : 0;
+ const size_t max_count = (repeat == '?') ? 1 :
+ static_cast<size_t>(-1) - 1;
+ // We cannot call numeric_limits::max() as it conflicts with the
+ // max() macro on Windows.
+
+ for (size_t i = 0; i <= max_count; ++i) {
+ // We know that the atom matches each of the first i characters in str.
+ if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
+ // We have enough matches at the head, and the tail matches too.
+ // Since we only care about *whether* the pattern matches str
+ // (as opposed to *how* it matches), there is no need to find a
+ // greedy match.
+ return true;
+ }
+ if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
+ return false;
+ }
+ return false;
+}
+
+// Returns true iff regex matches a prefix of str. regex must be a
+// valid simple regular expression and not start with "^", or the
+// result is undefined.
+bool MatchRegexAtHead(const char* regex, const char* str) {
+ if (*regex == '\0') // An empty regex matches a prefix of anything.
+ return true;
+
+ // "$" only matches the end of a string. Note that regex being
+ // valid guarantees that there's nothing after "$" in it.
+ if (*regex == '$')
+ return *str == '\0';
+
+ // Is the first thing in regex an escape sequence?
+ const bool escaped = *regex == '\\';
+ if (escaped)
+ ++regex;
+ if (IsRepeat(regex[1])) {
+ // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
+ // here's an indirect recursion. It terminates as the regex gets
+ // shorter in each recursion.
+ return MatchRepetitionAndRegexAtHead(
+ escaped, regex[0], regex[1], regex + 2, str);
+ } else {
+ // regex isn't empty, isn't "$", and doesn't start with a
+ // repetition. We match the first atom of regex with the first
+ // character of str and recurse.
+ return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
+ MatchRegexAtHead(regex + 1, str + 1);
+ }
+}
+
+// Returns true iff regex matches any substring of str. regex must be
+// a valid simple regular expression, or the result is undefined.
+//
+// The algorithm is recursive, but the recursion depth doesn't exceed
+// the regex length, so we won't need to worry about running out of
+// stack space normally. In rare cases the time complexity can be
+// exponential with respect to the regex length + the string length,
+// but usually it's must faster (often close to linear).
+bool MatchRegexAnywhere(const char* regex, const char* str) {
+ if (regex == NULL || str == NULL)
+ return false;
+
+ if (*regex == '^')
+ return MatchRegexAtHead(regex + 1, str);
+
+ // A successful match can be anywhere in str.
+ do {
+ if (MatchRegexAtHead(regex, str))
+ return true;
+ } while (*str++ != '\0');
+ return false;
+}
+
+// Implements the RE class.
+
+RE::~RE() {
+ free(const_cast<char*>(pattern_));
+ free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+ return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+ return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = full_pattern_ = NULL;
+ if (regex != NULL) {
+ pattern_ = posix::StrDup(regex);
+ }
+
+ is_valid_ = ValidateRegex(regex);
+ if (!is_valid_) {
+ // No need to calculate the full pattern when the regex is invalid.
+ return;
+ }
+
+ const size_t len = strlen(regex);
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match: we need space to prepend a '^', append a '$', and
+ // terminate the string with '\0'.
+ char* buffer = static_cast<char*>(malloc(len + 3));
+ full_pattern_ = buffer;
+
+ if (*regex != '^')
+ *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'.
+
+ // We don't use snprintf or strncpy, as they trigger a warning when
+ // compiled with VC++ 8.0.
+ memcpy(buffer, regex, len);
+ buffer += len;
+
+ if (len == 0 || regex[len - 1] != '$')
+ *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'.
+
+ *buffer = '\0';
+}
+
+#endif // GTEST_USES_POSIX_RE
+
+const char kUnknownFile[] = "unknown file";
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
+ const char* const file_name = file == NULL ? kUnknownFile : file;
+
+ if (line < 0) {
+ return String::Format("%s:", file_name).c_str();
+ }
+#ifdef _MSC_VER
+ return String::Format("%s(%d):", file_name, line).c_str();
+#else
+ return String::Format("%s:%d:", file_name, line).c_str();
+#endif // _MSC_VER
+}
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+// Note that FormatCompilerIndependentFileLocation() does NOT append colon
+// to the file location it produces, unlike FormatFileLocation().
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
+ const char* file, int line) {
+ const char* const file_name = file == NULL ? kUnknownFile : file;
+
+ if (line < 0)
+ return file_name;
+ else
+ return String::Format("%s:%d", file_name, line).c_str();
+}
+
+
+GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
+ : severity_(severity) {
+ const char* const marker =
+ severity == GTEST_INFO ? "[ INFO ]" :
+ severity == GTEST_WARNING ? "[WARNING]" :
+ severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
+ GetStream() << ::std::endl << marker << " "
+ << FormatFileLocation(file, line).c_str() << ": ";
+}
+
+// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+GTestLog::~GTestLog() {
+ GetStream() << ::std::endl;
+ if (severity_ == GTEST_FATAL) {
+ fflush(stderr);
+ posix::Abort();
+ }
+}
+// Disable Microsoft deprecation warnings for POSIX functions called from
+// this class (creat, dup, dup2, and close)
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4996)
+#endif // _MSC_VER
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Object that captures an output stream (stdout/stderr).
+class CapturedStream {
+ public:
+ // The ctor redirects the stream to a temporary file.
+ CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
+
+# if GTEST_OS_WINDOWS
+ char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+ char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+
+ ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
+ const UINT success = ::GetTempFileNameA(temp_dir_path,
+ "gtest_redir",
+ 0, // Generate unique file name.
+ temp_file_path);
+ GTEST_CHECK_(success != 0)
+ << "Unable to create a temporary file in " << temp_dir_path;
+ const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
+ GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
+ << temp_file_path;
+ filename_ = temp_file_path;
+# else
+ // There's no guarantee that a test has write access to the
+ // current directory, so we create the temporary file in the /tmp
+ // directory instead.
+ char name_template[] = "/tmp/captured_stream.XXXXXX";
+ const int captured_fd = mkstemp(name_template);
+ filename_ = name_template;
+# endif // GTEST_OS_WINDOWS
+ fflush(NULL);
+ dup2(captured_fd, fd_);
+ close(captured_fd);
+ }
+
+ ~CapturedStream() {
+ remove(filename_.c_str());
+ }
+
+ String GetCapturedString() {
+ if (uncaptured_fd_ != -1) {
+ // Restores the original stream.
+ fflush(NULL);
+ dup2(uncaptured_fd_, fd_);
+ close(uncaptured_fd_);
+ uncaptured_fd_ = -1;
+ }
+
+ FILE* const file = posix::FOpen(filename_.c_str(), "r");
+ const String content = ReadEntireFile(file);
+ posix::FClose(file);
+ return content;
+ }
+
+ private:
+ // Reads the entire content of a file as a String.
+ static String ReadEntireFile(FILE* file);
+
+ // Returns the size (in bytes) of a file.
+ static size_t GetFileSize(FILE* file);
+
+ const int fd_; // A stream to capture.
+ int uncaptured_fd_;
+ // Name of the temporary file holding the stderr output.
+ ::std::string filename_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
+};
+
+// Returns the size (in bytes) of a file.
+size_t CapturedStream::GetFileSize(FILE* file) {
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+String CapturedStream::ReadEntireFile(FILE* file) {
+ const size_t file_size = GetFileSize(file);
+ char* const buffer = new char[file_size];
+
+ size_t bytes_last_read = 0; // # of bytes read in the last fread()
+ size_t bytes_read = 0; // # of bytes read so far
+
+ fseek(file, 0, SEEK_SET);
+
+ // Keeps reading the file until we cannot read further or the
+ // pre-determined file size is reached.
+ do {
+ bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+ bytes_read += bytes_last_read;
+ } while (bytes_last_read > 0 && bytes_read < file_size);
+
+ const String content(buffer, bytes_read);
+ delete[] buffer;
+
+ return content;
+}
+
+# ifdef _MSC_VER
+# pragma warning(pop)
+# endif // _MSC_VER
+
+static CapturedStream* g_captured_stderr = NULL;
+static CapturedStream* g_captured_stdout = NULL;
+
+// Starts capturing an output stream (stdout/stderr).
+void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
+ if (*stream != NULL) {
+ GTEST_LOG_(FATAL) << "Only one " << stream_name
+ << " capturer can exist at a time.";
+ }
+ *stream = new CapturedStream(fd);
+}
+
+// Stops capturing the output stream and returns the captured string.
+String GetCapturedStream(CapturedStream** captured_stream) {
+ const String content = (*captured_stream)->GetCapturedString();
+
+ delete *captured_stream;
+ *captured_stream = NULL;
+
+ return content;
+}
+
+// Starts capturing stdout.
+void CaptureStdout() {
+ CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+ CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
+}
+
+// Stops capturing stdout and returns the captured string.
+String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
+
+// Stops capturing stderr and returns the captured string.
+String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+::std::vector<String> g_argvs;
+
+// Returns the command line as a vector of strings.
+const ::std::vector<String>& GetArgvs() { return g_argvs; }
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_WINDOWS_MOBILE
+namespace posix {
+void Abort() {
+ DebugBreak();
+ TerminateProcess(GetCurrentProcess(), 1);
+}
+} // namespace posix
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Returns the name of the environment variable corresponding to the
+// given flag. For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static String FlagToEnvVar(const char* flag) {
+ const String full_flag =
+ (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
+
+ Message env_var;
+ for (size_t i = 0; i != full_flag.length(); i++) {
+ env_var << ToUpper(full_flag.c_str()[i]);
+ }
+
+ return env_var.GetString();
+}
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+ // Parses the environment variable as a decimal integer.
+ char* end = NULL;
+ const long long_value = strtol(str, &end, 10); // NOLINT
+
+ // Has strtol() consumed all characters in the string?
+ if (*end != '\0') {
+ // No - an invalid character was encountered.
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value \"" << str << "\".\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ // Is the parsed value in the range of an Int32?
+ const Int32 result = static_cast<Int32>(long_value);
+ if (long_value == LONG_MAX || long_value == LONG_MIN ||
+ // The parsed value overflows as a long. (strtol() returns
+ // LONG_MAX or LONG_MIN when the input overflows.)
+ result != long_value
+ // The parsed value overflows as an Int32.
+ ) {
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value " << str << ", which overflows.\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ *value = result;
+ return true;
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ return string_value == NULL ?
+ default_value : strcmp(string_value, "0") != 0;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ if (string_value == NULL) {
+ // The environment variable is not set.
+ return default_value;
+ }
+
+ Int32 result = default_value;
+ if (!ParseInt32(Message() << "Environment variable " << env_var,
+ string_value, &result)) {
+ printf("The default value %s is used.\n",
+ (Message() << default_value).GetString().c_str());
+ fflush(stdout);
+ return default_value;
+ }
+
+ return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const value = posix::GetEnv(env_var.c_str());
+ return value == NULL ? default_value : value;
+}
+
+} // namespace internal
+} // namespace testing
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// It uses the << operator when possible, and prints the bytes in the
+// object otherwise. A user can override its behavior for a class
+// type Foo by defining either operator<<(::std::ostream&, const Foo&)
+// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
+// defines Foo.
+
+#include <ctype.h>
+#include <stdio.h>
+#include <ostream> // NOLINT
+#include <string>
+
+namespace testing {
+
+namespace {
+
+using ::std::ostream;
+
+#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s.
+# define snprintf _snprintf
+#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf.
+# define snprintf _snprintf_s
+#elif _MSC_VER
+# define snprintf _snprintf
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Prints a segment of bytes in the given object.
+void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
+ size_t count, ostream* os) {
+ char text[5] = "";
+ for (size_t i = 0; i != count; i++) {
+ const size_t j = start + i;
+ if (i != 0) {
+ // Organizes the bytes into groups of 2 for easy parsing by
+ // human.
+ if ((j % 2) == 0)
+ *os << ' ';
+ else
+ *os << '-';
+ }
+ snprintf(text, sizeof(text), "%02X", obj_bytes[j]);
+ *os << text;
+ }
+}
+
+// Prints the bytes in the given value to the given ostream.
+void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
+ ostream* os) {
+ // Tells the user how big the object is.
+ *os << count << "-byte object <";
+
+ const size_t kThreshold = 132;
+ const size_t kChunkSize = 64;
+ // If the object size is bigger than kThreshold, we'll have to omit
+ // some details by printing only the first and the last kChunkSize
+ // bytes.
+ // TODO(wan): let the user control the threshold using a flag.
+ if (count < kThreshold) {
+ PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
+ } else {
+ PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
+ *os << " ... ";
+ // Rounds up to 2-byte boundary.
+ const size_t resume_pos = (count - kChunkSize + 1)/2*2;
+ PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
+ }
+ *os << ">";
+}
+
+} // namespace
+
+namespace internal2 {
+
+// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
+// given object. The delegation simplifies the implementation, which
+// uses the << operator and thus is easier done outside of the
+// ::testing::internal namespace, which contains a << operator that
+// sometimes conflicts with the one in STL.
+void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
+ ostream* os) {
+ PrintBytesInObjectToImpl(obj_bytes, count, os);
+}
+
+} // namespace internal2
+
+namespace internal {
+
+// Depending on the value of a char (or wchar_t), we print it in one
+// of three formats:
+// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
+// - as a hexidecimal escape sequence (e.g. '\x7F'), or
+// - as a special escape sequence (e.g. '\r', '\n').
+enum CharFormat {
+ kAsIs,
+ kHexEscape,
+ kSpecialEscape
+};
+
+// Returns true if c is a printable ASCII character. We test the
+// value of c directly instead of calling isprint(), which is buggy on
+// Windows Mobile.
+inline bool IsPrintableAscii(wchar_t c) {
+ return 0x20 <= c && c <= 0x7E;
+}
+
+// Prints a wide or narrow char c as a character literal without the
+// quotes, escaping it when necessary; returns how c was formatted.
+// The template argument UnsignedChar is the unsigned version of Char,
+// which is the type of c.
+template <typename UnsignedChar, typename Char>
+static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
+ switch (static_cast<wchar_t>(c)) {
+ case L'\0':
+ *os << "\\0";
+ break;
+ case L'\'':
+ *os << "\\'";
+ break;
+ case L'\\':
+ *os << "\\\\";
+ break;
+ case L'\a':
+ *os << "\\a";
+ break;
+ case L'\b':
+ *os << "\\b";
+ break;
+ case L'\f':
+ *os << "\\f";
+ break;
+ case L'\n':
+ *os << "\\n";
+ break;
+ case L'\r':
+ *os << "\\r";
+ break;
+ case L'\t':
+ *os << "\\t";
+ break;
+ case L'\v':
+ *os << "\\v";
+ break;
+ default:
+ if (IsPrintableAscii(c)) {
+ *os << static_cast<char>(c);
+ return kAsIs;
+ } else {
+ *os << String::Format("\\x%X", static_cast<UnsignedChar>(c));
+ return kHexEscape;
+ }
+ }
+ return kSpecialEscape;
+}
+
+// Prints a char c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) {
+ switch (c) {
+ case L'\'':
+ *os << "'";
+ return kAsIs;
+ case L'"':
+ *os << "\\\"";
+ return kSpecialEscape;
+ default:
+ return PrintAsCharLiteralTo<wchar_t>(c, os);
+ }
+}
+
+// Prints a char c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) {
+ return PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os);
+}
+
+// Prints a wide or narrow character c and its code. '\0' is printed
+// as "'\\0'", other unprintable characters are also properly escaped
+// using the standard C++ escape sequence. The template argument
+// UnsignedChar is the unsigned version of Char, which is the type of c.
+template <typename UnsignedChar, typename Char>
+void PrintCharAndCodeTo(Char c, ostream* os) {
+ // First, print c as a literal in the most readable form we can find.
+ *os << ((sizeof(c) > 1) ? "L'" : "'");
+ const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
+ *os << "'";
+
+ // To aid user debugging, we also print c's code in decimal, unless
+ // it's 0 (in which case c was printed as '\\0', making the code
+ // obvious).
+ if (c == 0)
+ return;
+ *os << " (" << String::Format("%d", c).c_str();
+
+ // For more convenience, we print c's code again in hexidecimal,
+ // unless c was already printed in the form '\x##' or the code is in
+ // [1, 9].
+ if (format == kHexEscape || (1 <= c && c <= 9)) {
+ // Do nothing.
+ } else {
+ *os << String::Format(", 0x%X",
+ static_cast<UnsignedChar>(c)).c_str();
+ }
+ *os << ")";
+}
+
+void PrintTo(unsigned char c, ::std::ostream* os) {
+ PrintCharAndCodeTo<unsigned char>(c, os);
+}
+void PrintTo(signed char c, ::std::ostream* os) {
+ PrintCharAndCodeTo<unsigned char>(c, os);
+}
+
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
+void PrintTo(wchar_t wc, ostream* os) {
+ PrintCharAndCodeTo<wchar_t>(wc, os);
+}
+
+// Prints the given array of characters to the ostream.
+// The array starts at *begin, the length is len, it may include '\0' characters
+// and may not be null-terminated.
+static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) {
+ *os << "\"";
+ bool is_previous_hex = false;
+ for (size_t index = 0; index < len; ++index) {
+ const char cur = begin[index];
+ if (is_previous_hex && IsXDigit(cur)) {
+ // Previous character is of '\x..' form and this character can be
+ // interpreted as another hexadecimal digit in its number. Break string to
+ // disambiguate.
+ *os << "\" \"";
+ }
+ is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape;
+ }
+ *os << "\"";
+}
+
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
+ PrintCharsAsStringTo(begin, len, os);
+}
+
+// Prints the given array of wide characters to the ostream.
+// The array starts at *begin, the length is len, it may include L'\0'
+// characters and may not be null-terminated.
+static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len,
+ ostream* os) {
+ *os << "L\"";
+ bool is_previous_hex = false;
+ for (size_t index = 0; index < len; ++index) {
+ const wchar_t cur = begin[index];
+ if (is_previous_hex && isascii(cur) && IsXDigit(static_cast<char>(cur))) {
+ // Previous character is of '\x..' form and this character can be
+ // interpreted as another hexadecimal digit in its number. Break string to
+ // disambiguate.
+ *os << "\" L\"";
+ }
+ is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape;
+ }
+ *os << "\"";
+}
+
+// Prints the given C string to the ostream.
+void PrintTo(const char* s, ostream* os) {
+ if (s == NULL) {
+ *os << "NULL";
+ } else {
+ *os << ImplicitCast_<const void*>(s) << " pointing to ";
+ PrintCharsAsStringTo(s, strlen(s), os);
+ }
+}
+
+// MSVC compiler can be configured to define whar_t as a typedef
+// of unsigned short. Defining an overload for const wchar_t* in that case
+// would cause pointers to unsigned shorts be printed as wide strings,
+// possibly accessing more memory than intended and causing invalid
+// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
+// wchar_t is implemented as a native type.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Prints the given wide C string to the ostream.
+void PrintTo(const wchar_t* s, ostream* os) {
+ if (s == NULL) {
+ *os << "NULL";
+ } else {
+ *os << ImplicitCast_<const void*>(s) << " pointing to ";
+ PrintWideCharsAsStringTo(s, wcslen(s), os);
+ }
+}
+#endif // wchar_t is native
+
+// Prints a ::string object.
+#if GTEST_HAS_GLOBAL_STRING
+void PrintStringTo(const ::string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+
+void PrintStringTo(const ::std::string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+// Prints a ::wstring object.
+#if GTEST_HAS_GLOBAL_WSTRING
+void PrintWideStringTo(const ::wstring& s, ostream* os) {
+ PrintWideCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
+ PrintWideCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+} // namespace internal
+
+} // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// The Google C++ Testing Framework (Google Test)
+
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+using internal::GetUnitTestImpl;
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+internal::String TestPartResult::ExtractSummary(const char* message) {
+ const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+ return stack_trace == NULL ? internal::String(message) :
+ internal::String(message, stack_trace - message);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+ return os
+ << result.file_name() << ":" << result.line_number() << ": "
+ << (result.type() == TestPartResult::kSuccess ? "Success" :
+ result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
+ "Non-fatal failure") << ":\n"
+ << result.message() << std::endl;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+ array_.push_back(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+ if (index < 0 || index >= size()) {
+ printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+ internal::posix::Abort();
+ }
+
+ return array_[index];
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+ return static_cast<int>(array_.size());
+}
+
+namespace internal {
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+ : has_new_fatal_failure_(false),
+ original_reporter_(GetUnitTestImpl()->
+ GetTestPartResultReporterForCurrentThread()) {
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
+ original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+ const TestPartResult& result) {
+ if (result.fatally_failed())
+ has_new_fatal_failure_ = true;
+ original_reporter_->ReportTestPartResult(result);
+}
+
+} // namespace internal
+
+} // namespace testing
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+
+namespace testing {
+namespace internal {
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Skips to the first non-space char in str. Returns an empty string if str
+// contains only whitespace characters.
+static const char* SkipSpaces(const char* str) {
+ while (IsSpace(*str))
+ str++;
+ return str;
+}
+
+// Verifies that registered_tests match the test names in
+// defined_test_names_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestCasePState::VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests) {
+ typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+ registered_ = true;
+
+ // Skip initial whitespace in registered_tests since some
+ // preprocessors prefix stringizied literals with whitespace.
+ registered_tests = SkipSpaces(registered_tests);
+
+ Message errors;
+ ::std::set<String> tests;
+ for (const char* names = registered_tests; names != NULL;
+ names = SkipComma(names)) {
+ const String name = GetPrefixUntilComma(names);
+ if (tests.count(name) != 0) {
+ errors << "Test " << name << " is listed more than once.\n";
+ continue;
+ }
+
+ bool found = false;
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (name == *it) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ tests.insert(name);
+ } else {
+ errors << "No test named " << name
+ << " can be found in this test case.\n";
+ }
+ }
+
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (tests.count(*it) == 0) {
+ errors << "You forgot to list test " << *it << ".\n";
+ }
+ }
+
+ const String& errors_str = errors.GetString();
+ if (errors_str != "") {
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors_str.c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+
+ return registered_tests;
+}
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+} // namespace internal
+} // namespace testing