summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2014-08-27 04:34:34 +0000
committerChris Johns <chrisj@rtems.org>2014-08-27 04:34:34 +0000
commitdf4a99d166c666c3c05af40ac05c038afc03cc5c (patch)
treeced658e63df818ddae19f43bdcc47ed5e2754f3f
parent3162858a3a0ec414d2b5ce3d9153ca0efb2c9d27 (diff)
parent097f1fdf569e631f5fae95f27e0ec2a2f626bcbc (diff)
linkers: Merge branch 'chrisj/rtl-host.git' into rtems-tools.git.
-rw-r--r--linkers/.gitignore4
-rw-r--r--linkers/ConvertUTF.c539
-rw-r--r--linkers/ConvertUTF.h149
-rw-r--r--linkers/README22
-rw-r--r--linkers/SimpleIni.h3385
-rw-r--r--linkers/elftoolchain/common/Makefile15
-rw-r--r--linkers/elftoolchain/common/_elftc.h176
-rw-r--r--linkers/elftoolchain/common/elfdefinitions.h2560
-rwxr-xr-xlinkers/elftoolchain/common/native-elf-format47
-rw-r--r--linkers/elftoolchain/common/os.Linux.mk13
-rw-r--r--linkers/elftoolchain/common/uthash.h906
-rw-r--r--linkers/elftoolchain/libelf/Makefile158
-rw-r--r--linkers/elftoolchain/libelf/Version.map97
-rw-r--r--linkers/elftoolchain/libelf/_libelf.h211
-rw-r--r--linkers/elftoolchain/libelf/_libelf_ar.h56
-rw-r--r--linkers/elftoolchain/libelf/_libelf_config.h197
-rw-r--r--linkers/elftoolchain/libelf/elf.3589
-rw-r--r--linkers/elftoolchain/libelf/elf.c40
-rw-r--r--linkers/elftoolchain/libelf/elf_begin.3311
-rw-r--r--linkers/elftoolchain/libelf/elf_begin.c276
-rw-r--r--linkers/elftoolchain/libelf/elf_cntl.3111
-rw-r--r--linkers/elftoolchain/libelf/elf_cntl.c58
-rw-r--r--linkers/elftoolchain/libelf/elf_data.c247
-rw-r--r--linkers/elftoolchain/libelf/elf_end.376
-rw-r--r--linkers/elftoolchain/libelf/elf_end.c93
-rw-r--r--linkers/elftoolchain/libelf/elf_errmsg.3107
-rw-r--r--linkers/elftoolchain/libelf/elf_errmsg.c85
-rw-r--r--linkers/elftoolchain/libelf/elf_errno.c43
-rw-r--r--linkers/elftoolchain/libelf/elf_fill.352
-rw-r--r--linkers/elftoolchain/libelf/elf_fill.c39
-rw-r--r--linkers/elftoolchain/libelf/elf_flag.c195
-rw-r--r--linkers/elftoolchain/libelf/elf_flagdata.3194
-rw-r--r--linkers/elftoolchain/libelf/elf_getarhdr.397
-rw-r--r--linkers/elftoolchain/libelf/elf_getarhdr.c47
-rw-r--r--linkers/elftoolchain/libelf/elf_getarsym.3130
-rw-r--r--linkers/elftoolchain/libelf/elf_getarsym.c58
-rw-r--r--linkers/elftoolchain/libelf/elf_getbase.371
-rw-r--r--linkers/elftoolchain/libelf/elf_getbase.c48
-rw-r--r--linkers/elftoolchain/libelf/elf_getdata.3229
-rw-r--r--linkers/elftoolchain/libelf/elf_getident.383
-rw-r--r--linkers/elftoolchain/libelf/elf_getident.c68
-rw-r--r--linkers/elftoolchain/libelf/elf_getphdrnum.386
-rw-r--r--linkers/elftoolchain/libelf/elf_getphnum.393
-rw-r--r--linkers/elftoolchain/libelf/elf_getscn.3151
-rw-r--r--linkers/elftoolchain/libelf/elf_getshdrnum.378
-rw-r--r--linkers/elftoolchain/libelf/elf_getshdrstrndx.379
-rw-r--r--linkers/elftoolchain/libelf/elf_getshnum.384
-rw-r--r--linkers/elftoolchain/libelf/elf_getshstrndx.394
-rw-r--r--linkers/elftoolchain/libelf/elf_hash.357
-rw-r--r--linkers/elftoolchain/libelf/elf_hash.c56
-rw-r--r--linkers/elftoolchain/libelf/elf_kind.371
-rw-r--r--linkers/elftoolchain/libelf/elf_kind.c44
-rw-r--r--linkers/elftoolchain/libelf/elf_memory.3122
-rw-r--r--linkers/elftoolchain/libelf/elf_memory.c92
-rw-r--r--linkers/elftoolchain/libelf/elf_next.396
-rw-r--r--linkers/elftoolchain/libelf/elf_next.c62
-rw-r--r--linkers/elftoolchain/libelf/elf_phnum.c67
-rw-r--r--linkers/elftoolchain/libelf/elf_rand.3118
-rw-r--r--linkers/elftoolchain/libelf/elf_rand.c59
-rw-r--r--linkers/elftoolchain/libelf/elf_rawfile.376
-rw-r--r--linkers/elftoolchain/libelf/elf_rawfile.c53
-rw-r--r--linkers/elftoolchain/libelf/elf_scn.c232
-rw-r--r--linkers/elftoolchain/libelf/elf_shnum.c67
-rw-r--r--linkers/elftoolchain/libelf/elf_shstrndx.c82
-rw-r--r--linkers/elftoolchain/libelf/elf_strptr.3116
-rw-r--r--linkers/elftoolchain/libelf/elf_strptr.c130
-rw-r--r--linkers/elftoolchain/libelf/elf_types.m4309
-rw-r--r--linkers/elftoolchain/libelf/elf_update.3378
-rw-r--r--linkers/elftoolchain/libelf/elf_update.c1184
-rw-r--r--linkers/elftoolchain/libelf/elf_version.395
-rw-r--r--linkers/elftoolchain/libelf/elf_version.c52
-rw-r--r--linkers/elftoolchain/libelf/gelf.3201
-rw-r--r--linkers/elftoolchain/libelf/gelf.h108
-rw-r--r--linkers/elftoolchain/libelf/gelf_cap.c144
-rw-r--r--linkers/elftoolchain/libelf/gelf_checksum.3115
-rw-r--r--linkers/elftoolchain/libelf/gelf_checksum.c58
-rw-r--r--linkers/elftoolchain/libelf/gelf_dyn.c143
-rw-r--r--linkers/elftoolchain/libelf/gelf_ehdr.c167
-rw-r--r--linkers/elftoolchain/libelf/gelf_fsize.396
-rw-r--r--linkers/elftoolchain/libelf/gelf_fsize.c62
-rw-r--r--linkers/elftoolchain/libelf/gelf_getcap.3121
-rw-r--r--linkers/elftoolchain/libelf/gelf_getclass.361
-rw-r--r--linkers/elftoolchain/libelf/gelf_getclass.c39
-rw-r--r--linkers/elftoolchain/libelf/gelf_getdyn.3123
-rw-r--r--linkers/elftoolchain/libelf/gelf_getehdr.3123
-rw-r--r--linkers/elftoolchain/libelf/gelf_getmove.3120
-rw-r--r--linkers/elftoolchain/libelf/gelf_getphdr.3141
-rw-r--r--linkers/elftoolchain/libelf/gelf_getrel.3121
-rw-r--r--linkers/elftoolchain/libelf/gelf_getrela.3121
-rw-r--r--linkers/elftoolchain/libelf/gelf_getshdr.3115
-rw-r--r--linkers/elftoolchain/libelf/gelf_getsym.3125
-rw-r--r--linkers/elftoolchain/libelf/gelf_getsyminfo.3115
-rw-r--r--linkers/elftoolchain/libelf/gelf_getsymshndx.3162
-rw-r--r--linkers/elftoolchain/libelf/gelf_move.c150
-rw-r--r--linkers/elftoolchain/libelf/gelf_newehdr.3185
-rw-r--r--linkers/elftoolchain/libelf/gelf_newphdr.3133
-rw-r--r--linkers/elftoolchain/libelf/gelf_phdr.c177
-rw-r--r--linkers/elftoolchain/libelf/gelf_rel.c152
-rw-r--r--linkers/elftoolchain/libelf/gelf_rela.c155
-rw-r--r--linkers/elftoolchain/libelf/gelf_shdr.c130
-rw-r--r--linkers/elftoolchain/libelf/gelf_sym.c153
-rw-r--r--linkers/elftoolchain/libelf/gelf_syminfo.c145
-rw-r--r--linkers/elftoolchain/libelf/gelf_symshndx.c128
-rw-r--r--linkers/elftoolchain/libelf/gelf_update_ehdr.3123
-rw-r--r--linkers/elftoolchain/libelf/gelf_xlate.c81
-rw-r--r--linkers/elftoolchain/libelf/gelf_xlatetof.3247
-rw-r--r--linkers/elftoolchain/libelf/libelf.h258
-rw-r--r--linkers/elftoolchain/libelf/libelf_align.c137
-rw-r--r--linkers/elftoolchain/libelf/libelf_allocate.c214
-rw-r--r--linkers/elftoolchain/libelf/libelf_ar.c461
-rw-r--r--linkers/elftoolchain/libelf/libelf_ar_util.c354
-rw-r--r--linkers/elftoolchain/libelf/libelf_checksum.c100
-rw-r--r--linkers/elftoolchain/libelf/libelf_convert.m41086
-rw-r--r--linkers/elftoolchain/libelf/libelf_data.c88
-rw-r--r--linkers/elftoolchain/libelf/libelf_ehdr.c204
-rw-r--r--linkers/elftoolchain/libelf/libelf_extended.c136
-rw-r--r--linkers/elftoolchain/libelf/libelf_fsize.m4159
-rw-r--r--linkers/elftoolchain/libelf/libelf_msize.m4108
-rw-r--r--linkers/elftoolchain/libelf/libelf_phdr.c156
-rw-r--r--linkers/elftoolchain/libelf/libelf_shdr.c56
-rw-r--r--linkers/elftoolchain/libelf/libelf_xlate.c150
-rw-r--r--linkers/elftoolchain/libelf/mmap_win32.c247
-rw-r--r--linkers/elftoolchain/libelf/os.FreeBSD.mk7
-rw-r--r--linkers/elftoolchain/libelf/os.NetBSD.mk7
-rw-r--r--linkers/fastlz.c551
-rw-r--r--linkers/fastlz.h100
-rw-r--r--linkers/libiberty/ansidecl.h423
-rw-r--r--linkers/libiberty/concat.c234
-rw-r--r--linkers/libiberty/cp-demangle.c5064
-rw-r--r--linkers/libiberty/cp-demangle.h168
-rw-r--r--linkers/libiberty/cplus-dem.c4728
-rw-r--r--linkers/libiberty/demangle.h616
-rw-r--r--linkers/libiberty/libiberty.h342
-rw-r--r--linkers/libiberty/make-temp-file.c217
-rw-r--r--linkers/libiberty/mkstemps.c147
-rw-r--r--linkers/libiberty/pex-common.c646
-rw-r--r--linkers/libiberty/pex-common.h153
-rw-r--r--linkers/libiberty/pex-djgpp.c294
-rw-r--r--linkers/libiberty/pex-msdos.c317
-rw-r--r--linkers/libiberty/pex-one.c43
-rw-r--r--linkers/libiberty/pex-unix.c788
-rw-r--r--linkers/libiberty/pex-win32.c943
-rw-r--r--linkers/libiberty/safe-ctype.c255
-rw-r--r--linkers/libiberty/safe-ctype.h150
-rw-r--r--linkers/libiberty/stpcpy.c43
-rw-r--r--linkers/main-page.cpp445
-rwxr-xr-xlinkers/mkapp.sh47
-rw-r--r--linkers/pkgconfig.cpp156
-rw-r--r--linkers/pkgconfig.h65
-rw-r--r--linkers/rld-cc.cpp192
-rw-r--r--linkers/rld-cc.h60
-rw-r--r--linkers/rld-compression.cpp303
-rw-r--r--linkers/rld-compression.h228
-rw-r--r--linkers/rld-config.cpp211
-rw-r--r--linkers/rld-config.h256
-rw-r--r--linkers/rld-elf-types.h60
-rw-r--r--linkers/rld-elf.cpp1210
-rw-r--r--linkers/rld-elf.h756
-rw-r--r--linkers/rld-files.cpp1675
-rw-r--r--linkers/rld-files.h1065
-rw-r--r--linkers/rld-outputter.cpp469
-rw-r--r--linkers/rld-outputter.h125
-rw-r--r--linkers/rld-process.cpp504
-rw-r--r--linkers/rld-process.h223
-rw-r--r--linkers/rld-rap.cpp1668
-rw-r--r--linkers/rld-rap.h97
-rw-r--r--linkers/rld-resolver.cpp243
-rw-r--r--linkers/rld-resolver.h54
-rw-r--r--linkers/rld-symbols.cpp389
-rw-r--r--linkers/rld-symbols.h297
-rw-r--r--linkers/rld.cpp164
-rw-r--r--linkers/rld.h280
-rw-r--r--linkers/rtems-ld.cpp546
-rw-r--r--linkers/rtems-ra.cpp621
-rw-r--r--linkers/rtems-rapper.cpp1311
-rw-r--r--linkers/rtems-syms.cpp336
-rw-r--r--linkers/rtems-tld.cpp940
-rw-r--r--linkers/rtems-utils.cpp162
-rw-r--r--linkers/rtems-utils.h53
-rw-r--r--linkers/rtems.ini20
-rw-r--r--linkers/rtl-host.conf1664
-rw-r--r--linkers/rtld-base.ini36
-rw-r--r--linkers/test-trace.ini60
-rw-r--r--linkers/waf-tools/doxygen.py164
-rw-r--r--linkers/win32/ar.h67
-rw-r--r--linkers/win32/sys/cdefs.h64
-rw-r--r--linkers/win32/sys/errno.h1
-rw-r--r--linkers/win32/sys/mman.h90
-rw-r--r--linkers/win32/sys/queue.h637
-rw-r--r--linkers/wscript392
190 files changed, 59261 insertions, 0 deletions
diff --git a/linkers/.gitignore b/linkers/.gitignore
new file mode 100644
index 0000000..c80a859
--- /dev/null
+++ b/linkers/.gitignore
@@ -0,0 +1,4 @@
+.lock-*
+build-*
+*.rap
+*.pyc
diff --git a/linkers/ConvertUTF.c b/linkers/ConvertUTF.c
new file mode 100644
index 0000000..9b3deeb
--- /dev/null
+++ b/linkers/ConvertUTF.c
@@ -0,0 +1,539 @@
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Sept 2001: fixed const & error conditions per
+ mods suggested by S. Parent & A. Lillich.
+ June 2002: Tim Dodd added detection and handling of incomplete
+ source sequences, enhanced error detection, added casts
+ to eliminate compiler warnings.
+ July 2003: slight mods to back out aggressive FFFE detection.
+ Jan 2004: updated switches in from-UTF8 conversions.
+ Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+
+ See the header file "ConvertUTF.h" for complete documentation.
+
+------------------------------------------------------------------------ */
+
+
+#include "ConvertUTF.h"
+#ifdef CVTUTF_DEBUG
+#include <stdio.h>
+#endif
+
+static const int halfShift = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START (UTF32)0xD800
+#define UNI_SUR_HIGH_END (UTF32)0xDBFF
+#define UNI_SUR_LOW_START (UTF32)0xDC00
+#define UNI_SUR_LOW_END (UTF32)0xDFFF
+#define false 0
+#define true 1
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ if (target >= targetEnd) {
+ result = targetExhausted; break;
+ }
+ ch = *source++;
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_LEGAL_UTF32) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ --source; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF32* target = *targetStart;
+ UTF32 ch, ch2;
+ while (source < sourceEnd) {
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ if (target >= targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ *target++ = ch;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+#ifdef CVTUTF_DEBUG
+if (result == sourceIllegal) {
+ fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+ fflush(stderr);
+}
+#endif
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow. There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /* Figure out how many bytes the result will require */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static Boolean isLegalUTF8(const UTF8 *source, int length) {
+ UTF8 a;
+ const UTF8 *srcptr = source+length;
+ switch (length) {
+ default: return false;
+ /* Everything else falls through when "true"... */
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0: if (a < 0xA0) return false; break;
+ case 0xED: if (a > 0x9F) return false; break;
+ case 0xF0: if (a < 0x90) return false; break;
+ case 0xF4: if (a > 0x8F) return false; break;
+ default: if (a < 0x80) return false;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+ }
+ if (*source > 0xF4) return false;
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+ int length = trailingBytesForUTF8[*source]+1;
+ if (source+length > sourceEnd) {
+ return false;
+ }
+ return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_UTF16) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ source -= (extraBytesToRead+1); /* return to the start */
+ break; /* Bail out; shouldn't continue */
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ ch = *source++;
+ if (flags == strictConversion ) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /*
+ * Figure out how many bytes the result will require. Turn any
+ * illegally large UTF32 things (> Plane 17) into replacement chars.
+ */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ result = sourceIllegal;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ --source; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF32* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6;
+ case 4: ch += *source++; ch <<= 6;
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up the source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = ch;
+ }
+ } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* ---------------------------------------------------------------------
+
+ Note A.
+ The fall-through switches in UTF-8 reading code save a
+ temp variable, some decrements & conditionals. The switches
+ are equivalent to the following loop:
+ {
+ int tmpBytesToRead = extraBytesToRead+1;
+ do {
+ ch += *source++;
+ --tmpBytesToRead;
+ if (tmpBytesToRead) ch <<= 6;
+ } while (tmpBytesToRead > 0);
+ }
+ In UTF-8 writing code, the switches on "bytesToWrite" are
+ similarly unrolled loops.
+
+ --------------------------------------------------------------------- */
diff --git a/linkers/ConvertUTF.h b/linkers/ConvertUTF.h
new file mode 100644
index 0000000..14d7b70
--- /dev/null
+++ b/linkers/ConvertUTF.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+ Several funtions are included here, forming a complete set of
+ conversions between the three formats. UTF-7 is not included
+ here, but is handled in a separate source file.
+
+ Each of these routines takes pointers to input buffers and output
+ buffers. The input buffers are const.
+
+ Each routine converts the text between *sourceStart and sourceEnd,
+ putting the result into the buffer between *targetStart and
+ targetEnd. Note: the end pointers are *after* the last item: e.g.
+ *(sourceEnd - 1) is the last item.
+
+ The return result indicates whether the conversion was successful,
+ and if not, whether the problem was in the source or target buffers.
+ (Only the first encountered problem is indicated.)
+
+ After the conversion, *sourceStart and *targetStart are both
+ updated to point to the end of last text successfully converted in
+ the respective buffers.
+
+ Input parameters:
+ sourceStart - pointer to a pointer to the source buffer.
+ The contents of this are modified on return so that
+ it points at the next thing to be converted.
+ targetStart - similarly, pointer to pointer to the target buffer.
+ sourceEnd, targetEnd - respectively pointers to the ends of the
+ two buffers, for overflow checking only.
+
+ These conversion functions take a ConversionFlags argument. When this
+ flag is set to strict, both irregular sequences and isolated surrogates
+ will cause an error. When the flag is set to lenient, both irregular
+ sequences and isolated surrogates are converted.
+
+ Whether the flag is strict or lenient, all illegal sequences will cause
+ an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ must check for illegal sequences.
+
+ When the flag is set to lenient, characters over 0x10FFFF are converted
+ to the replacement character; otherwise (when the flag is set to strict)
+ they constitute an error.
+
+ Output parameters:
+ The value "sourceIllegal" is returned from some routines if the input
+ sequence is malformed. When "sourceIllegal" is returned, the source
+ value will point to the illegal value that caused the problem. E.g.,
+ in UTF-8 when a sequence is malformed, it points to the start of the
+ malformed sequence.
+
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+/* ---------------------------------------------------------------------
+ The following 4 definitions are compiler-specific.
+ The C standard does not guarantee that wchar_t has at least
+ 16 bits, so wchar_t is no less portable than unsigned short!
+ All should be unsigned values to avoid sign extension during
+ bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned int UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+typedef unsigned char Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+typedef enum {
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+} ConversionResult;
+
+typedef enum {
+ strictConversion = 0,
+ lenientConversion
+} ConversionFlags;
+
+/* This is for C++ and does no harm in C */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ConversionResult ConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* --------------------------------------------------------------------- */
diff --git a/linkers/README b/linkers/README
new file mode 100644
index 0000000..95ed6a2
--- /dev/null
+++ b/linkers/README
@@ -0,0 +1,22 @@
+RTEMS Dynamic Loader Project
+============================
+Chris Johns <chrisj@rtems.org>
+
+RTEMS Linker
+------------
+
+This package contains the RTEMS linker used to create dynamically loadable
+applications.
+
+To build download and install waf (http://code.google.com/p/waf/). Then:
+
+ $ waf configure build
+
+You will have a linker.
+
+License
+-------
+
+The linker code is licensed under the ISC license. Currently some libiberty
+code is present in the libiberty directory which is GPL. In time this code will
+be removed.
diff --git a/linkers/SimpleIni.h b/linkers/SimpleIni.h
new file mode 100644
index 0000000..fd37c4b
--- /dev/null
+++ b/linkers/SimpleIni.h
@@ -0,0 +1,3385 @@
+/** @mainpage
+
+ <table>
+ <tr><th>Library <td>SimpleIni
+ <tr><th>File <td>SimpleIni.h
+ <tr><th>Author <td>Brodie Thiesfield [code at jellycan dot com]
+ <tr><th>Source <td>https://github.com/brofield/simpleini
+ <tr><th>Version <td>4.17
+ </table>
+
+ Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation.
+
+ @section intro INTRODUCTION
+
+ This component allows an INI-style configuration file to be used on both
+ Windows and Linux/Unix. It is fast, simple and source code using this
+ component will compile unchanged on either OS.
+
+
+ @section features FEATURES
+
+ - MIT Licence allows free use in all software (including GPL and commercial)
+ - multi-platform (Windows 95/98/ME/NT/2K/XP/2003, Windows CE, Linux, Unix)
+ - loading and saving of INI-style configuration files
+ - configuration files can have any newline format on all platforms
+ - liberal acceptance of file format
+ - key/values with no section
+ - removal of whitespace around sections, keys and values
+ - support for multi-line values (values with embedded newline characters)
+ - optional support for multiple keys with the same name
+ - optional case-insensitive sections and keys (for ASCII characters only)
+ - saves files with sections and keys in the same order as they were loaded
+ - preserves comments on the file, section and keys where possible.
+ - supports both char or wchar_t programming interfaces
+ - supports both MBCS (system locale) and UTF-8 file encodings
+ - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file
+ - support for non-ASCII characters in section, keys, values and comments
+ - support for non-standard character types or file encodings
+ via user-written converter classes
+ - support for adding/modifying values programmatically
+ - compiles cleanly in the following compilers:
+ - Windows/VC6 (warning level 3)
+ - Windows/VC.NET 2003 (warning level 4)
+ - Windows/VC 2005 (warning level 4)
+ - Linux/gcc (-Wall)
+
+
+ @section usage USAGE SUMMARY
+
+ -# Define the appropriate symbol for the converter you wish to use and
+ include the SimpleIni.h header file. If no specific converter is defined
+ then the default converter is used. The default conversion mode uses
+ SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other
+ platforms. If you are using ICU then SI_CONVERT_ICU is supported on all
+ platforms.
+ -# Declare an instance the appropriate class. Note that the following
+ definitions are just shortcuts for commonly used types. Other types
+ (PRUnichar, unsigned short, unsigned char) are also possible.
+ <table>
+ <tr><th>Interface <th>Case-sensitive <th>Load UTF-8 <th>Load MBCS <th>Typedef
+ <tr><th>SI_CONVERT_GENERIC
+ <tr><td>char <td>No <td>Yes <td>Yes #1 <td>CSimpleIniA
+ <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
+ <tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
+ <tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
+ <tr><th>SI_CONVERT_WIN32
+ <tr><td>char <td>No <td>No #2 <td>Yes <td>CSimpleIniA
+ <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
+ <tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
+ <tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
+ <tr><th>SI_CONVERT_ICU
+ <tr><td>char <td>No <td>Yes <td>Yes <td>CSimpleIniA
+ <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
+ <tr><td>UChar <td>No <td>Yes <td>Yes <td>CSimpleIniW
+ <tr><td>UChar <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
+ </table>
+ #1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.<br>
+ #2 Only affects Windows. On Windows this uses MBCS functions and
+ so may fold case incorrectly leading to uncertain results.
+ -# Call LoadData() or LoadFile() to load and parse the INI configuration file
+ -# Access and modify the data of the file using the following functions
+ <table>
+ <tr><td>GetAllSections <td>Return all section names
+ <tr><td>GetAllKeys <td>Return all key names within a section
+ <tr><td>GetAllValues <td>Return all values within a section & key
+ <tr><td>GetSection <td>Return all key names and values in a section
+ <tr><td>GetSectionSize <td>Return the number of keys in a section
+ <tr><td>GetValue <td>Return a value for a section & key
+ <tr><td>SetValue <td>Add or update a value for a section & key
+ <tr><td>Delete <td>Remove a section, or a key from a section
+ </table>
+ -# Call Save() or SaveFile() to save the INI configuration data
+
+ @section iostreams IO STREAMS
+
+ SimpleIni supports reading from and writing to STL IO streams. Enable this
+ by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header
+ file. Ensure that if the streams are backed by a file (e.g. ifstream or
+ ofstream) then the flag ios_base::binary has been used when the file was
+ opened.
+
+ @section multiline MULTI-LINE VALUES
+
+ Values that span multiple lines are created using the following format.
+
+ <pre>
+ key = <<<ENDTAG
+ .... multiline value ....
+ ENDTAG
+ </pre>
+
+ Note the following:
+ - The text used for ENDTAG can be anything and is used to find
+ where the multi-line text ends.
+ - The newline after ENDTAG in the start tag, and the newline
+ before ENDTAG in the end tag is not included in the data value.
+ - The ending tag must be on it's own line with no whitespace before
+ or after it.
+ - The multi-line value is modified at load so that each line in the value
+ is delimited by a single '\\n' character on all platforms. At save time
+ it will be converted into the newline format used by the current
+ platform.
+
+ @section comments COMMENTS
+
+ Comments are preserved in the file within the following restrictions:
+ - Every file may have a single "file comment". It must start with the
+ first character in the file, and will end with the first non-comment
+ line in the file.
+ - Every section may have a single "section comment". It will start
+ with the first comment line following the file comment, or the last
+ data entry. It ends at the beginning of the section.
+ - Every key may have a single "key comment". This comment will start
+ with the first comment line following the section start, or the file
+ comment if there is no section name.
+ - Comments are set at the time that the file, section or key is first
+ created. The only way to modify a comment on a section or a key is to
+ delete that entry and recreate it with the new comment. There is no
+ way to change the file comment.
+
+ @section save SAVE ORDER
+
+ The sections and keys are written out in the same order as they were
+ read in from the file. Sections and keys added to the data after the
+ file has been loaded will be added to the end of the file when it is
+ written. There is no way to specify the location of a section or key
+ other than in first-created, first-saved order.
+
+ @section notes NOTES
+
+ - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
+ Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
+ - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
+ - When using SI_CONVERT_ICU, ICU header files must be on the include
+ path and icuuc.lib must be linked in.
+ - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
+ you should use SI_CONVERT_GENERIC.
+ - The collation (sorting) order used for sections and keys returned from
+ iterators is NOT DEFINED. If collation order of the text is important
+ then it should be done yourself by either supplying a replacement
+ SI_STRLESS class, or by sorting the strings external to this library.
+ - Usage of the <mbstring.h> header on Windows can be disabled by defining
+ SI_NO_MBCS. This is defined automatically on Windows CE platforms.
+
+ @section contrib CONTRIBUTIONS
+
+ - 2010/05/03: Tobias Gehrig: added GetDoubleValue()
+
+ @section licence MIT LICENCE
+
+ The licence text below is the boilerplate "MIT Licence" used from:
+ http://www.opensource.org/licenses/mit-license.php
+
+ Copyright (c) 2006-2012, Brodie Thiesfield
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in 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:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ 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 AUTHORS 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 IN THE SOFTWARE.
+*/
+
+#ifndef INCLUDED_SimpleIni_h
+#define INCLUDED_SimpleIni_h
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+// Disable these warnings in MSVC:
+// 4127 "conditional expression is constant" as the conversion classes trigger
+// it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
+// be optimized away in a release build.
+// 4503 'insert' : decorated name length exceeded, name was truncated
+// 4702 "unreachable code" as the MS STL header causes it in release mode.
+// Again, the code causing the warning will be cleaned up by the compiler.
+// 4786 "identifier truncated to 256 characters" as this is thrown hundreds
+// of times VC6 as soon as STL is used.
+#ifdef _MSC_VER
+# pragma warning (push)
+# pragma warning (disable: 4127 4503 4702 4786)
+#endif
+
+#include <cstring>
+#include <string>
+#include <map>
+#include <list>
+#include <algorithm>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef SI_SUPPORT_IOSTREAMS
+# include <iostream>
+#endif // SI_SUPPORT_IOSTREAMS
+
+#ifdef _DEBUG
+# ifndef assert
+# include <cassert>
+# endif
+# define SI_ASSERT(x) assert(x)
+#else
+# define SI_ASSERT(x)
+#endif
+
+enum SI_Error {
+ SI_OK = 0, //!< No error
+ SI_UPDATED = 1, //!< An existing value was updated
+ SI_INSERTED = 2, //!< A new value was inserted
+
+ // note: test for any error with (retval < 0)
+ SI_FAIL = -1, //!< Generic failure
+ SI_NOMEM = -2, //!< Out of memory error
+ SI_FILE = -3 //!< File error (see errno for detail error)
+};
+
+#define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
+
+#ifdef _WIN32
+# define SI_NEWLINE_A "\r\n"
+# define SI_NEWLINE_W L"\r\n"
+#else // !_WIN32
+# define SI_NEWLINE_A "\n"
+# define SI_NEWLINE_W L"\n"
+#endif // _WIN32
+
+#if defined(SI_CONVERT_ICU)
+# include <unicode/ustring.h>
+#endif
+
+#if defined(_WIN32)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T wchar_t
+#elif defined(SI_CONVERT_ICU)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T UChar
+#endif
+
+
+// ---------------------------------------------------------------------------
+// MAIN TEMPLATE CLASS
+// ---------------------------------------------------------------------------
+
+/** Simple INI file reader.
+
+ This can be instantiated with the choice of unicode or native characterset,
+ and case sensitive or insensitive comparisons of section and key names.
+ The supported combinations are pre-defined with the following typedefs:
+
+ <table>
+ <tr><th>Interface <th>Case-sensitive <th>Typedef
+ <tr><td>char <td>No <td>CSimpleIniA
+ <tr><td>char <td>Yes <td>CSimpleIniCaseA
+ <tr><td>wchar_t <td>No <td>CSimpleIniW
+ <tr><td>wchar_t <td>Yes <td>CSimpleIniCaseW
+ </table>
+
+ Note that using other types for the SI_CHAR is supported. For instance,
+ unsigned char, unsigned short, etc. Note that where the alternative type
+ is a different size to char/wchar_t you may need to supply new helper
+ classes for SI_STRLESS and SI_CONVERTER.
+ */
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+class CSimpleIniTempl
+{
+public:
+ typedef SI_CHAR SI_CHAR_T;
+
+ /** key entry */
+ struct Entry {
+ const SI_CHAR * pItem;
+ const SI_CHAR * pComment;
+ int nOrder;
+
+ Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0)
+ : pItem(a_pszItem)
+ , pComment(NULL)
+ , nOrder(a_nOrder)
+ { }
+ Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder)
+ : pItem(a_pszItem)
+ , pComment(a_pszComment)
+ , nOrder(a_nOrder)
+ { }
+ Entry(const Entry & rhs) { operator=(rhs); }
+ Entry & operator=(const Entry & rhs) {
+ pItem = rhs.pItem;
+ pComment = rhs.pComment;
+ nOrder = rhs.nOrder;
+ return *this;
+ }
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+ /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */
+ bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); }
+ bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); }
+#endif
+
+ /** Strict less ordering by name of key only */
+ struct KeyOrder : std::binary_function<Entry, Entry, bool> {
+ bool operator()(const Entry & lhs, const Entry & rhs) const {
+ const static SI_STRLESS isLess = SI_STRLESS();
+ return isLess(lhs.pItem, rhs.pItem);
+ }
+ };
+
+ /** Strict less ordering by order, and then name of key */
+ struct LoadOrder : std::binary_function<Entry, Entry, bool> {
+ bool operator()(const Entry & lhs, const Entry & rhs) const {
+ if (lhs.nOrder != rhs.nOrder) {
+ return lhs.nOrder < rhs.nOrder;
+ }
+ return KeyOrder()(lhs.pItem, rhs.pItem);
+ }
+ };
+ };
+
+ /** map keys to values */
+ typedef std::multimap<Entry,const SI_CHAR *,typename Entry::KeyOrder> TKeyVal;
+
+ /** map sections to key/value map */
+ typedef std::map<Entry,TKeyVal,typename Entry::KeyOrder> TSection;
+
+ /** set of dependent string pointers. Note that these pointers are
+ dependent on memory owned by CSimpleIni.
+ */
+ typedef std::list<Entry> TNamesDepend;
+
+ /** interface definition for the OutputWriter object to pass to Save()
+ in order to output the INI file data.
+ */
+ class OutputWriter {
+ public:
+ OutputWriter() { }
+ virtual ~OutputWriter() { }
+ virtual void Write(const char * a_pBuf) = 0;
+ private:
+ OutputWriter(const OutputWriter &); // disable
+ OutputWriter & operator=(const OutputWriter &); // disable
+ };
+
+ /** OutputWriter class to write the INI data to a file */
+ class FileWriter : public OutputWriter {
+ FILE * m_file;
+ public:
+ FileWriter(FILE * a_file) : m_file(a_file) { }
+ void Write(const char * a_pBuf) {
+ fputs(a_pBuf, m_file);
+ }
+ private:
+ FileWriter(const FileWriter &); // disable
+ FileWriter & operator=(const FileWriter &); // disable
+ };
+
+ /** OutputWriter class to write the INI data to a string */
+ class StringWriter : public OutputWriter {
+ std::string & m_string;
+ public:
+ StringWriter(std::string & a_string) : m_string(a_string) { }
+ void Write(const char * a_pBuf) {
+ m_string.append(a_pBuf);
+ }
+ private:
+ StringWriter(const StringWriter &); // disable
+ StringWriter & operator=(const StringWriter &); // disable
+ };
+
+#ifdef SI_SUPPORT_IOSTREAMS
+ /** OutputWriter class to write the INI data to an ostream */
+ class StreamWriter : public OutputWriter {
+ std::ostream & m_ostream;
+ public:
+ StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { }
+ void Write(const char * a_pBuf) {
+ m_ostream << a_pBuf;
+ }
+ private:
+ StreamWriter(const StreamWriter &); // disable
+ StreamWriter & operator=(const StreamWriter &); // disable
+ };
+#endif // SI_SUPPORT_IOSTREAMS
+
+ /** Characterset conversion utility class to convert strings to the
+ same format as is used for the storage.
+ */
+ class Converter : private SI_CONVERTER {
+ public:
+ Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
+ m_scratch.resize(1024);
+ }
+ Converter(const Converter & rhs) { operator=(rhs); }
+ Converter & operator=(const Converter & rhs) {
+ m_scratch = rhs.m_scratch;
+ return *this;
+ }
+ bool ConvertToStore(const SI_CHAR * a_pszString) {
+ size_t uLen = SI_CONVERTER::SizeToStore(a_pszString);
+ if (uLen == (size_t)(-1)) {
+ return false;
+ }
+ while (uLen > m_scratch.size()) {
+ m_scratch.resize(m_scratch.size() * 2);
+ }
+ return SI_CONVERTER::ConvertToStore(
+ a_pszString,
+ const_cast<char*>(m_scratch.data()),
+ m_scratch.size());
+ }
+ const char * Data() { return m_scratch.data(); }
+ private:
+ std::string m_scratch;
+ };
+
+public:
+ /*-----------------------------------------------------------------------*/
+
+ /** Default constructor.
+
+ @param a_bIsUtf8 See the method SetUnicode() for details.
+ @param a_bMultiKey See the method SetMultiKey() for details.
+ @param a_bMultiLine See the method SetMultiLine() for details.
+ */
+ CSimpleIniTempl(
+ bool a_bIsUtf8 = false,
+ bool a_bMultiKey = false,
+ bool a_bMultiLine = false
+ );
+
+ /** Destructor */
+ ~CSimpleIniTempl();
+
+ /** Deallocate all memory stored by this object */
+ void Reset();
+
+ /** Has any data been loaded */
+ bool IsEmpty() const { return m_data.empty(); }
+
+ /*-----------------------------------------------------------------------*/
+ /** @{ @name Settings */
+
+ /** Set the storage format of the INI data. This affects both the loading
+ and saving of the INI data using all of the Load/Save API functions.
+ This value cannot be changed after any INI data has been loaded.
+
+ If the file is not set to Unicode (UTF-8), then the data encoding is
+ assumed to be the OS native encoding. This encoding is the system
+ locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP.
+ If the storage format is set to Unicode then the file will be loaded
+ as UTF-8 encoded data regardless of the native file encoding. If
+ SI_CHAR == char then all of the char* parameters take and return UTF-8
+ encoded data regardless of the system locale.
+
+ \param a_bIsUtf8 Assume UTF-8 encoding for the source?
+ */
+ void SetUnicode(bool a_bIsUtf8 = true) {
+ if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8;
+ }
+
+ /** Get the storage format of the INI data. */
+ bool IsUnicode() const { return m_bStoreIsUtf8; }
+
+ /** Should multiple identical keys be permitted in the file. If set to false
+ then the last value encountered will be used as the value of the key.
+ If set to true, then all values will be available to be queried. For
+ example, with the following input:
+
+ <pre>
+ [section]
+ test=value1
+ test=value2
+ </pre>
+
+ Then with SetMultiKey(true), both of the values "value1" and "value2"
+ will be returned for the key test. If SetMultiKey(false) is used, then
+ the value for "test" will only be "value2". This value may be changed
+ at any time.
+
+ \param a_bAllowMultiKey Allow multi-keys in the source?
+ */
+ void SetMultiKey(bool a_bAllowMultiKey = true) {
+ m_bAllowMultiKey = a_bAllowMultiKey;
+ }
+
+ /** Get the storage format of the INI data. */
+ bool IsMultiKey() const { return m_bAllowMultiKey; }
+
+ /** Should data values be permitted to span multiple lines in the file. If
+ set to false then the multi-line construct <<<TAG as a value will be
+ returned as is instead of loading the data. This value may be changed
+ at any time.
+
+ \param a_bAllowMultiLine Allow multi-line values in the source?
+ */
+ void SetMultiLine(bool a_bAllowMultiLine = true) {
+ m_bAllowMultiLine = a_bAllowMultiLine;
+ }
+
+ /** Query the status of multi-line data */
+ bool IsMultiLine() const { return m_bAllowMultiLine; }
+
+ /** Should spaces be added around the equals sign when writing key/value
+ pairs out. When true, the result will be "key = value". When false,
+ the result will be "key=value". This value may be changed at any time.
+
+ \param a_bSpaces Add spaces around the equals sign?
+ */
+ void SetSpaces(bool a_bSpaces = true) {
+ m_bSpaces = a_bSpaces;
+ }
+
+ /** Query the status of spaces output */
+ bool UsingSpaces() const { return m_bSpaces; }
+
+ /*-----------------------------------------------------------------------*/
+ /** @}
+ @{ @name Loading INI Data */
+
+ /** Load an INI file from disk into memory
+
+ @param a_pszFile Path of the file to be loaded. This will be passed
+ to fopen() and so must be a valid path for the
+ current platform.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error LoadFile(
+ const char * a_pszFile
+ );
+
+#ifdef SI_HAS_WIDE_FILE
+ /** Load an INI file from disk into memory
+
+ @param a_pwszFile Path of the file to be loaded in UTF-16.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error LoadFile(
+ const SI_WCHAR_T * a_pwszFile
+ );
+#endif // SI_HAS_WIDE_FILE
+
+ /** Load the file from a file pointer.
+
+ @param a_fpFile Valid file pointer to read the file data from. The
+ file will be read until end of file.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error LoadFile(
+ FILE * a_fpFile
+ );
+
+#ifdef SI_SUPPORT_IOSTREAMS
+ /** Load INI file data from an istream.
+
+ @param a_istream Stream to read from
+
+ @return SI_Error See error definitions
+ */
+ SI_Error LoadData(
+ std::istream & a_istream
+ );
+#endif // SI_SUPPORT_IOSTREAMS
+
+ /** Load INI file data direct from a std::string
+
+ @param a_strData Data to be loaded
+
+ @return SI_Error See error definitions
+ */
+ SI_Error LoadData(const std::string & a_strData) {
+ return LoadData(a_strData.c_str(), a_strData.size());
+ }
+
+ /** Load INI file data direct from memory
+
+ @param a_pData Data to be loaded
+ @param a_uDataLen Length of the data in bytes
+
+ @return SI_Error See error definitions
+ */
+ SI_Error LoadData(
+ const char * a_pData,
+ size_t a_uDataLen
+ );
+
+ /*-----------------------------------------------------------------------*/
+ /** @}
+ @{ @name Saving INI Data */
+
+ /** Save an INI file from memory to disk
+
+ @param a_pszFile Path of the file to be saved. This will be passed
+ to fopen() and so must be a valid path for the
+ current platform.
+
+ @param a_bAddSignature Prepend the UTF-8 BOM if the output data is
+ in UTF-8 format. If it is not UTF-8 then
+ this parameter is ignored.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error SaveFile(
+ const char * a_pszFile,
+ bool a_bAddSignature = true
+ ) const;
+
+#ifdef SI_HAS_WIDE_FILE
+ /** Save an INI file from memory to disk
+
+ @param a_pwszFile Path of the file to be saved in UTF-16.
+
+ @param a_bAddSignature Prepend the UTF-8 BOM if the output data is
+ in UTF-8 format. If it is not UTF-8 then
+ this parameter is ignored.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error SaveFile(
+ const SI_WCHAR_T * a_pwszFile,
+ bool a_bAddSignature = true
+ ) const;
+#endif // _WIN32
+
+ /** Save the INI data to a file. See Save() for details.
+
+ @param a_pFile Handle to a file. File should be opened for
+ binary output.
+
+ @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
+ UTF-8 format. If it is not UTF-8 then this value is
+ ignored. Do not set this to true if anything has
+ already been written to the file.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error SaveFile(
+ FILE * a_pFile,
+ bool a_bAddSignature = false
+ ) const;
+
+ /** Save the INI data. The data will be written to the output device
+ in a format appropriate to the current data, selected by:
+
+ <table>
+ <tr><th>SI_CHAR <th>FORMAT
+ <tr><td>char <td>same format as when loaded (MBCS or UTF-8)
+ <tr><td>wchar_t <td>UTF-8
+ <tr><td>other <td>UTF-8
+ </table>
+
+ Note that comments from the original data is preserved as per the
+ documentation on comments. The order of the sections and values
+ from the original file will be preserved.
+
+ Any data prepended or appended to the output device must use the the
+ same format (MBCS or UTF-8). You may use the GetConverter() method to
+ convert text to the correct format regardless of the output format
+ being used by SimpleIni.
+
+ To add a BOM to UTF-8 data, write it out manually at the very beginning
+ like is done in SaveFile when a_bUseBOM is true.
+
+ @param a_oOutput Output writer to write the data to.
+
+ @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
+ UTF-8 format. If it is not UTF-8 then this value is
+ ignored. Do not set this to true if anything has
+ already been written to the OutputWriter.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error Save(
+ OutputWriter & a_oOutput,
+ bool a_bAddSignature = false
+ ) const;
+
+#ifdef SI_SUPPORT_IOSTREAMS
+ /** Save the INI data to an ostream. See Save() for details.
+
+ @param a_ostream String to have the INI data appended to.
+
+ @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
+ UTF-8 format. If it is not UTF-8 then this value is
+ ignored. Do not set this to true if anything has
+ already been written to the stream.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error Save(
+ std::ostream & a_ostream,
+ bool a_bAddSignature = false
+ ) const
+ {
+ StreamWriter writer(a_ostream);
+ return Save(writer, a_bAddSignature);
+ }
+#endif // SI_SUPPORT_IOSTREAMS
+
+ /** Append the INI data to a string. See Save() for details.
+
+ @param a_sBuffer String to have the INI data appended to.
+
+ @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
+ UTF-8 format. If it is not UTF-8 then this value is
+ ignored. Do not set this to true if anything has
+ already been written to the string.
+
+ @return SI_Error See error definitions
+ */
+ SI_Error Save(
+ std::string & a_sBuffer,
+ bool a_bAddSignature = false
+ ) const
+ {
+ StringWriter writer(a_sBuffer);
+ return Save(writer, a_bAddSignature);
+ }
+
+ /*-----------------------------------------------------------------------*/
+ /** @}
+ @{ @name Accessing INI Data */
+
+ /** Retrieve all section names. The list is returned as an STL vector of
+ names and can be iterated or searched as necessary. Note that the
+ sort order of the returned strings is NOT DEFINED. You can sort
+ the names into the load order if desired. Search this file for ".sort"
+ for an example.
+
+ NOTE! This structure contains only pointers to strings. The actual
+ string data is stored in memory owned by CSimpleIni. Ensure that the
+ CSimpleIni object is not destroyed or Reset() while these pointers
+ are in use!
+
+ @param a_names Vector that will receive all of the section
+ names. See note above!
+ */
+ void GetAllSections(
+ TNamesDepend & a_names
+ ) const;
+
+ /** Retrieve all unique key names in a section. The sort order of the
+ returned strings is NOT DEFINED. You can sort the names into the load
+ order if desired. Search this file for ".sort" for an example. Only
+ unique key names are returned.
+
+ NOTE! This structure contains only pointers to strings. The actual
+ string data is stored in memory owned by CSimpleIni. Ensure that the
+ CSimpleIni object is not destroyed or Reset() while these strings
+ are in use!
+
+ @param a_pSection Section to request data for
+ @param a_names List that will receive all of the key
+ names. See note above!
+
+ @return true Section was found.
+ @return false Matching section was not found.
+ */
+ bool GetAllKeys(
+ const SI_CHAR * a_pSection,
+ TNamesDepend & a_names
+ ) const;
+
+ /** Retrieve all values for a specific key. This method can be used when
+ multiple keys are both enabled and disabled. Note that the sort order
+ of the returned strings is NOT DEFINED. You can sort the names into
+ the load order if desired. Search this file for ".sort" for an example.
+
+ NOTE! The returned values are pointers to string data stored in memory
+ owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed
+ or Reset while you are using this pointer!
+
+ @param a_pSection Section to search
+ @param a_pKey Key to search for
+ @param a_values List to return if the key is not found
+
+ @return true Key was found.
+ @return false Matching section/key was not found.
+ */
+ bool GetAllValues(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ TNamesDepend & a_values
+ ) const;
+
+ /** Query the number of keys in a specific section. Note that if multiple
+ keys are enabled, then this value may be different to the number of
+ keys returned by GetAllKeys.
+
+ @param a_pSection Section to request data for
+
+ @return -1 Section does not exist in the file
+ @return >=0 Number of keys in the section
+ */
+ int GetSectionSize(
+ const SI_CHAR * a_pSection
+ ) const;
+
+ /** Retrieve all key and value pairs for a section. The data is returned
+ as a pointer to an STL map and can be iterated or searched as
+ desired. Note that multiple entries for the same key may exist when
+ multiple keys have been enabled.
+
+ NOTE! This structure contains only pointers to strings. The actual
+ string data is stored in memory owned by CSimpleIni. Ensure that the
+ CSimpleIni object is not destroyed or Reset() while these strings
+ are in use!
+
+ @param a_pSection Name of the section to return
+ @return boolean Was a section matching the supplied
+ name found.
+ */
+ const TKeyVal * GetSection(
+ const SI_CHAR * a_pSection
+ ) const;
+
+ /** Retrieve the value for a specific key. If multiple keys are enabled
+ (see SetMultiKey) then only the first value associated with that key
+ will be returned, see GetAllValues for getting all values with multikey.
+
+ NOTE! The returned value is a pointer to string data stored in memory
+ owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed
+ or Reset while you are using this pointer!
+
+ @param a_pSection Section to search
+ @param a_pKey Key to search for
+ @param a_pDefault Value to return if the key is not found
+ @param a_pHasMultiple Optionally receive notification of if there are
+ multiple entries for this key.
+
+ @return a_pDefault Key was not found in the section
+ @return other Value of the key
+ */
+ const SI_CHAR * GetValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ const SI_CHAR * a_pDefault = NULL,
+ bool * a_pHasMultiple = NULL
+ ) const;
+
+ /** Retrieve a numeric value for a specific key. If multiple keys are enabled
+ (see SetMultiKey) then only the first value associated with that key
+ will be returned, see GetAllValues for getting all values with multikey.
+
+ @param a_pSection Section to search
+ @param a_pKey Key to search for
+ @param a_nDefault Value to return if the key is not found
+ @param a_pHasMultiple Optionally receive notification of if there are
+ multiple entries for this key.
+
+ @return a_nDefault Key was not found in the section
+ @return other Value of the key
+ */
+ long GetLongValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ long a_nDefault = 0,
+ bool * a_pHasMultiple = NULL
+ ) const;
+
+ /** Retrieve a numeric value for a specific key. If multiple keys are enabled
+ (see SetMultiKey) then only the first value associated with that key
+ will be returned, see GetAllValues for getting all values with multikey.
+
+ @param a_pSection Section to search
+ @param a_pKey Key to search for
+ @param a_nDefault Value to return if the key is not found
+ @param a_pHasMultiple Optionally receive notification of if there are
+ multiple entries for this key.
+
+ @return a_nDefault Key was not found in the section
+ @return other Value of the key
+ */
+ double GetDoubleValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ double a_nDefault = 0,
+ bool * a_pHasMultiple = NULL
+ ) const;
+
+ /** Retrieve a boolean value for a specific key. If multiple keys are enabled
+ (see SetMultiKey) then only the first value associated with that key
+ will be returned, see GetAllValues for getting all values with multikey.
+
+ Strings starting with "t", "y", "on" or "1" are returned as logically true.
+ Strings starting with "f", "n", "of" or "0" are returned as logically false.
+ For all other values the default is returned. Character comparisons are
+ case-insensitive.
+
+ @param a_pSection Section to search
+ @param a_pKey Key to search for
+ @param a_bDefault Value to return if the key is not found
+ @param a_pHasMultiple Optionally receive notification of if there are
+ multiple entries for this key.
+
+ @return a_nDefault Key was not found in the section
+ @return other Value of the key
+ */
+ bool GetBoolValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ bool a_bDefault = false,
+ bool * a_pHasMultiple = NULL
+ ) const;
+
+ /** Add or update a section or value. This will always insert
+ when multiple keys are enabled.
+
+ @param a_pSection Section to add or update
+ @param a_pKey Key to add or update. Set to NULL to
+ create an empty section.
+ @param a_pValue Value to set. Set to NULL to create an
+ empty section.
+ @param a_pComment Comment to be associated with the section or the
+ key. If a_pKey is NULL then it will be associated
+ with the section, otherwise the key. Note that a
+ comment may be set ONLY when the section or key is
+ first created (i.e. when this function returns the
+ value SI_INSERTED). If you wish to create a section
+ with a comment then you need to create the section
+ separately to the key. The comment string must be
+ in full comment form already (have a comment
+ character starting every line).
+ @param a_bForceReplace Should all existing values in a multi-key INI
+ file be replaced with this entry. This option has
+ no effect if not using multi-key files. The
+ difference between Delete/SetValue and SetValue
+ with a_bForceReplace = true, is that the load
+ order and comment will be preserved this way.
+
+ @return SI_Error See error definitions
+ @return SI_UPDATED Value was updated
+ @return SI_INSERTED Value was inserted
+ */
+ SI_Error SetValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ const SI_CHAR * a_pValue,
+ const SI_CHAR * a_pComment = NULL,
+ bool a_bForceReplace = false
+ )
+ {
+ return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true);
+ }
+
+ /** Add or update a numeric value. This will always insert
+ when multiple keys are enabled.
+
+ @param a_pSection Section to add or update
+ @param a_pKey Key to add or update.
+ @param a_nValue Value to set.
+ @param a_pComment Comment to be associated with the key. See the
+ notes on SetValue() for comments.
+ @param a_bUseHex By default the value will be written to the file
+ in decimal format. Set this to true to write it
+ as hexadecimal.
+ @param a_bForceReplace Should all existing values in a multi-key INI
+ file be replaced with this entry. This option has
+ no effect if not using multi-key files. The
+ difference between Delete/SetLongValue and
+ SetLongValue with a_bForceReplace = true, is that
+ the load order and comment will be preserved this
+ way.
+
+ @return SI_Error See error definitions
+ @return SI_UPDATED Value was updated
+ @return SI_INSERTED Value was inserted
+ */
+ SI_Error SetLongValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ long a_nValue,
+ const SI_CHAR * a_pComment = NULL,
+ bool a_bUseHex = false,
+ bool a_bForceReplace = false
+ );
+
+ /** Add or update a double value. This will always insert
+ when multiple keys are enabled.
+
+ @param a_pSection Section to add or update
+ @param a_pKey Key to add or update.
+ @param a_nValue Value to set.
+ @param a_pComment Comment to be associated with the key. See the
+ notes on SetValue() for comments.
+ @param a_bForceReplace Should all existing values in a multi-key INI
+ file be replaced with this entry. This option has
+ no effect if not using multi-key files. The
+ difference between Delete/SetDoubleValue and
+ SetDoubleValue with a_bForceReplace = true, is that
+ the load order and comment will be preserved this
+ way.
+
+ @return SI_Error See error definitions
+ @return SI_UPDATED Value was updated
+ @return SI_INSERTED Value was inserted
+ */
+ SI_Error SetDoubleValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ double a_nValue,
+ const SI_CHAR * a_pComment = NULL,
+ bool a_bForceReplace = false
+ );
+
+ /** Add or update a boolean value. This will always insert
+ when multiple keys are enabled.
+
+ @param a_pSection Section to add or update
+ @param a_pKey Key to add or update.
+ @param a_bValue Value to set.
+ @param a_pComment Comment to be associated with the key. See the
+ notes on SetValue() for comments.
+ @param a_bForceReplace Should all existing values in a multi-key INI
+ file be replaced with this entry. This option has
+ no effect if not using multi-key files. The
+ difference between Delete/SetBoolValue and
+ SetBoolValue with a_bForceReplace = true, is that
+ the load order and comment will be preserved this
+ way.
+
+ @return SI_Error See error definitions
+ @return SI_UPDATED Value was updated
+ @return SI_INSERTED Value was inserted
+ */
+ SI_Error SetBoolValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ bool a_bValue,
+ const SI_CHAR * a_pComment = NULL,
+ bool a_bForceReplace = false
+ );
+
+ /** Delete an entire section, or a key from a section. Note that the
+ data returned by GetSection is invalid and must not be used after
+ anything has been deleted from that section using this method.
+ Note when multiple keys is enabled, this will delete all keys with
+ that name; there is no way to selectively delete individual key/values
+ in this situation.
+
+ @param a_pSection Section to delete key from, or if
+ a_pKey is NULL, the section to remove.
+ @param a_pKey Key to remove from the section. Set to
+ NULL to remove the entire section.
+ @param a_bRemoveEmpty If the section is empty after this key has
+ been deleted, should the empty section be
+ removed?
+
+ @return true Key or section was deleted.
+ @return false Key or section was not found.
+ */
+ bool Delete(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ bool a_bRemoveEmpty = false
+ );
+
+ /*-----------------------------------------------------------------------*/
+ /** @}
+ @{ @name Converter */
+
+ /** Return a conversion object to convert text to the same encoding
+ as is used by the Save(), SaveFile() and SaveString() functions.
+ Use this to prepare the strings that you wish to append or prepend
+ to the output INI data.
+ */
+ Converter GetConverter() const {
+ return Converter(m_bStoreIsUtf8);
+ }
+
+ /*-----------------------------------------------------------------------*/
+ /** @} */
+
+private:
+ // copying is not permitted
+ CSimpleIniTempl(const CSimpleIniTempl &); // disabled
+ CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled
+
+ /** Parse the data looking for a file comment and store it if found.
+ */
+ SI_Error FindFileComment(
+ SI_CHAR *& a_pData,
+ bool a_bCopyStrings
+ );
+
+ /** Parse the data looking for the next valid entry. The memory pointed to
+ by a_pData is modified by inserting NULL characters. The pointer is
+ updated to the current location in the block of text.
+ */
+ bool FindEntry(
+ SI_CHAR *& a_pData,
+ const SI_CHAR *& a_pSection,
+ const SI_CHAR *& a_pKey,
+ const SI_CHAR *& a_pVal,
+ const SI_CHAR *& a_pComment
+ ) const;
+
+ /** Add the section/key/value to our data.
+
+ @param a_pSection Section name. Sections will be created if they
+ don't already exist.
+ @param a_pKey Key name. May be NULL to create an empty section.
+ Existing entries will be updated. New entries will
+ be created.
+ @param a_pValue Value for the key.
+ @param a_pComment Comment to be associated with the section or the
+ key. If a_pKey is NULL then it will be associated
+ with the section, otherwise the key. This must be
+ a string in full comment form already (have a
+ comment character starting every line).
+ @param a_bForceReplace Should all existing values in a multi-key INI
+ file be replaced with this entry. This option has
+ no effect if not using multi-key files. The
+ difference between Delete/AddEntry and AddEntry
+ with a_bForceReplace = true, is that the load
+ order and comment will be preserved this way.
+ @param a_bCopyStrings Should copies of the strings be made or not.
+ If false then the pointers will be used as is.
+ */
+ SI_Error AddEntry(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ const SI_CHAR * a_pValue,
+ const SI_CHAR * a_pComment,
+ bool a_bForceReplace,
+ bool a_bCopyStrings
+ );
+
+ /** Is the supplied character a whitespace character? */
+ inline bool IsSpace(SI_CHAR ch) const {
+ return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
+ }
+
+ /** Does the supplied character start a comment line? */
+ inline bool IsComment(SI_CHAR ch) const {
+ return (ch == ';' || ch == '#');
+ }
+
+
+ /** Skip over a newline character (or characters) for either DOS or UNIX */
+ inline void SkipNewLine(SI_CHAR *& a_pData) const {
+ a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1;
+ }
+
+ /** Make a copy of the supplied string, replacing the original pointer */
+ SI_Error CopyString(const SI_CHAR *& a_pString);
+
+ /** Delete a string from the copied strings buffer if necessary */
+ void DeleteString(const SI_CHAR * a_pString);
+
+ /** Internal use of our string comparison function */
+ bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const {
+ const static SI_STRLESS isLess = SI_STRLESS();
+ return isLess(a_pLeft, a_pRight);
+ }
+
+ bool IsMultiLineTag(const SI_CHAR * a_pData) const;
+ bool IsMultiLineData(const SI_CHAR * a_pData) const;
+ bool LoadMultiLineText(
+ SI_CHAR *& a_pData,
+ const SI_CHAR *& a_pVal,
+ const SI_CHAR * a_pTagName,
+ bool a_bAllowBlankLinesInComment = false
+ ) const;
+ bool IsNewLineChar(SI_CHAR a_c) const;
+
+ bool OutputMultiLineText(
+ OutputWriter & a_oOutput,
+ Converter & a_oConverter,
+ const SI_CHAR * a_pText
+ ) const;
+
+private:
+ /** Copy of the INI file data in our character format. This will be
+ modified when parsed to have NULL characters added after all
+ interesting string entries. All of the string pointers to sections,
+ keys and values point into this block of memory.
+ */
+ SI_CHAR * m_pData;
+
+ /** Length of the data that we have stored. Used when deleting strings
+ to determine if the string is stored here or in the allocated string
+ buffer.
+ */
+ size_t m_uDataLen;
+
+ /** File comment for this data, if one exists. */
+ const SI_CHAR * m_pFileComment;
+
+ /** Parsed INI data. Section -> (Key -> Value). */
+ TSection m_data;
+
+ /** This vector stores allocated memory for copies of strings that have
+ been supplied after the file load. It will be empty unless SetValue()
+ has been called.
+ */
+ TNamesDepend m_strings;
+
+ /** Is the format of our datafile UTF-8 or MBCS? */
+ bool m_bStoreIsUtf8;
+
+ /** Are multiple values permitted for the same key? */
+ bool m_bAllowMultiKey;
+
+ /** Are data values permitted to span multiple lines? */
+ bool m_bAllowMultiLine;
+
+ /** Should spaces be written out surrounding the equals sign? */
+ bool m_bSpaces;
+
+ /** Next order value, used to ensure sections and keys are output in the
+ same order that they are loaded/added.
+ */
+ int m_nOrder;
+};
+
+// ---------------------------------------------------------------------------
+// IMPLEMENTATION
+// ---------------------------------------------------------------------------
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CSimpleIniTempl(
+ bool a_bIsUtf8,
+ bool a_bAllowMultiKey,
+ bool a_bAllowMultiLine
+ )
+ : m_pData(0)
+ , m_uDataLen(0)
+ , m_pFileComment(NULL)
+ , m_bStoreIsUtf8(a_bIsUtf8)
+ , m_bAllowMultiKey(a_bAllowMultiKey)
+ , m_bAllowMultiLine(a_bAllowMultiLine)
+ , m_bSpaces(true)
+ , m_nOrder(0)
+{ }
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::~CSimpleIniTempl()
+{
+ Reset();
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+void
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Reset()
+{
+ // remove all data
+ delete[] m_pData;
+ m_pData = NULL;
+ m_uDataLen = 0;
+ m_pFileComment = NULL;
+ if (!m_data.empty()) {
+ m_data.erase(m_data.begin(), m_data.end());
+ }
+
+ // remove all strings
+ if (!m_strings.empty()) {
+ typename TNamesDepend::iterator i = m_strings.begin();
+ for (; i != m_strings.end(); ++i) {
+ delete[] const_cast<SI_CHAR*>(i->pItem);
+ }
+ m_strings.erase(m_strings.begin(), m_strings.end());
+ }
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
+ const char * a_pszFile
+ )
+{
+ FILE * fp = NULL;
+#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
+ fopen_s(&fp, a_pszFile, "rb");
+#else // !__STDC_WANT_SECURE_LIB__
+ fp = fopen(a_pszFile, "rb");
+#endif // __STDC_WANT_SECURE_LIB__
+ if (!fp) {
+ return SI_FILE;
+ }
+ SI_Error rc = LoadFile(fp);
+ fclose(fp);
+ return rc;
+}
+
+#ifdef SI_HAS_WIDE_FILE
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
+ const SI_WCHAR_T * a_pwszFile
+ )
+{
+#ifdef _WIN32
+ FILE * fp = NULL;
+#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
+ _wfopen_s(&fp, a_pwszFile, L"rb");
+#else // !__STDC_WANT_SECURE_LIB__
+ fp = _wfopen(a_pwszFile, L"rb");
+#endif // __STDC_WANT_SECURE_LIB__
+ if (!fp) return SI_FILE;
+ SI_Error rc = LoadFile(fp);
+ fclose(fp);
+ return rc;
+#else // !_WIN32 (therefore SI_CONVERT_ICU)
+ char szFile[256];
+ u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
+ return LoadFile(szFile);
+#endif // _WIN32
+}
+#endif // SI_HAS_WIDE_FILE
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
+ FILE * a_fpFile
+ )
+{
+ // load the raw file data
+ int retval = fseek(a_fpFile, 0, SEEK_END);
+ if (retval != 0) {
+ return SI_FILE;
+ }
+ long lSize = ftell(a_fpFile);
+ if (lSize < 0) {
+ return SI_FILE;
+ }
+ if (lSize == 0) {
+ return SI_OK;
+ }
+
+ // allocate and ensure NULL terminated
+ char * pData = new char[lSize+1];
+ if (!pData) {
+ return SI_NOMEM;
+ }
+ pData[lSize] = 0;
+
+ // load data into buffer
+ fseek(a_fpFile, 0, SEEK_SET);
+ size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile);
+ if (uRead != (size_t) lSize) {
+ delete[] pData;
+ return SI_FILE;
+ }
+
+ // convert the raw data to unicode
+ SI_Error rc = LoadData(pData, uRead);
+ delete[] pData;
+ return rc;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadData(
+ const char * a_pData,
+ size_t a_uDataLen
+ )
+{
+ SI_CONVERTER converter(m_bStoreIsUtf8);
+
+ if (a_uDataLen == 0) {
+ return SI_OK;
+ }
+
+ // consume the UTF-8 BOM if it exists
+ if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
+ if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
+ a_pData += 3;
+ a_uDataLen -= 3;
+ }
+ }
+
+ // determine the length of the converted data
+ size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
+ if (uLen == (size_t)(-1)) {
+ return SI_FAIL;
+ }
+
+ // allocate memory for the data, ensure that there is a NULL
+ // terminator wherever the converted data ends
+ SI_CHAR * pData = new SI_CHAR[uLen+1];
+ if (!pData) {
+ return SI_NOMEM;
+ }
+ memset(pData, 0, sizeof(SI_CHAR)*(uLen+1));
+
+ // convert the data
+ if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
+ delete[] pData;
+ return SI_FAIL;
+ }
+
+ // parse it
+ const static SI_CHAR empty = 0;
+ SI_CHAR * pWork = pData;
+ const SI_CHAR * pSection = &empty;
+ const SI_CHAR * pItem = NULL;
+ const SI_CHAR * pVal = NULL;
+ const SI_CHAR * pComment = NULL;
+
+ // We copy the strings if we are loading data into this class when we
+ // already have stored some.
+ bool bCopyStrings = (m_pData != NULL);
+
+ // find a file comment if it exists, this is a comment that starts at the
+ // beginning of the file and continues until the first blank line.
+ SI_Error rc = FindFileComment(pWork, bCopyStrings);
+ if (rc < 0) return rc;
+
+ // add every entry in the file to the data table
+ while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
+ rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings);
+ if (rc < 0) return rc;
+ }
+
+ // store these strings if we didn't copy them
+ if (bCopyStrings) {
+ delete[] pData;
+ }
+ else {
+ m_pData = pData;
+ m_uDataLen = uLen+1;
+ }
+
+ return SI_OK;
+}
+
+#ifdef SI_SUPPORT_IOSTREAMS
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadData(
+ std::istream & a_istream
+ )
+{
+ std::string strData;
+ char szBuf[512];
+ do {
+ a_istream.get(szBuf, sizeof(szBuf), '\0');
+ strData.append(szBuf);
+ }
+ while (a_istream.good());
+ return LoadData(strData);
+}
+#endif // SI_SUPPORT_IOSTREAMS
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindFileComment(
+ SI_CHAR *& a_pData,
+ bool a_bCopyStrings
+ )
+{
+ // there can only be a single file comment
+ if (m_pFileComment) {
+ return SI_OK;
+ }
+
+ // Load the file comment as multi-line text, this will modify all of
+ // the newline characters to be single \n chars
+ if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) {
+ return SI_OK;
+ }
+
+ // copy the string if necessary
+ if (a_bCopyStrings) {
+ SI_Error rc = CopyString(m_pFileComment);
+ if (rc < 0) return rc;
+ }
+
+ return SI_OK;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
+ SI_CHAR *& a_pData,
+ const SI_CHAR *& a_pSection,
+ const SI_CHAR *& a_pKey,
+ const SI_CHAR *& a_pVal,
+ const SI_CHAR *& a_pComment
+ ) const
+{
+ a_pComment = NULL;
+
+ SI_CHAR * pTrail = NULL;
+ while (*a_pData) {
+ // skip spaces and empty lines
+ while (*a_pData && IsSpace(*a_pData)) {
+ ++a_pData;
+ }
+ if (!*a_pData) {
+ break;
+ }
+
+ // skip processing of comment lines but keep a pointer to
+ // the start of the comment.
+ if (IsComment(*a_pData)) {
+ LoadMultiLineText(a_pData, a_pComment, NULL, true);
+ continue;
+ }
+
+ // process section names
+ if (*a_pData == '[') {
+ // skip leading spaces
+ ++a_pData;
+ while (*a_pData && IsSpace(*a_pData)) {
+ ++a_pData;
+ }
+
+ // find the end of the section name (it may contain spaces)
+ // and convert it to lowercase as necessary
+ a_pSection = a_pData;
+ while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) {
+ ++a_pData;
+ }
+
+ // if it's an invalid line, just skip it
+ if (*a_pData != ']') {
+ continue;
+ }
+
+ // remove trailing spaces from the section
+ pTrail = a_pData - 1;
+ while (pTrail >= a_pSection && IsSpace(*pTrail)) {
+ --pTrail;
+ }
+ ++pTrail;
+ *pTrail = 0;
+
+ // skip to the end of the line
+ ++a_pData; // safe as checked that it == ']' above
+ while (*a_pData && !IsNewLineChar(*a_pData)) {
+ ++a_pData;
+ }
+
+ a_pKey = NULL;
+ a_pVal = NULL;
+ return true;
+ }
+
+ // find the end of the key name (it may contain spaces)
+ // and convert it to lowercase as necessary
+ a_pKey = a_pData;
+ while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
+ ++a_pData;
+ }
+
+ // if it's an invalid line, just skip it
+ if (*a_pData != '=') {
+ continue;
+ }
+
+ // empty keys are invalid
+ if (a_pKey == a_pData) {
+ while (*a_pData && !IsNewLineChar(*a_pData)) {
+ ++a_pData;
+ }
+ continue;
+ }
+
+ // remove trailing spaces from the key
+ pTrail = a_pData - 1;
+ while (pTrail >= a_pKey && IsSpace(*pTrail)) {
+ --pTrail;
+ }
+ ++pTrail;
+ *pTrail = 0;
+
+ // skip leading whitespace on the value
+ ++a_pData; // safe as checked that it == '=' above
+ while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
+ ++a_pData;
+ }
+
+ // find the end of the value which is the end of this line
+ a_pVal = a_pData;
+ while (*a_pData && !IsNewLineChar(*a_pData)) {
+ ++a_pData;
+ }
+
+ // remove trailing spaces from the value
+ pTrail = a_pData - 1;
+ if (*a_pData) { // prepare for the next round
+ SkipNewLine(a_pData);
+ }
+ while (pTrail >= a_pVal && IsSpace(*pTrail)) {
+ --pTrail;
+ }
+ ++pTrail;
+ *pTrail = 0;
+
+ // check for multi-line entries
+ if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
+ // skip the "<<<" to get the tag that will end the multiline
+ const SI_CHAR * pTagName = a_pVal + 3;
+ return LoadMultiLineText(a_pData, a_pVal, pTagName);
+ }
+
+ // return the standard entry
+ return true;
+ }
+
+ return false;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineTag(
+ const SI_CHAR * a_pVal
+ ) const
+{
+ // check for the "<<<" prefix for a multi-line entry
+ if (*a_pVal++ != '<') return false;
+ if (*a_pVal++ != '<') return false;
+ if (*a_pVal++ != '<') return false;
+ return true;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineData(
+ const SI_CHAR * a_pData
+ ) const
+{
+ // data is multi-line if it has any of the following features:
+ // * whitespace prefix
+ // * embedded newlines
+ // * whitespace suffix
+
+ // empty string
+ if (!*a_pData) {
+ return false;
+ }
+
+ // check for prefix
+ if (IsSpace(*a_pData)) {
+ return true;
+ }
+
+ // embedded newlines
+ while (*a_pData) {
+ if (IsNewLineChar(*a_pData)) {
+ return true;
+ }
+ ++a_pData;
+ }
+
+ // check for suffix
+ if (IsSpace(*--a_pData)) {
+ return true;
+ }
+
+ return false;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsNewLineChar(
+ SI_CHAR a_c
+ ) const
+{
+ return (a_c == '\n' || a_c == '\r');
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadMultiLineText(
+ SI_CHAR *& a_pData,
+ const SI_CHAR *& a_pVal,
+ const SI_CHAR * a_pTagName,
+ bool a_bAllowBlankLinesInComment
+ ) const
+{
+ // we modify this data to strip all newlines down to a single '\n'
+ // character. This means that on Windows we need to strip out some
+ // characters which will make the data shorter.
+ // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become
+ // LINE1-LINE1\nLINE2-LINE2\0
+ // The pDataLine entry is the pointer to the location in memory that
+ // the current line needs to start to run following the existing one.
+ // This may be the same as pCurrLine in which case no move is needed.
+ SI_CHAR * pDataLine = a_pData;
+ SI_CHAR * pCurrLine;
+
+ // value starts at the current line
+ a_pVal = a_pData;
+
+ // find the end tag. This tag must start in column 1 and be
+ // followed by a newline. No whitespace removal is done while
+ // searching for this tag.
+ SI_CHAR cEndOfLineChar = *a_pData;
+ for(;;) {
+ // if we are loading comments then we need a comment character as
+ // the first character on every line
+ if (!a_pTagName && !IsComment(*a_pData)) {
+ // if we aren't allowing blank lines then we're done
+ if (!a_bAllowBlankLinesInComment) {
+ break;
+ }
+
+ // if we are allowing blank lines then we only include them
+ // in this comment if another comment follows, so read ahead
+ // to find out.
+ SI_CHAR * pCurr = a_pData;
+ int nNewLines = 0;
+ while (IsSpace(*pCurr)) {
+ if (IsNewLineChar(*pCurr)) {
+ ++nNewLines;
+ SkipNewLine(pCurr);
+ }
+ else {
+ ++pCurr;
+ }
+ }
+
+ // we have a comment, add the blank lines to the output
+ // and continue processing from here
+ if (IsComment(*pCurr)) {
+ for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n';
+ a_pData = pCurr;
+ continue;
+ }
+
+ // the comment ends here
+ break;
+ }
+
+ // find the end of this line
+ pCurrLine = a_pData;
+ while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
+
+ // move this line down to the location that it should be if necessary
+ if (pDataLine < pCurrLine) {
+ size_t nLen = (size_t) (a_pData - pCurrLine);
+ memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR));
+ pDataLine[nLen] = '\0';
+ }
+
+ // end the line with a NULL
+ cEndOfLineChar = *a_pData;
+ *a_pData = 0;
+
+ // if are looking for a tag then do the check now. This is done before
+ // checking for end of the data, so that if we have the tag at the end
+ // of the data then the tag is removed correctly.
+ if (a_pTagName &&
+ (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
+ {
+ break;
+ }
+
+ // if we are at the end of the data then we just automatically end
+ // this entry and return the current data.
+ if (!cEndOfLineChar) {
+ return true;
+ }
+
+ // otherwise we need to process this newline to ensure that it consists
+ // of just a single \n character.
+ pDataLine += (a_pData - pCurrLine);
+ *a_pData = cEndOfLineChar;
+ SkipNewLine(a_pData);
+ *pDataLine++ = '\n';
+ }
+
+ // if we didn't find a comment at all then return false
+ if (a_pVal == a_pData) {
+ a_pVal = NULL;
+ return false;
+ }
+
+ // the data (which ends at the end of the last line) needs to be
+ // null-terminated BEFORE before the newline character(s). If the
+ // user wants a new line in the multi-line data then they need to
+ // add an empty line before the tag.
+ *--pDataLine = '\0';
+
+ // if looking for a tag and if we aren't at the end of the data,
+ // then move a_pData to the start of the next line.
+ if (a_pTagName && cEndOfLineChar) {
+ SI_ASSERT(IsNewLineChar(cEndOfLineChar));
+ *a_pData = cEndOfLineChar;
+ SkipNewLine(a_pData);
+ }
+
+ return true;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CopyString(
+ const SI_CHAR *& a_pString
+ )
+{
+ size_t uLen = 0;
+ if (sizeof(SI_CHAR) == sizeof(char)) {
+ uLen = strlen((const char *)a_pString);
+ }
+ else if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
+ uLen = wcslen((const wchar_t *)a_pString);
+ }
+ else {
+ for ( ; a_pString[uLen]; ++uLen) /*loop*/ ;
+ }
+ ++uLen; // NULL character
+ SI_CHAR * pCopy = new SI_CHAR[uLen];
+ if (!pCopy) {
+ return SI_NOMEM;
+ }
+ memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen);
+ m_strings.push_back(pCopy);
+ a_pString = pCopy;
+ return SI_OK;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ const SI_CHAR * a_pValue,
+ const SI_CHAR * a_pComment,
+ bool a_bForceReplace,
+ bool a_bCopyStrings
+ )
+{
+ SI_Error rc;
+ bool bInserted = false;
+
+ SI_ASSERT(!a_pComment || IsComment(*a_pComment));
+
+ // if we are copying strings then make a copy of the comment now
+ // because we will need it when we add the entry.
+ if (a_bCopyStrings && a_pComment) {
+ rc = CopyString(a_pComment);
+ if (rc < 0) return rc;
+ }
+
+ // create the section entry if necessary
+ typename TSection::iterator iSection = m_data.find(a_pSection);
+ if (iSection == m_data.end()) {
+ // if the section doesn't exist then we need a copy as the
+ // string needs to last beyond the end of this function
+ if (a_bCopyStrings) {
+ rc = CopyString(a_pSection);
+ if (rc < 0) return rc;
+ }
+
+ // only set the comment if this is a section only entry
+ Entry oSection(a_pSection, ++m_nOrder);
+ if (a_pComment && (!a_pKey || !a_pValue)) {
+ oSection.pComment = a_pComment;
+ }
+
+ typename TSection::value_type oEntry(oSection, TKeyVal());
+ typedef typename TSection::iterator SectionIterator;
+ std::pair<SectionIterator,bool> i = m_data.insert(oEntry);
+ iSection = i.first;
+ bInserted = true;
+ }
+ if (!a_pKey || !a_pValue) {
+ // section only entries are specified with pItem and pVal as NULL
+ return bInserted ? SI_INSERTED : SI_UPDATED;
+ }
+
+ // check for existence of the key
+ TKeyVal & keyval = iSection->second;
+ typename TKeyVal::iterator iKey = keyval.find(a_pKey);
+
+ // remove all existing entries but save the load order and
+ // comment of the first entry
+ int nLoadOrder = ++m_nOrder;
+ if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
+ const SI_CHAR * pComment = NULL;
+ while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
+ if (iKey->first.nOrder < nLoadOrder) {
+ nLoadOrder = iKey->first.nOrder;
+ pComment = iKey->first.pComment;
+ }
+ ++iKey;
+ }
+ if (pComment) {
+ DeleteString(a_pComment);
+ a_pComment = pComment;
+ CopyString(a_pComment);
+ }
+ Delete(a_pSection, a_pKey);
+ iKey = keyval.end();
+ }
+
+ // make string copies if necessary
+ bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
+ if (a_bCopyStrings) {
+ if (bForceCreateNewKey || iKey == keyval.end()) {
+ // if the key doesn't exist then we need a copy as the
+ // string needs to last beyond the end of this function
+ // because we will be inserting the key next
+ rc = CopyString(a_pKey);
+ if (rc < 0) return rc;
+ }
+
+ // we always need a copy of the value
+ rc = CopyString(a_pValue);
+ if (rc < 0) return rc;
+ }
+
+ // create the key entry
+ if (iKey == keyval.end() || bForceCreateNewKey) {
+ Entry oKey(a_pKey, nLoadOrder);
+ if (a_pComment) {
+ oKey.pComment = a_pComment;
+ }
+ typename TKeyVal::value_type oEntry(oKey, static_cast<const SI_CHAR *>(NULL));
+ iKey = keyval.insert(oEntry);
+ bInserted = true;
+ }
+ iKey->second = a_pValue;
+ return bInserted ? SI_INSERTED : SI_UPDATED;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+const SI_CHAR *
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ const SI_CHAR * a_pDefault,
+ bool * a_pHasMultiple
+ ) const
+{
+ if (a_pHasMultiple) {
+ *a_pHasMultiple = false;
+ }
+ if (!a_pSection || !a_pKey) {
+ return a_pDefault;
+ }
+ typename TSection::const_iterator iSection = m_data.find(a_pSection);
+ if (iSection == m_data.end()) {
+ return a_pDefault;
+ }
+ typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
+ if (iKeyVal == iSection->second.end()) {
+ return a_pDefault;
+ }
+
+ // check for multiple entries with the same key
+ if (m_bAllowMultiKey && a_pHasMultiple) {
+ typename TKeyVal::const_iterator iTemp = iKeyVal;
+ if (++iTemp != iSection->second.end()) {
+ if (!IsLess(a_pKey, iTemp->first.pItem)) {
+ *a_pHasMultiple = true;
+ }
+ }
+ }
+
+ return iKeyVal->second;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+long
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetLongValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ long a_nDefault,
+ bool * a_pHasMultiple
+ ) const
+{
+ // return the default if we don't have a value
+ const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
+ if (!pszValue || !*pszValue) return a_nDefault;
+
+ // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
+ char szValue[64] = { 0 };
+ SI_CONVERTER c(m_bStoreIsUtf8);
+ if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
+ return a_nDefault;
+ }
+
+ // handle the value as hex if prefaced with "0x"
+ long nValue = a_nDefault;
+ char * pszSuffix = szValue;
+ if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) {
+ if (!szValue[2]) return a_nDefault;
+ nValue = ::strtol(&szValue[2], &pszSuffix, 16);
+ }
+ else {
+ nValue = ::strtol(szValue, &pszSuffix, 10);
+ }
+
+ // any invalid strings will return the default value
+ if (*pszSuffix) {
+ return a_nDefault;
+ }
+
+ return nValue;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetLongValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ long a_nValue,
+ const SI_CHAR * a_pComment,
+ bool a_bUseHex,
+ bool a_bForceReplace
+ )
+{
+ // use SetValue to create sections
+ if (!a_pSection || !a_pKey) return SI_FAIL;
+
+ // convert to an ASCII string
+ char szInput[64];
+#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
+ sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
+#else // !__STDC_WANT_SECURE_LIB__
+ sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
+#endif // __STDC_WANT_SECURE_LIB__
+
+ // convert to output text
+ SI_CHAR szOutput[64];
+ SI_CONVERTER c(m_bStoreIsUtf8);
+ c.ConvertFromStore(szInput, strlen(szInput) + 1,
+ szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
+
+ // actually add it
+ return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+double
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetDoubleValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ double a_nDefault,
+ bool * a_pHasMultiple
+ ) const
+{
+ // return the default if we don't have a value
+ const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
+ if (!pszValue || !*pszValue) return a_nDefault;
+
+ // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
+ char szValue[64] = { 0 };
+ SI_CONVERTER c(m_bStoreIsUtf8);
+ if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
+ return a_nDefault;
+ }
+
+ char * pszSuffix = NULL;
+ double nValue = strtod(szValue, &pszSuffix);
+
+ // any invalid strings will return the default value
+ if (!pszSuffix || *pszSuffix) {
+ return a_nDefault;
+ }
+
+ return nValue;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetDoubleValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ double a_nValue,
+ const SI_CHAR * a_pComment,
+ bool a_bForceReplace
+ )
+{
+ // use SetValue to create sections
+ if (!a_pSection || !a_pKey) return SI_FAIL;
+
+ // convert to an ASCII string
+ char szInput[64];
+#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
+ sprintf_s(szInput, "%f", a_nValue);
+#else // !__STDC_WANT_SECURE_LIB__
+ sprintf(szInput, "%f", a_nValue);
+#endif // __STDC_WANT_SECURE_LIB__
+
+ // convert to output text
+ SI_CHAR szOutput[64];
+ SI_CONVERTER c(m_bStoreIsUtf8);
+ c.ConvertFromStore(szInput, strlen(szInput) + 1,
+ szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
+
+ // actually add it
+ return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetBoolValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ bool a_bDefault,
+ bool * a_pHasMultiple
+ ) const
+{
+ // return the default if we don't have a value
+ const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
+ if (!pszValue || !*pszValue) return a_bDefault;
+
+ // we only look at the minimum number of characters
+ switch (pszValue[0]) {
+ case 't': case 'T': // true
+ case 'y': case 'Y': // yes
+ case '1': // 1 (one)
+ return true;
+
+ case 'f': case 'F': // false
+ case 'n': case 'N': // no
+ case '0': // 0 (zero)
+ return false;
+
+ case 'o': case 'O':
+ if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on
+ if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off
+ break;
+ }
+
+ // no recognized value, return the default
+ return a_bDefault;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetBoolValue(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ bool a_bValue,
+ const SI_CHAR * a_pComment,
+ bool a_bForceReplace
+ )
+{
+ // use SetValue to create sections
+ if (!a_pSection || !a_pKey) return SI_FAIL;
+
+ // convert to an ASCII string
+ const char * pszInput = a_bValue ? "true" : "false";
+
+ // convert to output text
+ SI_CHAR szOutput[64];
+ SI_CONVERTER c(m_bStoreIsUtf8);
+ c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
+ szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
+
+ // actually add it
+ return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllValues(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ TNamesDepend & a_values
+ ) const
+{
+ a_values.clear();
+
+ if (!a_pSection || !a_pKey) {
+ return false;
+ }
+ typename TSection::const_iterator iSection = m_data.find(a_pSection);
+ if (iSection == m_data.end()) {
+ return false;
+ }
+ typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
+ if (iKeyVal == iSection->second.end()) {
+ return false;
+ }
+
+ // insert all values for this key
+ a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
+ if (m_bAllowMultiKey) {
+ ++iKeyVal;
+ while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
+ a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
+ ++iKeyVal;
+ }
+ }
+
+ return true;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+int
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetSectionSize(
+ const SI_CHAR * a_pSection
+ ) const
+{
+ if (!a_pSection) {
+ return -1;
+ }
+
+ typename TSection::const_iterator iSection = m_data.find(a_pSection);
+ if (iSection == m_data.end()) {
+ return -1;
+ }
+ const TKeyVal & section = iSection->second;
+
+ // if multi-key isn't permitted then the section size is
+ // the number of keys that we have.
+ if (!m_bAllowMultiKey || section.empty()) {
+ return (int) section.size();
+ }
+
+ // otherwise we need to count them
+ int nCount = 0;
+ const SI_CHAR * pLastKey = NULL;
+ typename TKeyVal::const_iterator iKeyVal = section.begin();
+ for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
+ if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
+ ++nCount;
+ pLastKey = iKeyVal->first.pItem;
+ }
+ }
+ return nCount;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+const typename CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::TKeyVal *
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetSection(
+ const SI_CHAR * a_pSection
+ ) const
+{
+ if (a_pSection) {
+ typename TSection::const_iterator i = m_data.find(a_pSection);
+ if (i != m_data.end()) {
+ return &(i->second);
+ }
+ }
+ return 0;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+void
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllSections(
+ TNamesDepend & a_names
+ ) const
+{
+ a_names.clear();
+ typename TSection::const_iterator i = m_data.begin();
+ for (int n = 0; i != m_data.end(); ++i, ++n ) {
+ a_names.push_back(i->first);
+ }
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllKeys(
+ const SI_CHAR * a_pSection,
+ TNamesDepend & a_names
+ ) const
+{
+ a_names.clear();
+
+ if (!a_pSection) {
+ return false;
+ }
+
+ typename TSection::const_iterator iSection = m_data.find(a_pSection);
+ if (iSection == m_data.end()) {
+ return false;
+ }
+
+ const TKeyVal & section = iSection->second;
+ const SI_CHAR * pLastKey = NULL;
+ typename TKeyVal::const_iterator iKeyVal = section.begin();
+ for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) {
+ if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
+ a_names.push_back(iKeyVal->first);
+ pLastKey = iKeyVal->first.pItem;
+ }
+ }
+
+ return true;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
+ const char * a_pszFile,
+ bool a_bAddSignature
+ ) const
+{
+ FILE * fp = NULL;
+#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
+ fopen_s(&fp, a_pszFile, "wb");
+#else // !__STDC_WANT_SECURE_LIB__
+ fp = fopen(a_pszFile, "wb");
+#endif // __STDC_WANT_SECURE_LIB__
+ if (!fp) return SI_FILE;
+ SI_Error rc = SaveFile(fp, a_bAddSignature);
+ fclose(fp);
+ return rc;
+}
+
+#ifdef SI_HAS_WIDE_FILE
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
+ const SI_WCHAR_T * a_pwszFile,
+ bool a_bAddSignature
+ ) const
+{
+#ifdef _WIN32
+ FILE * fp = NULL;
+#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
+ _wfopen_s(&fp, a_pwszFile, L"wb");
+#else // !__STDC_WANT_SECURE_LIB__
+ fp = _wfopen(a_pwszFile, L"wb");
+#endif // __STDC_WANT_SECURE_LIB__
+ if (!fp) return SI_FILE;
+ SI_Error rc = SaveFile(fp, a_bAddSignature);
+ fclose(fp);
+ return rc;
+#else // !_WIN32 (therefore SI_CONVERT_ICU)
+ char szFile[256];
+ u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
+ return SaveFile(szFile, a_bAddSignature);
+#endif // _WIN32
+}
+#endif // SI_HAS_WIDE_FILE
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
+ FILE * a_pFile,
+ bool a_bAddSignature
+ ) const
+{
+ FileWriter writer(a_pFile);
+ return Save(writer, a_bAddSignature);
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+SI_Error
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
+ OutputWriter & a_oOutput,
+ bool a_bAddSignature
+ ) const
+{
+ Converter convert(m_bStoreIsUtf8);
+
+ // add the UTF-8 signature if it is desired
+ if (m_bStoreIsUtf8 && a_bAddSignature) {
+ a_oOutput.Write(SI_UTF8_SIGNATURE);
+ }
+
+ // get all of the sections sorted in load order
+ TNamesDepend oSections;
+ GetAllSections(oSections);
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+ oSections.sort();
+#elif defined(__BORLANDC__)
+ oSections.sort(Entry::LoadOrder());
+#else
+ oSections.sort(typename Entry::LoadOrder());
+#endif
+
+ // write the file comment if we have one
+ bool bNeedNewLine = false;
+ if (m_pFileComment) {
+ if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
+ return SI_FAIL;
+ }
+ bNeedNewLine = true;
+ }
+
+ // iterate through our sections and output the data
+ typename TNamesDepend::const_iterator iSection = oSections.begin();
+ for ( ; iSection != oSections.end(); ++iSection ) {
+ // write out the comment if there is one
+ if (iSection->pComment) {
+ if (bNeedNewLine) {
+ a_oOutput.Write(SI_NEWLINE_A);
+ a_oOutput.Write(SI_NEWLINE_A);
+ }
+ if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
+ return SI_FAIL;
+ }
+ bNeedNewLine = false;
+ }
+
+ if (bNeedNewLine) {
+ a_oOutput.Write(SI_NEWLINE_A);
+ a_oOutput.Write(SI_NEWLINE_A);
+ bNeedNewLine = false;
+ }
+
+ // write the section (unless there is no section name)
+ if (*iSection->pItem) {
+ if (!convert.ConvertToStore(iSection->pItem)) {
+ return SI_FAIL;
+ }
+ a_oOutput.Write("[");
+ a_oOutput.Write(convert.Data());
+ a_oOutput.Write("]");
+ a_oOutput.Write(SI_NEWLINE_A);
+ }
+
+ // get all of the keys sorted in load order
+ TNamesDepend oKeys;
+ GetAllKeys(iSection->pItem, oKeys);
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+ oKeys.sort();
+#elif defined(__BORLANDC__)
+ oKeys.sort(Entry::LoadOrder());
+#else
+ oKeys.sort(typename Entry::LoadOrder());
+#endif
+
+ // write all keys and values
+ typename TNamesDepend::const_iterator iKey = oKeys.begin();
+ for ( ; iKey != oKeys.end(); ++iKey) {
+ // get all values for this key
+ TNamesDepend oValues;
+ GetAllValues(iSection->pItem, iKey->pItem, oValues);
+
+ typename TNamesDepend::const_iterator iValue = oValues.begin();
+ for ( ; iValue != oValues.end(); ++iValue) {
+ // write out the comment if there is one
+ if (iValue->pComment) {
+ a_oOutput.Write(SI_NEWLINE_A);
+ if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
+ return SI_FAIL;
+ }
+ }
+
+ // write the key
+ if (!convert.ConvertToStore(iKey->pItem)) {
+ return SI_FAIL;
+ }
+ a_oOutput.Write(convert.Data());
+
+ // write the value
+ if (!convert.ConvertToStore(iValue->pItem)) {
+ return SI_FAIL;
+ }
+ a_oOutput.Write(m_bSpaces ? " = " : "=");
+ if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
+ // multi-line data needs to be processed specially to ensure
+ // that we use the correct newline format for the current system
+ a_oOutput.Write("<<<END_OF_TEXT" SI_NEWLINE_A);
+ if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
+ return SI_FAIL;
+ }
+ a_oOutput.Write("END_OF_TEXT");
+ }
+ else {
+ a_oOutput.Write(convert.Data());
+ }
+ a_oOutput.Write(SI_NEWLINE_A);
+ }
+ }
+
+ bNeedNewLine = true;
+ }
+
+ return SI_OK;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::OutputMultiLineText(
+ OutputWriter & a_oOutput,
+ Converter & a_oConverter,
+ const SI_CHAR * a_pText
+ ) const
+{
+ const SI_CHAR * pEndOfLine;
+ SI_CHAR cEndOfLineChar = *a_pText;
+ while (cEndOfLineChar) {
+ // find the end of this line
+ pEndOfLine = a_pText;
+ for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ;
+ cEndOfLineChar = *pEndOfLine;
+
+ // temporarily null terminate, convert and output the line
+ *const_cast<SI_CHAR*>(pEndOfLine) = 0;
+ if (!a_oConverter.ConvertToStore(a_pText)) {
+ return false;
+ }
+ *const_cast<SI_CHAR*>(pEndOfLine) = cEndOfLineChar;
+ a_pText += (pEndOfLine - a_pText) + 1;
+ a_oOutput.Write(a_oConverter.Data());
+ a_oOutput.Write(SI_NEWLINE_A);
+ }
+ return true;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+bool
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Delete(
+ const SI_CHAR * a_pSection,
+ const SI_CHAR * a_pKey,
+ bool a_bRemoveEmpty
+ )
+{
+ if (!a_pSection) {
+ return false;
+ }
+
+ typename TSection::iterator iSection = m_data.find(a_pSection);
+ if (iSection == m_data.end()) {
+ return false;
+ }
+
+ // remove a single key if we have a keyname
+ if (a_pKey) {
+ typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
+ if (iKeyVal == iSection->second.end()) {
+ return false;
+ }
+
+ // remove any copied strings and then the key
+ typename TKeyVal::iterator iDelete;
+ do {
+ iDelete = iKeyVal++;
+
+ DeleteString(iDelete->first.pItem);
+ DeleteString(iDelete->second);
+ iSection->second.erase(iDelete);
+ }
+ while (iKeyVal != iSection->second.end()
+ && !IsLess(a_pKey, iKeyVal->first.pItem));
+
+ // done now if the section is not empty or we are not pruning away
+ // the empty sections. Otherwise let it fall through into the section
+ // deletion code
+ if (!a_bRemoveEmpty || !iSection->second.empty()) {
+ return true;
+ }
+ }
+ else {
+ // delete all copied strings from this section. The actual
+ // entries will be removed when the section is removed.
+ typename TKeyVal::iterator iKeyVal = iSection->second.begin();
+ for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) {
+ DeleteString(iKeyVal->first.pItem);
+ DeleteString(iKeyVal->second);
+ }
+ }
+
+ // delete the section itself
+ DeleteString(iSection->first.pItem);
+ m_data.erase(iSection);
+
+ return true;
+}
+
+template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
+void
+CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::DeleteString(
+ const SI_CHAR * a_pString
+ )
+{
+ // strings may exist either inside the data block, or they will be
+ // individually allocated and stored in m_strings. We only physically
+ // delete those stored in m_strings.
+ if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
+ typename TNamesDepend::iterator i = m_strings.begin();
+ for (;i != m_strings.end(); ++i) {
+ if (a_pString == i->pItem) {
+ delete[] const_cast<SI_CHAR*>(i->pItem);
+ m_strings.erase(i);
+ break;
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CONVERSION FUNCTIONS
+// ---------------------------------------------------------------------------
+
+// Defines the conversion classes for different libraries. Before including
+// SimpleIni.h, set the converter that you wish you use by defining one of the
+// following symbols.
+//
+// SI_CONVERT_GENERIC Use the Unicode reference conversion library in
+// the accompanying files ConvertUTF.h/c
+// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
+// ICU headers on include path and icuuc.lib
+// SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
+
+#if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
+# ifdef _WIN32
+# define SI_CONVERT_WIN32
+# else
+# define SI_CONVERT_GENERIC
+# endif
+#endif
+
+/**
+ * Generic case-sensitive less than comparison. This class returns numerically
+ * ordered ASCII case-sensitive text for all possible sizes and types of
+ * SI_CHAR.
+ */
+template<class SI_CHAR>
+struct SI_GenericCase {
+ bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
+ long cmp;
+ for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
+ cmp = (long) *pLeft - (long) *pRight;
+ if (cmp != 0) {
+ return cmp < 0;
+ }
+ }
+ return *pRight != 0;
+ }
+};
+
+/**
+ * Generic ASCII case-insensitive less than comparison. This class returns
+ * numerically ordered ASCII case-insensitive text for all possible sizes
+ * and types of SI_CHAR. It is not safe for MBCS text comparison where
+ * ASCII A-Z characters are used in the encoding of multi-byte characters.
+ */
+template<class SI_CHAR>
+struct SI_GenericNoCase {
+ inline SI_CHAR locase(SI_CHAR ch) const {
+ return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a');
+ }
+ bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
+ long cmp;
+ for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
+ cmp = (long) locase(*pLeft) - (long) locase(*pRight);
+ if (cmp != 0) {
+ return cmp < 0;
+ }
+ }
+ return *pRight != 0;
+ }
+};
+
+/**
+ * Null conversion class for MBCS/UTF-8 to char (or equivalent).
+ */
+template<class SI_CHAR>
+class SI_ConvertA {
+ bool m_bStoreIsUtf8;
+protected:
+ SI_ConvertA() { }
+public:
+ SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
+
+ /* copy and assignment */
+ SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); }
+ SI_ConvertA & operator=(const SI_ConvertA & rhs) {
+ m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
+ return *this;
+ }
+
+ /** Calculate the number of SI_CHAR required for converting the input
+ * from the storage format. The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to SI_CHAR.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @return Number of SI_CHAR required by the string when
+ * converted. If there are embedded NULL bytes in the
+ * input data, only the string up and not including
+ * the NULL byte will be converted.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen)
+ {
+ (void)a_pInputData;
+ SI_ASSERT(a_uInputDataLen != (size_t) -1);
+
+ // ASCII/MBCS/UTF-8 needs no conversion
+ return a_uInputDataLen;
+ }
+
+ /** Convert the input string from the storage format to SI_CHAR.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to SI_CHAR.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @param a_pOutputData Pointer to the output buffer to received the
+ * converted data.
+ * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
+ * @return true if all of the input data was successfully
+ * converted.
+ */
+ bool ConvertFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen,
+ SI_CHAR * a_pOutputData,
+ size_t a_uOutputDataSize)
+ {
+ // ASCII/MBCS/UTF-8 needs no conversion
+ if (a_uInputDataLen > a_uOutputDataSize) {
+ return false;
+ }
+ memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
+ return true;
+ }
+
+ /** Calculate the number of char required by the storage format of this
+ * data. The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData NULL terminated string to calculate the number of
+ * bytes required to be converted to storage format.
+ * @return Number of bytes required by the string when
+ * converted to storage format. This size always
+ * includes space for the terminating NULL character.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeToStore(
+ const SI_CHAR * a_pInputData)
+ {
+ // ASCII/MBCS/UTF-8 needs no conversion
+ return strlen((const char *)a_pInputData) + 1;
+ }
+
+ /** Convert the input string to the storage format of this data.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData NULL terminated source string to convert. All of
+ * the data will be converted including the
+ * terminating NULL character.
+ * @param a_pOutputData Pointer to the buffer to receive the converted
+ * string.
+ * @param a_uOutputDataSize Size of the output buffer in char.
+ * @return true if all of the input data, including the
+ * terminating NULL character was successfully
+ * converted.
+ */
+ bool ConvertToStore(
+ const SI_CHAR * a_pInputData,
+ char * a_pOutputData,
+ size_t a_uOutputDataSize)
+ {
+ // calc input string length (SI_CHAR type and size independent)
+ size_t uInputLen = strlen((const char *)a_pInputData) + 1;
+ if (uInputLen > a_uOutputDataSize) {
+ return false;
+ }
+
+ // ascii/UTF-8 needs no conversion
+ memcpy(a_pOutputData, a_pInputData, uInputLen);
+ return true;
+ }
+};
+
+
+// ---------------------------------------------------------------------------
+// SI_CONVERT_GENERIC
+// ---------------------------------------------------------------------------
+#ifdef SI_CONVERT_GENERIC
+
+#define SI_Case SI_GenericCase
+#define SI_NoCase SI_GenericNoCase
+
+#include <wchar.h>
+#include "ConvertUTF.h"
+
+/**
+ * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference
+ * library functions. This can be used on all platforms.
+ */
+template<class SI_CHAR>
+class SI_ConvertW {
+ bool m_bStoreIsUtf8;
+protected:
+ SI_ConvertW() { }
+public:
+ SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
+
+ /* copy and assignment */
+ SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
+ SI_ConvertW & operator=(const SI_ConvertW & rhs) {
+ m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
+ return *this;
+ }
+
+ /** Calculate the number of SI_CHAR required for converting the input
+ * from the storage format. The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to SI_CHAR.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @return Number of SI_CHAR required by the string when
+ * converted. If there are embedded NULL bytes in the
+ * input data, only the string up and not including
+ * the NULL byte will be converted.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen)
+ {
+ SI_ASSERT(a_uInputDataLen != (size_t) -1);
+
+ if (m_bStoreIsUtf8) {
+ // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
+ // so we just return the same number of characters required as for
+ // the source text.
+ return a_uInputDataLen;
+ }
+
+#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
+ // fall back processing for platforms that don't support a NULL dest to mbstowcs
+ // worst case scenario is 1:1, this will be a sufficient buffer size
+ (void)a_pInputData;
+ return a_uInputDataLen;
+#else
+ // get the actual required buffer size
+ return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
+#endif
+ }
+
+ /** Convert the input string from the storage format to SI_CHAR.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to SI_CHAR.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @param a_pOutputData Pointer to the output buffer to received the
+ * converted data.
+ * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
+ * @return true if all of the input data was successfully
+ * converted.
+ */
+ bool ConvertFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen,
+ SI_CHAR * a_pOutputData,
+ size_t a_uOutputDataSize)
+ {
+ if (m_bStoreIsUtf8) {
+ // This uses the Unicode reference implementation to do the
+ // conversion from UTF-8 to wchar_t. The required files are
+ // ConvertUTF.h and ConvertUTF.c which should be included in
+ // the distribution but are publically available from unicode.org
+ // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
+ ConversionResult retval;
+ const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
+ if (sizeof(wchar_t) == sizeof(UTF32)) {
+ UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
+ retval = ConvertUTF8toUTF32(
+ &pUtf8, pUtf8 + a_uInputDataLen,
+ &pUtf32, pUtf32 + a_uOutputDataSize,
+ lenientConversion);
+ }
+ else if (sizeof(wchar_t) == sizeof(UTF16)) {
+ UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
+ retval = ConvertUTF8toUTF16(
+ &pUtf8, pUtf8 + a_uInputDataLen,
+ &pUtf16, pUtf16 + a_uOutputDataSize,
+ lenientConversion);
+ }
+ return retval == conversionOK;
+ }
+
+ // convert to wchar_t
+ size_t retval = mbstowcs(a_pOutputData,
+ a_pInputData, a_uOutputDataSize);
+ return retval != (size_t)(-1);
+ }
+
+ /** Calculate the number of char required by the storage format of this
+ * data. The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData NULL terminated string to calculate the number of
+ * bytes required to be converted to storage format.
+ * @return Number of bytes required by the string when
+ * converted to storage format. This size always
+ * includes space for the terminating NULL character.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeToStore(
+ const SI_CHAR * a_pInputData)
+ {
+ if (m_bStoreIsUtf8) {
+ // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
+ size_t uLen = 0;
+ while (a_pInputData[uLen]) {
+ ++uLen;
+ }
+ return (6 * uLen) + 1;
+ }
+ else {
+ size_t uLen = wcstombs(NULL, a_pInputData, 0);
+ if (uLen == (size_t)(-1)) {
+ return uLen;
+ }
+ return uLen + 1; // include NULL terminator
+ }
+ }
+
+ /** Convert the input string to the storage format of this data.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData NULL terminated source string to convert. All of
+ * the data will be converted including the
+ * terminating NULL character.
+ * @param a_pOutputData Pointer to the buffer to receive the converted
+ * string.
+ * @param a_uOutputDataSize Size of the output buffer in char.
+ * @return true if all of the input data, including the
+ * terminating NULL character was successfully
+ * converted.
+ */
+ bool ConvertToStore(
+ const SI_CHAR * a_pInputData,
+ char * a_pOutputData,
+ size_t a_uOutputDataSize
+ )
+ {
+ if (m_bStoreIsUtf8) {
+ // calc input string length (SI_CHAR type and size independent)
+ size_t uInputLen = 0;
+ while (a_pInputData[uInputLen]) {
+ ++uInputLen;
+ }
+ ++uInputLen; // include the NULL char
+
+ // This uses the Unicode reference implementation to do the
+ // conversion from wchar_t to UTF-8. The required files are
+ // ConvertUTF.h and ConvertUTF.c which should be included in
+ // the distribution but are publically available from unicode.org
+ // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
+ ConversionResult retval;
+ UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
+ if (sizeof(wchar_t) == sizeof(UTF32)) {
+ const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
+ retval = ConvertUTF32toUTF8(
+ &pUtf32, pUtf32 + uInputLen,
+ &pUtf8, pUtf8 + a_uOutputDataSize,
+ lenientConversion);
+ }
+ else if (sizeof(wchar_t) == sizeof(UTF16)) {
+ const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
+ retval = ConvertUTF16toUTF8(
+ &pUtf16, pUtf16 + uInputLen,
+ &pUtf8, pUtf8 + a_uOutputDataSize,
+ lenientConversion);
+ }
+ return retval == conversionOK;
+ }
+ else {
+ size_t retval = wcstombs(a_pOutputData,
+ a_pInputData, a_uOutputDataSize);
+ return retval != (size_t) -1;
+ }
+ }
+};
+
+#endif // SI_CONVERT_GENERIC
+
+
+// ---------------------------------------------------------------------------
+// SI_CONVERT_ICU
+// ---------------------------------------------------------------------------
+#ifdef SI_CONVERT_ICU
+
+#define SI_Case SI_GenericCase
+#define SI_NoCase SI_GenericNoCase
+
+#include <unicode/ucnv.h>
+
+/**
+ * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms.
+ */
+template<class SI_CHAR>
+class SI_ConvertW {
+ const char * m_pEncoding;
+ UConverter * m_pConverter;
+protected:
+ SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { }
+public:
+ SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) {
+ m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL;
+ }
+
+ /* copy and assignment */
+ SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
+ SI_ConvertW & operator=(const SI_ConvertW & rhs) {
+ m_pEncoding = rhs.m_pEncoding;
+ m_pConverter = NULL;
+ return *this;
+ }
+ ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); }
+
+ /** Calculate the number of UChar required for converting the input
+ * from the storage format. The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to UChar.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @return Number of UChar required by the string when
+ * converted. If there are embedded NULL bytes in the
+ * input data, only the string up and not including
+ * the NULL byte will be converted.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen)
+ {
+ SI_ASSERT(a_uInputDataLen != (size_t) -1);
+
+ UErrorCode nError;
+
+ if (!m_pConverter) {
+ nError = U_ZERO_ERROR;
+ m_pConverter = ucnv_open(m_pEncoding, &nError);
+ if (U_FAILURE(nError)) {
+ return (size_t) -1;
+ }
+ }
+
+ nError = U_ZERO_ERROR;
+ int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
+ a_pInputData, (int32_t) a_uInputDataLen, &nError);
+ if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
+ return (size_t) -1;
+ }
+
+ return (size_t) nLen;
+ }
+
+ /** Convert the input string from the storage format to UChar.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to UChar.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @param a_pOutputData Pointer to the output buffer to received the
+ * converted data.
+ * @param a_uOutputDataSize Size of the output buffer in UChar.
+ * @return true if all of the input data was successfully
+ * converted.
+ */
+ bool ConvertFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen,
+ UChar * a_pOutputData,
+ size_t a_uOutputDataSize)
+ {
+ UErrorCode nError;
+
+ if (!m_pConverter) {
+ nError = U_ZERO_ERROR;
+ m_pConverter = ucnv_open(m_pEncoding, &nError);
+ if (U_FAILURE(nError)) {
+ return false;
+ }
+ }
+
+ nError = U_ZERO_ERROR;
+ ucnv_toUChars(m_pConverter,
+ a_pOutputData, (int32_t) a_uOutputDataSize,
+ a_pInputData, (int32_t) a_uInputDataLen, &nError);
+ if (U_FAILURE(nError)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /** Calculate the number of char required by the storage format of this
+ * data. The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData NULL terminated string to calculate the number of
+ * bytes required to be converted to storage format.
+ * @return Number of bytes required by the string when
+ * converted to storage format. This size always
+ * includes space for the terminating NULL character.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeToStore(
+ const UChar * a_pInputData)
+ {
+ UErrorCode nError;
+
+ if (!m_pConverter) {
+ nError = U_ZERO_ERROR;
+ m_pConverter = ucnv_open(m_pEncoding, &nError);
+ if (U_FAILURE(nError)) {
+ return (size_t) -1;
+ }
+ }
+
+ nError = U_ZERO_ERROR;
+ int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
+ a_pInputData, -1, &nError);
+ if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
+ return (size_t) -1;
+ }
+
+ return (size_t) nLen + 1;
+ }
+
+ /** Convert the input string to the storage format of this data.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData NULL terminated source string to convert. All of
+ * the data will be converted including the
+ * terminating NULL character.
+ * @param a_pOutputData Pointer to the buffer to receive the converted
+ * string.
+ * @param a_pOutputDataSize Size of the output buffer in char.
+ * @return true if all of the input data, including the
+ * terminating NULL character was successfully
+ * converted.
+ */
+ bool ConvertToStore(
+ const UChar * a_pInputData,
+ char * a_pOutputData,
+ size_t a_uOutputDataSize)
+ {
+ UErrorCode nError;
+
+ if (!m_pConverter) {
+ nError = U_ZERO_ERROR;
+ m_pConverter = ucnv_open(m_pEncoding, &nError);
+ if (U_FAILURE(nError)) {
+ return false;
+ }
+ }
+
+ nError = U_ZERO_ERROR;
+ ucnv_fromUChars(m_pConverter,
+ a_pOutputData, (int32_t) a_uOutputDataSize,
+ a_pInputData, -1, &nError);
+ if (U_FAILURE(nError)) {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+#endif // SI_CONVERT_ICU
+
+
+// ---------------------------------------------------------------------------
+// SI_CONVERT_WIN32
+// ---------------------------------------------------------------------------
+#ifdef SI_CONVERT_WIN32
+
+#define SI_Case SI_GenericCase
+
+// Windows CE doesn't have errno or MBCS libraries
+#ifdef _WIN32_WCE
+# ifndef SI_NO_MBCS
+# define SI_NO_MBCS
+# endif
+#endif
+
+#include <windows.h>
+#ifdef SI_NO_MBCS
+# define SI_NoCase SI_GenericNoCase
+#else // !SI_NO_MBCS
+/**
+ * Case-insensitive comparison class using Win32 MBCS functions. This class
+ * returns a case-insensitive semi-collation order for MBCS text. It may not
+ * be safe for UTF-8 text returned in char format as we don't know what
+ * characters will be folded by the function! Therefore, if you are using
+ * SI_CHAR == char and SetUnicode(true), then you need to use the generic
+ * SI_NoCase class instead.
+ */
+#include <mbstring.h>
+template<class SI_CHAR>
+struct SI_NoCase {
+ bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
+ if (sizeof(SI_CHAR) == sizeof(char)) {
+ return _mbsicmp((const unsigned char *)pLeft,
+ (const unsigned char *)pRight) < 0;
+ }
+ if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
+ return _wcsicmp((const wchar_t *)pLeft,
+ (const wchar_t *)pRight) < 0;
+ }
+ return SI_GenericNoCase<SI_CHAR>()(pLeft, pRight);
+ }
+};
+#endif // SI_NO_MBCS
+
+/**
+ * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses
+ * only the Win32 functions and doesn't require the external Unicode UTF-8
+ * conversion library. It will not work on Windows 95 without using Microsoft
+ * Layer for Unicode in your application.
+ */
+template<class SI_CHAR>
+class SI_ConvertW {
+ UINT m_uCodePage;
+protected:
+ SI_ConvertW() { }
+public:
+ SI_ConvertW(bool a_bStoreIsUtf8) {
+ m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP;
+ }
+
+ /* copy and assignment */
+ SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
+ SI_ConvertW & operator=(const SI_ConvertW & rhs) {
+ m_uCodePage = rhs.m_uCodePage;
+ return *this;
+ }
+
+ /** Calculate the number of SI_CHAR required for converting the input
+ * from the storage format. The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to SI_CHAR.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @return Number of SI_CHAR required by the string when
+ * converted. If there are embedded NULL bytes in the
+ * input data, only the string up and not including
+ * the NULL byte will be converted.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen)
+ {
+ SI_ASSERT(a_uInputDataLen != (size_t) -1);
+
+ int retval = MultiByteToWideChar(
+ m_uCodePage, 0,
+ a_pInputData, (int) a_uInputDataLen,
+ 0, 0);
+ return (size_t)(retval > 0 ? retval : -1);
+ }
+
+ /** Convert the input string from the storage format to SI_CHAR.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData Data in storage format to be converted to SI_CHAR.
+ * @param a_uInputDataLen Length of storage format data in bytes. This
+ * must be the actual length of the data, including
+ * NULL byte if NULL terminated string is required.
+ * @param a_pOutputData Pointer to the output buffer to received the
+ * converted data.
+ * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
+ * @return true if all of the input data was successfully
+ * converted.
+ */
+ bool ConvertFromStore(
+ const char * a_pInputData,
+ size_t a_uInputDataLen,
+ SI_CHAR * a_pOutputData,
+ size_t a_uOutputDataSize)
+ {
+ int nSize = MultiByteToWideChar(
+ m_uCodePage, 0,
+ a_pInputData, (int) a_uInputDataLen,
+ (wchar_t *) a_pOutputData, (int) a_uOutputDataSize);
+ return (nSize > 0);
+ }
+
+ /** Calculate the number of char required by the storage format of this
+ * data. The storage format is always UTF-8.
+ *
+ * @param a_pInputData NULL terminated string to calculate the number of
+ * bytes required to be converted to storage format.
+ * @return Number of bytes required by the string when
+ * converted to storage format. This size always
+ * includes space for the terminating NULL character.
+ * @return -1 cast to size_t on a conversion error.
+ */
+ size_t SizeToStore(
+ const SI_CHAR * a_pInputData)
+ {
+ int retval = WideCharToMultiByte(
+ m_uCodePage, 0,
+ (const wchar_t *) a_pInputData, -1,
+ 0, 0, 0, 0);
+ return (size_t) (retval > 0 ? retval : -1);
+ }
+
+ /** Convert the input string to the storage format of this data.
+ * The storage format is always UTF-8 or MBCS.
+ *
+ * @param a_pInputData NULL terminated source string to convert. All of
+ * the data will be converted including the
+ * terminating NULL character.
+ * @param a_pOutputData Pointer to the buffer to receive the converted
+ * string.
+ * @param a_pOutputDataSize Size of the output buffer in char.
+ * @return true if all of the input data, including the
+ * terminating NULL character was successfully
+ * converted.
+ */
+ bool ConvertToStore(
+ const SI_CHAR * a_pInputData,
+ char * a_pOutputData,
+ size_t a_uOutputDataSize)
+ {
+ int retval = WideCharToMultiByte(
+ m_uCodePage, 0,
+ (const wchar_t *) a_pInputData, -1,
+ a_pOutputData, (int) a_uOutputDataSize, 0, 0);
+ return retval > 0;
+ }
+};
+
+#endif // SI_CONVERT_WIN32
+
+
+// ---------------------------------------------------------------------------
+// TYPE DEFINITIONS
+// ---------------------------------------------------------------------------
+
+typedef CSimpleIniTempl<char,
+ SI_NoCase<char>,SI_ConvertA<char> > CSimpleIniA;
+typedef CSimpleIniTempl<char,
+ SI_Case<char>,SI_ConvertA<char> > CSimpleIniCaseA;
+
+#if defined(SI_CONVERT_ICU)
+typedef CSimpleIniTempl<UChar,
+ SI_NoCase<UChar>,SI_ConvertW<UChar> > CSimpleIniW;
+typedef CSimpleIniTempl<UChar,
+ SI_Case<UChar>,SI_ConvertW<UChar> > CSimpleIniCaseW;
+#else
+typedef CSimpleIniTempl<wchar_t,
+ SI_NoCase<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniW;
+typedef CSimpleIniTempl<wchar_t,
+ SI_Case<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniCaseW;
+#endif
+
+#ifdef _UNICODE
+# define CSimpleIni CSimpleIniW
+# define CSimpleIniCase CSimpleIniCaseW
+# define SI_NEWLINE SI_NEWLINE_W
+#else // !_UNICODE
+# define CSimpleIni CSimpleIniA
+# define CSimpleIniCase CSimpleIniCaseA
+# define SI_NEWLINE SI_NEWLINE_A
+#endif // _UNICODE
+
+#ifdef _MSC_VER
+# pragma warning (pop)
+#endif
+
+#endif // INCLUDED_SimpleIni_h
+
diff --git a/linkers/elftoolchain/common/Makefile b/linkers/elftoolchain/common/Makefile
new file mode 100644
index 0000000..b7b5372
--- /dev/null
+++ b/linkers/elftoolchain/common/Makefile
@@ -0,0 +1,15 @@
+# $Id: Makefile 2140 2011-11-10 14:27:03Z jkoshy $
+
+TOP= ..
+
+INCS= elfdefinitions.h
+INCSDIR?= /usr/include
+
+.PHONY: all clean clobber depend obj
+
+all depend obj:
+
+clean clobber:
+ rm -f ${CLEANFILES}
+
+.include "${TOP}/mk/elftoolchain.inc.mk"
diff --git a/linkers/elftoolchain/common/_elftc.h b/linkers/elftoolchain/common/_elftc.h
new file mode 100644
index 0000000..9ee8db1
--- /dev/null
+++ b/linkers/elftoolchain/common/_elftc.h
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2009 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: _elftc.h 2064 2011-10-26 15:12:32Z jkoshy $
+ */
+
+/**
+ ** Miscellanous definitions needed by multiple components.
+ **/
+
+#ifndef _ELFTC_H
+#define _ELFTC_H
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#ifndef offsetof
+#define offsetof(T, M) ((int) &((T*) 0) -> M)
+#endif
+
+/*
+ * Supply macros missing from <sys/queue.h>
+ */
+
+#ifndef STAILQ_FOREACH_SAFE
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+#endif
+
+#ifndef STAILQ_LAST
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *)(void *) \
+ ((char *)((head)->stqh_last) - offsetof(struct type, field))))
+#endif
+
+#ifndef TAILQ_FOREACH_SAFE
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+#endif
+
+/*
+ * VCS Ids.
+ */
+
+#ifndef ELFTC_VCSID
+
+#if defined(__FreeBSD__)
+#define ELFTC_VCSID(ID) __FBSDID(ID)
+#endif
+
+#if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)
+#if defined(__GNUC__)
+#define ELFTC_VCSID(ID) __asm__(".ident\t\"" ID "\"")
+#else
+#define ELFTC_VCSID(ID) /**/
+#endif
+#endif
+
+#if defined(__NetBSD__)
+#define ELFTC_VCSID(ID) __RCSID(ID)
+#endif
+
+#endif /* ELFTC_VCSID */
+
+/*
+ * Provide an equivalent for getprogname(3).
+ */
+
+#ifndef ELFTC_GETPROGNAME
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+
+#include <stdlib.h>
+
+#define ELFTC_GETPROGNAME() getprogname()
+
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */
+
+
+#if defined(__linux__)
+
+/*
+ * GLIBC based systems have a global 'char *' pointer referencing
+ * the executable's name.
+ */
+extern const char *program_invocation_short_name;
+
+#define ELFTC_GETPROGNAME() program_invocation_short_name
+
+#endif /* __linux__ */
+
+#endif /* ELFTC_GETPROGNAME */
+
+/**
+ ** Per-OS configuration.
+ **/
+
+#if defined(__linux__)
+
+#include <endian.h>
+
+#define ELFTC_BYTE_ORDER __BYTE_ORDER
+#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN __LITTLE_ENDIAN
+#define ELFTC_BYTE_ORDER_BIG_ENDIAN __BIG_ENDIAN
+
+/*
+ * Debian GNU/Linux is missing strmode(3).
+ */
+#define ELFTC_HAVE_STRMODE 0
+
+/* Whether we need to supply {be,le}32dec. */
+#define ELFTC_NEED_BYTEORDER_EXTENSIONS 1
+
+#define roundup2 roundup
+
+#endif /* __linux__ */
+
+
+#if defined(__FreeBSD__)
+
+#include <osreldate.h>
+#include <sys/endian.h>
+
+#define ELFTC_BYTE_ORDER _BYTE_ORDER
+#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN
+#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN
+
+#define ELFTC_HAVE_STRMODE 1
+#if __FreeBSD_version <= 900000
+#define ELFTC_BROKEN_YY_NO_INPUT 1
+#endif
+#endif /* __FreeBSD__ */
+
+
+#if defined(__NetBSD__)
+
+#include <sys/endian.h>
+
+#define ELFTC_BYTE_ORDER _BYTE_ORDER
+#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN
+#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN
+
+#define ELFTC_HAVE_STRMODE 1
+#define ELFTC_BROKEN_YY_NO_INPUT 1
+#endif /* __NetBSD __ */
+
+#endif /* _ELFTC_H */
diff --git a/linkers/elftoolchain/common/elfdefinitions.h b/linkers/elftoolchain/common/elfdefinitions.h
new file mode 100644
index 0000000..79b6e7f
--- /dev/null
+++ b/linkers/elftoolchain/common/elfdefinitions.h
@@ -0,0 +1,2560 @@
+/*-
+ * Copyright (c) 2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: elfdefinitions.h 2132 2011-11-10 08:27:41Z jkoshy $
+ */
+
+/*
+ * These definitions are based on:
+ * - The public specification of the ELF format as defined in the
+ * October 2009 draft of System V ABI.
+ * See: http://www.sco.com/developers/gabi/latest/ch4.intro.html
+ * - The May 1998 (version 1.5) draft of "The ELF-64 object format".
+ * - Processor-specific ELF ABI definitions for sparc, i386, amd64, mips,
+ * ia64, and powerpc processors.
+ * - The "Linkers and Libraries Guide", from Sun Microsystems.
+ */
+
+#ifndef _ELFDEFINITIONS_H_
+#define _ELFDEFINITIONS_H_
+
+#include <stdint.h>
+
+/*
+ * Types of capabilities.
+ */
+
+#define _ELF_DEFINE_CAPABILITIES() \
+_ELF_DEFINE_CA(CA_SUNW_NULL, 0, "ignored") \
+_ELF_DEFINE_CA(CA_SUNW_HW_1, 1, "hardware capability") \
+_ELF_DEFINE_CA(CA_SUNW_SW_1, 2, "software capability")
+
+#undef _ELF_DEFINE_CA
+#define _ELF_DEFINE_CA(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_CAPABILITIES()
+ CA__LAST__
+};
+
+/*
+ * Flags used with dynamic linking entries.
+ */
+
+#define _ELF_DEFINE_DYN_FLAGS() \
+_ELF_DEFINE_DF(DF_ORIGIN, 0x1, \
+ "object being loaded may refer to $ORIGIN") \
+_ELF_DEFINE_DF(DF_SYMBOLIC, 0x2, \
+ "search library for references before executable") \
+_ELF_DEFINE_DF(DF_TEXTREL, 0x4, \
+ "relocation entries may modify text segment") \
+_ELF_DEFINE_DF(DF_BIND_NOW, 0x8, \
+ "process relocation entries at load time") \
+_ELF_DEFINE_DF(DF_STATIC_TLS, 0x10, \
+ "uses static thread-local storage")
+#undef _ELF_DEFINE_DF
+#define _ELF_DEFINE_DF(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_DYN_FLAGS()
+ DF__LAST__
+};
+
+
+/*
+ * Dynamic linking entry types.
+ */
+
+#define _ELF_DEFINE_DYN_TYPES() \
+_ELF_DEFINE_DT(DT_NULL, 0, "end of array") \
+_ELF_DEFINE_DT(DT_NEEDED, 1, "names a needed library") \
+_ELF_DEFINE_DT(DT_PLTRELSZ, 2, \
+ "size in bytes of associated relocation entries") \
+_ELF_DEFINE_DT(DT_PLTGOT, 3, \
+ "address associated with the procedure linkage table") \
+_ELF_DEFINE_DT(DT_HASH, 4, \
+ "address of the symbol hash table") \
+_ELF_DEFINE_DT(DT_STRTAB, 5, \
+ "address of the string table") \
+_ELF_DEFINE_DT(DT_SYMTAB, 6, \
+ "address of the symbol table") \
+_ELF_DEFINE_DT(DT_RELA, 7, \
+ "address of the relocation table") \
+_ELF_DEFINE_DT(DT_RELASZ, 8, "size of the DT_RELA table") \
+_ELF_DEFINE_DT(DT_RELAENT, 9, "size of each DT_RELA entry") \
+_ELF_DEFINE_DT(DT_STRSZ, 10, "size of the string table") \
+_ELF_DEFINE_DT(DT_SYMENT, 11, \
+ "size of a symbol table entry") \
+_ELF_DEFINE_DT(DT_INIT, 12, \
+ "address of the initialization function") \
+_ELF_DEFINE_DT(DT_FINI, 13, \
+ "address of the finalization function") \
+_ELF_DEFINE_DT(DT_SONAME, 14, "names the shared object") \
+_ELF_DEFINE_DT(DT_RPATH, 15, \
+ "runtime library search path") \
+_ELF_DEFINE_DT(DT_SYMBOLIC, 16, \
+ "alter symbol resolution algorithm") \
+_ELF_DEFINE_DT(DT_REL, 17, \
+ "address of the DT_REL table") \
+_ELF_DEFINE_DT(DT_RELSZ, 18, "size of the DT_REL table") \
+_ELF_DEFINE_DT(DT_RELENT, 19, "size of each DT_REL entry") \
+_ELF_DEFINE_DT(DT_PLTREL, 20, \
+ "type of relocation entry in the procedure linkage table") \
+_ELF_DEFINE_DT(DT_DEBUG, 21, "used for debugging") \
+_ELF_DEFINE_DT(DT_TEXTREL, 22, \
+ "text segment may be written to during relocation") \
+_ELF_DEFINE_DT(DT_JMPREL, 23, \
+ "address of relocation entries associated with the procedure linkage table") \
+_ELF_DEFINE_DT(DT_BIND_NOW, 24, \
+ "bind symbols at loading time") \
+_ELF_DEFINE_DT(DT_INIT_ARRAY, 25, \
+ "pointers to initialization functions") \
+_ELF_DEFINE_DT(DT_FINI_ARRAY, 26, \
+ "pointers to termination functions") \
+_ELF_DEFINE_DT(DT_INIT_ARRAYSZ, 27, "size of the DT_INIT_ARRAY") \
+_ELF_DEFINE_DT(DT_FINI_ARRAYSZ, 28, "size of the DT_FINI_ARRAY") \
+_ELF_DEFINE_DT(DT_RUNPATH, 29, \
+ "index of library search path string") \
+_ELF_DEFINE_DT(DT_FLAGS, 30, \
+ "flags specific to the object being loaded") \
+_ELF_DEFINE_DT(DT_ENCODING, 32, "standard semantics") \
+_ELF_DEFINE_DT(DT_PREINIT_ARRAY, 32, \
+ "pointers to pre-initialization functions") \
+_ELF_DEFINE_DT(DT_PREINIT_ARRAYSZ, 33, \
+ "size of pre-initialization array") \
+_ELF_DEFINE_DT(DT_MAXPOSTAGS, 34, \
+ "the number of positive tags") \
+_ELF_DEFINE_DT(DT_LOOS, 0x6000000DUL, \
+ "start of OS-specific types") \
+_ELF_DEFINE_DT(DT_SUNW_AUXILIARY, 0x6000000DUL, \
+ "offset of string naming auxiliary filtees") \
+_ELF_DEFINE_DT(DT_SUNW_RTLDINF, 0x6000000EUL, "rtld internal use") \
+_ELF_DEFINE_DT(DT_SUNW_FILTER, 0x6000000FUL, \
+ "offset of string naming standard filtees") \
+_ELF_DEFINE_DT(DT_SUNW_CAP, 0x60000010UL, \
+ "address of hardware capabilities section") \
+_ELF_DEFINE_DT(DT_HIOS, 0x6FFFF000UL, \
+ "end of OS-specific types") \
+_ELF_DEFINE_DT(DT_VALRNGLO, 0x6FFFFD00UL, \
+ "start of range using the d_val field") \
+_ELF_DEFINE_DT(DT_GNU_PRELINKED, 0x6FFFFDF5UL, \
+ "prelinking timestamp") \
+_ELF_DEFINE_DT(DT_GNU_CONFLICTSZ, 0x6FFFFDF6UL, \
+ "size of conflict section") \
+_ELF_DEFINE_DT(DT_GNU_LIBLISTSZ, 0x6FFFFDF7UL, \
+ "size of library list") \
+_ELF_DEFINE_DT(DT_CHECKSUM, 0x6FFFFDF8UL, \
+ "checksum for the object") \
+_ELF_DEFINE_DT(DT_PLTPADSZ, 0x6FFFFDF9UL, \
+ "size of PLT padding") \
+_ELF_DEFINE_DT(DT_MOVEENT, 0x6FFFFDFAUL, \
+ "size of DT_MOVETAB entries") \
+_ELF_DEFINE_DT(DT_MOVESZ, 0x6FFFFDFBUL, \
+ "total size of the MOVETAB table") \
+_ELF_DEFINE_DT(DT_FEATURE_1, 0x6FFFFDFCUL, "feature values") \
+_ELF_DEFINE_DT(DT_POSFLAG_1, 0x6FFFFDFDUL, \
+ "dynamic position flags") \
+_ELF_DEFINE_DT(DT_SYMINSZ, 0x6FFFFDFEUL, \
+ "size of the DT_SYMINFO table") \
+_ELF_DEFINE_DT(DT_SYMINENT, 0x6FFFFDFFUL, \
+ "size of a DT_SYMINFO entry") \
+_ELF_DEFINE_DT(DT_VALRNGHI, 0x6FFFFDFFUL, \
+ "end of range using the d_val field") \
+_ELF_DEFINE_DT(DT_ADDRRNGLO, 0x6FFFFE00UL, \
+ "start of range using the d_ptr field") \
+_ELF_DEFINE_DT(DT_GNU_HASH, 0x6FFFFEF5UL, \
+ "GNU style hash tables") \
+_ELF_DEFINE_DT(DT_GNU_CONFLICT, 0x6FFFFEF8UL, \
+ "address of conflict section") \
+_ELF_DEFINE_DT(DT_GNU_LIBLIST, 0x6FFFFEF9UL, \
+ "address of conflict section") \
+_ELF_DEFINE_DT(DT_CONFIG, 0x6FFFFEFAUL, \
+ "configuration file") \
+_ELF_DEFINE_DT(DT_DEPAUDIT, 0x6FFFFEFBUL, \
+ "string defining audit libraries") \
+_ELF_DEFINE_DT(DT_AUDIT, 0x6FFFFEFCUL, \
+ "string defining audit libraries") \
+_ELF_DEFINE_DT(DT_PLTPAD, 0x6FFFFEFDUL, "PLT padding") \
+_ELF_DEFINE_DT(DT_MOVETAB, 0x6FFFFEFEUL, \
+ "address of a move table") \
+_ELF_DEFINE_DT(DT_SYMINFO, 0x6FFFFEFFUL, \
+ "address of the symbol information table") \
+_ELF_DEFINE_DT(DT_ADDRRNGHI, 0x6FFFFEFFUL, \
+ "end of range using the d_ptr field") \
+_ELF_DEFINE_DT(DT_VERSYM, 0x6FFFFFF0UL, \
+ "address of the version section") \
+_ELF_DEFINE_DT(DT_RELACOUNT, 0x6FFFFFF9UL, \
+ "count of RELA relocations") \
+_ELF_DEFINE_DT(DT_RELCOUNT, 0x6FFFFFFAUL, \
+ "count of REL relocations") \
+_ELF_DEFINE_DT(DT_FLAGS_1, 0x6FFFFFFBUL, "flag values") \
+_ELF_DEFINE_DT(DT_VERDEF, 0x6FFFFFFCUL, \
+ "address of the version definition segment") \
+_ELF_DEFINE_DT(DT_VERDEFNUM, 0x6FFFFFFDUL, \
+ "the number of version definition entries") \
+_ELF_DEFINE_DT(DT_VERNEED, 0x6FFFFFFEUL, \
+ "address of section with needed versions") \
+_ELF_DEFINE_DT(DT_VERNEEDNUM, 0x6FFFFFFFUL, \
+ "the number of version needed entries") \
+_ELF_DEFINE_DT(DT_LOPROC, 0x70000000UL, \
+ "start of processor-specific types") \
+_ELF_DEFINE_DT(DT_ARM_SYMTABSZ, 0x70000001UL, \
+ "number of entries in the dynamic symbol table") \
+_ELF_DEFINE_DT(DT_SPARC_REGISTER, 0x70000001UL, \
+ "index of an STT_SPARC_REGISTER symbol") \
+_ELF_DEFINE_DT(DT_ARM_PREEMPTMAP, 0x70000002UL, \
+ "address of the preemption map") \
+_ELF_DEFINE_DT(DT_MIPS_RLD_VERSION, 0x70000001UL, \
+ "version ID for runtime linker interface") \
+_ELF_DEFINE_DT(DT_MIPS_TIME_STAMP, 0x70000002UL, \
+ "timestamp") \
+_ELF_DEFINE_DT(DT_MIPS_ICHECKSUM, 0x70000003UL, \
+ "checksum of all external strings and common sizes") \
+_ELF_DEFINE_DT(DT_MIPS_IVERSION, 0x70000004UL, \
+ "string table index of a version string") \
+_ELF_DEFINE_DT(DT_MIPS_FLAGS, 0x70000005UL, \
+ "MIPS-specific flags") \
+_ELF_DEFINE_DT(DT_MIPS_BASE_ADDRESS, 0x70000006UL, \
+ "base address for the executable/DSO") \
+_ELF_DEFINE_DT(DT_MIPS_CONFLICT, 0x70000008UL, \
+ "address of .conflict section") \
+_ELF_DEFINE_DT(DT_MIPS_LIBLIST, 0x70000009UL, \
+ "address of .liblist section") \
+_ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTNO, 0x7000000AUL, \
+ "number of local GOT entries") \
+_ELF_DEFINE_DT(DT_MIPS_CONFLICTNO, 0x7000000BUL, \
+ "number of entries in the .conflict section") \
+_ELF_DEFINE_DT(DT_MIPS_LIBLISTNO, 0x70000010UL, \
+ "number of entries in the .liblist section") \
+_ELF_DEFINE_DT(DT_MIPS_SYMTABNO, 0x70000011UL, \
+ "number of entries in the .dynsym section") \
+_ELF_DEFINE_DT(DT_MIPS_UNREFEXTNO, 0x70000012UL, \
+ "index of first external dynamic symbol not ref'ed locally") \
+_ELF_DEFINE_DT(DT_MIPS_GOTSYM, 0x70000013UL, \
+ "index of first dynamic symbol corresponds to a GOT entry") \
+_ELF_DEFINE_DT(DT_MIPS_HIPAGENO, 0x70000014UL, \
+ "number of page table entries in GOT") \
+_ELF_DEFINE_DT(DT_MIPS_RLD_MAP, 0x70000016UL, \
+ "address of runtime linker map") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS, 0x70000017UL, \
+ "Delta C++ class definition") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS_NO, 0x70000018UL, \
+ "number of entries in DT_MIPS_DELTA_CLASS") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE, 0x70000019UL, \
+ "Delta C++ class instances") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE_NO, 0x7000001AUL, \
+ "number of entries in DT_MIPS_DELTA_INSTANCE") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC, 0x7000001BUL, \
+ "Delta relocations") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC_NO, 0x7000001CUL, \
+ "number of entries in DT_MIPS_DELTA_RELOC") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_SYM, 0x7000001DUL, \
+ "Delta symbols refered by Delta relocations") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_SYM_NO, 0x7000001EUL, \
+ "number of entries in DT_MIPS_DELTA_SYM") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM, 0x70000020UL, \
+ "Delta symbols for class declarations") \
+_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM_NO, 0x70000021UL, \
+ "number of entries in DT_MIPS_DELTA_CLASSSYM") \
+_ELF_DEFINE_DT(DT_MIPS_CXX_FLAGS, 0x70000022UL, \
+ "C++ flavor flags") \
+_ELF_DEFINE_DT(DT_MIPS_PIXIE_INIT, 0x70000023UL, \
+ "address of an initialization routine created by pixie") \
+_ELF_DEFINE_DT(DT_MIPS_SYMBOL_LIB, 0x70000024UL, \
+ "address of .MIPS.symlib section") \
+_ELF_DEFINE_DT(DT_MIPS_LOCALPAGE_GOTIDX, 0x70000025UL, \
+ "GOT index of first page table entry for a segment") \
+_ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTIDX, 0x70000026UL, \
+ "GOT index of first page table entry for a local symbol") \
+_ELF_DEFINE_DT(DT_MIPS_HIDDEN_GOTIDX, 0x70000027UL, \
+ "GOT index of first page table entry for a hidden symbol") \
+_ELF_DEFINE_DT(DT_MIPS_PROTECTED_GOTIDX, 0x70000028UL, \
+ "GOT index of first page table entry for a protected symbol") \
+_ELF_DEFINE_DT(DT_MIPS_OPTIONS, 0x70000029UL, \
+ "address of .MIPS.options section") \
+_ELF_DEFINE_DT(DT_MIPS_INTERFACE, 0x7000002AUL, \
+ "address of .MIPS.interface section") \
+_ELF_DEFINE_DT(DT_MIPS_DYNSTR_ALIGN, 0x7000002BUL, "???") \
+_ELF_DEFINE_DT(DT_MIPS_INTERFACE_SIZE, 0x7000002CUL, \
+ "size of .MIPS.interface section") \
+_ELF_DEFINE_DT(DT_MIPS_RLD_TEXT_RESOLVE_ADDR, 0x7000002DUL, \
+ "address of _rld_text_resolve in GOT") \
+_ELF_DEFINE_DT(DT_MIPS_PERF_SUFFIX, 0x7000002EUL, \
+ "default suffix of DSO to be appended by dlopen") \
+_ELF_DEFINE_DT(DT_MIPS_COMPACT_SIZE, 0x7000002FUL, \
+ "size of a ucode compact relocation record (o32)") \
+_ELF_DEFINE_DT(DT_MIPS_GP_VALUE, 0x70000030UL, \
+ "GP value of a specified GP relative range") \
+_ELF_DEFINE_DT(DT_MIPS_AUX_DYNAMIC, 0x70000031UL, \
+ "address of an auxiliary dynamic table") \
+_ELF_DEFINE_DT(DT_MIPS_PLTGOT, 0x70000032UL, \
+ "address of the PLTGOT") \
+_ELF_DEFINE_DT(DT_MIPS_RLD_OBJ_UPDATE, 0x70000033UL, \
+ "object list update callback") \
+_ELF_DEFINE_DT(DT_MIPS_RWPLT, 0x70000034UL, \
+ "address of a writable PLT") \
+_ELF_DEFINE_DT(DT_PPC_GOT, 0x70000000UL, \
+ "value of _GLOBAL_OFFSET_TABLE_") \
+_ELF_DEFINE_DT(DT_PPC_TLSOPT, 0x70000001UL, \
+ "TLS descriptor should be optimized") \
+_ELF_DEFINE_DT(DT_PPC64_GLINK, 0x70000000UL, \
+ "address of .glink section") \
+_ELF_DEFINE_DT(DT_PPC64_OPD, 0x70000001UL, \
+ "address of .opd section") \
+_ELF_DEFINE_DT(DT_PPC64_OPDSZ, 0x70000002UL, \
+ "size of .opd section") \
+_ELF_DEFINE_DT(DT_PPC64_TLSOPT, 0x70000003UL, \
+ "TLS descriptor should be optimized") \
+_ELF_DEFINE_DT(DT_AUXILIARY, 0x7FFFFFFDUL, \
+ "offset of string naming auxiliary filtees") \
+_ELF_DEFINE_DT(DT_USED, 0x7FFFFFFEUL, "ignored") \
+_ELF_DEFINE_DT(DT_FILTER, 0x7FFFFFFFUL, \
+ "index of string naming filtees") \
+_ELF_DEFINE_DT(DT_HIPROC, 0x7FFFFFFFUL, \
+ "end of processor-specific types")
+
+#undef _ELF_DEFINE_DT
+#define _ELF_DEFINE_DT(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_DYN_TYPES()
+ DT__LAST__ = DT_HIPROC
+};
+
+#define DT_DEPRECATED_SPARC_REGISTER DT_SPARC_REGISTER
+
+/*
+ * Flags used in the executable header (field: e_flags).
+ */
+#define _ELF_DEFINE_EHDR_FLAGS() \
+_ELF_DEFINE_EF(EF_ARM_RELEXEC, 0x00000001UL, \
+ "dynamic segment describes only how to relocate segments") \
+_ELF_DEFINE_EF(EF_ARM_HASENTRY, 0x00000002UL, \
+ "e_entry contains a program entry point") \
+_ELF_DEFINE_EF(EF_ARM_SYMSARESORTED, 0x00000004UL, \
+ "subsection of symbol table is sorted by symbol value") \
+_ELF_DEFINE_EF(EF_ARM_DYNSYMSUSESEGIDX, 0x00000008UL, \
+ "dynamic symbol st_shndx = containing segment index + 1") \
+_ELF_DEFINE_EF(EF_ARM_MAPSYMSFIRST, 0x00000010UL, \
+ "mapping symbols precede other local symbols in symtab") \
+_ELF_DEFINE_EF(EF_ARM_BE8, 0x00800000UL, \
+ "file contains BE-8 code") \
+_ELF_DEFINE_EF(EF_ARM_LE8, 0x00400000UL, \
+ "file contains LE-8 code") \
+_ELF_DEFINE_EF(EF_ARM_EABIMASK, 0xFF000000UL, \
+ "mask for ARM EABI version number (0 denotes GNU or unknown)") \
+_ELF_DEFINE_EF(EF_ARM_INTERWORK, 0x00000004UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_APCS_26, 0x00000008UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_APCS_FLOAT, 0x00000010UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_PIC, 0x00000020UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_ALIGN8, 0x00000040UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_NEW_ABI, 0x00000080UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_OLD_ABI, 0x00000100UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_SOFT_FLOAT, 0x00000200UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_VFP_FLOAT, 0x00000400UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_ARM_MAVERICK_FLOAT, 0x00000800UL, \
+ "GNU EABI extension") \
+_ELF_DEFINE_EF(EF_MIPS_NOREORDER, 0x00000001UL, \
+ "at least one .noreorder directive appeared in the source") \
+_ELF_DEFINE_EF(EF_MIPS_PIC, 0x00000002UL, \
+ "file contains position independent code") \
+_ELF_DEFINE_EF(EF_MIPS_CPIC, 0x00000004UL, \
+ "file's code uses standard conventions for calling PIC") \
+_ELF_DEFINE_EF(EF_MIPS_UCODE, 0x00000010UL, \
+ "file contains UCODE (obsolete)") \
+_ELF_DEFINE_EF(EF_MIPS_ABI2, 0x00000020UL, \
+ "file follows MIPS III 32-bit ABI") \
+_ELF_DEFINE_EF(EF_MIPS_OPTIONS_FIRST, 0x00000080UL, \
+ "ld(1) should process .MIPS.options section first") \
+_ELF_DEFINE_EF(EF_MIPS_ARCH_ASE, 0x0F000000UL, \
+ "file uses application-specific architectural extensions") \
+_ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_MDMX, 0x08000000UL, \
+ "file uses MDMX multimedia extensions") \
+_ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_M16, 0x04000000UL, \
+ "file uses MIPS-16 ISA extensions") \
+_ELF_DEFINE_EF(EF_MIPS_ARCH, 0xF0000000UL, \
+ "4-bit MIPS architecture field") \
+_ELF_DEFINE_EF(EF_PPC_EMB, 0x80000000UL, \
+ "Embedded PowerPC flag") \
+_ELF_DEFINE_EF(EF_PPC_RELOCATABLE, 0x00010000UL, \
+ "-mrelocatable flag") \
+_ELF_DEFINE_EF(EF_PPC_RELOCATABLE_LIB, 0x00008000UL, \
+ "-mrelocatable-lib flag") \
+_ELF_DEFINE_EF(EF_SPARC_EXT_MASK, 0x00ffff00UL, \
+ "Vendor Extension mask") \
+_ELF_DEFINE_EF(EF_SPARC_32PLUS, 0x00000100UL, \
+ "Generic V8+ features") \
+_ELF_DEFINE_EF(EF_SPARC_SUN_US1, 0x00000200UL, \
+ "Sun UltraSPARCTM 1 Extensions") \
+_ELF_DEFINE_EF(EF_SPARC_HAL_R1, 0x00000400UL, "HAL R1 Extensions") \
+_ELF_DEFINE_EF(EF_SPARC_SUN_US3, 0x00000800UL, \
+ "Sun UltraSPARC 3 Extensions") \
+_ELF_DEFINE_EF(EF_SPARCV9_MM, 0x00000003UL, \
+ "Mask for Memory Model") \
+_ELF_DEFINE_EF(EF_SPARCV9_TSO, 0x00000000UL, \
+ "Total Store Ordering") \
+_ELF_DEFINE_EF(EF_SPARCV9_PSO, 0x00000001UL, \
+ "Partial Store Ordering") \
+_ELF_DEFINE_EF(EF_SPARCV9_RMO, 0x00000002UL, \
+ "Relaxed Memory Ordering")
+
+#undef _ELF_DEFINE_EF
+#define _ELF_DEFINE_EF(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_EHDR_FLAGS()
+ EF__LAST__
+};
+
+/*
+ * Offsets in the `ei_ident[]` field of an ELF executable header.
+ */
+#define _ELF_DEFINE_EI_OFFSETS() \
+_ELF_DEFINE_EI(EI_MAG0, 0, "magic number") \
+_ELF_DEFINE_EI(EI_MAG1, 1, "magic number") \
+_ELF_DEFINE_EI(EI_MAG2, 2, "magic number") \
+_ELF_DEFINE_EI(EI_MAG3, 3, "magic number") \
+_ELF_DEFINE_EI(EI_CLASS, 4, "file class") \
+_ELF_DEFINE_EI(EI_DATA, 5, "data encoding") \
+_ELF_DEFINE_EI(EI_VERSION, 6, "file version") \
+_ELF_DEFINE_EI(EI_OSABI, 7, "OS ABI kind") \
+_ELF_DEFINE_EI(EI_ABIVERSION, 8, "OS ABI version") \
+_ELF_DEFINE_EI(EI_PAD, 9, "padding start") \
+_ELF_DEFINE_EI(EI_NIDENT, 16, "total size")
+
+#undef _ELF_DEFINE_EI
+#define _ELF_DEFINE_EI(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_EI_OFFSETS()
+ EI__LAST__
+};
+
+/*
+ * The ELF class of an object.
+ */
+#define _ELF_DEFINE_ELFCLASS() \
+_ELF_DEFINE_EC(ELFCLASSNONE, 0, "Unknown ELF class") \
+_ELF_DEFINE_EC(ELFCLASS32, 1, "32 bit objects") \
+_ELF_DEFINE_EC(ELFCLASS64, 2, "64 bit objects")
+
+#undef _ELF_DEFINE_EC
+#define _ELF_DEFINE_EC(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ELFCLASS()
+ EC__LAST__
+};
+
+/*
+ * Endianness of data in an ELF object.
+ */
+
+#define _ELF_DEFINE_ELF_DATA_ENDIANNESS() \
+_ELF_DEFINE_ED(ELFDATANONE, 0, "Unknown data endianness") \
+_ELF_DEFINE_ED(ELFDATA2LSB, 1, "little endian") \
+_ELF_DEFINE_ED(ELFDATA2MSB, 2, "big endian")
+
+#undef _ELF_DEFINE_ED
+#define _ELF_DEFINE_ED(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ELF_DATA_ENDIANNESS()
+ ED__LAST__
+};
+
+/*
+ * Values of the magic numbers used in identification array.
+ */
+#define _ELF_DEFINE_ELF_MAGIC() \
+_ELF_DEFINE_EMAG(ELFMAG0, 0x7FU) \
+_ELF_DEFINE_EMAG(ELFMAG1, 'E') \
+_ELF_DEFINE_EMAG(ELFMAG2, 'L') \
+_ELF_DEFINE_EMAG(ELFMAG3, 'F')
+
+#undef _ELF_DEFINE_EMAG
+#define _ELF_DEFINE_EMAG(N, V) N = V ,
+enum {
+ _ELF_DEFINE_ELF_MAGIC()
+ ELFMAG__LAST__
+};
+
+/*
+ * ELF OS ABI field.
+ */
+#define _ELF_DEFINE_ELF_OSABI() \
+_ELF_DEFINE_EABI(ELFOSABI_NONE, 0, \
+ "No extensions or unspecified") \
+_ELF_DEFINE_EABI(ELFOSABI_SYSV, 0, "SYSV") \
+_ELF_DEFINE_EABI(ELFOSABI_HPUX, 1, "Hewlett-Packard HP-UX") \
+_ELF_DEFINE_EABI(ELFOSABI_NETBSD, 2, "NetBSD") \
+_ELF_DEFINE_EABI(ELFOSABI_GNU, 3, "GNU") \
+_ELF_DEFINE_EABI(ELFOSABI_HURD, 4, "GNU/HURD") \
+_ELF_DEFINE_EABI(ELFOSABI_86OPEN, 5, "86Open Common ABI") \
+_ELF_DEFINE_EABI(ELFOSABI_SOLARIS, 6, "Sun Solaris") \
+_ELF_DEFINE_EABI(ELFOSABI_AIX, 7, "AIX") \
+_ELF_DEFINE_EABI(ELFOSABI_IRIX, 8, "IRIX") \
+_ELF_DEFINE_EABI(ELFOSABI_FREEBSD, 9, "FreeBSD") \
+_ELF_DEFINE_EABI(ELFOSABI_TRU64, 10, "Compaq TRU64 UNIX") \
+_ELF_DEFINE_EABI(ELFOSABI_MODESTO, 11, "Novell Modesto") \
+_ELF_DEFINE_EABI(ELFOSABI_OPENBSD, 12, "Open BSD") \
+_ELF_DEFINE_EABI(ELFOSABI_OPENVMS, 13, "Open VMS") \
+_ELF_DEFINE_EABI(ELFOSABI_NSK, 14, \
+ "Hewlett-Packard Non-Stop Kernel") \
+_ELF_DEFINE_EABI(ELFOSABI_AROS, 15, "Amiga Research OS") \
+_ELF_DEFINE_EABI(ELFOSABI_FENIXOS, 16, \
+ "The FenixOS highly scalable multi-core OS") \
+_ELF_DEFINE_EABI(ELFOSABI_ARM_AEABI, 64, \
+ "ARM specific symbol versioning extensions") \
+_ELF_DEFINE_EABI(ELFOSABI_ARM, 97, "ARM ABI") \
+_ELF_DEFINE_EABI(ELFOSABI_STANDALONE, 255, \
+ "Standalone (embedded) application")
+
+#undef _ELF_DEFINE_EABI
+#define _ELF_DEFINE_EABI(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ELF_OSABI()
+ ELFOSABI__LAST__
+};
+
+#define ELFOSABI_LINUX ELFOSABI_GNU
+
+/*
+ * ELF Machine types: (EM_*).
+ */
+#define _ELF_DEFINE_ELF_MACHINES() \
+_ELF_DEFINE_EM(EM_NONE, 0, "No machine") \
+_ELF_DEFINE_EM(EM_M32, 1, "AT&T WE 32100") \
+_ELF_DEFINE_EM(EM_SPARC, 2, "SPARC") \
+_ELF_DEFINE_EM(EM_386, 3, "Intel 80386") \
+_ELF_DEFINE_EM(EM_68K, 4, "Motorola 68000") \
+_ELF_DEFINE_EM(EM_88K, 5, "Motorola 88000") \
+_ELF_DEFINE_EM(EM_860, 7, "Intel 80860") \
+_ELF_DEFINE_EM(EM_MIPS, 8, "MIPS I Architecture") \
+_ELF_DEFINE_EM(EM_S370, 9, "IBM System/370 Processor") \
+_ELF_DEFINE_EM(EM_MIPS_RS3_LE, 10, "MIPS RS3000 Little-endian") \
+_ELF_DEFINE_EM(EM_PARISC, 15, "Hewlett-Packard PA-RISC") \
+_ELF_DEFINE_EM(EM_VPP500, 17, "Fujitsu VPP500") \
+_ELF_DEFINE_EM(EM_SPARC32PLUS, 18, \
+ "Enhanced instruction set SPARC") \
+_ELF_DEFINE_EM(EM_960, 19, "Intel 80960") \
+_ELF_DEFINE_EM(EM_PPC, 20, "PowerPC") \
+_ELF_DEFINE_EM(EM_PPC64, 21, "64-bit PowerPC") \
+_ELF_DEFINE_EM(EM_S390, 22, "IBM System/390 Processor") \
+_ELF_DEFINE_EM(EM_SPU, 23, "IBM SPU/SPC") \
+_ELF_DEFINE_EM(EM_V800, 36, "NEC V800") \
+_ELF_DEFINE_EM(EM_FR20, 37, "Fujitsu FR20") \
+_ELF_DEFINE_EM(EM_RH32, 38, "TRW RH-32") \
+_ELF_DEFINE_EM(EM_RCE, 39, "Motorola RCE") \
+_ELF_DEFINE_EM(EM_ARM, 40, "Advanced RISC Machines ARM") \
+_ELF_DEFINE_EM(EM_ALPHA, 41, "Digital Alpha") \
+_ELF_DEFINE_EM(EM_SH, 42, "Hitachi SH") \
+_ELF_DEFINE_EM(EM_SPARCV9, 43, "SPARC Version 9") \
+_ELF_DEFINE_EM(EM_TRICORE, 44, \
+ "Siemens TriCore embedded processor") \
+_ELF_DEFINE_EM(EM_ARC, 45, \
+ "Argonaut RISC Core, Argonaut Technologies Inc.") \
+_ELF_DEFINE_EM(EM_H8_300, 46, "Hitachi H8/300") \
+_ELF_DEFINE_EM(EM_H8_300H, 47, "Hitachi H8/300H") \
+_ELF_DEFINE_EM(EM_H8S, 48, "Hitachi H8S") \
+_ELF_DEFINE_EM(EM_H8_500, 49, "Hitachi H8/500") \
+_ELF_DEFINE_EM(EM_IA_64, 50, \
+ "Intel IA-64 processor architecture") \
+_ELF_DEFINE_EM(EM_MIPS_X, 51, "Stanford MIPS-X") \
+_ELF_DEFINE_EM(EM_COLDFIRE, 52, "Motorola ColdFire") \
+_ELF_DEFINE_EM(EM_68HC12, 53, "Motorola M68HC12") \
+_ELF_DEFINE_EM(EM_MMA, 54, \
+ "Fujitsu MMA Multimedia Accelerator") \
+_ELF_DEFINE_EM(EM_PCP, 55, "Siemens PCP") \
+_ELF_DEFINE_EM(EM_NCPU, 56, \
+ "Sony nCPU embedded RISC processor") \
+_ELF_DEFINE_EM(EM_NDR1, 57, "Denso NDR1 microprocessor") \
+_ELF_DEFINE_EM(EM_STARCORE, 58, "Motorola Star*Core processor") \
+_ELF_DEFINE_EM(EM_ME16, 59, "Toyota ME16 processor") \
+_ELF_DEFINE_EM(EM_ST100, 60, \
+ "STMicroelectronics ST100 processor") \
+_ELF_DEFINE_EM(EM_TINYJ, 61, \
+ "Advanced Logic Corp. TinyJ embedded processor family") \
+_ELF_DEFINE_EM(EM_X86_64, 62, "AMD x86-64 architecture") \
+_ELF_DEFINE_EM(EM_PDSP, 63, "Sony DSP Processor") \
+_ELF_DEFINE_EM(EM_PDP10, 64, \
+ "Digital Equipment Corp. PDP-10") \
+_ELF_DEFINE_EM(EM_PDP11, 65, \
+ "Digital Equipment Corp. PDP-11") \
+_ELF_DEFINE_EM(EM_FX66, 66, "Siemens FX66 microcontroller") \
+_ELF_DEFINE_EM(EM_ST9PLUS, 67, \
+ "STMicroelectronics ST9+ 8/16 bit microcontroller") \
+_ELF_DEFINE_EM(EM_ST7, 68, \
+ "STMicroelectronics ST7 8-bit microcontroller") \
+_ELF_DEFINE_EM(EM_68HC16, 69, \
+ "Motorola MC68HC16 Microcontroller") \
+_ELF_DEFINE_EM(EM_68HC11, 70, \
+ "Motorola MC68HC11 Microcontroller") \
+_ELF_DEFINE_EM(EM_68HC08, 71, \
+ "Motorola MC68HC08 Microcontroller") \
+_ELF_DEFINE_EM(EM_68HC05, 72, \
+ "Motorola MC68HC05 Microcontroller") \
+_ELF_DEFINE_EM(EM_SVX, 73, "Silicon Graphics SVx") \
+_ELF_DEFINE_EM(EM_ST19, 74, \
+ "STMicroelectronics ST19 8-bit microcontroller") \
+_ELF_DEFINE_EM(EM_VAX, 75, "Digital VAX") \
+_ELF_DEFINE_EM(EM_CRIS, 76, \
+ "Axis Communications 32-bit embedded processor") \
+_ELF_DEFINE_EM(EM_JAVELIN, 77, \
+ "Infineon Technologies 32-bit embedded processor") \
+_ELF_DEFINE_EM(EM_FIREPATH, 78, \
+ "Element 14 64-bit DSP Processor") \
+_ELF_DEFINE_EM(EM_ZSP, 79, \
+ "LSI Logic 16-bit DSP Processor") \
+_ELF_DEFINE_EM(EM_MMIX, 80, \
+ "Donald Knuth's educational 64-bit processor") \
+_ELF_DEFINE_EM(EM_HUANY, 81, \
+ "Harvard University machine-independent object files") \
+_ELF_DEFINE_EM(EM_PRISM, 82, "SiTera Prism") \
+_ELF_DEFINE_EM(EM_AVR, 83, \
+ "Atmel AVR 8-bit microcontroller") \
+_ELF_DEFINE_EM(EM_FR30, 84, "Fujitsu FR30") \
+_ELF_DEFINE_EM(EM_D10V, 85, "Mitsubishi D10V") \
+_ELF_DEFINE_EM(EM_D30V, 86, "Mitsubishi D30V") \
+_ELF_DEFINE_EM(EM_V850, 87, "NEC v850") \
+_ELF_DEFINE_EM(EM_M32R, 88, "Mitsubishi M32R") \
+_ELF_DEFINE_EM(EM_MN10300, 89, "Matsushita MN10300") \
+_ELF_DEFINE_EM(EM_MN10200, 90, "Matsushita MN10200") \
+_ELF_DEFINE_EM(EM_PJ, 91, "picoJava") \
+_ELF_DEFINE_EM(EM_OPENRISC, 92, \
+ "OpenRISC 32-bit embedded processor") \
+_ELF_DEFINE_EM(EM_ARC_COMPACT, 93, \
+ "ARC International ARCompact processor") \
+_ELF_DEFINE_EM(EM_XTENSA, 94, \
+ "Tensilica Xtensa Architecture") \
+_ELF_DEFINE_EM(EM_VIDEOCORE, 95, \
+ "Alphamosaic VideoCore processor") \
+_ELF_DEFINE_EM(EM_TMM_GPP, 96, \
+ "Thompson Multimedia General Purpose Processor") \
+_ELF_DEFINE_EM(EM_NS32K, 97, \
+ "National Semiconductor 32000 series") \
+_ELF_DEFINE_EM(EM_TPC, 98, "Tenor Network TPC processor") \
+_ELF_DEFINE_EM(EM_SNP1K, 99, "Trebia SNP 1000 processor") \
+_ELF_DEFINE_EM(EM_ST200, 100, \
+ "STMicroelectronics (www.st.com) ST200 microcontroller") \
+_ELF_DEFINE_EM(EM_IP2K, 101, \
+ "Ubicom IP2xxx microcontroller family") \
+_ELF_DEFINE_EM(EM_MAX, 102, "MAX Processor") \
+_ELF_DEFINE_EM(EM_CR, 103, \
+ "National Semiconductor CompactRISC microprocessor") \
+_ELF_DEFINE_EM(EM_F2MC16, 104, "Fujitsu F2MC16") \
+_ELF_DEFINE_EM(EM_MSP430, 105, \
+ "Texas Instruments embedded microcontroller msp430") \
+_ELF_DEFINE_EM(EM_BLACKFIN, 106, \
+ "Analog Devices Blackfin (DSP) processor") \
+_ELF_DEFINE_EM(EM_SE_C33, 107, \
+ "S1C33 Family of Seiko Epson processors") \
+_ELF_DEFINE_EM(EM_SEP, 108, \
+ "Sharp embedded microprocessor") \
+_ELF_DEFINE_EM(EM_ARCA, 109, "Arca RISC Microprocessor") \
+_ELF_DEFINE_EM(EM_UNICORE, 110, \
+ "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University") \
+_ELF_DEFINE_EM(EM_EXCESS, 111, \
+ "eXcess: 16/32/64-bit configurable embedded CPU") \
+_ELF_DEFINE_EM(EM_DXP, 112, \
+ "Icera Semiconductor Inc. Deep Execution Processor") \
+_ELF_DEFINE_EM(EM_ALTERA_NIOS2, 113, \
+ "Altera Nios II soft-core processor") \
+_ELF_DEFINE_EM(EM_CRX, 114, \
+ "National Semiconductor CompactRISC CRX microprocessor") \
+_ELF_DEFINE_EM(EM_XGATE, 115, \
+ "Motorola XGATE embedded processor") \
+_ELF_DEFINE_EM(EM_C166, 116, \
+ "Infineon C16x/XC16x processor") \
+_ELF_DEFINE_EM(EM_M16C, 117, \
+ "Renesas M16C series microprocessors") \
+_ELF_DEFINE_EM(EM_DSPIC30F, 118, \
+ "Microchip Technology dsPIC30F Digital Signal Controller") \
+_ELF_DEFINE_EM(EM_CE, 119, \
+ "Freescale Communication Engine RISC core") \
+_ELF_DEFINE_EM(EM_M32C, 120, \
+ "Renesas M32C series microprocessors") \
+_ELF_DEFINE_EM(EM_TSK3000, 131, "Altium TSK3000 core") \
+_ELF_DEFINE_EM(EM_RS08, 132, \
+ "Freescale RS08 embedded processor") \
+_ELF_DEFINE_EM(EM_SHARC, 133, \
+ "Analog Devices SHARC family of 32-bit DSP processors") \
+_ELF_DEFINE_EM(EM_ECOG2, 134, \
+ "Cyan Technology eCOG2 microprocessor") \
+_ELF_DEFINE_EM(EM_SCORE7, 135, \
+ "Sunplus S+core7 RISC processor") \
+_ELF_DEFINE_EM(EM_DSP24, 136, \
+ "New Japan Radio (NJR) 24-bit DSP Processor") \
+_ELF_DEFINE_EM(EM_VIDEOCORE3, 137, \
+ "Broadcom VideoCore III processor") \
+_ELF_DEFINE_EM(EM_LATTICEMICO32, 138, \
+ "RISC processor for Lattice FPGA architecture") \
+_ELF_DEFINE_EM(EM_SE_C17, 139, "Seiko Epson C17 family") \
+_ELF_DEFINE_EM(EM_TI_C6000, 140, \
+ "The Texas Instruments TMS320C6000 DSP family") \
+_ELF_DEFINE_EM(EM_TI_C2000, 141, \
+ "The Texas Instruments TMS320C2000 DSP family") \
+_ELF_DEFINE_EM(EM_TI_C5500, 142, \
+ "The Texas Instruments TMS320C55x DSP family") \
+_ELF_DEFINE_EM(EM_MMDSP_PLUS, 160, \
+ "STMicroelectronics 64bit VLIW Data Signal Processor") \
+_ELF_DEFINE_EM(EM_CYPRESS_M8C, 161, "Cypress M8C microprocessor") \
+_ELF_DEFINE_EM(EM_R32C, 162, \
+ "Renesas R32C series microprocessors") \
+_ELF_DEFINE_EM(EM_TRIMEDIA, 163, \
+ "NXP Semiconductors TriMedia architecture family") \
+_ELF_DEFINE_EM(EM_QDSP6, 164, "QUALCOMM DSP6 Processor") \
+_ELF_DEFINE_EM(EM_8051, 165, "Intel 8051 and variants") \
+_ELF_DEFINE_EM(EM_STXP7X, 166, \
+ "STMicroelectronics STxP7x family of configurable and extensible RISC processors") \
+_ELF_DEFINE_EM(EM_NDS32, 167, \
+ "Andes Technology compact code size embedded RISC processor family") \
+_ELF_DEFINE_EM(EM_ECOG1, 168, \
+ "Cyan Technology eCOG1X family") \
+_ELF_DEFINE_EM(EM_ECOG1X, 168, \
+ "Cyan Technology eCOG1X family") \
+_ELF_DEFINE_EM(EM_MAXQ30, 169, \
+ "Dallas Semiconductor MAXQ30 Core Micro-controllers") \
+_ELF_DEFINE_EM(EM_XIMO16, 170, \
+ "New Japan Radio (NJR) 16-bit DSP Processor") \
+_ELF_DEFINE_EM(EM_MANIK, 171, \
+ "M2000 Reconfigurable RISC Microprocessor") \
+_ELF_DEFINE_EM(EM_CRAYNV2, 172, \
+ "Cray Inc. NV2 vector architecture") \
+_ELF_DEFINE_EM(EM_RX, 173, "Renesas RX family") \
+_ELF_DEFINE_EM(EM_METAG, 174, \
+ "Imagination Technologies META processor architecture") \
+_ELF_DEFINE_EM(EM_MCST_ELBRUS, 175, \
+ "MCST Elbrus general purpose hardware architecture") \
+_ELF_DEFINE_EM(EM_ECOG16, 176, \
+ "Cyan Technology eCOG16 family") \
+_ELF_DEFINE_EM(EM_CR16, 177, \
+ "National Semiconductor CompactRISC CR16 16-bit microprocessor") \
+_ELF_DEFINE_EM(EM_ETPU, 178, \
+ "Freescale Extended Time Processing Unit") \
+_ELF_DEFINE_EM(EM_SLE9X, 179, \
+ "Infineon Technologies SLE9X core") \
+_ELF_DEFINE_EM(EM_AVR32, 185, \
+ "Atmel Corporation 32-bit microprocessor family") \
+_ELF_DEFINE_EM(EM_STM8, 186, \
+ "STMicroeletronics STM8 8-bit microcontroller") \
+_ELF_DEFINE_EM(EM_TILE64, 187, \
+ "Tilera TILE64 multicore architecture family") \
+_ELF_DEFINE_EM(EM_TILEPRO, 188, \
+ "Tilera TILEPro multicore architecture family") \
+_ELF_DEFINE_EM(EM_MICROBLAZE, 189, \
+ "Xilinx MicroBlaze 32-bit RISC soft processor core") \
+_ELF_DEFINE_EM(EM_CUDA, 190, "NVIDIA CUDA architecture") \
+_ELF_DEFINE_EM(EM_TILEGX, 191, \
+ "Tilera TILE-Gx multicore architecture family") \
+_ELF_DEFINE_EM(EM_CLOUDSHIELD, 192, \
+ "CloudShield architecture family") \
+_ELF_DEFINE_EM(EM_COREA_1ST, 193, \
+ "KIPO-KAIST Core-A 1st generation processor family") \
+_ELF_DEFINE_EM(EM_COREA_2ND, 194, \
+ "KIPO-KAIST Core-A 2nd generation processor family") \
+_ELF_DEFINE_EM(EM_ARC_COMPACT2, 195, "Synopsys ARCompact V2") \
+_ELF_DEFINE_EM(EM_OPEN8, 196, \
+ "Open8 8-bit RISC soft processor core") \
+_ELF_DEFINE_EM(EM_RL78, 197, "Renesas RL78 family") \
+_ELF_DEFINE_EM(EM_VIDEOCORE5, 198, "Broadcom VideoCore V processor") \
+_ELF_DEFINE_EM(EM_78KOR, 199, "Renesas 78KOR family")
+
+#undef _ELF_DEFINE_EM
+#define _ELF_DEFINE_EM(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ELF_MACHINES()
+ EM__LAST__
+};
+
+/* Older synonyms. */
+#define EM_ARC_A5 EM_ARC_COMPACT
+
+/*
+ * ELF file types: (ET_*).
+ */
+#define _ELF_DEFINE_ELF_TYPES() \
+_ELF_DEFINE_ET(ET_NONE, 0, "No file type") \
+_ELF_DEFINE_ET(ET_REL, 1, "Relocatable object") \
+_ELF_DEFINE_ET(ET_EXEC, 2, "Executable") \
+_ELF_DEFINE_ET(ET_DYN, 3, "Shared object") \
+_ELF_DEFINE_ET(ET_CORE, 4, "Core file") \
+_ELF_DEFINE_ET(ET_LOOS, 0xFE00U, "Begin OS-specific range") \
+_ELF_DEFINE_ET(ET_HIOS, 0xFEFFU, "End OS-specific range") \
+_ELF_DEFINE_ET(ET_LOPROC, 0xFF00U, "Begin processor-specific range") \
+_ELF_DEFINE_ET(ET_HIPROC, 0xFFFFU, "End processor-specific range")
+
+#undef _ELF_DEFINE_ET
+#define _ELF_DEFINE_ET(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ELF_TYPES()
+ ET__LAST__
+};
+
+/* ELF file format version numbers. */
+#define EV_NONE 0
+#define EV_CURRENT 1
+
+/*
+ * Flags for section groups.
+ */
+#define GRP_COMDAT 0x1 /* COMDAT semantics */
+#define GRP_MASKOS 0x0ff00000 /* OS-specific flags */
+#define GRP_MASKPROC 0xf0000000 /* processor-specific flags */
+
+/*
+ * Flags used by program header table entries.
+ */
+
+#define _ELF_DEFINE_PHDR_FLAGS() \
+_ELF_DEFINE_PF(PF_X, 0x1, "Execute") \
+_ELF_DEFINE_PF(PF_W, 0x2, "Write") \
+_ELF_DEFINE_PF(PF_R, 0x4, "Read") \
+_ELF_DEFINE_PF(PF_MASKOS, 0x0ff00000, "OS-specific flags") \
+_ELF_DEFINE_PF(PF_MASKPROC, 0xf0000000, "Processor-specific flags") \
+_ELF_DEFINE_PF(PF_ARM_SB, 0x10000000, \
+ "segment contains the location addressed by the static base") \
+_ELF_DEFINE_PF(PF_ARM_PI, 0x20000000, \
+ "segment is position-independent") \
+_ELF_DEFINE_PF(PF_ARM_ABS, 0x40000000, \
+ "segment must be loaded at its base address")
+
+#undef _ELF_DEFINE_PF
+#define _ELF_DEFINE_PF(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_PHDR_FLAGS()
+ PF__LAST__
+};
+
+/*
+ * Types of program header table entries.
+ */
+
+#define _ELF_DEFINE_PHDR_TYPES() \
+_ELF_DEFINE_PT(PT_NULL, 0, "ignored entry") \
+_ELF_DEFINE_PT(PT_LOAD, 1, "loadable segment") \
+_ELF_DEFINE_PT(PT_DYNAMIC, 2, \
+ "contains dynamic linking information") \
+_ELF_DEFINE_PT(PT_INTERP, 3, "names an interpreter") \
+_ELF_DEFINE_PT(PT_NOTE, 4, "auxiliary information") \
+_ELF_DEFINE_PT(PT_SHLIB, 5, "reserved") \
+_ELF_DEFINE_PT(PT_PHDR, 6, \
+ "describes the program header itself") \
+_ELF_DEFINE_PT(PT_TLS, 7, "thread local storage") \
+_ELF_DEFINE_PT(PT_LOOS, 0x60000000UL, \
+ "start of OS-specific range") \
+_ELF_DEFINE_PT(PT_SUNW_UNWIND, 0x6464E550UL, \
+ "Solaris/amd64 stack unwind tables") \
+_ELF_DEFINE_PT(PT_GNU_EH_FRAME, 0x6474E550UL, \
+ "GCC generated .eh_frame_hdr segment") \
+_ELF_DEFINE_PT(PT_GNU_STACK, 0x6474E551UL, \
+ "Stack flags") \
+_ELF_DEFINE_PT(PT_GNU_RELRO, 0x6474E552UL, \
+ "Segment becomes read-only after relocation") \
+_ELF_DEFINE_PT(PT_SUNWBSS, 0x6FFFFFFAUL, \
+ "A Solaris .SUNW_bss section") \
+_ELF_DEFINE_PT(PT_SUNWSTACK, 0x6FFFFFFBUL, \
+ "A Solaris process stack") \
+_ELF_DEFINE_PT(PT_SUNWDTRACE, 0x6FFFFFFCUL, \
+ "Used by dtrace(1)") \
+_ELF_DEFINE_PT(PT_SUNWCAP, 0x6FFFFFFDUL, \
+ "Special hardware capability requirements") \
+_ELF_DEFINE_PT(PT_HIOS, 0x6FFFFFFFUL, \
+ "end of OS-specific range") \
+_ELF_DEFINE_PT(PT_LOPROC, 0x70000000UL, \
+ "start of processor-specific range") \
+_ELF_DEFINE_PT(PT_ARM_ARCHEXT, 0x70000000UL, \
+ "platform architecture compatibility information") \
+_ELF_DEFINE_PT(PT_ARM_EXIDX, 0x70000001UL, \
+ "exception unwind tables") \
+_ELF_DEFINE_PT(PT_MIPS_REGINFO, 0x70000000UL, \
+ "register usage information") \
+_ELF_DEFINE_PT(PT_MIPS_RTPROC, 0x70000001UL, \
+ "runtime procedure table") \
+_ELF_DEFINE_PT(PT_MIPS_OPTIONS, 0x70000002UL, \
+ "options segment") \
+_ELF_DEFINE_PT(PT_HIPROC, 0x7FFFFFFFUL, \
+ "end of processor-specific range")
+
+#undef _ELF_DEFINE_PT
+#define _ELF_DEFINE_PT(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_PHDR_TYPES()
+ PT__LAST__ = PT_HIPROC
+};
+
+/* synonyms. */
+#define PT_ARM_UNWIND PT_ARM_EXIDX
+#define PT_HISUNW PT_HIOS
+#define PT_LOSUNW PT_SUNWBSS
+
+/*
+ * Section flags.
+ */
+
+#define _ELF_DEFINE_SECTION_FLAGS() \
+_ELF_DEFINE_SHF(SHF_WRITE, 0x1, \
+ "writable during program execution") \
+_ELF_DEFINE_SHF(SHF_ALLOC, 0x2, \
+ "occupies memory during program execution") \
+_ELF_DEFINE_SHF(SHF_EXECINSTR, 0x4, "executable instructions") \
+_ELF_DEFINE_SHF(SHF_MERGE, 0x10, \
+ "may be merged to prevent duplication") \
+_ELF_DEFINE_SHF(SHF_STRINGS, 0x20, \
+ "NUL-terminated character strings") \
+_ELF_DEFINE_SHF(SHF_INFO_LINK, 0x40, \
+ "the sh_info field holds a link") \
+_ELF_DEFINE_SHF(SHF_LINK_ORDER, 0x80, \
+ "special ordering requirements during linking") \
+_ELF_DEFINE_SHF(SHF_OS_NONCONFORMING, 0x100, \
+ "requires OS-specific processing during linking") \
+_ELF_DEFINE_SHF(SHF_GROUP, 0x200, \
+ "member of a section group") \
+_ELF_DEFINE_SHF(SHF_TLS, 0x400, \
+ "holds thread-local storage") \
+_ELF_DEFINE_SHF(SHF_MASKOS, 0x0FF00000UL, \
+ "bits reserved for OS-specific semantics") \
+_ELF_DEFINE_SHF(SHF_AMD64_LARGE, 0x10000000UL, \
+ "section uses large code model") \
+_ELF_DEFINE_SHF(SHF_ENTRYSECT, 0x10000000UL, \
+ "section contains an entry point (ARM)") \
+_ELF_DEFINE_SHF(SHF_COMDEF, 0x80000000UL, \
+ "section may be multiply defined in input to link step (ARM)") \
+_ELF_DEFINE_SHF(SHF_MIPS_GPREL, 0x10000000UL, \
+ "section must be part of global data area") \
+_ELF_DEFINE_SHF(SHF_MIPS_MERGE, 0x20000000UL, \
+ "section data should be merged to eliminate duplication") \
+_ELF_DEFINE_SHF(SHF_MIPS_ADDR, 0x40000000UL, \
+ "section data is addressed by default") \
+_ELF_DEFINE_SHF(SHF_MIPS_STRING, 0x80000000UL, \
+ "section data is string data by default") \
+_ELF_DEFINE_SHF(SHF_MIPS_NOSTRIP, 0x08000000UL, \
+ "section data may not be stripped") \
+_ELF_DEFINE_SHF(SHF_MIPS_LOCAL, 0x04000000UL, \
+ "section data local to process") \
+_ELF_DEFINE_SHF(SHF_MIPS_NAMES, 0x02000000UL, \
+ "linker must generate implicit hidden weak names") \
+_ELF_DEFINE_SHF(SHF_MIPS_NODUPE, 0x01000000UL, \
+ "linker must retain only one copy") \
+_ELF_DEFINE_SHF(SHF_ORDERED, 0x40000000UL, \
+ "section is ordered with respect to other sections") \
+_ELF_DEFINE_SHF(SHF_EXCLUDE, 0x80000000UL, \
+ "section is excluded from executables and shared objects") \
+_ELF_DEFINE_SHF(SHF_MASKPROC, 0xF0000000UL, \
+ "bits reserved for processor-specific semantics")
+
+#undef _ELF_DEFINE_SHF
+#define _ELF_DEFINE_SHF(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SECTION_FLAGS()
+ SHF__LAST__
+};
+
+/*
+ * Special section indices.
+ */
+#define _ELF_DEFINE_SECTION_INDICES() \
+_ELF_DEFINE_SHN(SHN_UNDEF, 0, "undefined section") \
+_ELF_DEFINE_SHN(SHN_LORESERVE, 0xFF00U, "start of reserved area") \
+_ELF_DEFINE_SHN(SHN_LOPROC, 0xFF00U, \
+ "start of processor-specific range") \
+_ELF_DEFINE_SHN(SHN_BEFORE, 0xFF00U, "used for section ordering") \
+_ELF_DEFINE_SHN(SHN_AFTER, 0xFF01U, "used for section ordering") \
+_ELF_DEFINE_SHN(SHN_AMD64_LCOMMON, 0xFF02U, "large common block label") \
+_ELF_DEFINE_SHN(SHN_MIPS_ACOMMON, 0xFF00U, \
+ "allocated common symbols in a DSO") \
+_ELF_DEFINE_SHN(SHN_MIPS_TEXT, 0xFF01U, "Reserved (obsolete)") \
+_ELF_DEFINE_SHN(SHN_MIPS_DATA, 0xFF02U, "Reserved (obsolete)") \
+_ELF_DEFINE_SHN(SHN_MIPS_SCOMMON, 0xFF03U, \
+ "gp-addressable common symbols") \
+_ELF_DEFINE_SHN(SHN_MIPS_SUNDEFINED, 0xFF04U, \
+ "gp-addressable undefined symbols") \
+_ELF_DEFINE_SHN(SHN_MIPS_LCOMMON, 0xFF05U, "local common symbols") \
+_ELF_DEFINE_SHN(SHN_MIPS_LUNDEFINED, 0xFF06U, \
+ "local undefined symbols") \
+_ELF_DEFINE_SHN(SHN_HIPROC, 0xFF1FU, \
+ "end of processor-specific range") \
+_ELF_DEFINE_SHN(SHN_LOOS, 0xFF20U, \
+ "start of OS-specific range") \
+_ELF_DEFINE_SHN(SHN_SUNW_IGNORE, 0xFF3FU, "used by dtrace") \
+_ELF_DEFINE_SHN(SHN_HIOS, 0xFF3FU, \
+ "end of OS-specific range") \
+_ELF_DEFINE_SHN(SHN_ABS, 0xFFF1U, "absolute references") \
+_ELF_DEFINE_SHN(SHN_COMMON, 0xFFF2U, "references to COMMON areas") \
+_ELF_DEFINE_SHN(SHN_XINDEX, 0xFFFFU, "extended index") \
+_ELF_DEFINE_SHN(SHN_HIRESERVE, 0xFFFFU, "end of reserved area")
+
+#undef _ELF_DEFINE_SHN
+#define _ELF_DEFINE_SHN(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SECTION_INDICES()
+ SHN__LAST__
+};
+
+/*
+ * Section types.
+ */
+
+#define _ELF_DEFINE_SECTION_TYPES() \
+_ELF_DEFINE_SHT(SHT_NULL, 0, "inactive header") \
+_ELF_DEFINE_SHT(SHT_PROGBITS, 1, "program defined information") \
+_ELF_DEFINE_SHT(SHT_SYMTAB, 2, "symbol table") \
+_ELF_DEFINE_SHT(SHT_STRTAB, 3, "string table") \
+_ELF_DEFINE_SHT(SHT_RELA, 4, \
+ "relocation entries with addends") \
+_ELF_DEFINE_SHT(SHT_HASH, 5, "symbol hash table") \
+_ELF_DEFINE_SHT(SHT_DYNAMIC, 6, \
+ "information for dynamic linking") \
+_ELF_DEFINE_SHT(SHT_NOTE, 7, "additional notes") \
+_ELF_DEFINE_SHT(SHT_NOBITS, 8, "section occupying no space") \
+_ELF_DEFINE_SHT(SHT_REL, 9, \
+ "relocation entries without addends") \
+_ELF_DEFINE_SHT(SHT_SHLIB, 10, "reserved") \
+_ELF_DEFINE_SHT(SHT_DYNSYM, 11, "symbol table") \
+_ELF_DEFINE_SHT(SHT_INIT_ARRAY, 14, \
+ "pointers to initialization functions") \
+_ELF_DEFINE_SHT(SHT_FINI_ARRAY, 15, \
+ "pointers to termination functions") \
+_ELF_DEFINE_SHT(SHT_PREINIT_ARRAY, 16, \
+ "pointers to functions called before initialization") \
+_ELF_DEFINE_SHT(SHT_GROUP, 17, "defines a section group") \
+_ELF_DEFINE_SHT(SHT_SYMTAB_SHNDX, 18, \
+ "used for extended section numbering") \
+_ELF_DEFINE_SHT(SHT_LOOS, 0x60000000UL, \
+ "start of OS-specific range") \
+_ELF_DEFINE_SHT(SHT_SUNW_dof, 0x6FFFFFF4UL, \
+ "used by dtrace") \
+_ELF_DEFINE_SHT(SHT_SUNW_cap, 0x6FFFFFF5UL, \
+ "capability requirements") \
+_ELF_DEFINE_SHT(SHT_GNU_ATTRIBUTES, 0x6FFFFFF5UL, \
+ "object attributes") \
+_ELF_DEFINE_SHT(SHT_SUNW_SIGNATURE, 0x6FFFFFF6UL, \
+ "module verification signature") \
+_ELF_DEFINE_SHT(SHT_GNU_HASH, 0x6FFFFFF6UL, \
+ "GNU Hash sections") \
+_ELF_DEFINE_SHT(SHT_GNU_LIBLIST, 0x6FFFFFF7UL, \
+ "List of libraries to be prelinked") \
+_ELF_DEFINE_SHT(SHT_SUNW_ANNOTATE, 0x6FFFFFF7UL, \
+ "special section where unresolved references are allowed") \
+_ELF_DEFINE_SHT(SHT_SUNW_DEBUGSTR, 0x6FFFFFF8UL, \
+ "debugging information") \
+_ELF_DEFINE_SHT(SHT_CHECKSUM, 0x6FFFFFF8UL, \
+ "checksum for dynamic shared objects") \
+_ELF_DEFINE_SHT(SHT_SUNW_DEBUG, 0x6FFFFFF9UL, \
+ "debugging information") \
+_ELF_DEFINE_SHT(SHT_SUNW_move, 0x6FFFFFFAUL, \
+ "information to handle partially initialized symbols") \
+_ELF_DEFINE_SHT(SHT_SUNW_COMDAT, 0x6FFFFFFBUL, \
+ "section supporting merging of multiple copies of data") \
+_ELF_DEFINE_SHT(SHT_SUNW_syminfo, 0x6FFFFFFCUL, \
+ "additional symbol information") \
+_ELF_DEFINE_SHT(SHT_SUNW_verdef, 0x6FFFFFFDUL, \
+ "symbol versioning information") \
+_ELF_DEFINE_SHT(SHT_SUNW_verneed, 0x6FFFFFFEUL, \
+ "symbol versioning requirements") \
+_ELF_DEFINE_SHT(SHT_SUNW_versym, 0x6FFFFFFFUL, \
+ "symbol versioning table") \
+_ELF_DEFINE_SHT(SHT_HIOS, 0x6FFFFFFFUL, \
+ "end of OS-specific range") \
+_ELF_DEFINE_SHT(SHT_LOPROC, 0x70000000UL, \
+ "start of processor-specific range") \
+_ELF_DEFINE_SHT(SHT_ARM_EXIDX, 0x70000001UL, \
+ "exception index table") \
+_ELF_DEFINE_SHT(SHT_ARM_PREEMPTMAP, 0x70000002UL, \
+ "BPABI DLL dynamic linking preemption map") \
+_ELF_DEFINE_SHT(SHT_ARM_ATTRIBUTES, 0x70000003UL, \
+ "object file compatibility attributes") \
+_ELF_DEFINE_SHT(SHT_ARM_DEBUGOVERLAY, 0x70000004UL, \
+ "overlay debug information") \
+_ELF_DEFINE_SHT(SHT_ARM_OVERLAYSECTION, 0x70000005UL, \
+ "overlay debug information") \
+_ELF_DEFINE_SHT(SHT_MIPS_LIBLIST, 0x70000000UL, \
+ "DSO library information used in link") \
+_ELF_DEFINE_SHT(SHT_MIPS_MSYM, 0x70000001UL, \
+ "MIPS symbol table extension") \
+_ELF_DEFINE_SHT(SHT_MIPS_CONFLICT, 0x70000002UL, \
+ "symbol conflicting with DSO-defined symbols ") \
+_ELF_DEFINE_SHT(SHT_MIPS_GPTAB, 0x70000003UL, \
+ "global pointer table") \
+_ELF_DEFINE_SHT(SHT_MIPS_UCODE, 0x70000004UL, \
+ "reserved") \
+_ELF_DEFINE_SHT(SHT_MIPS_DEBUG, 0x70000005UL, \
+ "reserved (obsolete debug information)") \
+_ELF_DEFINE_SHT(SHT_MIPS_REGINFO, 0x70000006UL, \
+ "register usage information") \
+_ELF_DEFINE_SHT(SHT_MIPS_PACKAGE, 0x70000007UL, \
+ "OSF reserved") \
+_ELF_DEFINE_SHT(SHT_MIPS_PACKSYM, 0x70000008UL, \
+ "OSF reserved") \
+_ELF_DEFINE_SHT(SHT_MIPS_RELD, 0x70000009UL, \
+ "dynamic relocation") \
+_ELF_DEFINE_SHT(SHT_MIPS_IFACE, 0x7000000BUL, \
+ "subprogram interface information") \
+_ELF_DEFINE_SHT(SHT_MIPS_CONTENT, 0x7000000CUL, \
+ "section content classification") \
+_ELF_DEFINE_SHT(SHT_MIPS_OPTIONS, 0x7000000DUL, \
+ "general options") \
+_ELF_DEFINE_SHT(SHT_MIPS_DELTASYM, 0x7000001BUL, \
+ "Delta C++: symbol table") \
+_ELF_DEFINE_SHT(SHT_MIPS_DELTAINST, 0x7000001CUL, \
+ "Delta C++: instance table") \
+_ELF_DEFINE_SHT(SHT_MIPS_DELTACLASS, 0x7000001DUL, \
+ "Delta C++: class table") \
+_ELF_DEFINE_SHT(SHT_MIPS_DWARF, 0x7000001EUL, \
+ "DWARF debug information") \
+_ELF_DEFINE_SHT(SHT_MIPS_DELTADECL, 0x7000001FUL, \
+ "Delta C++: declarations") \
+_ELF_DEFINE_SHT(SHT_MIPS_SYMBOL_LIB, 0x70000020UL, \
+ "symbol-to-library mapping") \
+_ELF_DEFINE_SHT(SHT_MIPS_EVENTS, 0x70000021UL, \
+ "event locations") \
+_ELF_DEFINE_SHT(SHT_MIPS_TRANSLATE, 0x70000022UL, \
+ "???") \
+_ELF_DEFINE_SHT(SHT_MIPS_PIXIE, 0x70000023UL, \
+ "special pixie sections") \
+_ELF_DEFINE_SHT(SHT_MIPS_XLATE, 0x70000024UL, \
+ "address translation table") \
+_ELF_DEFINE_SHT(SHT_MIPS_XLATE_DEBUG, 0x70000025UL, \
+ "SGI internal address translation table") \
+_ELF_DEFINE_SHT(SHT_MIPS_WHIRL, 0x70000026UL, \
+ "intermediate code") \
+_ELF_DEFINE_SHT(SHT_MIPS_EH_REGION, 0x70000027UL, \
+ "C++ exception handling region info") \
+_ELF_DEFINE_SHT(SHT_MIPS_XLATE_OLD, 0x70000028UL, \
+ "obsolete") \
+_ELF_DEFINE_SHT(SHT_MIPS_PDR_EXCEPTION, 0x70000029UL, \
+ "runtime procedure descriptor table exception information") \
+_ELF_DEFINE_SHT(SHT_SPARC_GOTDATA, 0x70000000UL, \
+ "SPARC-specific data") \
+_ELF_DEFINE_SHT(SHT_AMD64_UNWIND, 0x70000001UL, \
+ "unwind tables for the AMD64") \
+_ELF_DEFINE_SHT(SHT_ORDERED, 0x7FFFFFFFUL, \
+ "sort entries in the section") \
+_ELF_DEFINE_SHT(SHT_HIPROC, 0x7FFFFFFFUL, \
+ "end of processor-specific range") \
+_ELF_DEFINE_SHT(SHT_LOUSER, 0x80000000UL, \
+ "start of application-specific range") \
+_ELF_DEFINE_SHT(SHT_HIUSER, 0xFFFFFFFFUL, \
+ "end of application-specific range")
+
+#undef _ELF_DEFINE_SHT
+#define _ELF_DEFINE_SHT(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SECTION_TYPES()
+ SHT__LAST__ = SHT_HIUSER
+};
+
+/* Aliases for section types. */
+#define SHT_GNU_verdef SHT_SUNW_verdef
+#define SHT_GNU_verneed SHT_SUNW_verneed
+#define SHT_GNU_versym SHT_SUNW_versym
+
+/*
+ * Symbol binding information.
+ */
+
+#define _ELF_DEFINE_SYMBOL_BINDING() \
+_ELF_DEFINE_STB(STB_LOCAL, 0, \
+ "not visible outside defining object file") \
+_ELF_DEFINE_STB(STB_GLOBAL, 1, \
+ "visible across all object files being combined") \
+_ELF_DEFINE_STB(STB_WEAK, 2, \
+ "visible across all object files but with low precedence") \
+_ELF_DEFINE_STB(STB_LOOS, 10, "start of OS-specific range") \
+_ELF_DEFINE_STB(STB_HIOS, 12, "end of OS-specific range") \
+_ELF_DEFINE_STB(STB_LOPROC, 13, \
+ "start of processor-specific range") \
+_ELF_DEFINE_STB(STB_HIPROC, 15, \
+ "end of processor-specific range")
+
+#undef _ELF_DEFINE_STB
+#define _ELF_DEFINE_STB(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SYMBOL_BINDING()
+ STB__LAST__
+};
+
+/*
+ * Symbol types
+ */
+
+#define _ELF_DEFINE_SYMBOL_TYPES() \
+_ELF_DEFINE_STT(STT_NOTYPE, 0, "unspecified type") \
+_ELF_DEFINE_STT(STT_OBJECT, 1, "data object") \
+_ELF_DEFINE_STT(STT_FUNC, 2, "executable code") \
+_ELF_DEFINE_STT(STT_SECTION, 3, "section") \
+_ELF_DEFINE_STT(STT_FILE, 4, "source file") \
+_ELF_DEFINE_STT(STT_COMMON, 5, "uninitialized common block") \
+_ELF_DEFINE_STT(STT_TLS, 6, "thread local storage") \
+_ELF_DEFINE_STT(STT_LOOS, 10, "start of OS-specific types") \
+_ELF_DEFINE_STT(STT_HIOS, 12, "end of OS-specific types") \
+_ELF_DEFINE_STT(STT_LOPROC, 13, \
+ "start of processor-specific types") \
+_ELF_DEFINE_STT(STT_ARM_TFUNC, 13, "Thumb function (GNU)") \
+_ELF_DEFINE_STT(STT_ARM_16BIT, 15, "Thumb label (GNU)") \
+_ELF_DEFINE_STT(STT_HIPROC, 15, \
+ "end of processor-specific types")
+
+#undef _ELF_DEFINE_STT
+#define _ELF_DEFINE_STT(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SYMBOL_TYPES()
+ STT__LAST__
+};
+
+/*
+ * Symbol binding.
+ */
+
+#define _ELF_DEFINE_SYMBOL_BINDING_KINDS() \
+_ELF_DEFINE_SYB(SYMINFO_BT_SELF, 0xFFFFU, \
+ "bound to self") \
+_ELF_DEFINE_SYB(SYMINFO_BT_PARENT, 0xFFFEU, \
+ "bound to parent") \
+_ELF_DEFINE_SYB(SYMINFO_BT_NONE, 0xFFFDU, \
+ "no special binding")
+
+#undef _ELF_DEFINE_SYB
+#define _ELF_DEFINE_SYB(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SYMBOL_BINDING_KINDS()
+ SYMINFO__LAST__
+};
+
+/*
+ * Symbol visibility.
+ */
+
+#define _ELF_DEFINE_SYMBOL_VISIBILITY() \
+_ELF_DEFINE_STV(STV_DEFAULT, 0, \
+ "as specified by symbol type") \
+_ELF_DEFINE_STV(STV_INTERNAL, 1, \
+ "as defined by processor semantics") \
+_ELF_DEFINE_STV(STV_HIDDEN, 2, \
+ "hidden from other components") \
+_ELF_DEFINE_STV(STV_PROTECTED, 3, \
+ "local references are not preemptable")
+
+#undef _ELF_DEFINE_STV
+#define _ELF_DEFINE_STV(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SYMBOL_VISIBILITY()
+ STV__LAST__
+};
+
+/*
+ * Symbol flags.
+ */
+#define _ELF_DEFINE_SYMBOL_FLAGS() \
+_ELF_DEFINE_SYF(SYMINFO_FLG_DIRECT, 0x01, \
+ "directly assocated reference") \
+_ELF_DEFINE_SYF(SYMINFO_FLG_COPY, 0x04, \
+ "definition by copy-relocation") \
+_ELF_DEFINE_SYF(SYMINFO_FLG_LAZYLOAD, 0x08, \
+ "object should be lazily loaded") \
+_ELF_DEFINE_SYF(SYMINFO_FLG_DIRECTBIND, 0x10, \
+ "reference should be directly bound") \
+_ELF_DEFINE_SYF(SYMINFO_FLG_NOEXTDIRECT, 0x20, \
+ "external references not allowed to bind to definition")
+
+#undef _ELF_DEFINE_SYF
+#define _ELF_DEFINE_SYF(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_SYMBOL_FLAGS()
+ SYMINFO_FLG__LAST__
+};
+
+/*
+ * Version dependencies.
+ */
+#define _ELF_DEFINE_VERSIONING_DEPENDENCIES() \
+_ELF_DEFINE_VERD(VER_NDX_LOCAL, 0, "local scope") \
+_ELF_DEFINE_VERD(VER_NDX_GLOBAL, 1, "global scope")
+#undef _ELF_DEFINE_VERD
+#define _ELF_DEFINE_VERD(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_VERSIONING_DEPENDENCIES()
+ VER_NDX__LAST__
+};
+
+/*
+ * Version flags.
+ */
+#define _ELF_DEFINE_VERSIONING_FLAGS() \
+_ELF_DEFINE_VERF(VER_FLG_BASE, 0x1, "file version") \
+_ELF_DEFINE_VERF(VER_FLG_WEAK, 0x2, "weak version")
+#undef _ELF_DEFINE_VERF
+#define _ELF_DEFINE_VERF(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_VERSIONING_FLAGS()
+ VER_FLG__LAST__
+};
+
+/*
+ * Version needs
+ */
+#define _ELF_DEFINE_VERSIONING_NEEDS() \
+_ELF_DEFINE_VRN(VER_NEED_NONE, 0, "invalid version") \
+_ELF_DEFINE_VRN(VER_NEED_CURRENT, 1, "current version")
+#undef _ELF_DEFINE_VRN
+#define _ELF_DEFINE_VRN(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_VERSIONING_NEEDS()
+ VER_NEED__LAST__
+};
+
+/*
+ * Version numbers.
+ */
+#define _ELF_DEFINE_VERSIONING_NUMBERS() \
+_ELF_DEFINE_VRNU(VER_DEF_NONE, 0, "invalid version") \
+_ELF_DEFINE_VRNU(VER_DEF_CURRENT, 1, "current version")
+#undef _ELF_DEFINE_VRNU
+#define _ELF_DEFINE_VRNU(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_VERSIONING_NUMBERS()
+ VER_DEF__LAST__
+};
+
+/**
+ ** Relocation types.
+ **/
+
+#define _ELF_DEFINE_386_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_386_NONE, 0) \
+_ELF_DEFINE_RELOC(R_386_32, 1) \
+_ELF_DEFINE_RELOC(R_386_PC32, 2) \
+_ELF_DEFINE_RELOC(R_386_GOT32, 3) \
+_ELF_DEFINE_RELOC(R_386_PLT32, 4) \
+_ELF_DEFINE_RELOC(R_386_COPY, 5) \
+_ELF_DEFINE_RELOC(R_386_GLOB_DAT, 6) \
+_ELF_DEFINE_RELOC(R_386_JMP_SLOT, 7) \
+_ELF_DEFINE_RELOC(R_386_RELATIVE, 8) \
+_ELF_DEFINE_RELOC(R_386_GOTOFF, 9) \
+_ELF_DEFINE_RELOC(R_386_GOTPC, 10) \
+_ELF_DEFINE_RELOC(R_386_32PLT, 11) \
+_ELF_DEFINE_RELOC(R_386_16, 20) \
+_ELF_DEFINE_RELOC(R_386_PC16, 21) \
+_ELF_DEFINE_RELOC(R_386_8, 22) \
+_ELF_DEFINE_RELOC(R_386_PC8, 23)
+
+/*
+ * These are the symbols used in the Sun ``Linkers and Loaders
+ * Guide'', Document No: 817-1984-17. See the X86_64 relocations list
+ * below for the spellings used in the ELF specification.
+ */
+#define _ELF_DEFINE_AMD64_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_AMD64_NONE, 0) \
+_ELF_DEFINE_RELOC(R_AMD64_64, 1) \
+_ELF_DEFINE_RELOC(R_AMD64_PC32, 2) \
+_ELF_DEFINE_RELOC(R_AMD64_GOT32, 3) \
+_ELF_DEFINE_RELOC(R_AMD64_PLT32, 4) \
+_ELF_DEFINE_RELOC(R_AMD64_COPY, 5) \
+_ELF_DEFINE_RELOC(R_AMD64_GLOB_DAT, 6) \
+_ELF_DEFINE_RELOC(R_AMD64_JUMP_SLOT, 7) \
+_ELF_DEFINE_RELOC(R_AMD64_RELATIVE, 8) \
+_ELF_DEFINE_RELOC(R_AMD64_GOTPCREL, 9) \
+_ELF_DEFINE_RELOC(R_AMD64_32, 10) \
+_ELF_DEFINE_RELOC(R_AMD64_32S, 11) \
+_ELF_DEFINE_RELOC(R_AMD64_16, 12) \
+_ELF_DEFINE_RELOC(R_AMD64_PC16, 13) \
+_ELF_DEFINE_RELOC(R_AMD64_8, 14) \
+_ELF_DEFINE_RELOC(R_AMD64_PC8, 15) \
+_ELF_DEFINE_RELOC(R_AMD64_PC64, 24) \
+_ELF_DEFINE_RELOC(R_AMD64_GOTOFF64, 25) \
+_ELF_DEFINE_RELOC(R_AMD64_GOTPC32, 26)
+
+#define _ELF_DEFINE_ARM_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_ARM_NONE, 0) \
+_ELF_DEFINE_RELOC(R_ARM_PC24, 1) \
+_ELF_DEFINE_RELOC(R_ARM_ABS32, 2) \
+_ELF_DEFINE_RELOC(R_ARM_REL32, 3) \
+_ELF_DEFINE_RELOC(R_ARM_LDR_PC_G0, 4) \
+_ELF_DEFINE_RELOC(R_ARM_ABS16, 5) \
+_ELF_DEFINE_RELOC(R_ARM_ABS12, 6) \
+_ELF_DEFINE_RELOC(R_ARM_THM_ABS5, 7) \
+_ELF_DEFINE_RELOC(R_ARM_ABS8, 8) \
+_ELF_DEFINE_RELOC(R_ARM_SBREL32, 9) \
+_ELF_DEFINE_RELOC(R_ARM_THM_CALL, 10) \
+_ELF_DEFINE_RELOC(R_ARM_THM_PC8, 11) \
+_ELF_DEFINE_RELOC(R_ARM_BREL_ADJ, 12) \
+_ELF_DEFINE_RELOC(R_ARM_SWI24, 13) \
+_ELF_DEFINE_RELOC(R_ARM_THM_SWI8, 14) \
+_ELF_DEFINE_RELOC(R_ARM_XPC25, 15) \
+_ELF_DEFINE_RELOC(R_ARM_THM_XPC22, 16) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_DTPMOD32, 17) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_DTPOFF32, 18) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_TPOFF32, 19) \
+_ELF_DEFINE_RELOC(R_ARM_COPY, 20) \
+_ELF_DEFINE_RELOC(R_ARM_GLOB_DAT, 21) \
+_ELF_DEFINE_RELOC(R_ARM_JUMP_SLOT, 22) \
+_ELF_DEFINE_RELOC(R_ARM_RELATIVE, 23) \
+_ELF_DEFINE_RELOC(R_ARM_GOTOFF32, 24) \
+_ELF_DEFINE_RELOC(R_ARM_BASE_PREL, 25) \
+_ELF_DEFINE_RELOC(R_ARM_GOT_BREL, 26) \
+_ELF_DEFINE_RELOC(R_ARM_PLT32, 27) \
+_ELF_DEFINE_RELOC(R_ARM_CALL, 28) \
+_ELF_DEFINE_RELOC(R_ARM_JUMP24, 29) \
+_ELF_DEFINE_RELOC(R_ARM_THM_JUMP24, 30) \
+_ELF_DEFINE_RELOC(R_ARM_BASE_ABS, 31) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PCREL7_0, 32) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PCREL15_8, 33) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PCREL23_15, 34) \
+_ELF_DEFINE_RELOC(R_ARM_LDR_SBREL_11_0, 35) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_19_12, 36) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_27_20, 37) \
+_ELF_DEFINE_RELOC(R_ARM_TARGET1, 38) \
+_ELF_DEFINE_RELOC(R_ARM_SBREL31, 39) \
+_ELF_DEFINE_RELOC(R_ARM_V4BX, 40) \
+_ELF_DEFINE_RELOC(R_ARM_TARGET2, 41) \
+_ELF_DEFINE_RELOC(R_ARM_PREL31, 42) \
+_ELF_DEFINE_RELOC(R_ARM_MOVW_ABS_NC, 43) \
+_ELF_DEFINE_RELOC(R_ARM_MOVT_ABS, 44) \
+_ELF_DEFINE_RELOC(R_ARM_MOVW_PREL_NC, 45) \
+_ELF_DEFINE_RELOC(R_ARM_MOVT_PREL, 46) \
+_ELF_DEFINE_RELOC(R_ARM_THM_MOVW_ABS_NC, 47) \
+_ELF_DEFINE_RELOC(R_ARM_THM_MOVT_ABS, 48) \
+_ELF_DEFINE_RELOC(R_ARM_MOVW_PREL_NC, 49) \
+_ELF_DEFINE_RELOC(R_ARM_THM_MOVT_PREL, 50) \
+_ELF_DEFINE_RELOC(R_ARM_THM_JUMP19, 51) \
+_ELF_DEFINE_RELOC(R_ARM_THM_JUMP6, 52) \
+_ELF_DEFINE_RELOC(R_ARM_THM_ALU_PREL_11_0, 53) \
+_ELF_DEFINE_RELOC(R_ARM_THM_PC12, 54) \
+_ELF_DEFINE_RELOC(R_ARM_ABS32_NOI, 55) \
+_ELF_DEFINE_RELOC(R_ARM_REL32_NOI, 56) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0_NC, 57) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0, 58) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1_NC, 59) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1, 60) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G2, 61) \
+_ELF_DEFINE_RELOC(R_ARM_LDR_PC_G1, 62) \
+_ELF_DEFINE_RELOC(R_ARM_LDR_PC_G2, 63) \
+_ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G0, 64) \
+_ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G1, 65) \
+_ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G2, 66) \
+_ELF_DEFINE_RELOC(R_ARM_LDC_PC_G0, 67) \
+_ELF_DEFINE_RELOC(R_ARM_LDC_PC_G1, 68) \
+_ELF_DEFINE_RELOC(R_ARM_LDC_PC_G2, 69) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0_NC, 70) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0, 71) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1_NC, 72) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1, 73) \
+_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G2, 74) \
+_ELF_DEFINE_RELOC(R_ARM_LDR_SB_G0, 75) \
+_ELF_DEFINE_RELOC(R_ARM_LDR_SB_G1, 76) \
+_ELF_DEFINE_RELOC(R_ARM_LDR_SB_G2, 77) \
+_ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G0, 78) \
+_ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G1, 79) \
+_ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G2, 80) \
+_ELF_DEFINE_RELOC(R_ARM_LDC_SB_G0, 81) \
+_ELF_DEFINE_RELOC(R_ARM_LDC_SB_G1, 82) \
+_ELF_DEFINE_RELOC(R_ARM_LDC_SB_G2, 83) \
+_ELF_DEFINE_RELOC(R_ARM_MOVW_BREL_NC, 84) \
+_ELF_DEFINE_RELOC(R_ARM_MOVT_BREL, 85) \
+_ELF_DEFINE_RELOC(R_ARM_MOVW_BREL, 86) \
+_ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL_NC, 87) \
+_ELF_DEFINE_RELOC(R_ARM_THM_MOVT_BREL, 88) \
+_ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL, 89) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_GOTDESC, 90) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_CALL, 91) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_DESCSEQ, 92) \
+_ELF_DEFINE_RELOC(R_ARM_THM_TLS_CALL, 93) \
+_ELF_DEFINE_RELOC(R_ARM_PLT32_ABS, 94) \
+_ELF_DEFINE_RELOC(R_ARM_GOT_ABS, 95) \
+_ELF_DEFINE_RELOC(R_ARM_GOT_PREL, 96) \
+_ELF_DEFINE_RELOC(R_ARM_GOT_BREL12, 97) \
+_ELF_DEFINE_RELOC(R_ARM_GOTOFF12, 98) \
+_ELF_DEFINE_RELOC(R_ARM_GOTRELAX, 99) \
+_ELF_DEFINE_RELOC(R_ARM_GNU_VTENTRY, 100) \
+_ELF_DEFINE_RELOC(R_ARM_GNU_VTINHERIT, 101) \
+_ELF_DEFINE_RELOC(R_ARM_THM_JUMP11, 102) \
+_ELF_DEFINE_RELOC(R_ARM_THM_JUMP8, 103) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_GD32, 104) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_LDM32, 105) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_LDO32, 106) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_IE32, 107) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_LE32, 108) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_LDO12, 109) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_LE12, 110) \
+_ELF_DEFINE_RELOC(R_ARM_TLS_IE12GP, 111) \
+_ELF_DEFINE_RELOC(R_ARM_ME_TOO, 128) \
+_ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ16, 129) \
+_ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ32, 130)
+
+#define _ELF_DEFINE_IA64_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_IA_64_NONE, 0) \
+_ELF_DEFINE_RELOC(R_IA_64_IMM14, 0x21) \
+_ELF_DEFINE_RELOC(R_IA_64_IMM22, 0x22) \
+_ELF_DEFINE_RELOC(R_IA_64_IMM64, 0x23) \
+_ELF_DEFINE_RELOC(R_IA_64_DIR32MSB, 0x24) \
+_ELF_DEFINE_RELOC(R_IA_64_DIR32LSB, 0x25) \
+_ELF_DEFINE_RELOC(R_IA_64_DIR64MSB, 0x26) \
+_ELF_DEFINE_RELOC(R_IA_64_DIR64LSB, 0x27) \
+_ELF_DEFINE_RELOC(R_IA_64_GPREL22, 0x2a) \
+_ELF_DEFINE_RELOC(R_IA_64_GPREL64I, 0x2b) \
+_ELF_DEFINE_RELOC(R_IA_64_GPREL32MSB, 0x2c) \
+_ELF_DEFINE_RELOC(R_IA_64_GPREL32LSB, 0x2d) \
+_ELF_DEFINE_RELOC(R_IA_64_GPREL64MSB, 0x2e) \
+_ELF_DEFINE_RELOC(R_IA_64_GPREL64LSB, 0x2f) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF22, 0x32) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF64I, 0x33) \
+_ELF_DEFINE_RELOC(R_IA_64_PLTOFF22, 0x3a) \
+_ELF_DEFINE_RELOC(R_IA_64_PLTOFF64I, 0x3b) \
+_ELF_DEFINE_RELOC(R_IA_64_PLTOFF64MSB, 0x3e) \
+_ELF_DEFINE_RELOC(R_IA_64_PLTOFF64LSB, 0x3f) \
+_ELF_DEFINE_RELOC(R_IA_64_FPTR64I, 0x43) \
+_ELF_DEFINE_RELOC(R_IA_64_FPTR32MSB, 0x44) \
+_ELF_DEFINE_RELOC(R_IA_64_FPTR32LSB, 0x45) \
+_ELF_DEFINE_RELOC(R_IA_64_FPTR64MSB, 0x46) \
+_ELF_DEFINE_RELOC(R_IA_64_FPTR64LSB, 0x47) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL60B, 0x48) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL21B, 0x49) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL21M, 0x4a) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL21F, 0x4b) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL32MSB, 0x4c) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL32LSB, 0x4d) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL64MSB, 0x4e) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL64LSB, 0x4f) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR22, 0x52) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64I, 0x53) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32MSB, 0x54) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32LSB, 0x55) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64MSB, 0x56) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64LSB, 0x57) \
+_ELF_DEFINE_RELOC(R_IA_64_SEGREL32MSB, 0x5c) \
+_ELF_DEFINE_RELOC(R_IA_64_SEGREL32LSB, 0x5d) \
+_ELF_DEFINE_RELOC(R_IA_64_SEGREL64MSB, 0x5e) \
+_ELF_DEFINE_RELOC(R_IA_64_SEGREL64LSB, 0x5f) \
+_ELF_DEFINE_RELOC(R_IA_64_SECREL32MSB, 0x64) \
+_ELF_DEFINE_RELOC(R_IA_64_SECREL32LSB, 0x65) \
+_ELF_DEFINE_RELOC(R_IA_64_SECREL64MSB, 0x66) \
+_ELF_DEFINE_RELOC(R_IA_64_SECREL64LSB, 0x67) \
+_ELF_DEFINE_RELOC(R_IA_64_REL32MSB, 0x6c) \
+_ELF_DEFINE_RELOC(R_IA_64_REL32LSB, 0x6d) \
+_ELF_DEFINE_RELOC(R_IA_64_REL64MSB, 0x6e) \
+_ELF_DEFINE_RELOC(R_IA_64_REL64LSB, 0x6f) \
+_ELF_DEFINE_RELOC(R_IA_64_LTV32MSB, 0x74) \
+_ELF_DEFINE_RELOC(R_IA_64_LTV32LSB, 0x75) \
+_ELF_DEFINE_RELOC(R_IA_64_LTV64MSB, 0x76) \
+_ELF_DEFINE_RELOC(R_IA_64_LTV64LSB, 0x77) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL21BIa, 0x79) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL22, 0x7A) \
+_ELF_DEFINE_RELOC(R_IA_64_PCREL64I, 0x7B) \
+_ELF_DEFINE_RELOC(R_IA_64_IPLTMSB, 0x80) \
+_ELF_DEFINE_RELOC(R_IA_64_IPLTLSB, 0x81) \
+_ELF_DEFINE_RELOC(R_IA_64_SUB, 0x85) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF22X, 0x86) \
+_ELF_DEFINE_RELOC(R_IA_64_LDXMOV, 0x87) \
+_ELF_DEFINE_RELOC(R_IA_64_TPREL14, 0x91) \
+_ELF_DEFINE_RELOC(R_IA_64_TPREL22, 0x92) \
+_ELF_DEFINE_RELOC(R_IA_64_TPREL64I, 0x93) \
+_ELF_DEFINE_RELOC(R_IA_64_TPREL64MSB, 0x96) \
+_ELF_DEFINE_RELOC(R_IA_64_TPREL64LSB, 0x97) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_TPREL22, 0x9A) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPMOD64MSB, 0xA6) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPMOD64LSB, 0xA7) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPMOD22, 0xAA) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPREL14, 0xB1) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPREL22, 0xB2) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPREL64I, 0xB3) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPREL32MSB, 0xB4) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPREL32LSB, 0xB5) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPREL64MSB, 0xB6) \
+_ELF_DEFINE_RELOC(R_IA_64_DTPREL64LSB, 0xB7) \
+_ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPREL22, 0xBA)
+
+#define _ELF_DEFINE_MIPS_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_MIPS_NONE, 0) \
+_ELF_DEFINE_RELOC(R_MIPS_16, 1) \
+_ELF_DEFINE_RELOC(R_MIPS_32, 2) \
+_ELF_DEFINE_RELOC(R_MIPS_REL32, 3) \
+_ELF_DEFINE_RELOC(R_MIPS_26, 4) \
+_ELF_DEFINE_RELOC(R_MIPS_HI16, 5) \
+_ELF_DEFINE_RELOC(R_MIPS_LO16, 6) \
+_ELF_DEFINE_RELOC(R_MIPS_GPREL16, 7) \
+_ELF_DEFINE_RELOC(R_MIPS_LITERAL, 8) \
+_ELF_DEFINE_RELOC(R_MIPS_GOT16, 9) \
+_ELF_DEFINE_RELOC(R_MIPS_PC16, 10) \
+_ELF_DEFINE_RELOC(R_MIPS_CALL16, 11) \
+_ELF_DEFINE_RELOC(R_MIPS_GPREL32, 12) \
+_ELF_DEFINE_RELOC(R_MIPS_64, 18) \
+_ELF_DEFINE_RELOC(R_MIPS_GOTHI16, 21) \
+_ELF_DEFINE_RELOC(R_MIPS_GOTLO16, 22) \
+_ELF_DEFINE_RELOC(R_MIPS_CALLHI16, 30) \
+_ELF_DEFINE_RELOC(R_MIPS_CALLLO16, 31)
+
+#define _ELF_DEFINE_PPC32_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_PPC_NONE, 0) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR32, 1) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR24, 2) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR16, 3) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR16_LO, 4) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR16_HI, 5) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR16_HA, 6) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR14, 7) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR14_BRTAKEN, 8) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR14_BRNTAKEN, 9) \
+_ELF_DEFINE_RELOC(R_PPC_REL24, 10) \
+_ELF_DEFINE_RELOC(R_PPC_REL14, 11) \
+_ELF_DEFINE_RELOC(R_PPC_REL14_BRTAKEN, 12) \
+_ELF_DEFINE_RELOC(R_PPC_REL14_BRNTAKEN, 13) \
+_ELF_DEFINE_RELOC(R_PPC_GOT16, 14) \
+_ELF_DEFINE_RELOC(R_PPC_GOT16_LO, 15) \
+_ELF_DEFINE_RELOC(R_PPC_GOT16_HI, 16) \
+_ELF_DEFINE_RELOC(R_PPC_GOT16_HA, 17) \
+_ELF_DEFINE_RELOC(R_PPC_PLTREL24, 18) \
+_ELF_DEFINE_RELOC(R_PPC_COPY, 19) \
+_ELF_DEFINE_RELOC(R_PPC_GLOB_DAT, 20) \
+_ELF_DEFINE_RELOC(R_PPC_JMP_SLOT, 21) \
+_ELF_DEFINE_RELOC(R_PPC_RELATIVE, 22) \
+_ELF_DEFINE_RELOC(R_PPC_LOCAL24PC, 23) \
+_ELF_DEFINE_RELOC(R_PPC_UADDR32, 24) \
+_ELF_DEFINE_RELOC(R_PPC_UADDR16, 25) \
+_ELF_DEFINE_RELOC(R_PPC_REL32, 26) \
+_ELF_DEFINE_RELOC(R_PPC_PLT32, 27) \
+_ELF_DEFINE_RELOC(R_PPC_PLTREL32, 28) \
+_ELF_DEFINE_RELOC(R_PPC_PLT16_LO, 29) \
+_ELF_DEFINE_RELOC(R_PPL_PLT16_HI, 30) \
+_ELF_DEFINE_RELOC(R_PPC_PLT16_HA, 31) \
+_ELF_DEFINE_RELOC(R_PPC_SDAREL16, 32) \
+_ELF_DEFINE_RELOC(R_PPC_SECTOFF, 33) \
+_ELF_DEFINE_RELOC(R_PPC_SECTOFF_LO, 34) \
+_ELF_DEFINE_RELOC(R_PPC_SECTOFF_HI, 35) \
+_ELF_DEFINE_RELOC(R_PPC_SECTOFF_HA, 36) \
+_ELF_DEFINE_RELOC(R_PPC_ADDR30, 37) \
+_ELF_DEFINE_RELOC(R_PPC_TLS, 67) \
+_ELF_DEFINE_RELOC(R_PPC_DTPMOD32, 68) \
+_ELF_DEFINE_RELOC(R_PPC_TPREL16, 69) \
+_ELF_DEFINE_RELOC(R_PPC_TPREL16_LO, 70) \
+_ELF_DEFINE_RELOC(R_PPC_TPREL16_HI, 71) \
+_ELF_DEFINE_RELOC(R_PPC_TPREL16_HA, 72) \
+_ELF_DEFINE_RELOC(R_PPC_TPREL32, 73) \
+_ELF_DEFINE_RELOC(R_PPC_DTPREL16, 74) \
+_ELF_DEFINE_RELOC(R_PPC_DTPREL16_LO, 75) \
+_ELF_DEFINE_RELOC(R_PPC_DTPREL16_HI, 76) \
+_ELF_DEFINE_RELOC(R_PPC_DTPREL16_HA, 77) \
+_ELF_DEFINE_RELOC(R_PPC_DTPREL32, 78) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16, 79) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_LO, 80) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HI, 81) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HA, 82) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16, 83) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_LO, 84) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HI, 85) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HA, 86) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16, 87) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_LO, 88) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HI, 89) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HA, 90) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16, 91) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_LO, 92) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HI, 93) \
+_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HA, 94) \
+_ELF_DEFINE_RELOC(R_PPC_TLSGD, 95) \
+_ELF_DEFINE_RELOC(R_PPC_TLSLD, 96) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR32, 101) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16, 102) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_LO, 103) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HI, 104) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HA, 105) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_SDAI16, 106) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_SDA2I16, 107) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_SDA2REL, 108) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_SDA21, 109) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_MRKREF, 110) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_RELSEC16, 111) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_RELST_LO, 112) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HI, 113) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HA, 114) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_BIT_FLD, 115) \
+_ELF_DEFINE_RELOC(R_PPC_EMB_RELSDA, 116) \
+
+#define _ELF_DEFINE_PPC64_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_PPC64_NONE, 0) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR32, 1) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR24, 2) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16, 3) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO, 4) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HI, 5) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HA, 6) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR14, 7) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRTAKEN, 8) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRNTAKEN, 9) \
+_ELF_DEFINE_RELOC(R_PPC64_REL24, 10) \
+_ELF_DEFINE_RELOC(R_PPC64_REL14, 11) \
+_ELF_DEFINE_RELOC(R_PPC64_REL14_BRTAKEN, 12) \
+_ELF_DEFINE_RELOC(R_PPC64_REL14_BRNTAKEN, 13) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT16, 14) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT16_LO, 15) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT16_HI, 16) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT16_HA, 17) \
+_ELF_DEFINE_RELOC(R_PPC64_COPY, 19) \
+_ELF_DEFINE_RELOC(R_PPC64_GLOB_DAT, 20) \
+_ELF_DEFINE_RELOC(R_PPC64_JMP_SLOT, 21) \
+_ELF_DEFINE_RELOC(R_PPC64_RELATIVE, 22) \
+_ELF_DEFINE_RELOC(R_PPC64_UADDR32, 24) \
+_ELF_DEFINE_RELOC(R_PPC64_UADDR16, 25) \
+_ELF_DEFINE_RELOC(R_PPC64_REL32, 26) \
+_ELF_DEFINE_RELOC(R_PPC64_PLT32, 27) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTREL32, 28) \
+_ELF_DEFINE_RELOC(R_PPC64_PLT16_LO, 29) \
+_ELF_DEFINE_RELOC(R_PPC64_PLT16_HI, 30) \
+_ELF_DEFINE_RELOC(R_PPC64_PLT16_HA, 31) \
+_ELF_DEFINE_RELOC(R_PPC64_SECTOFF, 33) \
+_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO, 34) \
+_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HI, 35) \
+_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HA, 36) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR30, 37) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR64, 38) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHER, 39) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHERA, 40) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHEST, 41) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHESTA, 42) \
+_ELF_DEFINE_RELOC(R_PPC64_UADDR64, 43) \
+_ELF_DEFINE_RELOC(R_PPC64_REL64, 44) \
+_ELF_DEFINE_RELOC(R_PPC64_PLT64, 45) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTREL64, 46) \
+_ELF_DEFINE_RELOC(R_PPC64_TOC16, 47) \
+_ELF_DEFINE_RELOC(R_PPC64_TOC16_LO, 48) \
+_ELF_DEFINE_RELOC(R_PPC64_TOC16_HI, 49) \
+_ELF_DEFINE_RELOC(R_PPC64_TOC16_HA, 50) \
+_ELF_DEFINE_RELOC(R_PPC64_TOC, 51) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16, 52) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO, 53) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HI, 54) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HA, 55) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_DS, 56) \
+_ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO_DS, 57) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT16_DS, 58) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT16_LO_DS, 59) \
+_ELF_DEFINE_RELOC(R_PPC64_PLT16_LO_DS, 60) \
+_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_DS, 61) \
+_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO_DS, 62) \
+_ELF_DEFINE_RELOC(R_PPC64_TOC16_DS, 63) \
+_ELF_DEFINE_RELOC(R_PPC64_TOC16_LO_DS, 64) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_DS, 65) \
+_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO_DS, 66) \
+_ELF_DEFINE_RELOC(R_PPC64_TLS, 67) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPMOD64, 68) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16, 69) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO, 60) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HI, 71) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HA, 72) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL64, 73) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16, 74) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO, 75) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HI, 76) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HA, 77) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL64, 78) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16, 79) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_LO, 80) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HI, 81) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HA, 82) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16, 83) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_LO, 84) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HI, 85) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HA, 86) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_DS, 87) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_LO_DS, 88) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HI, 89) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HA, 90) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_DS, 91) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_LO_DS, 92) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HI, 93) \
+_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HA, 94) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_DS, 95) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO_DS, 96) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHER, 97) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHERA, 98) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHEST, 99) \
+_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHESTA, 100) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_DS, 101) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO_DS, 102) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHER, 103) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHERA, 104) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHEST, 105) \
+_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHESTA, 106) \
+_ELF_DEFINE_RELOC(R_PPC64_TLSGD, 107) \
+_ELF_DEFINE_RELOC(R_PPC64_TLSLD, 108)
+
+#define _ELF_DEFINE_SPARC_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_SPARC_NONE, 0) \
+_ELF_DEFINE_RELOC(R_SPARC_8, 1) \
+_ELF_DEFINE_RELOC(R_SPARC_16, 2) \
+_ELF_DEFINE_RELOC(R_SPARC_32, 3) \
+_ELF_DEFINE_RELOC(R_SPARC_DISP8, 4) \
+_ELF_DEFINE_RELOC(R_SPARC_DISP16, 5) \
+_ELF_DEFINE_RELOC(R_SPARC_DISP32, 6) \
+_ELF_DEFINE_RELOC(R_SPARC_WDISP30, 7) \
+_ELF_DEFINE_RELOC(R_SPARC_WDISP22, 8) \
+_ELF_DEFINE_RELOC(R_SPARC_HI22, 9) \
+_ELF_DEFINE_RELOC(R_SPARC_22, 10) \
+_ELF_DEFINE_RELOC(R_SPARC_13, 11) \
+_ELF_DEFINE_RELOC(R_SPARC_LO10, 12) \
+_ELF_DEFINE_RELOC(R_SPARC_GOT10, 13) \
+_ELF_DEFINE_RELOC(R_SPARC_GOT13, 14) \
+_ELF_DEFINE_RELOC(R_SPARC_GOT22, 15) \
+_ELF_DEFINE_RELOC(R_SPARC_PC10, 16) \
+_ELF_DEFINE_RELOC(R_SPARC_PC22, 17) \
+_ELF_DEFINE_RELOC(R_SPARC_WPLT30, 18) \
+_ELF_DEFINE_RELOC(R_SPARC_COPY, 19) \
+_ELF_DEFINE_RELOC(R_SPARC_GLOB_DAT, 20) \
+_ELF_DEFINE_RELOC(R_SPARC_JMP_SLOT, 21) \
+_ELF_DEFINE_RELOC(R_SPARC_RELATIVE, 22) \
+_ELF_DEFINE_RELOC(R_SPARC_UA32, 23) \
+_ELF_DEFINE_RELOC(R_SPARC_PLT32, 24) \
+_ELF_DEFINE_RELOC(R_SPARC_HIPLT22, 25) \
+_ELF_DEFINE_RELOC(R_SPARC_LOPLT10, 26) \
+_ELF_DEFINE_RELOC(R_SPARC_PCPLT32, 27) \
+_ELF_DEFINE_RELOC(R_SPARC_PCPLT22, 28) \
+_ELF_DEFINE_RELOC(R_SPARC_PCPLT10, 29) \
+_ELF_DEFINE_RELOC(R_SPARC_10, 30) \
+_ELF_DEFINE_RELOC(R_SPARC_11, 31) \
+_ELF_DEFINE_RELOC(R_SPARC_64, 32) \
+_ELF_DEFINE_RELOC(R_SPARC_OLO10, 33) \
+_ELF_DEFINE_RELOC(R_SPARC_HH22, 34) \
+_ELF_DEFINE_RELOC(R_SPARC_HM10, 35) \
+_ELF_DEFINE_RELOC(R_SPARC_LM22, 36) \
+_ELF_DEFINE_RELOC(R_SPARC_PC_HH22, 37) \
+_ELF_DEFINE_RELOC(R_SPARC_PC_HM10, 38) \
+_ELF_DEFINE_RELOC(R_SPARC_PC_LM22, 39) \
+_ELF_DEFINE_RELOC(R_SPARC_WDISP16, 40) \
+_ELF_DEFINE_RELOC(R_SPARC_WDISP19, 41) \
+_ELF_DEFINE_RELOC(R_SPARC_7, 43) \
+_ELF_DEFINE_RELOC(R_SPARC_5, 44) \
+_ELF_DEFINE_RELOC(R_SPARC_6, 45) \
+_ELF_DEFINE_RELOC(R_SPARC_DISP64, 46) \
+_ELF_DEFINE_RELOC(R_SPARC_PLT64, 47) \
+_ELF_DEFINE_RELOC(R_SPARC_HIX22, 48) \
+_ELF_DEFINE_RELOC(R_SPARC_LOX10, 49) \
+_ELF_DEFINE_RELOC(R_SPARC_H44, 50) \
+_ELF_DEFINE_RELOC(R_SPARC_M44, 51) \
+_ELF_DEFINE_RELOC(R_SPARC_L44, 52) \
+_ELF_DEFINE_RELOC(R_SPARC_REGISTER, 53) \
+_ELF_DEFINE_RELOC(R_SPARC_UA64, 54) \
+_ELF_DEFINE_RELOC(R_SPARC_UA16, 55) \
+_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_HIX22, 80) \
+_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_LOX10, 81) \
+_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_HIX22, 82) \
+_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_LOX10, 83) \
+_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP, 84) \
+_ELF_DEFINE_RELOC(R_SPARC_H34, 85)
+
+#define _ELF_DEFINE_X86_64_RELOCATIONS() \
+_ELF_DEFINE_RELOC(R_X86_64_NONE, 0) \
+_ELF_DEFINE_RELOC(R_X86_64_64, 1) \
+_ELF_DEFINE_RELOC(R_X86_64_PC32, 2) \
+_ELF_DEFINE_RELOC(R_X86_64_GOT32, 3) \
+_ELF_DEFINE_RELOC(R_X86_64_PLT32, 4) \
+_ELF_DEFINE_RELOC(R_X86_64_COPY, 5) \
+_ELF_DEFINE_RELOC(R_X86_64_GLOB_DAT, 6) \
+_ELF_DEFINE_RELOC(R_X86_64_JUMP_SLOT, 7) \
+_ELF_DEFINE_RELOC(R_X86_64_RELATIVE, 8) \
+_ELF_DEFINE_RELOC(R_X86_64_GOTPCREL, 9) \
+_ELF_DEFINE_RELOC(R_X86_64_32, 10) \
+_ELF_DEFINE_RELOC(R_X86_64_32S, 11) \
+_ELF_DEFINE_RELOC(R_X86_64_16, 12) \
+_ELF_DEFINE_RELOC(R_X86_64_PC16, 13) \
+_ELF_DEFINE_RELOC(R_X86_64_8, 14) \
+_ELF_DEFINE_RELOC(R_X86_64_PC8, 15) \
+_ELF_DEFINE_RELOC(R_X86_64_DTPMOD64, 16) \
+_ELF_DEFINE_RELOC(R_X86_64_DTPOFF64, 17) \
+_ELF_DEFINE_RELOC(R_X86_64_TPOFF64, 18) \
+_ELF_DEFINE_RELOC(R_X86_64_TLSGD, 19) \
+_ELF_DEFINE_RELOC(R_X86_64_TLSLD, 20) \
+_ELF_DEFINE_RELOC(R_X86_64_DTPOFF32, 21) \
+_ELF_DEFINE_RELOC(R_X86_64_GOTTPOFF, 22) \
+_ELF_DEFINE_RELOC(R_X86_64_TPOFF32, 23) \
+_ELF_DEFINE_RELOC(R_X86_64_PC64, 24) \
+_ELF_DEFINE_RELOC(R_X86_64_GOTOFF64, 25) \
+_ELF_DEFINE_RELOC(R_X86_64_GOTPC32, 26) \
+_ELF_DEFINE_RELOC(R_X86_64_SIZE32, 32) \
+_ELF_DEFINE_RELOC(R_X86_64_SIZE64, 33) \
+_ELF_DEFINE_RELOC(R_X86_64_GOTPC32_TLSDESC, 34) \
+_ELF_DEFINE_RELOC(R_X86_64_TLSDESC_CALL, 35) \
+_ELF_DEFINE_RELOC(R_X86_64_TLSDESC, 36)
+
+#define _ELF_DEFINE_RELOCATIONS() \
+_ELF_DEFINE_386_RELOCATIONS() \
+_ELF_DEFINE_AMD64_RELOCATIONS() \
+_ELF_DEFINE_IA64_RELOCATIONS() \
+_ELF_DEFINE_MIPS_RELOCATIONS() \
+_ELF_DEFINE_PPC32_RELOCATIONS() \
+_ELF_DEFINE_PPC64_RELOCATIONS() \
+_ELF_DEFINE_SPARC_RELOCATIONS() \
+_ELF_DEFINE_X86_64_RELOCATIONS()
+
+#undef _ELF_DEFINE_RELOC
+#define _ELF_DEFINE_RELOC(N, V) N = V ,
+enum {
+ _ELF_DEFINE_RELOCATIONS()
+ R__LAST__
+};
+
+#define PN_XNUM 0xFFFFU /* Use extended section numbering. */
+
+/**
+ ** ELF Types.
+ **/
+
+typedef uint32_t Elf32_Addr; /* Program address. */
+typedef uint8_t Elf32_Byte; /* Unsigned tiny integer. */
+typedef uint16_t Elf32_Half; /* Unsigned medium integer. */
+typedef uint32_t Elf32_Off; /* File offset. */
+typedef uint16_t Elf32_Section; /* Section index. */
+typedef int32_t Elf32_Sword; /* Signed integer. */
+typedef uint32_t Elf32_Word; /* Unsigned integer. */
+typedef uint64_t Elf32_Lword; /* Unsigned long integer. */
+
+typedef uint64_t Elf64_Addr; /* Program address. */
+typedef uint8_t Elf64_Byte; /* Unsigned tiny integer. */
+typedef uint16_t Elf64_Half; /* Unsigned medium integer. */
+typedef uint64_t Elf64_Off; /* File offset. */
+typedef uint16_t Elf64_Section; /* Section index. */
+typedef int32_t Elf64_Sword; /* Signed integer. */
+typedef uint32_t Elf64_Word; /* Unsigned integer. */
+typedef uint64_t Elf64_Lword; /* Unsigned long integer. */
+typedef uint64_t Elf64_Xword; /* Unsigned long integer. */
+typedef int64_t Elf64_Sxword; /* Signed long integer. */
+
+
+/*
+ * Capability descriptors.
+ */
+
+/* 32-bit capability descriptor. */
+typedef struct {
+ Elf32_Word c_tag; /* Type of entry. */
+ union {
+ Elf32_Word c_val; /* Integer value. */
+ Elf32_Addr c_ptr; /* Pointer value. */
+ } c_un;
+} Elf32_Cap;
+
+/* 64-bit capability descriptor. */
+typedef struct {
+ Elf64_Xword c_tag; /* Type of entry. */
+ union {
+ Elf64_Xword c_val; /* Integer value. */
+ Elf64_Addr c_ptr; /* Pointer value. */
+ } c_un;
+} Elf64_Cap;
+
+/*
+ * MIPS .conflict section entries.
+ */
+
+/* 32-bit entry. */
+typedef struct {
+ Elf32_Addr c_index;
+} Elf32_Conflict;
+
+/* 64-bit entry. */
+typedef struct {
+ Elf64_Addr c_index;
+} Elf64_Conflict;
+
+/*
+ * Dynamic section entries.
+ */
+
+/* 32-bit entry. */
+typedef struct {
+ Elf32_Sword d_tag; /* Type of entry. */
+ union {
+ Elf32_Word d_val; /* Integer value. */
+ Elf32_Addr d_ptr; /* Pointer value. */
+ } d_un;
+} Elf32_Dyn;
+
+/* 64-bit entry. */
+typedef struct {
+ Elf64_Sxword d_tag; /* Type of entry. */
+ union {
+ Elf64_Xword d_val; /* Integer value. */
+ Elf64_Addr d_ptr; /* Pointer value; */
+ } d_un;
+} Elf64_Dyn;
+
+
+/*
+ * The executable header (EHDR).
+ */
+
+/* 32 bit EHDR. */
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* ELF identification. */
+ Elf32_Half e_type; /* Object file type (ET_*). */
+ Elf32_Half e_machine; /* Machine type (EM_*). */
+ Elf32_Word e_version; /* File format version (EV_*). */
+ Elf32_Addr e_entry; /* Start address. */
+ Elf32_Off e_phoff; /* File offset to the PHDR table. */
+ Elf32_Off e_shoff; /* File offset to the SHDRheader. */
+ Elf32_Word e_flags; /* Flags (EF_*). */
+ Elf32_Half e_ehsize; /* Elf header size in bytes. */
+ Elf32_Half e_phentsize; /* PHDR table entry size in bytes. */
+ Elf32_Half e_phnum; /* Number of PHDR entries. */
+ Elf32_Half e_shentsize; /* SHDR table entry size in bytes. */
+ Elf32_Half e_shnum; /* Number of SHDR entries. */
+ Elf32_Half e_shstrndx; /* Index of section name string table. */
+} Elf32_Ehdr;
+
+
+/* 64 bit EHDR. */
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* ELF identification. */
+ Elf64_Half e_type; /* Object file type (ET_*). */
+ Elf64_Half e_machine; /* Machine type (EM_*). */
+ Elf64_Word e_version; /* File format version (EV_*). */
+ Elf64_Addr e_entry; /* Start address. */
+ Elf64_Off e_phoff; /* File offset to the PHDR table. */
+ Elf64_Off e_shoff; /* File offset to the SHDRheader. */
+ Elf64_Word e_flags; /* Flags (EF_*). */
+ Elf64_Half e_ehsize; /* Elf header size in bytes. */
+ Elf64_Half e_phentsize; /* PHDR table entry size in bytes. */
+ Elf64_Half e_phnum; /* Number of PHDR entries. */
+ Elf64_Half e_shentsize; /* SHDR table entry size in bytes. */
+ Elf64_Half e_shnum; /* Number of SHDR entries. */
+ Elf64_Half e_shstrndx; /* Index of section name string table. */
+} Elf64_Ehdr;
+
+
+/*
+ * Shared object information.
+ */
+
+/* 32-bit entry. */
+typedef struct {
+ Elf32_Word l_name; /* The name of a shared object. */
+ Elf32_Word l_time_stamp; /* 32-bit timestamp. */
+ Elf32_Word l_checksum; /* Checksum of visible symbols, sizes. */
+ Elf32_Word l_version; /* Interface version string index. */
+ Elf32_Word l_flags; /* Flags (LL_*). */
+} Elf32_Lib;
+
+/* 64-bit entry. */
+typedef struct {
+ Elf64_Word l_name;
+ Elf64_Word l_time_stamp;
+ Elf64_Word l_checksum;
+ Elf64_Word l_version;
+ Elf64_Word l_flags;
+} Elf64_Lib;
+
+#define _ELF_DEFINE_LL_FLAGS() \
+_ELF_DEFINE_LL(LL_NONE, 0, \
+ "no flags") \
+_ELF_DEFINE_LL(LL_EXACT_MATCH, 0x1, \
+ "require an exact match") \
+_ELF_DEFINE_LL(LL_IGNORE_INT_VER, 0x2, \
+ "ignore version incompatibilities") \
+_ELF_DEFINE_LL(LL_REQUIRE_MINOR, 0x4, \
+ "") \
+_ELF_DEFINE_LL(LL_EXPORTS, 0x8, \
+ "") \
+_ELF_DEFINE_LL(LL_DELAY_LOAD, 0x10, \
+ "") \
+_ELF_DEFINE_LL(LL_DELTA, 0x20, \
+ "")
+
+#undef _ELF_DEFINE_LL
+#define _ELF_DEFINE_LL(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_LL_FLAGS()
+ LL__LAST__
+};
+
+/*
+ * Note tags
+ */
+
+#define _ELF_DEFINE_NOTE_ENTRY_TYPES() \
+_ELF_DEFINE_NT(NT_ABI_TAG, 1, "Tag indicating the ABI") \
+_ELF_DEFINE_NT(NT_GNU_HWCAP, 2, "Hardware capabilities") \
+_ELF_DEFINE_NT(NT_GNU_BUILD_ID, 3, "Build id, set by ld(1)") \
+_ELF_DEFINE_NT(NT_GNU_GOLD_VERSION, 4, \
+ "Version number of the GNU gold linker") \
+_ELF_DEFINE_NT(NT_PRSTATUS, 1, "Process status") \
+_ELF_DEFINE_NT(NT_FPREGSET, 2, "Floating point information") \
+_ELF_DEFINE_NT(NT_PRPSINFO, 3, "Process information") \
+_ELF_DEFINE_NT(NT_AUXV, 6, "Auxiliary vector") \
+_ELF_DEFINE_NT(NT_PRXFPREG, 0x46E62B7FUL, \
+ "Linux user_xfpregs structure") \
+_ELF_DEFINE_NT(NT_PSTATUS, 10, "Linux process status") \
+_ELF_DEFINE_NT(NT_FPREGS, 12, "Linux floating point regset") \
+_ELF_DEFINE_NT(NT_PSINFO, 13, "Linux process information") \
+_ELF_DEFINE_NT(NT_LWPSTATUS, 16, "Linux lwpstatus_t type") \
+_ELF_DEFINE_NT(NT_LWPSINFO, 17, "Linux lwpinfo_t type")
+
+#undef _ELF_DEFINE_NT
+#define _ELF_DEFINE_NT(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_NOTE_ENTRY_TYPES()
+ NT__LAST__
+};
+
+/* Aliases for the ABI tag. */
+#define NT_FREEBSD_ABI_TAG NT_ABI_TAG
+#define NT_GNU_ABI_TAG NT_ABI_TAG
+#define NT_NETBSD_IDENT NT_ABI_TAG
+#define NT_OPENBSD_IDENT NT_ABI_TAG
+
+/*
+ * Note descriptors.
+ */
+
+typedef struct {
+ uint32_t n_namesz; /* Length of note's name. */
+ uint32_t n_descsz; /* Length of note's value. */
+ uint32_t n_type; /* Type of note. */
+} Elf_Note;
+
+typedef Elf_Note Elf32_Nhdr; /* 32-bit note header. */
+typedef Elf_Note Elf64_Nhdr; /* 64-bit note header. */
+
+/*
+ * MIPS ELF options descriptor header.
+ */
+
+typedef struct {
+ Elf64_Byte kind; /* Type of options. */
+ Elf64_Byte size; /* Size of option descriptor. */
+ Elf64_Half section; /* Index of section affected. */
+ Elf64_Word info; /* Kind-specific information. */
+} Elf_Options;
+
+/*
+ * Option kinds.
+ */
+
+#define _ELF_DEFINE_OPTION_KINDS() \
+_ELF_DEFINE_ODK(ODK_NULL, 0, "undefined") \
+_ELF_DEFINE_ODK(ODK_REGINFO, 1, "register usage info") \
+_ELF_DEFINE_ODK(ODK_EXCEPTIONS, 2, "exception processing info") \
+_ELF_DEFINE_ODK(ODK_PAD, 3, "section padding") \
+_ELF_DEFINE_ODK(ODK_HWPATCH, 4, "hardware patch applied") \
+_ELF_DEFINE_ODK(ODK_FILL, 5, "fill value used by linker") \
+_ELF_DEFINE_ODK(ODK_TAGS, 6, "reserved space for tools") \
+_ELF_DEFINE_ODK(ODK_HWAND, 7, "hardware AND patch applied") \
+_ELF_DEFINE_ODK(ODK_HWOR, 8, "hardware OR patch applied") \
+_ELF_DEFINE_ODK(ODK_GP_GROUP, 9, \
+ "GP group to use for text/data sections") \
+_ELF_DEFINE_ODK(ODK_IDENT, 10, "ID information") \
+_ELF_DEFINE_ODK(ODK_PAGESIZE, 11, "page size infomation")
+
+#undef _ELF_DEFINE_ODK
+#define _ELF_DEFINE_ODK(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_OPTION_KINDS()
+ ODK__LAST__
+};
+
+/*
+ * ODK_EXCEPTIONS info field masks.
+ */
+
+#define _ELF_DEFINE_ODK_EXCEPTIONS_MASK() \
+_ELF_DEFINE_OEX(OEX_FPU_MIN, 0x0000001FUL, \
+ "minimum FPU exception which must be enabled") \
+_ELF_DEFINE_OEX(OEX_FPU_MAX, 0x00001F00UL, \
+ "maximum FPU exception which can be enabled") \
+_ELF_DEFINE_OEX(OEX_PAGE0, 0x00010000UL, \
+ "page zero must be mapped") \
+_ELF_DEFINE_OEX(OEX_SMM, 0x00020000UL, \
+ "run in sequential memory mode") \
+_ELF_DEFINE_OEX(OEX_PRECISEFP, 0x00040000UL, \
+ "run in precise FP exception mode") \
+_ELF_DEFINE_OEX(OEX_DISMISS, 0x00080000UL, \
+ "dismiss invalid address traps")
+
+#undef _ELF_DEFINE_OEX
+#define _ELF_DEFINE_OEX(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ODK_EXCEPTIONS_MASK()
+ OEX__LAST__
+};
+
+/*
+ * ODK_PAD info field masks.
+ */
+
+#define _ELF_DEFINE_ODK_PAD_MASK() \
+_ELF_DEFINE_OPAD(OPAD_PREFIX, 0x0001) \
+_ELF_DEFINE_OPAD(OPAD_POSTFIX, 0x0002) \
+_ELF_DEFINE_OPAD(OPAD_SYMBOL, 0x0004)
+
+#undef _ELF_DEFINE_OPAD
+#define _ELF_DEFINE_OPAD(N, V) N = V ,
+enum {
+ _ELF_DEFINE_ODK_PAD_MASK()
+ OPAD__LAST__
+};
+
+/*
+ * ODK_HWPATCH info field masks.
+ */
+
+#define _ELF_DEFINE_ODK_HWPATCH_MASK() \
+_ELF_DEFINE_OHW(OHW_R4KEOP, 0x00000001UL, \
+ "patch for R4000 branch at end-of-page bug") \
+_ELF_DEFINE_OHW(OHW_R8KPFETCH, 0x00000002UL, \
+ "R8000 prefetch bug may occur") \
+_ELF_DEFINE_OHW(OHW_R5KEOP, 0x00000004UL, \
+ "patch for R5000 branch at end-of-page bug") \
+_ELF_DEFINE_OHW(OHW_R5KCVTL, 0x00000008UL, \
+ "R5000 cvt.[ds].l bug: clean == 1") \
+_ELF_DEFINE_OHW(OHW_R10KLDL, 0x00000010UL, \
+ "needd patch for R10000 misaligned load")
+
+#undef _ELF_DEFINE_OHW
+#define _ELF_DEFINE_OHW(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ODK_HWPATCH_MASK()
+ OHW__LAST__
+};
+
+/*
+ * ODK_HWAND/ODK_HWOR info field and hwp_flags[12] masks.
+ */
+
+#define _ELF_DEFINE_ODK_HWP_MASK() \
+_ELF_DEFINE_HWP(OHWA0_R4KEOP_CHECKED, 0x00000001UL, \
+ "object checked for R4000 end-of-page bug") \
+_ELF_DEFINE_HWP(OHWA0_R4KEOP_CLEAN, 0x00000002UL, \
+ "object verified clean for R4000 end-of-page bug") \
+_ELF_DEFINE_HWP(OHWO0_FIXADE, 0x00000001UL, \
+ "object requires call to fixade")
+
+#undef _ELF_DEFINE_HWP
+#define _ELF_DEFINE_HWP(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ODK_HWP_MASK()
+ OHWX0__LAST__
+};
+
+/*
+ * ODK_IDENT/ODK_GP_GROUP info field masks.
+ */
+
+#define _ELF_DEFINE_ODK_GP_MASK() \
+_ELF_DEFINE_OGP(OGP_GROUP, 0x0000FFFFUL, "GP group number") \
+_ELF_DEFINE_OGP(OGP_SELF, 0x00010000UL, \
+ "GP group is self-contained")
+
+#undef _ELF_DEFINE_OGP
+#define _ELF_DEFINE_OGP(N, V, DESCR) N = V ,
+enum {
+ _ELF_DEFINE_ODK_GP_MASK()
+ OGP__LAST__
+};
+
+/*
+ * MIPS ELF register info descriptor.
+ */
+
+/* 32 bit RegInfo entry. */
+typedef struct {
+ Elf32_Word ri_gprmask; /* Mask of general register used. */
+ Elf32_Word ri_cprmask[4]; /* Mask of coprocessor register used. */
+ Elf32_Addr ri_gp_value; /* GP register value. */
+} Elf32_RegInfo;
+
+/* 64 bit RegInfo entry. */
+typedef struct {
+ Elf64_Word ri_gprmask; /* Mask of general register used. */
+ Elf64_Word ri_pad; /* Padding. */
+ Elf64_Word ri_cprmask[4]; /* Mask of coprocessor register used. */
+ Elf64_Addr ri_gp_value; /* GP register value. */
+} Elf64_RegInfo;
+
+/*
+ * Program Header Table (PHDR) entries.
+ */
+
+/* 32 bit PHDR entry. */
+typedef struct {
+ Elf32_Word p_type; /* Type of segment. */
+ Elf32_Off p_offset; /* File offset to segment. */
+ Elf32_Addr p_vaddr; /* Virtual address in memory. */
+ Elf32_Addr p_paddr; /* Physical address (if relevant). */
+ Elf32_Word p_filesz; /* Size of segment in file. */
+ Elf32_Word p_memsz; /* Size of segment in memory. */
+ Elf32_Word p_flags; /* Segment flags. */
+ Elf32_Word p_align; /* Alignment constraints. */
+} Elf32_Phdr;
+
+/* 64 bit PHDR entry. */
+typedef struct {
+ Elf64_Word p_type; /* Type of segment. */
+ Elf64_Word p_flags; /* File offset to segment. */
+ Elf64_Off p_offset; /* Virtual address in memory. */
+ Elf64_Addr p_vaddr; /* Physical address (if relevant). */
+ Elf64_Addr p_paddr; /* Size of segment in file. */
+ Elf64_Xword p_filesz; /* Size of segment in memory. */
+ Elf64_Xword p_memsz; /* Segment flags. */
+ Elf64_Xword p_align; /* Alignment constraints. */
+} Elf64_Phdr;
+
+
+/*
+ * Move entries, for describing data in COMMON blocks in a compact
+ * manner.
+ */
+
+/* 32-bit move entry. */
+typedef struct {
+ Elf32_Lword m_value; /* Initialization value. */
+ Elf32_Word m_info; /* Encoded size and index. */
+ Elf32_Word m_poffset; /* Offset relative to symbol. */
+ Elf32_Half m_repeat; /* Repeat count. */
+ Elf32_Half m_stride; /* Number of units to skip. */
+} Elf32_Move;
+
+/* 64-bit move entry. */
+typedef struct {
+ Elf64_Lword m_value; /* Initialization value. */
+ Elf64_Xword m_info; /* Encoded size and index. */
+ Elf64_Xword m_poffset; /* Offset relative to symbol. */
+ Elf64_Half m_repeat; /* Repeat count. */
+ Elf64_Half m_stride; /* Number of units to skip. */
+} Elf64_Move;
+
+#define ELF32_M_SYM(I) ((I) >> 8)
+#define ELF32_M_SIZE(I) ((unsigned char) (I))
+#define ELF32_M_INFO(M, S) (((M) << 8) + (unsigned char) (S))
+
+#define ELF64_M_SYM(I) ((I) >> 8)
+#define ELF64_M_SIZE(I) ((unsigned char) (I))
+#define ELF64_M_INFO(M, S) (((M) << 8) + (unsigned char) (S))
+
+/*
+ * Section Header Table (SHDR) entries.
+ */
+
+/* 32 bit SHDR */
+typedef struct {
+ Elf32_Word sh_name; /* index of section name */
+ Elf32_Word sh_type; /* section type */
+ Elf32_Word sh_flags; /* section flags */
+ Elf32_Addr sh_addr; /* in-memory address of section */
+ Elf32_Off sh_offset; /* file offset of section */
+ Elf32_Word sh_size; /* section size in bytes */
+ Elf32_Word sh_link; /* section header table link */
+ Elf32_Word sh_info; /* extra information */
+ Elf32_Word sh_addralign; /* alignment constraint */
+ Elf32_Word sh_entsize; /* size for fixed-size entries */
+} Elf32_Shdr;
+
+/* 64 bit SHDR */
+typedef struct {
+ Elf64_Word sh_name; /* index of section name */
+ Elf64_Word sh_type; /* section type */
+ Elf64_Xword sh_flags; /* section flags */
+ Elf64_Addr sh_addr; /* in-memory address of section */
+ Elf64_Off sh_offset; /* file offset of section */
+ Elf64_Xword sh_size; /* section size in bytes */
+ Elf64_Word sh_link; /* section header table link */
+ Elf64_Word sh_info; /* extra information */
+ Elf64_Xword sh_addralign; /* alignment constraint */
+ Elf64_Xword sh_entsize; /* size for fixed-size entries */
+} Elf64_Shdr;
+
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+ Elf32_Word st_name; /* index of symbol's name */
+ Elf32_Addr st_value; /* value for the symbol */
+ Elf32_Word st_size; /* size of associated data */
+ unsigned char st_info; /* type and binding attributes */
+ unsigned char st_other; /* visibility */
+ Elf32_Half st_shndx; /* index of related section */
+} Elf32_Sym;
+
+typedef struct {
+ Elf64_Word st_name; /* index of symbol's name */
+ unsigned char st_info; /* value for the symbol */
+ unsigned char st_other; /* size of associated data */
+ Elf64_Half st_shndx; /* type and binding attributes */
+ Elf64_Addr st_value; /* visibility */
+ Elf64_Xword st_size; /* index of related section */
+} Elf64_Sym;
+
+#define ELF32_ST_BIND(I) ((I) >> 4)
+#define ELF32_ST_TYPE(I) ((I) & 0xFU)
+#define ELF32_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF))
+
+#define ELF64_ST_BIND(I) ((I) >> 4)
+#define ELF64_ST_TYPE(I) ((I) & 0xFU)
+#define ELF64_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF))
+
+#define ELF32_ST_VISIBILITY(O) ((O) & 0x3)
+#define ELF64_ST_VISIBILITY(O) ((O) & 0x3)
+
+/*
+ * Syminfo descriptors, containing additional symbol information.
+ */
+
+/* 32-bit entry. */
+typedef struct {
+ Elf32_Half si_boundto; /* Entry index with additional flags. */
+ Elf32_Half si_flags; /* Flags. */
+} Elf32_Syminfo;
+
+/* 64-bit entry. */
+typedef struct {
+ Elf64_Half si_boundto; /* Entry index with additional flags. */
+ Elf64_Half si_flags; /* Flags. */
+} Elf64_Syminfo;
+
+/*
+ * Relocation descriptors.
+ */
+
+typedef struct {
+ Elf32_Addr r_offset; /* location to apply relocation to */
+ Elf32_Word r_info; /* type+section for relocation */
+} Elf32_Rel;
+
+typedef struct {
+ Elf32_Addr r_offset; /* location to apply relocation to */
+ Elf32_Word r_info; /* type+section for relocation */
+ Elf32_Sword r_addend; /* constant addend */
+} Elf32_Rela;
+
+typedef struct {
+ Elf64_Addr r_offset; /* location to apply relocation to */
+ Elf64_Xword r_info; /* type+section for relocation */
+} Elf64_Rel;
+
+typedef struct {
+ Elf64_Addr r_offset; /* location to apply relocation to */
+ Elf64_Xword r_info; /* type+section for relocation */
+ Elf64_Sxword r_addend; /* constant addend */
+} Elf64_Rela;
+
+
+#define ELF32_R_SYM(I) ((I) >> 8)
+#define ELF32_R_TYPE(I) ((unsigned char) (I))
+#define ELF32_R_INFO(S,T) (((S) << 8) + (unsigned char) (T))
+
+#define ELF64_R_SYM(I) ((I) >> 32)
+#define ELF64_R_TYPE(I) ((I) & 0xFFFFFFFFUL)
+#define ELF64_R_INFO(S,T) (((S) << 32) + ((T) & 0xFFFFFFFFUL))
+
+/*
+ * Symbol versioning structures.
+ */
+
+/* 32-bit structures. */
+typedef struct
+{
+ Elf32_Word vda_name; /* Index to name. */
+ Elf32_Word vda_next; /* Offset to next entry. */
+} Elf32_Verdaux;
+
+typedef struct
+{
+ Elf32_Word vna_hash; /* Hash value of dependency name. */
+ Elf32_Half vna_flags; /* Flags. */
+ Elf32_Half vna_other; /* Unused. */
+ Elf32_Word vna_name; /* Offset to dependency name. */
+ Elf32_Word vna_next; /* Offset to next vernaux entry. */
+} Elf32_Vernaux;
+
+typedef struct
+{
+ Elf32_Half vd_version; /* Version information. */
+ Elf32_Half vd_flags; /* Flags. */
+ Elf32_Half vd_ndx; /* Index into the versym section. */
+ Elf32_Half vd_cnt; /* Number of aux entries. */
+ Elf32_Word vd_hash; /* Hash value of name. */
+ Elf32_Word vd_aux; /* Offset to aux entries. */
+ Elf32_Word vd_next; /* Offset to next version definition. */
+} Elf32_Verdef;
+
+typedef struct
+{
+ Elf32_Half vn_version; /* Version number. */
+ Elf32_Half vn_cnt; /* Number of aux entries. */
+ Elf32_Word vn_file; /* Offset of associated file name. */
+ Elf32_Word vn_aux; /* Offset of vernaux array. */
+ Elf32_Word vn_next; /* Offset of next verneed entry. */
+} Elf32_Verneed;
+
+typedef Elf32_Half Elf32_Versym;
+
+/* 64-bit structures. */
+
+typedef struct {
+ Elf64_Word vda_name; /* Index to name. */
+ Elf64_Word vda_next; /* Offset to next entry. */
+} Elf64_Verdaux;
+
+typedef struct {
+ Elf64_Word vna_hash; /* Hash value of dependency name. */
+ Elf64_Half vna_flags; /* Flags. */
+ Elf64_Half vna_other; /* Unused. */
+ Elf64_Word vna_name; /* Offset to dependency name. */
+ Elf64_Word vna_next; /* Offset to next vernaux entry. */
+} Elf64_Vernaux;
+
+typedef struct {
+ Elf64_Half vd_version; /* Version information. */
+ Elf64_Half vd_flags; /* Flags. */
+ Elf64_Half vd_ndx; /* Index into the versym section. */
+ Elf64_Half vd_cnt; /* Number of aux entries. */
+ Elf64_Word vd_hash; /* Hash value of name. */
+ Elf64_Word vd_aux; /* Offset to aux entries. */
+ Elf64_Word vd_next; /* Offset to next version definition. */
+} Elf64_Verdef;
+
+typedef struct {
+ Elf64_Half vn_version; /* Version number. */
+ Elf64_Half vn_cnt; /* Number of aux entries. */
+ Elf64_Word vn_file; /* Offset of associated file name. */
+ Elf64_Word vn_aux; /* Offset of vernaux array. */
+ Elf64_Word vn_next; /* Offset of next verneed entry. */
+} Elf64_Verneed;
+
+typedef Elf64_Half Elf64_Versym;
+
+
+/*
+ * The header for GNU-style hash sections.
+ */
+
+typedef struct {
+ uint32_t gh_nbuckets; /* Number of hash buckets. */
+ uint32_t gh_symndx; /* First visible symbol in .dynsym. */
+ uint32_t gh_maskwords; /* #maskwords used in bloom filter. */
+ uint32_t gh_shift2; /* Bloom filter shift count. */
+} Elf_GNU_Hash_Header;
+
+#endif /* _ELFDEFINITIONS_H_ */
diff --git a/linkers/elftoolchain/common/native-elf-format b/linkers/elftoolchain/common/native-elf-format
new file mode 100755
index 0000000..af70759
--- /dev/null
+++ b/linkers/elftoolchain/common/native-elf-format
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# $Id: native-elf-format 2064 2011-10-26 15:12:32Z jkoshy $
+#
+# Find the native ELF format for a host platform by compiling a
+# test object and examining the resulting object.
+#
+# This script is used if there is no easy way to determine this
+# information statically at compile time.
+
+program=`basename $0`
+tmp_c=`mktemp -u nefXXXXXX`.c
+tmp_o=`echo ${tmp_c} | sed -e 's/.c$/.o/'`
+
+trap "rm -f ${tmp_c} ${tmp_o}" 0 1 2 3 15
+
+touch ${tmp_c}
+
+echo "/* Generated by ${program} on `date` */"
+
+cc -c ${tmp_c} -o ${tmp_o}
+readelf -h ${tmp_o} | awk '
+$1 ~ "Class:" {
+ sub("ELF","",$2); elfclass = $2;
+ }
+$1 ~ "Data:" {
+ if (match($0, "little")) {
+ elfdata = "LSB";
+ } else {
+ elfdata = "MSB";
+ }
+ }
+$1 ~ "Machine:" {
+ if (match($0, "Intel.*386")) {
+ elfarch = "EM_386";
+ } else if (match($0, ".*X86-64")) {
+ elfarch = "EM_X86_64";
+ } else {
+ elfarch = "unknown";
+ }
+ }
+END {
+ printf("#define ELFTC_CLASS ELFCLASS%s\n", elfclass);
+ printf("#define ELFTC_ARCH %s\n", elfarch);
+ printf("#define ELFTC_BYTEORDER ELFDATA2%s\n", elfdata);
+}'
+
diff --git a/linkers/elftoolchain/common/os.Linux.mk b/linkers/elftoolchain/common/os.Linux.mk
new file mode 100644
index 0000000..2339e2a
--- /dev/null
+++ b/linkers/elftoolchain/common/os.Linux.mk
@@ -0,0 +1,13 @@
+#
+# Build recipes for Linux based operating systems.
+#
+# $Id: os.Linux.mk 2064 2011-10-26 15:12:32Z jkoshy $
+
+_NATIVE_ELF_FORMAT = native-elf-format
+
+.BEGIN: ${_NATIVE_ELF_FORMAT}.h
+
+${_NATIVE_ELF_FORMAT}.h:
+ ${.CURDIR}/${_NATIVE_ELF_FORMAT} > ${.TARGET} || rm ${.TARGET}
+
+CLEANFILES += ${_NATIVE_ELF_FORMAT}.h
diff --git a/linkers/elftoolchain/common/uthash.h b/linkers/elftoolchain/common/uthash.h
new file mode 100644
index 0000000..8428b9c
--- /dev/null
+++ b/linkers/elftoolchain/common/uthash.h
@@ -0,0 +1,906 @@
+/*
+Copyright (c) 2003-2011, Troy D. Hanson http://uthash.sourceforge.net
+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.
+
+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.
+*/
+
+/* $Id: uthash.h 2064 2011-10-26 15:12:32Z jkoshy $ */
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#include <string.h> /* memcmp,strlen */
+#include <stddef.h> /* ptrdiff_t */
+#include <stdlib.h> /* exit() */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#else /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ char **_da_dst = (char**)(&(dst)); \
+ *_da_dst = (char*)(src); \
+} while(0)
+#else
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ (dst) = DECLTYPE(dst)(src); \
+} while(0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on win32 */
+#ifdef _MSC_VER
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#else
+#include <inttypes.h> /* uint32_t */
+#endif
+
+#define UTHASH_VERSION 1.9.4
+
+#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
+#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
+#define uthash_free(ptr,sz) free(ptr) /* free fcn */
+
+#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
+#define uthash_expand_fyi(tbl) /* can be defined to log expands */
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhe */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+
+#define HASH_FIND(hh,head,keyptr,keylen,out) \
+do { \
+ unsigned _hf_bkt,_hf_hashv; \
+ out=NULL; \
+ if (head) { \
+ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
+ if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
+ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
+ keyptr,keylen,out); \
+ } \
+ } \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+#define HASH_BLOOM_MAKE(tbl) \
+do { \
+ (tbl)->bloom_nbits = HASH_BLOOM; \
+ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
+ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
+ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
+ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
+} while (0);
+
+#define HASH_BLOOM_FREE(tbl) \
+do { \
+ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+} while (0);
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+
+#define HASH_BLOOM_ADD(tbl,hashv) \
+ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#define HASH_BLOOM_TEST(tbl,hashv) \
+ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#endif
+
+#define HASH_MAKE_TABLE(hh,head) \
+do { \
+ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
+ sizeof(UT_hash_table)); \
+ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
+ (head)->hh.tbl->tail = &((head)->hh); \
+ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
+ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
+ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
+ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl->buckets, 0, \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_MAKE((head)->hh.tbl); \
+ (head)->hh.tbl->signature = HASH_SIGNATURE; \
+} while(0)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
+ HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
+do { \
+ unsigned _ha_bkt; \
+ (add)->hh.next = NULL; \
+ (add)->hh.key = (char*)keyptr; \
+ (add)->hh.keylen = keylen_in; \
+ if (!(head)) { \
+ head = (add); \
+ (head)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh,head); \
+ } else { \
+ (head)->hh.tbl->tail->next = (add); \
+ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
+ (head)->hh.tbl->tail = &((add)->hh); \
+ } \
+ (head)->hh.tbl->num_items++; \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
+ (add)->hh.hashv, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
+ HASH_FSCK(hh,head); \
+} while(0)
+
+#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
+do { \
+ bkt = ((hashv) & ((num_bkts) - 1)); \
+} while(0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ * HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr) \
+do { \
+ unsigned _hd_bkt; \
+ struct UT_hash_handle *_hd_hh_del; \
+ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ head = NULL; \
+ } else { \
+ _hd_hh_del = &((delptr)->hh); \
+ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
+ (head)->hh.tbl->tail = \
+ (UT_hash_handle*)((char*)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho); \
+ } \
+ if ((delptr)->hh.prev) { \
+ ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \
+ } else { \
+ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
+ } \
+ if (_hd_hh_del->next) { \
+ ((UT_hash_handle*)((char*)_hd_hh_del->next + \
+ (head)->hh.tbl->hho))->prev = \
+ _hd_hh_del->prev; \
+ } \
+ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
+ (head)->hh.tbl->num_items--; \
+ } \
+ HASH_FSCK(hh,head); \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out) \
+ HASH_FIND(hh,head,findstr,strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add) \
+ HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
+#define HASH_FIND_INT(head,findint,out) \
+ HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add) \
+ HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_FIND_PTR(head,findptr,out) \
+ HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add) \
+ HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_DEL(head,delptr) \
+ HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head) \
+do { \
+ unsigned _bkt_i; \
+ unsigned _count, _bkt_count; \
+ char *_prev; \
+ struct UT_hash_handle *_thh; \
+ if (head) { \
+ _count = 0; \
+ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
+ _bkt_count = 0; \
+ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
+ _prev = NULL; \
+ while (_thh) { \
+ if (_prev != (char*)(_thh->hh_prev)) { \
+ HASH_OOPS("invalid hh_prev %p, actual %p\n", \
+ _thh->hh_prev, _prev ); \
+ } \
+ _bkt_count++; \
+ _prev = (char*)(_thh); \
+ _thh = _thh->hh_next; \
+ } \
+ _count += _bkt_count; \
+ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
+ HASH_OOPS("invalid bucket count %d, actual %d\n", \
+ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
+ } \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid hh item count %d, actual %d\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ /* traverse hh in app order; check next/prev integrity, count */ \
+ _count = 0; \
+ _prev = NULL; \
+ _thh = &(head)->hh; \
+ while (_thh) { \
+ _count++; \
+ if (_prev !=(char*)(_thh->prev)) { \
+ HASH_OOPS("invalid prev %p, actual %p\n", \
+ _thh->prev, _prev ); \
+ } \
+ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
+ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
+ (head)->hh.tbl->hho) : NULL ); \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid app item count %d, actual %d\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ } \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
+do { \
+ unsigned _klen = fieldlen; \
+ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
+ write(HASH_EMIT_KEYS, keyptr, fieldlen); \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6 */
+#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hb_keylen=keylen; \
+ char *_hb_key=(char*)(key); \
+ (hashv) = 0; \
+ while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \
+ bkt = (hashv) & (num_bkts-1); \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _sx_i; \
+ char *_hs_key=(char*)(key); \
+ hashv = 0; \
+ for(_sx_i=0; _sx_i < keylen; _sx_i++) \
+ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
+ bkt = hashv & (num_bkts-1); \
+} while (0)
+
+#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _fn_i; \
+ char *_hf_key=(char*)(key); \
+ hashv = 2166136261UL; \
+ for(_fn_i=0; _fn_i < keylen; _fn_i++) \
+ hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \
+ bkt = hashv & (num_bkts-1); \
+} while(0);
+
+#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _ho_i; \
+ char *_ho_key=(char*)(key); \
+ hashv = 0; \
+ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
+ hashv += _ho_key[_ho_i]; \
+ hashv += (hashv << 10); \
+ hashv ^= (hashv >> 6); \
+ } \
+ hashv += (hashv << 3); \
+ hashv ^= (hashv >> 11); \
+ hashv += (hashv << 15); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#define HASH_JEN_MIX(a,b,c) \
+do { \
+ a -= b; a -= c; a ^= ( c >> 13 ); \
+ b -= c; b -= a; b ^= ( a << 8 ); \
+ c -= a; c -= b; c ^= ( b >> 13 ); \
+ a -= b; a -= c; a ^= ( c >> 12 ); \
+ b -= c; b -= a; b ^= ( a << 16 ); \
+ c -= a; c -= b; c ^= ( b >> 5 ); \
+ a -= b; a -= c; a ^= ( c >> 3 ); \
+ b -= c; b -= a; b ^= ( a << 10 ); \
+ c -= a; c -= b; c ^= ( b >> 15 ); \
+} while (0)
+
+#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hj_i,_hj_j,_hj_k; \
+ char *_hj_key=(char*)(key); \
+ hashv = 0xfeedbeef; \
+ _hj_i = _hj_j = 0x9e3779b9; \
+ _hj_k = keylen; \
+ while (_hj_k >= 12) { \
+ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ + ( (unsigned)_hj_key[2] << 16 ) \
+ + ( (unsigned)_hj_key[3] << 24 ) ); \
+ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ + ( (unsigned)_hj_key[6] << 16 ) \
+ + ( (unsigned)_hj_key[7] << 24 ) ); \
+ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ + ( (unsigned)_hj_key[10] << 16 ) \
+ + ( (unsigned)_hj_key[11] << 24 ) ); \
+ \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ \
+ _hj_key += 12; \
+ _hj_k -= 12; \
+ } \
+ hashv += keylen; \
+ switch ( _hj_k ) { \
+ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
+ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
+ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
+ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
+ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
+ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
+ case 5: _hj_j += _hj_key[4]; \
+ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
+ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
+ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
+ case 1: _hj_i += _hj_key[0]; \
+ } \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ char *_sfh_key=(char*)(key); \
+ uint32_t _sfh_tmp, _sfh_len = keylen; \
+ \
+ int _sfh_rem = _sfh_len & 3; \
+ _sfh_len >>= 2; \
+ hashv = 0xcafebabe; \
+ \
+ /* Main loop */ \
+ for (;_sfh_len > 0; _sfh_len--) { \
+ hashv += get16bits (_sfh_key); \
+ _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \
+ hashv = (hashv << 16) ^ _sfh_tmp; \
+ _sfh_key += 2*sizeof (uint16_t); \
+ hashv += hashv >> 11; \
+ } \
+ \
+ /* Handle end cases */ \
+ switch (_sfh_rem) { \
+ case 3: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 16; \
+ hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \
+ hashv += hashv >> 11; \
+ break; \
+ case 2: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 11; \
+ hashv += hashv >> 17; \
+ break; \
+ case 1: hashv += *_sfh_key; \
+ hashv ^= hashv << 10; \
+ hashv += hashv >> 1; \
+ } \
+ \
+ /* Force "avalanching" of final 127 bits */ \
+ hashv ^= hashv << 3; \
+ hashv += hashv >> 5; \
+ hashv ^= hashv << 4; \
+ hashv += hashv >> 17; \
+ hashv ^= hashv << 25; \
+ hashv += hashv >> 6; \
+ bkt = hashv & (num_bkts-1); \
+} while(0);
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ * gcc -m64 -dM -E - < /dev/null (on gcc)
+ * cc -## a.c (where a.c is a simple test file) (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
+ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
+ MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do { \
+ _h ^= _h >> 16; \
+ _h *= 0x85ebca6b; \
+ _h ^= _h >> 13; \
+ _h *= 0xc2b2ae35l; \
+ _h ^= _h >> 16; \
+} while(0)
+
+#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ const uint8_t *_mur_data = (const uint8_t*)(key); \
+ const int _mur_nblocks = (keylen) / 4; \
+ uint32_t _mur_h1 = 0xf88D5353; \
+ uint32_t _mur_c1 = 0xcc9e2d51; \
+ uint32_t _mur_c2 = 0x1b873593; \
+ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
+ int _mur_i; \
+ for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
+ uint32_t _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ \
+ _mur_h1 ^= _mur_k1; \
+ _mur_h1 = MUR_ROTL32(_mur_h1,13); \
+ _mur_h1 = _mur_h1*5+0xe6546b64; \
+ } \
+ const uint8_t *_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \
+ uint32_t _mur_k1=0; \
+ switch((keylen) & 3) { \
+ case 3: _mur_k1 ^= _mur_tail[2] << 16; \
+ case 2: _mur_k1 ^= _mur_tail[1] << 8; \
+ case 1: _mur_k1 ^= _mur_tail[0]; \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ _mur_h1 ^= _mur_k1; \
+ } \
+ _mur_h1 ^= (keylen); \
+ MUR_FMIX(_mur_h1); \
+ hashv = _mur_h1; \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+#endif /* HASH_USING_NO_STRICT_ALIASING */
+
+/* key comparison function; return 0 if keys equal */
+#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
+do { \
+ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
+ else out=NULL; \
+ while (out) { \
+ if (out->hh.keylen == keylen_in) { \
+ if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \
+ } \
+ if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \
+ else out = NULL; \
+ } \
+} while(0)
+
+/* add an item to a bucket */
+#define HASH_ADD_TO_BKT(head,addhh) \
+do { \
+ head.count++; \
+ (addhh)->hh_next = head.hh_head; \
+ (addhh)->hh_prev = NULL; \
+ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
+ (head).hh_head=addhh; \
+ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
+ && (addhh)->tbl->noexpand != 1) { \
+ HASH_EXPAND_BUCKETS((addhh)->tbl); \
+ } \
+} while(0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del) \
+ (head).count--; \
+ if ((head).hh_head == hh_del) { \
+ (head).hh_head = hh_del->hh_next; \
+ } \
+ if (hh_del->hh_prev) { \
+ hh_del->hh_prev->hh_next = hh_del->hh_next; \
+ } \
+ if (hh_del->hh_next) { \
+ hh_del->hh_next->hh_prev = hh_del->hh_prev; \
+ }
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ * ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(tbl) \
+do { \
+ unsigned _he_bkt; \
+ unsigned _he_bkt_i; \
+ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
+ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
+ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
+ memset(_he_new_buckets, 0, \
+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ tbl->ideal_chain_maxlen = \
+ (tbl->num_items >> (tbl->log2_num_buckets+1)) + \
+ ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
+ tbl->nonideal_items = 0; \
+ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
+ { \
+ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
+ while (_he_thh) { \
+ _he_hh_nxt = _he_thh->hh_next; \
+ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
+ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
+ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
+ tbl->nonideal_items++; \
+ _he_newbkt->expand_mult = _he_newbkt->count / \
+ tbl->ideal_chain_maxlen; \
+ } \
+ _he_thh->hh_prev = NULL; \
+ _he_thh->hh_next = _he_newbkt->hh_head; \
+ if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
+ _he_thh; \
+ _he_newbkt->hh_head = _he_thh; \
+ _he_thh = _he_hh_nxt; \
+ } \
+ } \
+ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+ tbl->num_buckets *= 2; \
+ tbl->log2_num_buckets++; \
+ tbl->buckets = _he_new_buckets; \
+ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
+ (tbl->ineff_expands+1) : 0; \
+ if (tbl->ineff_expands > 1) { \
+ tbl->noexpand=1; \
+ uthash_noexpand_fyi(tbl); \
+ } \
+ uthash_expand_fyi(tbl); \
+} while(0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn) \
+do { \
+ unsigned _hs_i; \
+ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
+ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
+ if (head) { \
+ _hs_insize = 1; \
+ _hs_looping = 1; \
+ _hs_list = &((head)->hh); \
+ while (_hs_looping) { \
+ _hs_p = _hs_list; \
+ _hs_list = NULL; \
+ _hs_tail = NULL; \
+ _hs_nmerges = 0; \
+ while (_hs_p) { \
+ _hs_nmerges++; \
+ _hs_q = _hs_p; \
+ _hs_psize = 0; \
+ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
+ _hs_psize++; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ if (! (_hs_q) ) break; \
+ } \
+ _hs_qsize = _hs_insize; \
+ while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
+ if (_hs_psize == 0) { \
+ _hs_e = _hs_q; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_qsize--; \
+ } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
+ _hs_e = _hs_p; \
+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \
+ ((void*)((char*)(_hs_p->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_psize--; \
+ } else if (( \
+ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+ ) <= 0) { \
+ _hs_e = _hs_p; \
+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \
+ ((void*)((char*)(_hs_p->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_psize--; \
+ } else { \
+ _hs_e = _hs_q; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_qsize--; \
+ } \
+ if ( _hs_tail ) { \
+ _hs_tail->next = ((_hs_e) ? \
+ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
+ } else { \
+ _hs_list = _hs_e; \
+ } \
+ _hs_e->prev = ((_hs_tail) ? \
+ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
+ _hs_tail = _hs_e; \
+ } \
+ _hs_p = _hs_q; \
+ } \
+ _hs_tail->next = NULL; \
+ if ( _hs_nmerges <= 1 ) { \
+ _hs_looping=0; \
+ (head)->hh.tbl->tail = _hs_tail; \
+ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
+ } \
+ _hs_insize *= 2; \
+ } \
+ HASH_FSCK(hh,head); \
+ } \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
+do { \
+ unsigned _src_bkt, _dst_bkt; \
+ void *_last_elt=NULL, *_elt; \
+ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
+ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
+ if (src) { \
+ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
+ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
+ _src_hh; \
+ _src_hh = _src_hh->hh_next) { \
+ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
+ if (cond(_elt)) { \
+ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
+ _dst_hh->key = _src_hh->key; \
+ _dst_hh->keylen = _src_hh->keylen; \
+ _dst_hh->hashv = _src_hh->hashv; \
+ _dst_hh->prev = _last_elt; \
+ _dst_hh->next = NULL; \
+ if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
+ if (!dst) { \
+ DECLTYPE_ASSIGN(dst,_elt); \
+ HASH_MAKE_TABLE(hh_dst,dst); \
+ } else { \
+ _dst_hh->tbl = (dst)->hh_dst.tbl; \
+ } \
+ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
+ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
+ (dst)->hh_dst.tbl->num_items++; \
+ _last_elt = _elt; \
+ _last_elt_hh = _dst_hh; \
+ } \
+ } \
+ } \
+ } \
+ HASH_FSCK(hh_dst,dst); \
+} while (0)
+
+#define HASH_CLEAR(hh,head) \
+do { \
+ if (head) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head)=NULL; \
+ } \
+} while(0)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp) \
+for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \
+ el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
+#else
+#define HASH_ITER(hh,head,el,tmp) \
+for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \
+ el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
+
+typedef struct UT_hash_bucket {
+ struct UT_hash_handle *hh_head;
+ unsigned count;
+
+ /* expand_mult is normally set to 0. In this situation, the max chain length
+ * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+ * the bucket's chain exceeds this length, bucket expansion is triggered).
+ * However, setting expand_mult to a non-zero value delays bucket expansion
+ * (that would be triggered by additions to this particular bucket)
+ * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+ * (The multiplier is simply expand_mult+1). The whole idea of this
+ * multiplier is to reduce bucket expansions, since they are expensive, in
+ * situations where we know that a particular bucket tends to be overused.
+ * It is better to let its chain length grow to a longer yet-still-bounded
+ * value, than to do an O(n) bucket expansion too often.
+ */
+ unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1
+#define HASH_BLOOM_SIGNATURE 0xb12220f2
+
+typedef struct UT_hash_table {
+ UT_hash_bucket *buckets;
+ unsigned num_buckets, log2_num_buckets;
+ unsigned num_items;
+ struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
+ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+ /* in an ideal situation (all buckets used equally), no bucket would have
+ * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+ unsigned ideal_chain_maxlen;
+
+ /* nonideal_items is the number of items in the hash whose chain position
+ * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+ * hash distribution; reaching them in a chain traversal takes >ideal steps */
+ unsigned nonideal_items;
+
+ /* ineffective expands occur when a bucket doubling was performed, but
+ * afterward, more than half the items in the hash had nonideal chain
+ * positions. If this happens on two consecutive expansions we inhibit any
+ * further expansion, as it's not helping; this happens when the hash
+ * function isn't a good fit for the key domain. When expansion is inhibited
+ * the hash will still work, albeit no longer in constant time. */
+ unsigned ineff_expands, noexpand;
+
+ uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+ uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+ uint8_t *bloom_bv;
+ char bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+ struct UT_hash_table *tbl;
+ void *prev; /* prev element in app order */
+ void *next; /* next element in app order */
+ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
+ struct UT_hash_handle *hh_next; /* next hh in bucket order */
+ void *key; /* ptr to enclosing struct's key */
+ unsigned keylen; /* enclosing struct's key len */
+ unsigned hashv; /* result of hash-fcn(key) */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/linkers/elftoolchain/libelf/Makefile b/linkers/elftoolchain/libelf/Makefile
new file mode 100644
index 0000000..41e902a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/Makefile
@@ -0,0 +1,158 @@
+# $Id: Makefile 1345 2011-01-01 11:17:52Z jkoshy $
+
+TOP= ${.CURDIR}/..
+
+LIB= elf
+
+SRCS= elf.c \
+ elf_begin.c \
+ elf_cntl.c \
+ elf_end.c elf_errmsg.c elf_errno.c \
+ elf_data.c \
+ elf_fill.c \
+ elf_flag.c \
+ elf_getarhdr.c \
+ elf_getarsym.c \
+ elf_getbase.c \
+ elf_getident.c \
+ elf_hash.c \
+ elf_kind.c \
+ elf_memory.c \
+ elf_next.c \
+ elf_rand.c \
+ elf_rawfile.c \
+ elf_phnum.c \
+ elf_shnum.c \
+ elf_shstrndx.c \
+ elf_scn.c \
+ elf_strptr.c \
+ elf_update.c \
+ elf_version.c \
+ gelf_cap.c \
+ gelf_checksum.c \
+ gelf_dyn.c \
+ gelf_ehdr.c \
+ gelf_getclass.c \
+ gelf_fsize.c \
+ gelf_move.c \
+ gelf_phdr.c \
+ gelf_rel.c \
+ gelf_rela.c \
+ gelf_shdr.c \
+ gelf_sym.c \
+ gelf_syminfo.c \
+ gelf_symshndx.c \
+ gelf_xlate.c \
+ libelf_align.c \
+ libelf_allocate.c \
+ libelf_ar.c \
+ libelf_ar_util.c \
+ libelf_checksum.c \
+ libelf_data.c \
+ libelf_ehdr.c \
+ libelf_extended.c \
+ libelf_phdr.c \
+ libelf_shdr.c \
+ libelf_xlate.c \
+ ${GENSRCS}
+INCS= libelf.h gelf.h
+
+GENSRCS= libelf_fsize.c libelf_msize.c libelf_convert.c
+CLEANFILES= ${GENSRCS}
+
+SHLIB_MAJOR= 1
+
+WARNS?= 6
+
+MAN= elf.3 \
+ elf_begin.3 \
+ elf_cntl.3 \
+ elf_end.3 \
+ elf_errmsg.3 \
+ elf_fill.3 \
+ elf_flagdata.3 \
+ elf_getarhdr.3 \
+ elf_getarsym.3 \
+ elf_getbase.3 \
+ elf_getdata.3 \
+ elf_getident.3 \
+ elf_getscn.3 \
+ elf_getphdrnum.3 \
+ elf_getphnum.3 \
+ elf_getshdrnum.3 \
+ elf_getshnum.3 \
+ elf_getshdrstrndx.3 \
+ elf_getshstrndx.3 \
+ elf_hash.3 \
+ elf_kind.3 \
+ elf_memory.3 \
+ elf_next.3 \
+ elf_rawfile.3 \
+ elf_rand.3 \
+ elf_strptr.3 \
+ elf_update.3 \
+ elf_version.3 \
+ gelf.3 \
+ gelf_checksum.3 \
+ gelf_fsize.3 \
+ gelf_getcap.3 \
+ gelf_getclass.3 \
+ gelf_getdyn.3 \
+ gelf_getehdr.3 \
+ gelf_getmove.3 \
+ gelf_getphdr.3 \
+ gelf_getrel.3 \
+ gelf_getrela.3 \
+ gelf_getshdr.3 \
+ gelf_getsym.3 \
+ gelf_getsyminfo.3 \
+ gelf_getsymshndx.3 \
+ gelf_newehdr.3 \
+ gelf_newphdr.3 \
+ gelf_update_ehdr.3 \
+ gelf_xlatetof.3
+
+MLINKS+= \
+ elf_errmsg.3 elf_errno.3 \
+ elf_flagdata.3 elf_flagarhdr.3 \
+ elf_flagdata.3 elf_flagehdr.3 \
+ elf_flagdata.3 elf_flagelf.3 \
+ elf_flagdata.3 elf_flagphdr.3 \
+ elf_flagdata.3 elf_flagscn.3 \
+ elf_flagdata.3 elf_flagshdr.3 \
+ elf_getdata.3 elf_newdata.3 \
+ elf_getdata.3 elf_rawdata.3 \
+ elf_getscn.3 elf_ndxscn.3 \
+ elf_getscn.3 elf_newscn.3 \
+ elf_getscn.3 elf_nextscn.3 \
+ elf_getshstrndx.3 elf_setshstrndx.3 \
+ gelf_getcap.3 gelf_update_cap.3 \
+ gelf_getdyn.3 gelf_update_dyn.3 \
+ gelf_getmove.3 gelf_update_move.3 \
+ gelf_getrel.3 gelf_update_rel.3 \
+ gelf_getrela.3 gelf_update_rela.3 \
+ gelf_getsym.3 gelf_update_sym.3 \
+ gelf_getsyminfo.3 gelf_update_syminfo.3 \
+ gelf_getsymshndx.3 gelf_update_symshndx.3 \
+ gelf_update_ehdr.3 gelf_update_phdr.3 \
+ gelf_update_ehdr.3 gelf_update_shdr.3 \
+ gelf_xlatetof.3 gelf_xlatetom.3
+
+.for E in 32 64
+MLINKS+= \
+ gelf_checksum.3 elf${E}_checksum.3 \
+ gelf_fsize.3 elf${E}_fsize.3 \
+ gelf_getehdr.3 elf${E}_getehdr.3 \
+ gelf_getphdr.3 elf${E}_getphdr.3 \
+ gelf_getshdr.3 elf${E}_getshdr.3 \
+ gelf_newehdr.3 elf${E}_newehdr.3 \
+ gelf_newphdr.3 elf${E}_newphdr.3 \
+ gelf_xlatetof.3 elf${E}_xlatetof.3 \
+ gelf_xlatetof.3 elf${E}_xlatetom.3
+.endfor
+
+libelf_convert.c: elf_types.m4 libelf_convert.m4
+libelf_fsize.c: elf_types.m4 libelf_fsize.m4
+libelf_msize.c: elf_types.m4 libelf_msize.m4
+
+.include "${TOP}/mk/elftoolchain.lib.mk"
diff --git a/linkers/elftoolchain/libelf/Version.map b/linkers/elftoolchain/libelf/Version.map
new file mode 100644
index 0000000..2c595ea
--- /dev/null
+++ b/linkers/elftoolchain/libelf/Version.map
@@ -0,0 +1,97 @@
+/*
+ * $Id: Version.map 2033 2011-10-23 09:21:13Z jkoshy $
+ *
+ * $FreeBSD: src/lib/libelf/Version.map,v 1.3 2007/04/29 14:05:22 deischen Exp $
+ */
+FBSD_1.0 {
+global:
+ elf32_checksum;
+ elf32_fsize;
+ elf32_getehdr;
+ elf32_getphdr;
+ elf32_getshdr;
+ elf32_newehdr;
+ elf32_newphdr;
+ elf32_xlatetof;
+ elf32_xlatetom;
+ elf64_checksum;
+ elf64_fsize;
+ elf64_getehdr;
+ elf64_getphdr;
+ elf64_getshdr;
+ elf64_newehdr;
+ elf64_newphdr;
+ elf64_xlatetof;
+ elf64_xlatetom;
+ elf_begin;
+ elf_cntl;
+ elf_end;
+ elf_errmsg;
+ elf_errno;
+ elf_fill;
+ elf_flagarhdr;
+ elf_flagdata;
+ elf_flagehdr;
+ elf_flagelf;
+ elf_flagphdr;
+ elf_flagscn;
+ elf_flagshdr;
+ elf_getarhdr;
+ elf_getarsym;
+ elf_getbase;
+ elf_getdata;
+ elf_getident;
+ elf_getscn;
+ elf_getphdrnum;
+ elf_getphnum;
+ elf_getshdrnum;
+ elf_getshnum;
+ elf_getshdrstrndx;
+ elf_getshstrndx;
+ elf_hash;
+ elf_kind;
+ elf_memory;
+ elf_ndxscn;
+ elf_newdata;
+ elf_newscn;
+ elf_next;
+ elf_nextscn;
+ elf_rand;
+ elf_rawdata;
+ elf_rawfile;
+ elf_setshstrndx;
+ elf_strptr;
+ elf_update;
+ elf_version;
+ gelf_checksum;
+ gelf_fsize;
+ gelf_getcap;
+ gelf_getclass;
+ gelf_getdyn;
+ gelf_getehdr;
+ gelf_getmove;
+ gelf_getphdr;
+ gelf_getrel;
+ gelf_getrela;
+ gelf_getshdr;
+ gelf_getsym;
+ gelf_getsyminfo;
+ gelf_getsymshndx;
+ gelf_newehdr;
+ gelf_newphdr;
+ gelf_update_cap;
+ gelf_update_dyn;
+ gelf_update_ehdr;
+ gelf_update_move;
+ gelf_update_phdr;
+ gelf_update_rel;
+ gelf_update_rela;
+ gelf_update_shdr;
+ gelf_update_sym;
+ gelf_update_syminfo;
+ gelf_update_symshndx;
+ gelf_xlatetof;
+ gelf_xlatetom;
+local:
+ *;
+};
diff --git a/linkers/elftoolchain/libelf/_libelf.h b/linkers/elftoolchain/libelf/_libelf.h
new file mode 100644
index 0000000..ef15642
--- /dev/null
+++ b/linkers/elftoolchain/libelf/_libelf.h
@@ -0,0 +1,211 @@
+/*-
+ * Copyright (c) 2006,2008-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: _libelf.h 1921 2011-09-23 08:04:02Z jkoshy $
+ */
+
+#ifndef __LIBELF_H_
+#define __LIBELF_H_
+
+#include <sys/queue.h>
+
+#include "_libelf_config.h"
+
+#include "_elftc.h"
+
+/*
+ * Library-private data structures.
+ */
+
+#define LIBELF_MSG_SIZE 256
+
+struct _libelf_globals {
+ int libelf_arch;
+ unsigned int libelf_byteorder;
+ int libelf_class;
+ int libelf_error;
+ int libelf_fillchar;
+ unsigned int libelf_version;
+ char libelf_msg[LIBELF_MSG_SIZE];
+};
+
+extern struct _libelf_globals _libelf;
+
+#define LIBELF_PRIVATE(N) (_libelf.libelf_##N)
+
+#define LIBELF_ELF_ERROR_MASK 0xFF
+#define LIBELF_OS_ERROR_SHIFT 8
+
+#define LIBELF_SET_ERROR(E, O) do { \
+ LIBELF_PRIVATE(error) = ((ELF_E_##E & LIBELF_ELF_ERROR_MASK)| \
+ ((O) << LIBELF_OS_ERROR_SHIFT)); \
+ } while (0)
+
+#define LIBELF_ADJUST_AR_SIZE(S) (((S) + 1U) & ~1U)
+
+/*
+ * Flags for library internal use. These use the upper 16 bits of the
+ * `e_flags' field.
+ */
+#define LIBELF_F_API_MASK 0x00FFFF /* Flags defined by the API. */
+#define LIBELF_F_AR_HEADER 0x010000 /* translated header available */
+#define LIBELF_F_AR_VARIANT_SVR4 0x020000 /* BSD style ar(1) archive */
+#define LIBELF_F_DATA_MALLOCED 0x040000 /* whether data was malloc'ed */
+#define LIBELF_F_RAWFILE_MALLOC 0x080000 /* whether e_rawfile was malloc'ed */
+#define LIBELF_F_RAWFILE_MMAP 0x100000 /* whether e_rawfile was mmap'ed */
+#define LIBELF_F_SHDRS_LOADED 0x200000 /* whether all shdrs were read in */
+#define LIBELF_F_SPECIAL_FILE 0x400000 /* non-regular file */
+
+struct _Elf {
+ int e_activations; /* activation count */
+ unsigned int e_byteorder; /* ELFDATA* */
+ int e_class; /* ELFCLASS* */
+ Elf_Cmd e_cmd; /* ELF_C_* used at creation time */
+ int e_fd; /* associated file descriptor */
+ unsigned int e_flags; /* ELF_F_* & LIBELF_F_* flags */
+ Elf_Kind e_kind; /* ELF_K_* */
+ Elf *e_parent; /* non-NULL for archive members */
+ char *e_rawfile; /* uninterpreted bytes */
+ size_t e_rawsize; /* size of uninterpreted bytes */
+ unsigned int e_version; /* file version */
+
+ /*
+ * Header information for archive members. See the
+ * LIBELF_F_AR_HEADER flag.
+ */
+ union {
+ Elf_Arhdr *e_arhdr; /* translated header */
+ char *e_rawhdr; /* untranslated header */
+ } e_hdr;
+
+ union {
+ struct { /* ar(1) archives */
+ off_t e_next; /* set by elf_rand()/elf_next() */
+ int e_nchildren;
+ char *e_rawstrtab; /* file name strings */
+ size_t e_rawstrtabsz;
+ char *e_rawsymtab; /* symbol table */
+ size_t e_rawsymtabsz;
+ Elf_Arsym *e_symtab;
+ size_t e_symtabsz;
+ } e_ar;
+ struct { /* regular ELF files */
+ union {
+ Elf32_Ehdr *e_ehdr32;
+ Elf64_Ehdr *e_ehdr64;
+ } e_ehdr;
+ union {
+ Elf32_Phdr *e_phdr32;
+ Elf64_Phdr *e_phdr64;
+ } e_phdr;
+ STAILQ_HEAD(, _Elf_Scn) e_scn; /* section list */
+ size_t e_nphdr; /* number of Phdr entries */
+ size_t e_nscn; /* number of sections */
+ size_t e_strndx; /* string table section index */
+ } e_elf;
+ } e_u;
+};
+
+struct _Elf_Scn {
+ union {
+ Elf32_Shdr s_shdr32;
+ Elf64_Shdr s_shdr64;
+ } s_shdr;
+ STAILQ_HEAD(, _Elf_Data) s_data; /* list of Elf_Data descriptors */
+ STAILQ_HEAD(, _Elf_Data) s_rawdata; /* raw data for this section */
+ STAILQ_ENTRY(_Elf_Scn) s_next;
+ struct _Elf *s_elf; /* parent ELF descriptor */
+ unsigned int s_flags; /* flags for the section as a whole */
+ size_t s_ndx; /* index# for this section */
+ uint64_t s_offset; /* managed by elf_update() */
+ uint64_t s_rawoff; /* original offset in the file */
+ uint64_t s_size; /* managed by elf_update() */
+};
+
+
+enum {
+ ELF_TOFILE,
+ ELF_TOMEMORY
+};
+
+#define LIBELF_COPY_U32(DST,SRC,NAME) do { \
+ if ((SRC)->NAME > UINT_MAX) { \
+ LIBELF_SET_ERROR(RANGE, 0); \
+ return (0); \
+ } \
+ (DST)->NAME = (SRC)->NAME; \
+ } while (0)
+
+#define LIBELF_COPY_S32(DST,SRC,NAME) do { \
+ if ((SRC)->NAME > INT_MAX || \
+ (SRC)->NAME < INT_MIN) { \
+ LIBELF_SET_ERROR(RANGE, 0); \
+ return (0); \
+ } \
+ (DST)->NAME = (SRC)->NAME; \
+ } while (0)
+
+
+/*
+ * Function Prototypes.
+ */
+
+__BEGIN_DECLS
+Elf_Data *_libelf_allocate_data(Elf_Scn *_s);
+Elf *_libelf_allocate_elf(void);
+Elf_Scn *_libelf_allocate_scn(Elf *_e, size_t _ndx);
+Elf_Arhdr *_libelf_ar_gethdr(Elf *_e);
+Elf *_libelf_ar_open(Elf *_e);
+Elf *_libelf_ar_open_member(int _fd, Elf_Cmd _c, Elf *_ar);
+int _libelf_ar_get_member(char *_s, size_t _sz, int _base, size_t *_ret);
+Elf_Arsym *_libelf_ar_process_bsd_symtab(Elf *_ar, size_t *_dst);
+Elf_Arsym *_libelf_ar_process_svr4_symtab(Elf *_ar, size_t *_dst);
+unsigned long _libelf_checksum(Elf *_e, int _elfclass);
+void *_libelf_ehdr(Elf *_e, int _elfclass, int _allocate);
+int _libelf_falign(Elf_Type _t, int _elfclass);
+size_t _libelf_fsize(Elf_Type _t, int _elfclass, unsigned int _version,
+ size_t count);
+int (*_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass))
+ (char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap);
+void *_libelf_getphdr(Elf *_e, int _elfclass);
+void *_libelf_getshdr(Elf_Scn *_scn, int _elfclass);
+void _libelf_init_elf(Elf *_e, Elf_Kind _kind);
+int _libelf_load_section_headers(Elf *e, void *ehdr);
+int _libelf_malign(Elf_Type _t, int _elfclass);
+size_t _libelf_msize(Elf_Type _t, int _elfclass, unsigned int _version);
+void *_libelf_newphdr(Elf *_e, int _elfclass, size_t _count);
+Elf_Data *_libelf_release_data(Elf_Data *_d);
+Elf *_libelf_release_elf(Elf *_e);
+Elf_Scn *_libelf_release_scn(Elf_Scn *_s);
+int _libelf_setphnum(Elf *_e, void *_eh, int _elfclass, size_t _phnum);
+int _libelf_setshnum(Elf *_e, void *_eh, int _elfclass, size_t _shnum);
+int _libelf_setshstrndx(Elf *_e, void *_eh, int _elfclass,
+ size_t _shstrndx);
+Elf_Data *_libelf_xlate(Elf_Data *_d, const Elf_Data *_s,
+ unsigned int _encoding, int _elfclass, int _direction);
+int _libelf_xlate_shtype(uint32_t _sht);
+__END_DECLS
+
+#endif /* __LIBELF_H_ */
diff --git a/linkers/elftoolchain/libelf/_libelf_ar.h b/linkers/elftoolchain/libelf/_libelf_ar.h
new file mode 100644
index 0000000..d6b15a7
--- /dev/null
+++ b/linkers/elftoolchain/libelf/_libelf_ar.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: _libelf_ar.h 2032 2011-10-23 09:07:00Z jkoshy $
+ */
+
+#ifndef __LIBELF_AR_H_
+#define __LIBELF_AR_H_
+
+/*
+ * Prototypes and declarations needed by libelf's ar(1) archive
+ * handling code.
+ */
+
+#include <ar.h>
+
+#define LIBELF_AR_BSD_EXTENDED_NAME_PREFIX "#1/"
+#define LIBELF_AR_BSD_SYMTAB_NAME "__.SYMDEF"
+#define LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE \
+ (sizeof(LIBELF_AR_BSD_EXTENDED_NAME_PREFIX) - 1)
+
+#define IS_EXTENDED_BSD_NAME(NAME) \
+ (strncmp((NAME), LIBELF_AR_BSD_EXTENDED_NAME_PREFIX, \
+ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE) == 0)
+
+
+char *_libelf_ar_get_string(const char *_buf, size_t _sz, int _rawname,
+ int _svr4names);
+char *_libelf_ar_get_raw_name(const struct ar_hdr *_arh);
+char *_libelf_ar_get_translated_name(const struct ar_hdr *_arh, Elf *_ar);
+int _libelf_ar_get_number(const char *_buf, size_t _sz, int _base,
+ size_t *_ret);
+
+#endif /* __LIBELF_AR_H_ */
diff --git a/linkers/elftoolchain/libelf/_libelf_config.h b/linkers/elftoolchain/libelf/_libelf_config.h
new file mode 100644
index 0000000..a318e70
--- /dev/null
+++ b/linkers/elftoolchain/libelf/_libelf_config.h
@@ -0,0 +1,197 @@
+/*-
+ * Copyright (c) 2008-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: _libelf_config.h 2032 2011-10-23 09:07:00Z jkoshy $
+ */
+
+#ifdef __FreeBSD__
+
+#define LIBELF_VCSID(ID) __FBSDID(ID)
+
+/*
+ * Define LIBELF_{ARCH,BYTEORDER,CLASS} based on the machine architecture.
+ * See also: <machine/elf.h>.
+ */
+
+#if defined(__amd64__)
+
+#define LIBELF_ARCH EM_X86_64
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS64
+
+#elif defined(__arm__)
+
+#define LIBELF_ARCH EM_ARM
+#if defined(__ARMEB__) /* Big-endian ARM. */
+#define LIBELF_BYTEORDER ELFDATA2MSB
+#else
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#endif
+#define LIBELF_CLASS ELFCLASS32
+
+#elif defined(__i386__)
+
+#define LIBELF_ARCH EM_386
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS32
+
+#elif defined(__ia64__)
+
+#define LIBELF_ARCH EM_IA_64
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS64
+
+#elif defined(__mips__)
+
+#define LIBELF_ARCH EM_MIPS
+#if defined(__MIPSEB__)
+#define LIBELF_BYTEORDER ELFDATA2MSB
+#else
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#endif
+#define LIBELF_CLASS ELFCLASS32
+
+#elif defined(__powerpc__)
+
+#define LIBELF_ARCH EM_PPC
+#define LIBELF_BYTEORDER ELFDATA2MSB
+#define LIBELF_CLASS ELFCLASS32
+
+#elif defined(__sparc__)
+
+#define LIBELF_ARCH EM_SPARCV9
+#define LIBELF_BYTEORDER ELFDATA2MSB
+#define LIBELF_CLASS ELFCLASS64
+
+#else
+#error Unknown FreeBSD architecture.
+#endif
+#endif /* __FreeBSD__ */
+
+
+#ifdef __NetBSD__
+
+#include <machine/elf_machdep.h>
+
+#define LIBELF_VCSID(ID) __RCSID(ID)
+
+#if !defined(ARCH_ELFSIZE)
+#error ARCH_ELFSIZE is not defined.
+#endif
+
+#if ARCH_ELFSIZE == 32
+#define LIBELF_ARCH ELF32_MACHDEP_ID
+#define LIBELF_BYTEORDER ELF32_MACHDEP_ENDIANNESS
+#define LIBELF_CLASS ELFCLASS32
+#define Elf_Note Elf32_Nhdr
+#else
+#define LIBELF_ARCH ELF64_MACHDEP_ID
+#define LIBELF_BYTEORDER ELF64_MACHDEP_ENDIANNESS
+#define LIBELF_CLASS ELFCLASS64
+#define Elf_Note Elf64_Nhdr
+#endif
+
+#endif /* __NetBSD__ */
+
+#ifdef __APPLE__
+
+#define LIBELF_VCSID(ID)
+
+#if defined(__amd64__)
+
+#define LIBELF_ARCH EM_X86_64
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS64
+
+#elif defined(__i386__)
+
+#define LIBELF_ARCH EM_386
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS32
+
+#else
+#error Unknown Apple architecture.
+#endif
+
+#define roundup2 roundup
+
+#endif /* __APPLE__ */
+
+/*
+ * GNU & Linux compatibility.
+ *
+ * `__linux__' is defined in an environment runs the Linux kernel and glibc.
+ * `__GNU__' is defined in an environment runs a GNU kernel (Hurd) and glibc.
+ * `__GLIBC__' is defined for an environment that runs glibc over a non-GNU
+ * kernel such as GNU/kFreeBSD.
+ */
+
+#if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)
+
+#if defined(__linux__)
+
+#include "native-elf-format.h"
+
+#define LIBELF_CLASS ELFTC_CLASS
+#define LIBELF_ARCH ELFTC_ARCH
+#define LIBELF_BYTEORDER ELFTC_BYTEORDER
+
+#endif /* defined(__linux__) */
+
+#define LIBELF_VCSID(ID)
+
+#if LIBELF_CLASS == ELFCLASS32
+#define Elf_Note Elf32_Nhdr
+#elif LIBELF_CLASS == ELFCLASS64
+#define Elf_Note Elf64_Nhdr
+#else
+#error LIBELF_CLASS needs to be one of ELFCLASS32 or ELFCLASS64
+#endif
+
+#define roundup2 roundup
+
+#endif /* defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) */
+
+#ifdef __WIN32__
+
+#define LIBELF_VCSID(ID)
+
+#if defined(__amd64__)
+
+#define LIBELF_ARCH EM_X86_64
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS64
+
+#elif defined(__i386__)
+
+#define LIBELF_ARCH EM_386
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS32
+
+#else
+#error Unknown Apple architecture.
+#endif
+
+#endif /* __APPLE__ */
diff --git a/linkers/elftoolchain/libelf/elf.3 b/linkers/elftoolchain/libelf/elf.3
new file mode 100644
index 0000000..5d86f60
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf.3
@@ -0,0 +1,589 @@
+.\" Copyright (c) 2006-2008,2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf.3 1730 2011-08-14 10:03:34Z jkoshy $
+.\"
+.Dd August 14, 2011
+.Os
+.Dt ELF 3
+.Sh NAME
+.Nm elf
+.Nd API for manipulating ELF objects
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Sh DESCRIPTION
+The
+.Lb libelf
+provides functions that allow an application to read and manipulate
+ELF object files, and to read
+.Xr ar 1
+archives.
+The library allows the manipulation of ELF objects in a byte ordering
+and word-size independent way, allowing an application to read and
+create ELF objects for 32 and 64 bit architectures and for little-
+and big-endian machines.
+The library is capable of processing ELF objects that use extended
+section numbering.
+.Pp
+This manual page serves to provide an overview of the functionality in
+the ELF library.
+Further information may found in the manual pages for individual
+.Xr ELF 3
+functions that comprise the library.
+.Ss ELF Concepts
+As described in
+.Xr elf 5 ,
+ELF files contain several data structures that are laid out in a
+specific way.
+ELF files begin with an
+.Dq Executable Header ,
+and may contain an optional
+.Dq Program Header Table ,
+and optional data in the form of ELF
+.Dq sections .
+A
+.Dq Section Header Table
+describes the content of the data in these sections.
+.Pp
+ELF objects have an associated
+.Dq "ELF class"
+which denotes the natural machine word size for the architecture
+the object is associated with.
+Objects for 32 bit architectures have an ELF class of
+.Dv ELFCLASS32 .
+Objects for 64 bit architectures have an ELF class of
+.Dv ELFCLASS64 .
+.Pp
+ELF objects also have an associated
+.Dq endianness
+which denotes the endianness of the machine architecture associated
+with the object.
+This may be
+.Dv ELFDATA2LSB
+for little-endian architectures and
+.Dv ELFDATA2MSB
+for big-endian architectures.
+.Pp
+ELF objects are also associated with an API version number.
+This version number determines the layout of the individual components
+of an ELF file and the semantics associated with these.
+.Ss Data Representation And Translation
+The
+.Xr ELF 3
+library distinguishes between
+.Dq native
+representations of ELF data structures and their
+.Dq file
+representations.
+.Pp
+An application would work with ELF data in its
+.Dq native
+representation, i.e., using the native byteorder and alignment mandated
+by the processor the application is running on.
+The
+.Dq file
+representation of the same data could use a different byte ordering
+and follow different constraints on object alignment than these native
+constraints.
+.Pp
+Accordingly, the
+.Xr ELF 3
+library offers translation facilities
+.Xr ( elf32_xlatetof 3 ,
+.Xr elf32_xlatetom 3 ,
+.Xr elf64_xlatetof 3
+and
+.Xr elf64_xlatetom 3 )
+to and from these
+representations and also provides higher-level APIs that retrieve and store
+data from the ELF object in a transparent manner.
+.Ss Library Working Version
+Conceptually, there are three version numbers associated with an
+application using the ELF library to manipulate ELF objects:
+.Bl -bullet -compact -offset indent
+.It
+The ELF version that the application was compiled against.
+This version determines the ABI expected by the application.
+.It
+The ELF version of the ELF object being manipulated by the
+application through the ELF library.
+.It
+The ELF version (or set of versions) supported by the ELF library itself.
+.El
+.Pp
+In order to facilitate working with ELF objects of differing versions,
+the ELF library requires the application to call the
+.Fn elf_version
+function before invoking many of its operations, in order to inform
+the library of the application's desired working version.
+.Pp
+In the current implementation, all three versions have to be
+.Dv EV_CURRENT .
+.Ss Namespace use
+The ELF library uses the following prefixes:
+.Bl -tag -width "ELF_F_*"
+.It Dv elf_
+Used for class-independent functions.
+.It Dv elf32_
+Used for functions working with 32 bit ELF objects.
+.It Dv elf64_
+Used for functions working with 64 bit ELF objects.
+.It Dv Elf_
+Used for class-independent data types.
+.It Dv ELF_C_
+Used for command values used in a few functions.
+These symbols are defined as members of the
+.Vt Dv Elf_Cmd
+enumeration.
+.It Dv ELF_E_
+Used for error numbers.
+.It Dv ELF_F_
+Used for flags.
+.It Dv ELF_K_
+These constants define the kind of file associated with an ELF
+descriptor.
+See
+.Xr elf_kind 3 .
+The symbols are defined by the
+.Vt Elf_Kind
+enumeration.
+.It Dv ELF_T_
+These values are defined by the
+.Vt Elf_Type
+enumeration, and denote the types of ELF data structures
+that can be present in an ELF object.
+.El
+.Pp
+In addition, the library uses symbols with prefixes
+.Dv _ELF
+and
+.Dv _libelf
+for its internal use.
+.Ss Descriptors
+Applications communicate with the library using descriptors.
+These are:
+.Bl -tag -width ".Vt Elf_Data"
+.It Vt Elf
+An
+.Vt Elf
+descriptor represents an ELF object or an
+.Xr ar 1
+archive.
+It is allocated using one of the
+.Fn elf_begin
+or
+.Fn elf_memory
+functions.
+An
+.Vt Elf
+descriptor can be used to read and write data to an ELF file.
+An
+.Vt Elf
+descriptor can be associated with zero or more
+.Vt Elf_Scn
+section descriptors.
+.Pp
+Given an ELF descriptor, the application may retrieve the ELF
+object's class-dependent
+.Dq "Executable Header"
+structures using the
+.Fn elf32_getehdr
+or
+.Fn elf64_getehdr
+functions.
+A new Ehdr structure may be allocated using the
+.Fn elf64_newehdr
+or
+.Fn elf64_newehdr
+functions.
+.Pp
+The
+.Dq "Program Header Table"
+associated with an ELF descriptor may be allocated using the
+.Fn elf32_getphdr
+or
+.Fn elf64_getphdr
+functions.
+A new program header table may be allocated or an existing table
+resized using the
+.Fn elf32_newphdr
+or
+.Fn elf64_newphdr
+functions.
+.Pp
+The
+.Vt Elf
+structure is opaque and has no members visible to the
+application.
+.\" TODO describe the Elf_Arhdr and Elf_Arsym structures.
+.It Vt Elf_Data
+An
+.Vt Elf_Data
+data structure describes an individual chunk of a ELF file as
+represented in memory.
+It has the following application-visible members:
+.Bl -tag -width ".Vt unsigned int d_version" -compact
+.It Vt "uint64_t d_align"
+The in-file alignment of the data buffer within its containing ELF section.
+This value must be non-zero and a power of two.
+.It Vt "void *d_buf"
+A pointer to data in memory.
+.It Vt "uint64_t d_off"
+The offset with the containing section where this descriptors data
+would be placed.
+This field will be computed by the library unless the application
+requests full control of the ELF object's layout.
+.It Vt "uint64_t d_size"
+The number of bytes of data in this descriptor.
+.It Vt "Elf_Type d_type"
+The ELF type (see below) of the data in this descriptor.
+.It Vt "unsigned int d_version"
+The operating version for the data in this buffer.
+.El
+.Pp
+.Vt Elf_Data
+descriptors are usually associated with
+.Vt Elf_Scn
+descriptors.
+Existing data descriptors associated with an ELF section may be
+structures are retrieved using the
+.Fn elf_getdata
+and
+.Fn elf_rawdata
+functions.
+The
+.Fn elf_newdata
+function may be used to attach new data descriptors to an ELF section.
+.It Vt Elf_Scn
+.Vt Elf_Scn
+descriptors represent a section in an ELF object.
+.Pp
+They are retrieved using the
+.Fn elf_getscn
+function.
+An application may iterate through the existing sections of an ELF
+object using the
+.Fn elf_nextscn
+function.
+New sections may be allocated using the
+.Fn elf_newscn
+function.
+.Pp
+The
+.Vt Elf_Scn
+descriptor is opaque and contains no application modifiable fields.
+.El
+.Ss Supported Elf Types
+The following ELF datatypes are supported by the library.
+.Pp
+.Bl -tag -width ".Dv ELF_T_SYMINFO" -compact
+.It Dv ELF_T_ADDR
+Machine addresses.
+.It Dv ELF_T_BYTE
+Byte data.
+The library will not attempt to translate byte data.
+.It Dv ELF_T_CAP
+Software and hardware capability records.
+.It Dv ELF_T_DYN
+Records used in a section of type
+.Dv SHT_DYNAMIC .
+.It Dv ELF_T_EHDR
+ELF executable header.
+.It Dv ELF_T_GNUHASH
+GNU-style hash tables.
+.It Dv ELF_T_HALF
+16-bit unsigned words.
+.It Dv ELF_T_LWORD
+64 bit unsigned words.
+.It Dv ELF_T_MOVE
+ELF Move records.
+.\".It Dv ELF_T_MOVEP
+.\" As yet unsupported.
+.It Dv ELF_T_NOTE
+ELF Note structures.
+.It Dv ELF_T_OFF
+File offsets.
+.It Dv ELF_T_PHDR
+ELF program header table entries.
+.It Dv ELF_T_REL
+ELF relocation entries.
+.It Dv ELF_T_RELA
+ELF relocation entries with addends.
+.It Dv ELF_T_SHDR
+ELF section header entries.
+.It Dv ELF_T_SWORD
+Signed 32-bit words.
+.It Dv ELF_T_SXWORD
+Signed 64-bit words.
+.It Dv ELF_T_SYMINFO
+ELF symbol information.
+.It Dv ELF_T_SYM
+ELF symbol table entries.
+.It Dv ELF_T_VDEF
+Symbol version definition records.
+.It Dv ELF_T_VNEED
+Symbol version requirement records.
+.It Dv ELF_T_WORD
+Unsigned 32-bit words.
+.It Dv ELF_T_XWORD
+Unsigned 64-bit words.
+.El
+.Pp
+The symbol
+.Dv ELF_T_NUM
+denotes the number of Elf types known to the library.
+.Pp
+The following table shows the mapping between ELF section types
+defined in
+.Xr elf 5
+and the types supported by the library.
+.Bl -column ".Dv SHT_PREINIT_ARRAY" ".Dv ELF_T_SYMINFO"
+.It Em Section Type Ta Em "Library Type" Ta Em Description
+.It Dv SHT_DYNAMIC Ta Dv ELF_T_DYN Ta Xo
+.Sq .dynamic
+section entries.
+.Xc
+.It Dv SHT_DYNSYM Ta Dv ELF_T_SYM Ta Symbols for dynamic linking.
+.It Dv SHT_FINI_ARRAY Ta Dv ELF_T_ADDR Ta Termination function pointers.
+.It Dv SHT_GROUP Ta Dv ELF_T_WORD Ta Section group marker.
+.It Dv SHT_HASH Ta Dv ELF_T_HASH Ta Symbol hashes.
+.It Dv SHT_INIT_ARRAY Ta Dv ELF_T_ADDR Ta Initialization function pointers.
+.It Dv SHT_NOBITS Ta Dv ELF_T_BYTE Ta Xo
+Empty sections.
+See
+.Xr elf 5 .
+.Xc
+.It Dv SHT_NOTE Ta Dv ELF_T_NOTE Ta ELF note records.
+.It Dv SHT_PREINIT_ARRAY Ta Dv ELF_T_ADDR Ta Pre-initialization function pointers.
+.It Dv SHT_PROGBITS Ta Dv ELF_T_BYTE Ta Machine code.
+.It Dv SHT_REL Ta Dv ELF_T_REL Ta ELF relocation records.
+.It Dv SHT_RELA Ta Dv ELF_T_RELA Ta Relocation records with addends.
+.It Dv SHT_STRTAB Ta Dv ELF_T_BYTE Ta String tables.
+.It Dv SHT_SYMTAB Ta Dv ELF_T_SYM Ta Symbol tables.
+.It Dv SHT_SYMTAB_SHNDX Ta Dv ELF_T_WORD Ta Used with extended section numbering.
+.It Dv SHT_GNU_verdef Ta Dv ELF_T_VDEF Ta Symbol version definitions.
+.It Dv SHT_GNU_verneed Ta Dv ELF_T_VNEED Ta Symbol versioning requirements.
+.It Dv SHT_GNU_versym Ta Dv ELF_T_HALF Ta Version symbols.
+.It Dv SHT_SUNW_move Ta Dv ELF_T_MOVE Ta ELF move records.
+.It Dv SHT_SUNW_syminfo Ta Dv ELF_T_SYMINFO Ta Additional symbol flags.
+.El
+.TE
+.Ss Functional Grouping
+This section contains a brief overview of the available functionality
+in the ELF library.
+Each function listed here is described further in its own manual page.
+.Bl -tag -width indent
+.It "Archive Access"
+.Bl -tag -compact
+.It Fn elf_getarsym
+Retrieve the archive symbol table.
+.It Fn elf_getarhdr
+Retrieve the archive header for an object.
+.It Fn elf_getbase
+Retrieve the offset of a member inside an archive.
+.It Fn elf_next
+Iterate through an
+.Xr ar 1
+archive.
+.It Fn elf_rand
+Random access inside an
+.Xr ar 1
+archive.
+.El
+.It "Data Structures"
+.Bl -tag -compact
+.It Fn elf_getdata
+Retrieve translated data for an ELF section.
+.It Fn elf_getscn
+Retrieve the section descriptor for a named section.
+.It Fn elf_ndxscn
+Retrieve the index for a section.
+.It Fn elf_newdata
+Add a new
+.Vt Elf_Data
+descriptor to an ELF section.
+.It Fn elf_newscn
+Add a new section descriptor to an ELF descriptor.
+.It Fn elf_nextscn
+Iterate through the sections in an ELF object.
+.It Fn elf_rawdata
+Retrieve untranslated data for an ELF sectino.
+.It Fn elf_rawfile
+Return a pointer to the untranslated file contents for an ELF object.
+.It Fn elf32_getehdr , Fn elf64_getehdr
+Retrieve the Executable Header in an ELF object.
+.It Fn elf32_getphdr , Fn elf64_getphdr
+Retrieve the Program Header Table in an ELF object.
+.It Fn elf32_getshdr , Fn elf64_getshdr
+Retrieve the ELF section header associated with an
+.Vt Elf_Scn
+descriptor.
+.It Fn elf32_newehdr , Fn elf64_newehdr
+Allocate an Executable Header in an ELF object.
+.It Fn elf32_newphdr , Fn elf64_newphdr
+Allocate or resize the Program Header Table in an ELF object.
+.El
+.It "Data Translation"
+.Bl -tag -compact
+.It Fn elf32_xlatetof , Fn elf64_xlatetof
+Translate an ELF data structure from its native representation to its
+file representation.
+.It Fn elf32_xlatetom , Fn elf64_xlatetom
+Translate an ELF data structure from its file representation to a
+native representation.
+.El
+.It "Error Reporting"
+.Bl -tag -compact
+.It Fn elf_errno
+Retrieve the current error.
+.It Fn elf_errmsg
+Retrieve a human readable description of the current error.
+.El
+.It "Initialization"
+.Bl -tag -compact
+.It Fn elf_begin
+Opens an
+.Xr ar 1
+archive or ELF object given a file descriptor.
+.It Fn elf_end
+Close an ELF descriptor and release all its resources.
+.It Fn elf_memory
+Opens an
+.Xr ar 1
+archive or ELF object present in a memory arena.
+.It Fn elf_version
+Sets the operating version.
+.El
+.It "IO Control"
+.Bl -tag -width ".Fn elf_setshstrndx" -compact
+.It Fn elf_cntl
+Manage the association between and ELF descriptor and its underlying file.
+.It Fn elf_flagdata
+Mark an
+.Vt Elf_Data
+descriptor as dirty.
+.It Fn elf_flagehdr
+Mark the ELF Executable Header in an ELF descriptor as dirty.
+.It Fn elf_flagphdr
+Mark the ELF Program Header Table in an ELF descriptor as dirty.
+.It Fn elf_flagscn
+Mark an
+.Vt Elf_Scn
+descriptor as dirty.
+.It Fn elf_flagshdr
+Mark an ELF Section Header as dirty.
+.It Fn elf_setshstrndx
+Set the index of the section name string table for the ELF object.
+.It Fn elf_update
+Recompute ELF object layout and optionally write the modified object
+back to the underlying file.
+.El
+.It "Queries"
+.Bl -tag -width ".Fn elf_getshstrndx" -compact
+.It Fn elf32_checksum , Fn elf64_checkum
+Compute checksum of an ELF object.
+.It Fn elf_getident
+Retrieve the identification bytes for an ELF object.
+.It Fn elf_getshnum
+Retrieve the number of sections in an ELF object.
+.It Fn elf_getshstrndx
+Retrieve the section index of the section name string table in
+an ELF object.
+.It Fn elf_hash
+Compute the ELF hash value of a string.
+.It Fn elf_kind
+Query the kind of object associated with an ELF descriptor.
+.It Fn elf32_fsize , Fn elf64_fsize
+Return the size of the file representation of an ELF type.
+.El
+.El
+.Ss Controlling ELF Object Layout
+In the usual mode of operation, library will compute section
+offsets and alignments based on the contents of an ELF descriptor's
+sections without need for further intervention by the
+application.
+.Pp
+However, if the application wishes to take complete charge of the
+layout of the ELF file, it may set the
+.Dv ELF_F_LAYOUT
+flag on an ELF descriptor using
+.Xr elf_flagelf 3 ,
+following which the library will use the data offsets and alignments
+specified by the application when laying out the file.
+Application control of file layout is described further in the
+.Xr elf_update 3
+manual page.
+.Pp
+Gaps in between sections will be filled with the fill character
+set by function
+.Fn elf_fill .
+.Ss Error Handling
+In case an error is encountered, these library functions set an
+internal error number and signal the presence of the error by
+returning an special return value.
+The application can check the
+current error number by calling
+.Xr elf_errno 3 .
+A human readable description of the recorded error is available by
+calling
+.Xr elf_errmsg 3 .
+.Ss Memory Management Rules
+The library keeps track of all
+.Vt Elf_Scn
+and
+.Vt Elf_Data
+descriptors associated with an ELF descriptor and recovers them
+when the descriptor is closed using
+.Xr elf_end 3 .
+Thus the application must not call
+.Xr free 3
+on data structures allocated by the ELF library.
+.Pp
+Conversely the library will not
+free data that it has not allocated.
+As an example, an application may call
+.Xr elf_newdata 3
+to allocate a new
+.Vt Elf_Data
+descriptor and can set the
+.Va d_off
+member of the descriptor to point to a region of memory allocated
+using
+.Xr malloc 3 .
+It is the applications responsibility to free this arena, though the
+library will reclaim the space used by the
+.Vt Elf_Data
+descriptor itself.
+.Sh SEE ALSO
+.Xr gelf 3 ,
+.Xr elf 5
+.Sh HISTORY
+The original ELF(3) API was developed for Unix System V.
+The current implementation of the ELF(3) API appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+The ELF library was written by
+.An "Joseph Koshy"
+.Aq jkoshy@FreeBSD.org .
diff --git a/linkers/elftoolchain/libelf/elf.c b/linkers/elftoolchain/libelf/elf.c
new file mode 100644
index 0000000..e3ef7f3
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf.c
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2006,2008,2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf.c 1345 2011-01-01 11:17:52Z jkoshy $");
+
+struct _libelf_globals _libelf = {
+ .libelf_arch = LIBELF_ARCH,
+ .libelf_byteorder = LIBELF_BYTEORDER,
+ .libelf_class = LIBELF_CLASS,
+ .libelf_error = 0,
+ .libelf_fillchar = 0,
+ .libelf_version = EV_NONE
+};
diff --git a/linkers/elftoolchain/libelf/elf_begin.3 b/linkers/elftoolchain/libelf/elf_begin.3
new file mode 100644
index 0000000..5a013a4
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_begin.3
@@ -0,0 +1,311 @@
+.\" Copyright (c) 2006,2008-2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_begin.3 1925 2011-09-23 09:34:05Z jkoshy $
+.\"
+.Dd September 23, 2011
+.Os
+.Dt ELF_BEGIN 3
+.Sh NAME
+.Nm elf_begin
+.Nd open an ELF file or ar(1) archive
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf *"
+.Fn elf_begin "int fd" "Elf_Cmd cmd" "Elf *elf"
+.Sh DESCRIPTION
+Function
+.Fn elf_begin
+is used to open ELF files and
+.Xr ar 1
+archives for further processing by other APIs in the
+.Xr elf 3
+library.
+It is also used to access individual ELF members of an
+.Xr ar 1
+archive in combination with the
+.Xr elf_next 3
+and
+.Xr elf_rand 3
+APIs.
+.Pp
+Argument
+.Ar fd
+is an open file descriptor returned from an
+.Xr open 2
+system call.
+Function
+.Fn elf_begin
+uses argument
+.Ar fd
+for reading or writing depending on the value of argument
+.Ar cmd .
+Argument
+.Ar elf
+is primarily used for iterating through archives.
+.Pp
+The argument
+.Ar cmd
+can have the following values:
+.Bl -tag -width "ELF_C_WRITE"
+.It ELF_C_NULL
+Causes
+.Fn elf_begin
+to return NULL.
+Arguments
+.Ar fd
+and
+.Ar elf
+are ignored, and no additional error is signalled.
+.It ELF_C_READ
+This value is to be when the application wishes to examine (but not
+modify) the contents of the file specified by the arguments
+.Ar fd
+and
+.Ar elf .
+It can be used for both
+.Xr ar 1
+archives and for ELF objects.
+.Pp
+If argument
+.Ar elf
+is NULL, the library will allocate a new ELF descriptor for the file
+being processed.
+The argument
+.Ar fd
+should have been opened for reading.
+.Pp
+If argument
+.Ar elf
+is not NULL, and references a regular ELF file previously opened with
+.Fn elf_begin ,
+then the activation count for the descriptor referenced by argument
+.Ar elf
+is incremented.
+The value in argument
+.Ar fd
+should match that used to open the descriptor argument
+.Ar elf .
+.Pp
+If argument
+.Ar elf
+is not NULL, and references a descriptor for an
+.Xr ar 1
+archive opened earlier with
+.Fn elf_begin ,
+a descriptor for an element in the archive is returned as
+described in the section
+.Sx "Processing ar(1) archives"
+below.
+The value for argument
+.Ar fd
+should match that used to open the archive earlier.
+.Pp
+If argument
+.Ar elf
+is not NULL, and references an
+.Xr ar 1
+archive opened earlier with
+.Fn elf_memory ,
+then the value of the argument
+.Ar fd
+is ignored.
+.It Dv ELF_C_RDWR
+This command is used to prepare an ELF file for reading and writing.
+This command is not supported for
+.Xr ar 1
+archives.
+.Pp
+Argument
+.Ar fd
+should have been opened for reading and writing.
+If argument
+.Ar elf
+is NULL, the library will allocate a new ELF descriptor for
+the file being processed.
+If the argument
+.Ar elf
+is non-null, it should point to a descriptor previously
+allocated with
+.Fn elf_begin
+with the same values for arguments
+.Ar fd
+and
+.Ar cmd ;
+in this case the library will increment the activation count for descriptor
+.Ar elf
+and return the same descriptor.
+.Pp
+Changes to the in-memory image of the ELF file may be written back to
+disk using the
+.Xr elf_update 3
+function.
+.It Dv ELF_C_WRITE
+This command is used when the application wishes to create a new ELF
+file.
+Argument
+.Ar fd
+should have been opened for writing.
+Argument
+.Ar elf
+is ignored, and the previous contents of file referenced by argument
+.Ar fd
+are overwritten.
+.El
+.Ss Processing ar(1) archives
+An
+.Xr ar 1
+archive may be opened in read mode (with argument
+.Ar cmd
+set to
+.Dv ELF_C_READ )
+using
+.Fn elf_begin
+or
+.Fn elf_memory .
+The returned ELF descriptor can be passed into to
+subsequent calls to
+.Fn elf_begin
+to access individual members of the archive.
+.Pp
+Random access within an opened archive is possible using
+the
+.Xr elf_next 3
+and
+.Xr elf_rand 3
+functions.
+.Pp
+The symbol table of the archive may be retrieved
+using
+.Xr elf_getarsym 3 .
+.Sh RETURN VALUES
+The function returns a pointer to a ELF descriptor if successful, or NULL
+if an error occurred.
+.Sh EXAMPLES
+To iterate through the members of an
+.Xr ar 1
+archive, use:
+.Bd -literal -offset indent
+Elf_Cmd c;
+Elf *ar_e, *elf_e;
+\&...
+c = ELF_C_READ;
+if ((ar_e = elf_begin(fd, c, (Elf *) 0)) == 0) {
+ \&... handle error in opening the archive ...
+}
+while ((elf_e = elf_begin(fd, c, ar_e)) != 0) {
+ \&... process member referenced by elf_e here ...
+ c = elf_next(elf_e);
+ elf_end(elf_e);
+}
+.Ed
+.Pp
+To create a new ELF file, use:
+.Bd -literal -offset indent
+int fd;
+Elf *e;
+\&...
+if ((fd = open("filename", O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) {
+ \&... handle the error from open(2) ...
+}
+if ((e = elf_begin(fd, ELF_C_WRITE, (Elf *) 0)) == 0) {
+ \&... handle the error from elf_begin() ...
+}
+\&... create the ELF image using other elf(3) APIs ...
+elf_update(e, ELF_C_WRITE);
+elf_end(e);
+.Ed
+.Sh ERRORS
+Function
+.Fn elf_begin
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARCHIVE
+The archive denoted by argument
+.Ar elf
+could not be parsed.
+.It Bq Er ELF_E_ARGUMENT
+The value in argument
+.Ar cmd
+was unrecognized.
+.It Bq Er ELF_E_ARGUMENT
+A non-null value for argument
+.Ar elf
+was specified when
+.Ar cmd
+was set to
+.Dv ELF_C_RDWR .
+.It Bq Er ELF_E_ARGUMENT
+The value of argument
+.Ar fd
+differs from the one the ELF descriptor
+.Ar elf
+was created with.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar cmd
+differs from the value specified when ELF descriptor
+.Ar elf
+was created.
+.It Bq Er ELF_E_ARGUMENT
+An
+.Xr ar 1
+archive was opened with with
+.Ar cmd
+set to
+.Dv ELF_C_RDWR .
+.It Bq Er ELF_E_ARGUMENT
+The file referenced by argument
+.Ar fd
+was empty.
+.It Bq Er ELF_E_ARGUMENT
+The underlying file for argument
+.Ar fd
+was of an unsupported type.
+.It Bq Er ELF_E_IO
+The file descriptor in argument
+.Ar fd
+was invalid.
+.It Bq Er ELF_E_IO
+The file descriptor in argument
+.Ar fd
+could not be read or written to.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was encountered.
+.It Bq Er ELF_E_SEQUENCE
+Function
+.Fn elf_begin
+was called before a working version was established with
+.Xr elf_version 3 .
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_end 3 ,
+.Xr elf_errno 3 ,
+.Xr elf_memory 3 ,
+.Xr elf_next 3 ,
+.Xr elf_rand 3 ,
+.Xr elf_update 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_begin.c b/linkers/elftoolchain/libelf/elf_begin.c
new file mode 100644
index 0000000..a6c9e4a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_begin.c
@@ -0,0 +1,276 @@
+/*-
+ * Copyright (c) 2006,2008-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <ar.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libelf.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_begin.c 1923 2011-09-23 09:01:13Z jkoshy $");
+
+#define _LIBELF_INITSIZE (64*1024)
+
+/*
+ * Read from a device file, pipe or socket.
+ */
+static void *
+_libelf_read_special_file(int fd, size_t *fsz)
+{
+ ssize_t readsz;
+ size_t bufsz, datasz;
+ unsigned char *buf, *t;
+
+ datasz = 0;
+ readsz = 0;
+ bufsz = _LIBELF_INITSIZE;
+ if ((buf = malloc(bufsz)) == NULL)
+ goto resourceerror;
+
+ /*
+ * Read data from the file descriptor till we reach EOF, or
+ * till an error is encountered.
+ */
+ do {
+ /* Check if we need to expand the data buffer. */
+ if (datasz == bufsz) {
+ bufsz *= 2;
+ if ((t = realloc(buf, bufsz)) == NULL)
+ goto resourceerror;
+ buf = t;
+ }
+
+ do {
+ readsz = bufsz - datasz;
+ t = buf + datasz;
+ if ((readsz = read(fd, t, readsz)) <= 0)
+ break;
+ datasz += readsz;
+ } while (datasz < bufsz);
+
+ } while (readsz > 0);
+
+ if (readsz < 0) {
+ LIBELF_SET_ERROR(IO, errno);
+ goto error;
+ }
+
+ assert(readsz == 0);
+
+ /*
+ * Free up extra buffer space.
+ */
+ if (bufsz > datasz) {
+ if (datasz > 0) {
+ if ((t = realloc(buf, datasz)) == NULL)
+ goto resourceerror;
+ buf = t;
+ } else { /* Zero bytes read. */
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ free(buf);
+ buf = NULL;
+ }
+ }
+
+ *fsz = datasz;
+ return (buf);
+
+resourceerror:
+ LIBELF_SET_ERROR(RESOURCE, 0);
+error:
+ if (buf != NULL)
+ free(buf);
+ return (NULL);
+}
+
+
+static Elf *
+_libelf_open_object(int fd, Elf_Cmd c)
+{
+ Elf *e;
+ void *m;
+ mode_t mode;
+ size_t fsize;
+ struct stat sb;
+ unsigned int flags;
+
+ assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE);
+
+ if (fstat(fd, &sb) < 0) {
+ LIBELF_SET_ERROR(IO, errno);
+ return (NULL);
+ }
+
+ mode = sb.st_mode;
+ fsize = (size_t) sb.st_size;
+
+ /*
+ * Reject unsupported file types.
+ */
+ if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) &&
+ !S_ISSOCK(mode)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ /*
+ * For ELF_C_WRITE mode, allocate and return a descriptor.
+ */
+ if (c == ELF_C_WRITE) {
+ if ((e = _libelf_allocate_elf()) != NULL) {
+ _libelf_init_elf(e, ELF_K_ELF);
+ e->e_byteorder = LIBELF_PRIVATE(byteorder);
+ e->e_fd = fd;
+ e->e_cmd = c;
+ if (!S_ISREG(mode))
+ e->e_flags |= LIBELF_F_SPECIAL_FILE;
+ }
+
+ return (e);
+ }
+
+
+ /*
+ * ELF_C_READ and ELF_C_RDWR mode.
+ */
+ m = NULL;
+ flags = 0;
+ if (S_ISREG(mode)) {
+ /*
+ * Always map regular files in with 'PROT_READ'
+ * permissions.
+ *
+ * For objects opened in ELF_C_RDWR mode, when
+ * elf_update(3) is called, we remove this mapping,
+ * write file data out using write(2), and map the new
+ * contents back.
+ */
+ if ((m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd,
+ (off_t) 0)) == MAP_FAILED) {
+ LIBELF_SET_ERROR(IO, errno);
+ return (NULL);
+ }
+
+ flags = LIBELF_F_RAWFILE_MMAP;
+ } else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL)
+ flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE;
+ else
+ return (NULL);
+
+ if ((e = elf_memory(m, fsize)) == NULL) {
+ assert((flags & LIBELF_F_RAWFILE_MALLOC) ||
+ (flags & LIBELF_F_RAWFILE_MMAP));
+ if (flags & LIBELF_F_RAWFILE_MMAP)
+ (void) munmap(m, fsize);
+ else
+ free(m);
+ return (NULL);
+ }
+
+ /* ar(1) archives aren't supported in RDWR mode. */
+ if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) {
+ (void) elf_end(e);
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ e->e_flags |= flags;
+ e->e_fd = fd;
+ e->e_cmd = c;
+
+ return (e);
+}
+
+Elf *
+elf_begin(int fd, Elf_Cmd c, Elf *a)
+{
+ Elf *e;
+
+ e = NULL;
+
+ if (LIBELF_PRIVATE(version) == EV_NONE) {
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+ return (NULL);
+ }
+
+ switch (c) {
+ case ELF_C_NULL:
+ return (NULL);
+
+ case ELF_C_WRITE:
+ /*
+ * The ELF_C_WRITE command is required to ignore the
+ * descriptor passed in.
+ */
+ a = NULL;
+ break;
+
+ case ELF_C_RDWR:
+ if (a != NULL) { /* not allowed for ar(1) archives. */
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+ /*FALLTHROUGH*/
+ case ELF_C_READ:
+ /*
+ * Descriptor `a' could be for a regular ELF file, or
+ * for an ar(1) archive. If descriptor `a' was opened
+ * using a valid file descriptor, we need to check if
+ * the passed in `fd' value matches the original one.
+ */
+ if (a &&
+ ((a->e_fd != -1 && a->e_fd != fd) || c != a->e_cmd)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+ break;
+
+ default:
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+
+ }
+
+ if (a == NULL)
+ e = _libelf_open_object(fd, c);
+ else if (a->e_kind == ELF_K_AR)
+ e = _libelf_ar_open_member(a->e_fd, c, a);
+ else
+ (e = a)->e_activations++;
+
+ return (e);
+}
diff --git a/linkers/elftoolchain/libelf/elf_cntl.3 b/linkers/elftoolchain/libelf/elf_cntl.3
new file mode 100644
index 0000000..32649d1
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_cntl.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_cntl.3 289 2009-01-08 08:26:08Z jkoshy $
+.\"
+.Dd August 9, 2006
+.Os
+.Dt ELF_CNTL 3
+.Sh NAME
+.Nm elf_cntl
+.Nd control an elf file descriptor
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_cntl "Elf *elf" "Elf_Cmd cmd"
+.Sh DESCRIPTION
+Function
+.Fn elf_cntl
+controls the ELF library's subsequent use of the file descriptor
+used to create ELF descriptor
+.Ar elf .
+.Pp
+Argument
+.Ar cmd
+informs the library of the action to be taken:
+.Bl -tag -width "ELF_C_FDDONE"
+.It Dv ELF_C_FDDONE
+This value instructs the ELF library not to perform any further
+I/O on the file descriptor associated with argument
+.Ar elf .
+For ELF descriptors opened with mode
+.Ar ELF_C_WRITE
+or
+.Ar ELF_C_RDWR
+subsequent
+.Fn elf_update
+operations on the descriptor will fail.
+.It Dv ELF_C_FDREAD
+This value instructs the ELF library to read in all necessary
+data associated with ELF descriptor
+.Ar elf
+into memory so that the underlying file descriptor can be
+safely closed with command
+.Dv ELF_C_FDDONE .
+.El
+.Pp
+Argument
+.Ar elf
+must be an ELF descriptor associated with a file system object
+(e.g., an
+.Xr ar 1
+archive, an ELF file, or other data file).
+.Sh IMPLEMENTATION NOTES
+Due to use of
+.Xr mmap 2
+internally, this function is a no-op for ELF objects opened in
+.Dv ELF_C_READ
+mode.
+.Sh RETURN VALUES
+Function
+.Fn elf_cntl
+returns 0 on success, or -1 if an error was detected.
+.Sh ERRORS
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARCHIVE
+Argument
+.Ar elf
+is a descriptor for an archive member.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar cmd
+was not recognized.
+.It Bq Er ELF_E_MODE
+An
+.Dv ELF_C_FDREAD
+operation was requested on an ELF descriptor opened
+for writing.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_end 3 ,
+.Xr elf_next 3 ,
+.Xr elf_update 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_cntl.c b/linkers/elftoolchain/libelf/elf_cntl.c
new file mode 100644
index 0000000..2021917
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_cntl.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_cntl.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+int
+elf_cntl(Elf *e, Elf_Cmd c)
+{
+ if (e == NULL ||
+ (c != ELF_C_FDDONE && c != ELF_C_FDREAD)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (-1);
+ }
+
+ if (e->e_parent) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (-1);
+ }
+
+ if (c == ELF_C_FDREAD) {
+ if (e->e_cmd == ELF_C_WRITE) {
+ LIBELF_SET_ERROR(MODE, 0);
+ return (-1);
+ }
+ else
+ return (0);
+ }
+
+ e->e_fd = -1;
+ return 0;
+}
diff --git a/linkers/elftoolchain/libelf/elf_data.c b/linkers/elftoolchain/libelf/elf_data.c
new file mode 100644
index 0000000..5ac6453
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_data.c
@@ -0,0 +1,247 @@
+/*-
+ * Copyright (c) 2006,2008,2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <libelf.h>
+#include <stdlib.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_data.c 1765 2011-08-22 05:59:05Z jkoshy $");
+
+Elf_Data *
+elf_getdata(Elf_Scn *s, Elf_Data *d)
+{
+ Elf *e;
+ size_t fsz, msz, count;
+ int elfclass, elftype;
+ unsigned int sh_type;
+ uint64_t sh_align, sh_offset, sh_size;
+ int (*xlate)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
+
+ if (s == NULL || (e = s->s_elf) == NULL ||
+ (d != NULL && s != d->d_scn)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ assert(e->e_kind == ELF_K_ELF);
+
+ if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL)
+ return (d);
+
+ if (d != NULL)
+ return (STAILQ_NEXT(d, d_next));
+
+ if (e->e_rawfile == NULL) {
+ /*
+ * In the ELF_C_WRITE case, there is no source that
+ * can provide data for the section.
+ */
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ elfclass = e->e_class;
+
+ assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
+
+ if (elfclass == ELFCLASS32) {
+ sh_type = s->s_shdr.s_shdr32.sh_type;
+ sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
+ sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
+ sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
+ } else {
+ sh_type = s->s_shdr.s_shdr64.sh_type;
+ sh_offset = s->s_shdr.s_shdr64.sh_offset;
+ sh_size = s->s_shdr.s_shdr64.sh_size;
+ sh_align = s->s_shdr.s_shdr64.sh_addralign;
+ }
+
+ if (sh_type == SHT_NULL) {
+ LIBELF_SET_ERROR(SECTION, 0);
+ return (NULL);
+ }
+
+ if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST ||
+ elftype > ELF_T_LAST || (sh_type != SHT_NOBITS &&
+ sh_offset + sh_size > (uint64_t) e->e_rawsize)) {
+ LIBELF_SET_ERROR(SECTION, 0);
+ return (NULL);
+ }
+
+ if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)
+ (elftype, (size_t) 1, e->e_version)) == 0) {
+ LIBELF_SET_ERROR(UNIMPL, 0);
+ return (NULL);
+ }
+
+ if (sh_size % fsz) {
+ LIBELF_SET_ERROR(SECTION, 0);
+ return (NULL);
+ }
+
+ count = sh_size / fsz;
+
+ msz = _libelf_msize(elftype, elfclass, e->e_version);
+
+ assert(msz > 0);
+
+ if ((d = _libelf_allocate_data(s)) == NULL)
+ return (NULL);
+
+ d->d_buf = NULL;
+ d->d_off = 0;
+ d->d_align = sh_align;
+ d->d_size = msz * count;
+ d->d_type = elftype;
+ d->d_version = e->e_version;
+
+ if (sh_type == SHT_NOBITS || sh_size == 0) {
+ STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
+ return (d);
+ }
+
+ if ((d->d_buf = malloc(msz*count)) == NULL) {
+ (void) _libelf_release_data(d);
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ d->d_flags |= LIBELF_F_DATA_MALLOCED;
+
+ xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass);
+ if (!(*xlate)(d->d_buf, d->d_size, e->e_rawfile + sh_offset, count,
+ e->e_byteorder != LIBELF_PRIVATE(byteorder))) {
+ _libelf_release_data(d);
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
+
+ return (d);
+}
+
+Elf_Data *
+elf_newdata(Elf_Scn *s)
+{
+ Elf *e;
+ Elf_Data *d;
+
+ if (s == NULL || (e = s->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ assert(e->e_kind == ELF_K_ELF);
+
+ /*
+ * elf_newdata() has to append a data descriptor, so
+ * bring in existing section data if not already present.
+ */
+ if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data))
+ if (elf_getdata(s, NULL) == NULL)
+ return (NULL);
+
+ if ((d = _libelf_allocate_data(s)) == NULL)
+ return (NULL);
+
+ STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
+
+ d->d_align = 1;
+ d->d_buf = NULL;
+ d->d_off = (uint64_t) ~0;
+ d->d_size = 0;
+ d->d_type = ELF_T_BYTE;
+ d->d_version = LIBELF_PRIVATE(version);
+
+ (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY);
+
+ return (d);
+}
+
+/*
+ * Retrieve a data descriptor for raw (untranslated) data for section
+ * `s'.
+ */
+
+Elf_Data *
+elf_rawdata(Elf_Scn *s, Elf_Data *d)
+{
+ Elf *e;
+ int elf_class;
+ uint32_t sh_type;
+ uint64_t sh_align, sh_offset, sh_size;
+
+ if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ assert(e->e_kind == ELF_K_ELF);
+
+ if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL)
+ return (d);
+
+ if (d != NULL)
+ return (STAILQ_NEXT(d, d_next));
+
+ elf_class = e->e_class;
+
+ assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64);
+
+ if (elf_class == ELFCLASS32) {
+ sh_type = s->s_shdr.s_shdr32.sh_type;
+ sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
+ sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
+ sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
+ } else {
+ sh_type = s->s_shdr.s_shdr64.sh_type;
+ sh_offset = s->s_shdr.s_shdr64.sh_offset;
+ sh_size = s->s_shdr.s_shdr64.sh_size;
+ sh_align = s->s_shdr.s_shdr64.sh_addralign;
+ }
+
+ if (sh_type == SHT_NULL)
+ return (NULL);
+
+ if ((d = _libelf_allocate_data(s)) == NULL)
+ return (NULL);
+
+ d->d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL :
+ e->e_rawfile + sh_offset;
+ d->d_off = 0;
+ d->d_align = sh_align;
+ d->d_size = sh_size;
+ d->d_type = ELF_T_BYTE;
+ d->d_version = e->e_version;
+
+ STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next);
+
+ return (d);
+}
diff --git a/linkers/elftoolchain/libelf/elf_end.3 b/linkers/elftoolchain/libelf/elf_end.3
new file mode 100644
index 0000000..8649faa
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_end.3
@@ -0,0 +1,76 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_end.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd June 29, 2006
+.Os
+.Dt ELF_END 3
+.Sh NAME
+.Nm elf_end
+.Nd release an ELF descriptor
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_end "Elf *elf"
+.Sh DESCRIPTION
+Function
+.Fn elf_end
+is used to release the resources associated with an ELF descriptor
+pointed to by argument
+.Ar elf .
+This descriptor must have been allocated by a previous call to
+.Xr elf_begin 3
+or
+.Xr elf_memory 3 .
+For programming convenience, a NULL value is permitted for argument
+.Ar elf .
+.Pp
+A call to
+.Fn elf_end
+decrements the activation count for descriptor
+.Ar elf
+by one.
+The resources associated with the descriptor are only released
+with its activation count goes to zero.
+.Pp
+Once function
+.Fn elf_end
+returns zero, the ELF descriptor
+.Ar elf
+will no longer be valid and should not be used further.
+.Sh RETURN VALUES
+Function
+.Fn elf_end
+returns the current value of the ELF descriptor
+.Ar elf Ap s
+activation count, or zero if argument
+.Ar elf
+was NULL.
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_memory 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_end.c b/linkers/elftoolchain/libelf/elf_end.c
new file mode 100644
index 0000000..136ed9a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_end.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2006,2008-2009,2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/mman.h>
+
+#include <assert.h>
+#include <libelf.h>
+#include <stdlib.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_end.c 1922 2011-09-23 08:04:33Z jkoshy $");
+
+int
+elf_end(Elf *e)
+{
+ Elf *sv;
+ Elf_Scn *scn, *tscn;
+
+ if (e == NULL || e->e_activations == 0)
+ return (0);
+
+ if (--e->e_activations > 0)
+ return (e->e_activations);
+
+ assert(e->e_activations == 0);
+
+ while (e && e->e_activations == 0) {
+ switch (e->e_kind) {
+ case ELF_K_AR:
+ /*
+ * If we still have open child descriptors, we
+ * need to defer reclaiming resources till all
+ * the child descriptors for the archive are
+ * closed.
+ */
+ if (e->e_u.e_ar.e_nchildren > 0)
+ return (0);
+ break;
+ case ELF_K_ELF:
+ /*
+ * Reclaim all section descriptors.
+ */
+ STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next,
+ tscn)
+ scn = _libelf_release_scn(scn);
+ break;
+ case ELF_K_NUM:
+ assert(0);
+ default:
+ break;
+ }
+
+ if (e->e_rawfile) {
+ if (e->e_flags & LIBELF_F_RAWFILE_MMAP)
+ (void) munmap(e->e_rawfile, e->e_rawsize);
+ else if (e->e_flags & LIBELF_F_RAWFILE_MALLOC)
+ free(e->e_rawfile);
+ }
+
+ sv = e;
+ if ((e = e->e_parent) != NULL)
+ e->e_u.e_ar.e_nchildren--;
+ sv = _libelf_release_elf(sv);
+ }
+
+ return (0);
+}
diff --git a/linkers/elftoolchain/libelf/elf_errmsg.3 b/linkers/elftoolchain/libelf/elf_errmsg.3
new file mode 100644
index 0000000..822ba6a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_errmsg.3
@@ -0,0 +1,107 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_errmsg.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd June 11, 2006
+.Os
+.Dt ELF_ERRMSG 3
+.Sh NAME
+.Nm elf_errmsg ,
+.Nm elf_errno
+.Nd ELF library error message handling
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_errno "void"
+.Ft "const char *"
+.Fn elf_errmsg "int error"
+.Sh DESCRIPTION
+When an error occurs during an ELF library API call, the library
+encodes the error using an error number and stores the error number
+internally for retrieval by the application at a later point of time.
+Error numbers may contain an OS supplied error code in addition to
+an ELF API specific error code.
+An error number value of zero indicates no error.
+.Pp
+Function
+.Fn elf_errno
+is used to retrieve the last error recorded by the ELF library.
+Invoking this function has the side-effect of resetting the
+ELF library's recorded error number to zero.
+.Pp
+The function
+.Fn elf_errmsg
+returns a null-terminated string with a human readable
+description of the error specified in argument
+.Ar error .
+A zero value for argument
+.Ar error
+retrieves the most recent error encountered by the ELF
+library.
+An argument value of -1 behaves identically, except that
+it guarantees a non-NULL return from
+.Fn elf_errmsg .
+.Sh RETURN VALUES
+Function
+.Fn elf_errno
+returns a non-zero value encoding the last error encountered
+by the ELF library, or zero if no error was encountered.
+.Pp
+Function
+.Fn elf_errmsg
+returns a pointer to library local storage for non-zero values
+of argument
+.Ar error .
+With a zero argument, the function will return a NULL pointer if no
+error had been encountered by the library, or will return a pointer to
+library local storage containing an appropriate message otherwise.
+.Sh EXAMPLES
+Clearing the ELF library's recorded error number can be accomplished
+by invoking
+.Fn elf_errno
+and discarding its return value.
+.Bd -literal -offset indent
+/* clear error */
+(void) elf_errno();
+.Ed
+.Pp
+Retrieving a human-readable description of the current error number
+can be done with the following snippet:
+.Bd -literal -offset indent
+int err;
+const char *errmsg;
+\&...
+err = elf_errno();
+if (err != 0)
+ errmsg = elf_errmsg(err);
+.Ed
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr gelf 3
+.Sh BUGS
+Function
+.Fn elf_errmsg
+is not localized.
diff --git a/linkers/elftoolchain/libelf/elf_errmsg.c b/linkers/elftoolchain/libelf/elf_errmsg.c
new file mode 100644
index 0000000..7a6e552
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_errmsg.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2006,2008,2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_errmsg.c 1345 2011-01-01 11:17:52Z jkoshy $");
+
+/*
+ * Retrieve a human readable translation for an error message.
+ */
+
+const char *_libelf_errors[] = {
+#define DEFINE_ERROR(N,S) [ELF_E_##N] = S
+ DEFINE_ERROR(NONE, "No Error"),
+ DEFINE_ERROR(ARCHIVE, "Malformed ar(1) archive"),
+ DEFINE_ERROR(ARGUMENT, "Invalid argument"),
+ DEFINE_ERROR(CLASS, "ELF class mismatch"),
+ DEFINE_ERROR(DATA, "Invalid data buffer descriptor"),
+ DEFINE_ERROR(HEADER, "Missing or malformed ELF header"),
+ DEFINE_ERROR(IO, "I/O error"),
+ DEFINE_ERROR(LAYOUT, "Layout constraint violation"),
+ DEFINE_ERROR(MODE, "Incorrect ELF descriptor mode"),
+ DEFINE_ERROR(RANGE, "Value out of range of target"),
+ DEFINE_ERROR(RESOURCE, "Resource exhaustion"),
+ DEFINE_ERROR(SECTION, "Invalid section descriptor"),
+ DEFINE_ERROR(SEQUENCE, "API calls out of sequence"),
+ DEFINE_ERROR(UNIMPL, "Unimplemented feature"),
+ DEFINE_ERROR(VERSION, "Unknown ELF API version"),
+ DEFINE_ERROR(NUM, "Unknown error")
+#undef DEFINE_ERROR
+};
+
+const char *
+elf_errmsg(int error)
+{
+ int oserr;
+
+ if (error == ELF_E_NONE &&
+ (error = LIBELF_PRIVATE(error)) == 0)
+ return NULL;
+ else if (error == -1)
+ error = LIBELF_PRIVATE(error);
+
+ oserr = error >> LIBELF_OS_ERROR_SHIFT;
+ error &= LIBELF_ELF_ERROR_MASK;
+
+ if (error < ELF_E_NONE || error >= ELF_E_NUM)
+ return _libelf_errors[ELF_E_NUM];
+ if (oserr) {
+ (void) snprintf(LIBELF_PRIVATE(msg),
+ sizeof(LIBELF_PRIVATE(msg)), "%s: %s",
+ _libelf_errors[error], strerror(oserr));
+ return (const char *)&LIBELF_PRIVATE(msg);
+ }
+ return _libelf_errors[error];
+}
diff --git a/linkers/elftoolchain/libelf/elf_errno.c b/linkers/elftoolchain/libelf/elf_errno.c
new file mode 100644
index 0000000..95e91b9
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_errno.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2006,2008,2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_errno.c 1345 2011-01-01 11:17:52Z jkoshy $");
+
+int
+elf_errno(void)
+{
+ int old;
+
+ old = LIBELF_PRIVATE(error);
+ LIBELF_PRIVATE(error) = 0;
+ return (old & LIBELF_ELF_ERROR_MASK);
+}
diff --git a/linkers/elftoolchain/libelf/elf_fill.3 b/linkers/elftoolchain/libelf/elf_fill.3
new file mode 100644
index 0000000..ab42a42
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_fill.3
@@ -0,0 +1,52 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_fill.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd June 11, 2006
+.Os
+.Dt ELF_FILL 3
+.Sh NAME
+.Nm elf_fill
+.Nd set fill byte for inter-section padding
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft void
+.Fn elf_fill "int fill"
+.Sh DESCRIPTION
+Function
+.Fn elf_fill
+allows an application to specify a fill value for the padding inserted
+between two sections of an ELF file to meet section alignment
+constraints.
+By default the ELF library uses zero bytes for padding.
+.Pp
+The ELF library will only pad bytes if the
+.Dv ELF_F_LAYOUT
+flag is not set for the ELF file.
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_flagelf 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_fill.c b/linkers/elftoolchain/libelf/elf_fill.c
new file mode 100644
index 0000000..ac9e02e
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_fill.c
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_fill.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+void
+elf_fill(int fill)
+{
+ LIBELF_PRIVATE(fillchar) = fill;
+}
diff --git a/linkers/elftoolchain/libelf/elf_flag.c b/linkers/elftoolchain/libelf/elf_flag.c
new file mode 100644
index 0000000..9d31719
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_flag.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2006,2008-2009,2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_flag.c 1918 2011-09-22 10:42:06Z jkoshy $");
+
+unsigned int
+elf_flagarhdr(Elf_Arhdr *a, Elf_Cmd c, unsigned int flags)
+{
+ unsigned int r;
+
+ if (a == NULL)
+ return (0);
+
+ if ((c != ELF_C_SET && c != ELF_C_CLR) ||
+ (flags & ~ELF_F_DIRTY) != 0) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (c == ELF_C_SET)
+ r = a->ar_flags |= flags;
+ else
+ r = a->ar_flags &= ~flags;
+
+ return (r & LIBELF_F_API_MASK);
+}
+
+unsigned int
+elf_flagdata(Elf_Data *d, Elf_Cmd c, unsigned int flags)
+{
+ unsigned int r;
+
+ if (d == NULL)
+ return (0);
+
+ if ((c != ELF_C_SET && c != ELF_C_CLR) ||
+ (flags & ~ELF_F_DIRTY) != 0) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (c == ELF_C_SET)
+ r = d->d_flags |= flags;
+ else
+ r = d->d_flags &= ~flags;
+
+ return (r & LIBELF_F_API_MASK);
+}
+
+unsigned int
+elf_flagehdr(Elf *e, Elf_Cmd c, unsigned int flags)
+{
+ int ec;
+ void *ehdr;
+
+ if (e == NULL)
+ return (0);
+
+ if ((c != ELF_C_SET && c != ELF_C_CLR) ||
+ (e->e_kind != ELF_K_ELF) || (flags & ~ELF_F_DIRTY) != 0 ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32)
+ ehdr = e->e_u.e_elf.e_ehdr.e_ehdr32;
+ else
+ ehdr = e->e_u.e_elf.e_ehdr.e_ehdr64;
+
+ if (ehdr == NULL) {
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+ return (0);
+ }
+
+ return (elf_flagelf(e, c, flags));
+}
+
+unsigned int
+elf_flagelf(Elf *e, Elf_Cmd c, unsigned int flags)
+{
+ int r;
+
+ if (e == NULL)
+ return (0);
+
+ if ((c != ELF_C_SET && c != ELF_C_CLR) ||
+ (e->e_kind != ELF_K_ELF) ||
+ (flags & ~(ELF_F_ARCHIVE | ELF_F_ARCHIVE_SYSV |
+ ELF_F_DIRTY | ELF_F_LAYOUT)) != 0) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if ((flags & ELF_F_ARCHIVE_SYSV) && (flags & ELF_F_ARCHIVE) == 0) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if ((flags & ELF_F_ARCHIVE) && e->e_cmd != ELF_C_WRITE) {
+ LIBELF_SET_ERROR(MODE, 0);
+ return (0);
+ }
+
+ if (c == ELF_C_SET)
+ r = e->e_flags |= flags;
+ else
+ r = e->e_flags &= ~flags;
+ return (r & LIBELF_F_API_MASK);
+}
+
+unsigned int
+elf_flagphdr(Elf *e, Elf_Cmd c, unsigned int flags)
+{
+ int ec;
+ void *phdr;
+
+ if (e == NULL)
+ return (0);
+
+ if ((c != ELF_C_SET && c != ELF_C_CLR) ||
+ (e->e_kind != ELF_K_ELF) || (flags & ~ELF_F_DIRTY) != 0 ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32)
+ phdr = e->e_u.e_elf.e_phdr.e_phdr32;
+ else
+ phdr = e->e_u.e_elf.e_phdr.e_phdr64;
+
+ if (phdr == NULL) {
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+ return (0);
+ }
+
+ return (elf_flagelf(e, c, flags));
+}
+
+unsigned int
+elf_flagscn(Elf_Scn *s, Elf_Cmd c, unsigned int flags)
+{
+ int r;
+
+ if (s == NULL)
+ return (0);
+
+ if ((c != ELF_C_SET && c != ELF_C_CLR) ||
+ (flags & ~ELF_F_DIRTY) != 0) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (c == ELF_C_SET)
+ r = s->s_flags |= flags;
+ else
+ r = s->s_flags &= ~flags;
+ return (r & LIBELF_F_API_MASK);
+}
+
+unsigned int
+elf_flagshdr(Elf_Scn *s, Elf_Cmd c, unsigned int flags)
+{
+ return (elf_flagscn(s, c, flags));
+}
diff --git a/linkers/elftoolchain/libelf/elf_flagdata.3 b/linkers/elftoolchain/libelf/elf_flagdata.3
new file mode 100644
index 0000000..d4fd420
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_flagdata.3
@@ -0,0 +1,194 @@
+.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_flagdata.3 221 2008-08-10 04:56:27Z jkoshy $
+.\"
+.Dd October 22, 2007
+.Os
+.Dt ELF_FLAGDATA 3
+.Sh NAME
+.Nm elf_flagarhdr ,
+.Nm elf_flagdata ,
+.Nm elf_flagehdr ,
+.Nm elf_flagelf ,
+.Nm elf_flagphdr ,
+.Nm elf_flagscn ,
+.Nm elf_flagshdr
+.Nd manipulate flags associated with ELF(3) data structures
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "unsigned int"
+.Fn elf_flagarhdr "Elf_Arhdr *arhdr" "Elf_Cmd cmd" "unsigned int flags"
+.Ft "unsigned int"
+.Fn elf_flagdata "Elf_Data *data" "Elf_Cmd cmd" "unsigned int flags"
+.Ft "unsigned int"
+.Fn elf_flagehdr "Elf *elf" "Elf_Cmd cmd" "unsigned int flags"
+.Ft "unsigned int"
+.Fn elf_flagelf "Elf *elf" "Elf_Cmd cmd" "unsigned int flags"
+.Ft "unsigned int"
+.Fn elf_flagphdr "Elf *elf" "Elf_Cmd cmd" "unsigned int flags"
+.Ft "unsigned int"
+.Fn elf_flagscn "Elf_Scn *scn" "Elf_Cmd cmd" "unsigned int flags"
+.Ft "unsigned int"
+.Fn elf_flagshdr "Elf_Scn *scn" "Elf_Cmd cmd" "unsigned int flags"
+.Sh DESCRIPTION
+These functions are used to query, set or reset flags on data
+structures associated with an ELF file.
+.Pp
+Arguments
+.Ar arhdr ,
+.Ar data ,
+.Ar elf
+and
+.Ar scn
+denote the data structures whose flags need to be changed.
+These values are allowed to be NULL to simplify error handling in
+application code.
+.Pp
+Argument
+.Ar cmd
+may have the following values:
+.Bl -tag -width ELF_C_SET
+.It Dv ELF_C_CLR
+The argument
+.Ar flags
+specifies the flags to be cleared.
+.It Dv ELF_C_SET
+The argument
+.Ar flags
+specifies the flags to be set.
+.El
+.Pp
+The argument
+.Ar flags
+is allowed to have the following flags set:
+.Bl -tag -width ELF_F_ARCHIVE_SYSV
+.It Dv ELF_F_ARCHIVE
+This flag is only valid with the
+.Fn elf_flagelf
+API.
+It informs the library that the application desires to create an
+.Xr ar 1
+archive.
+Argument
+.Ar elf
+should have been opened for writing using the
+.Dv ELF_C_WRITE
+command to function
+.Fn elf_begin .
+.It Dv ELF_F_ARCHIVE_SYSV
+This flag is used in conjunction with the
+.Dv ELF_F_ARCHIVE
+flag to indicate that library should create archives that conform
+to System V layout rules.
+The default is to create BSD style archives.
+.It Dv ELF_F_DIRTY
+Mark the associated data structure as needing to be written back
+to the underlying file.
+A subsequent call to
+.Xr elf_update 3
+will resynchronize the library's internal data structures.
+.It Dv ELF_F_LAYOUT
+This flag is only valid with the
+.Fn elf_flagelf
+API.
+It informs the library that the application will take
+responsibility for the layout of the file and that the library is
+not to insert any padding in between sections.
+.El
+.Pp
+Marking a given data structure as
+.Dq dirty
+affects all of its contained elements.
+Thus marking an ELF descriptor
+.Ar elf
+with
+.Fn elf_flagelf "elf" "ELF_C_SET" "ELF_F_DIRTY"
+means that the entire contents of the descriptor are
+.Dq dirty .
+.Pp
+Using a value of zero for argument
+.Ar flags
+will return the current set of flags for the data structure being
+queried.
+.Sh RETURN VALUES
+These functions return the updated flags is successful, and zero if
+an error is detected.
+.Sh COMPATIBILITY
+The
+.Fn elf_flagarhdr
+function and the
+.Dv ELF_F_ARCHIVE
+and
+.Dv ELF_F_ARCHIVE_SYSV
+flags are an extension to the ELF(3) API.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+An unsupported value was used for the
+.Ar cmd
+argument.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar flags
+had unsupported flags set.
+.It Bq Er ELF_E_ARGUMENT
+The argument
+.Ar elf
+was not a descriptor for an ELF object.
+.It Bq Er ELF_E_MODE
+The
+.Dv ELF_F_ARCHIVE
+flag was used with an ELF descriptor that had not been opened for writing.
+.It Bq Er ELF_E_SEQUENCE
+Function
+.Fn elf_flagehdr
+was called without an executable header being allocated.
+.It Bq Er ELF_E_SEQUENCE
+Function
+.Fn elf_flagphdr
+was called without a program header being allocated.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_newehdr 3 ,
+.Xr elf32_newphdr 3 ,
+.Xr elf32_newshdr 3 ,
+.Xr elf64_newehdr 3 ,
+.Xr elf64_newphdr 3 ,
+.Xr elf64_newshdr 3 ,
+.Xr elf_newdata 3 ,
+.Xr elf_update 3 ,
+.Xr gelf 3 ,
+.Xr gelf_newehdr 3 ,
+.Xr gelf_newphdr 3 ,
+.Xr gelf_newshdr 3 ,
+.Xr gelf_update_dyn 3 ,
+.Xr gelf_update_move 3 ,
+.Xr gelf_update_rel 3 ,
+.Xr gelf_update_rela 3 ,
+.Xr gelf_update_sym 3 ,
+.Xr gelf_update_syminfo 3
diff --git a/linkers/elftoolchain/libelf/elf_getarhdr.3 b/linkers/elftoolchain/libelf/elf_getarhdr.3
new file mode 100644
index 0000000..1aab71c
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getarhdr.3
@@ -0,0 +1,97 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getarhdr.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 15, 2006
+.Os
+.Dt ELF_GETARHDR 3
+.Sh NAME
+.Nm elf_getarhdr
+.Nd retrieve ar(1) header for an archive member
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf_Arhdr *"
+.Fn elf_getarhdr "Elf *elf"
+.Sh DESCRIPTION
+The
+.Fn elf_getarhdr
+function returns a pointer to an archive member header for
+a descriptor
+.Ar elf .
+This descriptor must have been returned by a prior call to
+.Xr elf_begin 3 ,
+and must be a descriptor for a member inside an
+.Xr ar 1
+archive.
+.Pp
+Structure
+.Vt Elf_Arhdr
+includes the following members:
+.Bl -tag -width indent
+.It Vt "char *" Va ar_name
+A pointer to a null terminated string containing the translated
+name of the archive member.
+.It Vt "char *" Va ar_rawname
+A pointer to a null terminated string containing the untranslated
+name for the archive member, including all
+.Xr ar 1
+formatting characters and trailing white space.
+.It Vt time_t Va ar_date
+The timestamp associated with the member.
+.It Vt uid_t Va ar_uid
+The uid of the creator of the member.
+.It Vt gid_t Va ar_gid
+The gid of the creator of the member.
+.It Vt mode_t Va ar_mode
+The file mode of the member.
+.It Vt size_t Va ar_size
+The size of the member in bytes.
+.El
+.Sh RETURN VALUES
+This function returns a valid pointer to an
+.Vt Elf_Arhdr
+structure if successful, or NULL if an error is encountered.
+.Sh ERRORS
+Function
+.Fn elf_getarhdr
+may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for a member of an
+.Xr ar 1
+archive.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_getarsym 3 ,
+.Xr elf_memory 3
diff --git a/linkers/elftoolchain/libelf/elf_getarhdr.c b/linkers/elftoolchain/libelf/elf_getarhdr.c
new file mode 100644
index 0000000..43ceafd
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getarhdr.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2006,2008,2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_getarhdr.c 1341 2011-01-01 04:28:29Z jkoshy $");
+
+Elf_Arhdr *
+elf_getarhdr(Elf *e)
+{
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (e->e_flags & LIBELF_F_AR_HEADER)
+ return (e->e_hdr.e_arhdr);
+
+ return (_libelf_ar_gethdr(e));
+}
diff --git a/linkers/elftoolchain/libelf/elf_getarsym.3 b/linkers/elftoolchain/libelf/elf_getarsym.3
new file mode 100644
index 0000000..cda0511
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getarsym.3
@@ -0,0 +1,130 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getarsym.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 15, 2006
+.Os
+.Dt ELF_GETARSYM 3
+.Sh NAME
+.Nm elf_getarsym
+.Nd retrieve the symbol table of an archive
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf_Arsym *"
+.Fn elf_getarsym "Elf *elf" "size_t *ptr"
+.Sh DESCRIPTION
+The function
+.Fn elf_getarsym
+retrieves the symbol table for an
+.Xr ar 1
+archive, if one is available.
+.Pp
+Argument
+.Ar elf
+should be a descriptor for an
+.Xr ar 1
+archive opened using
+.Fn elf_begin
+or
+.Fn elf_memory .
+.Pp
+If the archive
+.Ar elf
+contains a symbol table with n entries, this function returns a
+pointer to an array of n+1
+.Vt Elf_Arsym
+structures.
+An
+.Vt Elf_Arsym
+structure has the following elements:
+.Bl -tag -width indent -compact
+.It Vt "char *" Va as_name
+This structure member is a pointer to a null-terminated symbol name.
+.It Vt "off_t" Va as_off
+This structure member contains the byte offset from the beginning of the archive to
+the header for the archive member.
+This value is suitable for use with
+.Xr elf_rand 3 .
+.It Vt "unsigned long" Va as_hash
+This structure member contains a portable hash value for the symbol
+name, as computed by
+.Xr elf_hash 3 .
+.El
+.Pp
+The last entry of the returned array will have a NULL value for member
+.Va as_name ,
+a zero value for member
+.Va as_off
+and an illegal value of ~0UL for
+.Va as_hash .
+.Pp
+If argument
+.Ar ptr
+is non-null, the
+.Fn elf_getarsym
+function will store the number of table entries returned (including the
+sentinel entry at the end) into the location it points to.
+.Sh RETURN VALUES
+Function
+.Fn elf_getarsym
+returns a pointer to an array of
+.Vt Elf_Arsym
+structures if successful, or a NULL
+pointer if an error was encountered.
+.Pp
+If argument
+.Ar ptr
+is non-null and there was no error, the library will store the
+number of archive symbol entries returned into the location it
+points to.
+If argument
+.Ar ptr
+is non-null and an error was encountered, the library will
+set the location pointed to by it to zero.
+.Sh ERRORS
+Function
+.Fn elf_getarsym
+may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an
+.Xr ar 1
+archive.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_getarhdr 3 ,
+.Xr elf_hash 3 ,
+.Xr elf_memory 3 ,
+.Xr elf_next 3 ,
+.Xr elf_rand 3
diff --git a/linkers/elftoolchain/libelf/elf_getarsym.c b/linkers/elftoolchain/libelf/elf_getarsym.c
new file mode 100644
index 0000000..1852262
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getarsym.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_getarsym.c 1360 2011-01-08 08:27:41Z jkoshy $");
+
+Elf_Arsym *
+elf_getarsym(Elf *ar, size_t *ptr)
+{
+ size_t n;
+ Elf_Arsym *symtab;
+
+ n = 0;
+ symtab = NULL;
+
+ if (ar == NULL || ar->e_kind != ELF_K_AR)
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ else if ((symtab = ar->e_u.e_ar.e_symtab) != NULL)
+ n = ar->e_u.e_ar.e_symtabsz;
+ else if (ar->e_u.e_ar.e_rawsymtab)
+ symtab = (ar->e_flags & LIBELF_F_AR_VARIANT_SVR4) ?
+ _libelf_ar_process_svr4_symtab(ar, &n) :
+ _libelf_ar_process_bsd_symtab(ar, &n);
+ else
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+
+ if (ptr)
+ *ptr = n;
+ return (symtab);
+}
diff --git a/linkers/elftoolchain/libelf/elf_getbase.3 b/linkers/elftoolchain/libelf/elf_getbase.3
new file mode 100644
index 0000000..fa17353
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getbase.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 2006,2008,2010 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getbase.3 978 2010-06-06 12:40:19Z jkoshy $
+.\"
+.Dd June 6, 2010
+.Os
+.Dt ELF_GETBASE 3
+.Sh NAME
+.Nm elf_getbase
+.Nd get the base offset for an object file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft off_t
+.Fn elf_getbase "Elf *elf"
+.Sh DESCRIPTION
+Function
+.Fn elf_getbase
+returns the file offset to the first byte of the object referenced by ELF
+descriptor
+.Ar elf .
+.Pp
+For descriptors referencing members of archives, the returned offset is
+the file offset of the member in its containing archive.
+For descriptors to regular objects, the returned offset is (vacuously)
+zero.
+.Sh RETURN VALUES
+Function
+.Fn elf_getbase
+returns a valid file offset if successful, or
+.Pq Vt off_t
+.Li -1
+in case of an error.
+.Sh ERRORS
+Function
+.Fn elf_getbase
+may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getarhdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_rawfile 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_getbase.c b/linkers/elftoolchain/libelf/elf_getbase.c
new file mode 100644
index 0000000..30058ca
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getbase.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_getbase.c 977 2010-06-06 11:50:31Z jkoshy $");
+
+off_t
+elf_getbase(Elf *e)
+{
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return ((off_t) -1);
+ }
+
+ if (e->e_parent == NULL)
+ return ((off_t) 0);
+
+ return ((off_t) ((uintptr_t) e->e_rawfile -
+ (uintptr_t) e->e_parent->e_rawfile));
+}
diff --git a/linkers/elftoolchain/libelf/elf_getdata.3 b/linkers/elftoolchain/libelf/elf_getdata.3
new file mode 100644
index 0000000..8816a5a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getdata.3
@@ -0,0 +1,229 @@
+.\" Copyright (c) 2006,2008,2010-2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getdata.3 1766 2011-08-22 06:01:03Z jkoshy $
+.\"
+.Dd January 26, 2011
+.Os
+.Dt ELF_GETDATA 3
+.Sh NAME
+.Nm elf_getdata ,
+.Nm elf_newdata ,
+.Nm elf_rawdata
+.Nd iterate through or allocate section data
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf_Data *"
+.Fn elf_getdata "Elf_Scn *scn" "Elf_Data *data"
+.Ft "Elf_Data *"
+.Fn elf_newdata "Elf_Scn *scn"
+.Ft "Elf_Data *"
+.Fn elf_rawdata "Elf_Scn *scn" "Elf_Data *data"
+.Sh DESCRIPTION
+These functions are used to access and manipulate data descriptors
+associated with section descriptors.
+Data descriptors used by the ELF library are described in
+.Xr elf 3 .
+.Pp
+Function
+.Fn elf_getdata
+will return the next data descriptor associated with section descriptor
+.Ar scn .
+The returned data descriptor will be setup to contain translated data.
+Argument
+.Ar data
+may be NULL, in which case the function returns the first data descriptor
+associated with section
+.Ar scn .
+If argument
+.Ar data
+is not NULL, it must be a pointer to a data descriptor associated with
+section descriptor
+.Ar scn ,
+and function
+.Fn elf_getdata
+will return a pointer to the next data descriptor for the section,
+or NULL when the end of the section's descriptor list is reached.
+.Pp
+Function
+.Fn elf_newdata
+will allocate a new data descriptor and append it to the list of data
+descriptors associated with section descriptor
+.Ar scn .
+The new data descriptor will be initialized as follows:
+.Bl -tag -width "d_version" -compact -offset indent
+.It Va d_align
+Set to 1.
+.It Va d_buf
+Initialized to NULL.
+.It Va d_off
+Set to (off_t) -1.
+This field is under application control if the
+.Dv ELF_F_LAYOUT
+flag was set on the ELF descriptor.
+.It Va d_size
+Set to zero.
+.It Va d_type
+Initialized to
+.Dv ELF_T_BYTE .
+.It Va d_version
+Set to the current working version of the library, as set by
+.Xr elf_version 3 .
+.El
+The application must set these values as appropriate before
+calling
+.Xr elf_update 3 .
+Section
+.Ar scn
+must be associated with an ELF file opened for writing.
+If the application has not requested full control of layout by
+setting the
+.Dv ELF_F_LAYOUT
+flag on descriptor
+.Ar elf ,
+then the data referenced by the returned descriptor will be positioned
+after the existing content of the section, honoring the file alignment
+specified in member
+.Va d_align .
+On successful completion of a call to
+.Fn elf_newdata ,
+the ELF library will mark the section
+.Ar scn
+as
+.Dq dirty .
+.Pp
+Function
+.Fn elf_rawdata
+is used to step through the data descriptors associated with
+section
+.Ar scn .
+In contrast to function
+.Fn elf_getdata ,
+this function returns untranslated data.
+If argument
+.Ar data
+is NULL, the first data descriptor associated with section
+.Ar scn
+is returned.
+If argument
+.Ar data
+is not NULL, is must be a data descriptor associated with
+section
+.Ar scn ,
+and function
+.Fn elf_rawdata
+will return the next data descriptor in the list, or NULL
+if no further descriptors are present.
+Function
+.Fn elf_rawdata
+always returns
+.Vt Elf_Data
+structures of type
+.Dv ELF_T_BYTE .
+.Ss Special handling of zero-sized and SHT_NOBITS sections
+For sections of type
+.Dv SHT_NOBITS,
+and for zero-sized sections,
+the functions
+.Fn elf_getdata
+and
+.Fn elf_rawdata
+return a pointer to a valid
+.Vt Elf_Data
+structure that has its
+.Va d_buf
+member set to NULL and its
+.Va d_size
+member set to the size of the section.
+.Pp
+If an application wishes to create a section of type
+.Dv SHT_NOBITS ,
+it should add a data buffer to the section using function
+.Fn elf_newdata .
+It should then set the
+.Va d_buf
+and
+.Va d_size
+members of the returned
+.Vt Elf_Data
+structure to NULL and the desired size of the section respectively.
+.Sh RETURN VALUES
+These functions return a valid pointer to a data descriptor if successful, or
+NULL if an error occurs.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Either of the arguments
+.Ar scn
+or
+.Ar data
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+The data descriptor referenced by argument
+.Ar data
+is not associated with section descriptor
+.Ar scn .
+.It Bq Er ELF_E_ARGUMENT
+The section denoted by argument
+.Ar scn
+had no data associated with it.
+.It Bq Er ELF_E_DATA
+Retrieval of data from the underlying object failed.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected.
+.It Bq Er ELF_E_SECTION
+Section
+.Ar scn
+had type
+.Dv SHT_NULL .
+.It Bq Er ELF_E_SECTION
+The type of the section
+.Ar scn
+was not recognized by the library.
+.It Bq Er ELF_E_SECTION
+The size of the section
+.Ar scn
+is not a multiple of the file size for its section type.
+.It Bq Er ELF_E_SECTION
+The file offset for section
+.Ar scn
+is incorrect.
+.It Bq Er ELF_E_UNIMPL
+The section type associated with section
+.Ar scn
+is currently unsupported by the library.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_flagdata 3 ,
+.Xr elf_flagscn 3 ,
+.Xr elf_getscn 3 ,
+.Xr elf_getshdr 3 ,
+.Xr elf_newscn 3 ,
+.Xr elf_rawfile 3 ,
+.Xr elf_update 3 ,
+.Xr elf_version 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_getident.3 b/linkers/elftoolchain/libelf/elf_getident.3
new file mode 100644
index 0000000..01d7f97
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getident.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getident.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd July 3, 2006
+.Os
+.Dt ELF_GETIDENT 3
+.Sh NAME
+.Nm elf_getident
+.Nd return the initial bytes of a file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft char *
+.Fn elf_getident "Elf *elf" "size_t *sz"
+.Sh DESCRIPTION
+Function
+.Fn elf_getident
+returns a pointer to the initial bytes of the file for descriptor
+.Ar elf .
+.Pp
+If argument
+.Ar sz
+is non-null, the size of the identification area returned is written
+to the location pointed to by
+.Ar sz .
+This location is set to zero on errors.
+.Sh RETURN VALUES
+Function
+.Fn elf_getident
+will return a non-NULL pointer to the initial bytes of the file if
+successful, or NULL if an error condition is detected.
+.Sh ERRORS
+Function
+.Fn elf_getident
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_SEQUENCE
+ELF descriptor
+.Ar elf
+was opened for writing and function
+.Fn elf_getident
+was called before a call to
+.Xr elf_update 3 .
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getarhdr 3 ,
+.Xr elf_getbase 3 ,
+.Xr elf_getflags 3 ,
+.Xr elf_kind 3 ,
+.Xr elf_rawfile 3 ,
+.Xr elf_update 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getclass 3 ,
+.Xr gelf_getehdr 3
diff --git a/linkers/elftoolchain/libelf/elf_getident.c b/linkers/elftoolchain/libelf/elf_getident.c
new file mode 100644
index 0000000..c17f3a5
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getident.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <ar.h>
+#include <assert.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_getident.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+char *
+elf_getident(Elf *e, size_t *sz)
+{
+
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ goto error;
+ }
+
+ if (e->e_cmd == ELF_C_WRITE && e->e_rawfile == NULL) {
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+ goto error;
+ }
+
+ assert(e->e_kind != ELF_K_AR || e->e_cmd == ELF_C_READ);
+
+ if (sz) {
+ if (e->e_kind == ELF_K_AR)
+ *sz = SARMAG;
+ else if (e->e_kind == ELF_K_ELF)
+ *sz = EI_NIDENT;
+ else
+ *sz = e->e_rawsize;
+ }
+
+ return ((char *) e->e_rawfile);
+
+ error:
+ if (sz)
+ *sz = 0;
+ return (NULL);
+}
diff --git a/linkers/elftoolchain/libelf/elf_getphdrnum.3 b/linkers/elftoolchain/libelf/elf_getphdrnum.3
new file mode 100644
index 0000000..f0fae5e
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getphdrnum.3
@@ -0,0 +1,86 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getphdrnum.3 467 2009-08-05 18:18:49Z jkoshy $
+.\"
+.Dd August 5, 2009
+.Os
+.Dt ELF_GETPHDRNUM 3
+.Sh NAME
+.Nm elf_getphdrnum
+.Nd return the number of program headers in an ELF file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_getphdrnum "Elf *elf" "size_t *phnum"
+.Sh DESCRIPTION
+Function
+.Fn elf_getphdrnum
+retrieves the number of ELF program headers associated with descriptor
+.Ar elf
+and stores it into the location pointed to by argument
+.Ar phnum .
+.Pp
+This routine allows applications to uniformly process both normal ELF
+objects and ELF objects that use extended numbering.
+.Pp
+.Sh RETURN VALUES
+Function
+.Fn elf_getphdrnum
+returns a zero value if successful, or -1 in case of an error.
+.Sh ERRORS
+Function
+.Fn elf_getphnum
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+lacks an ELF Executable Header.
+.It Bq Er ELF_E_HEADER
+The ELF Executable Header associated with argument
+.Ar elf
+was corrupt.
+.It Bq Er ELF_E_SECTION
+The section header at index
+.Dv SHN_UNDEF
+was corrupt.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_getshdrnum 3 ,
+.Xr elf_getshdrstrndx 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3
diff --git a/linkers/elftoolchain/libelf/elf_getphnum.3 b/linkers/elftoolchain/libelf/elf_getphnum.3
new file mode 100644
index 0000000..95c7540
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getphnum.3
@@ -0,0 +1,93 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getphnum.3 467 2009-08-05 18:18:49Z jkoshy $
+.\"
+.Dd August 5, 2009
+.Os
+.Dt ELF_GETPHNUM 3
+.Sh NAME
+.Nm elf_getphnum
+.Nd return the number of program headers in an ELF file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_getphnum "Elf *elf" "size_t *phnum"
+.Sh DESCRIPTION
+This function is deprecated.
+Please use function
+.Xr elf_getphdrnum 3
+instead.
+.Pp
+Function
+.Fn elf_getphnum
+retrieves the number of ELF program headers associated with descriptor
+.Ar elf
+and stores it into the location pointed to by argument
+.Ar phnum .
+.Pp
+This routine allows applications to uniformly process both normal ELF
+objects and ELF objects that use extended numbering.
+.Pp
+.Sh RETURN VALUES
+Function
+.Fn elf_getphnum
+returns a non-zero value if successful, or zero in case of an
+error.
+.Sh ERRORS
+Function
+.Fn elf_getphnum
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+lacks an ELF Executable Header.
+.It Bq Er ELF_E_HEADER
+The ELF Executable Header associated with argument
+.Ar elf
+was corrupt.
+.It Bq Er ELF_E_SECTION
+The section header at index
+.Dv SHN_UNDEF
+was corrupt.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_getphdrnum 3 ,
+.Xr elf_getshdrnum 3 ,
+.Xr elf_getshdrstrndx 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3
diff --git a/linkers/elftoolchain/libelf/elf_getscn.3 b/linkers/elftoolchain/libelf/elf_getscn.3
new file mode 100644
index 0000000..0afe443
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getscn.3
@@ -0,0 +1,151 @@
+.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getscn.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd October 22, 2007
+.Os
+.Dt ELF_GETSCN 3
+.Sh NAME
+.Nm elf_getscn ,
+.Nm elf_ndxscn ,
+.Nm elf_newscn ,
+.Nm elf_nextscn
+.Nd get/allocate section information for an ELF object
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf_Scn *"
+.Fn elf_getscn "Elf *elf" "size_t index"
+.Ft size_t
+.Fn elf_ndxscn "Elf_Scn *scn"
+.Ft "Elf_Scn *"
+.Fn elf_newscn "Elf *elf"
+.Ft "Elf_Scn *"
+.Fn elf_nextscn "Elf *elf" "Elf_Scn *scn"
+.Sh DESCRIPTION
+These functions are used to iterate through the sections associated
+with an ELF descriptor.
+.Pp
+Function
+.Fn elf_getscn
+will return a section descriptor for the section at index
+.Ar index
+in the object denoted by ELF descriptor
+.Ar elf .
+An error will be signalled if the specified section does not
+exist.
+.Pp
+Function
+.Fn elf_ndxscn
+returns the section table index associated with section descriptor
+.Ar scn .
+.Pp
+Function
+.Fn elf_newscn
+creates a new section and appends it to the list of sections
+associated with descriptor
+.Ar elf .
+The library will automatically increment the
+.Va e_shnum
+field of the ELF header associated with descriptor
+.Ar elf ,
+and will set the
+.Dv ELF_F_DIRTY
+flag on the returned section descriptor.
+For ELF descriptors opened for writing, the ELF library will
+automatically create an empty section at index zero
+.Dv ( SHN_UNDEF )
+on the first call to
+.Fn elf_newscn .
+.Pp
+Function
+.Fn elf_nextscn
+takes a section descriptor
+.Ar scn
+and returns a pointer to the section descriptor at the next higher
+index.
+Argument
+.Ar scn
+is allowed to be NULL, in which case this function will return a
+pointer to the section descriptor at index 1.
+If no further sections are present, function
+.Fn elf_nextscn
+will return a NULL pointer.
+.Sh RETURN VALUES
+Functions
+.Fn elf_getscn ,
+.Fn elf_newscn
+and
+.Fn elf_nextscn
+return a valid pointer to a section descriptor if successful, or
+NULL if an error occurs.
+.Pp
+Function
+.Fn elf_ndxscn
+returns a valid section table index if successful, or
+.Dv SHN_UNDEF
+if an error occurs.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar elf
+or
+.Ar scn
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar index
+exceeded the current number of sections in the ELF object.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Section descriptor
+.Ar scn
+was not associated with ELF descriptor
+.Ar elf .
+.It Bq Er ELF_E_CLASS
+Descriptor
+.Ar elf
+was of an unknown ELF class.
+.It Bq Er ELF_E_SECTION
+Argument
+.Ar elf
+specified extended section numbering in the ELF header with the section header at
+index
+.Dv SHN_UNDEF
+not being of type
+.Dv SHT_NULL .
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_flagdata 3 ,
+.Xr elf_flagscn 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getshdr 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_getshdrnum.3 b/linkers/elftoolchain/libelf/elf_getshdrnum.3
new file mode 100644
index 0000000..e2bf354
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getshdrnum.3
@@ -0,0 +1,78 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getshdrnum.3 467 2009-08-05 18:18:49Z jkoshy $
+.\"
+.Dd August 4, 2009
+.Os
+.Dt ELF_GETSHDRNUM 3
+.Sh NAME
+.Nm elf_getshdrnum
+.Nd return the number of sections in an ELF file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_getshdrnum "Elf *elf" "size_t *shnum"
+.Sh DESCRIPTION
+Function
+.Fn elf_getshdrnum
+retrieves the number of ELF sections associated with descriptor
+.Ar elf
+and stores it into the location pointed to by argument
+.Ar shnum .
+.Pp
+This routine allows applications to uniformly process both normal ELF
+objects, and ELF objects that use extended section numbering.
+.Pp
+.Sh RETURN VALUES
+Function
+.Fn elf_getshdrnum
+returns zero value if successful, or -1 in case of an error.
+.Sh ERRORS
+Function
+.Fn elf_getshdrnum
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+lacks an ELF Executable header.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_getphdrnum 3 ,
+.Xr elf_getshdrstrndx 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3
diff --git a/linkers/elftoolchain/libelf/elf_getshdrstrndx.3 b/linkers/elftoolchain/libelf/elf_getshdrstrndx.3
new file mode 100644
index 0000000..b02e715
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getshdrstrndx.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getshdrstrndx.3 467 2009-08-05 18:18:49Z jkoshy $
+.\"
+.Dd August 5, 2009
+.Os
+.Dt ELF_GETSHDRSTRNDX 3
+.Sh NAME
+.Nm elf_getshdrstrndx
+.Nd retrieve the index of the section name string table
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_getshdrstrndx "Elf *elf" "size_t *ndxptr"
+.Sh DESCRIPTION
+Function
+.Fn elf_getshdrstrndx
+retrieves the section index of the string table containing section
+names from descriptor
+.Ar elf
+and stores it into the location pointed to by argument
+.Ar ndxptr .
+.Pp
+This function allow applications to process both normal ELF
+objects and ELF objects that use extended section numbering uniformly.
+.Pp
+.Sh RETURN VALUES
+These functions return zero if successful, or -1 in case of an error.
+.Sh ERRORS
+These functions can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+lacks an ELF Executable header.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+contained a value in the reserved range of section indices.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_getphdrnum 3 ,
+.Xr elf_getshdrnum 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3
diff --git a/linkers/elftoolchain/libelf/elf_getshnum.3 b/linkers/elftoolchain/libelf/elf_getshnum.3
new file mode 100644
index 0000000..615aa71
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getshnum.3
@@ -0,0 +1,84 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getshnum.3 467 2009-08-05 18:18:49Z jkoshy $
+.\"
+.Dd August 5, 2009
+.Os
+.Dt ELF_GETSHNUM 3
+.Sh NAME
+.Nm elf_getshnum
+.Nd return the number of sections in an ELF file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_getshnum "Elf *elf" "size_t *shnum"
+.Sh DESCRIPTION
+This function is deprecated.
+Please use
+.Xr elf_getshdrnum 3
+instead.
+.Pp
+Function
+.Fn elf_getshnum
+retrieves the number of ELF sections associated with descriptor
+.Ar elf
+and stores it into the location pointed to by argument
+.Ar shnum .
+.Pp
+This routine allows applications to uniformly process both normal ELF
+objects, and ELF objects that use extended section numbering.
+.Pp
+.Sh RETURN VALUES
+Function
+.Fn elf_getshnum
+returns a non-zero value if successful, or zero in case of an
+error.
+.Sh ERRORS
+Function
+.Fn elf_getshnum
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+lacks an ELF Executable header.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_getphdrnum 3 ,
+.Xr elf_getshdrstrndx 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3
diff --git a/linkers/elftoolchain/libelf/elf_getshstrndx.3 b/linkers/elftoolchain/libelf/elf_getshstrndx.3
new file mode 100644
index 0000000..71c6f95
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_getshstrndx.3
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_getshstrndx.3 467 2009-08-05 18:18:49Z jkoshy $
+.\"
+.Dd August 5, 2009
+.Os
+.Dt ELF_GETSHSTRNDX 3
+.Sh NAME
+.Nm elf_getshstrndx ,
+.Nm elf_setshstrndx
+.Nd retrieve/update the index of the section name string table
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_getshstrndx "Elf *elf" "size_t *ndxptr"
+.Ft int
+.Fn elf_setshstrndx "Elf *elf" "size_t ndx"
+.Sh DESCRIPTION
+Function
+.Fn elf_getshstrndx
+retrieves the section index of the string table containing section
+names from descriptor
+.Ar elf
+and stores it into the location pointed to by argument
+.Ar ndxptr .
+Function
+.Fn elf_getshstrndx
+is deprecated.
+Please use
+.Xr elf_getshdrstrndx 3
+instead.
+.Pp
+Function
+.Fn elf_setshstrndx
+sets the index of the section name string table to argument
+.Ar ndx .
+.Pp
+These routines allow applications to process both normal ELF
+objects and ELF objects that use extended section numbering uniformly.
+.Pp
+.Sh RETURN VALUES
+These functions return a non-zero value if successful, or zero in case
+of an error.
+.Sh ERRORS
+These functions can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+lacks an ELF Executable header.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+contained a value in the reserved range of section indices.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_getphdrnum 3 ,
+.Xr elf_getshdrnum 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3
diff --git a/linkers/elftoolchain/libelf/elf_hash.3 b/linkers/elftoolchain/libelf/elf_hash.3
new file mode 100644
index 0000000..f099558
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_hash.3
@@ -0,0 +1,57 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_hash.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 15, 2006
+.Os
+.Dt ELF_HASH 3
+.Sh NAME
+.Nm elf_hash
+.Nd compute a hash value for a string
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "unsigned long"
+.Fn elf_hash "const char *name"
+.Sh DESCRIPTION
+Function
+.Fn elf_hash
+computes a portable hash value for the null terminated string
+pointed to by argument
+.Ar name .
+.Pp
+The hash value returned is will be identical across
+machines of different architectures.
+This allows hash tables to be built on one machine and
+correctly used on another of a different architecture.
+The hash value returned is also guaranteed
+.Em not
+to be the bit pattern of all ones (~0UL).
+.Sh IMPLEMENTATION NOTES
+The library internally uses unsigned 32 bit arithmetic to compute
+the hash value.
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_hash.c b/linkers/elftoolchain/libelf/elf_hash.c
new file mode 100644
index 0000000..12c764d
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_hash.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf_config.h"
+
+LIBELF_VCSID("$Id: elf_hash.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+/*
+ * This elf_hash function is defined by the System V ABI.
+ */
+
+unsigned long
+elf_hash(const char *name)
+{
+ unsigned long h, t;
+ const unsigned char *s;
+
+ s = (const unsigned char *) name;
+ h = t = 0;
+
+ for (; *s != '\0'; h = h & ~t) {
+ h = (h << 4) + *s++;
+ t = h & 0xF0000000UL;
+ if (t)
+ h ^= t >> 24;
+ }
+
+ return (h);
+}
diff --git a/linkers/elftoolchain/libelf/elf_kind.3 b/linkers/elftoolchain/libelf/elf_kind.3
new file mode 100644
index 0000000..a5bbf9d
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_kind.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_kind.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd June 1, 2006
+.Os
+.Dt ELF_KIND 3
+.Sh NAME
+.Nm elf_kind
+.Nd determine ELF file type
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft Elf_Kind
+.Fn elf_kind "Elf *elf"
+.Sh DESCRIPTION
+The
+.Fn elf_kind
+function identifies the kind of file associated with its argument
+.Ar elf .
+The argument
+.Ar elf
+is allowed to be NULL.
+.Sh RETURN VALUES
+The
+.Fn elf_kind
+function returns one of the following values:
+.Bl -tag -width indent
+.It Dv ELF_K_AR
+The file associated with argument
+.Ar elf
+is an archive.
+.It Dv ELF_K_ELF
+The file associated with argument
+.Ar elf
+is an ELF file.
+.It Dv ELF_K_NONE
+The argument
+.Ar elf
+was NULL, or the ELF library could not determine the type of the file
+associated with argument
+.Ar elf ,
+or an error occurred when processing.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_getident 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_kind.c b/linkers/elftoolchain/libelf/elf_kind.c
new file mode 100644
index 0000000..0b4251a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_kind.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_kind.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+Elf_Kind
+elf_kind(Elf *e)
+{
+ if (e == NULL)
+ return (ELF_K_NONE);
+ if (e->e_kind == ELF_K_AR ||
+ e->e_kind == ELF_K_ELF)
+ return (e->e_kind);
+ return (ELF_K_NONE);
+}
diff --git a/linkers/elftoolchain/libelf/elf_memory.3 b/linkers/elftoolchain/libelf/elf_memory.3
new file mode 100644
index 0000000..2f9da44
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_memory.3
@@ -0,0 +1,122 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_memory.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd June 28, 2006
+.Os
+.Dt ELF_MEMORY 3
+.Sh NAME
+.Nm elf_memory
+.Nd process an ELF or ar(1) archive mapped into memory
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf *"
+.Fn elf_memory "char *image" "size_t size"
+.Sh DESCRIPTION
+Function
+.Fn elf_memory
+is used to process an ELF file or
+.Xr ar 1
+archive whose image is present in memory.
+.Pp
+Argument
+.Ar image
+points to the start of the memory image of the file or archive.
+Argument
+.Ar size
+contains the size in bytes of the memory image.
+.Pp
+The ELF descriptor is created for reading (i.e., analogous to the
+use of
+.Xr elf_begin 3
+with a command argument value of
+.Dv ELF_C_READ Ns ).
+.Sh RETURN VALUES
+Function
+.Fn elf_memory
+returns a pointer to a new ELF descriptor if successful, or NULL if an
+error occurred.
+.Pp
+The return value may be queried for the file type using
+.Xr elf_kind 3 .
+.Sh EXAMPLES
+To read parse an elf file, use:
+.Bd -literal -offset indent
+int fd;
+void *p;
+struct stat sb;
+Elf *e;
+\&...
+if ((fd = open("./elf-file", O_RDONLY)) < 0 ||
+ fstat(fd, &sb) < 0 ||
+ (p = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t) 0)) ==
+ MAP_FAILED) {
+ ... handle system error ...
+}
+
+if ((e = elf_memory(p, sb.st_size)) == NULL) {
+ ... handle elf(3) error ...
+}
+\&... use ELF descriptor "e" here ...
+.Ed
+.Sh ERRORS
+Function
+.Fn elf_memory
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was used for argument
+.Ar image
+or the value of argument
+.Ar sz
+was zero.
+.It Bq Er ELF_E_HEADER
+The header of the ELF object contained an unsupported value in its
+.Va e_ident[EI_CLASS]
+field.
+.It Bq Er ELF_E_HEADER
+The header of the ELF object contained an unsupported value in its
+.Va e_ident[EI_DATA]
+field.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected.
+.It Bq Er ELF_E_SEQUENCE
+Function
+.Fn elf_memory
+was called before a working version was set using
+.Xr elf_version 3 .
+.It Bq Er ELF_E_VERSION
+The argument
+.Ar image
+corresponds to an ELF file with an unsupported version.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_end 3 ,
+.Xr elf_errno 3 ,
+.Xr elf_kind 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_memory.c b/linkers/elftoolchain/libelf/elf_memory.c
new file mode 100644
index 0000000..691beaf
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_memory.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <ar.h>
+#include <libelf.h>
+#include <string.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_memory.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+Elf *
+elf_memory(char *image, size_t sz)
+{
+ Elf *e;
+
+ if (LIBELF_PRIVATE(version) == EV_NONE) {
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+ return (NULL);
+ }
+
+ if (image == NULL || sz == 0) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if ((e = _libelf_allocate_elf()) == NULL)
+ return (NULL);
+
+ e->e_cmd = ELF_C_READ;
+ e->e_rawfile = image;
+ e->e_rawsize = sz;
+
+#undef LIBELF_IS_ELF
+#define LIBELF_IS_ELF(P) ((P)[EI_MAG0] == ELFMAG0 && \
+ (P)[EI_MAG1] == ELFMAG1 && (P)[EI_MAG2] == ELFMAG2 && \
+ (P)[EI_MAG3] == ELFMAG3)
+
+ if (sz > EI_NIDENT && LIBELF_IS_ELF(image)) {
+ _libelf_init_elf(e, ELF_K_ELF);
+ e->e_class = image[EI_CLASS];
+ e->e_byteorder = image[EI_DATA];
+ e->e_version = image[EI_VERSION];
+
+ if (e->e_version > EV_CURRENT) {
+ e = _libelf_release_elf(e);
+ LIBELF_SET_ERROR(VERSION, 0);
+ return (NULL);
+ }
+
+ if ((e->e_byteorder != ELFDATA2LSB && e->e_byteorder !=
+ ELFDATA2MSB) || (e->e_class != ELFCLASS32 && e->e_class !=
+ ELFCLASS64)) {
+ e = _libelf_release_elf(e);
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (NULL);
+ }
+
+ } else if (sz >= SARMAG &&
+ strncmp(image, ARMAG, (size_t) SARMAG) == 0) {
+ _libelf_init_elf(e, ELF_K_AR);
+ e = _libelf_ar_open(e);
+ } else
+ _libelf_init_elf(e, ELF_K_NONE);
+
+ return (e);
+}
diff --git a/linkers/elftoolchain/libelf/elf_next.3 b/linkers/elftoolchain/libelf/elf_next.3
new file mode 100644
index 0000000..859d06c
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_next.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_next.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd June 17, 2006
+.Os
+.Dt ELF_NEXT 3
+.Sh NAME
+.Nm elf_next
+.Nd provide sequential access to the next archive member
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft Elf_Cmd
+.Fn elf_next "Elf *elf"
+.Sh DESCRIPTION
+The
+.Fn elf_next
+function causes the ELF archive descriptor corresponding to argument
+.Ar elf
+to be adjusted to provide access to the next member in
+the archive on a subsequent call to
+.Fn elf_begin .
+.Pp
+The return value of
+.Fn elf_next
+is suitable for use in a loop invoking
+.Fn elf_begin .
+.Sh RETURN VALUES
+If successful, function
+.Fn elf_next
+returns the value
+.Dv ELF_C_READ .
+Otherwise, if argument
+.Ar elf
+was not associated with an archive, or if it was
+.Dv NULL ,
+or if any other error occurred, the value
+.Dv ELF_C_NULL
+is returned.
+.Sh EXAMPLES
+To process all the members of an archive use:
+.Bd -literal -offset indent
+Elf_Cmd cmd;
+Elf *archive, *e;
+\&...
+cmd = ELF_C_READ;
+archive = elf_begin(fd, cmd, NULL);
+while ((e = elf_begin(fd, cmd, archive)) != (Elf *) 0)
+{
+ ... process `e' here ...
+
+ cmd = elf_next(e);
+ elf_end(e);
+}
+elf_end(archive);
+.Ed
+.Sh ERRORS
+Function
+.Fn elf_next
+may fail with the following error:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not associated with a containing
+.Xr ar 1
+archive.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_end 3 ,
+.Xr elf_rand 3
diff --git a/linkers/elftoolchain/libelf/elf_next.c b/linkers/elftoolchain/libelf/elf_next.c
new file mode 100644
index 0000000..d6ca552
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_next.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <ar.h>
+#include <assert.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_next.c 1678 2011-07-28 04:36:34Z jkoshy $");
+
+Elf_Cmd
+elf_next(Elf *e)
+{
+ off_t next;
+ Elf *parent;
+
+ if (e == NULL)
+ return (ELF_C_NULL);
+
+ if ((parent = e->e_parent) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (ELF_C_NULL);
+ }
+
+ assert (parent->e_kind == ELF_K_AR);
+ assert (parent->e_cmd == ELF_C_READ);
+ assert(e->e_rawfile > parent->e_rawfile);
+
+ next = e->e_rawfile - parent->e_rawfile + e->e_rawsize;
+ next = (next + 1) & ~1; /* round up to an even boundary */
+
+ parent->e_u.e_ar.e_next = (next >= (off_t) parent->e_rawsize) ?
+ (off_t) 0 : next;
+
+ return (ELF_C_READ);
+}
diff --git a/linkers/elftoolchain/libelf/elf_phnum.c b/linkers/elftoolchain/libelf/elf_phnum.c
new file mode 100644
index 0000000..d63c490
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_phnum.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <ar.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_phnum.c 466 2009-08-04 17:17:42Z jkoshy $");
+
+static int
+_libelf_getphdrnum(Elf *e, size_t *phnum)
+{
+ void *eh;
+ int ec;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (-1);
+ }
+
+ if ((eh = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (-1);
+
+ *phnum = e->e_u.e_elf.e_nphdr;
+
+ return (0);
+}
+
+int
+elf_getphdrnum(Elf *e, size_t *phnum)
+{
+ return (_libelf_getphdrnum(e, phnum));
+}
+
+/* Deprecated API */
+int
+elf_getphnum(Elf *e, size_t *phnum)
+{
+ return (_libelf_getphdrnum(e, phnum) >= 0);
+}
diff --git a/linkers/elftoolchain/libelf/elf_rand.3 b/linkers/elftoolchain/libelf/elf_rand.3
new file mode 100644
index 0000000..e5affd6
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_rand.3
@@ -0,0 +1,118 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_rand.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd June 17, 2006
+.Os
+.Dt ELF_RAND 3
+.Sh NAME
+.Nm elf_rand
+.Nd provide sequential access to the next archive member
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft off_t
+.Fn elf_rand "Elf *archive" "off_t offset"
+.Sh DESCRIPTION
+The
+.Fn elf_rand
+function causes the ELF descriptor
+.Ar archive
+to be adjusted so that the next call to
+.Xr elf_begin 3
+will provide access to the archive member at byte offset
+.Ar offset
+in the archive.
+Argument
+.Ar offset
+is the byte offset from the start of the archive to the beginning of
+the archive header for the desired member.
+.Pp
+Archive member offsets may be retrieved using the
+.Xr elf_getarsym 3
+function.
+.Sh RETURN VALUES
+Function
+.Fn elf_rand
+returns
+.Ar offset
+if successful or zero in case of an error.
+.Sh EXAMPLES
+To process all the members of an archive use:
+.Bd -literal -offset indent
+off_t off;
+Elf *archive, *e;
+\&...
+cmd = ELF_C_READ;
+archive = elf_begin(fd, cmd, NULL);
+while ((e = elf_begin(fd, cmd, archive)) != (Elf *) 0)
+{
+ ... process `e' here ...
+ elf_end(e);
+
+ off = ...new value...;
+ if (elf_rand(archive, off) != off) {
+ ... process error ...
+ }
+}
+elf_end(archive);
+.Ed
+.Pp
+To rewind an archive, use:
+.Bd -literal -offset indent
+Elf *archive;
+\&...
+if (elf_rand(archive, SARMAG) != SARMAG) {
+ ... error ...
+}
+.Ed
+.Sh ERRORS
+Function
+.Fn elf_rand
+may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar archive
+was null.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar archive
+was not a descriptor for an
+.Xr ar 1
+archive.
+.It Bq Er ELF_E_ARCHIVE
+Argument
+.Ar offset
+did not correspond to the start of an archive member header.
+.El
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr elf 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_end 3 ,
+.Xr elf_getarsym 3 ,
+.Xr elf_next 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_rand.c b/linkers/elftoolchain/libelf/elf_rand.c
new file mode 100644
index 0000000..2e7328a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_rand.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <ar.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_rand.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+off_t
+elf_rand(Elf *ar, off_t offset)
+{
+ struct ar_hdr *arh;
+
+ if (ar == NULL || ar->e_kind != ELF_K_AR ||
+ (offset & 1) || offset < SARMAG ||
+ offset + sizeof(struct ar_hdr) >= ar->e_rawsize) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return 0;
+ }
+
+ arh = (struct ar_hdr *) (ar->e_rawfile + offset);
+
+ /* a too simple sanity check */
+ if (arh->ar_fmag[0] != '`' || arh->ar_fmag[1] != '\n') {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return 0;
+ }
+
+ ar->e_u.e_ar.e_next = offset;
+
+ return (offset);
+}
diff --git a/linkers/elftoolchain/libelf/elf_rawfile.3 b/linkers/elftoolchain/libelf/elf_rawfile.3
new file mode 100644
index 0000000..a713b42
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_rawfile.3
@@ -0,0 +1,76 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_rawfile.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd July 3, 2006
+.Os
+.Dt ELF_RAWFILE 3
+.Sh NAME
+.Nm elf_rawfile
+.Nd return uninterpreted contents of an ELF file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft char *
+.Fn elf_rawfile "Elf *elf" "size_t *sz"
+.Sh DESCRIPTION
+Function
+.Fn elf_rawfile
+returns the uninterpreted contents of the file referenced by ELF descriptor
+.Ar elf .
+.Pp
+If argument
+.Ar sz
+is non-null, the function stores the file's size in bytes
+in the location to which it points.
+A value of zero is written to this location if an error is
+encountered.
+.Sh RETURN VALUES
+Function
+.Fn elf_rawfile
+returns a valid pointer if successful or NULL if an error occurs.
+.Sh ERRORS
+Function
+.Fn elf_rawfile
+may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_SEQUENCE
+Argument
+.Ar elf
+was opened for writing and function
+.Fn elf_rawfile
+was invoked before
+.Xr elf_update 3 .
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_kind 3 ,
+.Xr elf_update 3
diff --git a/linkers/elftoolchain/libelf/elf_rawfile.c b/linkers/elftoolchain/libelf/elf_rawfile.c
new file mode 100644
index 0000000..22a9f95
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_rawfile.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_rawfile.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+char *
+elf_rawfile(Elf *e, size_t *sz)
+{
+ char *ptr;
+ size_t size;
+
+ size = e ? e->e_rawsize : 0;
+ ptr = NULL;
+
+ if (e == NULL)
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ else if ((ptr = e->e_rawfile) == NULL && e->e_cmd == ELF_C_WRITE)
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+
+ if (sz)
+ *sz = size;
+
+ return (ptr);
+}
diff --git a/linkers/elftoolchain/libelf/elf_scn.c b/linkers/elftoolchain/libelf/elf_scn.c
new file mode 100644
index 0000000..80444fd
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_scn.c
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 2006,2008-2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_scn.c 1077 2010-08-09 15:37:40Z jkoshy $");
+
+/*
+ * Load an ELF section table and create a list of Elf_Scn structures.
+ */
+int
+_libelf_load_section_headers(Elf *e, void *ehdr)
+{
+ int ec, swapbytes;
+ size_t fsz, i, shnum;
+ uint64_t shoff;
+ char *src;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+ Elf_Scn *scn;
+ int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
+
+ assert(e != NULL);
+ assert(ehdr != NULL);
+ assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0);
+
+#define CHECK_EHDR(E,EH) do { \
+ if (fsz != (EH)->e_shentsize || \
+ shoff + fsz * shnum > e->e_rawsize) { \
+ LIBELF_SET_ERROR(HEADER, 0); \
+ return (0); \
+ } \
+ } while (0)
+
+ ec = e->e_class;
+ fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
+ assert(fsz > 0);
+
+ shnum = e->e_u.e_elf.e_nscn;
+
+ if (ec == ELFCLASS32) {
+ eh32 = (Elf32_Ehdr *) ehdr;
+ shoff = (uint64_t) eh32->e_shoff;
+ CHECK_EHDR(e, eh32);
+ } else {
+ eh64 = (Elf64_Ehdr *) ehdr;
+ shoff = eh64->e_shoff;
+ CHECK_EHDR(e, eh64);
+ }
+
+ xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec);
+
+ swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder);
+ src = e->e_rawfile + shoff;
+
+ /*
+ * If the file is using extended numbering then section #0
+ * would have already been read in.
+ */
+
+ i = 0;
+ if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) {
+ assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) ==
+ STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next));
+
+ i = 1;
+ src += fsz;
+ }
+
+ for (; i < shnum; i++, src += fsz) {
+ if ((scn = _libelf_allocate_scn(e, i)) == NULL)
+ return (0);
+
+ (*xlator)((char *) &scn->s_shdr, sizeof(scn->s_shdr), src,
+ (size_t) 1, swapbytes);
+
+ if (ec == ELFCLASS32) {
+ scn->s_offset = scn->s_rawoff =
+ scn->s_shdr.s_shdr32.sh_offset;
+ scn->s_size = scn->s_shdr.s_shdr32.sh_size;
+ } else {
+ scn->s_offset = scn->s_rawoff =
+ scn->s_shdr.s_shdr64.sh_offset;
+ scn->s_size = scn->s_shdr.s_shdr64.sh_size;
+ }
+ }
+
+ e->e_flags |= LIBELF_F_SHDRS_LOADED;
+
+ return (1);
+}
+
+
+Elf_Scn *
+elf_getscn(Elf *e, size_t index)
+{
+ int ec;
+ void *ehdr;
+ Elf_Scn *s;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (NULL);
+
+ if (e->e_cmd != ELF_C_WRITE &&
+ (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
+ _libelf_load_section_headers(e, ehdr) == 0)
+ return (NULL);
+
+ STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next)
+ if (s->s_ndx == index)
+ return (s);
+
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+}
+
+size_t
+elf_ndxscn(Elf_Scn *s)
+{
+ if (s == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (SHN_UNDEF);
+ }
+ return (s->s_ndx);
+}
+
+Elf_Scn *
+elf_newscn(Elf *e)
+{
+ int ec;
+ void *ehdr;
+ Elf_Scn *scn;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
+ LIBELF_SET_ERROR(CLASS, 0);
+ return (NULL);
+ }
+
+ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (NULL);
+
+ /*
+ * The application may be asking for a new section descriptor
+ * on an ELF object opened with ELF_C_RDWR or ELF_C_READ. We
+ * need to bring in the existing section information before
+ * appending a new one to the list.
+ *
+ * Per the ELF(3) API, an application is allowed to open a
+ * file using ELF_C_READ, mess with its internal structure and
+ * use elf_update(...,ELF_C_NULL) to compute its new layout.
+ */
+ if (e->e_cmd != ELF_C_WRITE &&
+ (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
+ _libelf_load_section_headers(e, ehdr) == 0)
+ return (NULL);
+
+ if (STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) {
+ assert(e->e_u.e_elf.e_nscn == 0);
+ if ((scn = _libelf_allocate_scn(e, (size_t) SHN_UNDEF)) ==
+ NULL)
+ return (NULL);
+ e->e_u.e_elf.e_nscn++;
+ }
+
+ assert(e->e_u.e_elf.e_nscn > 0);
+
+ if ((scn = _libelf_allocate_scn(e, e->e_u.e_elf.e_nscn)) == NULL)
+ return (NULL);
+
+ e->e_u.e_elf.e_nscn++;
+
+ (void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ return (scn);
+}
+
+Elf_Scn *
+elf_nextscn(Elf *e, Elf_Scn *s)
+{
+ if (e == NULL || (e->e_kind != ELF_K_ELF) ||
+ (s && s->s_elf != e)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ return (s == NULL ? elf_getscn(e, (size_t) 1) :
+ STAILQ_NEXT(s, s_next));
+}
diff --git a/linkers/elftoolchain/libelf/elf_shnum.c b/linkers/elftoolchain/libelf/elf_shnum.c
new file mode 100644
index 0000000..515027a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_shnum.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <ar.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_shnum.c 466 2009-08-04 17:17:42Z jkoshy $");
+
+static int
+_libelf_getshdrnum(Elf *e, size_t *shnum)
+{
+ void *eh;
+ int ec;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (-1);
+ }
+
+ if ((eh = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (-1);
+
+ *shnum = e->e_u.e_elf.e_nscn;
+
+ return (0);
+}
+
+int
+elf_getshdrnum(Elf *e, size_t *shnum)
+{
+ return (_libelf_getshdrnum(e, shnum));
+}
+
+/* Deprecated API. */
+int
+elf_getshnum(Elf *e, size_t *shnum)
+{
+ return (_libelf_getshdrnum(e, shnum) >= 0);
+}
diff --git a/linkers/elftoolchain/libelf/elf_shstrndx.c b/linkers/elftoolchain/libelf/elf_shstrndx.c
new file mode 100644
index 0000000..bac14b4
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_shstrndx.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <ar.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_shstrndx.c 466 2009-08-04 17:17:42Z jkoshy $");
+
+static int
+_libelf_getshdrstrndx(Elf *e, size_t *strndx)
+{
+ void *eh;
+ int ec;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (-1);
+ }
+
+ if ((eh = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (-1);
+
+ *strndx = e->e_u.e_elf.e_strndx;
+
+ return (0);
+}
+
+int
+elf_getshdrstrndx(Elf *e, size_t *strndx)
+{
+ return (_libelf_getshdrstrndx(e, strndx));
+}
+
+int
+elf_getshstrndx(Elf *e, size_t *strndx) /* Deprecated API. */
+{
+ return (_libelf_getshdrstrndx(e, strndx) >= 0);
+}
+
+int
+elf_setshstrndx(Elf *e, size_t strndx)
+{
+ void *eh;
+ int ec;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) ||
+ ((eh = _libelf_ehdr(e, ec, 0)) == NULL)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ return (_libelf_setshstrndx(e, eh, ec, strndx));
+}
diff --git a/linkers/elftoolchain/libelf/elf_strptr.3 b/linkers/elftoolchain/libelf/elf_strptr.3
new file mode 100644
index 0000000..31e0f83
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_strptr.3
@@ -0,0 +1,116 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_strptr.3 1081 2010-08-14 02:23:48Z jkoshy $
+.\"
+.Dd December 16, 2006
+.Os
+.Dt ELF_STRPTR 3
+.Sh NAME
+.Nm elf_strptr
+.Nd retrieve a string pointer in a string table
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "char *"
+.Fn elf_strptr "Elf *elf" "size_t scndx" "size_t stroffset"
+.Sh DESCRIPTION
+Function
+.Fn elf_strptr
+allows an application to convert a string table offset to a string
+pointer, correctly translating the offset in the presence
+of multiple
+.Vt Elf_Data
+descriptors covering the contents of the section.
+.Pp
+Argument
+.Ar elf
+is a descriptor for an ELF object.
+Argument
+.Ar scndx
+is the section index for an ELF string table.
+Argument
+.Ar stroffset
+is the index of the desired string in the string
+table.
+.Sh RETURN VALUES
+Function
+.Fn elf_strptr
+returns a valid pointer on success or NULL in case an error was
+encountered.
+.Sh ERRORS
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF object.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar scndx
+was not the section index for a string table.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar stroffset
+exceeded the size of the string table.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar stroffset
+index an unallocated region of the string table.
+.It Bq Er ELF_E_DATA
+Offset
+.Ar stroffset
+indexed a region that was not covered by any Elf_Data
+descriptor.
+.It Bq Er ELF_E_DATA
+An erroneous
+.Vt Elf_Data
+descriptor was part of the section specified by argument
+.Ar scndx .
+.It Bq Er ELF_E_HEADER
+ELF descriptor
+.Ar elf
+contained an invalid section header.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected.
+.It Bq Er ELF_E_SECTION
+Section
+.Ar scndx
+contained a malformed section header.
+.It Bq Er ELF_E_SECTION
+The ELF descriptor in argument
+.Ar elf
+did not adhere to the conventions used for extended numbering.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getshdr 3 ,
+.Xr elf64_getshdr 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_rawdata 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getshdr 3
diff --git a/linkers/elftoolchain/libelf/elf_strptr.c b/linkers/elftoolchain/libelf/elf_strptr.c
new file mode 100644
index 0000000..bfa39de
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_strptr.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_strptr.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+/*
+ * Convert an ELF section#,offset pair to a string pointer.
+ */
+
+char *
+elf_strptr(Elf *e, size_t scndx, size_t offset)
+{
+ Elf_Scn *s;
+ Elf_Data *d;
+ size_t alignment, count;
+ GElf_Shdr shdr;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if ((s = elf_getscn(e, scndx)) == NULL ||
+ gelf_getshdr(s, &shdr) == NULL)
+ return (NULL);
+
+ if (shdr.sh_type != SHT_STRTAB ||
+ offset >= shdr.sh_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ d = NULL;
+ if (e->e_flags & ELF_F_LAYOUT) {
+
+ /*
+ * The application is taking responsibility for the
+ * ELF object's layout, so we can directly translate
+ * an offset to a `char *' address using the `d_off'
+ * members of Elf_Data descriptors.
+ */
+ while ((d = elf_getdata(s, d)) != NULL) {
+
+ if (d->d_buf == 0 || d->d_size == 0)
+ continue;
+
+ if (d->d_type != ELF_T_BYTE) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ if (offset >= d->d_off &&
+ offset < d->d_off + d->d_size)
+ return ((char *) d->d_buf + offset - d->d_off);
+ }
+ } else {
+ /*
+ * Otherwise, the `d_off' members are not useable and
+ * we need to compute offsets ourselves, taking into
+ * account 'holes' in coverage of the section introduced
+ * by alignment requirements.
+ */
+ count = (size_t) 0; /* cumulative count of bytes seen */
+ while ((d = elf_getdata(s, d)) != NULL && count <= offset) {
+
+ if (d->d_buf == NULL || d->d_size == 0)
+ continue;
+
+ if (d->d_type != ELF_T_BYTE) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ if ((alignment = d->d_align) > 1) {
+ if ((alignment & (alignment - 1)) != 0) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+ count = roundup2(count, alignment);
+ }
+
+ if (offset < count) {
+ /* offset starts in the 'hole' */
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (offset < count + d->d_size) {
+ if (d->d_buf != NULL)
+ return ((char *) d->d_buf +
+ offset - count);
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ count += d->d_size;
+ }
+ }
+
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+}
diff --git a/linkers/elftoolchain/libelf/elf_types.m4 b/linkers/elftoolchain/libelf/elf_types.m4
new file mode 100644
index 0000000..9e9680d
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_types.m4
@@ -0,0 +1,309 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: elf_types.m4 321 2009-03-07 16:59:14Z jkoshy $
+ */
+
+/*
+ * ELF types, defined in the "enum Elf_Type" API.
+ *
+ * The members of the list form a 2-tuple: (name, C-type-suffix).
+ * + `name' is an Elf_Type symbol without the `ELF_T_' prefix.
+ * + `C-type-suffix' is the suffix for Elf32_ and Elf64_ type names.
+ */
+
+define(`ELF_TYPE_LIST',
+ ``ADDR, Addr',
+ `BYTE, Byte',
+ `CAP, Cap',
+ `DYN, Dyn',
+ `EHDR, Ehdr',
+ `GNUHASH, -',
+ `HALF, Half',
+ `LWORD, Lword',
+ `MOVE, Move',
+ `MOVEP, MoveP',
+ `NOTE, Note',
+ `OFF, Off',
+ `PHDR, Phdr',
+ `REL, Rel',
+ `RELA, Rela',
+ `SHDR, Shdr',
+ `SWORD, Sword',
+ `SXWORD, Sxword',
+ `SYMINFO, Syminfo',
+ `SYM, Sym',
+ `VDEF, Verdef',
+ `VNEED, Verneed',
+ `WORD, Word',
+ `XWORD, Xword',
+ `NUM, _'')
+
+/*
+ * DEFINE_STRUCT(NAME,MEMBERLIST...)
+ *
+ * Map a type name to its members.
+ *
+ * Each member-list element comprises of pairs of (field name, type),
+ * in the sequence used in the file representation of `NAME'.
+ *
+ * Each member list element comprises a pair containing a field name
+ * and a basic type. Basic types include IDENT, HALF, WORD, LWORD,
+ * ADDR{32,64}, OFF{32,64}, SWORD, XWORD, SXWORD.
+ *
+ * The last element of a member list is the null element: `_,_'.
+ */
+
+define(`DEFINE_STRUCT',`define(`$1_DEF',shift($@))dnl')
+
+DEFINE_STRUCT(`Elf32_Cap',
+ ``c_tag, WORD',
+ `c_un.c_val, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Cap',
+ ``c_tag, XWORD',
+ `c_un.c_val, XWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Dyn',
+ ``d_tag, SWORD',
+ `d_un.d_ptr, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Dyn',
+ ``d_tag, SXWORD',
+ `d_un.d_ptr, XWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Ehdr',
+ ``e_ident, IDENT',
+ `e_type, HALF',
+ `e_machine, HALF',
+ `e_version, WORD',
+ `e_entry, ADDR',
+ `e_phoff, OFF',
+ `e_shoff, OFF',
+ `e_flags, WORD',
+ `e_ehsize, HALF',
+ `e_phentsize, HALF',
+ `e_phnum, HALF',
+ `e_shentsize, HALF',
+ `e_shnum, HALF',
+ `e_shstrndx, HALF',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Ehdr',
+ ``e_ident, IDENT',
+ `e_type, HALF',
+ `e_machine, HALF',
+ `e_version, WORD',
+ `e_entry, ADDR',
+ `e_phoff, OFF',
+ `e_shoff, OFF',
+ `e_flags, WORD',
+ `e_ehsize, HALF',
+ `e_phentsize, HALF',
+ `e_phnum, HALF',
+ `e_shentsize, HALF',
+ `e_shnum, HALF',
+ `e_shstrndx, HALF',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Move',
+ ``m_value, LWORD',
+ `m_info, WORD',
+ `m_poffset, WORD',
+ `m_repeat, HALF',
+ `m_stride, HALF',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Move',
+ ``m_value, LWORD',
+ `m_info, XWORD',
+ `m_poffset, XWORD',
+ `m_repeat, HALF',
+ `m_stride, HALF',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Phdr',
+ ``p_type, WORD',
+ `p_offset, OFF',
+ `p_vaddr, ADDR',
+ `p_paddr, ADDR',
+ `p_filesz, WORD',
+ `p_memsz, WORD',
+ `p_flags, WORD',
+ `p_align, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Phdr',
+ ``p_type, WORD',
+ `p_flags, WORD',
+ `p_offset, OFF',
+ `p_vaddr, ADDR',
+ `p_paddr, ADDR',
+ `p_filesz, XWORD',
+ `p_memsz, XWORD',
+ `p_align, XWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Rel',
+ ``r_offset, ADDR',
+ `r_info, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Rel',
+ ``r_offset, ADDR',
+ `r_info, XWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Rela',
+ ``r_offset, ADDR',
+ `r_info, WORD',
+ `r_addend, SWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Rela',
+ ``r_offset, ADDR',
+ `r_info, XWORD',
+ `r_addend, SXWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Shdr',
+ ``sh_name, WORD',
+ `sh_type, WORD',
+ `sh_flags, WORD',
+ `sh_addr, ADDR',
+ `sh_offset, OFF',
+ `sh_size, WORD',
+ `sh_link, WORD',
+ `sh_info, WORD',
+ `sh_addralign, WORD',
+ `sh_entsize, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Shdr',
+ ``sh_name, WORD',
+ `sh_type, WORD',
+ `sh_flags, XWORD',
+ `sh_addr, ADDR',
+ `sh_offset, OFF',
+ `sh_size, XWORD',
+ `sh_link, WORD',
+ `sh_info, WORD',
+ `sh_addralign, XWORD',
+ `sh_entsize, XWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Sym',
+ ``st_name, WORD',
+ `st_value, ADDR',
+ `st_size, WORD',
+ `st_info, BYTE',
+ `st_other, BYTE',
+ `st_shndx, HALF',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Sym',
+ ``st_name, WORD',
+ `st_info, BYTE',
+ `st_other, BYTE',
+ `st_shndx, HALF',
+ `st_value, ADDR',
+ `st_size, XWORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Syminfo',
+ ``si_boundto, HALF',
+ `si_flags, HALF',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Syminfo',
+ ``si_boundto, HALF',
+ `si_flags, HALF',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Verdaux',
+ ``vda_name, WORD',
+ `vda_next, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Verdaux',
+ ``vda_name, WORD',
+ `vda_next, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Verdef',
+ ``vd_version, HALF',
+ `vd_flags, HALF',
+ `vd_ndx, HALF',
+ `vd_cnt, HALF',
+ `vd_hash, WORD',
+ `vd_aux, WORD',
+ `vd_next, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Verdef',
+ ``vd_version, HALF',
+ `vd_flags, HALF',
+ `vd_ndx, HALF',
+ `vd_cnt, HALF',
+ `vd_hash, WORD',
+ `vd_aux, WORD',
+ `vd_next, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Verneed',
+ ``vn_version, HALF',
+ `vn_cnt, HALF',
+ `vn_file, WORD',
+ `vn_aux, WORD',
+ `vn_next, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Verneed',
+ ``vn_version, HALF',
+ `vn_cnt, HALF',
+ `vn_file, WORD',
+ `vn_aux, WORD',
+ `vn_next, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf32_Vernaux',
+ ``vna_hash, WORD',
+ `vna_flags, HALF',
+ `vna_other, HALF',
+ `vna_name, WORD',
+ `vna_next, WORD',
+ `_,_'')
+
+DEFINE_STRUCT(`Elf64_Vernaux',
+ ``vna_hash, WORD',
+ `vna_flags, HALF',
+ `vna_other, HALF',
+ `vna_name, WORD',
+ `vna_next, WORD',
+ `_,_'')
diff --git a/linkers/elftoolchain/libelf/elf_update.3 b/linkers/elftoolchain/libelf/elf_update.3
new file mode 100644
index 0000000..40a1e40
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_update.3
@@ -0,0 +1,378 @@
+.\" Copyright (c) 2006-2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_update.3 1729 2011-08-14 09:13:00Z jkoshy $
+.\"
+.Dd August 14, 2011
+.Os
+.Dt ELF_UPDATE 3
+.Sh NAME
+.Nm elf_update
+.Nd update an ELF descriptor
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft off_t
+.Fn elf_update "Elf *elf" "Elf_Cmd cmd"
+.Sh DESCRIPTION
+Function
+.Fn elf_update
+causes the library to recalculate the structure of an ELF
+object and optionally write out the image of the object
+to file.
+.Pp
+Argument
+.Ar elf
+should reference a valid ELF descriptor.
+.Pp
+Argument
+.Ar cmd
+can be one of the following values:
+.Bl -tag -width "Dv ELF_C_WRITE"
+.It Dv ELF_C_NULL
+The library will recalculate structural information flagging
+modified structures with the
+.Dv ELF_F_DIRTY
+flag, but will not write data to the underlying file image.
+.It Dv ELF_C_WRITE
+The library will recalculate structural information and will
+also write the new image to the underlying file.
+The ELF descriptor referenced by argument
+.Ar elf
+should permit the underlying ELF object to be written or updated
+(see
+.Xr elf_begin 3 ) .
+.El
+.Pp
+All pointers to
+.Vt Elf_Scn
+and
+.Vt Elf_Data
+descriptors associated with descriptor
+.Ar elf
+should be considered invalid after a call to
+.Fn elf_update .
+.Ss Specifying Object Layout
+The
+.Lb libelf
+supports two layout modes.
+.Bl -tag -width indent
+.It "Library Layout"
+If the
+.Dv ELF_F_LAYOUT
+flag is not set on the ELF descriptor, the ELF library will lay out
+the ELF object according to the following scheme:
+.Bl -tag -compact -width "Section Data"
+.It Em EHDR
+The ELF executable header will be placed at the start of the object.
+.It Em PHDR
+If the ELF descriptor contains a program header table, it will be
+placed after the Executable Header.
+.It Em Section Data
+ELF section data, if any, will be placed next, keeping each section's
+alignment requirements in mind.
+.It Em SHDR
+The ELF section header table, if any, will be placed last.
+.El
+.It "Application Controlled Layout"
+The application can take full control of the layout of the ELF object
+by setting the
+.Dv ELF_F_LAYOUT
+flag on the ELF descriptor (see
+.Xr elf_flagelf 3 ) .
+In this case the library will lay out the ELF object using
+application-supplied information as below:
+.Pp
+.Bl -tag -compact -width "Section Data"
+.It Em EHDR
+The ELF executable header will be placed at the start of the object.
+.It Em PHDR
+The ELF program header table, if any, it will be placed at the offset
+specified in the
+.Va e_phoff
+field of the ELF executable header.
+.It Em Section Data
+The data for each ELF section will be placed at the offset specified
+by the
+.Va sh_offset
+field of the section's header.
+The size of the section will be taken from the
+.Va sh_size
+field of the section header.
+.It Em SHDR
+The ELF section header table, if any, will be placed at the offset
+specified by the
+.Va e_shoff
+field of the executable header.
+.El
+.El
+.Pp
+Gaps in the coverage of the file's contents will be set to the fill value
+specified by
+.Xr elf_fill 3 .
+.Ss Application Supplied Information
+The application needs to set the following fields in the data
+structures associated with the ELF descriptor prior to calling
+.Fn elf_update .
+.Bl -tag -width indent
+.It "Executable Header"
+The fields of the ELF executable header that need to be set by the
+application are:
+.Pp
+.Bl -tag -width "e_ident[EI_OSABI]" -compact
+.It Va e_entry
+To be set to the desired entry address for executables.
+.It Va e_flags
+To be set to the desired processor specific flags.
+.It Va "e_ident[EI_DATA]"
+Must be set to one of
+.Dv ELFDATA2LSB
+or
+.Dv ELFDATA2MSB .
+.It Va "e_ident[EI_OSABI]"
+To be set to the OS ABI desired.
+For example, for
+.Fx
+executables, this field should be set to
+.Dv ELFOSABI_FREEBSD .
+.It Va e_machine
+To be set to the desired machine architecture, one of the
+.Dv EM_*
+values in the header file
+.In elfdefinitions.h .
+.It Va e_phoff
+If the application is managing the object's layout, it must
+set this field to the file offset of the ELF program header table.
+.It Va e_shoff
+If the application is managing the object's layout, it must
+set this field to the file offset of the ELF section header table.
+.It Va e_shstrndx
+To be set to the index of the string table containing
+section names.
+.It Va e_type
+To be set to the type of the ELF object, one of the
+.Dv ET_*
+values in the header file
+.In elfdefinitions.h .
+.It Va e_version
+To be set to the desired version of the ELF object.
+.El
+.It "Program Header"
+All fields of the entries in the program header table need to be
+set by the application.
+.It "Section Header"
+The fields of ELF section headers that need to be set by the
+application are:
+.Pp
+.Bl -tag -width "sh_addralign" -compact
+.It Va sh_addr
+To be set to the memory address where the section should reside.
+.It Va sh_addralign
+If the application is managing the file layout, it must set this
+field to the desired alignment for the section's contents.
+This value must be a power of two and must be at least as large as the
+largest alignment needed by any
+.Vt Elf_Data
+descriptor associated with the section.
+.It Va sh_entsize
+To be set to the size of each entry, for sections containing fixed size
+elements, or set to zero for sections without fixed size elements.
+If the application is not managing file layout, it may leave this
+field as zero for those sections whose types are known to the library.
+.It Va sh_flags
+To be set to the desired section flags.
+.It Va sh_info
+To be set as described in
+.Xr elf 5 .
+.It Va sh_link
+To be set as described in
+.Xr elf 5 .
+.It Va sh_name
+To be set to the index of the section's name in the string table
+containing section names.
+.It Va sh_offset
+If the application is managing the file layout, it must set this
+field to the file offset of the section's contents.
+.It Va sh_size
+If the application is managing the file layout, it must set this
+field to the file size of the section's contents.
+.It Va sh_type
+To be set to the type of the section.
+.El
+.It "Section Data"
+The
+.Vt Elf_Data
+descriptors associated with each section specify its contents
+(see
+.Xr elf_getdata 3 ) .
+While all the fields in these descriptors are under application
+control, the following fields influence object layout:
+.Bl -tag -width "Va d_align" -compact
+.It Va d_align
+To be set to the desired alignment, within the containing section, of
+the descriptor's data.
+.It Va d_off
+If the application is managing object layout, it must set this field
+to the file offset, within the section, at which the descriptor's data
+should be placed.
+.It Va d_size
+To be set to the size in bytes of the memory representation of the
+descriptor's data.
+.El
+.El
+.Sh RETURN VALUES
+Function
+.Fn elf_update
+returns the total size of the file image if successful, or -1 if an
+error occurred.
+.Sh ERRORS
+This function may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was null.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar cmd
+was not recognized.
+.It Bq Er ELF_E_ARGUMENT
+The argument
+.Ar elf
+was not a descriptor for an ELF object.
+.It Bq Er ELF_E_CLASS
+The
+.Va e_ident[EI_CLASS]
+field of the executable header of argument
+.Ar elf
+did not match the class of the file.
+.It Bq Er ELF_E_DATA
+An
+.Vt Elf_Data
+descriptor contained in argument
+.Ar elf
+specified an unsupported type.
+.It Bq Er ELF_E_DATA
+An
+.Vt Elf_Data
+descriptor specified an alignment that was zero or was not a power of
+two.
+.It Bq Er ELF_E_HEADER
+The ELF header in argument
+.Ar elf
+requested a different byte order from the byte order already
+associated with the file.
+.It Bq Er ELF_E_IO
+An I/O error was encountered.
+.It Bq Er ELF_E_LAYOUT
+An
+.Vt Elf_Data
+descriptor contained in argument
+.Ar elf
+specified an alignment incompatible with its containing section.
+.It Bq Er ELF_E_LAYOUT
+Argument
+.Ar elf
+contained section descriptors that overlapped in extent.
+.It Bq Er ELF_E_LAYOUT
+Argument
+.Ar elf
+contained section descriptors that were incorrectly aligned or were
+too small for their data.
+.It Bq Er ELF_E_LAYOUT
+The flag
+.Dv ELF_F_LAYOUT
+was set on the Elf descriptor and the executable header overlapped
+with the program header table.
+.It Bq Er ELF_E_LAYOUT
+The flag
+.Dv ELF_F_LAYOUT
+was set on the Elf descriptor and the program header table was placed
+at a misaligned file offset.
+.It Bq Er ELF_E_LAYOUT
+The flag
+.Dv ELF_F_LAYOUT
+was set on the Elf descriptor and the section header table overlapped
+an extent mapped by a section descriptor.
+.It Bq Er ELF_E_LAYOUT
+The
+.Dv ELF_F_LAYOUT
+flag was set on the Elf descriptor, and the
+.Va d_offset
+field in an
+.Vt Elf_Data
+descriptor contained a value that was not a multiple of the
+descriptor's specified alignment.
+.It Bq Er ELF_E_MODE
+An
+.Dv ELF_C_WRITE
+operation was requested with an ELF descriptor that was not opened for
+writing or updating.
+.It Bq Er ELF_E_SECTION
+Argument
+.Ar elf
+contained a section with an unrecognized type.
+.It Bq Er ELF_E_SECTION
+The section header at index
+.Dv SHN_UNDEF
+had an illegal section type.
+.It Bq Er ELF_E_SEQUENCE
+An
+.Dv ELF_C_WRITE
+operation was requested after a prior call to
+.Fn elf_cntl elf ELF_C_FDDONE
+disassociated the ELF descriptor
+.Ar elf
+from its underlying file.
+.It Bq Er ELF_E_VERSION
+Argument
+.Ar elf
+had an unsupported version or contained an
+.Vt Elf_Data
+descriptor with an unsupported version.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf32_getphdr 3 ,
+.Xr elf32_newehdr 3 ,
+.Xr elf32_newphdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf64_getphdr 3 ,
+.Xr elf64_newehdr 3 ,
+.Xr elf64_newphdr 3 ,
+.Xr elf_begin 3 ,
+.Xr elf_cntl 3 ,
+.Xr elf_fill 3 ,
+.Xr elf_flagehdr 3 ,
+.Xr elf_flagelf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr elf_newdata 3 ,
+.Xr elf_newscn 3 ,
+.Xr elf_rawdata 3 ,
+.Xr gelf 3 ,
+.Xr gelf_newehdr 3 ,
+.Xr gelf_newphdr 3 ,
+.Xr elf 5
diff --git a/linkers/elftoolchain/libelf/elf_update.c b/linkers/elftoolchain/libelf/elf_update.c
new file mode 100644
index 0000000..9806131
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_update.c
@@ -0,0 +1,1184 @@
+/*-
+ * Copyright (c) 2006-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_update.c 1922 2011-09-23 08:04:33Z jkoshy $");
+
+/*
+ * Layout strategy:
+ *
+ * - Case 1: ELF_F_LAYOUT is asserted
+ * In this case the application has full control over where the
+ * section header table, program header table, and section data
+ * will reside. The library only perform error checks.
+ *
+ * - Case 2: ELF_F_LAYOUT is not asserted
+ *
+ * The library will do the object layout using the following
+ * ordering:
+ * - The executable header is placed first, are required by the
+ * ELF specification.
+ * - The program header table is placed immediately following the
+ * executable header.
+ * - Section data, if any, is placed after the program header
+ * table, aligned appropriately.
+ * - The section header table, if needed, is placed last.
+ *
+ * There are two sub-cases to be taken care of:
+ *
+ * - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR
+ *
+ * In this sub-case, the underlying ELF object may already have
+ * content in it, which the application may have modified. The
+ * library will retrieve content from the existing object as
+ * needed.
+ *
+ * - Case 2b: e->e_cmd == ELF_C_WRITE
+ *
+ * The ELF object is being created afresh in this sub-case;
+ * there is no pre-existing content in the underlying ELF
+ * object.
+ */
+
+/*
+ * The types of extents in an ELF object.
+ */
+enum elf_extent {
+ ELF_EXTENT_EHDR,
+ ELF_EXTENT_PHDR,
+ ELF_EXTENT_SECTION,
+ ELF_EXTENT_SHDR
+};
+
+/*
+ * A extent descriptor, used when laying out an ELF object.
+ */
+struct _Elf_Extent {
+ SLIST_ENTRY(_Elf_Extent) ex_next;
+ uint64_t ex_start; /* Start of the region. */
+ uint64_t ex_size; /* The size of the region. */
+ enum elf_extent ex_type; /* Type of region. */
+ void *ex_desc; /* Associated descriptor. */
+};
+
+SLIST_HEAD(_Elf_Extent_List, _Elf_Extent);
+
+/*
+ * Compute the extents of a section, by looking at the data
+ * descriptors associated with it. The function returns 1
+ * if successful, or zero if an error was detected.
+ */
+static int
+_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
+{
+ int ec;
+ size_t fsz, msz;
+ Elf_Data *d;
+ Elf32_Shdr *shdr32;
+ Elf64_Shdr *shdr64;
+ uint32_t sh_type;
+ uint64_t d_align;
+ unsigned int elftype;
+ uint64_t scn_size, scn_alignment;
+ uint64_t sh_align, sh_entsize, sh_offset, sh_size;
+
+ ec = e->e_class;
+
+ shdr32 = &s->s_shdr.s_shdr32;
+ shdr64 = &s->s_shdr.s_shdr64;
+ if (ec == ELFCLASS32) {
+ sh_type = shdr32->sh_type;
+ sh_align = (uint64_t) shdr32->sh_addralign;
+ sh_entsize = (uint64_t) shdr32->sh_entsize;
+ sh_offset = (uint64_t) shdr32->sh_offset;
+ sh_size = (uint64_t) shdr32->sh_size;
+ } else {
+ sh_type = shdr64->sh_type;
+ sh_align = shdr64->sh_addralign;
+ sh_entsize = shdr64->sh_entsize;
+ sh_offset = shdr64->sh_offset;
+ sh_size = shdr64->sh_size;
+ }
+
+ assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS);
+
+ elftype = _libelf_xlate_shtype(sh_type);
+ if (elftype > ELF_T_LAST) {
+ LIBELF_SET_ERROR(SECTION, 0);
+ return (0);
+ }
+
+ if (sh_align == 0)
+ sh_align = _libelf_falign(elftype, ec);
+
+ /*
+ * Compute the section's size and alignment using the data
+ * descriptors associated with the section.
+ */
+ if (STAILQ_EMPTY(&s->s_data)) {
+ /*
+ * The section's content (if any) has not been read in
+ * yet. If section is not dirty marked dirty, we can
+ * reuse the values in the 'sh_size' and 'sh_offset'
+ * fields of the section header.
+ */
+ if ((s->s_flags & ELF_F_DIRTY) == 0) {
+ /*
+ * If the library is doing the layout, then we
+ * compute the new start offset for the
+ * section based on the current offset and the
+ * section's alignment needs.
+ *
+ * If the application is doing the layout, we
+ * can use the value in the 'sh_offset' field
+ * in the section header directly.
+ */
+ if (e->e_flags & ELF_F_LAYOUT)
+ goto updatedescriptor;
+ else
+ goto computeoffset;
+ }
+
+ /*
+ * Otherwise, we need to bring in the section's data
+ * from the underlying ELF object.
+ */
+ if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL)
+ return (0);
+ }
+
+ /*
+ * Loop through the section's data descriptors.
+ */
+ scn_size = 0L;
+ scn_alignment = 0;
+ STAILQ_FOREACH(d, &s->s_data, d_next) {
+
+ /*
+ * The data buffer's type is known.
+ */
+ if (d->d_type >= ELF_T_NUM) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (0);
+ }
+
+ /*
+ * The data buffer's version is supported.
+ */
+ if (d->d_version != e->e_version) {
+ LIBELF_SET_ERROR(VERSION, 0);
+ return (0);
+ }
+
+ /*
+ * The buffer's alignment is non-zero and a power of
+ * two.
+ */
+ if ((d_align = d->d_align) == 0 ||
+ (d_align & (d_align - 1))) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (0);
+ }
+
+ /*
+ * The buffer's size should be a multiple of the
+ * memory size of the underlying type.
+ */
+ msz = _libelf_msize(d->d_type, ec, e->e_version);
+ if (d->d_size % msz) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (0);
+ }
+
+ /*
+ * If the application is controlling layout, then the
+ * d_offset field should be compatible with the
+ * buffer's specified alignment.
+ */
+ if ((e->e_flags & ELF_F_LAYOUT) &&
+ (d->d_off & (d_align - 1))) {
+ LIBELF_SET_ERROR(LAYOUT, 0);
+ return (0);
+ }
+
+ /*
+ * Compute the section's size.
+ */
+ if (e->e_flags & ELF_F_LAYOUT) {
+ if ((uint64_t) d->d_off + d->d_size > scn_size)
+ scn_size = d->d_off + d->d_size;
+ } else {
+ scn_size = roundup2(scn_size, d->d_align);
+ d->d_off = scn_size;
+ fsz = _libelf_fsize(d->d_type, ec, d->d_version,
+ d->d_size / msz);
+ scn_size += fsz;
+ }
+
+ /*
+ * The section's alignment is the maximum alignment
+ * needed for its data buffers.
+ */
+ if (d_align > scn_alignment)
+ scn_alignment = d_align;
+ }
+
+
+ /*
+ * If the application is requesting full control over the
+ * layout of the section, check the section's specified size,
+ * offsets and alignment for sanity.
+ */
+ if (e->e_flags & ELF_F_LAYOUT) {
+ if (scn_alignment > sh_align || sh_offset % sh_align ||
+ sh_size < scn_size) {
+ LIBELF_SET_ERROR(LAYOUT, 0);
+ return (0);
+ }
+ goto updatedescriptor;
+ }
+
+ /*
+ * Otherwise, compute the values in the section header.
+ *
+ * The section alignment is the maximum alignment for any of
+ * its contained data descriptors.
+ */
+ if (scn_alignment > sh_align)
+ sh_align = scn_alignment;
+
+ /*
+ * If the section entry size is zero, try and fill in an
+ * appropriate entry size. Per the elf(5) manual page
+ * sections without fixed-size entries should have their
+ * 'sh_entsize' field set to zero.
+ */
+ if (sh_entsize == 0 &&
+ (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
+ (size_t) 1)) == 1)
+ sh_entsize = 0;
+
+ sh_size = scn_size;
+
+computeoffset:
+ /*
+ * Compute the new offset for the section based on
+ * the section's alignment needs.
+ */
+ sh_offset = roundup(rc, sh_align);
+
+ /*
+ * Update the section header.
+ */
+ if (ec == ELFCLASS32) {
+ shdr32->sh_addralign = (uint32_t) sh_align;
+ shdr32->sh_entsize = (uint32_t) sh_entsize;
+ shdr32->sh_offset = (uint32_t) sh_offset;
+ shdr32->sh_size = (uint32_t) sh_size;
+ } else {
+ shdr64->sh_addralign = sh_align;
+ shdr64->sh_entsize = sh_entsize;
+ shdr64->sh_offset = sh_offset;
+ shdr64->sh_size = sh_size;
+ }
+
+updatedescriptor:
+ /*
+ * Update the section descriptor.
+ */
+ s->s_size = sh_size;
+ s->s_offset = sh_offset;
+
+ return (1);
+}
+
+/*
+ * Free a list of extent descriptors.
+ */
+
+static void
+_libelf_release_extents(struct _Elf_Extent_List *extents)
+{
+ struct _Elf_Extent *ex;
+
+ while ((ex = SLIST_FIRST(extents)) != NULL) {
+ SLIST_REMOVE_HEAD(extents, ex_next);
+ free(ex);
+ }
+}
+
+/*
+ * Check if an extent 's' defined by [start..start+size) is free.
+ * This routine assumes that the given extent list is sorted in order
+ * of ascending extent offsets.
+ */
+
+static int
+_libelf_extent_is_unused(struct _Elf_Extent_List *extents,
+ const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt)
+{
+ uint64_t tmax, tmin;
+ struct _Elf_Extent *t, *pt;
+ const uint64_t smax = start + size;
+
+ /* First, look for overlaps with existing extents. */
+ pt = NULL;
+ SLIST_FOREACH(t, extents, ex_next) {
+ tmin = t->ex_start;
+ tmax = tmin + t->ex_size;
+
+ if (tmax <= start) {
+ /*
+ * 't' lies entirely before 's': ...| t |...| s |...
+ */
+ pt = t;
+ continue;
+ } else if (smax <= tmin) {
+ /*
+ * 's' lies entirely before 't', and after 'pt':
+ * ...| pt |...| s |...| t |...
+ */
+ assert(pt == NULL ||
+ pt->ex_start + pt->ex_size <= start);
+ break;
+ } else
+ /* 's' and 't' overlap. */
+ return (0);
+ }
+
+ if (prevt)
+ *prevt = pt;
+ return (1);
+}
+
+/*
+ * Insert an extent into the list of extents.
+ */
+
+static int
+_libelf_insert_extent(struct _Elf_Extent_List *extents, int type,
+ uint64_t start, uint64_t size, void *desc)
+{
+ struct _Elf_Extent *ex, *prevt;
+
+ assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR);
+
+ prevt = NULL;
+
+ /*
+ * If the requested range overlaps with an existing extent,
+ * signal an error.
+ */
+ if (!_libelf_extent_is_unused(extents, start, size, &prevt)) {
+ LIBELF_SET_ERROR(LAYOUT, 0);
+ return (0);
+ }
+
+ /* Allocate and fill in a new extent descriptor. */
+ if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, errno);
+ return (0);
+ }
+ ex->ex_start = start;
+ ex->ex_size = size;
+ ex->ex_desc = desc;
+ ex->ex_type = type;
+
+ /* Insert the region descriptor into the list. */
+ if (prevt)
+ SLIST_INSERT_AFTER(prevt, ex, ex_next);
+ else
+ SLIST_INSERT_HEAD(extents, ex, ex_next);
+ return (1);
+}
+
+/*
+ * Recompute section layout.
+ */
+
+static off_t
+_libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents)
+{
+ int ec;
+ Elf_Scn *s;
+ size_t sh_type;
+
+ ec = e->e_class;
+
+ /*
+ * Make a pass through sections, computing the extent of each
+ * section.
+ */
+ STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) {
+ if (ec == ELFCLASS32)
+ sh_type = s->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = s->s_shdr.s_shdr64.sh_type;
+
+ if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
+ continue;
+
+ if (_libelf_compute_section_extents(e, s, rc) == 0)
+ return ((off_t) -1);
+
+ if (s->s_size == 0)
+ continue;
+
+ if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION,
+ s->s_offset, s->s_size, s))
+ return ((off_t) -1);
+
+ if ((size_t) rc < s->s_offset + s->s_size)
+ rc = s->s_offset + s->s_size;
+ }
+
+ return (rc);
+}
+
+/*
+ * Recompute the layout of the ELF object and update the internal data
+ * structures associated with the ELF descriptor.
+ *
+ * Returns the size in bytes the ELF object would occupy in its file
+ * representation.
+ *
+ * After a successful call to this function, the following structures
+ * are updated:
+ *
+ * - The ELF header is updated.
+ * - All extents in the ELF object are sorted in order of ascending
+ * addresses. Sections have their section header table entries
+ * updated. An error is signalled if an overlap was detected among
+ * extents.
+ * - Data descriptors associated with sections are checked for valid
+ * types, offsets and alignment.
+ *
+ * After a resync_elf() successfully returns, the ELF descriptor is
+ * ready for being handed over to _libelf_write_elf().
+ */
+
+static off_t
+_libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents)
+{
+ int ec, eh_class, eh_type;
+ unsigned int eh_byteorder, eh_version;
+ size_t align, fsz;
+ size_t phnum, shnum;
+ off_t rc, phoff, shoff;
+ void *ehdr, *phdr;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+
+ rc = 0;
+
+ ec = e->e_class;
+
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ /*
+ * Prepare the EHDR.
+ */
+ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
+ return ((off_t) -1);
+
+ eh32 = ehdr;
+ eh64 = ehdr;
+
+ if (ec == ELFCLASS32) {
+ eh_byteorder = eh32->e_ident[EI_DATA];
+ eh_class = eh32->e_ident[EI_CLASS];
+ phoff = (uint64_t) eh32->e_phoff;
+ shoff = (uint64_t) eh32->e_shoff;
+ eh_type = eh32->e_type;
+ eh_version = eh32->e_version;
+ } else {
+ eh_byteorder = eh64->e_ident[EI_DATA];
+ eh_class = eh64->e_ident[EI_CLASS];
+ phoff = eh64->e_phoff;
+ shoff = eh64->e_shoff;
+ eh_type = eh64->e_type;
+ eh_version = eh64->e_version;
+ }
+
+ if (eh_version == EV_NONE)
+ eh_version = EV_CURRENT;
+
+ if (eh_version != e->e_version) { /* always EV_CURRENT */
+ LIBELF_SET_ERROR(VERSION, 0);
+ return ((off_t) -1);
+ }
+
+ if (eh_class != e->e_class) {
+ LIBELF_SET_ERROR(CLASS, 0);
+ return ((off_t) -1);
+ }
+
+ if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
+ LIBELF_SET_ERROR(HEADER, 0);
+ return ((off_t) -1);
+ }
+
+ shnum = e->e_u.e_elf.e_nscn;
+ phnum = e->e_u.e_elf.e_nphdr;
+
+ e->e_byteorder = eh_byteorder;
+
+#define INITIALIZE_EHDR(E,EC,V) do { \
+ (E)->e_ident[EI_MAG0] = ELFMAG0; \
+ (E)->e_ident[EI_MAG1] = ELFMAG1; \
+ (E)->e_ident[EI_MAG2] = ELFMAG2; \
+ (E)->e_ident[EI_MAG3] = ELFMAG3; \
+ (E)->e_ident[EI_CLASS] = (EC); \
+ (E)->e_ident[EI_VERSION] = (V); \
+ (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), \
+ (size_t) 1); \
+ (E)->e_phentsize = (phnum == 0) ? 0 : _libelf_fsize( \
+ ELF_T_PHDR, (EC), (V), (size_t) 1); \
+ (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V), \
+ (size_t) 1); \
+ } while (0)
+
+ if (ec == ELFCLASS32)
+ INITIALIZE_EHDR(eh32, ec, eh_version);
+ else
+ INITIALIZE_EHDR(eh64, ec, eh_version);
+
+ (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
+
+ rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1);
+
+ if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, rc, ehdr))
+ return ((off_t) -1);
+
+ /*
+ * Compute the layout the program header table, if one is
+ * present. The program header table needs to be aligned to a
+ * `natural' boundary.
+ */
+ if (phnum) {
+ fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
+ align = _libelf_falign(ELF_T_PHDR, ec);
+
+ if (e->e_flags & ELF_F_LAYOUT) {
+ /*
+ * Check offsets for sanity.
+ */
+ if (rc > phoff) {
+ LIBELF_SET_ERROR(LAYOUT, 0);
+ return ((off_t) -1);
+ }
+
+ if (phoff % align) {
+ LIBELF_SET_ERROR(LAYOUT, 0);
+ return ((off_t) -1);
+ }
+
+ } else
+ phoff = roundup(rc, align);
+
+ rc = phoff + fsz;
+
+ phdr = _libelf_getphdr(e, ec);
+
+ if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR, phoff,
+ fsz, phdr))
+ return ((off_t) -1);
+ } else
+ phoff = 0;
+
+ /*
+ * Compute the layout of the sections associated with the
+ * file.
+ */
+
+ if (e->e_cmd != ELF_C_WRITE &&
+ (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
+ _libelf_load_section_headers(e, ehdr) == 0)
+ return ((off_t) -1);
+
+ if ((rc = _libelf_resync_sections(e, rc, extents)) < 0)
+ return ((off_t) -1);
+
+ /*
+ * Compute the space taken up by the section header table, if
+ * one is needed.
+ *
+ * If ELF_F_LAYOUT has been asserted, the application may have
+ * placed the section header table in between existing
+ * sections, so the net size of the file need not increase due
+ * to the presence of the section header table.
+ *
+ * If the library is responsible for laying out the object,
+ * the section header table is placed after section data.
+ */
+ if (shnum) {
+ fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum);
+ align = _libelf_falign(ELF_T_SHDR, ec);
+
+ if (e->e_flags & ELF_F_LAYOUT) {
+ if (shoff % align) {
+ LIBELF_SET_ERROR(LAYOUT, 0);
+ return ((off_t) -1);
+ }
+ } else
+ shoff = roundup(rc, align);
+
+ if (shoff + fsz > (size_t) rc)
+ rc = shoff + fsz;
+
+ if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR, shoff,
+ fsz, NULL))
+ return ((off_t) -1);
+ } else
+ shoff = 0;
+
+ /*
+ * Set the fields of the Executable Header that could potentially use
+ * extended numbering.
+ */
+ _libelf_setphnum(e, ehdr, ec, phnum);
+ _libelf_setshnum(e, ehdr, ec, shnum);
+
+ /*
+ * Update the `e_phoff' and `e_shoff' fields if the library is
+ * doing the layout.
+ */
+ if ((e->e_flags & ELF_F_LAYOUT) == 0) {
+ if (ec == ELFCLASS32) {
+ eh32->e_phoff = (uint32_t) phoff;
+ eh32->e_shoff = (uint32_t) shoff;
+ } else {
+ eh64->e_phoff = (uint64_t) phoff;
+ eh64->e_shoff = (uint64_t) shoff;
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * Write out the contents of an ELF section.
+ */
+
+static size_t
+_libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex)
+{
+ int ec;
+ size_t fsz, msz, nobjects, rc;
+ uint32_t sh_type;
+ uint64_t sh_off, sh_size;
+ int elftype;
+ Elf_Scn *s;
+ Elf_Data *d, dst;
+
+ assert(ex->ex_type == ELF_EXTENT_SECTION);
+
+ s = ex->ex_desc;
+ rc = ex->ex_start;
+
+ if ((ec = e->e_class) == ELFCLASS32) {
+ sh_type = s->s_shdr.s_shdr32.sh_type;
+ sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
+ } else {
+ sh_type = s->s_shdr.s_shdr64.sh_type;
+ sh_size = s->s_shdr.s_shdr64.sh_size;
+ }
+
+ /*
+ * Ignore sections that do not allocate space in the file.
+ */
+ if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0)
+ return (rc);
+
+ elftype = _libelf_xlate_shtype(sh_type);
+ assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
+
+ sh_off = s->s_offset;
+ assert(sh_off % _libelf_falign(elftype, ec) == 0);
+
+ /*
+ * If the section has a `rawdata' descriptor, and the section
+ * contents have not been modified, use its contents directly.
+ * The `s_rawoff' member contains the offset into the original
+ * file, while `s_offset' contains its new location in the
+ * destination.
+ */
+
+ if (STAILQ_EMPTY(&s->s_data)) {
+
+ if ((d = elf_rawdata(s, NULL)) == NULL)
+ return ((off_t) -1);
+
+ STAILQ_FOREACH(d, &s->s_rawdata, d_next) {
+ if ((uint64_t) rc < sh_off + d->d_off)
+ (void) memset(nf + rc,
+ LIBELF_PRIVATE(fillchar), sh_off +
+ d->d_off - rc);
+ rc = sh_off + d->d_off;
+
+ assert(d->d_buf != NULL);
+ assert(d->d_type == ELF_T_BYTE);
+ assert(d->d_version == e->e_version);
+
+ (void) memcpy(nf + rc,
+ e->e_rawfile + s->s_rawoff + d->d_off, d->d_size);
+
+ rc += d->d_size;
+ }
+
+ return (rc);
+ }
+
+ /*
+ * Iterate over the set of data descriptors for this section.
+ * The prior call to _libelf_resync_elf() would have setup the
+ * descriptors for this step.
+ */
+
+ dst.d_version = e->e_version;
+
+ STAILQ_FOREACH(d, &s->s_data, d_next) {
+
+ msz = _libelf_msize(d->d_type, ec, e->e_version);
+
+ if ((uint64_t) rc < sh_off + d->d_off)
+ (void) memset(nf + rc,
+ LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc);
+
+ rc = sh_off + d->d_off;
+
+ assert(d->d_buf != NULL);
+ assert(d->d_version == e->e_version);
+ assert(d->d_size % msz == 0);
+
+ nobjects = d->d_size / msz;
+
+ fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects);
+
+ dst.d_buf = nf + rc;
+ dst.d_size = fsz;
+
+ if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) ==
+ NULL)
+ return ((off_t) -1);
+
+ rc += fsz;
+ }
+
+ return ((off_t) rc);
+}
+
+/*
+ * Write out an ELF Executable Header.
+ */
+
+static off_t
+_libelf_write_ehdr(Elf *e, char *nf, struct _Elf_Extent *ex)
+{
+ int ec;
+ void *ehdr;
+ size_t fsz, msz;
+ Elf_Data dst, src;
+
+ assert(ex->ex_type == ELF_EXTENT_EHDR);
+ assert(ex->ex_start == 0); /* Ehdr always comes first. */
+
+ ec = e->e_class;
+
+ ehdr = _libelf_ehdr(e, ec, 0);
+ assert(ehdr != NULL);
+
+ fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
+ msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);
+
+ (void) memset(&dst, 0, sizeof(dst));
+ (void) memset(&src, 0, sizeof(src));
+
+ src.d_buf = ehdr;
+ src.d_size = msz;
+ src.d_type = ELF_T_EHDR;
+ src.d_version = dst.d_version = e->e_version;
+
+ dst.d_buf = nf;
+ dst.d_size = fsz;
+
+ if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
+ NULL)
+ return ((off_t) -1);
+
+ return ((off_t) fsz);
+}
+
+/*
+ * Write out an ELF program header table.
+ */
+
+static off_t
+_libelf_write_phdr(Elf *e, char *nf, struct _Elf_Extent *ex)
+{
+ int ec;
+ void *ehdr;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+ Elf_Data dst, src;
+ size_t fsz, phnum;
+ uint64_t phoff;
+
+ assert(ex->ex_type == ELF_EXTENT_PHDR);
+
+ ec = e->e_class;
+ ehdr = _libelf_ehdr(e, ec, 0);
+ phnum = e->e_u.e_elf.e_nphdr;
+
+ assert(phnum > 0);
+
+ if (ec == ELFCLASS32) {
+ eh32 = (Elf32_Ehdr *) ehdr;
+ phoff = (uint64_t) eh32->e_phoff;
+ } else {
+ eh64 = (Elf64_Ehdr *) ehdr;
+ phoff = eh64->e_phoff;
+ }
+
+ assert(phoff > 0);
+ assert(ex->ex_start == phoff);
+ assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);
+
+ (void) memset(&dst, 0, sizeof(dst));
+ (void) memset(&src, 0, sizeof(src));
+
+ fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
+ assert(fsz > 0);
+
+ src.d_buf = _libelf_getphdr(e, ec);
+ src.d_version = dst.d_version = e->e_version;
+ src.d_type = ELF_T_PHDR;
+ src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,
+ e->e_version);
+
+ dst.d_size = fsz;
+ dst.d_buf = nf + ex->ex_start;
+
+ if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
+ NULL)
+ return ((off_t) -1);
+
+ return (phoff + fsz);
+}
+
+/*
+ * Write out an ELF section header table.
+ */
+
+static off_t
+_libelf_write_shdr(Elf *e, char *nf, struct _Elf_Extent *ex)
+{
+ int ec;
+ void *ehdr;
+ Elf_Scn *scn;
+ uint64_t shoff;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+ size_t fsz, nscn;
+ Elf_Data dst, src;
+
+ assert(ex->ex_type == ELF_EXTENT_SHDR);
+
+ ec = e->e_class;
+ ehdr = _libelf_ehdr(e, ec, 0);
+ nscn = e->e_u.e_elf.e_nscn;
+
+ if (ec == ELFCLASS32) {
+ eh32 = (Elf32_Ehdr *) ehdr;
+ shoff = (uint64_t) eh32->e_shoff;
+ } else {
+ eh64 = (Elf64_Ehdr *) ehdr;
+ shoff = eh64->e_shoff;
+ }
+
+ assert(nscn > 0);
+ assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0);
+ assert(ex->ex_start == shoff);
+
+ (void) memset(&dst, 0, sizeof(dst));
+ (void) memset(&src, 0, sizeof(src));
+
+ src.d_type = ELF_T_SHDR;
+ src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);
+ src.d_version = dst.d_version = e->e_version;
+
+ fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
+
+ STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) {
+ if (ec == ELFCLASS32)
+ src.d_buf = &scn->s_shdr.s_shdr32;
+ else
+ src.d_buf = &scn->s_shdr.s_shdr64;
+
+ dst.d_size = fsz;
+ dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz;
+
+ if (_libelf_xlate(&dst, &src, e->e_byteorder, ec,
+ ELF_TOFILE) == NULL)
+ return ((off_t) -1);
+ }
+
+ return (ex->ex_start + nscn * fsz);
+}
+
+/*
+ * Write out the file image.
+ *
+ * The original file could have been mapped in with an ELF_C_RDWR
+ * command and the application could have added new content or
+ * re-arranged its sections before calling elf_update(). Consequently
+ * its not safe to work `in place' on the original file. So we
+ * malloc() the required space for the updated ELF object and build
+ * the object there and write it out to the underlying file at the
+ * end. Note that the application may have opened the underlying file
+ * in ELF_C_RDWR and only retrieved/modified a few sections. We take
+ * care to avoid translating file sections unnecessarily.
+ *
+ * Gaps in the coverage of the file by the file's sections will be
+ * filled with the fill character set by elf_fill(3).
+ */
+
+static off_t
+_libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
+{
+ off_t nrc, rc;
+ char *newfile;
+ Elf_Scn *scn, *tscn;
+ struct _Elf_Extent *ex;
+
+ assert(e->e_kind == ELF_K_ELF);
+ assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE);
+ assert(e->e_fd >= 0);
+
+ if ((newfile = malloc((size_t) newsize)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, errno);
+ return ((off_t) -1);
+ }
+
+ nrc = rc = 0;
+ SLIST_FOREACH(ex, extents, ex_next) {
+
+ /* Fill inter-extent gaps. */
+ if (ex->ex_start > (size_t) rc)
+ (void) memset(newfile + rc, LIBELF_PRIVATE(fillchar),
+ ex->ex_start - rc);
+
+ switch (ex->ex_type) {
+ case ELF_EXTENT_EHDR:
+ if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0)
+ goto error;
+ break;
+
+ case ELF_EXTENT_PHDR:
+ if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0)
+ goto error;
+ break;
+
+ case ELF_EXTENT_SECTION:
+ if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0)
+ goto error;
+ break;
+
+ case ELF_EXTENT_SHDR:
+ if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0)
+ goto error;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ assert(ex->ex_start + ex->ex_size == (size_t) nrc);
+ assert(rc < nrc);
+
+ rc = nrc;
+ }
+
+ assert(rc == newsize);
+
+ /*
+ * For regular files, throw away existing file content and
+ * unmap any existing mappings.
+ */
+ if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0) {
+ if (ftruncate(e->e_fd, (off_t) 0) < 0 ||
+ lseek(e->e_fd, (off_t) 0, SEEK_SET)) {
+ LIBELF_SET_ERROR(IO, errno);
+ goto error;
+ }
+ if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
+ assert(e->e_rawfile != NULL);
+ assert(e->e_cmd == ELF_C_RDWR);
+ if (munmap(e->e_rawfile, e->e_rawsize) < 0) {
+ LIBELF_SET_ERROR(IO, errno);
+ goto error;
+ }
+ }
+ }
+
+ /*
+ * Write out the new contents.
+ */
+ if (write(e->e_fd, newfile, (size_t) newsize) != newsize) {
+ LIBELF_SET_ERROR(IO, errno);
+ goto error;
+ }
+
+ /*
+ * For files opened in ELF_C_RDWR mode, set up the new 'raw'
+ * contents.
+ */
+ if (e->e_cmd == ELF_C_RDWR) {
+ assert(e->e_rawfile != NULL);
+ if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
+ if ((e->e_rawfile = mmap(NULL, (size_t) newsize,
+ PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) ==
+ MAP_FAILED) {
+ LIBELF_SET_ERROR(IO, errno);
+ goto error;
+ }
+ } else if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) {
+ free(e->e_rawfile);
+ e->e_rawfile = newfile;
+ newfile = NULL;
+ }
+
+ /* Record the new size of the file. */
+ e->e_rawsize = newsize;
+ } else {
+ /* File opened in ELF_C_WRITE mode. */
+ assert(e->e_rawfile == NULL);
+ }
+
+ /*
+ * Reset flags, remove existing section descriptors and
+ * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
+ * and elf_getscn() will function correctly.
+ */
+
+ e->e_flags &= ~ELF_F_DIRTY;
+
+ STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)
+ _libelf_release_scn(scn);
+
+ if (e->e_class == ELFCLASS32) {
+ free(e->e_u.e_elf.e_ehdr.e_ehdr32);
+ if (e->e_u.e_elf.e_phdr.e_phdr32)
+ free(e->e_u.e_elf.e_phdr.e_phdr32);
+
+ e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
+ e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
+ } else {
+ free(e->e_u.e_elf.e_ehdr.e_ehdr64);
+ if (e->e_u.e_elf.e_phdr.e_phdr64)
+ free(e->e_u.e_elf.e_phdr.e_phdr64);
+
+ e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
+ e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
+ }
+
+ /* Free the temporary buffer. */
+ if (newfile)
+ free(newfile);
+
+ return (rc);
+
+ error:
+ free(newfile);
+
+ return ((off_t) -1);
+}
+
+/*
+ * Update an ELF object.
+ */
+
+off_t
+elf_update(Elf *e, Elf_Cmd c)
+{
+ int ec;
+ off_t rc;
+ struct _Elf_Extent_List extents;
+
+ rc = (off_t) -1;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF ||
+ (c != ELF_C_NULL && c != ELF_C_WRITE)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (rc);
+ }
+
+ if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
+ LIBELF_SET_ERROR(CLASS, 0);
+ return (rc);
+ }
+
+ if (e->e_version == EV_NONE)
+ e->e_version = EV_CURRENT;
+
+ if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
+ LIBELF_SET_ERROR(MODE, 0);
+ return (rc);
+ }
+
+ SLIST_INIT(&extents);
+
+ if ((rc = _libelf_resync_elf(e, &extents)) < 0)
+ goto done;
+
+ if (c == ELF_C_NULL)
+ goto done;
+
+ if (e->e_fd < 0) {
+ rc = (off_t) -1;
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+ goto done;
+ }
+
+ return (_libelf_write_elf(e, rc, &extents));
+
+done:
+ _libelf_release_extents(&extents);
+ return (rc);
+}
diff --git a/linkers/elftoolchain/libelf/elf_version.3 b/linkers/elftoolchain/libelf/elf_version.3
new file mode 100644
index 0000000..b09fb47
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_version.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: elf_version.3 2123 2011-11-09 15:40:09Z jkoshy $
+.\"
+.Dd November 9, 2011
+.Os
+.Dt ELF_VERSION 3
+.Sh NAME
+.Nm elf_version
+.Nd retrieve or set ELF library operating version
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft unsigned int
+.Fn elf_version "unsigned int version"
+.Sh DESCRIPTION
+The
+.Fn elf_version
+function is used to query the current operating version of the ELF
+library, and to inform the ELF library about the application's desired
+operating version.
+.Pp
+If the argument
+.Ar version
+is
+.Dv EV_NONE ,
+the
+.Fn elf_version
+function returns the currently configured operating version for the
+ELF library.
+.Pp
+If the argument
+.Ar version
+is not
+.Dv EV_NONE ,
+and if argument
+.Ar version
+is supported by the ELF library, function
+.Fn elf_version
+sets the library's operating version to
+.Ar version ,
+and returns the previous value of the operating version.
+If argument
+.Ar version
+cannot be supported, then the
+.Fn elf_version
+function returns
+.Dv EV_NONE .
+.Sh RETURN VALUES
+The
+.Fn elf_version
+function returns the currently configured ELF library version, or
+.Dv EV_NONE
+if an unsupported version is requested.
+.Sh EXAMPLES
+An application program would inform the ELF library about its desired
+operating version and check for an error using the following code
+snippet:
+.Bd -literal -offset indent
+if (elf_version(EV_CURRENT) == EV_NONE)
+ err(EXIT_FAILURE, "ELF library too old");
+.Ed
+.Sh ERRORS
+Function
+.Fn elf_version
+may fail with the following error:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er "ELF_E_VERSION"
+An unsupported library version number was requested.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/elf_version.c b/linkers/elftoolchain/libelf/elf_version.c
new file mode 100644
index 0000000..48950f4
--- /dev/null
+++ b/linkers/elftoolchain/libelf/elf_version.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: elf_version.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+unsigned int
+elf_version(unsigned int v)
+{
+ unsigned int old;
+
+ if ((old = LIBELF_PRIVATE(version)) == EV_NONE)
+ old = EV_CURRENT;
+
+ if (v == EV_NONE)
+ return old;
+ if (v > EV_CURRENT) {
+ LIBELF_SET_ERROR(VERSION, 0);
+ return EV_NONE;
+ }
+
+ LIBELF_PRIVATE(version) = v;
+ return (old);
+}
diff --git a/linkers/elftoolchain/libelf/gelf.3 b/linkers/elftoolchain/libelf/gelf.3
new file mode 100644
index 0000000..a5d68ce
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf.3
@@ -0,0 +1,201 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd September 1, 2006
+.Os
+.Dt GELF 3
+.Sh NAME
+.Nm GElf
+.Nd class-independent API for ELF manipulation
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Sh DESCRIPTION
+This manual page describes a class independent API for manipulating
+ELF objects.
+This API allows an application to operate on ELF descriptors without
+needing to the know the ELF class of the descriptor.
+.Pp
+The GElf API may be used alongside the ELF API without restriction.
+.Ss GElf Data Structures
+The GElf API defines the following class-independent data structures:
+.Bl -tag -width GElf_Sxword
+.It Vt GElf_Addr
+A representation of ELF addresses.
+.It Vt GElf_Dyn
+A class-independent representation of ELF
+.Sy .dynamic
+section entries.
+.It Vt GElf_Ehdr
+A class-independent representation of an ELF Executable Header.
+.It Vt GElf_Half
+An unsigned 16 bit quantity.
+.It Vt GElf_Off
+A class-independent representation of a ELF offset.
+.It Vt GElf_Phdr
+A class-independent representation of an ELF Program Header Table
+entry.
+.It Vt GElf_Rel
+A class-independent representation of an ELF relocation entry.
+.It Vt GElf_Rela
+A class-independent representation of an ELF relocation entry with
+addend.
+.It Vt GElf_Shdr
+A class-independent representation of an ELF Section Header Table
+entry.
+.It Vt GElf_Sword
+A signed 32 bit quantity.
+.It Vt GElf_Sxword
+A signed 64 bit quantity.
+.It Vt GElf_Sym
+A class-independent representation of an ELF symbol table entry.
+.It Vt GElf_Word
+An unsigned 32 bit quantity.
+.It Vt GElf_Xword
+An unsigned 64 bit quantity.
+.El
+.Pp
+These data structures are sized to be compatible with the
+corresponding 64 bit ELF structures, and have the same internal
+structure as their 64 bit class-dependent counterparts.
+Class-dependent ELF structures are described in
+.Xr elf 5 .
+.Ss GElf Programming Model
+GElf functions always return a
+.Em copy
+of the underlying (class-dependent) ELF data structure.
+The programming model with GElf is as follows:
+.Bl -enum
+.It
+An application will retrieve data from an ELF descriptor using a
+.Fn gelf_get_*
+function.
+This will copy out data into a private
+.Vt GElf_*
+data structure.
+.It
+The application will work with its private copy of the GElf
+structure.
+.It
+Once done, the application copies the new values back to the
+underlying ELF data structure using the
+.Fn gelf_update_*
+functions.
+.It
+The application will then use the
+.Fn elf_flag*
+APIs to indicate to the ELF library that an ELF data structure is dirty.
+.El
+.Pp
+When updating an underlying 32 bit ELF data structure, the GElf
+routines will signal an error if a GElf value is out of range
+for the underlying ELF data type.
+.Ss Namespace use
+The GElf interface uses the following symbols:
+.Bl -tag
+.It GElf_*
+Class-independent data types.
+.It gelf_*
+For functions defined in the API set.
+.El
+.Ss GElf Programming APIs
+This section provides an overview of the GElf programming APIs.
+Further information is provided in the manual page of each function
+listed here.
+.Bl -tag
+.It "Allocating ELF Data Structures"
+.Bl -tag -compact
+.It Fn gelf_newehdr
+Allocate a new ELF Executable Header.
+.It Fn gelf_newphdr
+Allocate a new ELF Program Header Table.
+.El
+.It "Data Translation"
+.Bl -tag -compact
+.It Fn gelf_xlatetof
+Translate the native representation of an ELF data structure to its
+file representation.
+.It Fn gelf_xlatetom
+Translate from the file representation of an ELF data structure to a
+native representation.
+.El
+.It "Retrieving ELF Data"
+.Bl -tag -compact
+.It Fn gelf_getdyn
+Retrieve an ELF
+.Sy .dynamic
+table entry.
+.It Fn gelf_getehdr
+Retrieve an ELF Executable Header from the underlying ELF descriptor.
+.It Fn gelf_getphdr
+Retrieve an ELF Program Header Table entry from the underlying ELF descriptor.
+.It Fn gelf_getrel
+Retrieve an ELF relocation entry.
+.It Fn gelf_getrela
+Retrieve an ELF relocation entry with addend.
+.It Fn gelf_getshdr
+Retrieve an ELF Section Header Table entry from the underlying ELF descriptor.
+.It Fn gelf_getsym
+Retrieve an ELF symbol table entry.
+.El
+.It Queries
+.Bl -tag -compact
+.It Fn gelf_checksum
+Retrieves the ELF checksum for an ELF descriptor.
+.It Fn gelf_fsize
+Retrieves the size of the file representation of an ELF type.
+.It Fn gelf_getclass
+Retrieves the ELF class of an ELF descriptor.
+.El
+.It "Updating ELF Data"
+.Bl -tag -compact -width ".Fn gelf_update_shdr"
+.It Fn gelf_update_dyn
+Copy back an ELF
+.Sy .dynamic
+Table entry.
+.It Fn gelf_update_phdr
+Copy back an ELF Program Header Table entry.
+.It Fn gelf_update_rel
+Copy back an ELF relocation entry.
+.It Fn gelf_update_rela
+Copy back an ELF relocation with addend entry.
+.It Fn gelf_update_shdr
+Copy back an ELF Section Header Table entry.
+.It Fn gelf_update_sym
+Copy back an ELF symbol table entry.
+.El
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf 5
+.Sh HISTORY
+The GELF(3) API first appeared in System V Release 4.
+This implementation of the API first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+The GElf API was implemented by
+.An "Joseph Koshy"
+.Aq jkoshy@FreeBSD.org .
diff --git a/linkers/elftoolchain/libelf/gelf.h b/linkers/elftoolchain/libelf/gelf.h
new file mode 100644
index 0000000..0a7dc24
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf.h
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: gelf.h 1168 2010-09-04 01:03:25Z jkoshy $
+ */
+
+#ifndef _GELF_H_
+#define _GELF_H_
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+typedef Elf64_Addr GElf_Addr; /* Addresses */
+typedef Elf64_Half GElf_Half; /* Half words (16 bit) */
+typedef Elf64_Off GElf_Off; /* Offsets */
+typedef Elf64_Sword GElf_Sword; /* Signed words (32 bit) */
+typedef Elf64_Sxword GElf_Sxword; /* Signed long words (64 bit) */
+typedef Elf64_Word GElf_Word; /* Unsigned words (32 bit) */
+typedef Elf64_Xword GElf_Xword; /* Unsigned long words (64 bit) */
+
+typedef Elf64_Dyn GElf_Dyn; /* ".dynamic" section entries */
+typedef Elf64_Ehdr GElf_Ehdr; /* ELF header */
+typedef Elf64_Phdr GElf_Phdr; /* Program header */
+typedef Elf64_Shdr GElf_Shdr; /* Section header */
+typedef Elf64_Sym GElf_Sym; /* Symbol table entries */
+typedef Elf64_Rel GElf_Rel; /* Relocation entries */
+typedef Elf64_Rela GElf_Rela; /* Relocation entries with addend */
+
+typedef Elf64_Cap GElf_Cap; /* SW/HW capabilities */
+typedef Elf64_Move GElf_Move; /* Move entries */
+typedef Elf64_Syminfo GElf_Syminfo; /* Symbol information */
+
+#define GELF_M_INFO ELF64_M_INFO
+#define GELF_M_SIZE ELF64_M_SIZE
+#define GELF_M_SYM ELF64_M_SYM
+
+#define GELF_R_INFO ELF64_R_INFO
+#define GELF_R_SYM ELF64_R_SYM
+#define GELF_R_TYPE ELF64_R_TYPE
+#define GELF_R_TYPE_DATA ELF64_R_TYPE_DATA
+#define GELF_R_TYPE_ID ELF64_R_TYPE_ID
+#define GELF_R_TYPE_INFO ELF64_R_TYPE_INFO
+
+#define GELF_ST_BIND ELF64_ST_BIND
+#define GELF_ST_INFO ELF64_ST_INFO
+#define GELF_ST_TYPE ELF64_ST_TYPE
+#define GELF_ST_VISIBILITY ELF64_ST_VISIBILITY
+
+__BEGIN_DECLS
+long gelf_checksum(Elf *_elf);
+size_t gelf_fsize(Elf *_elf, Elf_Type _type, size_t _count,
+ unsigned int _version);
+int gelf_getclass(Elf *_elf);
+GElf_Dyn *gelf_getdyn(Elf_Data *_data, int _index, GElf_Dyn *_dst);
+GElf_Ehdr *gelf_getehdr(Elf *_elf, GElf_Ehdr *_dst);
+GElf_Phdr *gelf_getphdr(Elf *_elf, int _index, GElf_Phdr *_dst);
+GElf_Rel *gelf_getrel(Elf_Data *_src, int _index, GElf_Rel *_dst);
+GElf_Rela *gelf_getrela(Elf_Data *_src, int _index, GElf_Rela *_dst);
+GElf_Shdr *gelf_getshdr(Elf_Scn *_scn, GElf_Shdr *_dst);
+GElf_Sym *gelf_getsym(Elf_Data *_src, int _index, GElf_Sym *_dst);
+GElf_Sym *gelf_getsymshndx(Elf_Data *_src, Elf_Data *_shindexsrc,
+ int _index, GElf_Sym *_dst, Elf32_Word *_shindexdst);
+void * gelf_newehdr(Elf *_elf, int _class);
+void * gelf_newphdr(Elf *_elf, size_t _phnum);
+int gelf_update_dyn(Elf_Data *_dst, int _index, GElf_Dyn *_src);
+int gelf_update_ehdr(Elf *_elf, GElf_Ehdr *_src);
+int gelf_update_phdr(Elf *_elf, int _index, GElf_Phdr *_src);
+int gelf_update_rel(Elf_Data *_dst, int _index, GElf_Rel *_src);
+int gelf_update_rela(Elf_Data *_dst, int _index, GElf_Rela *_src);
+int gelf_update_shdr(Elf_Scn *_dst, GElf_Shdr *_src);
+int gelf_update_sym(Elf_Data *_dst, int _index, GElf_Sym *_src);
+int gelf_update_symshndx(Elf_Data *_symdst, Elf_Data *_shindexdst,
+ int _index, GElf_Sym *_symsrc, Elf32_Word _shindexsrc);
+Elf_Data *gelf_xlatetof(Elf *_elf, Elf_Data *_dst, const Elf_Data *_src, unsigned int _encode);
+Elf_Data *gelf_xlatetom(Elf *_elf, Elf_Data *_dst, const Elf_Data *_src, unsigned int _encode);
+
+GElf_Cap *gelf_getcap(Elf_Data *_data, int _index, GElf_Cap *_cap);
+GElf_Move *gelf_getmove(Elf_Data *_src, int _index, GElf_Move *_dst);
+GElf_Syminfo *gelf_getsyminfo(Elf_Data *_src, int _index, GElf_Syminfo *_dst);
+int gelf_update_cap(Elf_Data *_dst, int _index, GElf_Cap *_src);
+int gelf_update_move(Elf_Data *_dst, int _index, GElf_Move *_src);
+int gelf_update_syminfo(Elf_Data *_dst, int _index, GElf_Syminfo *_src);
+__END_DECLS
+
+#endif /* _GELF_H_ */
diff --git a/linkers/elftoolchain/libelf/gelf_cap.c b/linkers/elftoolchain/libelf/gelf_cap.c
new file mode 100644
index 0000000..af0b388
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_cap.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_cap.c 1166 2010-09-04 00:54:36Z jkoshy $");
+
+GElf_Cap *
+gelf_getcap(Elf_Data *d, int ndx, GElf_Cap *dst)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Cap *cap32;
+ Elf64_Cap *cap64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dst == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_CAP) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_CAP, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+
+ cap32 = (Elf32_Cap *) d->d_buf + ndx;
+
+ dst->c_tag = cap32->c_tag;
+ dst->c_un.c_val = (Elf64_Xword) cap32->c_un.c_val;
+
+ } else {
+
+ cap64 = (Elf64_Cap *) d->d_buf + ndx;
+
+ *dst = *cap64;
+ }
+
+ return (dst);
+}
+
+int
+gelf_update_cap(Elf_Data *d, int ndx, GElf_Cap *gc)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Cap *cap32;
+ Elf64_Cap *cap64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || gc == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_CAP) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_CAP, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32) {
+ cap32 = (Elf32_Cap *) d->d_buf + ndx;
+
+ LIBELF_COPY_U32(cap32, gc, c_tag);
+ LIBELF_COPY_U32(cap32, gc, c_un.c_val);
+ } else {
+ cap64 = (Elf64_Cap *) d->d_buf + ndx;
+
+ *cap64 = *gc;
+ }
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_checksum.3 b/linkers/elftoolchain/libelf/gelf_checksum.3
new file mode 100644
index 0000000..e5f845f
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_checksum.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_checksum.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_CHECKSUM 3
+.Sh NAME
+.Nm elf32_checksum ,
+.Nm elf64_checksum ,
+.Nm gelf_checksum
+.Nd return the checksum of an ELF object
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft long
+.Fn elf32_checksum "Elf *elf"
+.Ft long
+.Fn elf64_checksum "Elf *elf"
+.In gelf.h
+.Ft long
+.Fn gelf_checksum "Elf *elf"
+.Sh DESCRIPTION
+These functions return a simple checksum of the ELF object described
+by their argument
+.Ar elf .
+The checksum is computed in way that allows its value to remain
+unchanged in presence of modifications to the ELF object by utilities
+like
+.Xr strip 1 .
+.Pp
+Function
+.Fn elf32_checksum
+returns a checksum for an ELF descriptor
+.Ar elf
+of class
+.Dv ELFCLASS32 .
+.Pp
+Function
+.Fn elf64_checksum
+returns a checksum for an ELF descriptor
+.Ar elf
+of class
+.Dv ELFCLASS64 .
+.Pp
+Function
+.Fn gelf_checksum
+provides a class-independent way retrieving the checksum
+for ELF object
+.Ar elf .
+.Sh RETURN VALUES
+These functions return the checksum of the ELF object, or zero in case
+an error was encountered.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+The ELF descriptor
+.Ar elf
+was not opened for reading or updating.
+.It Bq Er ELF_E_CLASS
+For functions
+.Fn elf32_checksum
+and
+.Fn elf64_checksum ,
+ELF descriptor
+.Ar elf
+did not match the class of the called function.
+.It Bq Er ELF_E_HEADER
+The ELF object specified by argument
+.Ar elf
+had a malformed executable header.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected during processing.
+.It Bq Er ELF_E_SECTION
+The ELF object specified by argument
+.Ar elf
+contained a section with a malformed section header.
+.It Bq Er ELF_E_VERSION
+The ELF object was of an unsupported version.
+.El
+.Sh SEE ALSO
+.Xr strip 1 ,
+.Xr elf 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_checksum.c b/linkers/elftoolchain/libelf/gelf_checksum.c
new file mode 100644
index 0000000..30fbb97
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_checksum.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <gelf.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_checksum.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+long
+elf32_checksum(Elf *e)
+{
+ return (_libelf_checksum(e, ELFCLASS32));
+}
+
+long
+elf64_checksum(Elf *e)
+{
+ return (_libelf_checksum(e, ELFCLASS64));
+}
+
+long
+gelf_checksum(Elf *e)
+{
+ int ec;
+ if (e == NULL ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0L);
+ }
+ return (_libelf_checksum(e, ec));
+}
diff --git a/linkers/elftoolchain/libelf/gelf_dyn.c b/linkers/elftoolchain/libelf/gelf_dyn.c
new file mode 100644
index 0000000..6a2885c
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_dyn.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_dyn.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+GElf_Dyn *
+gelf_getdyn(Elf_Data *d, int ndx, GElf_Dyn *dst)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Dyn *dyn32;
+ Elf64_Dyn *dyn64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dst == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_DYN) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_DYN, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+ dyn32 = (Elf32_Dyn *) d->d_buf + ndx;
+
+ dst->d_tag = dyn32->d_tag;
+ dst->d_un.d_val = (Elf64_Xword) dyn32->d_un.d_val;
+
+ } else {
+
+ dyn64 = (Elf64_Dyn *) d->d_buf + ndx;
+
+ *dst = *dyn64;
+ }
+
+ return (dst);
+}
+
+int
+gelf_update_dyn(Elf_Data *d, int ndx, GElf_Dyn *ds)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Dyn *dyn32;
+ Elf64_Dyn *dyn64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || ds == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_DYN) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_DYN, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32) {
+ dyn32 = (Elf32_Dyn *) d->d_buf + ndx;
+
+ LIBELF_COPY_S32(dyn32, ds, d_tag);
+ LIBELF_COPY_U32(dyn32, ds, d_un.d_val);
+ } else {
+ dyn64 = (Elf64_Dyn *) d->d_buf + ndx;
+
+ *dyn64 = *ds;
+ }
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_ehdr.c b/linkers/elftoolchain/libelf/gelf_ehdr.c
new file mode 100644
index 0000000..37ccce8
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_ehdr.c
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <string.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_ehdr.c 1678 2011-07-28 04:36:34Z jkoshy $");
+
+Elf32_Ehdr *
+elf32_getehdr(Elf *e)
+{
+ return (_libelf_ehdr(e, ELFCLASS32, 0));
+}
+
+Elf64_Ehdr *
+elf64_getehdr(Elf *e)
+{
+ return (_libelf_ehdr(e, ELFCLASS64, 0));
+}
+
+GElf_Ehdr *
+gelf_getehdr(Elf *e, GElf_Ehdr *d)
+{
+ int ec;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+
+ if (d == NULL || e == NULL ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+ if ((eh32 = _libelf_ehdr(e, ELFCLASS32, 0)) == NULL)
+ return (NULL);
+
+ (void) memcpy(d->e_ident, eh32->e_ident,
+ sizeof(eh32->e_ident));
+ d->e_type = eh32->e_type;
+ d->e_machine = eh32->e_machine;
+ d->e_version = eh32->e_version;
+ d->e_entry = eh32->e_entry;
+ d->e_phoff = eh32->e_phoff;
+ d->e_shoff = eh32->e_shoff;
+ d->e_flags = eh32->e_flags;
+ d->e_ehsize = eh32->e_ehsize;
+ d->e_phentsize = eh32->e_phentsize;
+ d->e_phnum = eh32->e_phnum;
+ d->e_shentsize = eh32->e_shentsize;
+ d->e_shnum = eh32->e_shnum;
+ d->e_shstrndx = eh32->e_shstrndx;
+
+ return (d);
+ }
+
+ assert(ec == ELFCLASS64);
+
+ if ((eh64 = _libelf_ehdr(e, ELFCLASS64, 0)) == NULL)
+ return (NULL);
+ *d = *eh64;
+
+ return (d);
+}
+
+Elf32_Ehdr *
+elf32_newehdr(Elf *e)
+{
+ return (_libelf_ehdr(e, ELFCLASS32, 1));
+}
+
+Elf64_Ehdr *
+elf64_newehdr(Elf *e)
+{
+ return (_libelf_ehdr(e, ELFCLASS64, 1));
+}
+
+void *
+gelf_newehdr(Elf *e, int ec)
+{
+ if (e != NULL &&
+ (ec == ELFCLASS32 || ec == ELFCLASS64))
+ return (_libelf_ehdr(e, ec, 1));
+
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+}
+
+int
+gelf_update_ehdr(Elf *e, GElf_Ehdr *s)
+{
+ int ec;
+ void *ehdr;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+
+ if (s== NULL || e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (e->e_cmd == ELF_C_READ) {
+ LIBELF_SET_ERROR(MODE, 0);
+ return (0);
+ }
+
+ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (0);
+
+ (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
+
+ if (ec == ELFCLASS64) {
+ eh64 = (Elf64_Ehdr *) ehdr;
+ *eh64 = *s;
+ return (1);
+ }
+
+ eh32 = (Elf32_Ehdr *) ehdr;
+
+ (void) memcpy(eh32->e_ident, s->e_ident, sizeof(eh32->e_ident));
+
+ eh32->e_type = s->e_type;
+ eh32->e_machine = s->e_machine;
+ eh32->e_version = s->e_version;
+ LIBELF_COPY_U32(eh32, s, e_entry);
+ LIBELF_COPY_U32(eh32, s, e_phoff);
+ LIBELF_COPY_U32(eh32, s, e_shoff);
+ eh32->e_flags = s->e_flags;
+ eh32->e_ehsize = s->e_ehsize;
+ eh32->e_phentsize = s->e_phentsize;
+ eh32->e_phnum = s->e_phnum;
+ eh32->e_shentsize = s->e_shentsize;
+ eh32->e_shnum = s->e_shnum;
+ eh32->e_shstrndx = s->e_shstrndx;
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_fsize.3 b/linkers/elftoolchain/libelf/gelf_fsize.3
new file mode 100644
index 0000000..ac7996f
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_fsize.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_fsize.3 317 2009-03-06 17:29:22Z jkoshy $
+.\"
+.Dd February 5, 2008
+.Os
+.Dt GELF_FSIZE 3
+.Sh NAME
+.Nm gelf_fsize ,
+.Nm elf32_fsize ,
+.Nm elf64_fsize
+.Nd return the size of a file type
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft size_t
+.Fn elf32_fsize "Elf_Type type" "size_t count" "unsigned int version"
+.Ft size_t
+.Fn elf64_fsize "Elf_Type type" "size_t count" "unsigned int version"
+.In gelf.h
+.Ft size_t
+.Fn gelf_fsize "Elf *elf" "Elf_Type type" "size_t count" "unsigned int version"
+.Sh DESCRIPTION
+These functions return the size in bytes of the file representation of
+.Ar count
+numbers of objects of ELF type
+.Ar type .
+For ELF types that are of variable length, these functions return a
+size of one byte.
+.Pp
+Functions
+.Fn elf32_fsize
+and
+.Fn elf64_fsize
+return sizes for files of class
+.Dv ELFCLASS32
+and
+.Dv ELFCLASS64
+respectively.
+Function
+.Fn gelf_fsize
+returns the size for the class of ELF descriptor
+.Ar elf .
+.Sh RETURN VALUES
+These functions return a non-zero value in case of success, or zero in
+case of an error.
+.Sh ERRORS
+These functions may fail with:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL in a call to
+.Fn gelf_fsize .
+.It Bq Er ELF_E_ARGUMENT
+ELF descriptor
+.Ar elf
+had an unknown ELF class.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar type
+contained an illegal value.
+.It Bq Er ELF_E_UNIMPL
+Support for ELF type
+.Ar type
+has not been implemented.
+.It Bq Er ELF_E_VERSION
+Argument
+.Ar version
+is not a supported version.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_fsize.c b/linkers/elftoolchain/libelf/gelf_fsize.c
new file mode 100644
index 0000000..0e38d14
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_fsize.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <gelf.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_fsize.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+size_t
+elf32_fsize(Elf_Type t, size_t c, unsigned int v)
+{
+ return (_libelf_fsize(t, ELFCLASS32, v, c));
+}
+
+size_t
+elf64_fsize(Elf_Type t, size_t c, unsigned int v)
+{
+ return (_libelf_fsize(t, ELFCLASS64, v, c));
+}
+
+size_t
+gelf_fsize(Elf *e, Elf_Type t, size_t c, unsigned int v)
+{
+
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (e->e_class == ELFCLASS32 || e->e_class == ELFCLASS64)
+ return (_libelf_fsize(t, e->e_class, v, c));
+
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_getcap.3 b/linkers/elftoolchain/libelf/gelf_getcap.3
new file mode 100644
index 0000000..ed8eb02
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getcap.3
@@ -0,0 +1,121 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getcap.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_GETCAP 3
+.Sh NAME
+.Nm gelf_getcap ,
+.Nm gelf_update_cap
+.Nd read and update ELF capability information
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Cap *"
+.Fn gelf_getcap "Elf_Data *data" "int ndx" "GElf_Cap *cap"
+.Ft int
+.Fn gelf_update_cap "Elf_Data *data" "int ndx" "GElf_Cap *cap"
+.Sh DESCRIPTION
+These convenience functions are used to retrieve and update class-dependent
+.Vt Elf32_Cap
+or
+.Vt Elf64_Cap
+information.
+.Pp
+Argument
+.Ar data
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_SUNW_cap .
+Argument
+.Ar ndx
+is the index of the entry being retrieved or updated.
+The class-independent
+.Vt GElf_Cap
+structure is described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getcap
+retrieves the class-dependent entry at index
+.Ar ndx
+in data buffer
+.Ar data
+and copies it to the destination pointed to by argument
+.Ar cap
+after translation to class-independent form.
+.Pp
+Function
+.Fn gelf_update_cap
+converts the class-independent entry pointed to
+by argument
+.Ar cap
+to class-dependent form, and writes it to the entry at index
+.Ar ndx
+in the data buffer described by argument
+.Ar data .
+Function
+.Fn gelf_update_cap
+signals an error if any of the values in the class-independent
+representation exceeds the representable limits of the target
+type.
+.Sh RETURN VALUES
+Function
+.Fn gelf_getcap
+returns the value of argument
+.Ar cap
+if successful, or NULL in case of an error.
+Function
+.Fn gelf_update_cap
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar data
+or
+.Ar cap
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero or larger than the number of entries in the data
+descriptor.
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar data
+was not associated with a section of type
+.Dv SHT_SUNW_cap .
+.It Bq Er ELF_E_RANGE
+A value was not representable in the target type.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_getclass.3 b/linkers/elftoolchain/libelf/gelf_getclass.3
new file mode 100644
index 0000000..3504569
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getclass.3
@@ -0,0 +1,61 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getclass.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd July 3, 2006
+.Os
+.Dt GELF_GETCLASS 3
+.Sh NAME
+.Nm gelf_getclass
+.Nd retrieve the class of an ELF descriptor
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft int
+.Fn gelf_getclass "Elf *elf"
+.Sh DESCRIPTION
+Function
+.Fn gelf_getclass
+returns the ELF class of the descriptor supplied in argument
+.Ar elf .
+.Sh RETURN VALUES
+Function
+.Fn gelf_getclass
+will return one of
+.Dv ELFCLASS32
+or
+.Dv ELFCLASS64
+if the argument
+.Ar elf
+is a descriptor for an ELF file.
+The value
+.Dv ELFCLASSNONE
+is returned if argument
+.Ar elf
+was null, or if it was not a descriptor for an ELF file.
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_kind 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_getclass.c b/linkers/elftoolchain/libelf/gelf_getclass.c
new file mode 100644
index 0000000..349a9cd
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getclass.c
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_getclass.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+int
+gelf_getclass(Elf *e)
+{
+ return (e != NULL ? e->e_class : ELFCLASSNONE);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_getdyn.3 b/linkers/elftoolchain/libelf/gelf_getdyn.3
new file mode 100644
index 0000000..f8c1778
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getdyn.3
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getdyn.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_GETDYN 3
+.Sh NAME
+.Nm gelf_getdyn ,
+.Nm gelf_update_dyn
+.Nd read and update ELF dynamic entries
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Dyn *"
+.Fn gelf_getdyn "Elf_Data *data" "int ndx" "GElf_Dyn *dyn"
+.Ft int
+.Fn gelf_update_dyn "Elf_Data *data" "int ndx" "GElf_Dyn *dyn"
+.Sh DESCRIPTION
+These convenience functions are used to retrieve and update class-dependent
+.Vt Elf32_Dyn
+or
+.Vt Elf64_Dyn
+information in the
+.Sy dynamic
+table of an ELF object.
+.Pp
+Argument
+.Ar data
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_DYNAMIC .
+Argument
+.Ar ndx
+is the index of the entry being retrieved or updated.
+The class-independent
+.Vt GElf_Dyn
+structure is described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getdyn
+retrieves the class-dependent entry at index
+.Ar ndx
+in data buffer
+.Ar data
+and copies it to the destination pointed to by argument
+.Ar dyn
+after translation to class-independent form.
+.Pp
+Function
+.Fn gelf_update_dyn
+converts the class-independent entry pointed to
+by argument
+.Ar dyn
+to class-dependent form, and writes it to the entry at index
+.Ar ndx
+in the data buffer described by argument
+.Ar data .
+Function
+.Fn gelf_update_dyn
+signals an error if any of the values in the class-independent
+representation exceeds the representable limits of the target
+type.
+.Sh RETURN VALUES
+Function
+.Fn gelf_getdyn
+returns the value of argument
+.Ar dyn
+if successful, or NULL in case of an error.
+Function
+.Fn gelf_update_dyn
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar data
+or
+.Ar dyn
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero or larger than the number of entries in the data
+descriptor.
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar data
+was not associated with a section of type
+.Dv SHT_DYNAMIC .
+.It Bq Er ELF_E_RANGE
+A value was not representable in the target type.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_getehdr.3 b/linkers/elftoolchain/libelf/gelf_getehdr.3
new file mode 100644
index 0000000..56bdcd4
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getehdr.3
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getehdr.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd December 16, 2006
+.Os
+.Dt GELF_GETEHDR 3
+.Sh NAME
+.Nm elf32_getehdr ,
+.Nm elf64_getehdr ,
+.Nm gelf_getehdr
+.Nd retrieve the object file header
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf32_Ehdr *"
+.Fn elf32_getehdr "Elf *elf"
+.Ft "Elf64_Ehdr *"
+.Fn elf64_getehdr "Elf *elf"
+.In gelf.h
+.Ft "GElf_Ehdr *"
+.Fn gelf_getehdr "Elf *elf" "GElf_Ehdr *dst"
+.Sh DESCRIPTION
+These functions retrieve the ELF object file
+header from the ELF descriptor
+.Ar elf
+and return a translated header descriptor to their callers.
+.Pp
+Functions
+.Fn elf32_getehdr
+and
+.Fn elf64_getehdr
+return a pointer to the appropriate class-specific header descriptor
+if it exists in the file referenced by descriptor
+.Ar elf .
+These functions return
+.Dv NULL
+if an ELF header was not found in file
+.Ar elf .
+.Pp
+Function
+.Fn gelf_getehdr
+stores a translated copy of the header for ELF file
+.Ar elf
+into the descriptor pointed to by argument
+.Ar dst .
+It returns argument
+.Ar dst
+if successful or
+.Dv NULL
+in case of failure.
+.Sh RETURN VALUES
+These functions return a pointer to a translated header descriptor
+if successful, or NULL on failure.
+.Sh ERRORS
+These functions can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+The argument
+.Ar elf
+was null.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+The elf class of descriptor
+.Ar elf
+was not recognized.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar dst
+was null.
+.It Bq Er ELF_E_CLASS
+The ELF class of descriptor
+.Ar elf
+did not match that of the API function being called.
+.It Bq Er ELF_E_HEADER
+ELF descriptor
+.Ar elf
+does not have an associated header.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected during execution.
+.It Bq Er ELF_E_SECTION
+The ELF descriptor in argument
+.Ar elf
+did not adhere to the conventions used for extended numbering.
+.It Bq Er ELF_E_VERSION
+The ELF descriptor
+.Ar elf
+had an unsupported ELF version number.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_newehdr 3 ,
+.Xr elf64_newehdr 3 ,
+.Xr elf_flagehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr gelf 3 ,
+.Xr gelf_newehdr 3 ,
+.Xr elf 5
diff --git a/linkers/elftoolchain/libelf/gelf_getmove.3 b/linkers/elftoolchain/libelf/gelf_getmove.3
new file mode 100644
index 0000000..871a040
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getmove.3
@@ -0,0 +1,120 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getmove.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_GETMOVE 3
+.Sh NAME
+.Nm gelf_getmove ,
+.Nm gelf_update_move
+.Nd read and update Elf Move information
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Move *"
+.Fn gelf_getmove "Elf_Data *data" "int ndx" "GElf_Move *move"
+.Ft int
+.Fn gelf_update_move "Elf_Data *data" "int ndx" "GElf_Move *move"
+.Sh DESCRIPTION
+These convenience functions are used to retrieve and update class-dependent
+.Vt Elf32_Move
+and
+.Vt Elf64_Move
+structures in an ELF object.
+.Pp
+Argument
+.Ar data
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_SUNW_move .
+Argument
+.Ar ndx
+is the index of the move record being retrieved or updated.
+The class-independent
+.Vt GElf_Move
+structure is described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getmove
+retrieves class-dependent move record at index
+.Ar ndx
+in data buffer
+.Ar data
+and copies it to the destination pointed to by argument
+.Ar move
+after translation to class-independent form.
+.Pp
+Function
+.Fn gelf_update_move
+converts the class-independent move information pointed to
+by argument
+.Ar move
+to class-dependent form, and writes it to the move record at index
+.Ar ndx
+in the data buffer described by argument
+.Ar data .
+Function
+.Fn gelf_update_move
+signals an error if any of the values in the class-independent
+representation exceeds the representable limits of the target
+type.
+.Sh RETURN VALUES
+Function
+.Fn gelf_getmove
+returns the value of argument
+.Ar move
+if successful, or NULL in case of an error.
+Function
+.Fn gelf_update_move
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar data
+or
+.Ar move
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero or larger than the number of records in the data
+descriptor.
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar data
+was not associated with a section containing move information.
+.It Bq Er ELF_E_RANGE
+A value was not representable in the target type.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_getphdr.3 b/linkers/elftoolchain/libelf/gelf_getphdr.3
new file mode 100644
index 0000000..f2d38aa
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getphdr.3
@@ -0,0 +1,141 @@
+.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getphdr.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd October 21, 2007
+.Os
+.Dt GELF_GETPHDR 3
+.Sh NAME
+.Nm elf32_getphdr ,
+.Nm elf64_getphdr ,
+.Nm gelf_getphdr
+.Nd retrieve an ELF program header table
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf32_Phdr *"
+.Fn elf32_getphdr "Elf *elf"
+.Ft "Elf64_Phdr *"
+.Fn elf64_getphdr "Elf *elf"
+.In gelf.h
+.Ft "GElf_Phdr *"
+.Fn gelf_getphdr "Elf *elf" "int index" "GElf_Phdr *dst"
+.Sh DESCRIPTION
+These functions retrieve and translate ELF program header information
+from an ELF descriptor, if this information exists.
+.Pp
+Functions
+.Fn elf32_getphdr
+and
+.Fn elf64_getphdr
+return a pointer to an array of translated
+.Vt Elf32_Phdr
+and
+.Vt Elf64_Phdr
+descriptors respectively.
+These descriptors are described in
+.Xr elf 5 .
+The number of entries in this array may be determined using the
+.Xr elf_getphnum 3
+function.
+.Pp
+Function
+.Fn gelf_getphdr
+will retrieve the program header table entry at index
+.Ar index
+from ELF descriptor
+.Ar elf.
+The translated program header table entry will be written to the
+address pointed to be argument
+.Ar dst .
+.Pp
+Applications may inform the library of modifications to a program header table entry
+by using the
+.Xr elf_flagphdr 3
+API.
+Applications using the
+.Xr gelf 3
+interface need to use the
+.Xr gelf_update_phdr 3
+API to copy modifications to a program header entry back to the underlying
+ELF descriptor.
+.Sh RETURN VALUES
+The functions a valid pointer if successful, or NULL in case an error
+was encountered.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF object.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar dst
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Index
+.Ar index
+was out of range.
+.It Bq Er ELF_E_CLASS
+The class of ELF descriptor
+.Ar elf
+did not match the expected class of the function being called.
+.It Bq Er ELF_E_HEADER
+ELF descriptor
+.Ar elf
+did not possess an executable header.
+.It Bq Er ELF_E_HEADER
+ELF descriptor
+.Ar elf
+had a corrupt executable header.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected.
+.It Bq Er ELF_E_SECTION
+The ELF descriptor in argument
+.Ar elf
+did not adhere to the conventions used for extended numbering.
+.It Bq Er ELF_VERSION
+ELF descriptor
+.Ar elf
+was of an unsupported version.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf32_newphdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf64_newphdr 3 ,
+.Xr elf_flagphdr 3 ,
+.Xr elf_getphnum 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3 ,
+.Xr gelf_newphdr 3 ,
+.Xr gelf_update_phdr 3 ,
+.Xr elf 5
diff --git a/linkers/elftoolchain/libelf/gelf_getrel.3 b/linkers/elftoolchain/libelf/gelf_getrel.3
new file mode 100644
index 0000000..c7566e6
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getrel.3
@@ -0,0 +1,121 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getrel.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_GETREL 3
+.Sh NAME
+.Nm gelf_getrel ,
+.Nm gelf_update_rel
+.Nd read and update ELF relocation entries
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Rel *"
+.Fn gelf_getrel "Elf_Data *data" "int ndx" "GElf_Rel *rel"
+.Ft int
+.Fn gelf_update_rel "Elf_Data *data" "int ndx" "GElf_Rel *rel"
+.Sh DESCRIPTION
+These convenience functions are used to retrieve and update class-dependent
+.Vt Elf32_Rel
+or
+.Vt Elf64_Rel
+structures in an ELF object.
+.Pp
+Argument
+.Ar data
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_REL .
+Argument
+.Ar ndx
+is the index of the entry being retrieved or updated.
+The class-independent
+.Vt GElf_Rel
+structure is described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getrel
+retrieves the class-dependent entry at index
+.Ar ndx
+in data buffer
+.Ar data
+and copies it to the destination pointed to by argument
+.Ar rel
+after translation to class-independent form.
+.Pp
+Function
+.Fn gelf_update_rel
+converts the class-independent entry pointed to
+by argument
+.Ar rel
+to class-dependent form, and writes it to the entry at index
+.Ar ndx
+in the data buffer described by argument
+.Ar data .
+Function
+.Fn gelf_update_rel
+signals an error if any of the values in the class-independent
+representation exceeds the representable limits of the target
+type.
+.Sh RETURN VALUES
+Function
+.Fn gelf_getrel
+returns the value of argument
+.Ar rel
+if successful, or NULL in case of an error.
+Function
+.Fn gelf_update_rel
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar data
+or
+.Ar rel
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero or larger than the number of entries in the data
+descriptor.
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar data
+was not associated with a section of type
+.Dv SHT_REL .
+.It Bq Er ELF_E_RANGE
+A value was not representable in the target type.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_getrela.3 b/linkers/elftoolchain/libelf/gelf_getrela.3
new file mode 100644
index 0000000..c77d52a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getrela.3
@@ -0,0 +1,121 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getrela.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_GETRELA 3
+.Sh NAME
+.Nm gelf_getrela ,
+.Nm gelf_update_rela
+.Nd read and update ELF relocation entries with addends
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Rela *"
+.Fn gelf_getrela "Elf_Data *data" "int ndx" "GElf_Rela *rela"
+.Ft int
+.Fn gelf_update_rela "Elf_Data *data" "int ndx" "GElf_Rela *rela"
+.Sh DESCRIPTION
+These convenience functions are used to retrieve and update class-dependent
+.Vt Elf32_Rela
+or
+.Vt Elf64_Rela
+structures in an ELF object.
+.Pp
+Argument
+.Ar data
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_RELA .
+Argument
+.Ar ndx
+is the index of the entry being retrieved or updated.
+The class-independent
+.Vt GElf_Rela
+structure is described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getrela
+retrieves the class-dependent entry at index
+.Ar ndx
+in data buffer
+.Ar data
+and copies it to the destination pointed to by argument
+.Ar rela
+after translation to class-independent form.
+.Pp
+Function
+.Fn gelf_update_rela
+converts the class-independent entry pointed to
+by argument
+.Ar rela
+to class-dependent form, and writes it to the entry at index
+.Ar ndx
+in the data buffer described by argument
+.Ar data .
+Function
+.Fn gelf_update_rela
+signals an error if any of the values in the class-independent
+representation exceeds the representable limits of the target
+type.
+.Sh RETURN VALUES
+Function
+.Fn gelf_getrela
+returns the value of argument
+.Ar rela
+if successful, or NULL in case of an error.
+Function
+.Fn gelf_update_rela
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar data
+or
+.Ar rela
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero or larger than the number of entries in the data
+descriptor.
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar data
+was not associated with a section of type
+.Dv SHT_RELA .
+.It Bq Er ELF_E_RANGE
+A value was not representable in the target type.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/gelf_getshdr.3 b/linkers/elftoolchain/libelf/gelf_getshdr.3
new file mode 100644
index 0000000..e92d414
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getshdr.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getshdr.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 27, 2006
+.Os
+.Dt GELF_GETSHDR 3
+.Sh NAME
+.Nm elf32_getshdr ,
+.Nm elf64_getshdr ,
+.Nm gelf_getshdr
+.Nd retrieve the class-dependent section header
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf32_Shdr *"
+.Fn elf32_getshdr "Elf_Scn *scn"
+.Ft "Elf64_Shdr *"
+.Fn elf64_getshdr "Elf_Scn *scn"
+.In gelf.h
+.Ft "GElf_Shdr *"
+.Fn gelf_getshdr "Elf_Scn *scn" "GElf_Shdr *shdr"
+.Sh DESCRIPTION
+These functions return a pointer to the ELF Section Header data
+structure associated with section descriptor
+.Ar scn .
+.Pp
+Function
+.Fn elf32_getshdr
+retrieves a pointer to an
+.Vt Elf32_Shdr
+structure.
+Section descriptor
+.Ar scn
+must be associated with an ELF descriptor of class
+.Dv ELFCLASS32 .
+.Pp
+Function
+.Fn elf64_getshdr
+retrieves a pointer to an
+.Vt Elf64_Shdr
+structure.
+Section descriptor
+.Ar scn
+must be associated with an ELF descriptor of class
+.Dv ELFCLASS64 .
+.Pp
+Function
+.Fn gelf_getshdr
+copies the values in the section header associated with argument
+.Ar scn
+to the structure pointed to be argument
+.Ar dst .
+The
+.Vt GElf_Shdr
+data structure is described in
+.Xr gelf 3 .
+.Sh RETURN VALUES
+Functions
+.Fn elf32_getshdr
+and
+.Fn elf64_getshdr
+return a valid pointer to the appropriate section header on success
+or NULL if an error was encountered.
+.Pp
+Function
+.Fn gelf_getshdr
+returns argument
+.Ar dst
+if successful, or NULL if an error was encountered.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar scn
+or
+.Ar shdr
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar scn
+was not associated a descriptor for an ELF object.
+.It Bq Er ELF_E_CLASS
+The ELF class associated with the section descriptor
+.Ar scn
+did not match the class expected by the API.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3 ,
+.Xr gelf_update_shdr 3
diff --git a/linkers/elftoolchain/libelf/gelf_getsym.3 b/linkers/elftoolchain/libelf/gelf_getsym.3
new file mode 100644
index 0000000..98d886f
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getsym.3
@@ -0,0 +1,125 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getsym.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_GETSYM 3
+.Sh NAME
+.Nm gelf_getsym ,
+.Nm gelf_update_sym
+.Nd read and update symbol information
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Sym *"
+.Fn gelf_getsym "Elf_Data *data" "int ndx" "GElf_Sym *sym"
+.Ft int
+.Fn gelf_update_sym "Elf_Data *data" "int ndx" "GElf_Sym *sym"
+.Sh DESCRIPTION
+These convenience functions are used to retrieve and update class-dependent
+.Vt Elf32_Sym
+and
+.Vt Elf64_Sym
+structures in an ELF object.
+.Pp
+Argument
+.Ar data
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_SYMTAB ,
+.Dv SHT_DYNSYM
+or
+.Dv SHT_GNU_versym .
+Argument
+.Ar ndx
+is the index of the symbol being retrieved or updated.
+The class-independent
+.Vt GElf_Sym
+structure is described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getsym
+retrieves class-dependent symbol information at index
+.Ar ndx
+in data buffer
+.Ar data
+and copies it to the destination pointed to by argument
+.Ar sym
+after translation to class-independent form.
+.Pp
+Function
+.Fn gelf_update_sym
+converts the class-independent symbol information pointed to
+by argument
+.Ar sym
+to class-dependent form, and writes it to the symbol entry at index
+.Ar ndx
+in the data buffer described by argument
+.Ar data .
+Function
+.Fn gelf_update_sym
+signals an error if any of the values in the class-independent
+representation exceeds the representable limits of the target
+type.
+.Sh RETURN VALUES
+Function
+.Fn gelf_getsym
+returns the value of argument
+.Ar sym
+if successful, or NULL in case of an error.
+Function
+.Fn gelf_update_sym
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar data
+or
+.Ar sym
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero or larger than the number of symbols in the data
+descriptor.
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar data
+was not associated with a section containing symbol information.
+.It Bq Er ELF_E_RANGE
+A value was not representable in the target type.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getsyminfo 3 ,
+.Xr gelf_update_syminfo 3
diff --git a/linkers/elftoolchain/libelf/gelf_getsyminfo.3 b/linkers/elftoolchain/libelf/gelf_getsyminfo.3
new file mode 100644
index 0000000..a1169f8
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getsyminfo.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getsyminfo.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 29, 2006
+.Os
+.Dt GELF_GETSYMINFO 3
+.Sh NAME
+.Nm gelf_getsyminfo ,
+.Nm gelf_update_syminfo
+.Nd read and update symbol information
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Syminfo *"
+.Fn gelf_getsyminfo "Elf_Data *data" "int ndx" "GElf_Syminfo *syminfo"
+.Ft int
+.Fn gelf_update_syminfo "Elf_Data *data" "int ndx" "GElf_Syminfo *syminfo"
+.Sh DESCRIPTION
+These convenience functions are used to retrieve and update class-dependent
+.Vt Elf32_Syminfo
+and
+.Vt Elf64_Syminfo
+records in an ELF object.
+.Pp
+Argument
+.Ar data
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_SUNW_syminfo .
+Argument
+.Ar ndx
+is the index of the record being retrieved or updated.
+The class-independent
+.Vt GElf_Syminfo
+structure is described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getsyminfo
+retrieves class-dependent record at index
+.Ar ndx
+in data buffer
+.Ar data
+and copies it to the destination pointed to by argument
+.Ar syminfo
+after translation to class-independent form.
+.Pp
+Function
+.Fn gelf_update_syminfo
+converts the class-independent record pointed to
+by argument
+.Ar syminfo
+to class-dependent form, and writes it to the record at index
+.Ar ndx
+in the data buffer described by argument
+.Ar data .
+.Sh RETURN VALUES
+Function
+.Fn gelf_getsyminfo
+returns the value of argument
+.Ar syminfo
+if successful, or NULL in case of an error.
+Function
+.Fn gelf_update_syminfo
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar data
+or
+.Ar syminfo
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero or larger than the number of symbols in the data
+descriptor.
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar data
+was not associated with a section containing symbol information.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getsym 3 ,
+.Xr gelf_update_sym 3
diff --git a/linkers/elftoolchain/libelf/gelf_getsymshndx.3 b/linkers/elftoolchain/libelf/gelf_getsymshndx.3
new file mode 100644
index 0000000..b635aac
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_getsymshndx.3
@@ -0,0 +1,162 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_getsymshndx.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd November 5, 2006
+.Os
+.Dt GELF_GETSYMSHNDX 3
+.Sh NAME
+.Nm gelf_getsymshndx ,
+.Nm gelf_update_symshndx
+.Nd read and update symbol information using extended section indices
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft "GElf_Sym *"
+.Fo gelf_getsymshndx
+.Fa "Elf_Data *symdata"
+.Fa "Elf_Data *xndxdata"
+.Fa "int ndx"
+.Fa "GElf_Sym *sym"
+.Fa "Elf32_Word *xndxptr"
+.Fc
+.Ft int
+.Fo gelf_update_symshndx
+.Fa "Elf_Data *symdata"
+.Fa "Elf_Data *xndxdata"
+.Fa "int ndx"
+.Fa "GElf_Sym *sym"
+.Fa "Elf32_Word xndx"
+.Fc
+.Sh DESCRIPTION
+These functions are analogous to
+.Fn gelf_getsym
+and
+.Fn gelf_update_sym
+respectively, but are capable of handling symbol tables using extended
+section numbering.
+.Pp
+Argument
+.Ar symdata
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_SYMTAB .
+Argument
+.Ar xndxdata
+is an
+.Vt Elf_Data
+descriptor associated with a section of type
+.Dv SHT_SYMTAB_SHNDX .
+Argument
+.Ar ndx
+is the index of the symbol table entry being retrieved or updated.
+Argument
+.Ar sym
+is a pointer to a class-independent
+.Vt GElf_Sym
+structure.
+.Vt GElf_Sym
+structures are described in detail in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_getsymshndx
+retrieves symbol information at index
+.Ar ndx
+from the data descriptor specified by argument
+.Ar symdata
+and stores in class-independent form in argument
+.Ar sym .
+In addition it retrieves the extended section index for the
+symbol from data buffer
+.Ar xndxdata
+and stores it into the location pointed to by argument
+.Ar xndxptr .
+.Pp
+Function
+.Fn gelf_update_symshndx
+updates the underlying symbol table entry in data
+descriptor
+.Ar symdata
+with the information in argument
+.Ar sym .
+In addition it sets the extended section index in
+data buffer
+.Ar xndxdata
+to the value of argument
+.Ar xndx .
+.Sh RETURN VALUES
+Function
+.Fn gelf_getsymshndx
+returns the value of argument
+.Ar sym
+if successful, or NULL in case of an error.
+.Pp
+Function
+.Fn gelf_update_symshndx
+returns a non-zero value if successful, or zero in case of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar symdata ,
+.Ar xndxdata ,
+.Ar xndxptr
+or
+.Ar sym
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+was less than zero, or too large for either of descriptors
+.Ar symdata
+or
+.Ar xndxdata .
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar symdata
+was not associated with a section of type
+.Dv SHT_SYMTAB .
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar xndxdata
+was not associated with a section of type
+.Dv SHT_SYMTAB_SHNDX .
+.It Bq Er ELF_E_ARGUMENT
+Data descriptor
+.Ar symdata
+and
+.Ar xndxdata
+were associated with different ELF objects.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr elf_getscn 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getsym 3 ,
+.Xr gelf_update_sym 3
diff --git a/linkers/elftoolchain/libelf/gelf_move.c b/linkers/elftoolchain/libelf/gelf_move.c
new file mode 100644
index 0000000..753aba9
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_move.c
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_move.c 1166 2010-09-04 00:54:36Z jkoshy $");
+
+GElf_Move *
+gelf_getmove(Elf_Data *d, int ndx, GElf_Move *dst)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Move *move32;
+ Elf64_Move *move64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dst == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_MOVE) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+
+ move32 = (Elf32_Move *) d->d_buf + ndx;
+
+ dst->m_value = move32->m_value;
+ dst->m_info = (Elf64_Xword) move32->m_info;
+ dst->m_poffset = (Elf64_Xword) move32->m_poffset;
+ dst->m_repeat = move32->m_repeat;
+ dst->m_stride = move32->m_stride;
+ } else {
+
+ move64 = (Elf64_Move *) d->d_buf + ndx;
+
+ *dst = *move64;
+ }
+
+ return (dst);
+}
+
+int
+gelf_update_move(Elf_Data *d, int ndx, GElf_Move *gm)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Move *move32;
+ Elf64_Move *move64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || gm == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_MOVE) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32) {
+ move32 = (Elf32_Move *) d->d_buf + ndx;
+
+ move32->m_value = gm->m_value;
+ LIBELF_COPY_U32(move32, gm, m_info);
+ LIBELF_COPY_U32(move32, gm, m_poffset);
+ move32->m_repeat = gm->m_repeat;
+ move32->m_stride = gm->m_stride;
+
+ } else {
+ move64 = (Elf64_Move *) d->d_buf + ndx;
+
+ *move64 = *gm;
+ }
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_newehdr.3 b/linkers/elftoolchain/libelf/gelf_newehdr.3
new file mode 100644
index 0000000..180fea9
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_newehdr.3
@@ -0,0 +1,185 @@
+.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_newehdr.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd October 22, 2007
+.Os
+.Dt GELF_NEWEHDR 3
+.Sh NAME
+.Nm elf32_newehdr ,
+.Nm elf64_newehdr ,
+.Nm gelf_newehdr
+.Nd retrieve or allocate the object file header
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf32_Ehdr *"
+.Fn elf32_newehdr "Elf *elf"
+.Ft "Elf64_Ehdr *"
+.Fn elf64_newehdr "Elf *elf"
+.In gelf.h
+.Ft "void *"
+.Fn gelf_newehdr "Elf *elf" "int elfclass"
+.Sh DESCRIPTION
+These functions retrieve the ELF header from the ELF descriptor
+.Ar elf ,
+allocating a new header if needed.
+File data structures are translated to their in-memory representations
+as described in
+.Xr elf 3 .
+.Pp
+Function
+.Fn elf32_newehdr
+returns a pointer to a 32 bit
+.Vt Elf32_Ehdr
+structure.
+Function
+.Fn elf64_newehdr
+returns a pointer to a 64 bit
+.Vt Elf64_Ehdr structure.
+.Pp
+When argument
+.Ar elfclass
+has value
+.Dv ELFCLASS32 ,
+function
+.Fn gelf_newehdr
+returns the value returned by
+.Fn elf32_newehdr "elf" .
+When argument
+.Ar elfclass
+has value
+.Dv ELFCLASS64
+it returns the value returned by
+.Fn elf64_newehdr "elf" .
+.Pp
+If a fresh header structure is allocated, the members of the
+structure are initialized as follows:
+.Bl -tag -width indent
+.It Va "e_ident[EI_MAG0..EI_MAG3]"
+Identification bytes at offsets
+.Dv EI_MAG0 ,
+.Dv EI_MAG1 ,
+.Dv EI_MAG2
+and
+.Dv EI_MAG3
+are set to the ELF signature.
+.It Va "e_ident[EI_CLASS]"
+The identification byte at offset
+.Dv EI_CLASS
+is set to the ELF class associated with the function being called
+or to argument
+.Ar elfclass
+for function
+.Fn gelf_newehdr .
+.It Va "e_ident[EI_DATA]"
+The identification byte at offset
+.Dv EI_DATA
+is set to
+.Dv ELFDATANONE .
+.It Va "e_ident[EI_VERSION]"
+The identification byte at offset
+.Dv EI_VERSION
+is set to the ELF library's operating version set by a prior call to
+.Xr elf_version 3 .
+.It Va e_machine
+is set to
+.Dv EM_NONE .
+.It Va e_type
+is set to
+.Dv ELF_K_NONE .
+.It Va e_version
+is set to the ELF library's operating version set by a prior call to
+.Xr elf_version 3 .
+.El
+.Pp
+Other members of the header are set to zero.
+The application is responsible for changing these values
+as needed before calling
+.Fn elf_update .
+.Pp
+If successful, these three functions set the
+.Dv ELF_F_DIRTY
+flag on ELF descriptor
+.Ar elf .
+.Sh RETURN VALUES
+These functions return a pointer to a translated header descriptor
+if successful, or NULL on failure.
+.Sh ERRORS
+These functions can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+The argument
+.Ar elf
+was null.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF object.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elfclass
+had an unsupported value.
+.It Bq Er ELF_E_ARGUMENT
+The class of the ELF descriptor
+.Ar elf
+did not match that of the requested operation.
+.It Bq Er ELF_E_ARGUMENT
+For function
+.Fn gelf_newehdr ,
+the class of argument
+.Ar elf
+was not
+.Dv ELFCLASSNONE
+and did not match the argument
+.Ar elfclass .
+.It Bq Er ELF_E_CLASS
+The ELF class of descriptor
+.Ar elf
+did not match that of the API function being called.
+.It Bq Er ELF_E_HEADER
+A malformed ELF header was detected.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected during execution.
+.It Bq Er ELF_E_SECTION
+The ELF descriptor in argument
+.Ar elf
+did not adhere to the conventions used for extended numbering.
+.It Bq Er ELF_E_VERSION
+The ELF descriptor
+.Ar elf
+had an unsupported ELF version number.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_flagdata 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_update 3 ,
+.Xr elf_version 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3 ,
+.Xr elf 5
diff --git a/linkers/elftoolchain/libelf/gelf_newphdr.3 b/linkers/elftoolchain/libelf/gelf_newphdr.3
new file mode 100644
index 0000000..931385e
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_newphdr.3
@@ -0,0 +1,133 @@
+.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_newphdr.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd October 22, 2007
+.Os
+.Dt GELF_NEWPHDR 3
+.Sh NAME
+.Nm elf32_newphdr ,
+.Nm elf64_newphdr ,
+.Nm gelf_newphdr
+.Nd allocate an ELF program header table
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf32_Phdr *"
+.Fn elf32_newphdr "Elf *elf" "size_t count"
+.Ft "Elf64_Phdr *"
+.Fn elf64_newphdr "Elf *elf" "size_t count"
+.In gelf.h
+.Ft "void *"
+.Fn gelf_newphdr "Elf *elf" "size_t count"
+.Sh DESCRIPTION
+These functions allocate an ELF Program Header table
+for an ELF descriptor.
+.Vt Elf32_Phdr
+and
+.Vt Elf64_Phdr
+descriptors are described further in
+.Xr elf 5 .
+.Pp
+Functions
+.Fn elf32_newphdr
+and
+.Fn elf64_newphdr
+allocate a table of
+.Ar count
+.Vt Elf32_Phdr
+and
+.Vt Elf64_Phdr
+descriptors respectively,
+discarding any existing program header table
+already present in the ELF descriptor
+.Ar elf .
+A value of zero for argument
+.Ar count
+may be used to delete an existing program header table
+from an ELF descriptor.
+.Pp
+Function
+.Fn gelf_newphdr
+will return a table of
+.Vt Elf32_Phdr
+or
+.Vt Elf64_Phdr
+with
+.Ar count
+elements depending on the ELF class of ELF descriptor
+.Ar elf .
+.Pp
+The functions set the
+.Dv ELF_F_DIRTY
+flag on the program header table.
+All members of the returned array of Phdr structures
+will be initialized to zero.
+.Pp
+After a successful call to these functions, the pointer returned
+by a prior call to
+.Fn elf32_getphdr
+or
+.Fn elf64_getphdr
+on the same descriptor
+.Ar elf
+will no longer be valid.
+.Sh RETURN VALUES
+The functions a valid pointer if successful, or NULL in case an error
+was encountered.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF object.
+.It Bq Er ELF_E_CLASS
+ELF descriptor
+.Ar elf
+was of an unrecognized class.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected.
+.It Bq Er ELF_E_SEQUENCE
+An executable header was not allocated for ELF descriptor
+.Ar elf
+before using these APIs.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getphdr 3 ,
+.Xr elf32_newehdr 3 ,
+.Xr elf64_getphdr 3 ,
+.Xr elf64_newehdr 3 ,
+.Xr elf_flagphdr 3 ,
+.Xr elf_getphnum 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getphdr 3 ,
+.Xr gelf_newehdr 3 ,
+.Xr elf 5
diff --git a/linkers/elftoolchain/libelf/gelf_phdr.c b/linkers/elftoolchain/libelf/gelf_phdr.c
new file mode 100644
index 0000000..47000d8
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_phdr.c
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <gelf.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_phdr.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+Elf32_Phdr *
+elf32_getphdr(Elf *e)
+{
+ return (_libelf_getphdr(e, ELFCLASS32));
+}
+
+Elf64_Phdr *
+elf64_getphdr(Elf *e)
+{
+ return (_libelf_getphdr(e, ELFCLASS64));
+}
+
+GElf_Phdr *
+gelf_getphdr(Elf *e, int index, GElf_Phdr *d)
+{
+ int ec;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+ Elf32_Phdr *ep32;
+ Elf64_Phdr *ep64;
+
+ if (d == NULL || e == NULL ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) ||
+ (e->e_kind != ELF_K_ELF) || index < 0) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+ if ((eh32 = _libelf_ehdr(e, ELFCLASS32, 0)) == NULL ||
+ ((ep32 = _libelf_getphdr(e, ELFCLASS32)) == NULL))
+ return (NULL);
+
+ if (index >= eh32->e_phnum) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ep32 += index;
+
+ d->p_type = ep32->p_type;
+ d->p_offset = ep32->p_offset;
+ d->p_vaddr = (Elf64_Addr) ep32->p_vaddr;
+ d->p_paddr = (Elf64_Addr) ep32->p_paddr;
+ d->p_filesz = (Elf64_Xword) ep32->p_filesz;
+ d->p_memsz = (Elf64_Xword) ep32->p_memsz;
+ d->p_flags = ep32->p_flags;
+ d->p_align = (Elf64_Xword) ep32->p_align;
+
+ } else {
+ if ((eh64 = _libelf_ehdr(e, ELFCLASS64, 0)) == NULL ||
+ (ep64 = _libelf_getphdr(e, ELFCLASS64)) == NULL)
+ return (NULL);
+
+ if (index >= eh64->e_phnum) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ep64 += index;
+
+ *d = *ep64;
+ }
+
+ return (d);
+}
+
+Elf32_Phdr *
+elf32_newphdr(Elf *e, size_t count)
+{
+ return (_libelf_newphdr(e, ELFCLASS32, count));
+}
+
+Elf64_Phdr *
+elf64_newphdr(Elf *e, size_t count)
+{
+ return (_libelf_newphdr(e, ELFCLASS64, count));
+}
+
+void *
+gelf_newphdr(Elf *e, size_t count)
+{
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+ return (_libelf_newphdr(e, e->e_class, count));
+}
+
+int
+gelf_update_phdr(Elf *e, int ndx, GElf_Phdr *s)
+{
+ int ec, phnum;
+ void *ehdr;
+ Elf32_Phdr *ph32;
+ Elf64_Phdr *ph64;
+
+ if (s == NULL || e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (e->e_cmd == ELF_C_READ) {
+ LIBELF_SET_ERROR(MODE, 0);
+ return (0);
+ }
+
+ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (0);
+
+ if (ec == ELFCLASS32)
+ phnum = ((Elf32_Ehdr *) ehdr)->e_phnum;
+ else
+ phnum = ((Elf64_Ehdr *) ehdr)->e_phnum;
+
+ if (ndx < 0 || ndx > phnum) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ (void) elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY);
+
+ if (ec == ELFCLASS64) {
+ ph64 = e->e_u.e_elf.e_phdr.e_phdr64 + ndx;
+ *ph64 = *s;
+ return (1);
+ }
+
+ ph32 = e->e_u.e_elf.e_phdr.e_phdr32 + ndx;
+
+ ph32->p_type = s->p_type;
+ ph32->p_flags = s->p_flags;
+ LIBELF_COPY_U32(ph32, s, p_offset);
+ LIBELF_COPY_U32(ph32, s, p_vaddr);
+ LIBELF_COPY_U32(ph32, s, p_paddr);
+ LIBELF_COPY_U32(ph32, s, p_filesz);
+ LIBELF_COPY_U32(ph32, s, p_memsz);
+ LIBELF_COPY_U32(ph32, s, p_align);
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_rel.c b/linkers/elftoolchain/libelf/gelf_rel.c
new file mode 100644
index 0000000..7d0b6af
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_rel.c
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_rel.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+GElf_Rel *
+gelf_getrel(Elf_Data *d, int ndx, GElf_Rel *dst)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Rel *rel32;
+ Elf64_Rel *rel64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dst == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_REL, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+ rel32 = (Elf32_Rel *) d->d_buf + ndx;
+
+ dst->r_offset = (Elf64_Addr) rel32->r_offset;
+ dst->r_info = ELF64_R_INFO(
+ (Elf64_Xword) ELF32_R_SYM(rel32->r_info),
+ ELF32_R_TYPE(rel32->r_info));
+
+ } else {
+
+ rel64 = (Elf64_Rel *) d->d_buf + ndx;
+
+ *dst = *rel64;
+ }
+
+ return (dst);
+}
+
+int
+gelf_update_rel(Elf_Data *d, int ndx, GElf_Rel *dr)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Rel *rel32;
+ Elf64_Rel *rel64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dr == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_REL, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32) {
+ rel32 = (Elf32_Rel *) d->d_buf + ndx;
+
+ LIBELF_COPY_U32(rel32, dr, r_offset);
+
+ if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) ||
+ ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) {
+ LIBELF_SET_ERROR(RANGE, 0);
+ return (0);
+ }
+ rel32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info),
+ ELF64_R_TYPE(dr->r_info));
+ } else {
+ rel64 = (Elf64_Rel *) d->d_buf + ndx;
+
+ *rel64 = *dr;
+ }
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_rela.c b/linkers/elftoolchain/libelf/gelf_rela.c
new file mode 100644
index 0000000..722c1ad
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_rela.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_rela.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+GElf_Rela *
+gelf_getrela(Elf_Data *d, int ndx, GElf_Rela *dst)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Rela *rela32;
+ Elf64_Rela *rela64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dst == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_RELA, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+ rela32 = (Elf32_Rela *) d->d_buf + ndx;
+
+ dst->r_offset = (Elf64_Addr) rela32->r_offset;
+ dst->r_info = ELF64_R_INFO(
+ (Elf64_Xword) ELF32_R_SYM(rela32->r_info),
+ ELF32_R_TYPE(rela32->r_info));
+ dst->r_addend = (Elf64_Sxword) rela32->r_addend;
+
+ } else {
+
+ rela64 = (Elf64_Rela *) d->d_buf + ndx;
+
+ *dst = *rela64;
+ }
+
+ return (dst);
+}
+
+int
+gelf_update_rela(Elf_Data *d, int ndx, GElf_Rela *dr)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Rela *rela32;
+ Elf64_Rela *rela64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dr == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_RELA, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32) {
+ rela32 = (Elf32_Rela *) d->d_buf + ndx;
+
+ LIBELF_COPY_U32(rela32, dr, r_offset);
+
+ if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) ||
+ ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) {
+ LIBELF_SET_ERROR(RANGE, 0);
+ return (0);
+ }
+ rela32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info),
+ ELF64_R_TYPE(dr->r_info));
+
+ LIBELF_COPY_S32(rela32, dr, r_addend);
+ } else {
+ rela64 = (Elf64_Rela *) d->d_buf + ndx;
+
+ *rela64 = *dr;
+ }
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_shdr.c b/linkers/elftoolchain/libelf/gelf_shdr.c
new file mode 100644
index 0000000..47e56e9
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_shdr.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_shdr.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+Elf32_Shdr *
+elf32_getshdr(Elf_Scn *s)
+{
+ return (_libelf_getshdr(s, ELFCLASS32));
+}
+
+Elf64_Shdr *
+elf64_getshdr(Elf_Scn *s)
+{
+ return (_libelf_getshdr(s, ELFCLASS64));
+}
+
+GElf_Shdr *
+gelf_getshdr(Elf_Scn *s, GElf_Shdr *d)
+{
+ int ec;
+ void *sh;
+ Elf32_Shdr *sh32;
+ Elf64_Shdr *sh64;
+
+ if (d == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if ((sh = _libelf_getshdr(s, ELFCLASSNONE)) == NULL)
+ return (NULL);
+
+ ec = s->s_elf->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32) {
+ sh32 = (Elf32_Shdr *) sh;
+
+ d->sh_name = sh32->sh_name;
+ d->sh_type = sh32->sh_type;
+ d->sh_flags = (Elf64_Xword) sh32->sh_flags;
+ d->sh_addr = (Elf64_Addr) sh32->sh_addr;
+ d->sh_offset = (Elf64_Off) sh32->sh_offset;
+ d->sh_size = (Elf64_Xword) sh32->sh_size;
+ d->sh_link = sh32->sh_link;
+ d->sh_info = sh32->sh_info;
+ d->sh_addralign = (Elf64_Xword) sh32->sh_addralign;
+ d->sh_entsize = (Elf64_Xword) sh32->sh_entsize;
+ } else {
+ sh64 = (Elf64_Shdr *) sh;
+ *d = *sh64;
+ }
+
+ return (d);
+}
+
+int
+gelf_update_shdr(Elf_Scn *scn, GElf_Shdr *s)
+{
+ int ec;
+ Elf *e;
+ Elf32_Shdr *sh32;
+
+
+ if (s == NULL || scn == NULL || (e = scn->s_elf) == NULL ||
+ e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (e->e_cmd == ELF_C_READ) {
+ LIBELF_SET_ERROR(MODE, 0);
+ return (0);
+ }
+
+ (void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ if (ec == ELFCLASS64) {
+ scn->s_shdr.s_shdr64 = *s;
+ return (1);
+ }
+
+ sh32 = &scn->s_shdr.s_shdr32;
+
+ sh32->sh_name = s->sh_name;
+ sh32->sh_type = s->sh_type;
+ LIBELF_COPY_U32(sh32, s, sh_flags);
+ LIBELF_COPY_U32(sh32, s, sh_addr);
+ LIBELF_COPY_U32(sh32, s, sh_offset);
+ LIBELF_COPY_U32(sh32, s, sh_size);
+ sh32->sh_link = s->sh_link;
+ sh32->sh_info = s->sh_info;
+ LIBELF_COPY_U32(sh32, s, sh_addralign);
+ LIBELF_COPY_U32(sh32, s, sh_entsize);
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_sym.c b/linkers/elftoolchain/libelf/gelf_sym.c
new file mode 100644
index 0000000..3f84a17
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_sym.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_sym.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+GElf_Sym *
+gelf_getsym(Elf_Data *d, int ndx, GElf_Sym *dst)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Sym *sym32;
+ Elf64_Sym *sym64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dst == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_SYM, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+
+ sym32 = (Elf32_Sym *) d->d_buf + ndx;
+
+ dst->st_name = sym32->st_name;
+ dst->st_value = (Elf64_Addr) sym32->st_value;
+ dst->st_size = (Elf64_Xword) sym32->st_size;
+ dst->st_info = ELF64_ST_INFO(ELF32_ST_BIND(sym32->st_info),
+ ELF32_ST_TYPE(sym32->st_info));
+ dst->st_other = sym32->st_other;
+ dst->st_shndx = sym32->st_shndx;
+ } else {
+
+ sym64 = (Elf64_Sym *) d->d_buf + ndx;
+
+ *dst = *sym64;
+ }
+
+ return (dst);
+}
+
+int
+gelf_update_sym(Elf_Data *d, int ndx, GElf_Sym *gs)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Sym *sym32;
+ Elf64_Sym *sym64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || gs == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_SYM, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32) {
+ sym32 = (Elf32_Sym *) d->d_buf + ndx;
+
+ sym32->st_name = gs->st_name;
+ sym32->st_info = gs->st_info;
+ sym32->st_other = gs->st_other;
+ sym32->st_shndx = gs->st_shndx;
+
+ LIBELF_COPY_U32(sym32, gs, st_value);
+ LIBELF_COPY_U32(sym32, gs, st_size);
+ } else {
+ sym64 = (Elf64_Sym *) d->d_buf + ndx;
+
+ *sym64 = *gs;
+ }
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_syminfo.c b/linkers/elftoolchain/libelf/gelf_syminfo.c
new file mode 100644
index 0000000..2e8d9d8
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_syminfo.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_syminfo.c 1166 2010-09-04 00:54:36Z jkoshy $");
+
+GElf_Syminfo *
+gelf_getsyminfo(Elf_Data *d, int ndx, GElf_Syminfo *dst)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Syminfo *syminfo32;
+ Elf64_Syminfo *syminfo64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || dst == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_SYMINFO) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+
+ syminfo32 = (Elf32_Syminfo *) d->d_buf + ndx;
+
+ dst->si_boundto = syminfo32->si_boundto;
+ dst->si_flags = syminfo32->si_flags;
+
+ } else {
+
+ syminfo64 = (Elf64_Syminfo *) d->d_buf + ndx;
+
+ *dst = *syminfo64;
+ }
+
+ return (dst);
+}
+
+int
+gelf_update_syminfo(Elf_Data *d, int ndx, GElf_Syminfo *gs)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf32_Syminfo *syminfo32;
+ Elf64_Syminfo *syminfo64;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (d == NULL || ndx < 0 || gs == NULL ||
+ (scn = d->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_SYMINFO) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= d->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if (ec == ELFCLASS32) {
+ syminfo32 = (Elf32_Syminfo *) d->d_buf + ndx;
+
+ syminfo32->si_boundto = gs->si_boundto;
+ syminfo32->si_flags = gs->si_flags;
+
+ } else {
+ syminfo64 = (Elf64_Syminfo *) d->d_buf + ndx;
+
+ *syminfo64 = *gs;
+ }
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_symshndx.c b/linkers/elftoolchain/libelf/gelf_symshndx.c
new file mode 100644
index 0000000..ab3549c
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_symshndx.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_symshndx.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+GElf_Sym *
+gelf_getsymshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *dst,
+ Elf32_Word *shindex)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (gelf_getsym(d, ndx, dst) == 0)
+ return (NULL);
+
+ if (id == NULL || (scn = id->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL || (e != d->d_scn->s_elf) ||
+ shindex == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD ||
+ id->d_type != ELF_T_WORD) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_WORD, ec, e->e_version);
+
+ assert(msz > 0);
+
+ if (msz * ndx >= id->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ *shindex = ((Elf32_Word *) id->d_buf)[ndx];
+
+ return (dst);
+}
+
+int
+gelf_update_symshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *gs,
+ Elf32_Word xindex)
+{
+ int ec;
+ Elf *e;
+ Elf_Scn *scn;
+ size_t msz;
+ uint32_t sh_type;
+
+ if (gelf_update_sym(d, ndx, gs) == 0)
+ return (0);
+
+ if (id == NULL || (scn = id->d_scn) == NULL ||
+ (e = scn->s_elf) == NULL || (e != d->d_scn->s_elf)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ ec = e->e_class;
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (ec == ELFCLASS32)
+ sh_type = scn->s_shdr.s_shdr32.sh_type;
+ else
+ sh_type = scn->s_shdr.s_shdr64.sh_type;
+
+ if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD ||
+ d->d_type != ELF_T_WORD) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ msz = _libelf_msize(ELF_T_WORD, ec, e->e_version);
+ assert(msz > 0);
+
+ if (msz * ndx >= id->d_size) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ *(((Elf32_Word *) id->d_buf) + ndx) = xindex;
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_update_ehdr.3 b/linkers/elftoolchain/libelf/gelf_update_ehdr.3
new file mode 100644
index 0000000..f5e041d
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_update_ehdr.3
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_update_ehdr.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd August 27, 2006
+.Os
+.Dt GELF_UPDATE_EHDR 3
+.Sh NAME
+.Nm gelf_update_ehdr ,
+.Nm gelf_update_phdr ,
+.Nm gelf_update_shdr
+.Nd update underlying ELF data structures
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In gelf.h
+.Ft int
+.Fn gelf_update_ehdr "Elf *elf" "GElf_Ehdr *ehdr"
+.Ft int
+.Fn gelf_update_phdr "Elf *elf" "int ndx" "GElf_Phdr *phdr"
+.Ft int
+.Fn gelf_update_shdr "Elf_Scn *scn" "GElf_Shdr *shdr"
+.Sh DESCRIPTION
+These functions are used to update ELF data structures on the underlying
+ELF descriptor.
+Class-dependent data structures in the underlying ELF descriptor
+are updated using the data in the class-independent GElf descriptors
+and the underlying ELF data structures are marked
+.Dq dirty .
+The conversion process signals an error if the values being copied
+to the target ELF data structure would exceed representation
+limits.
+GElf descriptors are described in
+.Xr gelf 3 .
+.Pp
+Function
+.Fn gelf_update_ehdr
+updates the ELF Executable Header with the values in the
+class-independent executable header
+.Ar ehdr .
+.Pp
+Function
+.Fn gelf_update_phdr
+updates the ELF Program Header structure at index
+.Ar ndx
+with the values in the class-independent program header
+.Ar phdr .
+.Pp
+Function
+.Fn gelf_update_shdr
+updates the ELF Section Header structure associated with section
+descriptor
+.Ar scn
+with the values in argument
+.Ar shdr .
+.Sh RETURN VALUES
+These functions return a non-zero integer on success, or zero in case
+of an error.
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar elf ,
+.Ar ehdr ,
+.Ar phdr ,
+.Ar scn ,
+or
+.Ar shdr
+were NULL.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not a descriptor for an ELF object.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+had an unsupported ELF class.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar ndx
+exceeded the number of entries in the program header table.
+.It Bq Er ELF_E_ARGUMENT
+Section descriptor
+.Ar scn
+was not associated with an ELF descriptor.
+.It Bq Er ELF_E_MODE
+ELF descriptor
+.Ar elf
+was not opened for writing or updating.
+.It Bq Er ELF_E_RESOURCE
+An out of memory condition was detected.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_flagelf 3 ,
+.Xr elf_flagphdr 3 ,
+.Xr elf_flagshdr 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3 ,
+.Xr gelf_getphdr 3 ,
+.Xr gelf_getshdr 3
diff --git a/linkers/elftoolchain/libelf/gelf_xlate.c b/linkers/elftoolchain/libelf/gelf_xlate.c
new file mode 100644
index 0000000..6cdf705
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_xlate.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <gelf.h>
+#include <libelf.h>
+#include <string.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: gelf_xlate.c 1678 2011-07-28 04:36:34Z jkoshy $");
+
+Elf_Data *
+elf32_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned int encoding)
+{
+ return _libelf_xlate(dst, src, encoding, ELFCLASS32, ELF_TOFILE);
+}
+
+Elf_Data *
+elf64_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned int encoding)
+{
+ return _libelf_xlate(dst, src, encoding, ELFCLASS64, ELF_TOFILE);
+}
+
+Elf_Data *
+elf32_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned int encoding)
+{
+ return _libelf_xlate(dst, src, encoding, ELFCLASS32, ELF_TOMEMORY);
+}
+
+Elf_Data *
+elf64_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned int encoding)
+{
+ return _libelf_xlate(dst, src, encoding, ELFCLASS64, ELF_TOMEMORY);
+}
+
+Elf_Data *
+gelf_xlatetom(Elf *e, Elf_Data *dst, const Elf_Data *src,
+ unsigned int encoding)
+{
+ if (e != NULL)
+ return (_libelf_xlate(dst, src, encoding, e->e_class,
+ ELF_TOMEMORY));
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+}
+
+Elf_Data *
+gelf_xlatetof(Elf *e, Elf_Data *dst, const Elf_Data *src,
+ unsigned int encoding)
+{
+ if (e != NULL)
+ return (_libelf_xlate(dst, src, encoding, e->e_class,
+ ELF_TOFILE));
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+}
diff --git a/linkers/elftoolchain/libelf/gelf_xlatetof.3 b/linkers/elftoolchain/libelf/gelf_xlatetof.3
new file mode 100644
index 0000000..ca90002
--- /dev/null
+++ b/linkers/elftoolchain/libelf/gelf_xlatetof.3
@@ -0,0 +1,247 @@
+.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``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 Joseph Koshy 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.
+.\"
+.\" $Id: gelf_xlatetof.3 189 2008-07-20 10:38:08Z jkoshy $
+.\"
+.Dd July 24, 2006
+.Os
+.Dt GELF_XLATETOF 3
+.Sh NAME
+.Nm elf32_xlate ,
+.Nm elf64_xlate ,
+.Nm gelf_xlate
+.Nd translate data between files and memory
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft "Elf_Data *"
+.Fn elf32_xlatetof "Elf_Data *dst" "Elf_Data *src" "unsigned int encode"
+.Ft "Elf_Data *"
+.Fn elf32_xlatetom "Elf_Data *dst" "Elf_Data *src" "unsigned int encode"
+.Ft "Elf_Data *"
+.Fn elf64_xlatetof "Elf_Data *dst" "Elf_Data *src" "unsigned int encode"
+.Ft "Elf_Data *"
+.Fn elf64_xlatetom "Elf_Data *dst" "Elf_Data *src" "unsigned int encode"
+.In gelf.h
+.Ft "Elf_Data *"
+.Fo gelf_xlatetof
+.Fa "Elf *elf"
+.Fa "Elf_Data *dst"
+.Fa "Elf_Data *src"
+.Fa "unsigned int encode"
+.Fc
+.Ft "Elf_Data *"
+.Fo gelf_xlatetom
+.Fa "Elf *elf"
+.Fa "Elf_Data *dst"
+.Fa "Elf_Data *src"
+.Fa "unsigned int encode"
+.Fc
+.Sh DESCRIPTION
+These functions translate between the file and memory representations
+of ELF data structures.
+The in-memory representation of an ELF data structure would confirm to
+the byte ordering and data alignment restrictions dictated by the host
+processor.
+A file representation of the same data structure could use a non-native byte
+ordering and in addition may be laid out differently with the file.
+.Pp
+Functions
+.Fn elf32_xlatetom ,
+.Fn elf64_xlatetom ,
+and
+.Fn gelf_xlatetom
+translate data from file representations to native, in-memory representations.
+Functions
+.Fn elf32_xlatetof ,
+.Fn elf64_xlatetof ,
+and
+.Fn gelf_xlatetof
+translate data from in-memory representations to file representations.
+.Pp
+Argument
+.Ar src
+denotes an
+.Vt Elf_Data
+descriptor describing the source to be translated.
+The following elements of the descriptor need to be set before
+invoking these functions:
+.Bl -hang -offset indent
+.It Va d_buf
+Set to a valid pointer value denoting the beginning of the data area
+to be translated.
+.It Va d_size
+Set to the total size in bytes of the source data area to be
+translated.
+.It Va d_type
+Set to the type of the source data being translated.
+This value is one of the values defined in the
+.Vt Elf_Type
+enumeration.
+The
+.Vt Elf_Type
+enumeration is described in
+.Xr elf 3 .
+.It Va d_version
+Set to the version number of the ELF data structures being
+translated.
+Currently only version
+.Dv EV_CURRENT
+is supported.
+.El
+.Pp
+Argument
+.Ar dst
+describes the destination buffer.
+The following elements of the
+.Vt Elf_Data
+descriptor need to be set before invoking these functions:
+.Bl -hang -offset indent
+.It Va d_buf
+Set to a valid pointer value that denotes the start of the destination
+buffer that will hold translated data.
+This value may be the same as that of the source buffer, in which case
+an in-place conversion will be attempted.
+.It Va d_size
+Set to the size of the destination buffer in bytes.
+This value will be modified if the function call succeeds.
+.It Va d_version
+Set to the desired version number of the destination.
+Currently only version
+.Dv EV_CURRENT
+is supported.
+.El
+.Pp
+These translations routines allow the source and destination buffers
+to coincide, in which case an in-place translation will be done
+if the destination is large enough to hold the translated data.
+Other kinds of overlap between the source and destination buffers
+are not permitted.
+.Pp
+On successful completion of the translation request the following
+fields of the
+.Ar dst
+descriptor would be modified:
+.Bl -hang -offset indent
+.It Va d_size
+Set to the size in bytes of the translated data.
+.It Va d_type
+Set to the
+.Va d_type
+value of the source data descriptor.
+.El
+.Pp
+Argument
+.Ar encode
+specifies the encoding in which the file objects are represented.
+It must be one of:
+.Bl -hang -offset indent
+.It Dv ELFDATANONE
+File objects use the library's native byte ordering.
+.It Dv ELFDATA2LSB
+File objects use a little-endian ordering.
+.It Dv ELFDATA2MSB
+File objects use a big-endian ordering.
+.El
+.Pp
+The functions
+.Fn gelf_xlatetof
+and
+.Fn gelf_xlatetom
+select the appropriate 32 or 64 bit translations based on the class of argument
+.Ar elf .
+.Sh RETURN VALUES
+These functions return argument
+.Ar dst
+if successful, or NULL in case of an error.
+.Sh EXAMPLES
+TODO
+.Sh ERRORS
+These functions may fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+One of arguments
+.Ar src ,
+.Ar dst
+or
+.Ar elf
+was NULL.
+.It Bq Er ELF_E_ARGUMENT
+Arguments
+.Ar src
+and
+.Ar dst
+were equal.
+.It Bq Er ELF_E_ARGUMENT
+The desired encoding parameter was not one of
+.Dv ELFDATANONE ,
+.Dv ELFDATA2LSB
+or
+.Dv ELFDATA2MSB .
+.It Bq Er ELF_E_ARGUMENT
+The
+.Ar d_type
+field of argument
+.Ar src
+specified an unsupported type.
+.It Bq Er ELF_E_DATA
+The
+.Ar src
+argument specified a buffer size that was not an integral multiple of
+its underlying type.
+.It Bq Er ELF_E_DATA
+The
+.Ar dst
+argument specified a buffer size that was too small.
+.It Bq Er ELF_E_DATA
+Argument
+.Ar dst
+specified a destination buffer that overlaps with the source
+buffer.
+.It Bq Er ELF_E_DATA
+The destination buffer for a conversion to memory had an alignment
+inappropriate for the underlying ELF type.
+.It Bq Er ELF_E_DATA
+The source buffer for a conversion to file had an alignment
+inappropriate for the underlying ELF type.
+.It Bq Er ELF_E_UNIMPL
+The version numbers for arguments
+.Ar dst
+and
+.Ar src
+were not identical.
+.It Bq Er ELF_E_UNIMPL
+The argument
+.Ar src
+requested conversion for a type which is not currently
+supported.
+.It Bq Er ELF_E_VERSION
+Argument
+.Ar src
+specified an unsupported version number.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_getdata 3 ,
+.Xr gelf 3
diff --git a/linkers/elftoolchain/libelf/libelf.h b/linkers/elftoolchain/libelf/libelf.h
new file mode 100644
index 0000000..60b0f1c
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf.h
@@ -0,0 +1,258 @@
+/*-
+ * Copyright (c) 2006,2008-2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: libelf.h 1345 2011-01-01 11:17:52Z jkoshy $
+ */
+
+#ifndef _LIBELF_H_
+#define _LIBELF_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <elfdefinitions.h>
+
+/* Library private data structures */
+typedef struct _Elf Elf;
+typedef struct _Elf_Scn Elf_Scn;
+
+/* File types */
+typedef enum {
+ ELF_K_NONE = 0,
+ ELF_K_AR, /* `ar' archives */
+ ELF_K_COFF, /* COFF files (unsupported) */
+ ELF_K_ELF, /* ELF files */
+ ELF_K_NUM
+} Elf_Kind;
+
+#define ELF_K_FIRST ELF_K_NONE
+#define ELF_K_LAST ELF_K_NUM
+
+/* Data types */
+typedef enum {
+ ELF_T_ADDR,
+ ELF_T_BYTE,
+ ELF_T_CAP,
+ ELF_T_DYN,
+ ELF_T_EHDR,
+ ELF_T_HALF,
+ ELF_T_LWORD,
+ ELF_T_MOVE,
+ ELF_T_MOVEP,
+ ELF_T_NOTE,
+ ELF_T_OFF,
+ ELF_T_PHDR,
+ ELF_T_REL,
+ ELF_T_RELA,
+ ELF_T_SHDR,
+ ELF_T_SWORD,
+ ELF_T_SXWORD,
+ ELF_T_SYMINFO,
+ ELF_T_SYM,
+ ELF_T_VDEF,
+ ELF_T_VNEED,
+ ELF_T_WORD,
+ ELF_T_XWORD,
+ ELF_T_GNUHASH, /* GNU style hash tables. */
+ ELF_T_NUM
+} Elf_Type;
+
+#define ELF_T_FIRST ELF_T_ADDR
+#define ELF_T_LAST ELF_T_GNUHASH
+
+/* Commands */
+typedef enum {
+ ELF_C_NULL = 0,
+ ELF_C_CLR,
+ ELF_C_FDDONE,
+ ELF_C_FDREAD,
+ ELF_C_RDWR,
+ ELF_C_READ,
+ ELF_C_SET,
+ ELF_C_WRITE,
+ ELF_C_NUM
+} Elf_Cmd;
+
+#define ELF_C_FIRST ELF_C_NULL
+#define ELF_C_LAST ELF_C_NUM
+
+/*
+ * An `Elf_Data' structure describes data in an
+ * ELF section.
+ */
+typedef struct _Elf_Data {
+ /*
+ * `Public' members that are part of the ELF(3) API.
+ */
+ uint64_t d_align;
+ void *d_buf;
+ uint64_t d_off;
+ uint64_t d_size;
+ Elf_Type d_type;
+ unsigned int d_version;
+
+ /*
+ * Members that are not part of the public API.
+ */
+ Elf_Scn *d_scn; /* containing section */
+ unsigned int d_flags;
+ STAILQ_ENTRY(_Elf_Data) d_next;
+} Elf_Data;
+
+/*
+ * An `Elf_Arhdr' structure describes an archive
+ * header.
+ */
+typedef struct {
+ time_t ar_date;
+ char *ar_name; /* archive member name */
+ gid_t ar_gid;
+ mode_t ar_mode;
+ char *ar_rawname; /* 'raw' member name */
+ size_t ar_size;
+ uid_t ar_uid;
+
+ /*
+ * Members that are not part of the public API.
+ */
+ int ar_flags;
+} Elf_Arhdr;
+
+/*
+ * An `Elf_Arsym' describes an entry in the archive
+ * symbol table.
+ */
+typedef struct {
+ off_t as_off; /* byte offset to member's header */
+ unsigned long as_hash; /* elf_hash() value for name */
+ char *as_name; /* null terminated symbol name */
+} Elf_Arsym;
+
+/*
+ * Error numbers.
+ */
+
+enum Elf_Error {
+ ELF_E_NONE, /* No error */
+ ELF_E_ARCHIVE, /* Malformed ar(1) archive */
+ ELF_E_ARGUMENT, /* Invalid argument */
+ ELF_E_CLASS, /* Mismatched ELF class */
+ ELF_E_DATA, /* Invalid data descriptor */
+ ELF_E_HEADER, /* Missing or malformed ELF header */
+ ELF_E_IO, /* I/O error */
+ ELF_E_LAYOUT, /* Layout constraint violation */
+ ELF_E_MODE, /* Wrong mode for ELF descriptor */
+ ELF_E_RANGE, /* Value out of range */
+ ELF_E_RESOURCE, /* Resource exhaustion */
+ ELF_E_SECTION, /* Invalid section descriptor */
+ ELF_E_SEQUENCE, /* API calls out of sequence */
+ ELF_E_UNIMPL, /* Feature is unimplemented */
+ ELF_E_VERSION, /* Unknown API version */
+ ELF_E_NUM /* Max error number */
+};
+
+/*
+ * Flags defined by the API.
+ */
+
+#define ELF_F_LAYOUT 0x001U /* application will layout the file */
+#define ELF_F_DIRTY 0x002U /* a section or ELF file is dirty */
+
+/* ELF(3) API extensions. */
+#define ELF_F_ARCHIVE 0x100U /* archive creation */
+#define ELF_F_ARCHIVE_SYSV 0x200U /* SYSV style archive */
+
+__BEGIN_DECLS
+Elf *elf_begin(int _fd, Elf_Cmd _cmd, Elf *_elf);
+int elf_cntl(Elf *_elf, Elf_Cmd _cmd);
+int elf_end(Elf *_elf);
+const char *elf_errmsg(int _error);
+int elf_errno(void);
+void elf_fill(int _fill);
+unsigned int elf_flagarhdr(Elf_Arhdr *_arh, Elf_Cmd _cmd,
+ unsigned int _flags);
+unsigned int elf_flagdata(Elf_Data *_data, Elf_Cmd _cmd,
+ unsigned int _flags);
+unsigned int elf_flagehdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags);
+unsigned int elf_flagelf(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags);
+unsigned int elf_flagphdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags);
+unsigned int elf_flagscn(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags);
+unsigned int elf_flagshdr(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags);
+Elf_Arhdr *elf_getarhdr(Elf *_elf);
+Elf_Arsym *elf_getarsym(Elf *_elf, size_t *_ptr);
+off_t elf_getbase(Elf *_elf);
+Elf_Data *elf_getdata(Elf_Scn *, Elf_Data *);
+char *elf_getident(Elf *_elf, size_t *_ptr);
+int elf_getphdrnum(Elf *_elf, size_t *_dst);
+int elf_getphnum(Elf *_elf, size_t *_dst); /* Deprecated */
+Elf_Scn *elf_getscn(Elf *_elf, size_t _index);
+int elf_getshdrnum(Elf *_elf, size_t *_dst);
+int elf_getshnum(Elf *_elf, size_t *_dst); /* Deprecated */
+int elf_getshdrstrndx(Elf *_elf, size_t *_dst);
+int elf_getshstrndx(Elf *_elf, size_t *_dst); /* Deprecated */
+unsigned long elf_hash(const char *_name);
+Elf_Kind elf_kind(Elf *_elf);
+Elf *elf_memory(char *_image, size_t _size);
+size_t elf_ndxscn(Elf_Scn *_scn);
+Elf_Data *elf_newdata(Elf_Scn *_scn);
+Elf_Scn *elf_newscn(Elf *_elf);
+Elf_Scn *elf_nextscn(Elf *_elf, Elf_Scn *_scn);
+Elf_Cmd elf_next(Elf *_elf);
+off_t elf_rand(Elf *_elf, off_t _off);
+Elf_Data *elf_rawdata(Elf_Scn *_scn, Elf_Data *_data);
+char *elf_rawfile(Elf *_elf, size_t *_size);
+int elf_setshstrndx(Elf *_elf, size_t _shnum);
+char *elf_strptr(Elf *_elf, size_t _section, size_t _offset);
+off_t elf_update(Elf *_elf, Elf_Cmd _cmd);
+unsigned int elf_version(unsigned int _version);
+
+long elf32_checksum(Elf *_elf);
+size_t elf32_fsize(Elf_Type _type, size_t _count,
+ unsigned int _version);
+Elf32_Ehdr *elf32_getehdr(Elf *_elf);
+Elf32_Phdr *elf32_getphdr(Elf *_elf);
+Elf32_Shdr *elf32_getshdr(Elf_Scn *_scn);
+Elf32_Ehdr *elf32_newehdr(Elf *_elf);
+Elf32_Phdr *elf32_newphdr(Elf *_elf, size_t _count);
+Elf_Data *elf32_xlatetof(Elf_Data *_dst, const Elf_Data *_src,
+ unsigned int _enc);
+Elf_Data *elf32_xlatetom(Elf_Data *_dst, const Elf_Data *_src,
+ unsigned int _enc);
+
+long elf64_checksum(Elf *_elf);
+size_t elf64_fsize(Elf_Type _type, size_t _count,
+ unsigned int _version);
+Elf64_Ehdr *elf64_getehdr(Elf *_elf);
+Elf64_Phdr *elf64_getphdr(Elf *_elf);
+Elf64_Shdr *elf64_getshdr(Elf_Scn *_scn);
+Elf64_Ehdr *elf64_newehdr(Elf *_elf);
+Elf64_Phdr *elf64_newphdr(Elf *_elf, size_t _count);
+Elf_Data *elf64_xlatetof(Elf_Data *_dst, const Elf_Data *_src,
+ unsigned int _enc);
+Elf_Data *elf64_xlatetom(Elf_Data *_dst, const Elf_Data *_src,
+ unsigned int _enc);
+__END_DECLS
+
+#endif /* _LIBELF_H_ */
diff --git a/linkers/elftoolchain/libelf/libelf_align.c b/linkers/elftoolchain/libelf/libelf_align.c
new file mode 100644
index 0000000..55a65f9
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_align.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_align.c 1169 2010-09-04 01:06:31Z jkoshy $");
+
+struct align {
+ int a32;
+ int a64;
+};
+
+#ifdef __GNUC__
+#define MALIGN(N) { \
+ .a32 = __alignof__(Elf32_##N), \
+ .a64 = __alignof__(Elf64_##N) \
+ }
+#define MALIGN64(V) { \
+ .a32 = 0, \
+ .a64 = __alignof__(Elf64_##V) \
+ }
+#define MALIGN_WORD() { \
+ .a32 = __alignof__(int32_t), \
+ .a64 = __alignof__(int64_t) \
+ }
+#else
+#error Need the __alignof__ builtin.
+#endif
+#define UNSUPPORTED() { \
+ .a32 = 0, \
+ .a64 = 0 \
+ }
+
+static struct align malign[ELF_T_NUM] = {
+ [ELF_T_ADDR] = MALIGN(Addr),
+ [ELF_T_BYTE] = { .a32 = 1, .a64 = 1 },
+ [ELF_T_CAP] = MALIGN(Cap),
+ [ELF_T_DYN] = MALIGN(Dyn),
+ [ELF_T_EHDR] = MALIGN(Ehdr),
+ [ELF_T_HALF] = MALIGN(Half),
+ [ELF_T_LWORD] = MALIGN(Lword),
+ [ELF_T_MOVE] = MALIGN(Move),
+ [ELF_T_MOVEP] = UNSUPPORTED(),
+ [ELF_T_NOTE] = MALIGN(Nhdr),
+ [ELF_T_OFF] = MALIGN(Off),
+ [ELF_T_PHDR] = MALIGN(Phdr),
+ [ELF_T_REL] = MALIGN(Rel),
+ [ELF_T_RELA] = MALIGN(Rela),
+ [ELF_T_SHDR] = MALIGN(Shdr),
+ [ELF_T_SWORD] = MALIGN(Sword),
+ [ELF_T_SXWORD] = MALIGN64(Sxword),
+ [ELF_T_SYM] = MALIGN(Sym),
+ [ELF_T_SYMINFO] = MALIGN(Syminfo),
+ [ELF_T_VDEF] = MALIGN(Verdef),
+ [ELF_T_VNEED] = MALIGN(Verneed),
+ [ELF_T_WORD] = MALIGN(Word),
+ [ELF_T_XWORD] = MALIGN64(Xword),
+ [ELF_T_GNUHASH] = MALIGN_WORD()
+};
+
+int
+_libelf_malign(Elf_Type t, int elfclass)
+{
+ if (t >= ELF_T_NUM || (int) t < 0)
+ return (0);
+
+ return (elfclass == ELFCLASS32 ? malign[t].a32 :
+ malign[t].a64);
+}
+
+#define FALIGN(A32,A64) { .a32 = (A32), .a64 = (A64) }
+
+static struct align falign[ELF_T_NUM] = {
+ [ELF_T_ADDR] = FALIGN(4,8),
+ [ELF_T_BYTE] = FALIGN(1,1),
+ [ELF_T_CAP] = FALIGN(4,8),
+ [ELF_T_DYN] = FALIGN(4,8),
+ [ELF_T_EHDR] = FALIGN(4,8),
+ [ELF_T_HALF] = FALIGN(2,2),
+ [ELF_T_LWORD] = FALIGN(8,8),
+ [ELF_T_MOVE] = FALIGN(8,8),
+ [ELF_T_MOVEP] = UNSUPPORTED(),
+ [ELF_T_NOTE] = FALIGN(4,4),
+ [ELF_T_OFF] = FALIGN(4,8),
+ [ELF_T_PHDR] = FALIGN(4,8),
+ [ELF_T_REL] = FALIGN(4,8),
+ [ELF_T_RELA] = FALIGN(4,8),
+ [ELF_T_SHDR] = FALIGN(4,8),
+ [ELF_T_SWORD] = FALIGN(4,4),
+ [ELF_T_SXWORD] = FALIGN(0,8),
+ [ELF_T_SYM] = FALIGN(4,8),
+ [ELF_T_SYMINFO] = FALIGN(2,2),
+ [ELF_T_VDEF] = FALIGN(4,4),
+ [ELF_T_VNEED] = FALIGN(4,4),
+ [ELF_T_WORD] = FALIGN(4,4),
+ [ELF_T_XWORD] = FALIGN(0,8),
+ [ELF_T_GNUHASH] = FALIGN(4,8)
+};
+
+int
+_libelf_falign(Elf_Type t, int elfclass)
+{
+ if (t >= ELF_T_NUM || (int) t < 0)
+ return (0);
+
+ return (elfclass == ELFCLASS32 ? falign[t].a32 :
+ falign[t].a64);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_allocate.c b/linkers/elftoolchain/libelf/libelf_allocate.c
new file mode 100644
index 0000000..a753e8e
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_allocate.c
@@ -0,0 +1,214 @@
+/*-
+ * Copyright (c) 2006,2008,2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Internal APIs
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/errno.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <libelf.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_allocate.c 1341 2011-01-01 04:28:29Z jkoshy $");
+
+Elf *
+_libelf_allocate_elf(void)
+{
+ Elf *e;
+
+ if ((e = malloc(sizeof(*e))) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, errno);
+ return NULL;
+ }
+
+ e->e_activations = 1;
+ e->e_hdr.e_rawhdr = NULL;
+ e->e_byteorder = ELFDATANONE;
+ e->e_class = ELFCLASSNONE;
+ e->e_cmd = ELF_C_NULL;
+ e->e_fd = -1;
+ e->e_flags = 0;
+ e->e_kind = ELF_K_NONE;
+ e->e_parent = NULL;
+ e->e_rawfile = NULL;
+ e->e_rawsize = 0;
+ e->e_version = LIBELF_PRIVATE(version);
+
+ (void) memset(&e->e_u, 0, sizeof(e->e_u));
+
+ return (e);
+}
+
+void
+_libelf_init_elf(Elf *e, Elf_Kind kind)
+{
+ assert(e != NULL);
+ assert(e->e_kind == ELF_K_NONE);
+
+ e->e_kind = kind;
+
+ switch (kind) {
+ case ELF_K_ELF:
+ STAILQ_INIT(&e->e_u.e_elf.e_scn);
+ break;
+ default:
+ break;
+ }
+}
+
+#define FREE(P) do { \
+ if (P) \
+ free(P); \
+ } while (0)
+
+
+Elf *
+_libelf_release_elf(Elf *e)
+{
+ Elf_Arhdr *arh;
+
+ switch (e->e_kind) {
+ case ELF_K_AR:
+ FREE(e->e_u.e_ar.e_symtab);
+ break;
+
+ case ELF_K_ELF:
+ switch (e->e_class) {
+ case ELFCLASS32:
+ FREE(e->e_u.e_elf.e_ehdr.e_ehdr32);
+ FREE(e->e_u.e_elf.e_phdr.e_phdr32);
+ break;
+ case ELFCLASS64:
+ FREE(e->e_u.e_elf.e_ehdr.e_ehdr64);
+ FREE(e->e_u.e_elf.e_phdr.e_phdr64);
+ break;
+ }
+
+ assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn));
+
+ if (e->e_flags & LIBELF_F_AR_HEADER) {
+ arh = e->e_hdr.e_arhdr;
+ FREE(arh->ar_name);
+ FREE(arh->ar_rawname);
+ free(arh);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ free(e);
+
+ return (NULL);
+}
+
+Elf_Data *
+_libelf_allocate_data(Elf_Scn *s)
+{
+ Elf_Data *d;
+
+ if ((d = calloc((size_t) 1, sizeof(Elf_Data))) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ d->d_scn = s;
+
+ return (d);
+}
+
+Elf_Data *
+_libelf_release_data(Elf_Data *d)
+{
+
+ if (d->d_flags & LIBELF_F_DATA_MALLOCED)
+ free(d->d_buf);
+
+ free(d);
+
+ return (NULL);
+}
+
+Elf_Scn *
+_libelf_allocate_scn(Elf *e, size_t ndx)
+{
+ Elf_Scn *s;
+
+ if ((s = calloc((size_t) 1, sizeof(Elf_Scn))) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, errno);
+ return (NULL);
+ }
+
+ s->s_elf = e;
+ s->s_ndx = ndx;
+
+ STAILQ_INIT(&s->s_data);
+ STAILQ_INIT(&s->s_rawdata);
+
+ STAILQ_INSERT_TAIL(&e->e_u.e_elf.e_scn, s, s_next);
+
+ return (s);
+}
+
+Elf_Scn *
+_libelf_release_scn(Elf_Scn *s)
+{
+ Elf *e;
+ Elf_Data *d, *td;
+
+ assert(s != NULL);
+
+ STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) {
+ STAILQ_REMOVE(&s->s_data, d, _Elf_Data, d_next);
+ d = _libelf_release_data(d);
+ }
+
+ STAILQ_FOREACH_SAFE(d, &s->s_rawdata, d_next, td) {
+ assert((d->d_flags & LIBELF_F_DATA_MALLOCED) == 0);
+ STAILQ_REMOVE(&s->s_rawdata, d, _Elf_Data, d_next);
+ d = _libelf_release_data(d);
+ }
+
+ e = s->s_elf;
+
+ assert(e != NULL);
+
+ STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn, s_next);
+
+ free(s);
+
+ return (NULL);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_ar.c b/linkers/elftoolchain/libelf/libelf_ar.c
new file mode 100644
index 0000000..14b383d
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_ar.c
@@ -0,0 +1,461 @@
+/*-
+ * Copyright (c) 2006,2008,2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <libelf.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelf.h"
+#include "_libelf_ar.h"
+
+LIBELF_VCSID("$Id: libelf_ar.c 1341 2011-01-01 04:28:29Z jkoshy $");
+
+#define LIBELF_NALLOC_SIZE 16
+
+/*
+ * `ar' archive handling.
+ *
+ * `ar' archives start with signature `ARMAG'. Each archive member is
+ * preceded by a header containing meta-data for the member. This
+ * header is described in <ar.h> (struct ar_hdr). The header always
+ * starts on an even address. File data is padded with "\n"
+ * characters to keep this invariant.
+ *
+ * Special considerations for `ar' archives:
+ *
+ * There are two variants of the `ar' archive format: traditional BSD
+ * and SVR4. These differ in the way long file names are treated, and
+ * in the layout of the archive symbol table.
+ *
+ * The `ar' header only has space for a 16 character file name.
+ *
+ * In the SVR4 format, file names are terminated with a '/', so this
+ * effectively leaves 15 characters for the actual file name. Longer
+ * file names stored in a separate 'string table' and referenced
+ * indirectly from the name field. The string table itself appears as
+ * an archive member with name "// ". An `indirect' file name in an
+ * `ar' header matches the pattern "/[0-9]*". The digits form a
+ * decimal number that corresponds to a byte offset into the string
+ * table where the actual file name of the object starts. Strings in
+ * the string table are padded to start on even addresses.
+ *
+ * In the BSD format, file names can be upto 16 characters. File
+ * names shorter than 16 characters are padded to 16 characters using
+ * (ASCII) space characters. File names with embedded spaces and file
+ * names longer than 16 characters are stored immediately after the
+ * archive header and the name field set to a special indirect name
+ * matching the pattern "#1/[0-9]+". The digits form a decimal number
+ * that corresponds to the actual length of the file name following
+ * the archive header. The content of the archive member immediately
+ * follows the file name, and the size field of the archive member
+ * holds the sum of the sizes of the member and of the appended file
+ * name.
+ *
+ * Archives may also have a symbol table (see ranlib(1)), mapping
+ * program symbols to object files inside the archive.
+ *
+ * In the SVR4 format, a symbol table uses a file name of "/ " in its
+ * archive header. The symbol table is structured as:
+ * - a 4-byte count of entries stored as a binary value, MSB first
+ * - 'n' 4-byte offsets, stored as binary values, MSB first
+ * - 'n' NUL-terminated strings, for ELF symbol names, stored unpadded.
+ *
+ * In the BSD format, the symbol table uses a file name of "__.SYMDEF".
+ * It is structured as two parts:
+ * - The first part is an array of "ranlib" structures preceded by
+ * the size of the array in bytes. Each "ranlib" structure
+ * describes one symbol. Each structure contains an offset into
+ * the string table for the symbol name, and a file offset into the
+ * archive for the member defining the symbol.
+ * - The second part is a string table containing NUL-terminated
+ * strings, preceded by the size of the string table in bytes.
+ *
+ * If the symbol table and string table are is present in an archive
+ * they must be the very first objects and in that order.
+ */
+
+
+/*
+ * Retrieve an archive header descriptor.
+ */
+
+Elf_Arhdr *
+_libelf_ar_gethdr(Elf *e)
+{
+ Elf *parent;
+ char *namelen;
+ Elf_Arhdr *eh;
+ size_t n, nlen;
+ struct ar_hdr *arh;
+
+ if ((parent = e->e_parent) == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ assert((e->e_flags & LIBELF_F_AR_HEADER) == 0);
+
+ arh = (struct ar_hdr *) (uintptr_t) e->e_hdr.e_rawhdr;
+
+ assert((uintptr_t) arh >= (uintptr_t) parent->e_rawfile + SARMAG);
+ assert((uintptr_t) arh <= (uintptr_t) parent->e_rawfile +
+ parent->e_rawsize - sizeof(struct ar_hdr));
+
+ if ((eh = malloc(sizeof(Elf_Arhdr))) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ e->e_hdr.e_arhdr = eh;
+ e->e_flags |= LIBELF_F_AR_HEADER;
+
+ eh->ar_name = eh->ar_rawname = NULL;
+
+ if ((eh->ar_name = _libelf_ar_get_translated_name(arh, parent)) ==
+ NULL)
+ goto error;
+
+ if (_libelf_ar_get_number(arh->ar_uid, sizeof(arh->ar_uid), 10,
+ &n) == 0)
+ goto error;
+ eh->ar_uid = (uid_t) n;
+
+ if (_libelf_ar_get_number(arh->ar_gid, sizeof(arh->ar_gid), 10,
+ &n) == 0)
+ goto error;
+ eh->ar_gid = (gid_t) n;
+
+ if (_libelf_ar_get_number(arh->ar_mode, sizeof(arh->ar_mode), 8,
+ &n) == 0)
+ goto error;
+ eh->ar_mode = (mode_t) n;
+
+ if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10,
+ &n) == 0)
+ goto error;
+
+ /*
+ * Get the true size of the member if extended naming is being used.
+ */
+ if (IS_EXTENDED_BSD_NAME(arh->ar_name)) {
+ namelen = arh->ar_name +
+ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
+ if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) -
+ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nlen) == 0)
+ goto error;
+ n -= nlen;
+ }
+
+ eh->ar_size = n;
+
+ if ((eh->ar_rawname = _libelf_ar_get_raw_name(arh)) == NULL)
+ goto error;
+
+ eh->ar_flags = 0;
+
+ return (eh);
+
+ error:
+ if (eh) {
+ if (eh->ar_name)
+ free(eh->ar_name);
+ if (eh->ar_rawname)
+ free(eh->ar_rawname);
+ free(eh);
+ }
+
+ e->e_flags &= ~LIBELF_F_AR_HEADER;
+ e->e_hdr.e_rawhdr = (char *) arh;
+
+ return (NULL);
+}
+
+Elf *
+_libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
+{
+ Elf *e;
+ char *member, *namelen;
+ size_t nsz, sz;
+ off_t next;
+ struct ar_hdr *arh;
+
+ assert(elf->e_kind == ELF_K_AR);
+
+ next = elf->e_u.e_ar.e_next;
+
+ /*
+ * `next' is only set to zero by elf_next() when the last
+ * member of an archive is processed.
+ */
+ if (next == (off_t) 0)
+ return (NULL);
+
+ assert((next & 1) == 0);
+
+ arh = (struct ar_hdr *) (elf->e_rawfile + next);
+
+ /*
+ * Retrieve the size of the member.
+ */
+ if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10,
+ &sz) == 0) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
+ /*
+ * Adjust the size field for members in BSD archives using
+ * extended naming.
+ */
+ if (IS_EXTENDED_BSD_NAME(arh->ar_name)) {
+ namelen = arh->ar_name +
+ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
+ if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) -
+ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nsz) == 0) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
+ member = (char *) (arh + 1) + nsz;
+ sz -= nsz;
+ } else
+ member = (char *) (arh + 1);
+
+
+ if ((e = elf_memory((char *) member, sz)) == NULL)
+ return (NULL);
+
+ e->e_fd = fd;
+ e->e_cmd = c;
+ e->e_hdr.e_rawhdr = (char *) arh;
+
+ elf->e_u.e_ar.e_nchildren++;
+ e->e_parent = elf;
+
+ return (e);
+}
+
+/*
+ * A BSD-style ar(1) symbol table has the following layout:
+ *
+ * - A count of bytes used by the following array of 'ranlib'
+ * structures, stored as a 'long'.
+ * - An array of 'ranlib' structures. Each array element is
+ * two 'long's in size.
+ * - A count of bytes used for the following symbol table.
+ * - The symbol table itself.
+ */
+
+/*
+ * A helper macro to read in a 'long' value from the archive. We use
+ * memcpy() since the source pointer may be misaligned with respect to
+ * the natural alignment for a C 'long'.
+ */
+#define GET_LONG(P, V)do { \
+ memcpy(&(V), (P), sizeof(long)); \
+ (P) += sizeof(long); \
+ } while (0)
+
+Elf_Arsym *
+_libelf_ar_process_bsd_symtab(Elf *e, size_t *count)
+{
+ Elf_Arsym *symtab, *sym;
+ unsigned char *end, *p, *p0, *s, *s0;
+ const unsigned int entrysize = 2 * sizeof(long);
+ long arraysize, fileoffset, n, nentries, stroffset, strtabsize;
+
+ assert(e != NULL);
+ assert(count != NULL);
+ assert(e->e_u.e_ar.e_symtab == NULL);
+
+ symtab = NULL;
+
+ /*
+ * The BSD symbol table always contains the count fields even
+ * if there are no entries in it.
+ */
+ if (e->e_u.e_ar.e_rawsymtabsz < 2 * sizeof(long))
+ goto symtaberror;
+
+ p = p0 = (unsigned char *) e->e_u.e_ar.e_rawsymtab;
+ end = p0 + e->e_u.e_ar.e_rawsymtabsz;
+
+ /*
+ * Retrieve the size of the array of ranlib descriptors and
+ * check it for validity.
+ */
+ GET_LONG(p, arraysize);
+
+ if (p0 + arraysize >= end || (arraysize % entrysize != 0))
+ goto symtaberror;
+
+ /*
+ * Check the value of the string table size.
+ */
+ s = p + arraysize;
+ GET_LONG(s, strtabsize);
+
+ s0 = s; /* Start of string table. */
+ if (s0 + strtabsize > end)
+ goto symtaberror;
+
+ nentries = arraysize / entrysize;
+
+ /*
+ * Allocate space for the returned Elf_Arsym array.
+ */
+ if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries + 1))) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ /* Read in symbol table entries. */
+ for (n = 0, sym = symtab; n < nentries; n++, sym++) {
+ GET_LONG(p, stroffset);
+ GET_LONG(p, fileoffset);
+
+ s = s0 + stroffset;
+
+ if (s >= end)
+ goto symtaberror;
+
+ sym->as_off = fileoffset;
+ sym->as_hash = elf_hash((char *) s);
+ sym->as_name = (char *) s;
+ }
+
+ /* Fill up the sentinel entry. */
+ sym->as_name = NULL;
+ sym->as_hash = ~0UL;
+ sym->as_off = (off_t) 0;
+
+ /* Remember the processed symbol table. */
+ e->e_u.e_ar.e_symtab = symtab;
+
+ *count = e->e_u.e_ar.e_symtabsz = nentries + 1;
+
+ return (symtab);
+
+symtaberror:
+ if (symtab)
+ free(symtab);
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+}
+
+/*
+ * An SVR4-style ar(1) symbol table has the following layout:
+ *
+ * - The first 4 bytes are a binary count of the number of entries in the
+ * symbol table, stored MSB-first.
+ * - Then there are 'n' 4-byte binary offsets, also stored MSB first.
+ * - Following this, there are 'n' null-terminated strings.
+ */
+
+#define GET_WORD(P, V) do { \
+ (V) = 0; \
+ (V) = (P)[0]; (V) <<= 8; \
+ (V) += (P)[1]; (V) <<= 8; \
+ (V) += (P)[2]; (V) <<= 8; \
+ (V) += (P)[3]; \
+ } while (0)
+
+#define INTSZ 4
+
+
+Elf_Arsym *
+_libelf_ar_process_svr4_symtab(Elf *e, size_t *count)
+{
+ size_t n, nentries, off;
+ Elf_Arsym *symtab, *sym;
+ unsigned char *p, *s, *end;
+
+ assert(e != NULL);
+ assert(count != NULL);
+ assert(e->e_u.e_ar.e_symtab == NULL);
+
+ symtab = NULL;
+
+ if (e->e_u.e_ar.e_rawsymtabsz < INTSZ)
+ goto symtaberror;
+
+ p = (unsigned char *) e->e_u.e_ar.e_rawsymtab;
+ end = p + e->e_u.e_ar.e_rawsymtabsz;
+
+ GET_WORD(p, nentries);
+ p += INTSZ;
+
+ if (nentries == 0 || p + nentries * INTSZ >= end)
+ goto symtaberror;
+
+ /* Allocate space for a nentries + a sentinel. */
+ if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries+1))) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ s = p + (nentries * INTSZ); /* start of the string table. */
+
+ for (n = nentries, sym = symtab; n > 0; n--) {
+
+ if (s >= end)
+ goto symtaberror;
+
+ off = 0;
+
+ GET_WORD(p, off);
+
+ sym->as_off = off;
+ sym->as_hash = elf_hash((char *) s);
+ sym->as_name = (char *) s;
+
+ p += INTSZ;
+ sym++;
+
+ for (; s < end && *s++ != '\0';) /* skip to next string */
+ ;
+ }
+
+ /* Fill up the sentinel entry. */
+ sym->as_name = NULL;
+ sym->as_hash = ~0UL;
+ sym->as_off = (off_t) 0;
+
+ *count = e->e_u.e_ar.e_symtabsz = nentries + 1;
+ e->e_u.e_ar.e_symtab = symtab;
+
+ return (symtab);
+
+symtaberror:
+ if (symtab)
+ free(symtab);
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_ar_util.c b/linkers/elftoolchain/libelf/libelf_ar_util.c
new file mode 100644
index 0000000..7051fe8
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_ar_util.c
@@ -0,0 +1,354 @@
+/*-
+ * Copyright (c) 2006,2009,2010 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <libelf.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelf.h"
+#include "_libelf_ar.h"
+
+LIBELF_VCSID("$Id: libelf_ar_util.c 2066 2011-10-26 15:40:28Z jkoshy $");
+
+/*
+ * Convert a string bounded by `start' and `start+sz' (exclusive) to a
+ * number in the specified base.
+ */
+int
+_libelf_ar_get_number(const char *s, size_t sz, int base, size_t *ret)
+{
+ int c, v;
+ size_t r;
+ const char *e;
+
+ assert(base <= 10);
+
+ e = s + sz;
+
+ /* skip leading blanks */
+ for (;s < e && (c = *s) == ' '; s++)
+ ;
+
+ r = 0L;
+ for (;s < e; s++) {
+ if ((c = *s) == ' ')
+ break;
+ if (c < '0' || c > '9')
+ return (0);
+ v = c - '0';
+ if (v >= base) /* Illegal digit. */
+ break;
+ r *= base;
+ r += v;
+ }
+
+ *ret = r;
+
+ return (1);
+}
+
+/*
+ * Return the translated name for an archive member.
+ */
+char *
+_libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar)
+{
+ char c, *s;
+ size_t len, offset;
+ const char *buf, *p, *q, *r;
+ const size_t bufsize = sizeof(arh->ar_name);
+
+ assert(arh != NULL);
+ assert(ar->e_kind == ELF_K_AR);
+ assert((const char *) arh >= ar->e_rawfile &&
+ (const char *) arh < ar->e_rawfile + ar->e_rawsize);
+
+ buf = arh->ar_name;
+
+ /*
+ * Check for extended naming.
+ *
+ * If the name matches the pattern "^/[0-9]+", it is an
+ * SVR4-style extended name. If the name matches the pattern
+ * "#1/[0-9]+", the entry uses BSD style extended naming.
+ */
+ if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') {
+ /*
+ * The value in field ar_name is a decimal offset into
+ * the archive string table where the actual name
+ * resides.
+ */
+ if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10,
+ &offset) == 0) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
+ if (offset > ar->e_u.e_ar.e_rawstrtabsz) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
+ p = q = ar->e_u.e_ar.e_rawstrtab + offset;
+ r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz;
+
+ for (; p < r && *p != '/'; p++)
+ ;
+ len = p - q + 1; /* space for the trailing NUL */
+
+ if ((s = malloc(len)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ (void) strncpy(s, q, len - 1);
+ s[len - 1] = '\0';
+
+ return (s);
+ } else if (IS_EXTENDED_BSD_NAME(buf)) {
+ r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
+
+ if (_libelf_ar_get_number(r, bufsize -
+ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10,
+ &len) == 0) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
+ /*
+ * Allocate space for the file name plus a
+ * trailing NUL.
+ */
+ if ((s = malloc(len + 1)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ /*
+ * The file name follows the archive header.
+ */
+ q = (const char *) (arh + 1);
+
+ (void) strncpy(s, q, len);
+ s[len] = '\0';
+
+ return (s);
+ }
+
+ /*
+ * A 'normal' name.
+ *
+ * Skip back over trailing blanks from the end of the field.
+ * In the SVR4 format, a '/' is used as a terminator for
+ * non-special names.
+ */
+ for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q)
+ ;
+
+ if (q >= buf) {
+ if (*q == '/') {
+ /*
+ * SVR4 style names: ignore the trailing
+ * character '/', but only if the name is not
+ * one of the special names "/" and "//".
+ */
+ if (q > buf + 1 ||
+ (q == (buf + 1) && *buf != '/'))
+ q--;
+ }
+
+ len = q - buf + 2; /* Add space for a trailing NUL. */
+ } else {
+ /* The buffer only had blanks. */
+ buf = "";
+ len = 1;
+ }
+
+ if ((s = malloc(len)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ (void) strncpy(s, buf, len - 1);
+ s[len - 1] = '\0';
+
+ return (s);
+}
+
+/*
+ * Return the raw name for an archive member, inclusive of any
+ * formatting characters.
+ */
+char *
+_libelf_ar_get_raw_name(const struct ar_hdr *arh)
+{
+ char *rawname;
+ const size_t namesz = sizeof(arh->ar_name);
+
+ if ((rawname = malloc(namesz + 1)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ (void) strncpy(rawname, arh->ar_name, namesz);
+ rawname[namesz] = '\0';
+ return (rawname);
+}
+
+/*
+ * Open an 'ar' archive.
+ */
+Elf *
+_libelf_ar_open(Elf *e)
+{
+ int scanahead;
+ char *s, *end;
+ size_t sz;
+ struct ar_hdr arh;
+
+ e->e_kind = ELF_K_AR;
+ e->e_u.e_ar.e_nchildren = 0;
+ e->e_u.e_ar.e_next = (off_t) -1;
+
+ /*
+ * Look for special members.
+ */
+
+ s = e->e_rawfile + SARMAG;
+ end = e->e_rawfile + e->e_rawsize;
+
+ assert(e->e_rawsize > 0);
+
+ /*
+ * We use heuristics to determine the flavor of the archive we
+ * are examining.
+ *
+ * SVR4 flavor archives use the name "/ " and "// " for
+ * special members.
+ *
+ * In BSD flavor archives the symbol table, if present, is the
+ * first archive with name "__.SYMDEF".
+ */
+
+#define READ_AR_HEADER(S, ARH, SZ, END) \
+ do { \
+ if ((S) + sizeof((ARH)) > (END)) \
+ goto error; \
+ (void) memcpy(&(ARH), (S), sizeof((ARH))); \
+ if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \
+ goto error; \
+ if (_libelf_ar_get_number((ARH).ar_size, \
+ sizeof((ARH).ar_size), 10, &(SZ)) == 0) \
+ goto error; \
+ } while (0)
+
+ READ_AR_HEADER(s, arh, sz, end);
+
+ /*
+ * Handle special archive members for the SVR4 format.
+ */
+ if (arh.ar_name[0] == '/') {
+
+ assert(sz > 0);
+
+ e->e_flags |= LIBELF_F_AR_VARIANT_SVR4;
+
+ scanahead = 0;
+
+ /*
+ * The symbol table (file name "/ ") always comes before the
+ * string table (file name "// ").
+ */
+ if (arh.ar_name[1] == ' ') {
+ /* "/ " => symbol table. */
+ scanahead = 1; /* The string table to follow. */
+
+ s += sizeof(arh);
+ e->e_u.e_ar.e_rawsymtab = s;
+ e->e_u.e_ar.e_rawsymtabsz = sz;
+
+ sz = LIBELF_ADJUST_AR_SIZE(sz);
+ s += sz;
+
+ } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') {
+ /* "// " => string table for long file names. */
+ s += sizeof(arh);
+ e->e_u.e_ar.e_rawstrtab = s;
+ e->e_u.e_ar.e_rawstrtabsz = sz;
+
+ sz = LIBELF_ADJUST_AR_SIZE(sz);
+ s += sz;
+ }
+
+ /*
+ * If the string table hasn't been seen yet, look for
+ * it in the next member.
+ */
+ if (scanahead) {
+ READ_AR_HEADER(s, arh, sz, end);
+
+ /* "// " => string table for long file names. */
+ if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' &&
+ arh.ar_name[2] == ' ') {
+
+ s += sizeof(arh);
+
+ e->e_u.e_ar.e_rawstrtab = s;
+ e->e_u.e_ar.e_rawstrtabsz = sz;
+
+ sz = LIBELF_ADJUST_AR_SIZE(sz);
+ s += sz;
+ }
+ }
+ } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME,
+ sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) {
+ /*
+ * BSD style archive symbol table.
+ */
+ s += sizeof(arh);
+ e->e_u.e_ar.e_rawsymtab = s;
+ e->e_u.e_ar.e_rawsymtabsz = sz;
+
+ sz = LIBELF_ADJUST_AR_SIZE(sz);
+ s += sz;
+ }
+
+ /*
+ * Update the 'next' offset, so that a subsequent elf_begin()
+ * works as expected.
+ */
+ e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile);
+
+ return (e);
+
+error:
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+
+}
diff --git a/linkers/elftoolchain/libelf/libelf_checksum.c b/linkers/elftoolchain/libelf/libelf_checksum.c
new file mode 100644
index 0000000..0bece9a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_checksum.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <gelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_checksum.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+static unsigned long
+_libelf_sum(unsigned long c, const unsigned char *s, size_t size)
+{
+ if (s == NULL || size == 0)
+ return (c);
+
+ while (size--)
+ c += *s++;
+
+ return (c);
+}
+
+unsigned long
+_libelf_checksum(Elf *e, int elfclass)
+{
+ size_t shn;
+ Elf_Scn *scn;
+ Elf_Data *d;
+ unsigned long checksum;
+ GElf_Ehdr eh;
+ GElf_Shdr shdr;
+
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0L);
+ }
+
+ if (e->e_class != elfclass) {
+ LIBELF_SET_ERROR(CLASS, 0);
+ return (0L);
+ }
+
+ if (gelf_getehdr(e, &eh) == NULL)
+ return (0);
+
+ /*
+ * Iterate over all sections in the ELF file, computing the
+ * checksum along the way.
+ *
+ * The first section is always SHN_UNDEF and can be skipped.
+ * Non-allocatable sections are skipped, as are sections that
+ * could be affected by utilities such as strip(1).
+ */
+
+ checksum = 0;
+ for (shn = 1; shn < e->e_u.e_elf.e_nscn; shn++) {
+ if ((scn = elf_getscn(e, shn)) == NULL)
+ return (0);
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return (0);
+ if ((shdr.sh_flags & SHF_ALLOC) == 0 ||
+ shdr.sh_type == SHT_DYNAMIC ||
+ shdr.sh_type == SHT_DYNSYM)
+ continue;
+
+ d = NULL;
+ while ((d = elf_rawdata(scn, d)) != NULL)
+ checksum = _libelf_sum(checksum,
+ (unsigned char *) d->d_buf, d->d_size);
+ }
+
+ /*
+ * Return a 16-bit checksum compatible with Solaris.
+ */
+ return (((checksum >> 16) & 0xFFFFUL) + (checksum & 0xFFFFUL));
+}
diff --git a/linkers/elftoolchain/libelf/libelf_convert.m4 b/linkers/elftoolchain/libelf/libelf_convert.m4
new file mode 100644
index 0000000..9b1679a
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_convert.m4
@@ -0,0 +1,1086 @@
+/*-
+ * Copyright (c) 2006-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <libelf.h>
+#include <string.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_convert.m4 1734 2011-08-16 09:55:07Z jkoshy $");
+
+/* WARNING: GENERATED FROM __file__. */
+
+divert(-1)
+
+# Generate conversion routines for converting between in-memory and
+# file representations of Elf data structures.
+#
+# These conversions use the type information defined in `elf_types.m4'.
+
+include(SRCDIR`/elf_types.m4')
+
+# For the purposes of generating conversion code, ELF types may be
+# classified according to the following characteristics:
+#
+# 1. Whether the ELF type can be directly mapped to an integral C
+# language type. For example, the ELF_T_WORD type maps directly to
+# a 'uint32_t', but ELF_T_GNUHASH lacks a matching C type.
+#
+# 2. Whether the type has word size dependent variants. For example,
+# ELT_T_EHDR is represented using C types Elf32_Ehdr and El64_Ehdr,
+# and the ELF_T_ADDR and ELF_T_OFF types have integral C types that
+# can be 32- or 64- bit wide.
+#
+# 3. Whether the ELF types has a fixed representation or not. For
+# example, the ELF_T_SYM type has a fixed size file representation,
+# some types like ELF_T_NOTE and ELF_T_GNUHASH use a variable size
+# representation.
+#
+# We use m4 macros to generate conversion code for ELF types that have
+# a fixed size representation. Conversion functions for the remaining
+# types are coded by hand.
+#
+#* Handling File and Memory Representations
+#
+# `In-memory' representations of an Elf data structure use natural
+# alignments and native byte ordering. This allows pointer arithmetic
+# and casting to work as expected. On the other hand, the `file'
+# representation of an ELF data structure could possibly be packed
+# tighter than its `in-memory' representation, and could be of a
+# differing byte order. Reading ELF objects that are members of `ar'
+# archives present an additional complication: `ar' pads file data to
+# even addresses, so file data structures in an archive member
+# residing inside an `ar' archive could be at misaligned memory
+# addresses when brought into memory.
+#
+# In summary, casting the `char *' pointers that point to memory
+# representations (i.e., source pointers for the *_tof() functions and
+# the destination pointers for the *_tom() functions), is safe, as
+# these pointers should be correctly aligned for the memory type
+# already. However, pointers to file representations have to be
+# treated as being potentially unaligned and no casting can be done.
+
+# NOCVT(TYPE) -- Do not generate the cvt[] structure entry for TYPE
+define(`NOCVT',`define(`NOCVT_'$1,1)')
+
+# NOFUNC(TYPE) -- Do not generate a conversion function for TYPE
+define(`NOFUNC',`define(`NOFUNC_'$1,1)')
+
+# IGNORE(TYPE) -- Completely ignore the type.
+define(`IGNORE',`NOCVT($1)NOFUNC($1)')
+
+# Mark ELF types that should not be processed by the M4 macros below.
+
+# Types for which we use functions with non-standard names.
+IGNORE(`BYTE') # Uses a wrapper around memcpy().
+IGNORE(`NOTE') # Not a fixed size type.
+
+# Types for which we supply hand-coded functions.
+NOFUNC(`GNUHASH') # A type with complex internal structure.
+NOFUNC(`VDEF') # See MAKE_VERSION_CONVERTERS below.
+NOFUNC(`VNEED') # ..
+
+# Unimplemented types.
+IGNORE(`MOVEP')
+
+# ELF types that don't exist in a 32-bit world.
+NOFUNC(`XWORD32')
+NOFUNC(`SXWORD32')
+
+# `Primitive' ELF types are those that are an alias for an integral
+# type. As they have no internal structure, they can be copied using
+# a `memcpy()', and byteswapped in straightforward way.
+#
+# Mark all ELF types that directly map to integral C types.
+define(`PRIM_ADDR', 1)
+define(`PRIM_BYTE', 1)
+define(`PRIM_HALF', 1)
+define(`PRIM_LWORD', 1)
+define(`PRIM_OFF', 1)
+define(`PRIM_SWORD', 1)
+define(`PRIM_SXWORD', 1)
+define(`PRIM_WORD', 1)
+define(`PRIM_XWORD', 1)
+
+# Note the primitive types that are size-dependent.
+define(`SIZEDEP_ADDR', 1)
+define(`SIZEDEP_OFF', 1)
+
+# Generate conversion functions for primitive types.
+#
+# Macro use: MAKEPRIMFUNCS(ELFTYPE,CTYPE,TYPESIZE,SYMSIZE)
+# `$1': Name of the ELF type.
+# `$2': C structure name suffix.
+# `$3': ELF class specifier for types, one of [`32', `64'].
+# `$4': Additional ELF class specifier, one of [`', `32', `64'].
+#
+# Generates a pair of conversion functions.
+define(`MAKEPRIMFUNCS',`
+static int
+libelf_cvt_$1$4_tof(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ Elf$3_$2 t, *s = (Elf$3_$2 *) (uintptr_t) src;
+ size_t c;
+
+ (void) dsz;
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count * sizeof(*s));
+ return (1);
+ }
+
+ for (c = 0; c < count; c++) {
+ t = *s++;
+ SWAP_$1$4(t);
+ WRITE_$1$4(dst,t);
+ }
+
+ return (1);
+}
+
+static int
+libelf_cvt_$1$4_tom(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ Elf$3_$2 t, *d = (Elf$3_$2 *) (uintptr_t) dst;
+ size_t c;
+
+ if (dsz < count * sizeof(Elf$3_$2))
+ return (0);
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count * sizeof(*d));
+ return (1);
+ }
+
+ for (c = 0; c < count; c++) {
+ READ_$1$4(src,t);
+ SWAP_$1$4(t);
+ *d++ = t;
+ }
+
+ return (1);
+}
+')
+
+#
+# Handling composite ELF types
+#
+
+# SWAP_FIELD(FIELDNAME,ELFTYPE) -- Generate code to swap one field.
+define(`SWAP_FIELD',
+ `ifdef(`SIZEDEP_'$2,
+ `SWAP_$2'SZ()`(t.$1);
+ ',
+ `SWAP_$2(t.$1);
+ ')')
+
+# SWAP_MEMBERS(STRUCT) -- Iterate over a structure definition.
+define(`SWAP_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')')
+
+# SWAP_STRUCT(CTYPE,SIZE) -- Generate code to swap an ELF structure.
+define(`SWAP_STRUCT',
+ `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */
+ SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+# WRITE_FIELD(ELFTYPE,FIELDNAME) -- Generate code to write one field.
+define(`WRITE_FIELD',
+ `ifdef(`SIZEDEP_'$2,
+ `WRITE_$2'SZ()`(dst,t.$1);
+ ',
+ `WRITE_$2(dst,t.$1);
+ ')')
+
+# WRITE_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
+define(`WRITE_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')')
+
+# WRITE_STRUCT(CTYPE,SIZE) -- Generate code to write out an ELF structure.
+define(`WRITE_STRUCT',
+ `pushdef(`SZ',$2)/* Write an Elf$2_$1 */
+ WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+# READ_FIELD(ELFTYPE,CTYPE) -- Generate code to read one field.
+define(`READ_FIELD',
+ `ifdef(`SIZEDEP_'$2,
+ `READ_$2'SZ()`(s,t.$1);
+ ',
+ `READ_$2(s,t.$1);
+ ')')
+
+# READ_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
+define(`READ_MEMBERS',
+ `ifelse($#,1,`/**/',
+ `READ_FIELD($1)READ_MEMBERS(shift($@))')')
+
+# READ_STRUCT(CTYPE,SIZE) -- Generate code to read an ELF structure.
+define(`READ_STRUCT',
+ `pushdef(`SZ',$2)/* Read an Elf$2_$1 */
+ READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
+
+
+# MAKECOMPFUNCS -- Generate converters for composite ELF structures.
+#
+# When converting data to file representation, the source pointer will
+# be naturally aligned for a data structure's in-memory
+# representation. When converting data to memory, the destination
+# pointer will be similarly aligned.
+#
+# For in-place conversions, when converting to file representations,
+# the source buffer is large enough to hold `file' data. When
+# converting from file to memory, we need to be careful to work
+# `backwards', to avoid overwriting unconverted data.
+#
+# Macro use:
+# `$1': Name of the ELF type.
+# `$2': C structure name suffix.
+# `$3': ELF class specifier, one of [`', `32', `64']
+define(`MAKECOMPFUNCS', `ifdef(`NOFUNC_'$1$3,`',`
+static int
+libelf_cvt_$1$3_tof(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ Elf$3_$2 t, *s;
+ size_t c;
+
+ (void) dsz;
+
+ s = (Elf$3_$2 *) (uintptr_t) src;
+ for (c = 0; c < count; c++) {
+ t = *s++;
+ if (byteswap) {
+ SWAP_STRUCT($2,$3)
+ }
+ WRITE_STRUCT($2,$3)
+ }
+
+ return (1);
+}
+
+static int
+libelf_cvt_$1$3_tom(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ Elf$3_$2 t, *d;
+ char *s,*s0;
+ size_t fsz;
+
+ fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT);
+ d = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1);
+ s0 = (char *) src + (count - 1) * fsz;
+
+ if (dsz < count * sizeof(Elf$3_$2))
+ return (0);
+
+ while (count--) {
+ s = s0;
+ READ_STRUCT($2,$3)
+ if (byteswap) {
+ SWAP_STRUCT($2,$3)
+ }
+ *d-- = t; s0 -= fsz;
+ }
+
+ return (1);
+}
+')')
+
+# MAKE_TYPE_CONVERTER(ELFTYPE,CTYPE)
+#
+# Make type convertor functions from the type definition
+# of the ELF type:
+# - Skip convertors marked as `NOFUNC'.
+# - Invoke `MAKEPRIMFUNCS' or `MAKECOMPFUNCS' as appropriate.
+define(`MAKE_TYPE_CONVERTER',
+ `ifdef(`NOFUNC_'$1,`',
+ `ifdef(`PRIM_'$1,
+ `ifdef(`SIZEDEP_'$1,
+ `MAKEPRIMFUNCS($1,$2,32,32)dnl
+ MAKEPRIMFUNCS($1,$2,64,64)',
+ `MAKEPRIMFUNCS($1,$2,64)')',
+ `MAKECOMPFUNCS($1,$2,32)dnl
+ MAKECOMPFUNCS($1,$2,64)')')')
+
+# MAKE_TYPE_CONVERTERS(ELFTYPELIST) -- Generate conversion functions.
+define(`MAKE_TYPE_CONVERTERS',
+ `ifelse($#,1,`',
+ `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')')
+
+
+#
+# Macros to generate entries for the table of convertors.
+#
+
+# CONV(ELFTYPE,SIZE,DIRECTION)
+#
+# Generate the name of a convertor function.
+define(`CONV',
+ `ifdef(`NOFUNC_'$1$2,
+ `.$3$2 = NULL',
+ `ifdef(`PRIM_'$1,
+ `ifdef(`SIZEDEP_'$1,
+ `.$3$2 = libelf_cvt_$1$2_$3',
+ `.$3$2 = libelf_cvt_$1_$3')',
+ `.$3$2 = libelf_cvt_$1$2_$3')')')
+
+# CONVERTER_NAME(ELFTYPE)
+#
+# Generate the contents of one `struct cvt' instance.
+define(`CONVERTER_NAME',
+ `ifdef(`NOCVT_'$1,`',
+ ` [ELF_T_$1] = {
+ CONV($1,32,tof),
+ CONV($1,32,tom),
+ CONV($1,64,tof),
+ CONV($1,64,tom)
+ },
+
+')')
+
+# CONVERTER_NAMES(ELFTYPELIST)
+#
+# Generate the `struct cvt[]' array.
+define(`CONVERTER_NAMES',
+ `ifelse($#,1,`',
+ `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')')
+
+#
+# Handling ELF version sections.
+#
+
+# _FSZ(FIELD,BASETYPE) - return the file size for a field.
+define(`_FSZ',
+ `ifelse($2,`HALF',2,
+ $2,`WORD',4)')
+
+# FSZ(STRUCT) - determine the file size of a structure.
+define(`FSZ',
+ `ifelse($#,1,0,
+ `eval(_FSZ($1) + FSZ(shift($@)))')')
+
+# MAKE_VERSION_CONVERTERS(TYPE,BASE,AUX,PFX) -- Generate conversion
+# functions for versioning structures.
+define(`MAKE_VERSION_CONVERTERS',
+ `MAKE_VERSION_CONVERTER($1,$2,$3,$4,32)
+ MAKE_VERSION_CONVERTER($1,$2,$3,$4,64)')
+
+# MAKE_VERSION_CONVERTOR(TYPE,CBASE,CAUX,PFX,SIZE) -- Generate a
+# conversion function.
+define(`MAKE_VERSION_CONVERTER',`
+static int
+libelf_cvt_$1$5_tof(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ Elf$5_$2 t;
+ Elf$5_$3 a;
+ const size_t verfsz = FSZ(Elf$5_$2_DEF);
+ const size_t auxfsz = FSZ(Elf$5_$3_DEF);
+ const size_t vermsz = sizeof(Elf$5_$2);
+ const size_t auxmsz = sizeof(Elf$5_$3);
+ char * const dstend = dst + dsz;
+ char * const srcend = src + count;
+ char *dtmp, *dstaux, *srcaux;
+ Elf$5_Word aux, anext, cnt, vnext;
+
+ for (dtmp = dst, vnext = ~0;
+ vnext != 0 && dtmp + verfsz <= dstend && src + vermsz <= srcend;
+ dtmp += vnext, src += vnext) {
+
+ /* Read in an Elf$5_$2 structure. */
+ t = *((Elf$5_$2 *) (uintptr_t) src);
+
+ aux = t.$4_aux;
+ cnt = t.$4_cnt;
+ vnext = t.$4_next;
+
+ if (byteswap) {
+ SWAP_STRUCT($2, $5)
+ }
+
+ dst = dtmp;
+ WRITE_STRUCT($2, $5)
+
+ if (aux < verfsz)
+ return (0);
+
+ /* Process AUX entries. */
+ for (anext = ~0, dstaux = dtmp + aux, srcaux = src + aux;
+ cnt != 0 && anext != 0 && dstaux + auxfsz <= dstend &&
+ srcaux + auxmsz <= srcend;
+ dstaux += anext, srcaux += anext, cnt--) {
+
+ /* Read in an Elf$5_$3 structure. */
+ a = *((Elf$5_$3 *) (uintptr_t) srcaux);
+ anext = a.$4a_next;
+
+ if (byteswap) {
+ pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
+ }
+
+ dst = dstaux;
+ pushdef(`t',`a')WRITE_STRUCT($3, $5)popdef(`t')
+ }
+
+ if (anext || cnt)
+ return (0);
+ }
+
+ if (vnext)
+ return (0);
+
+ return (1);
+}
+
+static int
+libelf_cvt_$1$5_tom(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ Elf$5_$2 t, *dp;
+ Elf$5_$3 a, *ap;
+ const size_t verfsz = FSZ(Elf$5_$2_DEF);
+ const size_t auxfsz = FSZ(Elf$5_$3_DEF);
+ const size_t vermsz = sizeof(Elf$5_$2);
+ const size_t auxmsz = sizeof(Elf$5_$3);
+ char * const dstend = dst + dsz;
+ char * const srcend = src + count;
+ char *dstaux, *s, *srcaux, *stmp;
+ Elf$5_Word aux, anext, cnt, vnext;
+
+ for (stmp = src, vnext = ~0;
+ vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend;
+ stmp += vnext, dst += vnext) {
+
+ /* Read in a $1 structure. */
+ s = stmp;
+ READ_STRUCT($2, $5)
+ if (byteswap) {
+ SWAP_STRUCT($2, $5)
+ }
+
+ dp = (Elf$5_$2 *) (uintptr_t) dst;
+ *dp = t;
+
+ aux = t.$4_aux;
+ cnt = t.$4_cnt;
+ vnext = t.$4_next;
+
+ if (aux < vermsz)
+ return (0);
+
+ /* Process AUX entries. */
+ for (anext = ~0, dstaux = dst + aux, srcaux = stmp + aux;
+ cnt != 0 && anext != 0 && dstaux + auxmsz <= dstend &&
+ srcaux + auxfsz <= srcend;
+ dstaux += anext, srcaux += anext, cnt--) {
+
+ s = srcaux;
+ pushdef(`t',`a')READ_STRUCT($3, $5)popdef(`t')
+
+ if (byteswap) {
+ pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
+ }
+
+ anext = a.$4a_next;
+
+ ap = ((Elf$5_$3 *) (uintptr_t) dstaux);
+ *ap = a;
+ }
+
+ if (anext || cnt)
+ return (0);
+ }
+
+ if (vnext)
+ return (0);
+
+ return (1);
+}')
+
+divert(0)
+
+/*
+ * C macros to byte swap integral quantities.
+ */
+
+#define SWAP_BYTE(X) do { (void) (X); } while (0)
+#define SWAP_IDENT(X) do { (void) (X); } while (0)
+#define SWAP_HALF(X) do { \
+ uint16_t _x = (uint16_t) (X); \
+ uint16_t _t = _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ (X) = _t; \
+ } while (0)
+#define SWAP_WORD(X) do { \
+ uint32_t _x = (uint32_t) (X); \
+ uint32_t _t = _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ (X) = _t; \
+ } while (0)
+#define SWAP_ADDR32(X) SWAP_WORD(X)
+#define SWAP_OFF32(X) SWAP_WORD(X)
+#define SWAP_SWORD(X) SWAP_WORD(X)
+#define SWAP_WORD64(X) do { \
+ uint64_t _x = (uint64_t) (X); \
+ uint64_t _t = _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \
+ (X) = _t; \
+ } while (0)
+#define SWAP_ADDR64(X) SWAP_WORD64(X)
+#define SWAP_LWORD(X) SWAP_WORD64(X)
+#define SWAP_OFF64(X) SWAP_WORD64(X)
+#define SWAP_SXWORD(X) SWAP_WORD64(X)
+#define SWAP_XWORD(X) SWAP_WORD64(X)
+
+/*
+ * C macros to write out various integral values.
+ *
+ * Note:
+ * - The destination pointer could be unaligned.
+ * - Values are written out in native byte order.
+ * - The destination pointer is incremented after the write.
+ */
+#define WRITE_BYTE(P,X) do { \
+ char *const _p = (char *) (P); \
+ _p[0] = (char) (X); \
+ (P) = _p + 1; \
+ } while (0)
+#define WRITE_HALF(P,X) do { \
+ uint16_t _t = (X); \
+ char *const _p = (char *) (P); \
+ const char *const _q = (char *) &_t; \
+ _p[0] = _q[0]; \
+ _p[1] = _q[1]; \
+ (P) = _p + 2; \
+ } while (0)
+#define WRITE_WORD(P,X) do { \
+ uint32_t _t = (X); \
+ char *const _p = (char *) (P); \
+ const char *const _q = (char *) &_t; \
+ _p[0] = _q[0]; \
+ _p[1] = _q[1]; \
+ _p[2] = _q[2]; \
+ _p[3] = _q[3]; \
+ (P) = _p + 4; \
+ } while (0)
+#define WRITE_ADDR32(P,X) WRITE_WORD(P,X)
+#define WRITE_OFF32(P,X) WRITE_WORD(P,X)
+#define WRITE_SWORD(P,X) WRITE_WORD(P,X)
+#define WRITE_WORD64(P,X) do { \
+ uint64_t _t = (X); \
+ char *const _p = (char *) (P); \
+ const char *const _q = (char *) &_t; \
+ _p[0] = _q[0]; \
+ _p[1] = _q[1]; \
+ _p[2] = _q[2]; \
+ _p[3] = _q[3]; \
+ _p[4] = _q[4]; \
+ _p[5] = _q[5]; \
+ _p[6] = _q[6]; \
+ _p[7] = _q[7]; \
+ (P) = _p + 8; \
+ } while (0)
+#define WRITE_ADDR64(P,X) WRITE_WORD64(P,X)
+#define WRITE_LWORD(P,X) WRITE_WORD64(P,X)
+#define WRITE_OFF64(P,X) WRITE_WORD64(P,X)
+#define WRITE_SXWORD(P,X) WRITE_WORD64(P,X)
+#define WRITE_XWORD(P,X) WRITE_WORD64(P,X)
+#define WRITE_IDENT(P,X) do { \
+ (void) memcpy((P), (X), sizeof((X))); \
+ (P) = (P) + EI_NIDENT; \
+ } while (0)
+
+/*
+ * C macros to read in various integral values.
+ *
+ * Note:
+ * - The source pointer could be unaligned.
+ * - Values are read in native byte order.
+ * - The source pointer is incremented appropriately.
+ */
+
+#define READ_BYTE(P,X) do { \
+ const char *const _p = \
+ (const char *) (P); \
+ (X) = _p[0]; \
+ (P) = (P) + 1; \
+ } while (0)
+#define READ_HALF(P,X) do { \
+ uint16_t _t; \
+ char *const _q = (char *) &_t; \
+ const char *const _p = \
+ (const char *) (P); \
+ _q[0] = _p[0]; \
+ _q[1] = _p[1]; \
+ (P) = (P) + 2; \
+ (X) = _t; \
+ } while (0)
+#define READ_WORD(P,X) do { \
+ uint32_t _t; \
+ char *const _q = (char *) &_t; \
+ const char *const _p = \
+ (const char *) (P); \
+ _q[0] = _p[0]; \
+ _q[1] = _p[1]; \
+ _q[2] = _p[2]; \
+ _q[3] = _p[3]; \
+ (P) = (P) + 4; \
+ (X) = _t; \
+ } while (0)
+#define READ_ADDR32(P,X) READ_WORD(P,X)
+#define READ_OFF32(P,X) READ_WORD(P,X)
+#define READ_SWORD(P,X) READ_WORD(P,X)
+#define READ_WORD64(P,X) do { \
+ uint64_t _t; \
+ char *const _q = (char *) &_t; \
+ const char *const _p = \
+ (const char *) (P); \
+ _q[0] = _p[0]; \
+ _q[1] = _p[1]; \
+ _q[2] = _p[2]; \
+ _q[3] = _p[3]; \
+ _q[4] = _p[4]; \
+ _q[5] = _p[5]; \
+ _q[6] = _p[6]; \
+ _q[7] = _p[7]; \
+ (P) = (P) + 8; \
+ (X) = _t; \
+ } while (0)
+#define READ_ADDR64(P,X) READ_WORD64(P,X)
+#define READ_LWORD(P,X) READ_WORD64(P,X)
+#define READ_OFF64(P,X) READ_WORD64(P,X)
+#define READ_SXWORD(P,X) READ_WORD64(P,X)
+#define READ_XWORD(P,X) READ_WORD64(P,X)
+#define READ_IDENT(P,X) do { \
+ (void) memcpy((X), (P), sizeof((X))); \
+ (P) = (P) + EI_NIDENT; \
+ } while (0)
+
+#define ROUNDUP2(V,N) (V) = ((((V) + (N) - 1)) & ~((N) - 1))
+
+/*[*/
+MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
+MAKE_VERSION_CONVERTERS(VDEF,Verdef,Verdaux,vd)
+MAKE_VERSION_CONVERTERS(VNEED,Verneed,Vernaux,vn)
+/*]*/
+
+/*
+ * Sections of type ELF_T_BYTE are never byteswapped, consequently a
+ * simple memcpy suffices for both directions of conversion.
+ */
+
+static int
+libelf_cvt_BYTE_tox(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ (void) byteswap;
+ if (dsz < count)
+ return (0);
+ if (dst != src)
+ (void) memcpy(dst, src, count);
+ return (1);
+}
+
+/*
+ * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit
+ * words. Bloom filter data comes next, followed by hash buckets and the
+ * hash chain.
+ *
+ * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit
+ * wide on ELFCLASS32 objects. The other objects in this section are 32
+ * bits wide.
+ *
+ * Argument `srcsz' denotes the number of bytes to be converted. In the
+ * 32-bit case we need to translate `srcsz' to a count of 32-bit words.
+ */
+
+static int
+libelf_cvt_GNUHASH32_tom(char *dst, size_t dsz, char *src, size_t srcsz,
+ int byteswap)
+{
+ return (libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t),
+ byteswap));
+}
+
+static int
+libelf_cvt_GNUHASH32_tof(char *dst, size_t dsz, char *src, size_t srcsz,
+ int byteswap)
+{
+ return (libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t),
+ byteswap));
+}
+
+static int
+libelf_cvt_GNUHASH64_tom(char *dst, size_t dsz, char *src, size_t srcsz,
+ int byteswap)
+{
+ size_t sz;
+ uint64_t t64, *bloom64;
+ Elf_GNU_Hash_Header *gh;
+ uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32;
+ uint32_t *buckets, *chains;
+
+ sz = 4 * sizeof(uint32_t); /* File header is 4 words long. */
+ if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz)
+ return (0);
+
+ /* Read in the section header and byteswap if needed. */
+ READ_WORD(src, nbuckets);
+ READ_WORD(src, symndx);
+ READ_WORD(src, maskwords);
+ READ_WORD(src, shift2);
+
+ srcsz -= sz;
+
+ if (byteswap) {
+ SWAP_WORD(nbuckets);
+ SWAP_WORD(symndx);
+ SWAP_WORD(maskwords);
+ SWAP_WORD(shift2);
+ }
+
+ /* Check source buffer and destination buffer sizes. */
+ sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t);
+ if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header))
+ return (0);
+
+ gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst;
+ gh->gh_nbuckets = nbuckets;
+ gh->gh_symndx = symndx;
+ gh->gh_maskwords = maskwords;
+ gh->gh_shift2 = shift2;
+
+ dsz -= sizeof(Elf_GNU_Hash_Header);
+ dst += sizeof(Elf_GNU_Hash_Header);
+
+ bloom64 = (uint64_t *) (uintptr_t) dst;
+
+ /* Copy bloom filter data. */
+ for (n = 0; n < maskwords; n++) {
+ READ_XWORD(src, t64);
+ if (byteswap)
+ SWAP_XWORD(t64);
+ bloom64[n] = t64;
+ }
+
+ /* The hash buckets follows the bloom filter. */
+ dst += maskwords * sizeof(uint64_t);
+ buckets = (uint32_t *) (uintptr_t) dst;
+
+ for (n = 0; n < nbuckets; n++) {
+ READ_WORD(src, t32);
+ if (byteswap)
+ SWAP_WORD(t32);
+ buckets[n] = t32;
+ }
+
+ dst += nbuckets * sizeof(uint32_t);
+
+ /* The hash chain follows the hash buckets. */
+ dsz -= sz;
+ srcsz -= sz;
+
+ if (dsz < srcsz) /* Destination lacks space. */
+ return (0);
+
+ nchains = srcsz / sizeof(uint32_t);
+ chains = (uint32_t *) (uintptr_t) dst;
+
+ for (n = 0; n < nchains; n++) {
+ READ_WORD(src, t32);
+ if (byteswap)
+ SWAP_WORD(t32);
+ *chains++ = t32;
+ }
+
+ return (1);
+}
+
+static int
+libelf_cvt_GNUHASH64_tof(char *dst, size_t dsz, char *src, size_t srcsz,
+ int byteswap)
+{
+ uint32_t *s32;
+ size_t sz, hdrsz;
+ uint64_t *s64, t64;
+ Elf_GNU_Hash_Header *gh;
+ uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32;
+
+ hdrsz = 4 * sizeof(uint32_t); /* Header is 4x32 bits. */
+ if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header))
+ return (0);
+
+ gh = (Elf_GNU_Hash_Header *) (uintptr_t) src;
+
+ t0 = nbuckets = gh->gh_nbuckets;
+ t1 = gh->gh_symndx;
+ t2 = maskwords = gh->gh_maskwords;
+ t3 = gh->gh_shift2;
+
+ src += sizeof(Elf_GNU_Hash_Header);
+ srcsz -= sizeof(Elf_GNU_Hash_Header);
+ dsz -= hdrsz;
+
+ sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords *
+ sizeof(uint64_t);
+
+ if (srcsz < sz || dsz < sz)
+ return (0);
+
+ /* Write out the header. */
+ if (byteswap) {
+ SWAP_WORD(t0);
+ SWAP_WORD(t1);
+ SWAP_WORD(t2);
+ SWAP_WORD(t3);
+ }
+
+ WRITE_WORD(dst, t0);
+ WRITE_WORD(dst, t1);
+ WRITE_WORD(dst, t2);
+ WRITE_WORD(dst, t3);
+
+ /* Copy the bloom filter and the hash table. */
+ s64 = (uint64_t *) (uintptr_t) src;
+ for (n = 0; n < maskwords; n++) {
+ t64 = *s64++;
+ if (byteswap)
+ SWAP_XWORD(t64);
+ WRITE_WORD64(dst, t64);
+ }
+
+ s32 = (uint32_t *) s64;
+ for (n = 0; n < nbuckets; n++) {
+ t32 = *s32++;
+ if (byteswap)
+ SWAP_WORD(t32);
+ WRITE_WORD(dst, t32);
+ }
+
+ srcsz -= sz;
+ dsz -= sz;
+
+ /* Copy out the hash chains. */
+ if (dsz < srcsz)
+ return (0);
+
+ nchains = srcsz / sizeof(uint32_t);
+ for (n = 0; n < nchains; n++) {
+ t32 = *s32++;
+ if (byteswap)
+ SWAP_WORD(t32);
+ WRITE_WORD(dst, t32);
+ }
+
+ return (1);
+}
+
+/*
+ * Elf_Note structures comprise a fixed size header followed by variable
+ * length strings. The fixed size header needs to be byte swapped, but
+ * not the strings.
+ *
+ * Argument `count' denotes the total number of bytes to be converted.
+ * The destination buffer needs to be at least `count' bytes in size.
+ */
+static int
+libelf_cvt_NOTE_tom(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ uint32_t namesz, descsz, type;
+ Elf_Note *en;
+ size_t sz, hdrsz;
+
+ if (dsz < count) /* Destination buffer is too small. */
+ return (0);
+
+ hdrsz = 3 * sizeof(uint32_t);
+ if (count < hdrsz) /* Source too small. */
+ return (0);
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count);
+ return (1);
+ }
+
+ /* Process all notes in the section. */
+ while (count > hdrsz) {
+ /* Read the note header. */
+ READ_WORD(src, namesz);
+ READ_WORD(src, descsz);
+ READ_WORD(src, type);
+
+ /* Translate. */
+ SWAP_WORD(namesz);
+ SWAP_WORD(descsz);
+ SWAP_WORD(type);
+
+ /* Copy out the translated note header. */
+ en = (Elf_Note *) (uintptr_t) dst;
+ en->n_namesz = namesz;
+ en->n_descsz = descsz;
+ en->n_type = type;
+
+ dsz -= sizeof(Elf_Note);
+ dst += sizeof(Elf_Note);
+ count -= hdrsz;
+
+ ROUNDUP2(namesz, 4);
+ ROUNDUP2(descsz, 4);
+
+ sz = namesz + descsz;
+
+ if (count < sz || dsz < sz) /* Buffers are too small. */
+ return (0);
+
+ (void) memcpy(dst, src, sz);
+
+ src += sz;
+ dst += sz;
+
+ count -= sz;
+ dsz -= sz;
+ }
+
+ return (1);
+}
+
+static int
+libelf_cvt_NOTE_tof(char *dst, size_t dsz, char *src, size_t count,
+ int byteswap)
+{
+ uint32_t namesz, descsz, type;
+ Elf_Note *en;
+ size_t sz;
+
+ if (dsz < count)
+ return (0);
+
+ if (!byteswap) {
+ (void) memcpy(dst, src, count);
+ return (1);
+ }
+
+ while (count > sizeof(Elf_Note)) {
+
+ en = (Elf_Note *) (uintptr_t) src;
+ namesz = en->n_namesz;
+ descsz = en->n_descsz;
+ type = en->n_type;
+
+ SWAP_WORD(namesz);
+ SWAP_WORD(descsz);
+ SWAP_WORD(type);
+
+ WRITE_WORD(dst, namesz);
+ WRITE_WORD(dst, descsz);
+ WRITE_WORD(dst, type);
+
+ src += sizeof(Elf_Note);
+
+ ROUNDUP2(namesz, 4);
+ ROUNDUP2(descsz, 4);
+
+ sz = namesz + descsz;
+
+ if (count < sz)
+ sz = count;
+
+ (void) memcpy(dst, src, sz);
+
+ src += sz;
+ dst += sz;
+ count -= sz;
+ }
+
+ return (1);
+}
+
+struct converters {
+ int (*tof32)(char *dst, size_t dsz, char *src, size_t cnt,
+ int byteswap);
+ int (*tom32)(char *dst, size_t dsz, char *src, size_t cnt,
+ int byteswap);
+ int (*tof64)(char *dst, size_t dsz, char *src, size_t cnt,
+ int byteswap);
+ int (*tom64)(char *dst, size_t dsz, char *src, size_t cnt,
+ int byteswap);
+};
+
+
+static struct converters cvt[ELF_T_NUM] = {
+ /*[*/
+CONVERTER_NAMES(ELF_TYPE_LIST)
+ /*]*/
+
+ /*
+ * Types that need hand-coded converters follow.
+ */
+
+ [ELF_T_BYTE] = {
+ .tof32 = libelf_cvt_BYTE_tox,
+ .tom32 = libelf_cvt_BYTE_tox,
+ .tof64 = libelf_cvt_BYTE_tox,
+ .tom64 = libelf_cvt_BYTE_tox
+ },
+
+ [ELF_T_NOTE] = {
+ .tof32 = libelf_cvt_NOTE_tof,
+ .tom32 = libelf_cvt_NOTE_tom,
+ .tof64 = libelf_cvt_NOTE_tof,
+ .tom64 = libelf_cvt_NOTE_tom
+ }
+};
+
+int (*_libelf_get_translator(Elf_Type t, int direction, int elfclass))
+ (char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap)
+{
+ assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
+ assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
+
+ if (t >= ELF_T_NUM ||
+ (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) ||
+ (direction != ELF_TOFILE && direction != ELF_TOMEMORY))
+ return (NULL);
+
+ return ((elfclass == ELFCLASS32) ?
+ (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) :
+ (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64));
+}
diff --git a/linkers/elftoolchain/libelf/libelf_data.c b/linkers/elftoolchain/libelf/libelf_data.c
new file mode 100644
index 0000000..8044c74
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_data.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_data.c 1264 2010-11-12 14:53:23Z jkoshy $");
+
+int
+_libelf_xlate_shtype(uint32_t sht)
+{
+ switch (sht) {
+ case SHT_DYNAMIC:
+ return (ELF_T_DYN);
+ case SHT_DYNSYM:
+ return (ELF_T_SYM);
+ case SHT_FINI_ARRAY:
+ return (ELF_T_ADDR);
+ case SHT_GNU_HASH:
+ return (ELF_T_GNUHASH);
+ case SHT_GNU_LIBLIST:
+ return (ELF_T_WORD);
+ case SHT_GROUP:
+ return (ELF_T_WORD);
+ case SHT_HASH:
+ return (ELF_T_WORD);
+ case SHT_INIT_ARRAY:
+ return (ELF_T_ADDR);
+ case SHT_NOBITS:
+ return (ELF_T_BYTE);
+ case SHT_NOTE:
+ return (ELF_T_NOTE);
+ case SHT_PREINIT_ARRAY:
+ return (ELF_T_ADDR);
+ case SHT_PROGBITS:
+ return (ELF_T_BYTE);
+ case SHT_REL:
+ return (ELF_T_REL);
+ case SHT_RELA:
+ return (ELF_T_RELA);
+ case SHT_STRTAB:
+ return (ELF_T_BYTE);
+ case SHT_SYMTAB:
+ return (ELF_T_SYM);
+ case SHT_SYMTAB_SHNDX:
+ return (ELF_T_WORD);
+ case SHT_SUNW_dof:
+ return (ELF_T_BYTE);
+ case SHT_SUNW_move:
+ return (ELF_T_MOVE);
+ case SHT_SUNW_syminfo:
+ return (ELF_T_SYMINFO);
+ case SHT_SUNW_verdef: /* == SHT_GNU_verdef */
+ return (ELF_T_VDEF);
+ case SHT_SUNW_verneed: /* == SHT_GNU_verneed */
+ return (ELF_T_VNEED);
+ case SHT_SUNW_versym: /* == SHT_GNU_versym */
+ return (ELF_T_HALF);
+ default:
+ return (-1);
+ }
+}
diff --git a/linkers/elftoolchain/libelf/libelf_ehdr.c b/linkers/elftoolchain/libelf/libelf_ehdr.c
new file mode 100644
index 0000000..affe541
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_ehdr.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <stdlib.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_ehdr.c 1677 2011-07-28 04:35:53Z jkoshy $");
+
+/*
+ * Retrieve counts for sections, phdrs and the section string table index
+ * from section header #0 of the ELF object.
+ */
+static int
+_libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum,
+ uint16_t strndx)
+{
+ Elf_Scn *scn;
+ size_t fsz;
+ int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
+ uint32_t shtype;
+
+ assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn));
+
+ fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1);
+ assert(fsz > 0);
+
+ if (e->e_rawsize < shoff + fsz) { /* raw file too small */
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (0);
+ }
+
+ if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL)
+ return (0);
+
+ xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec);
+ (*xlator)((char *) &scn->s_shdr, sizeof(scn->s_shdr),
+ e->e_rawfile + shoff, (size_t) 1,
+ e->e_byteorder != LIBELF_PRIVATE(byteorder));
+
+#define GET_SHDR_MEMBER(M) ((ec == ELFCLASS32) ? scn->s_shdr.s_shdr32.M : \
+ scn->s_shdr.s_shdr64.M)
+
+ if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) {
+ LIBELF_SET_ERROR(SECTION, 0);
+ return (0);
+ }
+
+ e->e_u.e_elf.e_nscn = GET_SHDR_MEMBER(sh_size);
+ e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum :
+ GET_SHDR_MEMBER(sh_info);
+ e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx :
+ GET_SHDR_MEMBER(sh_link);
+#undef GET_SHDR_MEMBER
+
+ return (1);
+}
+
+#define EHDR_INIT(E,SZ) do { \
+ Elf##SZ##_Ehdr *eh = (E); \
+ eh->e_ident[EI_MAG0] = ELFMAG0; \
+ eh->e_ident[EI_MAG1] = ELFMAG1; \
+ eh->e_ident[EI_MAG2] = ELFMAG2; \
+ eh->e_ident[EI_MAG3] = ELFMAG3; \
+ eh->e_ident[EI_CLASS] = ELFCLASS##SZ; \
+ eh->e_ident[EI_DATA] = ELFDATANONE; \
+ eh->e_ident[EI_VERSION] = LIBELF_PRIVATE(version); \
+ eh->e_machine = EM_NONE; \
+ eh->e_type = ELF_K_NONE; \
+ eh->e_version = LIBELF_PRIVATE(version); \
+ } while (0)
+
+void *
+_libelf_ehdr(Elf *e, int ec, int allocate)
+{
+ void *ehdr;
+ size_t fsz, msz;
+ uint16_t phnum, shnum, strndx;
+ uint64_t shoff;
+ int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
+
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (e == NULL || e->e_kind != ELF_K_ELF) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (e->e_class != ELFCLASSNONE && e->e_class != ec) {
+ LIBELF_SET_ERROR(CLASS, 0);
+ return (NULL);
+ }
+
+ if (e->e_version != EV_CURRENT) {
+ LIBELF_SET_ERROR(VERSION, 0);
+ return (NULL);
+ }
+
+ if (e->e_class == ELFCLASSNONE)
+ e->e_class = ec;
+
+ if (ec == ELFCLASS32)
+ ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr32;
+ else
+ ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr64;
+
+ if (ehdr != NULL) /* already have a translated ehdr */
+ return (ehdr);
+
+ fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
+ assert(fsz > 0);
+
+ if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) {
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT);
+
+ assert(msz > 0);
+
+ if ((ehdr = calloc((size_t) 1, msz)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+ e->e_u.e_elf.e_ehdr.e_ehdr32 = ehdr;
+ EHDR_INIT(ehdr,32);
+ } else {
+ e->e_u.e_elf.e_ehdr.e_ehdr64 = ehdr;
+ EHDR_INIT(ehdr,64);
+ }
+
+ if (allocate)
+ e->e_flags |= ELF_F_DIRTY;
+
+ if (e->e_cmd == ELF_C_WRITE)
+ return (ehdr);
+
+ xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec);
+ (*xlator)(ehdr, msz, e->e_rawfile, (size_t) 1,
+ e->e_byteorder != LIBELF_PRIVATE(byteorder));
+
+ /*
+ * If extended numbering is being used, read the correct
+ * number of sections and program header entries.
+ */
+ if (ec == ELFCLASS32) {
+ phnum = ((Elf32_Ehdr *) ehdr)->e_phnum;
+ shnum = ((Elf32_Ehdr *) ehdr)->e_shnum;
+ shoff = ((Elf32_Ehdr *) ehdr)->e_shoff;
+ strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx;
+ } else {
+ phnum = ((Elf64_Ehdr *) ehdr)->e_phnum;
+ shnum = ((Elf64_Ehdr *) ehdr)->e_shnum;
+ shoff = ((Elf64_Ehdr *) ehdr)->e_shoff;
+ strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx;
+ }
+
+ if (shnum >= SHN_LORESERVE ||
+ (shoff == 0LL && (shnum != 0 || phnum == PN_XNUM ||
+ strndx == SHN_XINDEX))) {
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (NULL);
+ }
+
+ if (shnum != 0 || shoff == 0LL) { /* not using extended numbering */
+ e->e_u.e_elf.e_nphdr = phnum;
+ e->e_u.e_elf.e_nscn = shnum;
+ e->e_u.e_elf.e_strndx = strndx;
+ } else if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0)
+ return (NULL);
+
+ return (ehdr);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_extended.c b/linkers/elftoolchain/libelf/libelf_extended.c
new file mode 100644
index 0000000..10590bb
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_extended.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_extended.c 1360 2011-01-08 08:27:41Z jkoshy $");
+
+/*
+ * Retrieve section #0, allocating a new section if needed.
+ */
+static Elf_Scn *
+_libelf_getscn0(Elf *e)
+{
+ Elf_Scn *s;
+
+ if ((s = STAILQ_FIRST(&e->e_u.e_elf.e_scn)) != NULL)
+ return (s);
+
+ return (_libelf_allocate_scn(e, (size_t) SHN_UNDEF));
+}
+
+int
+_libelf_setshnum(Elf *e, void *eh, int ec, size_t shnum)
+{
+ Elf_Scn *scn;
+
+ if (shnum >= SHN_LORESERVE) {
+ if ((scn = _libelf_getscn0(e)) == NULL)
+ return (0);
+
+ assert(scn->s_ndx == SHN_UNDEF);
+
+ if (ec == ELFCLASS32)
+ scn->s_shdr.s_shdr32.sh_size = shnum;
+ else
+ scn->s_shdr.s_shdr64.sh_size = shnum;
+
+ (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ shnum = 0;
+ }
+
+ if (ec == ELFCLASS32)
+ ((Elf32_Ehdr *) eh)->e_shnum = shnum;
+ else
+ ((Elf64_Ehdr *) eh)->e_shnum = shnum;
+
+
+ return (1);
+}
+
+int
+_libelf_setshstrndx(Elf *e, void *eh, int ec, size_t shstrndx)
+{
+ Elf_Scn *scn;
+
+ if (shstrndx >= SHN_LORESERVE) {
+ if ((scn = _libelf_getscn0(e)) == NULL)
+ return (0);
+
+ assert(scn->s_ndx == SHN_UNDEF);
+
+ if (ec == ELFCLASS32)
+ scn->s_shdr.s_shdr32.sh_link = shstrndx;
+ else
+ scn->s_shdr.s_shdr64.sh_link = shstrndx;
+
+ (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ shstrndx = SHN_XINDEX;
+ }
+
+ if (ec == ELFCLASS32)
+ ((Elf32_Ehdr *) eh)->e_shstrndx = shstrndx;
+ else
+ ((Elf64_Ehdr *) eh)->e_shstrndx = shstrndx;
+
+ return (1);
+}
+
+int
+_libelf_setphnum(Elf *e, void *eh, int ec, size_t phnum)
+{
+ Elf_Scn *scn;
+
+ if (phnum >= PN_XNUM) {
+ if ((scn = _libelf_getscn0(e)) == NULL)
+ return (0);
+
+ assert(scn->s_ndx == SHN_UNDEF);
+
+ if (ec == ELFCLASS32)
+ scn->s_shdr.s_shdr32.sh_info = phnum;
+ else
+ scn->s_shdr.s_shdr64.sh_info = phnum;
+
+ (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ phnum = PN_XNUM;
+ }
+
+ if (ec == ELFCLASS32)
+ ((Elf32_Ehdr *) eh)->e_phnum = phnum;
+ else
+ ((Elf64_Ehdr *) eh)->e_phnum = phnum;
+
+ return (1);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_fsize.m4 b/linkers/elftoolchain/libelf/libelf_fsize.m4
new file mode 100644
index 0000000..4829789
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_fsize.m4
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 2006,2008-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_fsize.m4 1724 2011-08-13 05:35:42Z jkoshy $");
+
+/* WARNING: GENERATED FROM __file__. */
+
+/*
+ * Create an array of file sizes from the elf_type definitions
+ */
+
+divert(-1)
+include(SRCDIR`/elf_types.m4')
+
+/*
+ * Translations from structure definitions to the size of their file
+ * representations.
+ */
+
+/* `Basic' types. */
+define(`BYTE_SIZE', 1)
+define(`IDENT_SIZE', `EI_NIDENT')
+
+/* Types that have variable length. */
+define(`GNUHASH_SIZE', 1)
+define(`NOTE_SIZE', 1)
+define(`VDEF_SIZE', 1)
+define(`VNEED_SIZE', 1)
+
+/* Currently unimplemented types. */
+define(`MOVEP_SIZE', 0)
+
+/* Overrides for 32 bit types that do not exist. */
+define(`XWORD_SIZE32', 0)
+define(`SXWORD_SIZE32', 0)
+
+/*
+ * FSZ{32,64} define the sizes of 32 and 64 bit file structures respectively.
+ */
+
+define(`FSZ32',`_FSZ32($1_DEF)')
+define(`_FSZ32',
+ `ifelse($#,1,0,
+ `_BSZ32($1)+_FSZ32(shift($@))')')
+define(`_BSZ32',`$2_SIZE32')
+
+define(`FSZ64',`_FSZ64($1_DEF)')
+define(`_FSZ64',
+ `ifelse($#,1,0,
+ `_BSZ64($1)+_FSZ64(shift($@))')')
+define(`_BSZ64',`$2_SIZE64')
+
+/*
+ * DEFINE_ELF_FSIZES(TYPE,NAME)
+ *
+ * Shorthand for defining for 32 and 64 versions
+ * of elf type TYPE.
+ *
+ * If TYPE`'_SIZE is defined, use its value for both 32 bit and 64 bit
+ * sizes.
+ *
+ * Otherwise, look for a explicit 32/64 bit size definition for TYPE,
+ * TYPE`'_SIZE32 or TYPE`'_SIZE64. If this definition is present, there
+ * is nothing further to do.
+ *
+ * Otherwise, if an Elf{32,64}_`'NAME structure definition is known,
+ * compute an expression that adds up the sizes of the structure's
+ * constituents.
+ *
+ * If such a structure definition is not known, treat TYPE as a primitive
+ * (i.e., integral) type and use sizeof(Elf{32,64}_`'NAME) to get its
+ * file representation size.
+ */
+
+define(`DEFINE_ELF_FSIZE',
+ `ifdef($1`_SIZE',
+ `define($1_SIZE32,$1_SIZE)
+ define($1_SIZE64,$1_SIZE)',
+ `ifdef($1`_SIZE32',`',
+ `ifdef(`Elf32_'$2`_DEF',
+ `define($1_SIZE32,FSZ32(Elf32_$2))',
+ `define($1_SIZE32,`sizeof(Elf32_'$2`)')')')
+ ifdef($1`_SIZE64',`',
+ `ifdef(`Elf64_'$2`_DEF',
+ `define($1_SIZE64,FSZ64(Elf64_$2))',
+ `define($1_SIZE64,`sizeof(Elf64_'$2`)')')')')')
+
+define(`DEFINE_ELF_FSIZES',
+ `ifelse($#,1,`',
+ `DEFINE_ELF_FSIZE($1)
+ DEFINE_ELF_FSIZES(shift($@))')')
+
+DEFINE_ELF_FSIZES(ELF_TYPE_LIST)
+DEFINE_ELF_FSIZE(`IDENT',`') # `IDENT' is a pseudo type
+
+define(`FSIZE',
+ `[ELF_T_$1] = { .fsz32 = $1_SIZE32, .fsz64 = $1_SIZE64 },
+')
+define(`FSIZES',
+ `ifelse($#,1,`',
+ `FSIZE($1)
+FSIZES(shift($@))')')
+
+divert(0)
+
+struct fsize {
+ size_t fsz32;
+ size_t fsz64;
+};
+
+static struct fsize fsize[ELF_T_NUM] = {
+FSIZES(ELF_TYPE_LIST)
+};
+
+size_t
+_libelf_fsize(Elf_Type t, int ec, unsigned int v, size_t c)
+{
+ size_t sz;
+
+ sz = 0;
+ if (v != EV_CURRENT)
+ LIBELF_SET_ERROR(VERSION, 0);
+ else if ((int) t < ELF_T_FIRST || t > ELF_T_LAST)
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ else {
+ sz = ec == ELFCLASS64 ? fsize[t].fsz64 : fsize[t].fsz32;
+ if (sz == 0)
+ LIBELF_SET_ERROR(UNIMPL, 0);
+ }
+
+ return (sz*c);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_msize.m4 b/linkers/elftoolchain/libelf/libelf_msize.m4
new file mode 100644
index 0000000..95621fb
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_msize.m4
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 2006,2008-2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <libelf.h>
+#include <string.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_msize.m4 1724 2011-08-13 05:35:42Z jkoshy $");
+
+/* WARNING: GENERATED FROM __file__. */
+
+struct msize {
+ size_t msz32;
+ size_t msz64;
+};
+
+divert(-1)
+include(SRCDIR`/elf_types.m4')
+
+/*
+ * ELF types whose memory representations have a variable size.
+ */
+define(BYTE_SIZE, 1)
+define(GNUHASH_SIZE, 1)
+define(NOTE_SIZE, 1)
+define(VDEF_SIZE, 1)
+define(VNEED_SIZE, 1)
+
+/*
+ * Unimplemented types.
+ */
+define(MOVEP_SIZE, 0)
+define(SXWORD_SIZE32, 0)
+define(XWORD_SIZE32, 0)
+
+define(`DEFINE_ELF_MSIZE',
+ `ifdef($1`_SIZE',
+ `define($1_SIZE32,$1_SIZE)
+ define($1_SIZE64,$1_SIZE)',
+ `ifdef($1`_SIZE32',`',
+ `define($1_SIZE32,sizeof(Elf32_$2))')
+ ifdef($1`_SIZE64',`',
+ `define($1_SIZE64,sizeof(Elf64_$2))')')')
+define(`DEFINE_ELF_MSIZES',
+ `ifelse($#,1,`',
+ `DEFINE_ELF_MSIZE($1)
+ DEFINE_ELF_MSIZES(shift($@))')')
+
+DEFINE_ELF_MSIZES(ELF_TYPE_LIST)
+
+define(`MSIZE',
+ `[ELF_T_$1] = { .msz32 = $1_SIZE32, .msz64 = $1_SIZE64 },
+')
+define(`MSIZES',
+ `ifelse($#,1,`',
+ `MSIZE($1)
+MSIZES(shift($@))')')
+
+divert(0)
+
+static struct msize msize[ELF_T_NUM] = {
+MSIZES(ELF_TYPE_LIST)
+};
+
+size_t
+_libelf_msize(Elf_Type t, int elfclass, unsigned int version)
+{
+ size_t sz;
+
+ assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
+ assert((signed) t >= ELF_T_FIRST && t <= ELF_T_LAST);
+
+ if (version != EV_CURRENT) {
+ LIBELF_SET_ERROR(VERSION, 0);
+ return (0);
+ }
+
+ sz = (elfclass == ELFCLASS32) ? msize[t].msz32 : msize[t].msz64;
+
+ return (sz);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_phdr.c b/linkers/elftoolchain/libelf/libelf_phdr.c
new file mode 100644
index 0000000..5a5bb5f
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_phdr.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <stdlib.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_phdr.c 1677 2011-07-28 04:35:53Z jkoshy $");
+
+void *
+_libelf_getphdr(Elf *e, int ec)
+{
+ size_t phnum, phentsize;
+ size_t fsz, msz;
+ uint64_t phoff;
+ Elf32_Ehdr *eh32;
+ Elf64_Ehdr *eh64;
+ void *ehdr, *phdr;
+ int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
+
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if ((phdr = (ec == ELFCLASS32 ?
+ (void *) e->e_u.e_elf.e_phdr.e_phdr32 :
+ (void *) e->e_u.e_elf.e_phdr.e_phdr64)) != NULL)
+ return (phdr);
+
+ /*
+ * Check the PHDR related fields in the EHDR for sanity.
+ */
+
+ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (NULL);
+
+ phnum = e->e_u.e_elf.e_nphdr;
+
+ if (ec == ELFCLASS32) {
+ eh32 = (Elf32_Ehdr *) ehdr;
+ phentsize = eh32->e_phentsize;
+ phoff = (uint64_t) eh32->e_phoff;
+ } else {
+ eh64 = (Elf64_Ehdr *) ehdr;
+ phentsize = eh64->e_phentsize;
+ phoff = (uint64_t) eh64->e_phoff;
+ }
+
+ fsz = gelf_fsize(e, ELF_T_PHDR, phnum, e->e_version);
+
+ assert(fsz > 0);
+
+ if ((uint64_t) e->e_rawsize < (phoff + fsz)) {
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (NULL);
+ }
+
+ msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT);
+
+ assert(msz > 0);
+
+ if ((phdr = calloc(phnum, msz)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32)
+ e->e_u.e_elf.e_phdr.e_phdr32 = phdr;
+ else
+ e->e_u.e_elf.e_phdr.e_phdr64 = phdr;
+
+
+ xlator = _libelf_get_translator(ELF_T_PHDR, ELF_TOMEMORY, ec);
+ (*xlator)(phdr, phnum * msz, e->e_rawfile + phoff, phnum,
+ e->e_byteorder != LIBELF_PRIVATE(byteorder));
+
+ return (phdr);
+}
+
+void *
+_libelf_newphdr(Elf *e, int ec, size_t count)
+{
+ void *ehdr, *newphdr, *oldphdr;
+ size_t msz;
+
+ if (e == NULL) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) {
+ LIBELF_SET_ERROR(SEQUENCE, 0);
+ return (NULL);
+ }
+
+ assert(e->e_class == ec);
+ assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+ assert(e->e_version == EV_CURRENT);
+
+ msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version);
+
+ assert(msz > 0);
+
+ newphdr = NULL;
+ if (count > 0 && (newphdr = calloc(count, msz)) == NULL) {
+ LIBELF_SET_ERROR(RESOURCE, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASS32) {
+ if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr32) != NULL)
+ free(oldphdr);
+ e->e_u.e_elf.e_phdr.e_phdr32 = (Elf32_Phdr *) newphdr;
+ } else {
+ if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr64) != NULL)
+ free(oldphdr);
+ e->e_u.e_elf.e_phdr.e_phdr64 = (Elf64_Phdr *) newphdr;
+ }
+
+ e->e_u.e_elf.e_nphdr = count;
+
+ elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY);
+
+ return (newphdr);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_shdr.c b/linkers/elftoolchain/libelf/libelf_shdr.c
new file mode 100644
index 0000000..a696cef
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_shdr.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <gelf.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_shdr.c 189 2008-07-20 10:38:08Z jkoshy $");
+
+void *
+_libelf_getshdr(Elf_Scn *s, int ec)
+{
+ Elf *e;
+
+ if (s == NULL || (e = s->s_elf) == NULL ||
+ e->e_kind != ELF_K_ELF) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ if (ec == ELFCLASSNONE)
+ ec = e->e_class;
+
+ if (ec != e->e_class) {
+ LIBELF_SET_ERROR(CLASS, 0);
+ return (NULL);
+ }
+
+ return ((void *) &s->s_shdr);
+}
diff --git a/linkers/elftoolchain/libelf/libelf_xlate.c b/linkers/elftoolchain/libelf/libelf_xlate.c
new file mode 100644
index 0000000..ace4e09
--- /dev/null
+++ b/linkers/elftoolchain/libelf/libelf_xlate.c
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 2006,2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+LIBELF_VCSID("$Id: libelf_xlate.c 316 2009-02-28 16:08:44Z jkoshy $");
+
+/*
+ * Translate to/from the file representation of ELF objects.
+ *
+ * Translation could potentially involve the following
+ * transformations:
+ *
+ * - an endianness conversion,
+ * - a change of layout, as the file representation of ELF objects
+ * can differ from their in-memory representation.
+ * - a change in representation due to a layout version change.
+ */
+
+Elf_Data *
+_libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding,
+ int elfclass, int direction)
+{
+ int byteswap;
+ size_t cnt, dsz, fsz, msz;
+ uintptr_t sb, se, db, de;
+
+ if (encoding == ELFDATANONE)
+ encoding = LIBELF_PRIVATE(byteorder);
+
+ if ((encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) ||
+ dst == NULL || src == NULL || dst == src) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (NULL);
+ }
+
+ assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
+ assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
+
+ if (dst->d_version != src->d_version) {
+ LIBELF_SET_ERROR(UNIMPL, 0);
+ return (NULL);
+ }
+
+ if (src->d_buf == NULL || dst->d_buf == NULL) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ if ((int) src->d_type < 0 || src->d_type >= ELF_T_NUM) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)
+ (src->d_type, (size_t) 1, src->d_version)) == 0)
+ return (NULL);
+
+ msz = _libelf_msize(src->d_type, elfclass, src->d_version);
+
+ assert(msz > 0);
+
+ if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ /*
+ * Determine the number of objects that need to be converted, and
+ * the space required for the converted objects in the destination
+ * buffer.
+ */
+ if (direction == ELF_TOMEMORY) {
+ cnt = src->d_size / fsz;
+ dsz = cnt * msz;
+ } else {
+ cnt = src->d_size / msz;
+ dsz = cnt * fsz;
+ }
+
+ if (dst->d_size < dsz) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ sb = (uintptr_t) src->d_buf;
+ se = sb + src->d_size;
+ db = (uintptr_t) dst->d_buf;
+ de = db + dst->d_size;
+
+ /*
+ * Check for overlapping buffers. Note that db == sb is
+ * allowed.
+ */
+ if (db != sb && de > sb && se > db) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ if ((direction == ELF_TOMEMORY ? db : sb) %
+ _libelf_malign(src->d_type, elfclass)) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ dst->d_type = src->d_type;
+ dst->d_size = dsz;
+
+ byteswap = encoding != LIBELF_PRIVATE(byteorder);
+
+ if (src->d_size == 0 ||
+ (db == sb && !byteswap && fsz == msz))
+ return (dst); /* nothing more to do */
+
+ if (!(_libelf_get_translator(src->d_type, direction, elfclass))
+ (dst->d_buf, dsz, src->d_buf, cnt, byteswap)) {
+ LIBELF_SET_ERROR(DATA, 0);
+ return (NULL);
+ }
+
+ return (dst);
+}
diff --git a/linkers/elftoolchain/libelf/mmap_win32.c b/linkers/elftoolchain/libelf/mmap_win32.c
new file mode 100644
index 0000000..f801fc6
--- /dev/null
+++ b/linkers/elftoolchain/libelf/mmap_win32.c
@@ -0,0 +1,247 @@
+/*-
+ * Copyright (c) 2011 Chris Johns <chrisj@rtems.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Basic mmap/munmap set of functions that allows software that needs to use
+ * these functions to work without changing. Currently only the basic read
+ * has been tested.
+ *
+ * The basic was taken from the implementation in Python 3.x by Sam Rushing
+ * <rushing@nightmare.com>.
+ */
+
+#ifndef __WIN32__
+#error "Wrong OS; only for WIN32"
+#endif
+
+#include <errno.h>
+#include <stdint.h>
+#include <windows.h>
+
+/*
+ * Bring in the local mman.h header to make sure the interface is in sync.
+ */
+#include <sys/mman.h>
+
+/*
+ * The data for each map. Maintained as a list. If performance is important maybe
+ * some other container can be used.
+ */
+typedef struct mmap_data_s
+{
+ struct mmap_data_s* next;
+ void* data;
+ HANDLE file_handle;
+ HANDLE map_handle;
+ size_t size;
+ off_t offset;
+} mmap_data;
+
+/*
+ * Head of the map list.
+ */
+static mmap_data* map_head;
+
+void*
+mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+ mmap_data* map = NULL;
+ DWORD flProtect;
+ DWORD dwDesiredAccess;
+ HANDLE fh = 0;
+ DWORD dwErr = 0;
+ DWORD size_lo;
+ DWORD size_hi;
+ DWORD off_lo;
+ DWORD off_hi;
+ uint64_t size = 0;
+
+ if ((fd == 0) || (fd == -1))
+ return MAP_FAILED;
+
+ /*
+ * Not implemented. Patches welcome.
+ */
+ if (prot & PROT_EXEC)
+ return MAP_FAILED;
+
+ /*
+ * Map the protection.
+ */
+ if ((prot & PROT_READ) == PROT_READ)
+ {
+ flProtect = PAGE_READONLY;
+ dwDesiredAccess = FILE_MAP_READ;
+ }
+ if ((prot & PROT_WRITE) == PROT_WRITE)
+ {
+ flProtect = PAGE_WRITECOPY;
+ dwDesiredAccess = FILE_MAP_WRITE;
+ }
+ if ((prot & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE))
+ {
+ flProtect = PAGE_READWRITE;
+ dwDesiredAccess = FILE_MAP_WRITE;
+ }
+
+ fh = (HANDLE) _get_osfhandle (fd);
+ if (fh == (HANDLE) -1)
+ return MAP_FAILED;
+
+ /*
+ * Win9x appears to need us seeked to zero.
+ */
+ lseek (fd, 0, SEEK_SET);
+
+ /*
+ * Allocate the space to handle the mapping.
+ */
+ map = malloc (sizeof (mmap_data));
+ if (!map)
+ return MAP_FAILED;
+
+ map->next = NULL;
+ map->data = NULL;
+ map->file_handle = fh;
+ map->map_handle = NULL;
+ map->offset = offset;
+
+ if (len == 0)
+ {
+ DWORD low;
+ DWORD high;
+
+ low = GetFileSize (fh, &high);
+
+ /*
+ * Low might just happen to have the value INVALID_FILE_SIZE; so we need to
+ * check the last error also.
+ */
+ if ((low == INVALID_FILE_SIZE) && (dwErr = GetLastError()) != NO_ERROR)
+ {
+ free (map);
+ return MAP_FAILED;
+ }
+
+ size = (((uint64_t) high) << 32) + low;
+
+ if (offset >= size)
+ {
+ free (map);
+ return MAP_FAILED;
+ }
+
+ if (offset - size > (size_t) -1LL)
+ /* Map area too large to fit in memory */
+ map->size = (size_t) -1;
+ else
+ map->size = (size_t) (size - offset);
+ }
+ else
+ {
+ map->size = len;
+ size = offset + len;
+ }
+
+ size_hi = (DWORD)(size >> 32);
+ size_lo = (DWORD)(size & 0xFFFFFFFF);
+ off_hi = (DWORD)(0);
+ off_lo = (DWORD)(offset & 0xFFFFFFFF);
+
+ /*
+ * For files, it would be sufficient to pass 0 as size. For anonymous maps,
+ * we have to pass the size explicitly.
+ */
+ map->map_handle = CreateFileMapping (map->file_handle,
+ NULL,
+ flProtect,
+ size_hi,
+ size_lo,
+ NULL);
+ if (!map->map_handle)
+ {
+ free (map);
+ return MAP_FAILED;
+ }
+
+ map->data = (char *) MapViewOfFileEx (map->map_handle,
+ dwDesiredAccess,
+ off_hi,
+ off_lo,
+ map->size,
+ addr);
+ if (!map->data)
+ {
+ CloseHandle (map->map_handle);
+ free (map);
+ return MAP_FAILED;
+ }
+
+ /*
+ * Add to the list.
+ */
+ map->next = map_head;
+ map_head = map;
+
+ return map->data;
+}
+
+int
+munmap (void* addr, size_t len)
+{
+ mmap_data* map = map_head;
+ mmap_data** prev_next = &map_head;
+
+ /*
+ * Find the map and remove from the list.
+ */
+ while (map)
+ {
+ if (map->data == addr)
+ {
+ *prev_next = map->next;
+ break;
+ }
+ prev_next = &map->next;
+ map = map->next;
+ }
+
+ if (!map)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (map->data != NULL)
+ UnmapViewOfFile (map->data);
+ if (map->map_handle != NULL)
+ CloseHandle (map->map_handle);
+
+ free (map);
+
+ errno = 0;
+ return 0;
+}
diff --git a/linkers/elftoolchain/libelf/os.FreeBSD.mk b/linkers/elftoolchain/libelf/os.FreeBSD.mk
new file mode 100644
index 0000000..72834b7
--- /dev/null
+++ b/linkers/elftoolchain/libelf/os.FreeBSD.mk
@@ -0,0 +1,7 @@
+#
+# Building for a FreeBSD target.
+#
+# $Id: os.FreeBSD.mk 710 2010-02-17 14:21:38Z jkoshy $
+
+# Symbol versioning support [FreeBSD 7.X and later]
+VERSION_MAP= ${.CURDIR}/Version.map
diff --git a/linkers/elftoolchain/libelf/os.NetBSD.mk b/linkers/elftoolchain/libelf/os.NetBSD.mk
new file mode 100644
index 0000000..96b8335
--- /dev/null
+++ b/linkers/elftoolchain/libelf/os.NetBSD.mk
@@ -0,0 +1,7 @@
+#
+# Build recipes for NetBSD.
+#
+# $Id: os.NetBSD.mk 710 2010-02-17 14:21:38Z jkoshy $
+#
+
+MKLINT= no # lint dies with a sigbus
diff --git a/linkers/fastlz.c b/linkers/fastlz.c
new file mode 100644
index 0000000..3c9d6f6
--- /dev/null
+++ b/linkers/fastlz.c
@@ -0,0 +1,551 @@
+/*
+ FastLZ - lightning-fast lossless compression library
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in 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:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ 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
+ AUTHORS 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 IN
+ THE SOFTWARE.
+*/
+
+#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
+
+/*
+ * Always check for bound when decompressing.
+ * Generally it is best to leave it defined.
+ */
+#define FASTLZ_SAFE
+
+/*
+ * Give hints to the compiler for branch prediction optimization.
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2)
+#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
+#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
+#else
+#define FASTLZ_EXPECT_CONDITIONAL(c) (c)
+#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
+#endif
+
+/*
+ * Use inlined functions for supported systems.
+ */
+#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
+#define FASTLZ_INLINE inline
+#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
+#define FASTLZ_INLINE __inline
+#else
+#define FASTLZ_INLINE
+#endif
+
+/*
+ * Prevent accessing more than 8-bit at once, except on x86 architectures.
+ */
+#if !defined(FASTLZ_STRICT_ALIGN)
+#define FASTLZ_STRICT_ALIGN
+#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(_M_IX86) /* Intel, MSVC */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__386)
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(_X86_) /* MinGW */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__I86__) /* Digital Mars */
+#undef FASTLZ_STRICT_ALIGN
+#endif
+#endif
+
+/*
+ * FIXME: use preprocessor magic to set this on different platforms!
+ */
+typedef unsigned char flzuint8;
+typedef unsigned short flzuint16;
+typedef unsigned int flzuint32;
+
+/* prototypes */
+int fastlz_compress(const void* input, int length, void* output);
+int fastlz_compress_level(int level, const void* input, int length, void* output);
+int fastlz_decompress(const void* input, int length, void* output, int maxout);
+
+#define MAX_COPY 32
+#define MAX_LEN 264 /* 256 + 8 */
+#define MAX_DISTANCE 8192
+
+#if !defined(FASTLZ_STRICT_ALIGN)
+#define FASTLZ_READU16(p) *((const flzuint16*)(p))
+#else
+#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
+#endif
+
+#define HASH_LOG 13
+#define HASH_SIZE (1<< HASH_LOG)
+#define HASH_MASK (HASH_SIZE-1)
+#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
+
+#undef FASTLZ_LEVEL
+#define FASTLZ_LEVEL 1
+
+#undef FASTLZ_COMPRESSOR
+#undef FASTLZ_DECOMPRESSOR
+#define FASTLZ_COMPRESSOR fastlz1_compress
+#define FASTLZ_DECOMPRESSOR fastlz1_decompress
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
+#include "fastlz.c"
+
+#undef FASTLZ_LEVEL
+#define FASTLZ_LEVEL 2
+
+#undef MAX_DISTANCE
+#define MAX_DISTANCE 8191
+#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
+
+#undef FASTLZ_COMPRESSOR
+#undef FASTLZ_DECOMPRESSOR
+#define FASTLZ_COMPRESSOR fastlz2_compress
+#define FASTLZ_DECOMPRESSOR fastlz2_decompress
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
+#include "fastlz.c"
+
+int fastlz_compress(const void* input, int length, void* output)
+{
+ /* for short block, choose fastlz1 */
+ if(length < 65536)
+ return fastlz1_compress(input, length, output);
+
+ /* else... */
+ return fastlz2_compress(input, length, output);
+}
+
+int fastlz_decompress(const void* input, int length, void* output, int maxout)
+{
+ /* magic identifier for compression level */
+ int level = ((*(const flzuint8*)input) >> 5) + 1;
+
+ if(level == 1)
+ return fastlz1_decompress(input, length, output, maxout);
+ if(level == 2)
+ return fastlz2_decompress(input, length, output, maxout);
+
+ /* unknown level, trigger error */
+ return 0;
+}
+
+int fastlz_compress_level(int level, const void* input, int length, void* output)
+{
+ if(level == 1)
+ return fastlz1_compress(input, length, output);
+ if(level == 2)
+ return fastlz2_compress(input, length, output);
+
+ return 0;
+}
+
+#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
+
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
+{
+ const flzuint8* ip = (const flzuint8*) input;
+ const flzuint8* ip_bound = ip + length - 2;
+ const flzuint8* ip_limit = ip + length - 12;
+ flzuint8* op = (flzuint8*) output;
+
+ const flzuint8* htab[HASH_SIZE];
+ const flzuint8** hslot;
+ flzuint32 hval;
+
+ flzuint32 copy;
+
+ /* sanity check */
+ if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
+ {
+ if(length)
+ {
+ /* create literal copy only */
+ *op++ = length-1;
+ ip_bound++;
+ while(ip <= ip_bound)
+ *op++ = *ip++;
+ return length+1;
+ }
+ else
+ return 0;
+ }
+
+ /* initializes hash table */
+ for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
+ *hslot = ip;
+
+ /* we start with literal copy */
+ copy = 2;
+ *op++ = MAX_COPY-1;
+ *op++ = *ip++;
+ *op++ = *ip++;
+
+ /* main loop */
+ while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
+ {
+ const flzuint8* ref;
+ flzuint32 distance;
+
+ /* minimum match length */
+ flzuint32 len = 3;
+
+ /* comparison starting-point */
+ const flzuint8* anchor = ip;
+
+ /* check for a run */
+#if FASTLZ_LEVEL==2
+ if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
+ {
+ distance = 1;
+ ip += 3;
+ ref = anchor - 1 + 3;
+ goto match;
+ }
+#endif
+
+ /* find potential match */
+ HASH_FUNCTION(hval,ip);
+ hslot = htab + hval;
+ ref = htab[hval];
+
+ /* calculate distance to the match */
+ distance = anchor - ref;
+
+ /* update hash table */
+ *hslot = anchor;
+
+ /* is this a match? check the first 3 bytes */
+ if(distance==0 ||
+#if FASTLZ_LEVEL==1
+ (distance >= MAX_DISTANCE) ||
+#else
+ (distance >= MAX_FARDISTANCE) ||
+#endif
+ *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
+ goto literal;
+
+#if FASTLZ_LEVEL==2
+ /* far, needs at least 5-byte match */
+ if(distance >= MAX_DISTANCE)
+ {
+ if(*ip++ != *ref++ || *ip++!= *ref++)
+ goto literal;
+ len += 2;
+ }
+
+ match:
+#endif
+
+ /* last matched byte */
+ ip = anchor + len;
+
+ /* distance is biased */
+ distance--;
+
+ if(!distance)
+ {
+ /* zero distance means a run */
+ flzuint8 x = ip[-1];
+ while(ip < ip_bound)
+ if(*ref++ != x) break; else ip++;
+ }
+ else
+ for(;;)
+ {
+ /* safe because the outer check against ip limit */
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ while(ip < ip_bound)
+ if(*ref++ != *ip++) break;
+ break;
+ }
+
+ /* if we have copied something, adjust the copy count */
+ if(copy)
+ /* copy is biased, '0' means 1 byte copy */
+ *(op-copy-1) = copy-1;
+ else
+ /* back, to overwrite the copy count */
+ op--;
+
+ /* reset literal counter */
+ copy = 0;
+
+ /* length is biased, '1' means a match of 3 bytes */
+ ip -= 3;
+ len = ip - anchor;
+
+ /* encode the match */
+#if FASTLZ_LEVEL==2
+ if(distance < MAX_DISTANCE)
+ {
+ if(len < 7)
+ {
+ *op++ = (len << 5) + (distance >> 8);
+ *op++ = (distance & 255);
+ }
+ else
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ for(len-=7; len >= 255; len-= 255)
+ *op++ = 255;
+ *op++ = len;
+ *op++ = (distance & 255);
+ }
+ }
+ else
+ {
+ /* far away, but not yet in the another galaxy... */
+ if(len < 7)
+ {
+ distance -= MAX_DISTANCE;
+ *op++ = (len << 5) + 31;
+ *op++ = 255;
+ *op++ = distance >> 8;
+ *op++ = distance & 255;
+ }
+ else
+ {
+ distance -= MAX_DISTANCE;
+ *op++ = (7 << 5) + 31;
+ for(len-=7; len >= 255; len-= 255)
+ *op++ = 255;
+ *op++ = len;
+ *op++ = 255;
+ *op++ = distance >> 8;
+ *op++ = distance & 255;
+ }
+ }
+#else
+
+ if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
+ while(len > MAX_LEN-2)
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ *op++ = MAX_LEN - 2 - 7 -2;
+ *op++ = (distance & 255);
+ len -= MAX_LEN-2;
+ }
+
+ if(len < 7)
+ {
+ *op++ = (len << 5) + (distance >> 8);
+ *op++ = (distance & 255);
+ }
+ else
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ *op++ = len - 7;
+ *op++ = (distance & 255);
+ }
+#endif
+
+ /* update the hash at match boundary */
+ HASH_FUNCTION(hval,ip);
+ htab[hval] = ip++;
+ HASH_FUNCTION(hval,ip);
+ htab[hval] = ip++;
+
+ /* assuming literal copy */
+ *op++ = MAX_COPY-1;
+
+ continue;
+
+ literal:
+ *op++ = *anchor++;
+ ip = anchor;
+ copy++;
+ if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
+ {
+ copy = 0;
+ *op++ = MAX_COPY-1;
+ }
+ }
+
+ /* left-over as literal copy */
+ ip_bound++;
+ while(ip <= ip_bound)
+ {
+ *op++ = *ip++;
+ copy++;
+ if(copy == MAX_COPY)
+ {
+ copy = 0;
+ *op++ = MAX_COPY-1;
+ }
+ }
+
+ /* if we have copied something, adjust the copy length */
+ if(copy)
+ *(op-copy-1) = copy-1;
+ else
+ op--;
+
+#if FASTLZ_LEVEL==2
+ /* marker for fastlz2 */
+ *(flzuint8*)output |= (1 << 5);
+#endif
+
+ return op - (flzuint8*)output;
+}
+
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
+{
+ const flzuint8* ip = (const flzuint8*) input;
+ const flzuint8* ip_limit = ip + length;
+ flzuint8* op = (flzuint8*) output;
+ flzuint8* op_limit = op + maxout;
+ flzuint32 ctrl = (*ip++) & 31;
+ int loop = 1;
+
+ do
+ {
+ const flzuint8* ref = op;
+ flzuint32 len = ctrl >> 5;
+ flzuint32 ofs = (ctrl & 31) << 8;
+
+ if(ctrl >= 32)
+ {
+#if FASTLZ_LEVEL==2
+ flzuint8 code;
+#endif
+ len--;
+ ref -= ofs;
+ if (len == 7-1)
+#if FASTLZ_LEVEL==1
+ len += *ip++;
+ ref -= *ip++;
+#else
+ do
+ {
+ code = *ip++;
+ len += code;
+ } while (code==255);
+ code = *ip++;
+ ref -= code;
+
+ /* match from 16-bit distance */
+ if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
+ if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
+ {
+ ofs = (*ip++) << 8;
+ ofs += *ip++;
+ ref = op - ofs - MAX_DISTANCE;
+ }
+#endif
+
+#ifdef FASTLZ_SAFE
+ if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
+ return 0;
+
+ if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
+ return 0;
+#endif
+
+ if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
+ ctrl = *ip++;
+ else
+ loop = 0;
+
+ if(ref == op)
+ {
+ /* optimize copy for a run */
+ flzuint8 b = ref[-1];
+ *op++ = b;
+ *op++ = b;
+ *op++ = b;
+ for(; len; --len)
+ *op++ = b;
+ }
+ else
+ {
+#if !defined(FASTLZ_STRICT_ALIGN)
+ const flzuint16* p;
+ flzuint16* q;
+#endif
+ /* copy from reference */
+ ref--;
+ *op++ = *ref++;
+ *op++ = *ref++;
+ *op++ = *ref++;
+
+#if !defined(FASTLZ_STRICT_ALIGN)
+ /* copy a byte, so that now it's word aligned */
+ if(len & 1)
+ {
+ *op++ = *ref++;
+ len--;
+ }
+
+ /* copy 16-bit at once */
+ q = (flzuint16*) op;
+ op += len;
+ p = (const flzuint16*) ref;
+ for(len>>=1; len > 4; len-=4)
+ {
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ }
+ for(; len; --len)
+ *q++ = *p++;
+#else
+ for(; len; --len)
+ *op++ = *ref++;
+#endif
+ }
+ }
+ else
+ {
+ ctrl++;
+#ifdef FASTLZ_SAFE
+ if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
+ return 0;
+ if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
+ return 0;
+#endif
+
+ *op++ = *ip++;
+ for(--ctrl; ctrl; ctrl--)
+ *op++ = *ip++;
+
+ loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
+ if(loop)
+ ctrl = *ip++;
+ }
+ }
+ while(FASTLZ_EXPECT_CONDITIONAL(loop));
+
+ return op - (flzuint8*)output;
+}
+
+#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
diff --git a/linkers/fastlz.h b/linkers/fastlz.h
new file mode 100644
index 0000000..f87bc7b
--- /dev/null
+++ b/linkers/fastlz.h
@@ -0,0 +1,100 @@
+/*
+ FastLZ - lightning-fast lossless compression library
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in 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:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ 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
+ AUTHORS 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 IN
+ THE SOFTWARE.
+*/
+
+#ifndef FASTLZ_H
+#define FASTLZ_H
+
+#define FASTLZ_VERSION 0x000100
+
+#define FASTLZ_VERSION_MAJOR 0
+#define FASTLZ_VERSION_MINOR 0
+#define FASTLZ_VERSION_REVISION 0
+
+#define FASTLZ_VERSION_STRING "0.1.0"
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/**
+ Compress a block of data in the input buffer and returns the size of
+ compressed block. The size of input buffer is specified by length. The
+ minimum input buffer size is 16.
+
+ The output buffer must be at least 5% larger than the input buffer
+ and can not be smaller than 66 bytes.
+
+ If the input is not compressible, the return value might be larger than
+ length (input buffer size).
+
+ The input buffer and the output buffer can not overlap.
+*/
+
+int fastlz_compress(const void* input, int length, void* output);
+
+/**
+ Decompress a block of compressed data and returns the size of the
+ decompressed block. If error occurs, e.g. the compressed data is
+ corrupted or the output buffer is not large enough, then 0 (zero)
+ will be returned instead.
+
+ The input buffer and the output buffer can not overlap.
+
+ Decompression is memory safe and guaranteed not to write the output buffer
+ more than what is specified in maxout.
+ */
+
+int fastlz_decompress(const void* input, int length, void* output, int maxout);
+
+/**
+ Compress a block of data in the input buffer and returns the size of
+ compressed block. The size of input buffer is specified by length. The
+ minimum input buffer size is 16.
+
+ The output buffer must be at least 5% larger than the input buffer
+ and can not be smaller than 66 bytes.
+
+ If the input is not compressible, the return value might be larger than
+ length (input buffer size).
+
+ The input buffer and the output buffer can not overlap.
+
+ Compression level can be specified in parameter level. At the moment,
+ only level 1 and level 2 are supported.
+ Level 1 is the fastest compression and generally useful for short data.
+ Level 2 is slightly slower but it gives better compression ratio.
+
+ Note that the compressed data, regardless of the level, can always be
+ decompressed using the function fastlz_decompress above.
+*/
+
+int fastlz_compress_level(int level, const void* input, int length, void* output);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* FASTLZ_H */
diff --git a/linkers/libiberty/ansidecl.h b/linkers/libiberty/ansidecl.h
new file mode 100644
index 0000000..86b0944
--- /dev/null
+++ b/linkers/libiberty/ansidecl.h
@@ -0,0 +1,423 @@
+/* ANSI and traditional C compatability macros
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004, 2005, 2006, 2007, 2009
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+This program 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. */
+
+/* ANSI and traditional C compatibility macros
+
+ ANSI C is assumed if __STDC__ is #defined.
+
+ Macro ANSI C definition Traditional C definition
+ ----- ---- - ---------- ----------- - ----------
+ ANSI_PROTOTYPES 1 not defined
+ PTR `void *' `char *'
+ PTRCONST `void *const' `char *'
+ LONG_DOUBLE `long double' `double'
+ const not defined `'
+ volatile not defined `'
+ signed not defined `'
+ VA_START(ap, var) va_start(ap, var) va_start(ap)
+
+ Note that it is safe to write "void foo();" indicating a function
+ with no return value, in all K+R compilers we have been able to test.
+
+ For declaring functions with prototypes, we also provide these:
+
+ PARAMS ((prototype))
+ -- for functions which take a fixed number of arguments. Use this
+ when declaring the function. When defining the function, write a
+ K+R style argument list. For example:
+
+ char *strcpy PARAMS ((char *dest, char *source));
+ ...
+ char *
+ strcpy (dest, source)
+ char *dest;
+ char *source;
+ { ... }
+
+
+ VPARAMS ((prototype, ...))
+ -- for functions which take a variable number of arguments. Use
+ PARAMS to declare the function, VPARAMS to define it. For example:
+
+ int printf PARAMS ((const char *format, ...));
+ ...
+ int
+ printf VPARAMS ((const char *format, ...))
+ {
+ ...
+ }
+
+ For writing functions which take variable numbers of arguments, we
+ also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These
+ hide the differences between K+R <varargs.h> and C89 <stdarg.h> more
+ thoroughly than the simple VA_START() macro mentioned above.
+
+ VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end.
+ Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls
+ corresponding to the list of fixed arguments. Then use va_arg
+ normally to get the variable arguments, or pass your va_list object
+ around. You do not declare the va_list yourself; VA_OPEN does it
+ for you.
+
+ Here is a complete example:
+
+ int
+ printf VPARAMS ((const char *format, ...))
+ {
+ int result;
+
+ VA_OPEN (ap, format);
+ VA_FIXEDARG (ap, const char *, format);
+
+ result = vfprintf (stdout, format, ap);
+ VA_CLOSE (ap);
+
+ return result;
+ }
+
+
+ You can declare variables either before or after the VA_OPEN,
+ VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning
+ and end of a block. They must appear at the same nesting level,
+ and any variables declared after VA_OPEN go out of scope at
+ VA_CLOSE. Unfortunately, with a K+R compiler, that includes the
+ argument list. You can have multiple instances of VA_OPEN/VA_CLOSE
+ pairs in a single function in case you need to traverse the
+ argument list more than once.
+
+ For ease of writing code which uses GCC extensions but needs to be
+ portable to other compilers, we provide the GCC_VERSION macro that
+ simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
+ wrappers around __attribute__. Also, __extension__ will be #defined
+ to nothing if it doesn't work. See below.
+
+ This header also defines a lot of obsolete macros:
+ CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID,
+ AND, DOTS, NOARGS. Don't use them. */
+
+#ifndef _ANSIDECL_H
+#define _ANSIDECL_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+/* Using MACRO(x,y) in cpp #if conditionals does not work with some
+ older preprocessors. Thus we can't define something like this:
+
+#define HAVE_GCC_VERSION(MAJOR, MINOR) \
+ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
+
+and then test "#if HAVE_GCC_VERSION(2,7)".
+
+So instead we use the macro below and test it against specific values. */
+
+/* This macro simplifies testing whether we are using gcc, and if it
+ is of a particular minimum version. (Both major & minor numbers are
+ significant.) This macro will evaluate to 0 if we are not using
+ gcc at all. */
+#ifndef GCC_VERSION
+#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif /* GCC_VERSION */
+
+#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32)
+/* All known AIX compilers implement these things (but don't always
+ define __STDC__). The RISC/OS MIPS compiler defines these things
+ in SVR4 mode, but does not define __STDC__. */
+/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
+ C++ compilers, does not define __STDC__, though it acts as if this
+ was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
+
+#define ANSI_PROTOTYPES 1
+#define PTR void *
+#define PTRCONST void *const
+#define LONG_DOUBLE long double
+
+/* PARAMS is often defined elsewhere (e.g. by libintl.h), so wrap it in
+ a #ifndef. */
+#ifndef PARAMS
+#define PARAMS(ARGS) ARGS
+#endif
+
+#define VPARAMS(ARGS) ARGS
+#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR)
+
+/* variadic function helper macros */
+/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's
+ use without inhibiting further decls and without declaring an
+ actual variable. */
+#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy
+#define VA_CLOSE(AP) } va_end(AP); }
+#define VA_FIXEDARG(AP, T, N) struct Qdmy
+
+#undef const
+#undef volatile
+#undef signed
+
+/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
+ it too, but it's not in C89. */
+#undef inline
+#if __STDC_VERSION__ > 199901L || defined(__cplusplus)
+/* it's a keyword */
+#else
+# if GCC_VERSION >= 2007
+# define inline __inline__ /* __inline__ prevents -pedantic warnings */
+# else
+# define inline /* nothing */
+# endif
+#endif
+
+/* These are obsolete. Do not use. */
+#ifndef IN_GCC
+#define CONST const
+#define VOLATILE volatile
+#define SIGNED signed
+
+#define PROTO(type, name, arglist) type name arglist
+#define EXFUN(name, proto) name proto
+#define DEFUN(name, arglist, args) name(args)
+#define DEFUN_VOID(name) name(void)
+#define AND ,
+#define DOTS , ...
+#define NOARGS void
+#endif /* ! IN_GCC */
+
+#else /* Not ANSI C. */
+
+#undef ANSI_PROTOTYPES
+#define PTR char *
+#define PTRCONST PTR
+#define LONG_DOUBLE double
+
+#define PARAMS(args) ()
+#define VPARAMS(args) (va_alist) va_dcl
+#define VA_START(va_list, var) va_start(va_list)
+
+#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy
+#define VA_CLOSE(AP) } va_end(AP); }
+#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE)
+
+/* some systems define these in header files for non-ansi mode */
+#undef const
+#undef volatile
+#undef signed
+#undef inline
+#define const
+#define volatile
+#define signed
+#define inline
+
+#ifndef IN_GCC
+#define CONST
+#define VOLATILE
+#define SIGNED
+
+#define PROTO(type, name, arglist) type name ()
+#define EXFUN(name, proto) name()
+#define DEFUN(name, arglist, args) name arglist args;
+#define DEFUN_VOID(name) name()
+#define AND ;
+#define DOTS
+#define NOARGS
+#endif /* ! IN_GCC */
+
+#endif /* ANSI C. */
+
+/* Define macros for some gcc attributes. This permits us to use the
+ macros freely, and know that they will come into play for the
+ version of gcc in which they are supported. */
+
+#if (GCC_VERSION < 2007)
+# define __attribute__(x)
+#endif
+
+/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
+#ifndef ATTRIBUTE_MALLOC
+# if (GCC_VERSION >= 2096)
+# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+# else
+# define ATTRIBUTE_MALLOC
+# endif /* GNUC >= 2.96 */
+#endif /* ATTRIBUTE_MALLOC */
+
+/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For
+ g++ an attribute on a label must be followed by a semicolon. */
+#ifndef ATTRIBUTE_UNUSED_LABEL
+# ifndef __cplusplus
+# if GCC_VERSION >= 2093
+# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
+# else
+# define ATTRIBUTE_UNUSED_LABEL
+# endif
+# else
+# if GCC_VERSION >= 4005
+# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ;
+# else
+# define ATTRIBUTE_UNUSED_LABEL
+# endif
+# endif
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+
+/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
+ identifier name. */
+#if ! defined(__cplusplus) || (GCC_VERSION >= 3004)
+# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED
+#else /* !__cplusplus || GNUC >= 3.4 */
+# define ARG_UNUSED(NAME) NAME
+#endif /* !__cplusplus || GNUC >= 3.4 */
+
+#ifndef ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#endif /* ATTRIBUTE_NORETURN */
+
+/* Attribute `nonnull' was valid as of gcc 3.3. */
+#ifndef ATTRIBUTE_NONNULL
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
+# else
+# define ATTRIBUTE_NONNULL(m)
+# endif /* GNUC >= 3.3 */
+#endif /* ATTRIBUTE_NONNULL */
+
+/* Attribute `pure' was valid as of gcc 3.0. */
+#ifndef ATTRIBUTE_PURE
+# if (GCC_VERSION >= 3000)
+# define ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define ATTRIBUTE_PURE
+# endif /* GNUC >= 3.0 */
+#endif /* ATTRIBUTE_PURE */
+
+/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
+ This was the case for the `printf' format attribute by itself
+ before GCC 3.3, but as of 3.3 we need to add the `nonnull'
+ attribute to retain this behavior. */
+#ifndef ATTRIBUTE_PRINTF
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
+#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
+#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
+#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
+#endif /* ATTRIBUTE_PRINTF */
+
+/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on
+ a function pointer. Format attributes were allowed on function
+ pointers as of gcc 3.1. */
+#ifndef ATTRIBUTE_FPTR_PRINTF
+# if (GCC_VERSION >= 3001)
+# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n)
+# else
+# define ATTRIBUTE_FPTR_PRINTF(m, n)
+# endif /* GNUC >= 3.1 */
+# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2)
+# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3)
+# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4)
+# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5)
+# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6)
+#endif /* ATTRIBUTE_FPTR_PRINTF */
+
+/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
+ NULL format specifier was allowed as of gcc 3.3. */
+#ifndef ATTRIBUTE_NULL_PRINTF
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
+# else
+# define ATTRIBUTE_NULL_PRINTF(m, n)
+# endif /* GNUC >= 3.3 */
+# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
+# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
+# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
+# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
+# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
+#endif /* ATTRIBUTE_NULL_PRINTF */
+
+/* Attribute `sentinel' was valid as of gcc 3.5. */
+#ifndef ATTRIBUTE_SENTINEL
+# if (GCC_VERSION >= 3005)
+# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
+# else
+# define ATTRIBUTE_SENTINEL
+# endif /* GNUC >= 3.5 */
+#endif /* ATTRIBUTE_SENTINEL */
+
+
+#ifndef ATTRIBUTE_ALIGNED_ALIGNOF
+# if (GCC_VERSION >= 3000)
+# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m))))
+# else
+# define ATTRIBUTE_ALIGNED_ALIGNOF(m)
+# endif /* GNUC >= 3.0 */
+#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
+
+/* Useful for structures whose layout must much some binary specification
+ regardless of the alignment and padding qualities of the compiler. */
+#ifndef ATTRIBUTE_PACKED
+# define ATTRIBUTE_PACKED __attribute__ ((packed))
+#endif
+
+/* Attribute `hot' and `cold' was valid as of gcc 4.3. */
+#ifndef ATTRIBUTE_COLD
+# if (GCC_VERSION >= 4003)
+# define ATTRIBUTE_COLD __attribute__ ((__cold__))
+# else
+# define ATTRIBUTE_COLD
+# endif /* GNUC >= 4.3 */
+#endif /* ATTRIBUTE_COLD */
+#ifndef ATTRIBUTE_HOT
+# if (GCC_VERSION >= 4003)
+# define ATTRIBUTE_HOT __attribute__ ((__hot__))
+# else
+# define ATTRIBUTE_HOT
+# endif /* GNUC >= 4.3 */
+#endif /* ATTRIBUTE_HOT */
+
+/* We use __extension__ in some places to suppress -pedantic warnings
+ about GCC extensions. This feature didn't work properly before
+ gcc 2.8. */
+#if GCC_VERSION < 2008
+#define __extension__
+#endif
+
+/* This is used to declare a const variable which should be visible
+ outside of the current compilation unit. Use it as
+ EXPORTED_CONST int i = 1;
+ This is because the semantics of const are different in C and C++.
+ "extern const" is permitted in C but it looks strange, and gcc
+ warns about it when -Wc++-compat is not used. */
+#ifdef __cplusplus
+#define EXPORTED_CONST extern const
+#else
+#define EXPORTED_CONST const
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ansidecl.h */
diff --git a/linkers/libiberty/concat.c b/linkers/libiberty/concat.c
new file mode 100644
index 0000000..9779d56
--- /dev/null
+++ b/linkers/libiberty/concat.c
@@ -0,0 +1,234 @@
+/* Concatenate variable number of strings.
+ Copyright (C) 1991, 1994, 2001, 2011 Free Software Foundation, Inc.
+ Written by Fred Fish @ Cygnus Support
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+
+/*
+
+@deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @
+ @dots{}, @code{NULL})
+
+Concatenate zero or more of strings and return the result in freshly
+@code{xmalloc}ed memory. Returns @code{NULL} if insufficient memory is
+available. The argument list is terminated by the first @code{NULL}
+pointer encountered. Pointers to empty strings are ignored.
+
+@end deftypefn
+
+NOTES
+
+ This function uses xmalloc() which is expected to be a front end
+ function to malloc() that deals with low memory situations. In
+ typical use, if malloc() returns NULL then xmalloc() diverts to an
+ error handler routine which never returns, and thus xmalloc will
+ never return a NULL pointer. If the client application wishes to
+ deal with low memory situations itself, it should supply an xmalloc
+ that just directly invokes malloc and blindly returns whatever
+ malloc returns.
+
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ansidecl.h"
+#include "libiberty.h"
+#include <sys/types.h> /* size_t */
+
+#include <stdarg.h>
+
+# if HAVE_STRING_H
+# include <string.h>
+# else
+# if HAVE_STRINGS_H
+# include <strings.h>
+# endif
+# endif
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+static inline unsigned long vconcat_length (const char *, va_list);
+static inline unsigned long
+vconcat_length (const char *first, va_list args)
+{
+ unsigned long length = 0;
+ const char *arg;
+
+ for (arg = first; arg ; arg = va_arg (args, const char *))
+ length += strlen (arg);
+
+ return length;
+}
+
+static inline char *
+vconcat_copy (char *dst, const char *first, va_list args)
+{
+ char *end = dst;
+ const char *arg;
+
+ for (arg = first; arg ; arg = va_arg (args, const char *))
+ {
+ unsigned long length = strlen (arg);
+ memcpy (end, arg, length);
+ end += length;
+ }
+ *end = '\000';
+
+ return dst;
+}
+
+/* @undocumented concat_length */
+
+unsigned long
+concat_length (const char *first, ...)
+{
+ unsigned long length;
+
+ VA_OPEN (args, first);
+ VA_FIXEDARG (args, const char *, first);
+ length = vconcat_length (first, args);
+ VA_CLOSE (args);
+
+ return length;
+}
+
+/* @undocumented concat_copy */
+
+char *
+concat_copy (char *dst, const char *first, ...)
+{
+ char *save_dst;
+
+ VA_OPEN (args, first);
+ VA_FIXEDARG (args, char *, dst);
+ VA_FIXEDARG (args, const char *, first);
+ vconcat_copy (dst, first, args);
+ save_dst = dst; /* With K&R C, dst goes out of scope here. */
+ VA_CLOSE (args);
+
+ return save_dst;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+char *libiberty_concat_ptr;
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+/* @undocumented concat_copy2 */
+
+char *
+concat_copy2 (const char *first, ...)
+{
+ VA_OPEN (args, first);
+ VA_FIXEDARG (args, const char *, first);
+ vconcat_copy (libiberty_concat_ptr, first, args);
+ VA_CLOSE (args);
+
+ return libiberty_concat_ptr;
+}
+
+char *
+concat (const char *first, ...)
+{
+ char *newstr;
+
+ /* First compute the size of the result and get sufficient memory. */
+ VA_OPEN (args, first);
+ VA_FIXEDARG (args, const char *, first);
+ newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
+ VA_CLOSE (args);
+
+ /* Now copy the individual pieces to the result string. */
+ VA_OPEN (args, first);
+ VA_FIXEDARG (args, const char *, first);
+ vconcat_copy (newstr, first, args);
+ VA_CLOSE (args);
+
+ return newstr;
+}
+
+/*
+
+@deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @
+ @dots{}, @code{NULL})
+
+Same as @code{concat}, except that if @var{optr} is not @code{NULL} it
+is freed after the string is created. This is intended to be useful
+when you're extending an existing string or building up a string in a
+loop:
+
+@example
+ str = reconcat (str, "pre-", str, NULL);
+@end example
+
+@end deftypefn
+
+*/
+
+char *
+reconcat (char *optr, const char *first, ...)
+{
+ char *newstr;
+
+ /* First compute the size of the result and get sufficient memory. */
+ VA_OPEN (args, first);
+ VA_FIXEDARG (args, char *, optr);
+ VA_FIXEDARG (args, const char *, first);
+ newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
+ VA_CLOSE (args);
+
+ /* Now copy the individual pieces to the result string. */
+ VA_OPEN (args, first);
+ VA_FIXEDARG (args, char *, optr);
+ VA_FIXEDARG (args, const char *, first);
+ vconcat_copy (newstr, first, args);
+ if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C. */
+ free (optr);
+ VA_CLOSE (args);
+
+ return newstr;
+}
+
+#ifdef MAIN
+#define NULLP (char *)0
+
+/* Simple little test driver. */
+
+#include <stdio.h>
+
+int
+main (void)
+{
+ printf ("\"\" = \"%s\"\n", concat (NULLP));
+ printf ("\"a\" = \"%s\"\n", concat ("a", NULLP));
+ printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP));
+ printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP));
+ printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP));
+ printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP));
+ printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP));
+ return 0;
+}
+
+#endif
diff --git a/linkers/libiberty/cp-demangle.c b/linkers/libiberty/cp-demangle.c
new file mode 100644
index 0000000..c590561
--- /dev/null
+++ b/linkers/libiberty/cp-demangle.c
@@ -0,0 +1,5064 @@
+/* Demangler for g++ V3 ABI.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@wasabisystems.com>.
+
+ This file is part of the libiberty library, which is part of GCC.
+
+ 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.
+
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file. (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combined
+ executable.)
+
+ 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 code implements a demangler for the g++ V3 ABI. The ABI is
+ described on this web page:
+ http://www.codesourcery.com/cxx-abi/abi.html#mangling
+
+ This code was written while looking at the demangler written by
+ Alex Samuel <samuel@codesourcery.com>.
+
+ This code first pulls the mangled name apart into a list of
+ components, and then walks the list generating the demangled
+ name.
+
+ This file will normally define the following functions, q.v.:
+ char *cplus_demangle_v3(const char *mangled, int options)
+ char *java_demangle_v3(const char *mangled)
+ int cplus_demangle_v3_callback(const char *mangled, int options,
+ demangle_callbackref callback)
+ int java_demangle_v3_callback(const char *mangled,
+ demangle_callbackref callback)
+ enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name)
+ enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name)
+
+ Also, the interface to the component list is public, and defined in
+ demangle.h. The interface consists of these types, which are
+ defined in demangle.h:
+ enum demangle_component_type
+ struct demangle_component
+ demangle_callbackref
+ and these functions defined in this file:
+ cplus_demangle_fill_name
+ cplus_demangle_fill_extended_operator
+ cplus_demangle_fill_ctor
+ cplus_demangle_fill_dtor
+ cplus_demangle_print
+ cplus_demangle_print_callback
+ and other functions defined in the file cp-demint.c.
+
+ This file also defines some other functions and variables which are
+ only to be used by the file cp-demint.c.
+
+ Preprocessor macros you can define while compiling this file:
+
+ IN_LIBGCC2
+ If defined, this file defines the following functions, q.v.:
+ char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
+ int *status)
+ int __gcclibcxx_demangle_callback (const char *,
+ void (*)
+ (const char *, size_t, void *),
+ void *)
+ instead of cplus_demangle_v3[_callback]() and
+ java_demangle_v3[_callback]().
+
+ IN_GLIBCPP_V3
+ If defined, this file defines only __cxa_demangle() and
+ __gcclibcxx_demangle_callback(), and no other publically visible
+ functions or variables.
+
+ STANDALONE_DEMANGLER
+ If defined, this file defines a main() function which demangles
+ any arguments, or, if none, demangles stdin.
+
+ CP_DEMANGLE_DEBUG
+ If defined, turns on debugging mode, which prints information on
+ stdout about the mangled string. This is not generally useful.
+*/
+
+#if defined (_AIX) && !defined (__GNUC__)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#else
+# ifndef alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# else
+extern char *alloca ();
+# endif /* __GNUC__ */
+# endif /* alloca */
+#endif /* HAVE_ALLOCA_H */
+
+#include "ansidecl.h"
+#include "libiberty.h"
+#include "demangle.h"
+#include "cp-demangle.h"
+
+/* If IN_GLIBCPP_V3 is defined, some functions are made static. We
+ also rename them via #define to avoid compiler errors when the
+ static definition conflicts with the extern declaration in a header
+ file. */
+#ifdef IN_GLIBCPP_V3
+
+#define CP_STATIC_IF_GLIBCPP_V3 static
+
+#define cplus_demangle_fill_name d_fill_name
+static int d_fill_name (struct demangle_component *, const char *, int);
+
+#define cplus_demangle_fill_extended_operator d_fill_extended_operator
+static int
+d_fill_extended_operator (struct demangle_component *, int,
+ struct demangle_component *);
+
+#define cplus_demangle_fill_ctor d_fill_ctor
+static int
+d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds,
+ struct demangle_component *);
+
+#define cplus_demangle_fill_dtor d_fill_dtor
+static int
+d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds,
+ struct demangle_component *);
+
+#define cplus_demangle_mangled_name d_mangled_name
+static struct demangle_component *d_mangled_name (struct d_info *, int);
+
+#define cplus_demangle_type d_type
+static struct demangle_component *d_type (struct d_info *);
+
+#define cplus_demangle_print d_print
+static char *d_print (int, const struct demangle_component *, int, size_t *);
+
+#define cplus_demangle_print_callback d_print_callback
+static int d_print_callback (int, const struct demangle_component *,
+ demangle_callbackref, void *);
+
+#define cplus_demangle_init_info d_init_info
+static void d_init_info (const char *, int, size_t, struct d_info *);
+
+#else /* ! defined(IN_GLIBCPP_V3) */
+#define CP_STATIC_IF_GLIBCPP_V3
+#endif /* ! defined(IN_GLIBCPP_V3) */
+
+/* See if the compiler supports dynamic arrays. */
+
+#ifdef __GNUC__
+#define CP_DYNAMIC_ARRAYS
+#else
+#ifdef __STDC__
+#ifdef __STDC_VERSION__
+#if __STDC_VERSION__ >= 199901L
+#define CP_DYNAMIC_ARRAYS
+#endif /* __STDC__VERSION >= 199901L */
+#endif /* defined (__STDC_VERSION__) */
+#endif /* defined (__STDC__) */
+#endif /* ! defined (__GNUC__) */
+
+/* We avoid pulling in the ctype tables, to prevent pulling in
+ additional unresolved symbols when this code is used in a library.
+ FIXME: Is this really a valid reason? This comes from the original
+ V3 demangler code.
+
+ As of this writing this file has the following undefined references
+ when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy,
+ strcat, strlen. */
+
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
+#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
+
+/* The prefix prepended by GCC to an identifier represnting the
+ anonymous namespace. */
+#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_"
+#define ANONYMOUS_NAMESPACE_PREFIX_LEN \
+ (sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1)
+
+/* Information we keep for the standard substitutions. */
+
+struct d_standard_sub_info
+{
+ /* The code for this substitution. */
+ char code;
+ /* The simple string it expands to. */
+ const char *simple_expansion;
+ /* The length of the simple expansion. */
+ int simple_len;
+ /* The results of a full, verbose, expansion. This is used when
+ qualifying a constructor/destructor, or when in verbose mode. */
+ const char *full_expansion;
+ /* The length of the full expansion. */
+ int full_len;
+ /* What to set the last_name field of d_info to; NULL if we should
+ not set it. This is only relevant when qualifying a
+ constructor/destructor. */
+ const char *set_last_name;
+ /* The length of set_last_name. */
+ int set_last_name_len;
+};
+
+/* Accessors for subtrees of struct demangle_component. */
+
+#define d_left(dc) ((dc)->u.s_binary.left)
+#define d_right(dc) ((dc)->u.s_binary.right)
+
+/* A list of templates. This is used while printing. */
+
+struct d_print_template
+{
+ /* Next template on the list. */
+ struct d_print_template *next;
+ /* This template. */
+ const struct demangle_component *template_decl;
+};
+
+/* A list of type modifiers. This is used while printing. */
+
+struct d_print_mod
+{
+ /* Next modifier on the list. These are in the reverse of the order
+ in which they appeared in the mangled string. */
+ struct d_print_mod *next;
+ /* The modifier. */
+ const struct demangle_component *mod;
+ /* Whether this modifier was printed. */
+ int printed;
+ /* The list of templates which applies to this modifier. */
+ struct d_print_template *templates;
+};
+
+/* We use these structures to hold information during printing. */
+
+struct d_growable_string
+{
+ /* Buffer holding the result. */
+ char *buf;
+ /* Current length of data in buffer. */
+ size_t len;
+ /* Allocated size of buffer. */
+ size_t alc;
+ /* Set to 1 if we had a memory allocation failure. */
+ int allocation_failure;
+};
+
+enum { D_PRINT_BUFFER_LENGTH = 256 };
+struct d_print_info
+{
+ /* The options passed to the demangler. */
+ int options;
+ /* Fixed-length allocated buffer for demangled data, flushed to the
+ callback with a NUL termination once full. */
+ char buf[D_PRINT_BUFFER_LENGTH];
+ /* Current length of data in buffer. */
+ size_t len;
+ /* The last character printed, saved individually so that it survives
+ any buffer flush. */
+ char last_char;
+ /* Callback function to handle demangled buffer flush. */
+ demangle_callbackref callback;
+ /* Opaque callback argument. */
+ void *opaque;
+ /* The current list of templates, if any. */
+ struct d_print_template *templates;
+ /* The current list of modifiers (e.g., pointer, reference, etc.),
+ if any. */
+ struct d_print_mod *modifiers;
+ /* Set to 1 if we saw a demangling error. */
+ int demangle_failure;
+ /* The current index into any template argument packs we are using
+ for printing. */
+ int pack_index;
+};
+
+#ifdef CP_DEMANGLE_DEBUG
+static void d_dump (struct demangle_component *, int);
+#endif
+
+static struct demangle_component *
+d_make_empty (struct d_info *);
+
+static struct demangle_component *
+d_make_comp (struct d_info *, enum demangle_component_type,
+ struct demangle_component *,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_name (struct d_info *, const char *, int);
+
+static struct demangle_component *
+d_make_builtin_type (struct d_info *,
+ const struct demangle_builtin_type_info *);
+
+static struct demangle_component *
+d_make_operator (struct d_info *,
+ const struct demangle_operator_info *);
+
+static struct demangle_component *
+d_make_extended_operator (struct d_info *, int,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_template_param (struct d_info *, long);
+
+static struct demangle_component *
+d_make_sub (struct d_info *, const char *, int);
+
+static int
+has_return_type (struct demangle_component *);
+
+static int
+is_ctor_dtor_or_conversion (struct demangle_component *);
+
+static struct demangle_component *d_encoding (struct d_info *, int);
+
+static struct demangle_component *d_name (struct d_info *);
+
+static struct demangle_component *d_nested_name (struct d_info *);
+
+static struct demangle_component *d_prefix (struct d_info *);
+
+static struct demangle_component *d_unqualified_name (struct d_info *);
+
+static struct demangle_component *d_source_name (struct d_info *);
+
+static long d_number (struct d_info *);
+
+static struct demangle_component *d_identifier (struct d_info *, int);
+
+static struct demangle_component *d_operator_name (struct d_info *);
+
+static struct demangle_component *d_special_name (struct d_info *);
+
+static int d_call_offset (struct d_info *, int);
+
+static struct demangle_component *d_ctor_dtor_name (struct d_info *);
+
+static struct demangle_component **
+d_cv_qualifiers (struct d_info *, struct demangle_component **, int);
+
+static struct demangle_component *
+d_function_type (struct d_info *);
+
+static struct demangle_component *
+d_bare_function_type (struct d_info *, int);
+
+static struct demangle_component *
+d_class_enum_type (struct d_info *);
+
+static struct demangle_component *d_array_type (struct d_info *);
+
+static struct demangle_component *
+d_pointer_to_member_type (struct d_info *);
+
+static struct demangle_component *
+d_template_param (struct d_info *);
+
+static struct demangle_component *d_template_args (struct d_info *);
+
+static struct demangle_component *
+d_template_arg (struct d_info *);
+
+static struct demangle_component *d_expression (struct d_info *);
+
+static struct demangle_component *d_expr_primary (struct d_info *);
+
+static struct demangle_component *d_local_name (struct d_info *);
+
+static int d_discriminator (struct d_info *);
+
+static int
+d_add_substitution (struct d_info *, struct demangle_component *);
+
+static struct demangle_component *d_substitution (struct d_info *, int);
+
+static void d_growable_string_init (struct d_growable_string *, size_t);
+
+static inline void
+d_growable_string_resize (struct d_growable_string *, size_t);
+
+static inline void
+d_growable_string_append_buffer (struct d_growable_string *,
+ const char *, size_t);
+static void
+d_growable_string_callback_adapter (const char *, size_t, void *);
+
+static void
+d_print_init (struct d_print_info *, int, demangle_callbackref, void *);
+
+static inline void d_print_error (struct d_print_info *);
+
+static inline int d_print_saw_error (struct d_print_info *);
+
+static inline void d_print_flush (struct d_print_info *);
+
+static inline void d_append_char (struct d_print_info *, char);
+
+static inline void d_append_buffer (struct d_print_info *,
+ const char *, size_t);
+
+static inline void d_append_string (struct d_print_info *, const char *);
+
+static inline char d_last_char (struct d_print_info *);
+
+static void
+d_print_comp (struct d_print_info *, const struct demangle_component *);
+
+static void
+d_print_java_identifier (struct d_print_info *, const char *, int);
+
+static void
+d_print_mod_list (struct d_print_info *, struct d_print_mod *, int);
+
+static void
+d_print_mod (struct d_print_info *, const struct demangle_component *);
+
+static void
+d_print_function_type (struct d_print_info *,
+ const struct demangle_component *,
+ struct d_print_mod *);
+
+static void
+d_print_array_type (struct d_print_info *,
+ const struct demangle_component *,
+ struct d_print_mod *);
+
+static void
+d_print_expr_op (struct d_print_info *, const struct demangle_component *);
+
+static void
+d_print_cast (struct d_print_info *, const struct demangle_component *);
+
+static int d_demangle_callback (const char *, int,
+ demangle_callbackref, void *);
+static char *d_demangle (const char *, int, size_t *);
+
+#ifdef CP_DEMANGLE_DEBUG
+
+static void
+d_dump (struct demangle_component *dc, int indent)
+{
+ int i;
+
+ if (dc == NULL)
+ {
+ if (indent == 0)
+ printf ("failed demangling\n");
+ return;
+ }
+
+ for (i = 0; i < indent; ++i)
+ putchar (' ');
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_NAME:
+ printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
+ return;
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ printf ("template parameter %ld\n", dc->u.s_number.number);
+ return;
+ case DEMANGLE_COMPONENT_CTOR:
+ printf ("constructor %d\n", (int) dc->u.s_ctor.kind);
+ d_dump (dc->u.s_ctor.name, indent + 2);
+ return;
+ case DEMANGLE_COMPONENT_DTOR:
+ printf ("destructor %d\n", (int) dc->u.s_dtor.kind);
+ d_dump (dc->u.s_dtor.name, indent + 2);
+ return;
+ case DEMANGLE_COMPONENT_SUB_STD:
+ printf ("standard substitution %s\n", dc->u.s_string.string);
+ return;
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ printf ("builtin type %s\n", dc->u.s_builtin.type->name);
+ return;
+ case DEMANGLE_COMPONENT_OPERATOR:
+ printf ("operator %s\n", dc->u.s_operator.op->name);
+ return;
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ printf ("extended operator with %d args\n",
+ dc->u.s_extended_operator.args);
+ d_dump (dc->u.s_extended_operator.name, indent + 2);
+ return;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ printf ("qualified name\n");
+ break;
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ printf ("local name\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ printf ("typed name\n");
+ break;
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ printf ("template\n");
+ break;
+ case DEMANGLE_COMPONENT_VTABLE:
+ printf ("vtable\n");
+ break;
+ case DEMANGLE_COMPONENT_VTT:
+ printf ("VTT\n");
+ break;
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ printf ("construction vtable\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ printf ("typeinfo\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ printf ("typeinfo name\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ printf ("typeinfo function\n");
+ break;
+ case DEMANGLE_COMPONENT_THUNK:
+ printf ("thunk\n");
+ break;
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ printf ("virtual thunk\n");
+ break;
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ printf ("covariant thunk\n");
+ break;
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ printf ("java class\n");
+ break;
+ case DEMANGLE_COMPONENT_GUARD:
+ printf ("guard\n");
+ break;
+ case DEMANGLE_COMPONENT_REFTEMP:
+ printf ("reference temporary\n");
+ break;
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ printf ("hidden alias\n");
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT:
+ printf ("restrict\n");
+ break;
+ case DEMANGLE_COMPONENT_VOLATILE:
+ printf ("volatile\n");
+ break;
+ case DEMANGLE_COMPONENT_CONST:
+ printf ("const\n");
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ printf ("restrict this\n");
+ break;
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ printf ("volatile this\n");
+ break;
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ printf ("const this\n");
+ break;
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ printf ("vendor type qualifier\n");
+ break;
+ case DEMANGLE_COMPONENT_POINTER:
+ printf ("pointer\n");
+ break;
+ case DEMANGLE_COMPONENT_REFERENCE:
+ printf ("reference\n");
+ break;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ printf ("rvalue reference\n");
+ break;
+ case DEMANGLE_COMPONENT_COMPLEX:
+ printf ("complex\n");
+ break;
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ printf ("imaginary\n");
+ break;
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ printf ("vendor type\n");
+ break;
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ printf ("function type\n");
+ break;
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ printf ("array type\n");
+ break;
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ printf ("pointer to member type\n");
+ break;
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ printf ("fixed-point type\n");
+ break;
+ case DEMANGLE_COMPONENT_ARGLIST:
+ printf ("argument list\n");
+ break;
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ printf ("template argument list\n");
+ break;
+ case DEMANGLE_COMPONENT_CAST:
+ printf ("cast\n");
+ break;
+ case DEMANGLE_COMPONENT_UNARY:
+ printf ("unary operator\n");
+ break;
+ case DEMANGLE_COMPONENT_BINARY:
+ printf ("binary operator\n");
+ break;
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ printf ("binary operator arguments\n");
+ break;
+ case DEMANGLE_COMPONENT_TRINARY:
+ printf ("trinary operator\n");
+ break;
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ printf ("trinary operator arguments 1\n");
+ break;
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ printf ("trinary operator arguments 1\n");
+ break;
+ case DEMANGLE_COMPONENT_LITERAL:
+ printf ("literal\n");
+ break;
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ printf ("negative literal\n");
+ break;
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ printf ("java resource\n");
+ break;
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ printf ("compound name\n");
+ break;
+ case DEMANGLE_COMPONENT_CHARACTER:
+ printf ("character '%c'\n", dc->u.s_character.character);
+ return;
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ printf ("decltype\n");
+ break;
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ printf ("pack expansion\n");
+ break;
+ }
+
+ d_dump (d_left (dc), indent + 2);
+ d_dump (d_right (dc), indent + 2);
+}
+
+#endif /* CP_DEMANGLE_DEBUG */
+
+/* Fill in a DEMANGLE_COMPONENT_NAME. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len)
+{
+ if (p == NULL || s == NULL || len == 0)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_NAME;
+ p->u.s_name.s = s;
+ p->u.s_name.len = len;
+ return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_extended_operator (struct demangle_component *p, int args,
+ struct demangle_component *name)
+{
+ if (p == NULL || args < 0 || name == NULL)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR;
+ p->u.s_extended_operator.args = args;
+ p->u.s_extended_operator.name = name;
+ return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_ctor (struct demangle_component *p,
+ enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name)
+{
+ if (p == NULL
+ || name == NULL
+ || (int) kind < gnu_v3_complete_object_ctor
+ || (int) kind > gnu_v3_complete_object_allocating_ctor)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_CTOR;
+ p->u.s_ctor.kind = kind;
+ p->u.s_ctor.name = name;
+ return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_dtor (struct demangle_component *p,
+ enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name)
+{
+ if (p == NULL
+ || name == NULL
+ || (int) kind < gnu_v3_deleting_dtor
+ || (int) kind > gnu_v3_base_object_dtor)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_DTOR;
+ p->u.s_dtor.kind = kind;
+ p->u.s_dtor.name = name;
+ return 1;
+}
+
+/* Add a new component. */
+
+static struct demangle_component *
+d_make_empty (struct d_info *di)
+{
+ struct demangle_component *p;
+
+ if (di->next_comp >= di->num_comps)
+ return NULL;
+ p = &di->comps[di->next_comp];
+ ++di->next_comp;
+ return p;
+}
+
+/* Add a new generic component. */
+
+static struct demangle_component *
+d_make_comp (struct d_info *di, enum demangle_component_type type,
+ struct demangle_component *left,
+ struct demangle_component *right)
+{
+ struct demangle_component *p;
+
+ /* We check for errors here. A typical error would be a NULL return
+ from a subroutine. We catch those here, and return NULL
+ upward. */
+ switch (type)
+ {
+ /* These types require two parameters. */
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ case DEMANGLE_COMPONENT_UNARY:
+ case DEMANGLE_COMPONENT_BINARY:
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ case DEMANGLE_COMPONENT_TRINARY:
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ case DEMANGLE_COMPONENT_LITERAL:
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ if (left == NULL || right == NULL)
+ return NULL;
+ break;
+
+ /* These types only require one parameter. */
+ case DEMANGLE_COMPONENT_VTABLE:
+ case DEMANGLE_COMPONENT_VTT:
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ case DEMANGLE_COMPONENT_THUNK:
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ case DEMANGLE_COMPONENT_GUARD:
+ case DEMANGLE_COMPONENT_REFTEMP:
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+ case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+ if (left == NULL)
+ return NULL;
+ break;
+
+ /* This needs a right parameter, but the left parameter can be
+ empty. */
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ if (right == NULL)
+ return NULL;
+ break;
+
+ /* These are allowed to have no parameters--in some cases they
+ will be filled in later. */
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ break;
+
+ /* Other types should not be seen here. */
+ default:
+ return NULL;
+ }
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = type;
+ p->u.s_binary.left = left;
+ p->u.s_binary.right = right;
+ }
+ return p;
+}
+
+/* Add a new name component. */
+
+static struct demangle_component *
+d_make_name (struct d_info *di, const char *s, int len)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_name (p, s, len))
+ return NULL;
+ return p;
+}
+
+/* Add a new builtin type component. */
+
+static struct demangle_component *
+d_make_builtin_type (struct d_info *di,
+ const struct demangle_builtin_type_info *type)
+{
+ struct demangle_component *p;
+
+ if (type == NULL)
+ return NULL;
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE;
+ p->u.s_builtin.type = type;
+ }
+ return p;
+}
+
+/* Add a new operator component. */
+
+static struct demangle_component *
+d_make_operator (struct d_info *di, const struct demangle_operator_info *op)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_OPERATOR;
+ p->u.s_operator.op = op;
+ }
+ return p;
+}
+
+/* Add a new extended operator component. */
+
+static struct demangle_component *
+d_make_extended_operator (struct d_info *di, int args,
+ struct demangle_component *name)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_extended_operator (p, args, name))
+ return NULL;
+ return p;
+}
+
+/* Add a new constructor component. */
+
+static struct demangle_component *
+d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_ctor (p, kind, name))
+ return NULL;
+ return p;
+}
+
+/* Add a new destructor component. */
+
+static struct demangle_component *
+d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_dtor (p, kind, name))
+ return NULL;
+ return p;
+}
+
+/* Add a new template parameter. */
+
+static struct demangle_component *
+d_make_template_param (struct d_info *di, long i)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM;
+ p->u.s_number.number = i;
+ }
+ return p;
+}
+
+/* Add a new function parameter. */
+
+static struct demangle_component *
+d_make_function_param (struct d_info *di, long i)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM;
+ p->u.s_number.number = i;
+ }
+ return p;
+}
+
+/* Add a new standard substitution component. */
+
+static struct demangle_component *
+d_make_sub (struct d_info *di, const char *name, int len)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_SUB_STD;
+ p->u.s_string.string = name;
+ p->u.s_string.len = len;
+ }
+ return p;
+}
+
+/* <mangled-name> ::= _Z <encoding>
+
+ TOP_LEVEL is non-zero when called at the top level. */
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_mangled_name (struct d_info *di, int top_level)
+{
+ if (! d_check_char (di, '_')
+ /* Allow missing _ if not at toplevel to work around a
+ bug in G++ abi-version=2 mangling; see the comment in
+ write_template_arg. */
+ && top_level)
+ return NULL;
+ if (! d_check_char (di, 'Z'))
+ return NULL;
+ return d_encoding (di, top_level);
+}
+
+/* Return whether a function should have a return type. The argument
+ is the function name, which may be qualified in various ways. The
+ rules are that template functions have return types with some
+ exceptions, function types which are not part of a function name
+ mangling have return types with some exceptions, and non-template
+ function names do not have return types. The exceptions are that
+ constructors, destructors, and conversion operators do not have
+ return types. */
+
+static int
+has_return_type (struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return 0;
+ switch (dc->type)
+ {
+ default:
+ return 0;
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ return ! is_ctor_dtor_or_conversion (d_left (dc));
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ return has_return_type (d_left (dc));
+ }
+}
+
+/* Return whether a name is a constructor, a destructor, or a
+ conversion operator. */
+
+static int
+is_ctor_dtor_or_conversion (struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return 0;
+ switch (dc->type)
+ {
+ default:
+ return 0;
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ return is_ctor_dtor_or_conversion (d_right (dc));
+ case DEMANGLE_COMPONENT_CTOR:
+ case DEMANGLE_COMPONENT_DTOR:
+ case DEMANGLE_COMPONENT_CAST:
+ return 1;
+ }
+}
+
+/* <encoding> ::= <(function) name> <bare-function-type>
+ ::= <(data) name>
+ ::= <special-name>
+
+ TOP_LEVEL is non-zero when called at the top level, in which case
+ if DMGL_PARAMS is not set we do not demangle the function
+ parameters. We only set this at the top level, because otherwise
+ we would not correctly demangle names in local scopes. */
+
+static struct demangle_component *
+d_encoding (struct d_info *di, int top_level)
+{
+ char peek = d_peek_char (di);
+
+ if (peek == 'G' || peek == 'T')
+ return d_special_name (di);
+ else
+ {
+ struct demangle_component *dc;
+
+ dc = d_name (di);
+
+ if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
+ {
+ /* Strip off any initial CV-qualifiers, as they really apply
+ to the `this' parameter, and they were not output by the
+ v2 demangler without DMGL_PARAMS. */
+ while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
+ dc = d_left (dc);
+
+ /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
+ there may be CV-qualifiers on its right argument which
+ really apply here; this happens when parsing a class
+ which is local to a function. */
+ if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+ {
+ struct demangle_component *dcr;
+
+ dcr = d_right (dc);
+ while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || dcr->type == DEMANGLE_COMPONENT_CONST_THIS)
+ dcr = d_left (dcr);
+ dc->u.s_binary.right = dcr;
+ }
+
+ return dc;
+ }
+
+ peek = d_peek_char (di);
+ if (dc == NULL || peek == '\0' || peek == 'E')
+ return dc;
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc,
+ d_bare_function_type (di, has_return_type (dc)));
+ }
+}
+
+/* <name> ::= <nested-name>
+ ::= <unscoped-name>
+ ::= <unscoped-template-name> <template-args>
+ ::= <local-name>
+
+ <unscoped-name> ::= <unqualified-name>
+ ::= St <unqualified-name>
+
+ <unscoped-template-name> ::= <unscoped-name>
+ ::= <substitution>
+*/
+
+static struct demangle_component *
+d_name (struct d_info *di)
+{
+ char peek = d_peek_char (di);
+ struct demangle_component *dc;
+
+ switch (peek)
+ {
+ case 'N':
+ return d_nested_name (di);
+
+ case 'Z':
+ return d_local_name (di);
+
+ case 'L':
+ return d_unqualified_name (di);
+
+ case 'S':
+ {
+ int subst;
+
+ if (d_peek_next_char (di) != 't')
+ {
+ dc = d_substitution (di, 0);
+ subst = 1;
+ }
+ else
+ {
+ d_advance (di, 2);
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME,
+ d_make_name (di, "std", 3),
+ d_unqualified_name (di));
+ di->expansion += 3;
+ subst = 0;
+ }
+
+ if (d_peek_char (di) != 'I')
+ {
+ /* The grammar does not permit this case to occur if we
+ called d_substitution() above (i.e., subst == 1). We
+ don't bother to check. */
+ }
+ else
+ {
+ /* This is <template-args>, which means that we just saw
+ <unscoped-template-name>, which is a substitution
+ candidate if we didn't just get it from a
+ substitution. */
+ if (! subst)
+ {
+ if (! d_add_substitution (di, dc))
+ return NULL;
+ }
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
+ d_template_args (di));
+ }
+
+ return dc;
+ }
+
+ default:
+ dc = d_unqualified_name (di);
+ if (d_peek_char (di) == 'I')
+ {
+ /* This is <template-args>, which means that we just saw
+ <unscoped-template-name>, which is a substitution
+ candidate. */
+ if (! d_add_substitution (di, dc))
+ return NULL;
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
+ d_template_args (di));
+ }
+ return dc;
+ }
+}
+
+/* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+ ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+*/
+
+static struct demangle_component *
+d_nested_name (struct d_info *di)
+{
+ struct demangle_component *ret;
+ struct demangle_component **pret;
+
+ if (! d_check_char (di, 'N'))
+ return NULL;
+
+ pret = d_cv_qualifiers (di, &ret, 1);
+ if (pret == NULL)
+ return NULL;
+
+ *pret = d_prefix (di);
+ if (*pret == NULL)
+ return NULL;
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+
+ return ret;
+}
+
+/* <prefix> ::= <prefix> <unqualified-name>
+ ::= <template-prefix> <template-args>
+ ::= <template-param>
+ ::=
+ ::= <substitution>
+
+ <template-prefix> ::= <prefix> <(template) unqualified-name>
+ ::= <template-param>
+ ::= <substitution>
+*/
+
+static struct demangle_component *
+d_prefix (struct d_info *di)
+{
+ struct demangle_component *ret = NULL;
+
+ while (1)
+ {
+ char peek;
+ enum demangle_component_type comb_type;
+ struct demangle_component *dc;
+
+ peek = d_peek_char (di);
+ if (peek == '\0')
+ return NULL;
+
+ /* The older code accepts a <local-name> here, but I don't see
+ that in the grammar. The older code does not accept a
+ <template-param> here. */
+
+ comb_type = DEMANGLE_COMPONENT_QUAL_NAME;
+ if (IS_DIGIT (peek)
+ || IS_LOWER (peek)
+ || peek == 'C'
+ || peek == 'D'
+ || peek == 'L')
+ dc = d_unqualified_name (di);
+ else if (peek == 'S')
+ dc = d_substitution (di, 1);
+ else if (peek == 'I')
+ {
+ if (ret == NULL)
+ return NULL;
+ comb_type = DEMANGLE_COMPONENT_TEMPLATE;
+ dc = d_template_args (di);
+ }
+ else if (peek == 'T')
+ dc = d_template_param (di);
+ else if (peek == 'E')
+ return ret;
+ else
+ return NULL;
+
+ if (ret == NULL)
+ ret = dc;
+ else
+ ret = d_make_comp (di, comb_type, ret, dc);
+
+ if (peek != 'S' && d_peek_char (di) != 'E')
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ }
+ }
+}
+
+/* <unqualified-name> ::= <operator-name>
+ ::= <ctor-dtor-name>
+ ::= <source-name>
+ ::= <local-source-name>
+
+ <local-source-name> ::= L <source-name> <discriminator>
+*/
+
+static struct demangle_component *
+d_unqualified_name (struct d_info *di)
+{
+ char peek;
+
+ peek = d_peek_char (di);
+ if (IS_DIGIT (peek))
+ return d_source_name (di);
+ else if (IS_LOWER (peek))
+ {
+ struct demangle_component *ret;
+
+ ret = d_operator_name (di);
+ if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
+ di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
+ return ret;
+ }
+ else if (peek == 'C' || peek == 'D')
+ return d_ctor_dtor_name (di);
+ else if (peek == 'L')
+ {
+ struct demangle_component * ret;
+
+ d_advance (di, 1);
+
+ ret = d_source_name (di);
+ if (ret == NULL)
+ return NULL;
+ if (! d_discriminator (di))
+ return NULL;
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+/* <source-name> ::= <(positive length) number> <identifier> */
+
+static struct demangle_component *
+d_source_name (struct d_info *di)
+{
+ long len;
+ struct demangle_component *ret;
+
+ len = d_number (di);
+ if (len <= 0)
+ return NULL;
+ ret = d_identifier (di, len);
+ di->last_name = ret;
+ return ret;
+}
+
+/* number ::= [n] <(non-negative decimal integer)> */
+
+static long
+d_number (struct d_info *di)
+{
+ int negative;
+ char peek;
+ long ret;
+
+ negative = 0;
+ peek = d_peek_char (di);
+ if (peek == 'n')
+ {
+ negative = 1;
+ d_advance (di, 1);
+ peek = d_peek_char (di);
+ }
+
+ ret = 0;
+ while (1)
+ {
+ if (! IS_DIGIT (peek))
+ {
+ if (negative)
+ ret = - ret;
+ return ret;
+ }
+ ret = ret * 10 + peek - '0';
+ d_advance (di, 1);
+ peek = d_peek_char (di);
+ }
+}
+
+/* identifier ::= <(unqualified source code identifier)> */
+
+static struct demangle_component *
+d_identifier (struct d_info *di, int len)
+{
+ const char *name;
+
+ name = d_str (di);
+
+ if (di->send - name < len)
+ return NULL;
+
+ d_advance (di, len);
+
+ /* A Java mangled name may have a trailing '$' if it is a C++
+ keyword. This '$' is not included in the length count. We just
+ ignore the '$'. */
+ if ((di->options & DMGL_JAVA) != 0
+ && d_peek_char (di) == '$')
+ d_advance (di, 1);
+
+ /* Look for something which looks like a gcc encoding of an
+ anonymous namespace, and replace it with a more user friendly
+ name. */
+ if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
+ && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX,
+ ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0)
+ {
+ const char *s;
+
+ s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN;
+ if ((*s == '.' || *s == '_' || *s == '$')
+ && s[1] == 'N')
+ {
+ di->expansion -= len - sizeof "(anonymous namespace)";
+ return d_make_name (di, "(anonymous namespace)",
+ sizeof "(anonymous namespace)" - 1);
+ }
+ }
+
+ return d_make_name (di, name, len);
+}
+
+/* operator_name ::= many different two character encodings.
+ ::= cv <type>
+ ::= v <digit> <source-name>
+*/
+
+#define NL(s) s, (sizeof s) - 1
+
+CP_STATIC_IF_GLIBCPP_V3
+const struct demangle_operator_info cplus_demangle_operators[] =
+{
+ { "aN", NL ("&="), 2 },
+ { "aS", NL ("="), 2 },
+ { "aa", NL ("&&"), 2 },
+ { "ad", NL ("&"), 1 },
+ { "an", NL ("&"), 2 },
+ { "cl", NL ("()"), 2 },
+ { "cm", NL (","), 2 },
+ { "co", NL ("~"), 1 },
+ { "dV", NL ("/="), 2 },
+ { "da", NL ("delete[]"), 1 },
+ { "de", NL ("*"), 1 },
+ { "dl", NL ("delete"), 1 },
+ { "dt", NL ("."), 2 },
+ { "dv", NL ("/"), 2 },
+ { "eO", NL ("^="), 2 },
+ { "eo", NL ("^"), 2 },
+ { "eq", NL ("=="), 2 },
+ { "ge", NL (">="), 2 },
+ { "gt", NL (">"), 2 },
+ { "ix", NL ("[]"), 2 },
+ { "lS", NL ("<<="), 2 },
+ { "le", NL ("<="), 2 },
+ { "ls", NL ("<<"), 2 },
+ { "lt", NL ("<"), 2 },
+ { "mI", NL ("-="), 2 },
+ { "mL", NL ("*="), 2 },
+ { "mi", NL ("-"), 2 },
+ { "ml", NL ("*"), 2 },
+ { "mm", NL ("--"), 1 },
+ { "na", NL ("new[]"), 1 },
+ { "ne", NL ("!="), 2 },
+ { "ng", NL ("-"), 1 },
+ { "nt", NL ("!"), 1 },
+ { "nw", NL ("new"), 1 },
+ { "oR", NL ("|="), 2 },
+ { "oo", NL ("||"), 2 },
+ { "or", NL ("|"), 2 },
+ { "pL", NL ("+="), 2 },
+ { "pl", NL ("+"), 2 },
+ { "pm", NL ("->*"), 2 },
+ { "pp", NL ("++"), 1 },
+ { "ps", NL ("+"), 1 },
+ { "pt", NL ("->"), 2 },
+ { "qu", NL ("?"), 3 },
+ { "rM", NL ("%="), 2 },
+ { "rS", NL (">>="), 2 },
+ { "rm", NL ("%"), 2 },
+ { "rs", NL (">>"), 2 },
+ { "st", NL ("sizeof "), 1 },
+ { "sz", NL ("sizeof "), 1 },
+ { "at", NL ("alignof "), 1 },
+ { "az", NL ("alignof "), 1 },
+ { NULL, NULL, 0, 0 }
+};
+
+static struct demangle_component *
+d_operator_name (struct d_info *di)
+{
+ char c1;
+ char c2;
+
+ c1 = d_next_char (di);
+ c2 = d_next_char (di);
+ if (c1 == 'v' && IS_DIGIT (c2))
+ return d_make_extended_operator (di, c2 - '0', d_source_name (di));
+ else if (c1 == 'c' && c2 == 'v')
+ return d_make_comp (di, DEMANGLE_COMPONENT_CAST,
+ cplus_demangle_type (di), NULL);
+ else
+ {
+ /* LOW is the inclusive lower bound. */
+ int low = 0;
+ /* HIGH is the exclusive upper bound. We subtract one to ignore
+ the sentinel at the end of the array. */
+ int high = ((sizeof (cplus_demangle_operators)
+ / sizeof (cplus_demangle_operators[0]))
+ - 1);
+
+ while (1)
+ {
+ int i;
+ const struct demangle_operator_info *p;
+
+ i = low + (high - low) / 2;
+ p = cplus_demangle_operators + i;
+
+ if (c1 == p->code[0] && c2 == p->code[1])
+ return d_make_operator (di, p);
+
+ if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1]))
+ high = i;
+ else
+ low = i + 1;
+ if (low == high)
+ return NULL;
+ }
+ }
+}
+
+static struct demangle_component *
+d_make_character (struct d_info *di, int c)
+{
+ struct demangle_component *p;
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_CHARACTER;
+ p->u.s_character.character = c;
+ }
+ return p;
+}
+
+static struct demangle_component *
+d_java_resource (struct d_info *di)
+{
+ struct demangle_component *p = NULL;
+ struct demangle_component *next = NULL;
+ long len, i;
+ char c;
+ const char *str;
+
+ len = d_number (di);
+ if (len <= 1)
+ return NULL;
+
+ /* Eat the leading '_'. */
+ if (d_next_char (di) != '_')
+ return NULL;
+ len--;
+
+ str = d_str (di);
+ i = 0;
+
+ while (len > 0)
+ {
+ c = str[i];
+ if (!c)
+ return NULL;
+
+ /* Each chunk is either a '$' escape... */
+ if (c == '$')
+ {
+ i++;
+ switch (str[i++])
+ {
+ case 'S':
+ c = '/';
+ break;
+ case '_':
+ c = '.';
+ break;
+ case '$':
+ c = '$';
+ break;
+ default:
+ return NULL;
+ }
+ next = d_make_character (di, c);
+ d_advance (di, i);
+ str = d_str (di);
+ len -= i;
+ i = 0;
+ if (next == NULL)
+ return NULL;
+ }
+ /* ... or a sequence of characters. */
+ else
+ {
+ while (i < len && str[i] && str[i] != '$')
+ i++;
+
+ next = d_make_name (di, str, i);
+ d_advance (di, i);
+ str = d_str (di);
+ len -= i;
+ i = 0;
+ if (next == NULL)
+ return NULL;
+ }
+
+ if (p == NULL)
+ p = next;
+ else
+ {
+ p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next);
+ if (p == NULL)
+ return NULL;
+ }
+ }
+
+ p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL);
+
+ return p;
+}
+
+/* <special-name> ::= TV <type>
+ ::= TT <type>
+ ::= TI <type>
+ ::= TS <type>
+ ::= GV <(object) name>
+ ::= T <call-offset> <(base) encoding>
+ ::= Tc <call-offset> <call-offset> <(base) encoding>
+ Also g++ extensions:
+ ::= TC <type> <(offset) number> _ <(base) type>
+ ::= TF <type>
+ ::= TJ <type>
+ ::= GR <name>
+ ::= GA <encoding>
+ ::= Gr <resource name>
+*/
+
+static struct demangle_component *
+d_special_name (struct d_info *di)
+{
+ di->expansion += 20;
+ if (d_check_char (di, 'T'))
+ {
+ switch (d_next_char (di))
+ {
+ case 'V':
+ di->expansion -= 5;
+ return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE,
+ cplus_demangle_type (di), NULL);
+ case 'T':
+ di->expansion -= 10;
+ return d_make_comp (di, DEMANGLE_COMPONENT_VTT,
+ cplus_demangle_type (di), NULL);
+ case 'I':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO,
+ cplus_demangle_type (di), NULL);
+ case 'S':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME,
+ cplus_demangle_type (di), NULL);
+
+ case 'h':
+ if (! d_call_offset (di, 'h'))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_THUNK,
+ d_encoding (di, 0), NULL);
+
+ case 'v':
+ if (! d_call_offset (di, 'v'))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK,
+ d_encoding (di, 0), NULL);
+
+ case 'c':
+ if (! d_call_offset (di, '\0'))
+ return NULL;
+ if (! d_call_offset (di, '\0'))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK,
+ d_encoding (di, 0), NULL);
+
+ case 'C':
+ {
+ struct demangle_component *derived_type;
+ long offset;
+ struct demangle_component *base_type;
+
+ derived_type = cplus_demangle_type (di);
+ offset = d_number (di);
+ if (offset < 0)
+ return NULL;
+ if (! d_check_char (di, '_'))
+ return NULL;
+ base_type = cplus_demangle_type (di);
+ /* We don't display the offset. FIXME: We should display
+ it in verbose mode. */
+ di->expansion += 5;
+ return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
+ base_type, derived_type);
+ }
+
+ case 'F':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN,
+ cplus_demangle_type (di), NULL);
+ case 'J':
+ return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS,
+ cplus_demangle_type (di), NULL);
+
+ default:
+ return NULL;
+ }
+ }
+ else if (d_check_char (di, 'G'))
+ {
+ switch (d_next_char (di))
+ {
+ case 'V':
+ return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
+
+ case 'R':
+ return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di),
+ NULL);
+
+ case 'A':
+ return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
+ d_encoding (di, 0), NULL);
+
+ case 'r':
+ return d_java_resource (di);
+
+ default:
+ return NULL;
+ }
+ }
+ else
+ return NULL;
+}
+
+/* <call-offset> ::= h <nv-offset> _
+ ::= v <v-offset> _
+
+ <nv-offset> ::= <(offset) number>
+
+ <v-offset> ::= <(offset) number> _ <(virtual offset) number>
+
+ The C parameter, if not '\0', is a character we just read which is
+ the start of the <call-offset>.
+
+ We don't display the offset information anywhere. FIXME: We should
+ display it in verbose mode. */
+
+static int
+d_call_offset (struct d_info *di, int c)
+{
+ if (c == '\0')
+ c = d_next_char (di);
+
+ if (c == 'h')
+ d_number (di);
+ else if (c == 'v')
+ {
+ d_number (di);
+ if (! d_check_char (di, '_'))
+ return 0;
+ d_number (di);
+ }
+ else
+ return 0;
+
+ if (! d_check_char (di, '_'))
+ return 0;
+
+ return 1;
+}
+
+/* <ctor-dtor-name> ::= C1
+ ::= C2
+ ::= C3
+ ::= D0
+ ::= D1
+ ::= D2
+*/
+
+static struct demangle_component *
+d_ctor_dtor_name (struct d_info *di)
+{
+ if (di->last_name != NULL)
+ {
+ if (di->last_name->type == DEMANGLE_COMPONENT_NAME)
+ di->expansion += di->last_name->u.s_name.len;
+ else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD)
+ di->expansion += di->last_name->u.s_string.len;
+ }
+ switch (d_peek_char (di))
+ {
+ case 'C':
+ {
+ enum gnu_v3_ctor_kinds kind;
+
+ switch (d_peek_next_char (di))
+ {
+ case '1':
+ kind = gnu_v3_complete_object_ctor;
+ break;
+ case '2':
+ kind = gnu_v3_base_object_ctor;
+ break;
+ case '3':
+ kind = gnu_v3_complete_object_allocating_ctor;
+ break;
+ default:
+ return NULL;
+ }
+ d_advance (di, 2);
+ return d_make_ctor (di, kind, di->last_name);
+ }
+
+ case 'D':
+ {
+ enum gnu_v3_dtor_kinds kind;
+
+ switch (d_peek_next_char (di))
+ {
+ case '0':
+ kind = gnu_v3_deleting_dtor;
+ break;
+ case '1':
+ kind = gnu_v3_complete_object_dtor;
+ break;
+ case '2':
+ kind = gnu_v3_base_object_dtor;
+ break;
+ default:
+ return NULL;
+ }
+ d_advance (di, 2);
+ return d_make_dtor (di, kind, di->last_name);
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+/* <type> ::= <builtin-type>
+ ::= <function-type>
+ ::= <class-enum-type>
+ ::= <array-type>
+ ::= <pointer-to-member-type>
+ ::= <template-param>
+ ::= <template-template-param> <template-args>
+ ::= <substitution>
+ ::= <CV-qualifiers> <type>
+ ::= P <type>
+ ::= R <type>
+ ::= O <type> (C++0x)
+ ::= C <type>
+ ::= G <type>
+ ::= U <source-name> <type>
+
+ <builtin-type> ::= various one letter codes
+ ::= u <source-name>
+*/
+
+CP_STATIC_IF_GLIBCPP_V3
+const struct demangle_builtin_type_info
+cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
+{
+ /* a */ { NL ("signed char"), NL ("signed char"), D_PRINT_DEFAULT },
+ /* b */ { NL ("bool"), NL ("boolean"), D_PRINT_BOOL },
+ /* c */ { NL ("char"), NL ("byte"), D_PRINT_DEFAULT },
+ /* d */ { NL ("double"), NL ("double"), D_PRINT_FLOAT },
+ /* e */ { NL ("long double"), NL ("long double"), D_PRINT_FLOAT },
+ /* f */ { NL ("float"), NL ("float"), D_PRINT_FLOAT },
+ /* g */ { NL ("__float128"), NL ("__float128"), D_PRINT_FLOAT },
+ /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT },
+ /* i */ { NL ("int"), NL ("int"), D_PRINT_INT },
+ /* j */ { NL ("unsigned int"), NL ("unsigned"), D_PRINT_UNSIGNED },
+ /* k */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* l */ { NL ("long"), NL ("long"), D_PRINT_LONG },
+ /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG },
+ /* n */ { NL ("__int128"), NL ("__int128"), D_PRINT_DEFAULT },
+ /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"),
+ D_PRINT_DEFAULT },
+ /* p */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* q */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* r */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* s */ { NL ("short"), NL ("short"), D_PRINT_DEFAULT },
+ /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT },
+ /* u */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* v */ { NL ("void"), NL ("void"), D_PRINT_VOID },
+ /* w */ { NL ("wchar_t"), NL ("char"), D_PRINT_DEFAULT },
+ /* x */ { NL ("long long"), NL ("long"), D_PRINT_LONG_LONG },
+ /* y */ { NL ("unsigned long long"), NL ("unsigned long long"),
+ D_PRINT_UNSIGNED_LONG_LONG },
+ /* z */ { NL ("..."), NL ("..."), D_PRINT_DEFAULT },
+ /* 26 */ { NL ("decimal32"), NL ("decimal32"), D_PRINT_DEFAULT },
+ /* 27 */ { NL ("decimal64"), NL ("decimal64"), D_PRINT_DEFAULT },
+ /* 28 */ { NL ("decimal128"), NL ("decimal128"), D_PRINT_DEFAULT },
+ /* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT },
+ /* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT },
+ /* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT },
+};
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *ret;
+ int can_subst;
+
+ /* The ABI specifies that when CV-qualifiers are used, the base type
+ is substitutable, and the fully qualified type is substitutable,
+ but the base type with a strict subset of the CV-qualifiers is
+ not substitutable. The natural recursive implementation of the
+ CV-qualifiers would cause subsets to be substitutable, so instead
+ we pull them all off now.
+
+ FIXME: The ABI says that order-insensitive vendor qualifiers
+ should be handled in the same way, but we have no way to tell
+ which vendor qualifiers are order-insensitive and which are
+ order-sensitive. So we just assume that they are all
+ order-sensitive. g++ 3.4 supports only one vendor qualifier,
+ __vector, and it treats it as order-sensitive when mangling
+ names. */
+
+ peek = d_peek_char (di);
+ if (peek == 'r' || peek == 'V' || peek == 'K')
+ {
+ struct demangle_component **pret;
+
+ pret = d_cv_qualifiers (di, &ret, 0);
+ if (pret == NULL)
+ return NULL;
+ *pret = cplus_demangle_type (di);
+ if (! *pret || ! d_add_substitution (di, ret))
+ return NULL;
+ return ret;
+ }
+
+ can_subst = 1;
+
+ switch (peek)
+ {
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+ case 'h': case 'i': case 'j': case 'l': case 'm': case 'n':
+ case 'o': case 's': case 't':
+ case 'v': case 'w': case 'x': case 'y': case 'z':
+ ret = d_make_builtin_type (di,
+ &cplus_demangle_builtin_types[peek - 'a']);
+ di->expansion += ret->u.s_builtin.type->len;
+ can_subst = 0;
+ d_advance (di, 1);
+ break;
+
+ case 'u':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE,
+ d_source_name (di), NULL);
+ break;
+
+ case 'F':
+ ret = d_function_type (di);
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'N':
+ case 'Z':
+ ret = d_class_enum_type (di);
+ break;
+
+ case 'A':
+ ret = d_array_type (di);
+ break;
+
+ case 'M':
+ ret = d_pointer_to_member_type (di);
+ break;
+
+ case 'T':
+ ret = d_template_param (di);
+ if (d_peek_char (di) == 'I')
+ {
+ /* This is <template-template-param> <template-args>. The
+ <template-template-param> part is a substitution
+ candidate. */
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ }
+ break;
+
+ case 'S':
+ /* If this is a special substitution, then it is the start of
+ <class-enum-type>. */
+ {
+ char peek_next;
+
+ peek_next = d_peek_next_char (di);
+ if (IS_DIGIT (peek_next)
+ || peek_next == '_'
+ || IS_UPPER (peek_next))
+ {
+ ret = d_substitution (di, 0);
+ /* The substituted name may have been a template name and
+ may be followed by tepmlate args. */
+ if (d_peek_char (di) == 'I')
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ else
+ can_subst = 0;
+ }
+ else
+ {
+ ret = d_class_enum_type (di);
+ /* If the substitution was a complete type, then it is not
+ a new substitution candidate. However, if the
+ substitution was followed by template arguments, then
+ the whole thing is a substitution candidate. */
+ if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD)
+ can_subst = 0;
+ }
+ }
+ break;
+
+ case 'O':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'P':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'R':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'C':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'G':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'U':
+ d_advance (di, 1);
+ ret = d_source_name (di);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ cplus_demangle_type (di), ret);
+ break;
+
+ case 'D':
+ can_subst = 0;
+ d_advance (di, 1);
+ peek = d_next_char (di);
+ switch (peek)
+ {
+ case 'T':
+ case 't':
+ /* decltype (expression) */
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE,
+ d_expression (di), NULL);
+ if (ret && d_next_char (di) != 'E')
+ ret = NULL;
+ break;
+
+ case 'p':
+ /* Pack expansion. */
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'f':
+ /* 32-bit decimal floating point */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'd':
+ /* 64-bit DFP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'e':
+ /* 128-bit DFP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'h':
+ /* 16-bit half-precision FP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 's':
+ /* char16_t */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'i':
+ /* char32_t */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+
+ case 'F':
+ /* Fixed point types. DF<int bits><length><fract bits><sat> */
+ ret = d_make_empty (di);
+ ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
+ if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
+ /* For demangling we don't care about the bits. */
+ d_number (di);
+ ret->u.s_fixed.length = cplus_demangle_type (di);
+ d_number (di);
+ peek = d_next_char (di);
+ ret->u.s_fixed.sat = (peek == 's');
+ break;
+
+ default:
+ return NULL;
+ }
+ break;
+
+ default:
+ return NULL;
+ }
+
+ if (can_subst)
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* <CV-qualifiers> ::= [r] [V] [K] */
+
+static struct demangle_component **
+d_cv_qualifiers (struct d_info *di,
+ struct demangle_component **pret, int member_fn)
+{
+ char peek;
+
+ peek = d_peek_char (di);
+ while (peek == 'r' || peek == 'V' || peek == 'K')
+ {
+ enum demangle_component_type t;
+
+ d_advance (di, 1);
+ if (peek == 'r')
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_RESTRICT_THIS
+ : DEMANGLE_COMPONENT_RESTRICT);
+ di->expansion += sizeof "restrict";
+ }
+ else if (peek == 'V')
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_VOLATILE_THIS
+ : DEMANGLE_COMPONENT_VOLATILE);
+ di->expansion += sizeof "volatile";
+ }
+ else
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_CONST_THIS
+ : DEMANGLE_COMPONENT_CONST);
+ di->expansion += sizeof "const";
+ }
+
+ *pret = d_make_comp (di, t, NULL, NULL);
+ if (*pret == NULL)
+ return NULL;
+ pret = &d_left (*pret);
+
+ peek = d_peek_char (di);
+ }
+
+ return pret;
+}
+
+/* <function-type> ::= F [Y] <bare-function-type> E */
+
+static struct demangle_component *
+d_function_type (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ if (! d_check_char (di, 'F'))
+ return NULL;
+ if (d_peek_char (di) == 'Y')
+ {
+ /* Function has C linkage. We don't print this information.
+ FIXME: We should print it in verbose mode. */
+ d_advance (di, 1);
+ }
+ ret = d_bare_function_type (di, 1);
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+}
+
+/* <bare-function-type> ::= [J]<type>+ */
+
+static struct demangle_component *
+d_bare_function_type (struct d_info *di, int has_return_type)
+{
+ struct demangle_component *return_type;
+ struct demangle_component *tl;
+ struct demangle_component **ptl;
+ char peek;
+
+ /* Detect special qualifier indicating that the first argument
+ is the return type. */
+ peek = d_peek_char (di);
+ if (peek == 'J')
+ {
+ d_advance (di, 1);
+ has_return_type = 1;
+ }
+
+ return_type = NULL;
+ tl = NULL;
+ ptl = &tl;
+ while (1)
+ {
+ struct demangle_component *type;
+
+ peek = d_peek_char (di);
+ if (peek == '\0' || peek == 'E')
+ break;
+ type = cplus_demangle_type (di);
+ if (type == NULL)
+ return NULL;
+ if (has_return_type)
+ {
+ return_type = type;
+ has_return_type = 0;
+ }
+ else
+ {
+ *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
+ if (*ptl == NULL)
+ return NULL;
+ ptl = &d_right (*ptl);
+ }
+ }
+
+ /* There should be at least one parameter type besides the optional
+ return type. A function which takes no arguments will have a
+ single parameter type void. */
+ if (tl == NULL)
+ return NULL;
+
+ /* If we have a single parameter type void, omit it. */
+ if (d_right (tl) == NULL
+ && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
+ && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID)
+ {
+ di->expansion -= d_left (tl)->u.s_builtin.type->len;
+ tl = NULL;
+ }
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, return_type, tl);
+}
+
+/* <class-enum-type> ::= <name> */
+
+static struct demangle_component *
+d_class_enum_type (struct d_info *di)
+{
+ return d_name (di);
+}
+
+/* <array-type> ::= A <(positive dimension) number> _ <(element) type>
+ ::= A [<(dimension) expression>] _ <(element) type>
+*/
+
+static struct demangle_component *
+d_array_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *dim;
+
+ if (! d_check_char (di, 'A'))
+ return NULL;
+
+ peek = d_peek_char (di);
+ if (peek == '_')
+ dim = NULL;
+ else if (IS_DIGIT (peek))
+ {
+ const char *s;
+
+ s = d_str (di);
+ do
+ {
+ d_advance (di, 1);
+ peek = d_peek_char (di);
+ }
+ while (IS_DIGIT (peek));
+ dim = d_make_name (di, s, d_str (di) - s);
+ if (dim == NULL)
+ return NULL;
+ }
+ else
+ {
+ dim = d_expression (di);
+ if (dim == NULL)
+ return NULL;
+ }
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim,
+ cplus_demangle_type (di));
+}
+
+/* <pointer-to-member-type> ::= M <(class) type> <(member) type> */
+
+static struct demangle_component *
+d_pointer_to_member_type (struct d_info *di)
+{
+ struct demangle_component *cl;
+ struct demangle_component *mem;
+ struct demangle_component **pmem;
+
+ if (! d_check_char (di, 'M'))
+ return NULL;
+
+ cl = cplus_demangle_type (di);
+
+ /* The ABI specifies that any type can be a substitution source, and
+ that M is followed by two types, and that when a CV-qualified
+ type is seen both the base type and the CV-qualified types are
+ substitution sources. The ABI also specifies that for a pointer
+ to a CV-qualified member function, the qualifiers are attached to
+ the second type. Given the grammar, a plain reading of the ABI
+ suggests that both the CV-qualified member function and the
+ non-qualified member function are substitution sources. However,
+ g++ does not work that way. g++ treats only the CV-qualified
+ member function as a substitution source. FIXME. So to work
+ with g++, we need to pull off the CV-qualifiers here, in order to
+ avoid calling add_substitution() in cplus_demangle_type(). But
+ for a CV-qualified member which is not a function, g++ does
+ follow the ABI, so we need to handle that case here by calling
+ d_add_substitution ourselves. */
+
+ pmem = d_cv_qualifiers (di, &mem, 1);
+ if (pmem == NULL)
+ return NULL;
+ *pmem = cplus_demangle_type (di);
+ if (*pmem == NULL)
+ return NULL;
+
+ if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ {
+ if (! d_add_substitution (di, mem))
+ return NULL;
+ }
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
+}
+
+/* <template-param> ::= T_
+ ::= T <(parameter-2 non-negative) number> _
+*/
+
+static struct demangle_component *
+d_template_param (struct d_info *di)
+{
+ long param;
+
+ if (! d_check_char (di, 'T'))
+ return NULL;
+
+ if (d_peek_char (di) == '_')
+ param = 0;
+ else
+ {
+ param = d_number (di);
+ if (param < 0)
+ return NULL;
+ param += 1;
+ }
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ ++di->did_subs;
+
+ return d_make_template_param (di, param);
+}
+
+/* <template-args> ::= I <template-arg>+ E */
+
+static struct demangle_component *
+d_template_args (struct d_info *di)
+{
+ struct demangle_component *hold_last_name;
+ struct demangle_component *al;
+ struct demangle_component **pal;
+
+ /* Preserve the last name we saw--don't let the template arguments
+ clobber it, as that would give us the wrong name for a subsequent
+ constructor or destructor. */
+ hold_last_name = di->last_name;
+
+ if (! d_check_char (di, 'I'))
+ return NULL;
+
+ if (d_peek_char (di) == 'E')
+ {
+ /* An argument pack can be empty. */
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL);
+ }
+
+ al = NULL;
+ pal = &al;
+ while (1)
+ {
+ struct demangle_component *a;
+
+ a = d_template_arg (di);
+ if (a == NULL)
+ return NULL;
+
+ *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL);
+ if (*pal == NULL)
+ return NULL;
+ pal = &d_right (*pal);
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ break;
+ }
+ }
+
+ di->last_name = hold_last_name;
+
+ return al;
+}
+
+/* <template-arg> ::= <type>
+ ::= X <expression> E
+ ::= <expr-primary>
+*/
+
+static struct demangle_component *
+d_template_arg (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ switch (d_peek_char (di))
+ {
+ case 'X':
+ d_advance (di, 1);
+ ret = d_expression (di);
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+
+ case 'L':
+ return d_expr_primary (di);
+
+ case 'I':
+ /* An argument pack. */
+ return d_template_args (di);
+
+ default:
+ return cplus_demangle_type (di);
+ }
+}
+
+/* Subroutine of <expression> ::= cl <expression>+ E */
+
+static struct demangle_component *
+d_exprlist (struct d_info *di)
+{
+ struct demangle_component *list = NULL;
+ struct demangle_component **p = &list;
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
+ }
+
+ while (1)
+ {
+ struct demangle_component *arg = d_expression (di);
+ if (arg == NULL)
+ return NULL;
+
+ *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL);
+ if (*p == NULL)
+ return NULL;
+ p = &d_right (*p);
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ break;
+ }
+ }
+
+ return list;
+}
+
+/* <expression> ::= <(unary) operator-name> <expression>
+ ::= <(binary) operator-name> <expression> <expression>
+ ::= <(trinary) operator-name> <expression> <expression> <expression>
+ ::= cl <expression>+ E
+ ::= st <type>
+ ::= <template-param>
+ ::= sr <type> <unqualified-name>
+ ::= sr <type> <unqualified-name> <template-args>
+ ::= <expr-primary>
+*/
+
+static struct demangle_component *
+d_expression (struct d_info *di)
+{
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'L')
+ return d_expr_primary (di);
+ else if (peek == 'T')
+ return d_template_param (di);
+ else if (peek == 's' && d_peek_next_char (di) == 'r')
+ {
+ struct demangle_component *type;
+ struct demangle_component *name;
+
+ d_advance (di, 2);
+ type = cplus_demangle_type (di);
+ name = d_unqualified_name (di);
+ if (d_peek_char (di) != 'I')
+ return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
+ else
+ return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
+ d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+ d_template_args (di)));
+ }
+ else if (peek == 's' && d_peek_next_char (di) == 'p')
+ {
+ d_advance (di, 2);
+ return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
+ d_expression (di), NULL);
+ }
+ else if (peek == 'f' && d_peek_next_char (di) == 'p')
+ {
+ /* Function parameter used in a late-specified return type. */
+ int index;
+ d_advance (di, 2);
+ if (d_peek_char (di) == '_')
+ index = 1;
+ else
+ {
+ index = d_number (di);
+ if (index < 0)
+ return NULL;
+ index += 2;
+ }
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ return d_make_function_param (di, index);
+ }
+ else if (IS_DIGIT (peek))
+ {
+ /* We can get an unqualified name as an expression in the case of
+ a dependent member access, i.e. decltype(T().i). */
+ struct demangle_component *name = d_unqualified_name (di);
+ if (name == NULL)
+ return NULL;
+ if (d_peek_char (di) == 'I')
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+ d_template_args (di));
+ else
+ return name;
+ }
+ else
+ {
+ struct demangle_component *op;
+ int args;
+
+ op = d_operator_name (di);
+ if (op == NULL)
+ return NULL;
+
+ if (op->type == DEMANGLE_COMPONENT_OPERATOR)
+ di->expansion += op->u.s_operator.op->len - 2;
+
+ if (op->type == DEMANGLE_COMPONENT_OPERATOR
+ && strcmp (op->u.s_operator.op->code, "st") == 0)
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ cplus_demangle_type (di));
+
+ switch (op->type)
+ {
+ default:
+ return NULL;
+ case DEMANGLE_COMPONENT_OPERATOR:
+ args = op->u.s_operator.op->args;
+ break;
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ args = op->u.s_extended_operator.args;
+ break;
+ case DEMANGLE_COMPONENT_CAST:
+ args = 1;
+ break;
+ }
+
+ switch (args)
+ {
+ case 1:
+ {
+ struct demangle_component *operand;
+ if (op->type == DEMANGLE_COMPONENT_CAST
+ && d_check_char (di, '_'))
+ operand = d_exprlist (di);
+ else
+ operand = d_expression (di);
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ operand);
+ }
+ case 2:
+ {
+ struct demangle_component *left;
+ struct demangle_component *right;
+
+ left = d_expression (di);
+ if (!strcmp (op->u.s_operator.op->code, "cl"))
+ right = d_exprlist (di);
+ else
+ right = d_expression (di);
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ left, right));
+ }
+ case 3:
+ {
+ struct demangle_component *first;
+ struct demangle_component *second;
+
+ first = d_expression (di);
+ second = d_expression (di);
+ return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_TRINARY_ARG1,
+ first,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_TRINARY_ARG2,
+ second,
+ d_expression (di))));
+ }
+ default:
+ return NULL;
+ }
+ }
+}
+
+/* <expr-primary> ::= L <type> <(value) number> E
+ ::= L <type> <(value) float> E
+ ::= L <mangled-name> E
+*/
+
+static struct demangle_component *
+d_expr_primary (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ if (! d_check_char (di, 'L'))
+ return NULL;
+ if (d_peek_char (di) == '_'
+ /* Workaround for G++ bug; see comment in write_template_arg. */
+ || d_peek_char (di) == 'Z')
+ ret = cplus_demangle_mangled_name (di, 0);
+ else
+ {
+ struct demangle_component *type;
+ enum demangle_component_type t;
+ const char *s;
+
+ type = cplus_demangle_type (di);
+ if (type == NULL)
+ return NULL;
+
+ /* If we have a type we know how to print, we aren't going to
+ print the type name itself. */
+ if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
+ && type->u.s_builtin.type->print != D_PRINT_DEFAULT)
+ di->expansion -= type->u.s_builtin.type->len;
+
+ /* Rather than try to interpret the literal value, we just
+ collect it as a string. Note that it's possible to have a
+ floating point literal here. The ABI specifies that the
+ format of such literals is machine independent. That's fine,
+ but what's not fine is that versions of g++ up to 3.2 with
+ -fabi-version=1 used upper case letters in the hex constant,
+ and dumped out gcc's internal representation. That makes it
+ hard to tell where the constant ends, and hard to dump the
+ constant in any readable form anyhow. We don't attempt to
+ handle these cases. */
+
+ t = DEMANGLE_COMPONENT_LITERAL;
+ if (d_peek_char (di) == 'n')
+ {
+ t = DEMANGLE_COMPONENT_LITERAL_NEG;
+ d_advance (di, 1);
+ }
+ s = d_str (di);
+ while (d_peek_char (di) != 'E')
+ {
+ if (d_peek_char (di) == '\0')
+ return NULL;
+ d_advance (di, 1);
+ }
+ ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s));
+ }
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+}
+
+/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
+ ::= Z <(function) encoding> E s [<discriminator>]
+*/
+
+static struct demangle_component *
+d_local_name (struct d_info *di)
+{
+ struct demangle_component *function;
+
+ if (! d_check_char (di, 'Z'))
+ return NULL;
+
+ function = d_encoding (di, 0);
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+
+ if (d_peek_char (di) == 's')
+ {
+ d_advance (di, 1);
+ if (! d_discriminator (di))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function,
+ d_make_name (di, "string literal",
+ sizeof "string literal" - 1));
+ }
+ else
+ {
+ struct demangle_component *name;
+
+ name = d_name (di);
+ if (! d_discriminator (di))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
+ }
+}
+
+/* <discriminator> ::= _ <(non-negative) number>
+
+ We demangle the discriminator, but we don't print it out. FIXME:
+ We should print it out in verbose mode. */
+
+static int
+d_discriminator (struct d_info *di)
+{
+ long discrim;
+
+ if (d_peek_char (di) != '_')
+ return 1;
+ d_advance (di, 1);
+ discrim = d_number (di);
+ if (discrim < 0)
+ return 0;
+ return 1;
+}
+
+/* Add a new substitution. */
+
+static int
+d_add_substitution (struct d_info *di, struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return 0;
+ if (di->next_sub >= di->num_subs)
+ return 0;
+ di->subs[di->next_sub] = dc;
+ ++di->next_sub;
+ return 1;
+}
+
+/* <substitution> ::= S <seq-id> _
+ ::= S_
+ ::= St
+ ::= Sa
+ ::= Sb
+ ::= Ss
+ ::= Si
+ ::= So
+ ::= Sd
+
+ If PREFIX is non-zero, then this type is being used as a prefix in
+ a qualified name. In this case, for the standard substitutions, we
+ need to check whether we are being used as a prefix for a
+ constructor or destructor, and return a full template name.
+ Otherwise we will get something like std::iostream::~iostream()
+ which does not correspond particularly well to any function which
+ actually appears in the source.
+*/
+
+static const struct d_standard_sub_info standard_subs[] =
+{
+ { 't', NL ("std"),
+ NL ("std"),
+ NULL, 0 },
+ { 'a', NL ("std::allocator"),
+ NL ("std::allocator"),
+ NL ("allocator") },
+ { 'b', NL ("std::basic_string"),
+ NL ("std::basic_string"),
+ NL ("basic_string") },
+ { 's', NL ("std::string"),
+ NL ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
+ NL ("basic_string") },
+ { 'i', NL ("std::istream"),
+ NL ("std::basic_istream<char, std::char_traits<char> >"),
+ NL ("basic_istream") },
+ { 'o', NL ("std::ostream"),
+ NL ("std::basic_ostream<char, std::char_traits<char> >"),
+ NL ("basic_ostream") },
+ { 'd', NL ("std::iostream"),
+ NL ("std::basic_iostream<char, std::char_traits<char> >"),
+ NL ("basic_iostream") }
+};
+
+static struct demangle_component *
+d_substitution (struct d_info *di, int prefix)
+{
+ char c;
+
+ if (! d_check_char (di, 'S'))
+ return NULL;
+
+ c = d_next_char (di);
+ if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
+ {
+ unsigned int id;
+
+ id = 0;
+ if (c != '_')
+ {
+ do
+ {
+ unsigned int new_id;
+
+ if (IS_DIGIT (c))
+ new_id = id * 36 + c - '0';
+ else if (IS_UPPER (c))
+ new_id = id * 36 + c - 'A' + 10;
+ else
+ return NULL;
+ if (new_id < id)
+ return NULL;
+ id = new_id;
+ c = d_next_char (di);
+ }
+ while (c != '_');
+
+ ++id;
+ }
+
+ if (id >= (unsigned int) di->next_sub)
+ return NULL;
+
+ ++di->did_subs;
+
+ return di->subs[id];
+ }
+ else
+ {
+ int verbose;
+ const struct d_standard_sub_info *p;
+ const struct d_standard_sub_info *pend;
+
+ verbose = (di->options & DMGL_VERBOSE) != 0;
+ if (! verbose && prefix)
+ {
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'C' || peek == 'D')
+ verbose = 1;
+ }
+
+ pend = (&standard_subs[0]
+ + sizeof standard_subs / sizeof standard_subs[0]);
+ for (p = &standard_subs[0]; p < pend; ++p)
+ {
+ if (c == p->code)
+ {
+ const char *s;
+ int len;
+
+ if (p->set_last_name != NULL)
+ di->last_name = d_make_sub (di, p->set_last_name,
+ p->set_last_name_len);
+ if (verbose)
+ {
+ s = p->full_expansion;
+ len = p->full_len;
+ }
+ else
+ {
+ s = p->simple_expansion;
+ len = p->simple_len;
+ }
+ di->expansion += len;
+ return d_make_sub (di, s, len);
+ }
+ }
+
+ return NULL;
+ }
+}
+
+/* Initialize a growable string. */
+
+static void
+d_growable_string_init (struct d_growable_string *dgs, size_t estimate)
+{
+ dgs->buf = NULL;
+ dgs->len = 0;
+ dgs->alc = 0;
+ dgs->allocation_failure = 0;
+
+ if (estimate > 0)
+ d_growable_string_resize (dgs, estimate);
+}
+
+/* Grow a growable string to a given size. */
+
+static inline void
+d_growable_string_resize (struct d_growable_string *dgs, size_t need)
+{
+ size_t newalc;
+ char *newbuf;
+
+ if (dgs->allocation_failure)
+ return;
+
+ /* Start allocation at two bytes to avoid any possibility of confusion
+ with the special value of 1 used as a return in *palc to indicate
+ allocation failures. */
+ newalc = dgs->alc > 0 ? dgs->alc : 2;
+ while (newalc < need)
+ newalc <<= 1;
+
+ newbuf = (char *) realloc (dgs->buf, newalc);
+ if (newbuf == NULL)
+ {
+ free (dgs->buf);
+ dgs->buf = NULL;
+ dgs->len = 0;
+ dgs->alc = 0;
+ dgs->allocation_failure = 1;
+ return;
+ }
+ dgs->buf = newbuf;
+ dgs->alc = newalc;
+}
+
+/* Append a buffer to a growable string. */
+
+static inline void
+d_growable_string_append_buffer (struct d_growable_string *dgs,
+ const char *s, size_t l)
+{
+ size_t need;
+
+ need = dgs->len + l + 1;
+ if (need > dgs->alc)
+ d_growable_string_resize (dgs, need);
+
+ if (dgs->allocation_failure)
+ return;
+
+ memcpy (dgs->buf + dgs->len, s, l);
+ dgs->buf[dgs->len + l] = '\0';
+ dgs->len += l;
+}
+
+/* Bridge growable strings to the callback mechanism. */
+
+static void
+d_growable_string_callback_adapter (const char *s, size_t l, void *opaque)
+{
+ struct d_growable_string *dgs = (struct d_growable_string*) opaque;
+
+ d_growable_string_append_buffer (dgs, s, l);
+}
+
+/* Initialize a print information structure. */
+
+static void
+d_print_init (struct d_print_info *dpi, int options,
+ demangle_callbackref callback, void *opaque)
+{
+ dpi->options = options;
+ dpi->len = 0;
+ dpi->last_char = '\0';
+ dpi->templates = NULL;
+ dpi->modifiers = NULL;
+
+ dpi->callback = callback;
+ dpi->opaque = opaque;
+
+ dpi->demangle_failure = 0;
+}
+
+/* Indicate that an error occurred during printing, and test for error. */
+
+static inline void
+d_print_error (struct d_print_info *dpi)
+{
+ dpi->demangle_failure = 1;
+}
+
+static inline int
+d_print_saw_error (struct d_print_info *dpi)
+{
+ return dpi->demangle_failure != 0;
+}
+
+/* Flush buffered characters to the callback. */
+
+static inline void
+d_print_flush (struct d_print_info *dpi)
+{
+ dpi->buf[dpi->len] = '\0';
+ dpi->callback (dpi->buf, dpi->len, dpi->opaque);
+ dpi->len = 0;
+}
+
+/* Append characters and buffers for printing. */
+
+static inline void
+d_append_char (struct d_print_info *dpi, char c)
+{
+ if (dpi->len == sizeof (dpi->buf) - 1)
+ d_print_flush (dpi);
+
+ dpi->buf[dpi->len++] = c;
+ dpi->last_char = c;
+}
+
+static inline void
+d_append_buffer (struct d_print_info *dpi, const char *s, size_t l)
+{
+ size_t i;
+
+ for (i = 0; i < l; i++)
+ d_append_char (dpi, s[i]);
+}
+
+static inline void
+d_append_string (struct d_print_info *dpi, const char *s)
+{
+ d_append_buffer (dpi, s, strlen (s));
+}
+
+static inline char
+d_last_char (struct d_print_info *dpi)
+{
+ return dpi->last_char;
+}
+
+/* Turn components into a human readable string. OPTIONS is the
+ options bits passed to the demangler. DC is the tree to print.
+ CALLBACK is a function to call to flush demangled string segments
+ as they fill the intermediate buffer, and OPAQUE is a generalized
+ callback argument. On success, this returns 1. On failure,
+ it returns 0, indicating a bad parse. It does not use heap
+ memory to build an output string, so cannot encounter memory
+ allocation failure. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_print_callback (int options,
+ const struct demangle_component *dc,
+ demangle_callbackref callback, void *opaque)
+{
+ struct d_print_info dpi;
+
+ d_print_init (&dpi, options, callback, opaque);
+
+ d_print_comp (&dpi, dc);
+
+ d_print_flush (&dpi);
+
+ return ! d_print_saw_error (&dpi);
+}
+
+/* Turn components into a human readable string. OPTIONS is the
+ options bits passed to the demangler. DC is the tree to print.
+ ESTIMATE is a guess at the length of the result. This returns a
+ string allocated by malloc, or NULL on error. On success, this
+ sets *PALC to the size of the allocated buffer. On failure, this
+ sets *PALC to 0 for a bad parse, or to 1 for a memory allocation
+ failure. */
+
+CP_STATIC_IF_GLIBCPP_V3
+char *
+cplus_demangle_print (int options, const struct demangle_component *dc,
+ int estimate, size_t *palc)
+{
+ struct d_growable_string dgs;
+
+ d_growable_string_init (&dgs, estimate);
+
+ if (! cplus_demangle_print_callback (options, dc,
+ d_growable_string_callback_adapter,
+ &dgs))
+ {
+ free (dgs.buf);
+ *palc = 0;
+ return NULL;
+ }
+
+ *palc = dgs.allocation_failure ? 1 : dgs.alc;
+ return dgs.buf;
+}
+
+/* Returns the I'th element of the template arglist ARGS, or NULL on
+ failure. */
+
+static struct demangle_component *
+d_index_template_argument (struct demangle_component *args, int i)
+{
+ struct demangle_component *a;
+
+ for (a = args;
+ a != NULL;
+ a = d_right (a))
+ {
+ if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ return NULL;
+ if (i <= 0)
+ break;
+ --i;
+ }
+ if (i != 0 || a == NULL)
+ return NULL;
+
+ return d_left (a);
+}
+
+/* Returns the template argument from the current context indicated by DC,
+ which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL. */
+
+static struct demangle_component *
+d_lookup_template_argument (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ if (dpi->templates == NULL)
+ {
+ d_print_error (dpi);
+ return NULL;
+ }
+
+ return d_index_template_argument
+ (d_right (dpi->templates->template_decl),
+ dc->u.s_number.number);
+}
+
+/* Returns a template argument pack used in DC (any will do), or NULL. */
+
+static struct demangle_component *
+d_find_pack (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ struct demangle_component *a;
+ if (dc == NULL)
+ return NULL;
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ a = d_lookup_template_argument (dpi, dc);
+ if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ return a;
+ return NULL;
+
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ return NULL;
+
+ case DEMANGLE_COMPONENT_NAME:
+ case DEMANGLE_COMPONENT_OPERATOR:
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ case DEMANGLE_COMPONENT_SUB_STD:
+ case DEMANGLE_COMPONENT_CHARACTER:
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ return NULL;
+
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ return d_find_pack (dpi, dc->u.s_extended_operator.name);
+ case DEMANGLE_COMPONENT_CTOR:
+ return d_find_pack (dpi, dc->u.s_ctor.name);
+ case DEMANGLE_COMPONENT_DTOR:
+ return d_find_pack (dpi, dc->u.s_dtor.name);
+
+ default:
+ a = d_find_pack (dpi, d_left (dc));
+ if (a)
+ return a;
+ return d_find_pack (dpi, d_right (dc));
+ }
+}
+
+/* Returns the length of the template argument pack DC. */
+
+static int
+d_pack_length (const struct demangle_component *dc)
+{
+ int count = 0;
+ while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST
+ && d_left (dc) != NULL)
+ {
+ ++count;
+ dc = d_right (dc);
+ }
+ return count;
+}
+
+/* DC is a component of a mangled expression. Print it, wrapped in parens
+ if needed. */
+
+static void
+d_print_subexpr (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ int simple = 0;
+ if (dc->type == DEMANGLE_COMPONENT_NAME
+ || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM)
+ simple = 1;
+ if (!simple)
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, dc);
+ if (!simple)
+ d_append_char (dpi, ')');
+}
+
+/* Subroutine to handle components. */
+
+static void
+d_print_comp (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ if (dc == NULL)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ if (d_print_saw_error (dpi))
+ return;
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_NAME:
+ if ((dpi->options & DMGL_JAVA) == 0)
+ d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len);
+ else
+ d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len);
+ return;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ d_print_comp (dpi, d_left (dc));
+ if ((dpi->options & DMGL_JAVA) == 0)
+ d_append_string (dpi, "::");
+ else
+ d_append_char (dpi, '.');
+ d_print_comp (dpi, d_right (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ {
+ struct d_print_mod *hold_modifiers;
+ struct demangle_component *typed_name;
+ struct d_print_mod adpm[4];
+ unsigned int i;
+ struct d_print_template dpt;
+
+ /* Pass the name down to the type so that it can be printed in
+ the right place for the type. We also have to pass down
+ any CV-qualifiers, which apply to the this parameter. */
+ hold_modifiers = dpi->modifiers;
+ dpi->modifiers = 0;
+ i = 0;
+ typed_name = d_left (dc);
+ while (typed_name != NULL)
+ {
+ if (i >= sizeof adpm / sizeof adpm[0])
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ adpm[i].next = dpi->modifiers;
+ dpi->modifiers = &adpm[i];
+ adpm[i].mod = typed_name;
+ adpm[i].printed = 0;
+ adpm[i].templates = dpi->templates;
+ ++i;
+
+ if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS)
+ break;
+
+ typed_name = d_left (typed_name);
+ }
+
+ if (typed_name == NULL)
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ /* If typed_name is a template, then it applies to the
+ function type as well. */
+ if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
+ {
+ dpt.next = dpi->templates;
+ dpi->templates = &dpt;
+ dpt.template_decl = typed_name;
+ }
+
+ /* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then
+ there may be CV-qualifiers on its right argument which
+ really apply here; this happens when parsing a class which
+ is local to a function. */
+ if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+ {
+ struct demangle_component *local_name;
+
+ local_name = d_right (typed_name);
+ while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || local_name->type == DEMANGLE_COMPONENT_CONST_THIS)
+ {
+ if (i >= sizeof adpm / sizeof adpm[0])
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ adpm[i] = adpm[i - 1];
+ adpm[i].next = &adpm[i - 1];
+ dpi->modifiers = &adpm[i];
+
+ adpm[i - 1].mod = local_name;
+ adpm[i - 1].printed = 0;
+ adpm[i - 1].templates = dpi->templates;
+ ++i;
+
+ local_name = d_left (local_name);
+ }
+ }
+
+ d_print_comp (dpi, d_right (dc));
+
+ if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
+ dpi->templates = dpt.next;
+
+ /* If the modifiers didn't get printed by the type, print them
+ now. */
+ while (i > 0)
+ {
+ --i;
+ if (! adpm[i].printed)
+ {
+ d_append_char (dpi, ' ');
+ d_print_mod (dpi, adpm[i].mod);
+ }
+ }
+
+ dpi->modifiers = hold_modifiers;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ {
+ struct d_print_mod *hold_dpm;
+ struct demangle_component *dcl;
+
+ /* Don't push modifiers into a template definition. Doing so
+ could give the wrong definition for a template argument.
+ Instead, treat the template essentially as a name. */
+
+ hold_dpm = dpi->modifiers;
+ dpi->modifiers = NULL;
+
+ dcl = d_left (dc);
+
+ if ((dpi->options & DMGL_JAVA) != 0
+ && dcl->type == DEMANGLE_COMPONENT_NAME
+ && dcl->u.s_name.len == 6
+ && strncmp (dcl->u.s_name.s, "JArray", 6) == 0)
+ {
+ /* Special-case Java arrays, so that JArray<TYPE> appears
+ instead as TYPE[]. */
+
+ d_print_comp (dpi, d_right (dc));
+ d_append_string (dpi, "[]");
+ }
+ else
+ {
+ d_print_comp (dpi, dcl);
+ if (d_last_char (dpi) == '<')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '<');
+ d_print_comp (dpi, d_right (dc));
+ /* Avoid generating two consecutive '>' characters, to avoid
+ the C++ syntactic ambiguity. */
+ if (d_last_char (dpi) == '>')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '>');
+ }
+
+ dpi->modifiers = hold_dpm;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ {
+ struct d_print_template *hold_dpt;
+ struct demangle_component *a = d_lookup_template_argument (dpi, dc);
+
+ if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ a = d_index_template_argument (a, dpi->pack_index);
+
+ if (a == NULL)
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ /* While processing this parameter, we need to pop the list of
+ templates. This is because the template parameter may
+ itself be a reference to a parameter of an outer
+ template. */
+
+ hold_dpt = dpi->templates;
+ dpi->templates = hold_dpt->next;
+
+ d_print_comp (dpi, a);
+
+ dpi->templates = hold_dpt;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_CTOR:
+ d_print_comp (dpi, dc->u.s_ctor.name);
+ return;
+
+ case DEMANGLE_COMPONENT_DTOR:
+ d_append_char (dpi, '~');
+ d_print_comp (dpi, dc->u.s_dtor.name);
+ return;
+
+ case DEMANGLE_COMPONENT_VTABLE:
+ d_append_string (dpi, "vtable for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_VTT:
+ d_append_string (dpi, "VTT for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ d_append_string (dpi, "construction vtable for ");
+ d_print_comp (dpi, d_left (dc));
+ d_append_string (dpi, "-in-");
+ d_print_comp (dpi, d_right (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ d_append_string (dpi, "typeinfo for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ d_append_string (dpi, "typeinfo name for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ d_append_string (dpi, "typeinfo fn for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_THUNK:
+ d_append_string (dpi, "non-virtual thunk to ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ d_append_string (dpi, "virtual thunk to ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ d_append_string (dpi, "covariant return thunk to ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ d_append_string (dpi, "java Class for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_GUARD:
+ d_append_string (dpi, "guard variable for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_REFTEMP:
+ d_append_string (dpi, "reference temporary for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ d_append_string (dpi, "hidden alias for ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_SUB_STD:
+ d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len);
+ return;
+
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ {
+ struct d_print_mod *pdpm;
+
+ /* When printing arrays, it's possible to have cases where the
+ same CV-qualifier gets pushed on the stack multiple times.
+ We only need to print it once. */
+
+ for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next)
+ {
+ if (! pdpm->printed)
+ {
+ if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT
+ && pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE
+ && pdpm->mod->type != DEMANGLE_COMPONENT_CONST)
+ break;
+ if (pdpm->mod->type == dc->type)
+ {
+ d_print_comp (dpi, d_left (dc));
+ return;
+ }
+ }
+ }
+ }
+ /* Fall through. */
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ {
+ /* We keep a list of modifiers on the stack. */
+ struct d_print_mod dpm;
+
+ dpm.next = dpi->modifiers;
+ dpi->modifiers = &dpm;
+ dpm.mod = dc;
+ dpm.printed = 0;
+ dpm.templates = dpi->templates;
+
+ d_print_comp (dpi, d_left (dc));
+
+ /* If the modifier didn't get printed by the type, print it
+ now. */
+ if (! dpm.printed)
+ d_print_mod (dpi, dc);
+
+ dpi->modifiers = dpm.next;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ if ((dpi->options & DMGL_JAVA) == 0)
+ d_append_buffer (dpi, dc->u.s_builtin.type->name,
+ dc->u.s_builtin.type->len);
+ else
+ d_append_buffer (dpi, dc->u.s_builtin.type->java_name,
+ dc->u.s_builtin.type->java_len);
+ return;
+
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ {
+ if ((dpi->options & DMGL_RET_POSTFIX) != 0)
+ d_print_function_type (dpi, dc, dpi->modifiers);
+
+ /* Print return type if present */
+ if (d_left (dc) != NULL)
+ {
+ struct d_print_mod dpm;
+
+ /* We must pass this type down as a modifier in order to
+ print it in the right location. */
+ dpm.next = dpi->modifiers;
+ dpi->modifiers = &dpm;
+ dpm.mod = dc;
+ dpm.printed = 0;
+ dpm.templates = dpi->templates;
+
+ d_print_comp (dpi, d_left (dc));
+
+ dpi->modifiers = dpm.next;
+
+ if (dpm.printed)
+ return;
+
+ /* In standard prefix notation, there is a space between the
+ return type and the function signature. */
+ if ((dpi->options & DMGL_RET_POSTFIX) == 0)
+ d_append_char (dpi, ' ');
+ }
+
+ if ((dpi->options & DMGL_RET_POSTFIX) == 0)
+ d_print_function_type (dpi, dc, dpi->modifiers);
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ {
+ struct d_print_mod *hold_modifiers;
+ struct d_print_mod adpm[4];
+ unsigned int i;
+ struct d_print_mod *pdpm;
+
+ /* We must pass this type down as a modifier in order to print
+ multi-dimensional arrays correctly. If the array itself is
+ CV-qualified, we act as though the element type were
+ CV-qualified. We do this by copying the modifiers down
+ rather than fiddling pointers, so that we don't wind up
+ with a d_print_mod higher on the stack pointing into our
+ stack frame after we return. */
+
+ hold_modifiers = dpi->modifiers;
+
+ adpm[0].next = hold_modifiers;
+ dpi->modifiers = &adpm[0];
+ adpm[0].mod = dc;
+ adpm[0].printed = 0;
+ adpm[0].templates = dpi->templates;
+
+ i = 1;
+ pdpm = hold_modifiers;
+ while (pdpm != NULL
+ && (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT
+ || pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE
+ || pdpm->mod->type == DEMANGLE_COMPONENT_CONST))
+ {
+ if (! pdpm->printed)
+ {
+ if (i >= sizeof adpm / sizeof adpm[0])
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ adpm[i] = *pdpm;
+ adpm[i].next = dpi->modifiers;
+ dpi->modifiers = &adpm[i];
+ pdpm->printed = 1;
+ ++i;
+ }
+
+ pdpm = pdpm->next;
+ }
+
+ d_print_comp (dpi, d_right (dc));
+
+ dpi->modifiers = hold_modifiers;
+
+ if (adpm[0].printed)
+ return;
+
+ while (i > 1)
+ {
+ --i;
+ d_print_mod (dpi, adpm[i].mod);
+ }
+
+ d_print_array_type (dpi, dc, dpi->modifiers);
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ {
+ struct d_print_mod dpm;
+
+ dpm.next = dpi->modifiers;
+ dpi->modifiers = &dpm;
+ dpm.mod = dc;
+ dpm.printed = 0;
+ dpm.templates = dpi->templates;
+
+ d_print_comp (dpi, d_right (dc));
+
+ /* If the modifier didn't get printed by the type, print it
+ now. */
+ if (! dpm.printed)
+ {
+ d_append_char (dpi, ' ');
+ d_print_comp (dpi, d_left (dc));
+ d_append_string (dpi, "::*");
+ }
+
+ dpi->modifiers = dpm.next;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ if (dc->u.s_fixed.sat)
+ d_append_string (dpi, "_Sat ");
+ /* Don't print "int _Accum". */
+ if (dc->u.s_fixed.length->u.s_builtin.type
+ != &cplus_demangle_builtin_types['i'-'a'])
+ {
+ d_print_comp (dpi, dc->u.s_fixed.length);
+ d_append_char (dpi, ' ');
+ }
+ if (dc->u.s_fixed.accum)
+ d_append_string (dpi, "_Accum");
+ else
+ d_append_string (dpi, "_Fract");
+ return;
+
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ if (d_left (dc) != NULL)
+ d_print_comp (dpi, d_left (dc));
+ if (d_right (dc) != NULL)
+ {
+ size_t len;
+ d_append_string (dpi, ", ");
+ len = dpi->len;
+ d_print_comp (dpi, d_right (dc));
+ /* If that didn't print anything (which can happen with empty
+ template argument packs), remove the comma and space. */
+ if (dpi->len == len)
+ dpi->len -= 2;
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_OPERATOR:
+ {
+ char c;
+
+ d_append_string (dpi, "operator");
+ c = dc->u.s_operator.op->name[0];
+ if (IS_LOWER (c))
+ d_append_char (dpi, ' ');
+ d_append_buffer (dpi, dc->u.s_operator.op->name,
+ dc->u.s_operator.op->len);
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ d_append_string (dpi, "operator ");
+ d_print_comp (dpi, dc->u.s_extended_operator.name);
+ return;
+
+ case DEMANGLE_COMPONENT_CAST:
+ d_append_string (dpi, "operator ");
+ d_print_cast (dpi, dc);
+ return;
+
+ case DEMANGLE_COMPONENT_UNARY:
+ if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST)
+ d_print_expr_op (dpi, d_left (dc));
+ else
+ {
+ d_append_char (dpi, '(');
+ d_print_cast (dpi, d_left (dc));
+ d_append_char (dpi, ')');
+ }
+ d_print_subexpr (dpi, d_right (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_BINARY:
+ if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS)
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ /* We wrap an expression which uses the greater-than operator in
+ an extra layer of parens so that it does not get confused
+ with the '>' which ends the template parameters. */
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
+ && d_left (dc)->u.s_operator.op->len == 1
+ && d_left (dc)->u.s_operator.op->name[0] == '>')
+ d_append_char (dpi, '(');
+
+ d_print_subexpr (dpi, d_left (d_right (dc)));
+ if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0)
+ d_print_expr_op (dpi, d_left (dc));
+ d_print_subexpr (dpi, d_right (d_right (dc)));
+
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
+ && d_left (dc)->u.s_operator.op->len == 1
+ && d_left (dc)->u.s_operator.op->name[0] == '>')
+ d_append_char (dpi, ')');
+
+ return;
+
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ /* We should only see this as part of DEMANGLE_COMPONENT_BINARY. */
+ d_print_error (dpi);
+ return;
+
+ case DEMANGLE_COMPONENT_TRINARY:
+ if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1
+ || d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ d_print_subexpr (dpi, d_left (d_right (dc)));
+ d_print_expr_op (dpi, d_left (dc));
+ d_print_subexpr (dpi, d_left (d_right (d_right (dc))));
+ d_append_string (dpi, " : ");
+ d_print_subexpr (dpi, d_right (d_right (d_right (dc))));
+ return;
+
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ /* We should only see these are part of DEMANGLE_COMPONENT_TRINARY. */
+ d_print_error (dpi);
+ return;
+
+ case DEMANGLE_COMPONENT_LITERAL:
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ {
+ enum d_builtin_type_print tp;
+
+ /* For some builtin types, produce simpler output. */
+ tp = D_PRINT_DEFAULT;
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE)
+ {
+ tp = d_left (dc)->u.s_builtin.type->print;
+ switch (tp)
+ {
+ case D_PRINT_INT:
+ case D_PRINT_UNSIGNED:
+ case D_PRINT_LONG:
+ case D_PRINT_UNSIGNED_LONG:
+ case D_PRINT_LONG_LONG:
+ case D_PRINT_UNSIGNED_LONG_LONG:
+ if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME)
+ {
+ if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
+ d_append_char (dpi, '-');
+ d_print_comp (dpi, d_right (dc));
+ switch (tp)
+ {
+ default:
+ break;
+ case D_PRINT_UNSIGNED:
+ d_append_char (dpi, 'u');
+ break;
+ case D_PRINT_LONG:
+ d_append_char (dpi, 'l');
+ break;
+ case D_PRINT_UNSIGNED_LONG:
+ d_append_string (dpi, "ul");
+ break;
+ case D_PRINT_LONG_LONG:
+ d_append_string (dpi, "ll");
+ break;
+ case D_PRINT_UNSIGNED_LONG_LONG:
+ d_append_string (dpi, "ull");
+ break;
+ }
+ return;
+ }
+ break;
+
+ case D_PRINT_BOOL:
+ if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME
+ && d_right (dc)->u.s_name.len == 1
+ && dc->type == DEMANGLE_COMPONENT_LITERAL)
+ {
+ switch (d_right (dc)->u.s_name.s[0])
+ {
+ case '0':
+ d_append_string (dpi, "false");
+ return;
+ case '1':
+ d_append_string (dpi, "true");
+ return;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, d_left (dc));
+ d_append_char (dpi, ')');
+ if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
+ d_append_char (dpi, '-');
+ if (tp == D_PRINT_FLOAT)
+ d_append_char (dpi, '[');
+ d_print_comp (dpi, d_right (dc));
+ if (tp == D_PRINT_FLOAT)
+ d_append_char (dpi, ']');
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ d_append_string (dpi, "java resource ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ d_print_comp (dpi, d_left (dc));
+ d_print_comp (dpi, d_right (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_CHARACTER:
+ d_append_char (dpi, dc->u.s_character.character);
+ return;
+
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ d_append_string (dpi, "decltype (");
+ d_print_comp (dpi, d_left (dc));
+ d_append_char (dpi, ')');
+ return;
+
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ {
+ int len;
+ int i;
+ struct demangle_component *a = d_find_pack (dpi, d_left (dc));
+ if (a == NULL)
+ {
+ /* d_find_pack won't find anything if the only packs involved
+ in this expansion are function parameter packs; in that
+ case, just print the pattern and "...". */
+ d_print_subexpr (dpi, d_left (dc));
+ d_append_string (dpi, "...");
+ return;
+ }
+
+ len = d_pack_length (a);
+ dc = d_left (dc);
+ for (i = 0; i < len; ++i)
+ {
+ dpi->pack_index = i;
+ d_print_comp (dpi, dc);
+ if (i < len-1)
+ d_append_string (dpi, ", ");
+ }
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ {
+ char buf[25];
+ d_append_string (dpi, "parm#");
+ sprintf(buf,"%ld", dc->u.s_number.number);
+ d_append_string (dpi, buf);
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+ d_append_string (dpi, "global constructors keyed to ");
+ d_print_comp (dpi, dc->u.s_binary.left);
+ return;
+
+ case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+ d_append_string (dpi, "global destructors keyed to ");
+ d_print_comp (dpi, dc->u.s_binary.left);
+ return;
+
+ default:
+ d_print_error (dpi);
+ return;
+ }
+}
+
+/* Print a Java dentifier. For Java we try to handle encoded extended
+ Unicode characters. The C++ ABI doesn't mention Unicode encoding,
+ so we don't it for C++. Characters are encoded as
+ __U<hex-char>+_. */
+
+static void
+d_print_java_identifier (struct d_print_info *dpi, const char *name, int len)
+{
+ const char *p;
+ const char *end;
+
+ end = name + len;
+ for (p = name; p < end; ++p)
+ {
+ if (end - p > 3
+ && p[0] == '_'
+ && p[1] == '_'
+ && p[2] == 'U')
+ {
+ unsigned long c;
+ const char *q;
+
+ c = 0;
+ for (q = p + 3; q < end; ++q)
+ {
+ int dig;
+
+ if (IS_DIGIT (*q))
+ dig = *q - '0';
+ else if (*q >= 'A' && *q <= 'F')
+ dig = *q - 'A' + 10;
+ else if (*q >= 'a' && *q <= 'f')
+ dig = *q - 'a' + 10;
+ else
+ break;
+
+ c = c * 16 + dig;
+ }
+ /* If the Unicode character is larger than 256, we don't try
+ to deal with it here. FIXME. */
+ if (q < end && *q == '_' && c < 256)
+ {
+ d_append_char (dpi, c);
+ p = q;
+ continue;
+ }
+ }
+
+ d_append_char (dpi, *p);
+ }
+}
+
+/* Print a list of modifiers. SUFFIX is 1 if we are printing
+ qualifiers on this after printing a function. */
+
+static void
+d_print_mod_list (struct d_print_info *dpi,
+ struct d_print_mod *mods, int suffix)
+{
+ struct d_print_template *hold_dpt;
+
+ if (mods == NULL || d_print_saw_error (dpi))
+ return;
+
+ if (mods->printed
+ || (! suffix
+ && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS)))
+ {
+ d_print_mod_list (dpi, mods->next, suffix);
+ return;
+ }
+
+ mods->printed = 1;
+
+ hold_dpt = dpi->templates;
+ dpi->templates = mods->templates;
+
+ if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ {
+ d_print_function_type (dpi, mods->mod, mods->next);
+ dpi->templates = hold_dpt;
+ return;
+ }
+ else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
+ {
+ d_print_array_type (dpi, mods->mod, mods->next);
+ dpi->templates = hold_dpt;
+ return;
+ }
+ else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+ {
+ struct d_print_mod *hold_modifiers;
+ struct demangle_component *dc;
+
+ /* When this is on the modifier stack, we have pulled any
+ qualifiers off the right argument already. Otherwise, we
+ print it as usual, but don't let the left argument see any
+ modifiers. */
+
+ hold_modifiers = dpi->modifiers;
+ dpi->modifiers = NULL;
+ d_print_comp (dpi, d_left (mods->mod));
+ dpi->modifiers = hold_modifiers;
+
+ if ((dpi->options & DMGL_JAVA) == 0)
+ d_append_string (dpi, "::");
+ else
+ d_append_char (dpi, '.');
+
+ dc = d_right (mods->mod);
+ while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
+ dc = d_left (dc);
+
+ d_print_comp (dpi, dc);
+
+ dpi->templates = hold_dpt;
+ return;
+ }
+
+ d_print_mod (dpi, mods->mod);
+
+ dpi->templates = hold_dpt;
+
+ d_print_mod_list (dpi, mods->next, suffix);
+}
+
+/* Print a modifier. */
+
+static void
+d_print_mod (struct d_print_info *dpi,
+ const struct demangle_component *mod)
+{
+ switch (mod->type)
+ {
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ d_append_string (dpi, " restrict");
+ return;
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ d_append_string (dpi, " volatile");
+ return;
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ d_append_string (dpi, " const");
+ return;
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ d_append_char (dpi, ' ');
+ d_print_comp (dpi, d_right (mod));
+ return;
+ case DEMANGLE_COMPONENT_POINTER:
+ /* There is no pointer symbol in Java. */
+ if ((dpi->options & DMGL_JAVA) == 0)
+ d_append_char (dpi, '*');
+ return;
+ case DEMANGLE_COMPONENT_REFERENCE:
+ d_append_char (dpi, '&');
+ return;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ d_append_string (dpi, "&&");
+ return;
+ case DEMANGLE_COMPONENT_COMPLEX:
+ d_append_string (dpi, "complex ");
+ return;
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ d_append_string (dpi, "imaginary ");
+ return;
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ if (d_last_char (dpi) != '(')
+ d_append_char (dpi, ' ');
+ d_print_comp (dpi, d_left (mod));
+ d_append_string (dpi, "::*");
+ return;
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ d_print_comp (dpi, d_left (mod));
+ return;
+ default:
+ /* Otherwise, we have something that won't go back on the
+ modifier stack, so we can just print it. */
+ d_print_comp (dpi, mod);
+ return;
+ }
+}
+
+/* Print a function type, except for the return type. */
+
+static void
+d_print_function_type (struct d_print_info *dpi,
+ const struct demangle_component *dc,
+ struct d_print_mod *mods)
+{
+ int need_paren;
+ int saw_mod;
+ int need_space;
+ struct d_print_mod *p;
+ struct d_print_mod *hold_modifiers;
+
+ need_paren = 0;
+ saw_mod = 0;
+ need_space = 0;
+ for (p = mods; p != NULL; p = p->next)
+ {
+ if (p->printed)
+ break;
+
+ saw_mod = 1;
+ switch (p->mod->type)
+ {
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ need_paren = 1;
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ need_space = 1;
+ need_paren = 1;
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ break;
+ default:
+ break;
+ }
+ if (need_paren)
+ break;
+ }
+
+ if (d_left (dc) != NULL && ! saw_mod)
+ need_paren = 1;
+
+ if (need_paren)
+ {
+ if (! need_space)
+ {
+ if (d_last_char (dpi) != '('
+ && d_last_char (dpi) != '*')
+ need_space = 1;
+ }
+ if (need_space && d_last_char (dpi) != ' ')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '(');
+ }
+
+ hold_modifiers = dpi->modifiers;
+ dpi->modifiers = NULL;
+
+ d_print_mod_list (dpi, mods, 0);
+
+ if (need_paren)
+ d_append_char (dpi, ')');
+
+ d_append_char (dpi, '(');
+
+ if (d_right (dc) != NULL)
+ d_print_comp (dpi, d_right (dc));
+
+ d_append_char (dpi, ')');
+
+ d_print_mod_list (dpi, mods, 1);
+
+ dpi->modifiers = hold_modifiers;
+}
+
+/* Print an array type, except for the element type. */
+
+static void
+d_print_array_type (struct d_print_info *dpi,
+ const struct demangle_component *dc,
+ struct d_print_mod *mods)
+{
+ int need_space;
+
+ need_space = 1;
+ if (mods != NULL)
+ {
+ int need_paren;
+ struct d_print_mod *p;
+
+ need_paren = 0;
+ for (p = mods; p != NULL; p = p->next)
+ {
+ if (! p->printed)
+ {
+ if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
+ {
+ need_space = 0;
+ break;
+ }
+ else
+ {
+ need_paren = 1;
+ need_space = 1;
+ break;
+ }
+ }
+ }
+
+ if (need_paren)
+ d_append_string (dpi, " (");
+
+ d_print_mod_list (dpi, mods, 0);
+
+ if (need_paren)
+ d_append_char (dpi, ')');
+ }
+
+ if (need_space)
+ d_append_char (dpi, ' ');
+
+ d_append_char (dpi, '[');
+
+ if (d_left (dc) != NULL)
+ d_print_comp (dpi, d_left (dc));
+
+ d_append_char (dpi, ']');
+}
+
+/* Print an operator in an expression. */
+
+static void
+d_print_expr_op (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ if (dc->type == DEMANGLE_COMPONENT_OPERATOR)
+ d_append_buffer (dpi, dc->u.s_operator.op->name,
+ dc->u.s_operator.op->len);
+ else
+ d_print_comp (dpi, dc);
+}
+
+/* Print a cast. */
+
+static void
+d_print_cast (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE)
+ d_print_comp (dpi, d_left (dc));
+ else
+ {
+ struct d_print_mod *hold_dpm;
+ struct d_print_template dpt;
+
+ /* It appears that for a templated cast operator, we need to put
+ the template parameters in scope for the operator name, but
+ not for the parameters. The effect is that we need to handle
+ the template printing here. */
+
+ hold_dpm = dpi->modifiers;
+ dpi->modifiers = NULL;
+
+ dpt.next = dpi->templates;
+ dpi->templates = &dpt;
+ dpt.template_decl = d_left (dc);
+
+ d_print_comp (dpi, d_left (d_left (dc)));
+
+ dpi->templates = dpt.next;
+
+ if (d_last_char (dpi) == '<')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '<');
+ d_print_comp (dpi, d_right (d_left (dc)));
+ /* Avoid generating two consecutive '>' characters, to avoid
+ the C++ syntactic ambiguity. */
+ if (d_last_char (dpi) == '>')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '>');
+
+ dpi->modifiers = hold_dpm;
+ }
+}
+
+/* Initialize the information structure we use to pass around
+ information. */
+
+CP_STATIC_IF_GLIBCPP_V3
+void
+cplus_demangle_init_info (const char *mangled, int options, size_t len,
+ struct d_info *di)
+{
+ di->s = mangled;
+ di->send = mangled + len;
+ di->options = options;
+
+ di->n = mangled;
+
+ /* We can not need more components than twice the number of chars in
+ the mangled string. Most components correspond directly to
+ chars, but the ARGLIST types are exceptions. */
+ di->num_comps = 2 * len;
+ di->next_comp = 0;
+
+ /* Similarly, we can not need more substitutions than there are
+ chars in the mangled string. */
+ di->num_subs = len;
+ di->next_sub = 0;
+ di->did_subs = 0;
+
+ di->last_name = NULL;
+
+ di->expansion = 0;
+}
+
+/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI
+ mangled name, return strings in repeated callback giving the demangled
+ name. OPTIONS is the usual libiberty demangler options. On success,
+ this returns 1. On failure, returns 0. */
+
+static int
+d_demangle_callback (const char *mangled, int options,
+ demangle_callbackref callback, void *opaque)
+{
+ enum
+ {
+ DCT_TYPE,
+ DCT_MANGLED,
+ DCT_GLOBAL_CTORS,
+ DCT_GLOBAL_DTORS
+ }
+ type;
+ struct d_info di;
+ struct demangle_component *dc = NULL;
+ int status;
+
+ if (mangled[0] == '_' && mangled[1] == 'Z')
+ type = DCT_MANGLED;
+ else if (strncmp (mangled, "_GLOBAL_", 8) == 0
+ && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$')
+ && (mangled[9] == 'D' || mangled[9] == 'I')
+ && mangled[10] == '_')
+ type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS;
+ else
+ {
+ if ((options & DMGL_TYPES) == 0)
+ return 0;
+ type = DCT_TYPE;
+ }
+
+ cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
+
+ {
+#ifdef CP_DYNAMIC_ARRAYS
+ __extension__ struct demangle_component comps[di.num_comps];
+ __extension__ struct demangle_component *subs[di.num_subs];
+
+ di.comps = comps;
+ di.subs = subs;
+#else
+ di.comps = alloca (di.num_comps * sizeof (*di.comps));
+ di.subs = alloca (di.num_subs * sizeof (*di.subs));
+#endif
+
+ switch (type)
+ {
+ case DCT_TYPE:
+ dc = cplus_demangle_type (&di);
+ break;
+ case DCT_MANGLED:
+ dc = cplus_demangle_mangled_name (&di, 1);
+ break;
+ case DCT_GLOBAL_CTORS:
+ case DCT_GLOBAL_DTORS:
+ d_advance (&di, 11);
+ dc = d_make_comp (&di,
+ (type == DCT_GLOBAL_CTORS
+ ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
+ : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
+ d_make_name (&di, d_str (&di), strlen (d_str (&di))),
+ NULL);
+ d_advance (&di, strlen (d_str (&di)));
+ break;
+ }
+
+ /* If DMGL_PARAMS is set, then if we didn't consume the entire
+ mangled string, then we didn't successfully demangle it. If
+ DMGL_PARAMS is not set, we didn't look at the trailing
+ parameters. */
+ if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
+ dc = NULL;
+
+#ifdef CP_DEMANGLE_DEBUG
+ d_dump (dc, 0);
+#endif
+
+ status = (dc != NULL)
+ ? cplus_demangle_print_callback (options, dc, callback, opaque)
+ : 0;
+ }
+
+ return status;
+}
+
+/* Entry point for the demangler. If MANGLED is a g++ v3 ABI mangled
+ name, return a buffer allocated with malloc holding the demangled
+ name. OPTIONS is the usual libiberty demangler options. On
+ success, this sets *PALC to the allocated size of the returned
+ buffer. On failure, this sets *PALC to 0 for a bad name, or 1 for
+ a memory allocation failure, and returns NULL. */
+
+static char *
+d_demangle (const char *mangled, int options, size_t *palc)
+{
+ struct d_growable_string dgs;
+ int status;
+
+ d_growable_string_init (&dgs, 0);
+
+ status = d_demangle_callback (mangled, options,
+ d_growable_string_callback_adapter, &dgs);
+ if (status == 0)
+ {
+ free (dgs.buf);
+ *palc = 0;
+ return NULL;
+ }
+
+ *palc = dgs.allocation_failure ? 1 : 0;
+ return dgs.buf;
+}
+
+#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
+
+extern char *__cxa_demangle (const char *, char *, size_t *, int *);
+
+/* ia64 ABI-mandated entry point in the C++ runtime library for
+ performing demangling. MANGLED_NAME is a NUL-terminated character
+ string containing the name to be demangled.
+
+ OUTPUT_BUFFER is a region of memory, allocated with malloc, of
+ *LENGTH bytes, into which the demangled name is stored. If
+ OUTPUT_BUFFER is not long enough, it is expanded using realloc.
+ OUTPUT_BUFFER may instead be NULL; in that case, the demangled name
+ is placed in a region of memory allocated with malloc.
+
+ If LENGTH is non-NULL, the length of the buffer containing the
+ demangled name, is placed in *LENGTH.
+
+ The return value is a pointer to the start of the NUL-terminated
+ demangled name, or NULL if the demangling fails. The caller is
+ responsible for deallocating this memory using free.
+
+ *STATUS is set to one of the following values:
+ 0: The demangling operation succeeded.
+ -1: A memory allocation failure occurred.
+ -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
+ -3: One of the arguments is invalid.
+
+ The demangling is performed using the C++ ABI mangling rules, with
+ GNU extensions. */
+
+char *
+__cxa_demangle (const char *mangled_name, char *output_buffer,
+ size_t *length, int *status)
+{
+ char *demangled;
+ size_t alc;
+
+ if (mangled_name == NULL)
+ {
+ if (status != NULL)
+ *status = -3;
+ return NULL;
+ }
+
+ if (output_buffer != NULL && length == NULL)
+ {
+ if (status != NULL)
+ *status = -3;
+ return NULL;
+ }
+
+ demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc);
+
+ if (demangled == NULL)
+ {
+ if (status != NULL)
+ {
+ if (alc == 1)
+ *status = -1;
+ else
+ *status = -2;
+ }
+ return NULL;
+ }
+
+ if (output_buffer == NULL)
+ {
+ if (length != NULL)
+ *length = alc;
+ }
+ else
+ {
+ if (strlen (demangled) < *length)
+ {
+ strcpy (output_buffer, demangled);
+ free (demangled);
+ demangled = output_buffer;
+ }
+ else
+ {
+ free (output_buffer);
+ *length = alc;
+ }
+ }
+
+ if (status != NULL)
+ *status = 0;
+
+ return demangled;
+}
+
+extern int __gcclibcxx_demangle_callback (const char *,
+ void (*)
+ (const char *, size_t, void *),
+ void *);
+
+/* Alternative, allocationless entry point in the C++ runtime library
+ for performing demangling. MANGLED_NAME is a NUL-terminated character
+ string containing the name to be demangled.
+
+ CALLBACK is a callback function, called with demangled string
+ segments as demangling progresses; it is called at least once,
+ but may be called more than once. OPAQUE is a generalized pointer
+ used as a callback argument.
+
+ The return code is one of the following values, equivalent to
+ the STATUS values of __cxa_demangle() (excluding -1, since this
+ function performs no memory allocations):
+ 0: The demangling operation succeeded.
+ -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
+ -3: One of the arguments is invalid.
+
+ The demangling is performed using the C++ ABI mangling rules, with
+ GNU extensions. */
+
+int
+__gcclibcxx_demangle_callback (const char *mangled_name,
+ void (*callback) (const char *, size_t, void *),
+ void *opaque)
+{
+ int status;
+
+ if (mangled_name == NULL || callback == NULL)
+ return -3;
+
+ status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES,
+ callback, opaque);
+ if (status == 0)
+ return -2;
+
+ return 0;
+}
+
+#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */
+
+/* Entry point for libiberty demangler. If MANGLED is a g++ v3 ABI
+ mangled name, return a buffer allocated with malloc holding the
+ demangled name. Otherwise, return NULL. */
+
+char *
+cplus_demangle_v3 (const char *mangled, int options)
+{
+ size_t alc;
+
+ return d_demangle (mangled, options, &alc);
+}
+
+int
+cplus_demangle_v3_callback (const char *mangled, int options,
+ demangle_callbackref callback, void *opaque)
+{
+ return d_demangle_callback (mangled, options, callback, opaque);
+}
+
+/* Demangle a Java symbol. Java uses a subset of the V3 ABI C++ mangling
+ conventions, but the output formatting is a little different.
+ This instructs the C++ demangler not to emit pointer characters ("*"), to
+ use Java's namespace separator symbol ("." instead of "::"), and to output
+ JArray<TYPE> as TYPE[]. */
+
+char *
+java_demangle_v3 (const char *mangled)
+{
+ size_t alc;
+
+ return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc);
+}
+
+int
+java_demangle_v3_callback (const char *mangled,
+ demangle_callbackref callback, void *opaque)
+{
+ return d_demangle_callback (mangled,
+ DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX,
+ callback, opaque);
+}
+
+#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */
+
+#ifndef IN_GLIBCPP_V3
+
+/* Demangle a string in order to find out whether it is a constructor
+ or destructor. Return non-zero on success. Set *CTOR_KIND and
+ *DTOR_KIND appropriately. */
+
+static int
+is_ctor_or_dtor (const char *mangled,
+ enum gnu_v3_ctor_kinds *ctor_kind,
+ enum gnu_v3_dtor_kinds *dtor_kind)
+{
+ struct d_info di;
+ struct demangle_component *dc;
+ int ret;
+
+ *ctor_kind = (enum gnu_v3_ctor_kinds) 0;
+ *dtor_kind = (enum gnu_v3_dtor_kinds) 0;
+
+ cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di);
+
+ {
+#ifdef CP_DYNAMIC_ARRAYS
+ __extension__ struct demangle_component comps[di.num_comps];
+ __extension__ struct demangle_component *subs[di.num_subs];
+
+ di.comps = comps;
+ di.subs = subs;
+#else
+ di.comps = alloca (di.num_comps * sizeof (*di.comps));
+ di.subs = alloca (di.num_subs * sizeof (*di.subs));
+#endif
+
+ dc = cplus_demangle_mangled_name (&di, 1);
+
+ /* Note that because we did not pass DMGL_PARAMS, we don't expect
+ to demangle the entire string. */
+
+ ret = 0;
+ while (dc != NULL)
+ {
+ switch (dc->type)
+ {
+ default:
+ dc = NULL;
+ break;
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ dc = d_left (dc);
+ break;
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ dc = d_right (dc);
+ break;
+ case DEMANGLE_COMPONENT_CTOR:
+ *ctor_kind = dc->u.s_ctor.kind;
+ ret = 1;
+ dc = NULL;
+ break;
+ case DEMANGLE_COMPONENT_DTOR:
+ *dtor_kind = dc->u.s_dtor.kind;
+ ret = 1;
+ dc = NULL;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/* Return whether NAME is the mangled form of a g++ V3 ABI constructor
+ name. A non-zero return indicates the type of constructor. */
+
+enum gnu_v3_ctor_kinds
+is_gnu_v3_mangled_ctor (const char *name)
+{
+ enum gnu_v3_ctor_kinds ctor_kind;
+ enum gnu_v3_dtor_kinds dtor_kind;
+
+ if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
+ return (enum gnu_v3_ctor_kinds) 0;
+ return ctor_kind;
+}
+
+
+/* Return whether NAME is the mangled form of a g++ V3 ABI destructor
+ name. A non-zero return indicates the type of destructor. */
+
+enum gnu_v3_dtor_kinds
+is_gnu_v3_mangled_dtor (const char *name)
+{
+ enum gnu_v3_ctor_kinds ctor_kind;
+ enum gnu_v3_dtor_kinds dtor_kind;
+
+ if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
+ return (enum gnu_v3_dtor_kinds) 0;
+ return dtor_kind;
+}
+
+#endif /* IN_GLIBCPP_V3 */
+
+#ifdef STANDALONE_DEMANGLER
+
+#include "getopt.h"
+#include "dyn-string.h"
+
+static void print_usage (FILE* fp, int exit_value);
+
+#define IS_ALPHA(CHAR) \
+ (((CHAR) >= 'a' && (CHAR) <= 'z') \
+ || ((CHAR) >= 'A' && (CHAR) <= 'Z'))
+
+/* Non-zero if CHAR is a character than can occur in a mangled name. */
+#define is_mangled_char(CHAR) \
+ (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) \
+ || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$')
+
+/* The name of this program, as invoked. */
+const char* program_name;
+
+/* Prints usage summary to FP and then exits with EXIT_VALUE. */
+
+static void
+print_usage (FILE* fp, int exit_value)
+{
+ fprintf (fp, "Usage: %s [options] [names ...]\n", program_name);
+ fprintf (fp, "Options:\n");
+ fprintf (fp, " -h,--help Display this message.\n");
+ fprintf (fp, " -p,--no-params Don't display function parameters\n");
+ fprintf (fp, " -v,--verbose Produce verbose demanglings.\n");
+ fprintf (fp, "If names are provided, they are demangled. Otherwise filters standard input.\n");
+
+ exit (exit_value);
+}
+
+/* Option specification for getopt_long. */
+static const struct option long_options[] =
+{
+ { "help", no_argument, NULL, 'h' },
+ { "no-params", no_argument, NULL, 'p' },
+ { "verbose", no_argument, NULL, 'v' },
+ { NULL, no_argument, NULL, 0 },
+};
+
+/* Main entry for a demangling filter executable. It will demangle
+ its command line arguments, if any. If none are provided, it will
+ filter stdin to stdout, replacing any recognized mangled C++ names
+ with their demangled equivalents. */
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+ int opt_char;
+ int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES;
+
+ /* Use the program name of this program, as invoked. */
+ program_name = argv[0];
+
+ /* Parse options. */
+ do
+ {
+ opt_char = getopt_long (argc, argv, "hpv", long_options, NULL);
+ switch (opt_char)
+ {
+ case '?': /* Unrecognized option. */
+ print_usage (stderr, 1);
+ break;
+
+ case 'h':
+ print_usage (stdout, 0);
+ break;
+
+ case 'p':
+ options &= ~ DMGL_PARAMS;
+ break;
+
+ case 'v':
+ options |= DMGL_VERBOSE;
+ break;
+ }
+ }
+ while (opt_char != -1);
+
+ if (optind == argc)
+ /* No command line arguments were provided. Filter stdin. */
+ {
+ dyn_string_t mangled = dyn_string_new (3);
+ char *s;
+
+ /* Read all of input. */
+ while (!feof (stdin))
+ {
+ char c;
+
+ /* Pile characters into mangled until we hit one that can't
+ occur in a mangled name. */
+ c = getchar ();
+ while (!feof (stdin) && is_mangled_char (c))
+ {
+ dyn_string_append_char (mangled, c);
+ if (feof (stdin))
+ break;
+ c = getchar ();
+ }
+
+ if (dyn_string_length (mangled) > 0)
+ {
+#ifdef IN_GLIBCPP_V3
+ s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL);
+#else
+ s = cplus_demangle_v3 (dyn_string_buf (mangled), options);
+#endif
+
+ if (s != NULL)
+ {
+ fputs (s, stdout);
+ free (s);
+ }
+ else
+ {
+ /* It might not have been a mangled name. Print the
+ original text. */
+ fputs (dyn_string_buf (mangled), stdout);
+ }
+
+ dyn_string_clear (mangled);
+ }
+
+ /* If we haven't hit EOF yet, we've read one character that
+ can't occur in a mangled name, so print it out. */
+ if (!feof (stdin))
+ putchar (c);
+ }
+
+ dyn_string_delete (mangled);
+ }
+ else
+ /* Demangle command line arguments. */
+ {
+ /* Loop over command line arguments. */
+ for (i = optind; i < argc; ++i)
+ {
+ char *s;
+#ifdef IN_GLIBCPP_V3
+ int status;
+#endif
+
+ /* Attempt to demangle. */
+#ifdef IN_GLIBCPP_V3
+ s = __cxa_demangle (argv[i], NULL, NULL, &status);
+#else
+ s = cplus_demangle_v3 (argv[i], options);
+#endif
+
+ /* If it worked, print the demangled name. */
+ if (s != NULL)
+ {
+ printf ("%s\n", s);
+ free (s);
+ }
+ else
+ {
+#ifdef IN_GLIBCPP_V3
+ fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status);
+#else
+ fprintf (stderr, "Failed: %s\n", argv[i]);
+#endif
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif /* STANDALONE_DEMANGLER */
diff --git a/linkers/libiberty/cp-demangle.h b/linkers/libiberty/cp-demangle.h
new file mode 100644
index 0000000..aad3743
--- /dev/null
+++ b/linkers/libiberty/cp-demangle.h
@@ -0,0 +1,168 @@
+/* Internal demangler interface for g++ V3 ABI.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@wasabisystems.com>.
+
+ This file is part of the libiberty library, which is part of GCC.
+
+ 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.
+
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file. (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combined
+ executable.)
+
+ 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 file provides some definitions shared by cp-demangle.c and
+ cp-demint.c. It should not be included by any other files. */
+
+/* Information we keep for operators. */
+
+struct demangle_operator_info
+{
+ /* Mangled name. */
+ const char *code;
+ /* Real name. */
+ const char *name;
+ /* Length of real name. */
+ int len;
+ /* Number of arguments. */
+ int args;
+};
+
+/* How to print the value of a builtin type. */
+
+enum d_builtin_type_print
+{
+ /* Print as (type)val. */
+ D_PRINT_DEFAULT,
+ /* Print as integer. */
+ D_PRINT_INT,
+ /* Print as unsigned integer, with trailing "u". */
+ D_PRINT_UNSIGNED,
+ /* Print as long, with trailing "l". */
+ D_PRINT_LONG,
+ /* Print as unsigned long, with trailing "ul". */
+ D_PRINT_UNSIGNED_LONG,
+ /* Print as long long, with trailing "ll". */
+ D_PRINT_LONG_LONG,
+ /* Print as unsigned long long, with trailing "ull". */
+ D_PRINT_UNSIGNED_LONG_LONG,
+ /* Print as bool. */
+ D_PRINT_BOOL,
+ /* Print as float--put value in square brackets. */
+ D_PRINT_FLOAT,
+ /* Print in usual way, but here to detect void. */
+ D_PRINT_VOID
+};
+
+/* Information we keep for a builtin type. */
+
+struct demangle_builtin_type_info
+{
+ /* Type name. */
+ const char *name;
+ /* Length of type name. */
+ int len;
+ /* Type name when using Java. */
+ const char *java_name;
+ /* Length of java name. */
+ int java_len;
+ /* How to print a value of this type. */
+ enum d_builtin_type_print print;
+};
+
+/* The information structure we pass around. */
+
+struct d_info
+{
+ /* The string we are demangling. */
+ const char *s;
+ /* The end of the string we are demangling. */
+ const char *send;
+ /* The options passed to the demangler. */
+ int options;
+ /* The next character in the string to consider. */
+ const char *n;
+ /* The array of components. */
+ struct demangle_component *comps;
+ /* The index of the next available component. */
+ int next_comp;
+ /* The number of available component structures. */
+ int num_comps;
+ /* The array of substitutions. */
+ struct demangle_component **subs;
+ /* The index of the next substitution. */
+ int next_sub;
+ /* The number of available entries in the subs array. */
+ int num_subs;
+ /* The number of substitutions which we actually made from the subs
+ array, plus the number of template parameter references we
+ saw. */
+ int did_subs;
+ /* The last name we saw, for constructors and destructors. */
+ struct demangle_component *last_name;
+ /* A running total of the length of large expansions from the
+ mangled name to the demangled name, such as standard
+ substitutions and builtin types. */
+ int expansion;
+};
+
+/* To avoid running past the ending '\0', don't:
+ - call d_peek_next_char if d_peek_char returned '\0'
+ - call d_advance with an 'i' that is too large
+ - call d_check_char(di, '\0')
+ Everything else is safe. */
+#define d_peek_char(di) (*((di)->n))
+#define d_peek_next_char(di) ((di)->n[1])
+#define d_advance(di, i) ((di)->n += (i))
+#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
+#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
+#define d_str(di) ((di)->n)
+
+/* Functions and arrays in cp-demangle.c which are referenced by
+ functions in cp-demint.c. */
+#ifdef IN_GLIBCPP_V3
+#define CP_STATIC_IF_GLIBCPP_V3 static
+#else
+#define CP_STATIC_IF_GLIBCPP_V3 extern
+#endif
+
+#ifndef IN_GLIBCPP_V3
+extern const struct demangle_operator_info cplus_demangle_operators[];
+#endif
+
+#define D_BUILTIN_TYPE_COUNT (32)
+
+CP_STATIC_IF_GLIBCPP_V3
+const struct demangle_builtin_type_info
+cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT];
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_mangled_name (struct d_info *, int);
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_type (struct d_info *);
+
+extern void
+cplus_demangle_init_info (const char *, int, size_t, struct d_info *);
+
+/* cp-demangle.c needs to define this a little differently */
+#undef CP_STATIC_IF_GLIBCPP_V3
diff --git a/linkers/libiberty/cplus-dem.c b/linkers/libiberty/cplus-dem.c
new file mode 100644
index 0000000..6628514
--- /dev/null
+++ b/linkers/libiberty/cplus-dem.c
@@ -0,0 +1,4728 @@
+/* Demangler for GNU C++
+ Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Written by James Clark (jjc@jclark.uucp)
+ Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
+ Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU Library General Public
+License, the Free Software Foundation gives you unlimited permission
+to link the compiled version of this file into combinations with other
+programs, and to distribute those combinations without any restriction
+coming from the use of this file. (The Library Public License
+restrictions do apply in other respects; for example, they cover
+modification of the file, and distribution when not linked into a
+combined executable.)
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
+
+ This file imports xmalloc and xrealloc, which are like malloc and
+ realloc except that they generate a fatal error if there is no
+ available memory. */
+
+/* This file lives in both GCC and libiberty. When making changes, please
+ try not to break either. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "safe-ctype.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+void * malloc ();
+void * realloc ();
+#endif
+
+#include <demangle.h>
+#undef CURRENT_DEMANGLING_STYLE
+#define CURRENT_DEMANGLING_STYLE work->options
+
+#include "libiberty.h"
+
+static char *ada_demangle (const char *, int);
+
+#define min(X,Y) (((X) < (Y)) ? (X) : (Y))
+
+/* A value at least one greater than the maximum number of characters
+ that will be output when using the `%d' format with `printf'. */
+#define INTBUF_SIZE 32
+
+extern void fancy_abort (void) ATTRIBUTE_NORETURN;
+
+/* In order to allow a single demangler executable to demangle strings
+ using various common values of CPLUS_MARKER, as well as any specific
+ one set at compile time, we maintain a string containing all the
+ commonly used ones, and check to see if the marker we are looking for
+ is in that string. CPLUS_MARKER is usually '$' on systems where the
+ assembler can deal with that. Where the assembler can't, it's usually
+ '.' (but on many systems '.' is used for other things). We put the
+ current defined CPLUS_MARKER first (which defaults to '$'), followed
+ by the next most common value, followed by an explicit '$' in case
+ the value of CPLUS_MARKER is not '$'.
+
+ We could avoid this if we could just get g++ to tell us what the actual
+ cplus marker character is as part of the debug information, perhaps by
+ ensuring that it is the character that terminates the gcc<n>_compiled
+ marker symbol (FIXME). */
+
+#if !defined (CPLUS_MARKER)
+#define CPLUS_MARKER '$'
+#endif
+
+enum demangling_styles current_demangling_style = auto_demangling;
+
+static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
+
+static char char_str[2] = { '\000', '\000' };
+
+void
+set_cplus_marker_for_demangling (int ch)
+{
+ cplus_markers[0] = ch;
+}
+
+typedef struct string /* Beware: these aren't required to be */
+{ /* '\0' terminated. */
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+/* Stuff that is shared between sub-routines.
+ Using a shared structure allows cplus_demangle to be reentrant. */
+
+struct work_stuff
+{
+ int options;
+ char **typevec;
+ char **ktypevec;
+ char **btypevec;
+ int numk;
+ int numb;
+ int ksize;
+ int bsize;
+ int ntypes;
+ int typevec_size;
+ int constructor;
+ int destructor;
+ int static_type; /* A static member function */
+ int temp_start; /* index in demangled to start of template args */
+ int type_quals; /* The type qualifiers. */
+ int dllimported; /* Symbol imported from a PE DLL */
+ char **tmpl_argvec; /* Template function arguments. */
+ int ntmpl_args; /* The number of template function arguments. */
+ int forgetting_types; /* Nonzero if we are not remembering the types
+ we see. */
+ string* previous_argument; /* The last function argument demangled. */
+ int nrepeats; /* The number of times to repeat the previous
+ argument. */
+};
+
+#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
+#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS)
+
+static const struct optable
+{
+ const char *const in;
+ const char *const out;
+ const int flags;
+} optable[] = {
+ {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */
+ {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */
+ {"new", " new", 0}, /* old (1.91, and 1.x) */
+ {"delete", " delete", 0}, /* old (1.91, and 1.x) */
+ {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */
+ {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */
+ {"as", "=", DMGL_ANSI}, /* ansi */
+ {"ne", "!=", DMGL_ANSI}, /* old, ansi */
+ {"eq", "==", DMGL_ANSI}, /* old, ansi */
+ {"ge", ">=", DMGL_ANSI}, /* old, ansi */
+ {"gt", ">", DMGL_ANSI}, /* old, ansi */
+ {"le", "<=", DMGL_ANSI}, /* old, ansi */
+ {"lt", "<", DMGL_ANSI}, /* old, ansi */
+ {"plus", "+", 0}, /* old */
+ {"pl", "+", DMGL_ANSI}, /* ansi */
+ {"apl", "+=", DMGL_ANSI}, /* ansi */
+ {"minus", "-", 0}, /* old */
+ {"mi", "-", DMGL_ANSI}, /* ansi */
+ {"ami", "-=", DMGL_ANSI}, /* ansi */
+ {"mult", "*", 0}, /* old */
+ {"ml", "*", DMGL_ANSI}, /* ansi */
+ {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */
+ {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */
+ {"convert", "+", 0}, /* old (unary +) */
+ {"negate", "-", 0}, /* old (unary -) */
+ {"trunc_mod", "%", 0}, /* old */
+ {"md", "%", DMGL_ANSI}, /* ansi */
+ {"amd", "%=", DMGL_ANSI}, /* ansi */
+ {"trunc_div", "/", 0}, /* old */
+ {"dv", "/", DMGL_ANSI}, /* ansi */
+ {"adv", "/=", DMGL_ANSI}, /* ansi */
+ {"truth_andif", "&&", 0}, /* old */
+ {"aa", "&&", DMGL_ANSI}, /* ansi */
+ {"truth_orif", "||", 0}, /* old */
+ {"oo", "||", DMGL_ANSI}, /* ansi */
+ {"truth_not", "!", 0}, /* old */
+ {"nt", "!", DMGL_ANSI}, /* ansi */
+ {"postincrement","++", 0}, /* old */
+ {"pp", "++", DMGL_ANSI}, /* ansi */
+ {"postdecrement","--", 0}, /* old */
+ {"mm", "--", DMGL_ANSI}, /* ansi */
+ {"bit_ior", "|", 0}, /* old */
+ {"or", "|", DMGL_ANSI}, /* ansi */
+ {"aor", "|=", DMGL_ANSI}, /* ansi */
+ {"bit_xor", "^", 0}, /* old */
+ {"er", "^", DMGL_ANSI}, /* ansi */
+ {"aer", "^=", DMGL_ANSI}, /* ansi */
+ {"bit_and", "&", 0}, /* old */
+ {"ad", "&", DMGL_ANSI}, /* ansi */
+ {"aad", "&=", DMGL_ANSI}, /* ansi */
+ {"bit_not", "~", 0}, /* old */
+ {"co", "~", DMGL_ANSI}, /* ansi */
+ {"call", "()", 0}, /* old */
+ {"cl", "()", DMGL_ANSI}, /* ansi */
+ {"alshift", "<<", 0}, /* old */
+ {"ls", "<<", DMGL_ANSI}, /* ansi */
+ {"als", "<<=", DMGL_ANSI}, /* ansi */
+ {"arshift", ">>", 0}, /* old */
+ {"rs", ">>", DMGL_ANSI}, /* ansi */
+ {"ars", ">>=", DMGL_ANSI}, /* ansi */
+ {"component", "->", 0}, /* old */
+ {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */
+ {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */
+ {"indirect", "*", 0}, /* old */
+ {"method_call", "->()", 0}, /* old */
+ {"addr", "&", 0}, /* old (unary &) */
+ {"array", "[]", 0}, /* old */
+ {"vc", "[]", DMGL_ANSI}, /* ansi */
+ {"compound", ", ", 0}, /* old */
+ {"cm", ", ", DMGL_ANSI}, /* ansi */
+ {"cond", "?:", 0}, /* old */
+ {"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */
+ {"max", ">?", 0}, /* old */
+ {"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */
+ {"min", "<?", 0}, /* old */
+ {"mn", "<?", DMGL_ANSI}, /* pseudo-ansi */
+ {"nop", "", 0}, /* old (for operator=) */
+ {"rm", "->*", DMGL_ANSI}, /* ansi */
+ {"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */
+};
+
+/* These values are used to indicate the various type varieties.
+ They are all non-zero so that they can be used as `success'
+ values. */
+typedef enum type_kind_t
+{
+ tk_none,
+ tk_pointer,
+ tk_reference,
+ tk_integral,
+ tk_bool,
+ tk_char,
+ tk_real
+} type_kind_t;
+
+const struct demangler_engine libiberty_demanglers[] =
+{
+ {
+ NO_DEMANGLING_STYLE_STRING,
+ no_demangling,
+ "Demangling disabled"
+ }
+ ,
+ {
+ AUTO_DEMANGLING_STYLE_STRING,
+ auto_demangling,
+ "Automatic selection based on executable"
+ }
+ ,
+ {
+ GNU_DEMANGLING_STYLE_STRING,
+ gnu_demangling,
+ "GNU (g++) style demangling"
+ }
+ ,
+ {
+ LUCID_DEMANGLING_STYLE_STRING,
+ lucid_demangling,
+ "Lucid (lcc) style demangling"
+ }
+ ,
+ {
+ ARM_DEMANGLING_STYLE_STRING,
+ arm_demangling,
+ "ARM style demangling"
+ }
+ ,
+ {
+ HP_DEMANGLING_STYLE_STRING,
+ hp_demangling,
+ "HP (aCC) style demangling"
+ }
+ ,
+ {
+ EDG_DEMANGLING_STYLE_STRING,
+ edg_demangling,
+ "EDG style demangling"
+ }
+ ,
+ {
+ GNU_V3_DEMANGLING_STYLE_STRING,
+ gnu_v3_demangling,
+ "GNU (g++) V3 ABI-style demangling"
+ }
+ ,
+ {
+ JAVA_DEMANGLING_STYLE_STRING,
+ java_demangling,
+ "Java style demangling"
+ }
+ ,
+ {
+ GNAT_DEMANGLING_STYLE_STRING,
+ gnat_demangling,
+ "GNAT style demangling"
+ }
+ ,
+ {
+ NULL, unknown_demangling, NULL
+ }
+};
+
+#define STRING_EMPTY(str) ((str) -> b == (str) -> p)
+#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
+ string_append(str, " ");}
+#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
+
+/* The scope separator appropriate for the language being demangled. */
+
+#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::")
+
+#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */
+#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */
+
+/* Prototypes for local functions */
+
+static void delete_work_stuff (struct work_stuff *);
+
+static void delete_non_B_K_work_stuff (struct work_stuff *);
+
+static char *mop_up (struct work_stuff *, string *, int);
+
+static void squangle_mop_up (struct work_stuff *);
+
+static void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *);
+
+#if 0
+static int
+demangle_method_args (struct work_stuff *, const char **, string *);
+#endif
+
+static char *
+internal_cplus_demangle (struct work_stuff *, const char *);
+
+static int
+demangle_template_template_parm (struct work_stuff *work,
+ const char **, string *);
+
+static int
+demangle_template (struct work_stuff *work, const char **, string *,
+ string *, int, int);
+
+static int
+arm_pt (struct work_stuff *, const char *, int, const char **,
+ const char **);
+
+static int
+demangle_class_name (struct work_stuff *, const char **, string *);
+
+static int
+demangle_qualified (struct work_stuff *, const char **, string *,
+ int, int);
+
+static int demangle_class (struct work_stuff *, const char **, string *);
+
+static int demangle_fund_type (struct work_stuff *, const char **, string *);
+
+static int demangle_signature (struct work_stuff *, const char **, string *);
+
+static int demangle_prefix (struct work_stuff *, const char **, string *);
+
+static int gnu_special (struct work_stuff *, const char **, string *);
+
+static int arm_special (const char **, string *);
+
+static void string_need (string *, int);
+
+static void string_delete (string *);
+
+static void
+string_init (string *);
+
+static void string_clear (string *);
+
+#if 0
+static int string_empty (string *);
+#endif
+
+static void string_append (string *, const char *);
+
+static void string_appends (string *, string *);
+
+static void string_appendn (string *, const char *, int);
+
+static void string_prepend (string *, const char *);
+
+static void string_prependn (string *, const char *, int);
+
+static void string_append_template_idx (string *, int);
+
+static int get_count (const char **, int *);
+
+static int consume_count (const char **);
+
+static int consume_count_with_underscores (const char**);
+
+static int demangle_args (struct work_stuff *, const char **, string *);
+
+static int demangle_nested_args (struct work_stuff*, const char**, string*);
+
+static int do_type (struct work_stuff *, const char **, string *);
+
+static int do_arg (struct work_stuff *, const char **, string *);
+
+static int
+demangle_function_name (struct work_stuff *, const char **, string *,
+ const char *);
+
+static int
+iterate_demangle_function (struct work_stuff *,
+ const char **, string *, const char *);
+
+static void remember_type (struct work_stuff *, const char *, int);
+
+static void remember_Btype (struct work_stuff *, const char *, int, int);
+
+static int register_Btype (struct work_stuff *);
+
+static void remember_Ktype (struct work_stuff *, const char *, int);
+
+static void forget_types (struct work_stuff *);
+
+static void forget_B_and_K_types (struct work_stuff *);
+
+static void string_prepends (string *, string *);
+
+static int
+demangle_template_value_parm (struct work_stuff*, const char**,
+ string*, type_kind_t);
+
+static int
+do_hpacc_template_const_value (struct work_stuff *, const char **, string *);
+
+static int
+do_hpacc_template_literal (struct work_stuff *, const char **, string *);
+
+static int snarf_numeric_literal (const char **, string *);
+
+/* There is a TYPE_QUAL value for each type qualifier. They can be
+ combined by bitwise-or to form the complete set of qualifiers for a
+ type. */
+
+#define TYPE_UNQUALIFIED 0x0
+#define TYPE_QUAL_CONST 0x1
+#define TYPE_QUAL_VOLATILE 0x2
+#define TYPE_QUAL_RESTRICT 0x4
+
+static int code_for_qualifier (int);
+
+static const char* qualifier_string (int);
+
+static const char* demangle_qualifier (int);
+
+static int demangle_expression (struct work_stuff *, const char **, string *,
+ type_kind_t);
+
+static int
+demangle_integral_value (struct work_stuff *, const char **, string *);
+
+static int
+demangle_real_value (struct work_stuff *, const char **, string *);
+
+static void
+demangle_arm_hp_template (struct work_stuff *, const char **, int, string *);
+
+static void
+recursively_demangle (struct work_stuff *, const char **, string *, int);
+
+static void grow_vect (char **, size_t *, size_t, int);
+
+/* Translate count to integer, consuming tokens in the process.
+ Conversion terminates on the first non-digit character.
+
+ Trying to consume something that isn't a count results in no
+ consumption of input and a return of -1.
+
+ Overflow consumes the rest of the digits, and returns -1. */
+
+static int
+consume_count (const char **type)
+{
+ int count = 0;
+
+ if (! ISDIGIT ((unsigned char)**type))
+ return -1;
+
+ while (ISDIGIT ((unsigned char)**type))
+ {
+ count *= 10;
+
+ /* Check for overflow.
+ We assume that count is represented using two's-complement;
+ no power of two is divisible by ten, so if an overflow occurs
+ when multiplying by ten, the result will not be a multiple of
+ ten. */
+ if ((count % 10) != 0)
+ {
+ while (ISDIGIT ((unsigned char) **type))
+ (*type)++;
+ return -1;
+ }
+
+ count += **type - '0';
+ (*type)++;
+ }
+
+ if (count < 0)
+ count = -1;
+
+ return (count);
+}
+
+
+/* Like consume_count, but for counts that are preceded and followed
+ by '_' if they are greater than 10. Also, -1 is returned for
+ failure, since 0 can be a valid value. */
+
+static int
+consume_count_with_underscores (const char **mangled)
+{
+ int idx;
+
+ if (**mangled == '_')
+ {
+ (*mangled)++;
+ if (!ISDIGIT ((unsigned char)**mangled))
+ return -1;
+
+ idx = consume_count (mangled);
+ if (**mangled != '_')
+ /* The trailing underscore was missing. */
+ return -1;
+
+ (*mangled)++;
+ }
+ else
+ {
+ if (**mangled < '0' || **mangled > '9')
+ return -1;
+
+ idx = **mangled - '0';
+ (*mangled)++;
+ }
+
+ return idx;
+}
+
+/* C is the code for a type-qualifier. Return the TYPE_QUAL
+ corresponding to this qualifier. */
+
+static int
+code_for_qualifier (int c)
+{
+ switch (c)
+ {
+ case 'C':
+ return TYPE_QUAL_CONST;
+
+ case 'V':
+ return TYPE_QUAL_VOLATILE;
+
+ case 'u':
+ return TYPE_QUAL_RESTRICT;
+
+ default:
+ break;
+ }
+
+ /* C was an invalid qualifier. */
+ abort ();
+}
+
+/* Return the string corresponding to the qualifiers given by
+ TYPE_QUALS. */
+
+static const char*
+qualifier_string (int type_quals)
+{
+ switch (type_quals)
+ {
+ case TYPE_UNQUALIFIED:
+ return "";
+
+ case TYPE_QUAL_CONST:
+ return "const";
+
+ case TYPE_QUAL_VOLATILE:
+ return "volatile";
+
+ case TYPE_QUAL_RESTRICT:
+ return "__restrict";
+
+ case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE:
+ return "const volatile";
+
+ case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT:
+ return "const __restrict";
+
+ case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
+ return "volatile __restrict";
+
+ case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
+ return "const volatile __restrict";
+
+ default:
+ break;
+ }
+
+ /* TYPE_QUALS was an invalid qualifier set. */
+ abort ();
+}
+
+/* C is the code for a type-qualifier. Return the string
+ corresponding to this qualifier. This function should only be
+ called with a valid qualifier code. */
+
+static const char*
+demangle_qualifier (int c)
+{
+ return qualifier_string (code_for_qualifier (c));
+}
+
+int
+cplus_demangle_opname (const char *opname, char *result, int options)
+{
+ int len, len1, ret;
+ string type;
+ struct work_stuff work[1];
+ const char *tem;
+
+ len = strlen(opname);
+ result[0] = '\0';
+ ret = 0;
+ memset ((char *) work, 0, sizeof (work));
+ work->options = options;
+
+ if (opname[0] == '_' && opname[1] == '_'
+ && opname[2] == 'o' && opname[3] == 'p')
+ {
+ /* ANSI. */
+ /* type conversion operator. */
+ tem = opname + 4;
+ if (do_type (work, &tem, &type))
+ {
+ strcat (result, "operator ");
+ strncat (result, type.b, type.p - type.b);
+ string_delete (&type);
+ ret = 1;
+ }
+ }
+ else if (opname[0] == '_' && opname[1] == '_'
+ && ISLOWER((unsigned char)opname[2])
+ && ISLOWER((unsigned char)opname[3]))
+ {
+ if (opname[4] == '\0')
+ {
+ /* Operator. */
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ if (strlen (optable[i].in) == 2
+ && memcmp (optable[i].in, opname + 2, 2) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ ret = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (opname[2] == 'a' && opname[5] == '\0')
+ {
+ /* Assignment. */
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ if (strlen (optable[i].in) == 3
+ && memcmp (optable[i].in, opname + 2, 3) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (len >= 3
+ && opname[0] == 'o'
+ && opname[1] == 'p'
+ && strchr (cplus_markers, opname[2]) != NULL)
+ {
+ /* see if it's an assignment expression */
+ if (len >= 10 /* op$assign_ */
+ && memcmp (opname + 3, "assign_", 7) == 0)
+ {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ len1 = len - 10;
+ if ((int) strlen (optable[i].in) == len1
+ && memcmp (optable[i].in, opname + 10, len1) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ strcat (result, "=");
+ ret = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ len1 = len - 3;
+ if ((int) strlen (optable[i].in) == len1
+ && memcmp (optable[i].in, opname + 3, len1) == 0)
+ {
+ strcat (result, "operator");
+ strcat (result, optable[i].out);
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ else if (len >= 5 && memcmp (opname, "type", 4) == 0
+ && strchr (cplus_markers, opname[4]) != NULL)
+ {
+ /* type conversion operator */
+ tem = opname + 5;
+ if (do_type (work, &tem, &type))
+ {
+ strcat (result, "operator ");
+ strncat (result, type.b, type.p - type.b);
+ string_delete (&type);
+ ret = 1;
+ }
+ }
+ squangle_mop_up (work);
+ return ret;
+
+}
+
+/* Takes operator name as e.g. "++" and returns mangled
+ operator name (e.g. "postincrement_expr"), or NULL if not found.
+
+ If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
+ if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */
+
+const char *
+cplus_mangle_opname (const char *opname, int options)
+{
+ size_t i;
+ int len;
+
+ len = strlen (opname);
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ if ((int) strlen (optable[i].out) == len
+ && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
+ && memcmp (optable[i].out, opname, len) == 0)
+ return optable[i].in;
+ }
+ return (0);
+}
+
+/* Add a routine to set the demangling style to be sure it is valid and
+ allow for any demangler initialization that maybe necessary. */
+
+enum demangling_styles
+cplus_demangle_set_style (enum demangling_styles style)
+{
+ const struct demangler_engine *demangler = libiberty_demanglers;
+
+ for (; demangler->demangling_style != unknown_demangling; ++demangler)
+ if (style == demangler->demangling_style)
+ {
+ current_demangling_style = style;
+ return current_demangling_style;
+ }
+
+ return unknown_demangling;
+}
+
+/* Do string name to style translation */
+
+enum demangling_styles
+cplus_demangle_name_to_style (const char *name)
+{
+ const struct demangler_engine *demangler = libiberty_demanglers;
+
+ for (; demangler->demangling_style != unknown_demangling; ++demangler)
+ if (strcmp (name, demangler->demangling_style_name) == 0)
+ return demangler->demangling_style;
+
+ return unknown_demangling;
+}
+
+/* char *cplus_demangle (const char *mangled, int options)
+
+ If MANGLED is a mangled function name produced by GNU C++, then
+ a pointer to a @code{malloc}ed string giving a C++ representation
+ of the name will be returned; otherwise NULL will be returned.
+ It is the caller's responsibility to free the string which
+ is returned.
+
+ The OPTIONS arg may contain one or more of the following bits:
+
+ DMGL_ANSI ANSI qualifiers such as `const' and `void' are
+ included.
+ DMGL_PARAMS Function parameters are included.
+
+ For example,
+
+ cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", 0) => "A::foo"
+
+ cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", 0) => "A::foo"
+
+ Note that any leading underscores, or other such characters prepended by
+ the compilation system, are presumed to have already been stripped from
+ MANGLED. */
+
+char *
+cplus_demangle (const char *mangled, int options)
+{
+ char *ret;
+ struct work_stuff work[1];
+
+ if (current_demangling_style == no_demangling)
+ return xstrdup (mangled);
+
+ memset ((char *) work, 0, sizeof (work));
+ work->options = options;
+ if ((work->options & DMGL_STYLE_MASK) == 0)
+ work->options |= (int) current_demangling_style & DMGL_STYLE_MASK;
+
+ /* The V3 ABI demangling is implemented elsewhere. */
+ if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
+ {
+ ret = cplus_demangle_v3 (mangled, work->options);
+ if (ret || GNU_V3_DEMANGLING)
+ return ret;
+ }
+
+ if (JAVA_DEMANGLING)
+ {
+ ret = java_demangle_v3 (mangled);
+ if (ret)
+ return ret;
+ }
+
+ if (GNAT_DEMANGLING)
+ return ada_demangle(mangled,options);
+
+ ret = internal_cplus_demangle (work, mangled);
+ squangle_mop_up (work);
+ return (ret);
+}
+
+
+/* Assuming *OLD_VECT points to an array of *SIZE objects of size
+ ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
+ updating *OLD_VECT and *SIZE as necessary. */
+
+static void
+grow_vect (char **old_vect, size_t *size, size_t min_size, int element_size)
+{
+ if (*size < min_size)
+ {
+ *size *= 2;
+ if (*size < min_size)
+ *size = min_size;
+ *old_vect = XRESIZEVAR (char, *old_vect, *size * element_size);
+ }
+}
+
+/* Demangle ada names:
+ 1. Discard final __{DIGIT}+ or ${DIGIT}+
+ 2. Convert other instances of embedded "__" to `.'.
+ 3. Discard leading _ada_.
+ 4. Remove everything after first ___ if it is followed by 'X'.
+ 5. Put symbols that should be suppressed in <...> brackets.
+ The resulting string is valid until the next call of ada_demangle. */
+
+static char *
+ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
+{
+ int i, j;
+ int len0;
+ const char* p;
+ char *demangled = NULL;
+ int changed;
+ size_t demangled_size = 0;
+
+ changed = 0;
+
+ if (strncmp (mangled, "_ada_", 5) == 0)
+ {
+ mangled += 5;
+ changed = 1;
+ }
+
+ if (mangled[0] == '_' || mangled[0] == '<')
+ goto Suppress;
+
+ p = strstr (mangled, "___");
+ if (p == NULL)
+ len0 = strlen (mangled);
+ else
+ {
+ if (p[3] == 'X')
+ {
+ len0 = p - mangled;
+ changed = 1;
+ }
+ else
+ goto Suppress;
+ }
+
+ /* Make demangled big enough for possible expansion by operator name. */
+ grow_vect (&demangled,
+ &demangled_size, 2 * len0 + 1,
+ sizeof (char));
+
+ if (ISDIGIT ((unsigned char) mangled[len0 - 1])) {
+ for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1)
+ ;
+ if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_')
+ {
+ len0 = i - 1;
+ changed = 1;
+ }
+ else if (mangled[i] == '$')
+ {
+ len0 = i;
+ changed = 1;
+ }
+ }
+
+ for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]);
+ i += 1, j += 1)
+ demangled[j] = mangled[i];
+
+ while (i < len0)
+ {
+ if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_')
+ {
+ demangled[j] = '.';
+ changed = 1;
+ i += 2; j += 1;
+ }
+ else
+ {
+ demangled[j] = mangled[i];
+ i += 1; j += 1;
+ }
+ }
+ demangled[j] = '\000';
+
+ for (i = 0; demangled[i] != '\0'; i += 1)
+ if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ')
+ goto Suppress;
+
+ if (! changed)
+ {
+ free (demangled);
+ return NULL;
+ }
+ else
+ return demangled;
+
+ Suppress:
+ grow_vect (&demangled,
+ &demangled_size, strlen (mangled) + 3,
+ sizeof (char));
+
+ if (mangled[0] == '<')
+ strcpy (demangled, mangled);
+ else
+ sprintf (demangled, "<%s>", mangled);
+
+ return demangled;
+}
+
+/* This function performs most of what cplus_demangle use to do, but
+ to be able to demangle a name with a B, K or n code, we need to
+ have a longer term memory of what types have been seen. The original
+ now initializes and cleans up the squangle code info, while internal
+ calls go directly to this routine to avoid resetting that info. */
+
+static char *
+internal_cplus_demangle (struct work_stuff *work, const char *mangled)
+{
+
+ string decl;
+ int success = 0;
+ char *demangled = NULL;
+ int s1, s2, s3, s4;
+ s1 = work->constructor;
+ s2 = work->destructor;
+ s3 = work->static_type;
+ s4 = work->type_quals;
+ work->constructor = work->destructor = 0;
+ work->type_quals = TYPE_UNQUALIFIED;
+ work->dllimported = 0;
+
+ if ((mangled != NULL) && (*mangled != '\0'))
+ {
+ string_init (&decl);
+
+ /* First check to see if gnu style demangling is active and if the
+ string to be demangled contains a CPLUS_MARKER. If so, attempt to
+ recognize one of the gnu special forms rather than looking for a
+ standard prefix. In particular, don't worry about whether there
+ is a "__" string in the mangled string. Consider "_$_5__foo" for
+ example. */
+
+ if ((AUTO_DEMANGLING || GNU_DEMANGLING))
+ {
+ success = gnu_special (work, &mangled, &decl);
+ }
+ if (!success)
+ {
+ success = demangle_prefix (work, &mangled, &decl);
+ }
+ if (success && (*mangled != '\0'))
+ {
+ success = demangle_signature (work, &mangled, &decl);
+ }
+ if (work->constructor == 2)
+ {
+ string_prepend (&decl, "global constructors keyed to ");
+ work->constructor = 0;
+ }
+ else if (work->destructor == 2)
+ {
+ string_prepend (&decl, "global destructors keyed to ");
+ work->destructor = 0;
+ }
+ else if (work->dllimported == 1)
+ {
+ string_prepend (&decl, "import stub for ");
+ work->dllimported = 0;
+ }
+ demangled = mop_up (work, &decl, success);
+ }
+ work->constructor = s1;
+ work->destructor = s2;
+ work->static_type = s3;
+ work->type_quals = s4;
+ return demangled;
+}
+
+
+/* Clear out and squangling related storage */
+static void
+squangle_mop_up (struct work_stuff *work)
+{
+ /* clean up the B and K type mangling types. */
+ forget_B_and_K_types (work);
+ if (work -> btypevec != NULL)
+ {
+ free ((char *) work -> btypevec);
+ }
+ if (work -> ktypevec != NULL)
+ {
+ free ((char *) work -> ktypevec);
+ }
+}
+
+
+/* Copy the work state and storage. */
+
+static void
+work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from)
+{
+ int i;
+
+ delete_work_stuff (to);
+
+ /* Shallow-copy scalars. */
+ memcpy (to, from, sizeof (*to));
+
+ /* Deep-copy dynamic storage. */
+ if (from->typevec_size)
+ to->typevec = XNEWVEC (char *, from->typevec_size);
+
+ for (i = 0; i < from->ntypes; i++)
+ {
+ int len = strlen (from->typevec[i]) + 1;
+
+ to->typevec[i] = XNEWVEC (char, len);
+ memcpy (to->typevec[i], from->typevec[i], len);
+ }
+
+ if (from->ksize)
+ to->ktypevec = XNEWVEC (char *, from->ksize);
+
+ for (i = 0; i < from->numk; i++)
+ {
+ int len = strlen (from->ktypevec[i]) + 1;
+
+ to->ktypevec[i] = XNEWVEC (char, len);
+ memcpy (to->ktypevec[i], from->ktypevec[i], len);
+ }
+
+ if (from->bsize)
+ to->btypevec = XNEWVEC (char *, from->bsize);
+
+ for (i = 0; i < from->numb; i++)
+ {
+ int len = strlen (from->btypevec[i]) + 1;
+
+ to->btypevec[i] = XNEWVEC (char , len);
+ memcpy (to->btypevec[i], from->btypevec[i], len);
+ }
+
+ if (from->ntmpl_args)
+ to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args);
+
+ for (i = 0; i < from->ntmpl_args; i++)
+ {
+ int len = strlen (from->tmpl_argvec[i]) + 1;
+
+ to->tmpl_argvec[i] = XNEWVEC (char, len);
+ memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len);
+ }
+
+ if (from->previous_argument)
+ {
+ to->previous_argument = XNEW (string);
+ string_init (to->previous_argument);
+ string_appends (to->previous_argument, from->previous_argument);
+ }
+}
+
+
+/* Delete dynamic stuff in work_stuff that is not to be re-used. */
+
+static void
+delete_non_B_K_work_stuff (struct work_stuff *work)
+{
+ /* Discard the remembered types, if any. */
+
+ forget_types (work);
+ if (work -> typevec != NULL)
+ {
+ free ((char *) work -> typevec);
+ work -> typevec = NULL;
+ work -> typevec_size = 0;
+ }
+ if (work->tmpl_argvec)
+ {
+ int i;
+
+ for (i = 0; i < work->ntmpl_args; i++)
+ if (work->tmpl_argvec[i])
+ free ((char*) work->tmpl_argvec[i]);
+
+ free ((char*) work->tmpl_argvec);
+ work->tmpl_argvec = NULL;
+ }
+ if (work->previous_argument)
+ {
+ string_delete (work->previous_argument);
+ free ((char*) work->previous_argument);
+ work->previous_argument = NULL;
+ }
+}
+
+
+/* Delete all dynamic storage in work_stuff. */
+static void
+delete_work_stuff (struct work_stuff *work)
+{
+ delete_non_B_K_work_stuff (work);
+ squangle_mop_up (work);
+}
+
+
+/* Clear out any mangled storage */
+
+static char *
+mop_up (struct work_stuff *work, string *declp, int success)
+{
+ char *demangled = NULL;
+
+ delete_non_B_K_work_stuff (work);
+
+ /* If demangling was successful, ensure that the demangled string is null
+ terminated and return it. Otherwise, free the demangling decl. */
+
+ if (!success)
+ {
+ string_delete (declp);
+ }
+ else
+ {
+ string_appendn (declp, "", 1);
+ demangled = declp->b;
+ }
+ return (demangled);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_signature -- demangle the signature part of a mangled name
+
+SYNOPSIS
+
+ static int
+ demangle_signature (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+DESCRIPTION
+
+ Consume and demangle the signature portion of the mangled name.
+
+ DECLP is the string where demangled output is being built. At
+ entry it contains the demangled root name from the mangled name
+ prefix. I.E. either a demangled operator name or the root function
+ name. In some special cases, it may contain nothing.
+
+ *MANGLED points to the current unconsumed location in the mangled
+ name. As tokens are consumed and demangling is performed, the
+ pointer is updated to continuously point at the next token to
+ be consumed.
+
+ Demangling GNU style mangled names is nasty because there is no
+ explicit token that marks the start of the outermost function
+ argument list. */
+
+static int
+demangle_signature (struct work_stuff *work,
+ const char **mangled, string *declp)
+{
+ int success = 1;
+ int func_done = 0;
+ int expect_func = 0;
+ int expect_return_type = 0;
+ const char *oldmangled = NULL;
+ string trawname;
+ string tname;
+
+ while (success && (**mangled != '\0'))
+ {
+ switch (**mangled)
+ {
+ case 'Q':
+ oldmangled = *mangled;
+ success = demangle_qualified (work, mangled, declp, 1, 0);
+ if (success)
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ expect_func = 1;
+ oldmangled = NULL;
+ break;
+
+ case 'K':
+ oldmangled = *mangled;
+ success = demangle_qualified (work, mangled, declp, 1, 0);
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
+
+ case 'S':
+ /* Static member function */
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ (*mangled)++;
+ work -> static_type = 1;
+ break;
+
+ case 'C':
+ case 'V':
+ case 'u':
+ work->type_quals |= code_for_qualifier (**mangled);
+
+ /* a qualified member function */
+ if (oldmangled == NULL)
+ oldmangled = *mangled;
+ (*mangled)++;
+ break;
+
+ case 'L':
+ /* Local class name follows after "Lnnn_" */
+ if (HP_DEMANGLING)
+ {
+ while (**mangled && (**mangled != '_'))
+ (*mangled)++;
+ if (!**mangled)
+ success = 0;
+ else
+ (*mangled)++;
+ }
+ else
+ success = 0;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ work->temp_start = -1; /* uppermost call to demangle_class */
+ success = demangle_class (work, mangled, declp);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING)
+ {
+ /* EDG and others will have the "F", so we let the loop cycle
+ if we are looking at one. */
+ if (**mangled != 'F')
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
+
+ case 'B':
+ {
+ string s;
+ success = do_type (work, mangled, &s);
+ if (success)
+ {
+ string_append (&s, SCOPE_STRING (work));
+ string_prepends (declp, &s);
+ string_delete (&s);
+ }
+ oldmangled = NULL;
+ expect_func = 1;
+ }
+ break;
+
+ case 'F':
+ /* Function */
+ /* ARM/HP style demangling includes a specific 'F' character after
+ the class name. For GNU style, it is just implied. So we can
+ safely just consume any 'F' at this point and be compatible
+ with either style. */
+
+ oldmangled = NULL;
+ func_done = 1;
+ (*mangled)++;
+
+ /* For lucid/ARM/HP style we have to forget any types we might
+ have remembered up to this point, since they were not argument
+ types. GNU style considers all types seen as available for
+ back references. See comment in demangle_args() */
+
+ if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
+ {
+ forget_types (work);
+ }
+ success = demangle_args (work, mangled, declp);
+ /* After picking off the function args, we expect to either
+ find the function return type (preceded by an '_') or the
+ end of the string. */
+ if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_')
+ {
+ ++(*mangled);
+ /* At this level, we do not care about the return type. */
+ success = do_type (work, mangled, &tname);
+ string_delete (&tname);
+ }
+
+ break;
+
+ case 't':
+ /* G++ Template */
+ string_init(&trawname);
+ string_init(&tname);
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ success = demangle_template (work, mangled, &tname,
+ &trawname, 1, 1);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ string_append (&tname, SCOPE_STRING (work));
+
+ string_prepends(declp, &tname);
+ if (work -> destructor & 1)
+ {
+ string_prepend (&trawname, "~");
+ string_appends (declp, &trawname);
+ work->destructor -= 1;
+ }
+ if ((work->constructor & 1) || (work->destructor & 1))
+ {
+ string_appends (declp, &trawname);
+ work->constructor -= 1;
+ }
+ string_delete(&trawname);
+ string_delete(&tname);
+ oldmangled = NULL;
+ expect_func = 1;
+ break;
+
+ case '_':
+ if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
+ {
+ /* Read the return type. */
+ string return_type;
+
+ (*mangled)++;
+ success = do_type (work, mangled, &return_type);
+ APPEND_BLANK (&return_type);
+
+ string_prepends (declp, &return_type);
+ string_delete (&return_type);
+ break;
+ }
+ else
+ /* At the outermost level, we cannot have a return type specified,
+ so if we run into another '_' at this point we are dealing with
+ a mangled name that is either bogus, or has been mangled by
+ some algorithm we don't know how to deal with. So just
+ reject the entire demangling. */
+ /* However, "_nnn" is an expected suffix for alternate entry point
+ numbered nnn for a function, with HP aCC, so skip over that
+ without reporting failure. pai/1997-09-04 */
+ if (HP_DEMANGLING)
+ {
+ (*mangled)++;
+ while (**mangled && ISDIGIT ((unsigned char)**mangled))
+ (*mangled)++;
+ }
+ else
+ success = 0;
+ break;
+
+ case 'H':
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* A G++ template function. Read the template arguments. */
+ success = demangle_template (work, mangled, declp, 0, 0,
+ 0);
+ if (!(work->constructor & 1))
+ expect_return_type = 1;
+ (*mangled)++;
+ break;
+ }
+ else
+ /* fall through */
+ {;}
+
+ default:
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* Assume we have stumbled onto the first outermost function
+ argument token, and start processing args. */
+ func_done = 1;
+ success = demangle_args (work, mangled, declp);
+ }
+ else
+ {
+ /* Non-GNU demanglers use a specific token to mark the start
+ of the outermost function argument tokens. Typically 'F',
+ for ARM/HP-demangling, for example. So if we find something
+ we are not prepared for, it must be an error. */
+ success = 0;
+ }
+ break;
+ }
+ /*
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ */
+ {
+ if (success && expect_func)
+ {
+ func_done = 1;
+ if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING)
+ {
+ forget_types (work);
+ }
+ success = demangle_args (work, mangled, declp);
+ /* Since template include the mangling of their return types,
+ we must set expect_func to 0 so that we don't try do
+ demangle more arguments the next time we get here. */
+ expect_func = 0;
+ }
+ }
+ }
+ if (success && !func_done)
+ {
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
+ bar__3fooi is 'foo::bar(int)'. We get here when we find the
+ first case, and need to ensure that the '(void)' gets added to
+ the current declp. Note that with ARM/HP, the first case
+ represents the name of a static data member 'foo::bar',
+ which is in the current declp, so we leave it alone. */
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+ if (success && PRINT_ARG_TYPES)
+ {
+ if (work->static_type)
+ string_append (declp, " static");
+ if (work->type_quals != TYPE_UNQUALIFIED)
+ {
+ APPEND_BLANK (declp);
+ string_append (declp, qualifier_string (work->type_quals));
+ }
+ }
+
+ return (success);
+}
+
+#if 0
+
+static int
+demangle_method_args (struct work_stuff *work, const char **mangled,
+ string *declp)
+{
+ int success = 0;
+
+ if (work -> static_type)
+ {
+ string_append (declp, *mangled + 1);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ success = demangle_args (work, mangled, declp);
+ }
+ return (success);
+}
+
+#endif
+
+static int
+demangle_template_template_parm (struct work_stuff *work,
+ const char **mangled, string *tname)
+{
+ int i;
+ int r;
+ int need_comma = 0;
+ int success = 1;
+ string temp;
+
+ string_append (tname, "template <");
+ /* get size of template parameter list */
+ if (get_count (mangled, &r))
+ {
+ for (i = 0; i < r; i++)
+ {
+ if (need_comma)
+ {
+ string_append (tname, ", ");
+ }
+
+ /* Z for type parameters */
+ if (**mangled == 'Z')
+ {
+ (*mangled)++;
+ string_append (tname, "class");
+ }
+ /* z for template parameters */
+ else if (**mangled == 'z')
+ {
+ (*mangled)++;
+ success =
+ demangle_template_template_parm (work, mangled, tname);
+ if (!success)
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ if (success)
+ {
+ string_appends (tname, &temp);
+ }
+ string_delete(&temp);
+ if (!success)
+ {
+ break;
+ }
+ }
+ need_comma = 1;
+ }
+
+ }
+ if (tname->p[-1] == '>')
+ string_append (tname, " ");
+ string_append (tname, "> class");
+ return (success);
+}
+
+static int
+demangle_expression (struct work_stuff *work, const char **mangled,
+ string *s, type_kind_t tk)
+{
+ int need_operator = 0;
+ int success;
+
+ success = 1;
+ string_appendn (s, "(", 1);
+ (*mangled)++;
+ while (success && **mangled != 'W' && **mangled != '\0')
+ {
+ if (need_operator)
+ {
+ size_t i;
+ size_t len;
+
+ success = 0;
+
+ len = strlen (*mangled);
+
+ for (i = 0; i < ARRAY_SIZE (optable); ++i)
+ {
+ size_t l = strlen (optable[i].in);
+
+ if (l <= len
+ && memcmp (optable[i].in, *mangled, l) == 0)
+ {
+ string_appendn (s, " ", 1);
+ string_append (s, optable[i].out);
+ string_appendn (s, " ", 1);
+ success = 1;
+ (*mangled) += l;
+ break;
+ }
+ }
+
+ if (!success)
+ break;
+ }
+ else
+ need_operator = 1;
+
+ success = demangle_template_value_parm (work, mangled, s, tk);
+ }
+
+ if (**mangled != 'W')
+ success = 0;
+ else
+ {
+ string_appendn (s, ")", 1);
+ (*mangled)++;
+ }
+
+ return success;
+}
+
+static int
+demangle_integral_value (struct work_stuff *work,
+ const char **mangled, string *s)
+{
+ int success;
+
+ if (**mangled == 'E')
+ success = demangle_expression (work, mangled, s, tk_integral);
+ else if (**mangled == 'Q' || **mangled == 'K')
+ success = demangle_qualified (work, mangled, s, 0, 1);
+ else
+ {
+ int value;
+
+ /* By default, we let the number decide whether we shall consume an
+ underscore. */
+ int multidigit_without_leading_underscore = 0;
+ int leave_following_underscore = 0;
+
+ success = 0;
+
+ if (**mangled == '_')
+ {
+ if (mangled[0][1] == 'm')
+ {
+ /* Since consume_count_with_underscores does not handle the
+ `m'-prefix we must do it here, using consume_count and
+ adjusting underscores: we have to consume the underscore
+ matching the prepended one. */
+ multidigit_without_leading_underscore = 1;
+ string_appendn (s, "-", 1);
+ (*mangled) += 2;
+ }
+ else
+ {
+ /* Do not consume a following underscore;
+ consume_count_with_underscores will consume what
+ should be consumed. */
+ leave_following_underscore = 1;
+ }
+ }
+ else
+ {
+ /* Negative numbers are indicated with a leading `m'. */
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ /* Since consume_count_with_underscores does not handle
+ multi-digit numbers that do not start with an underscore,
+ and this number can be an integer template parameter,
+ we have to call consume_count. */
+ multidigit_without_leading_underscore = 1;
+ /* These multi-digit numbers never end on an underscore,
+ so if there is one then don't eat it. */
+ leave_following_underscore = 1;
+ }
+
+ /* We must call consume_count if we expect to remove a trailing
+ underscore, since consume_count_with_underscores expects
+ the leading underscore (that we consumed) if it is to handle
+ multi-digit numbers. */
+ if (multidigit_without_leading_underscore)
+ value = consume_count (mangled);
+ else
+ value = consume_count_with_underscores (mangled);
+
+ if (value != -1)
+ {
+ char buf[INTBUF_SIZE];
+ sprintf (buf, "%d", value);
+ string_append (s, buf);
+
+ /* Numbers not otherwise delimited, might have an underscore
+ appended as a delimeter, which we should skip.
+
+ ??? This used to always remove a following underscore, which
+ is wrong. If other (arbitrary) cases are followed by an
+ underscore, we need to do something more radical. */
+
+ if ((value > 9 || multidigit_without_leading_underscore)
+ && ! leave_following_underscore
+ && **mangled == '_')
+ (*mangled)++;
+
+ /* All is well. */
+ success = 1;
+ }
+ }
+
+ return success;
+}
+
+/* Demangle the real value in MANGLED. */
+
+static int
+demangle_real_value (struct work_stuff *work,
+ const char **mangled, string *s)
+{
+ if (**mangled == 'E')
+ return demangle_expression (work, mangled, s, tk_real);
+
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ while (ISDIGIT ((unsigned char)**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ if (**mangled == '.') /* fraction */
+ {
+ string_appendn (s, ".", 1);
+ (*mangled)++;
+ while (ISDIGIT ((unsigned char)**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ if (**mangled == 'e') /* exponent */
+ {
+ string_appendn (s, "e", 1);
+ (*mangled)++;
+ while (ISDIGIT ((unsigned char)**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+
+ return 1;
+}
+
+static int
+demangle_template_value_parm (struct work_stuff *work, const char **mangled,
+ string *s, type_kind_t tk)
+{
+ int success = 1;
+
+ if (**mangled == 'Y')
+ {
+ /* The next argument is a template parameter. */
+ int idx;
+
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1
+ || (work->tmpl_argvec && idx >= work->ntmpl_args)
+ || consume_count_with_underscores (mangled) == -1)
+ return -1;
+ if (work->tmpl_argvec)
+ string_append (s, work->tmpl_argvec[idx]);
+ else
+ string_append_template_idx (s, idx);
+ }
+ else if (tk == tk_integral)
+ success = demangle_integral_value (work, mangled, s);
+ else if (tk == tk_char)
+ {
+ char tmp[2];
+ int val;
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ string_appendn (s, "'", 1);
+ val = consume_count(mangled);
+ if (val <= 0)
+ success = 0;
+ else
+ {
+ tmp[0] = (char)val;
+ tmp[1] = '\0';
+ string_appendn (s, &tmp[0], 1);
+ string_appendn (s, "'", 1);
+ }
+ }
+ else if (tk == tk_bool)
+ {
+ int val = consume_count (mangled);
+ if (val == 0)
+ string_appendn (s, "false", 5);
+ else if (val == 1)
+ string_appendn (s, "true", 4);
+ else
+ success = 0;
+ }
+ else if (tk == tk_real)
+ success = demangle_real_value (work, mangled, s);
+ else if (tk == tk_pointer || tk == tk_reference)
+ {
+ if (**mangled == 'Q')
+ success = demangle_qualified (work, mangled, s,
+ /*isfuncname=*/0,
+ /*append=*/1);
+ else
+ {
+ int symbol_len = consume_count (mangled);
+ if (symbol_len == -1)
+ return -1;
+ if (symbol_len == 0)
+ string_appendn (s, "0", 1);
+ else
+ {
+ char *p = XNEWVEC (char, symbol_len + 1), *q;
+ strncpy (p, *mangled, symbol_len);
+ p [symbol_len] = '\0';
+ /* We use cplus_demangle here, rather than
+ internal_cplus_demangle, because the name of the entity
+ mangled here does not make use of any of the squangling
+ or type-code information we have built up thus far; it is
+ mangled independently. */
+ q = cplus_demangle (p, work->options);
+ if (tk == tk_pointer)
+ string_appendn (s, "&", 1);
+ /* FIXME: Pointer-to-member constants should get a
+ qualifying class name here. */
+ if (q)
+ {
+ string_append (s, q);
+ free (q);
+ }
+ else
+ string_append (s, p);
+ free (p);
+ }
+ *mangled += symbol_len;
+ }
+ }
+
+ return success;
+}
+
+/* Demangle the template name in MANGLED. The full name of the
+ template (e.g., S<int>) is placed in TNAME. The name without the
+ template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
+ non-NULL. If IS_TYPE is nonzero, this template is a type template,
+ not a function template. If both IS_TYPE and REMEMBER are nonzero,
+ the template is remembered in the list of back-referenceable
+ types. */
+
+static int
+demangle_template (struct work_stuff *work, const char **mangled,
+ string *tname, string *trawname,
+ int is_type, int remember)
+{
+ int i;
+ int r;
+ int need_comma = 0;
+ int success = 0;
+ int is_java_array = 0;
+ string temp;
+
+ (*mangled)++;
+ if (is_type)
+ {
+ /* get template name */
+ if (**mangled == 'z')
+ {
+ int idx;
+ (*mangled)++;
+ (*mangled)++;
+
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1
+ || (work->tmpl_argvec && idx >= work->ntmpl_args)
+ || consume_count_with_underscores (mangled) == -1)
+ return (0);
+
+ if (work->tmpl_argvec)
+ {
+ string_append (tname, work->tmpl_argvec[idx]);
+ if (trawname)
+ string_append (trawname, work->tmpl_argvec[idx]);
+ }
+ else
+ {
+ string_append_template_idx (tname, idx);
+ if (trawname)
+ string_append_template_idx (trawname, idx);
+ }
+ }
+ else
+ {
+ if ((r = consume_count (mangled)) <= 0
+ || (int) strlen (*mangled) < r)
+ {
+ return (0);
+ }
+ is_java_array = (work -> options & DMGL_JAVA)
+ && strncmp (*mangled, "JArray1Z", 8) == 0;
+ if (! is_java_array)
+ {
+ string_appendn (tname, *mangled, r);
+ }
+ if (trawname)
+ string_appendn (trawname, *mangled, r);
+ *mangled += r;
+ }
+ }
+ if (!is_java_array)
+ string_append (tname, "<");
+ /* get size of template parameter list */
+ if (!get_count (mangled, &r))
+ {
+ return (0);
+ }
+ if (!is_type)
+ {
+ /* Create an array for saving the template argument values. */
+ work->tmpl_argvec = XNEWVEC (char *, r);
+ work->ntmpl_args = r;
+ for (i = 0; i < r; i++)
+ work->tmpl_argvec[i] = 0;
+ }
+ for (i = 0; i < r; i++)
+ {
+ if (need_comma)
+ {
+ string_append (tname, ", ");
+ }
+ /* Z for type parameters */
+ if (**mangled == 'Z')
+ {
+ (*mangled)++;
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ if (success)
+ {
+ string_appends (tname, &temp);
+
+ if (!is_type)
+ {
+ /* Save the template argument. */
+ int len = temp.p - temp.b;
+ work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
+ memcpy (work->tmpl_argvec[i], temp.b, len);
+ work->tmpl_argvec[i][len] = '\0';
+ }
+ }
+ string_delete(&temp);
+ if (!success)
+ {
+ break;
+ }
+ }
+ /* z for template parameters */
+ else if (**mangled == 'z')
+ {
+ int r2;
+ (*mangled)++;
+ success = demangle_template_template_parm (work, mangled, tname);
+
+ if (success
+ && (r2 = consume_count (mangled)) > 0
+ && (int) strlen (*mangled) >= r2)
+ {
+ string_append (tname, " ");
+ string_appendn (tname, *mangled, r2);
+ if (!is_type)
+ {
+ /* Save the template argument. */
+ int len = r2;
+ work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
+ memcpy (work->tmpl_argvec[i], *mangled, len);
+ work->tmpl_argvec[i][len] = '\0';
+ }
+ *mangled += r2;
+ }
+ if (!success)
+ {
+ break;
+ }
+ }
+ else
+ {
+ string param;
+ string* s;
+
+ /* otherwise, value parameter */
+
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ string_delete(&temp);
+ if (!success)
+ break;
+
+ if (!is_type)
+ {
+ s = &param;
+ string_init (s);
+ }
+ else
+ s = tname;
+
+ success = demangle_template_value_parm (work, mangled, s,
+ (type_kind_t) success);
+
+ if (!success)
+ {
+ if (!is_type)
+ string_delete (s);
+ success = 0;
+ break;
+ }
+
+ if (!is_type)
+ {
+ int len = s->p - s->b;
+ work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
+ memcpy (work->tmpl_argvec[i], s->b, len);
+ work->tmpl_argvec[i][len] = '\0';
+
+ string_appends (tname, s);
+ string_delete (s);
+ }
+ }
+ need_comma = 1;
+ }
+ if (is_java_array)
+ {
+ string_append (tname, "[]");
+ }
+ else
+ {
+ if (tname->p[-1] == '>')
+ string_append (tname, " ");
+ string_append (tname, ">");
+ }
+
+ if (is_type && remember)
+ {
+ const int bindex = register_Btype (work);
+ remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
+ }
+
+ /*
+ if (work -> static_type)
+ {
+ string_append (declp, *mangled + 1);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+ */
+ return (success);
+}
+
+static int
+arm_pt (struct work_stuff *work, const char *mangled,
+ int n, const char **anchor, const char **args)
+{
+ /* Check if ARM template with "__pt__" in it ("parameterized type") */
+ /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */
+ if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__")))
+ {
+ int len;
+ *args = *anchor + 6;
+ len = consume_count (args);
+ if (len == -1)
+ return 0;
+ if (*args + len == mangled + n && **args == '_')
+ {
+ ++*args;
+ return 1;
+ }
+ }
+ if (AUTO_DEMANGLING || EDG_DEMANGLING)
+ {
+ if ((*anchor = strstr (mangled, "__tm__"))
+ || (*anchor = strstr (mangled, "__ps__"))
+ || (*anchor = strstr (mangled, "__pt__")))
+ {
+ int len;
+ *args = *anchor + 6;
+ len = consume_count (args);
+ if (len == -1)
+ return 0;
+ if (*args + len == mangled + n && **args == '_')
+ {
+ ++*args;
+ return 1;
+ }
+ }
+ else if ((*anchor = strstr (mangled, "__S")))
+ {
+ int len;
+ *args = *anchor + 3;
+ len = consume_count (args);
+ if (len == -1)
+ return 0;
+ if (*args + len == mangled + n && **args == '_')
+ {
+ ++*args;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void
+demangle_arm_hp_template (struct work_stuff *work, const char **mangled,
+ int n, string *declp)
+{
+ const char *p;
+ const char *args;
+ const char *e = *mangled + n;
+ string arg;
+
+ /* Check for HP aCC template spec: classXt1t2 where t1, t2 are
+ template args */
+ if (HP_DEMANGLING && ((*mangled)[n] == 'X'))
+ {
+ char *start_spec_args = NULL;
+ int hold_options;
+
+ /* First check for and omit template specialization pseudo-arguments,
+ such as in "Spec<#1,#1.*>" */
+ start_spec_args = strchr (*mangled, '<');
+ if (start_spec_args && (start_spec_args - *mangled < n))
+ string_appendn (declp, *mangled, start_spec_args - *mangled);
+ else
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n + 1;
+ string_init (&arg);
+ if (work->temp_start == -1) /* non-recursive call */
+ work->temp_start = declp->p - declp->b;
+
+ /* We want to unconditionally demangle parameter types in
+ template parameters. */
+ hold_options = work->options;
+ work->options |= DMGL_PARAMS;
+
+ string_append (declp, "<");
+ while (1)
+ {
+ string_delete (&arg);
+ switch (**mangled)
+ {
+ case 'T':
+ /* 'T' signals a type parameter */
+ (*mangled)++;
+ if (!do_type (work, mangled, &arg))
+ goto hpacc_template_args_done;
+ break;
+
+ case 'U':
+ case 'S':
+ /* 'U' or 'S' signals an integral value */
+ if (!do_hpacc_template_const_value (work, mangled, &arg))
+ goto hpacc_template_args_done;
+ break;
+
+ case 'A':
+ /* 'A' signals a named constant expression (literal) */
+ if (!do_hpacc_template_literal (work, mangled, &arg))
+ goto hpacc_template_args_done;
+ break;
+
+ default:
+ /* Today, 1997-09-03, we have only the above types
+ of template parameters */
+ /* FIXME: maybe this should fail and return null */
+ goto hpacc_template_args_done;
+ }
+ string_appends (declp, &arg);
+ /* Check if we're at the end of template args.
+ 0 if at end of static member of template class,
+ _ if done with template args for a function */
+ if ((**mangled == '\000') || (**mangled == '_'))
+ break;
+ else
+ string_append (declp, ",");
+ }
+ hpacc_template_args_done:
+ string_append (declp, ">");
+ string_delete (&arg);
+ if (**mangled == '_')
+ (*mangled)++;
+ work->options = hold_options;
+ return;
+ }
+ /* ARM template? (Also handles HP cfront extensions) */
+ else if (arm_pt (work, *mangled, n, &p, &args))
+ {
+ int hold_options;
+ string type_str;
+
+ string_init (&arg);
+ string_appendn (declp, *mangled, p - *mangled);
+ if (work->temp_start == -1) /* non-recursive call */
+ work->temp_start = declp->p - declp->b;
+
+ /* We want to unconditionally demangle parameter types in
+ template parameters. */
+ hold_options = work->options;
+ work->options |= DMGL_PARAMS;
+
+ string_append (declp, "<");
+ /* should do error checking here */
+ while (args < e) {
+ string_delete (&arg);
+
+ /* Check for type or literal here */
+ switch (*args)
+ {
+ /* HP cfront extensions to ARM for template args */
+ /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */
+ /* FIXME: We handle only numeric literals for HP cfront */
+ case 'X':
+ /* A typed constant value follows */
+ args++;
+ if (!do_type (work, &args, &type_str))
+ goto cfront_template_args_done;
+ string_append (&arg, "(");
+ string_appends (&arg, &type_str);
+ string_delete (&type_str);
+ string_append (&arg, ")");
+ if (*args != 'L')
+ goto cfront_template_args_done;
+ args++;
+ /* Now snarf a literal value following 'L' */
+ if (!snarf_numeric_literal (&args, &arg))
+ goto cfront_template_args_done;
+ break;
+
+ case 'L':
+ /* Snarf a literal following 'L' */
+ args++;
+ if (!snarf_numeric_literal (&args, &arg))
+ goto cfront_template_args_done;
+ break;
+ default:
+ /* Not handling other HP cfront stuff */
+ {
+ const char* old_args = args;
+ if (!do_type (work, &args, &arg))
+ goto cfront_template_args_done;
+
+ /* Fail if we didn't make any progress: prevent infinite loop. */
+ if (args == old_args)
+ {
+ work->options = hold_options;
+ return;
+ }
+ }
+ }
+ string_appends (declp, &arg);
+ string_append (declp, ",");
+ }
+ cfront_template_args_done:
+ string_delete (&arg);
+ if (args >= e)
+ --declp->p; /* remove extra comma */
+ string_append (declp, ">");
+ work->options = hold_options;
+ }
+ else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
+ && (*mangled)[9] == 'N'
+ && (*mangled)[8] == (*mangled)[10]
+ && strchr (cplus_markers, (*mangled)[8]))
+ {
+ /* A member of the anonymous namespace. */
+ string_append (declp, "{anonymous}");
+ }
+ else
+ {
+ if (work->temp_start == -1) /* non-recursive call only */
+ work->temp_start = 0; /* disable in recursive calls */
+ string_appendn (declp, *mangled, n);
+ }
+ *mangled += n;
+}
+
+/* Extract a class name, possibly a template with arguments, from the
+ mangled string; qualifiers, local class indicators, etc. have
+ already been dealt with */
+
+static int
+demangle_class_name (struct work_stuff *work, const char **mangled,
+ string *declp)
+{
+ int n;
+ int success = 0;
+
+ n = consume_count (mangled);
+ if (n == -1)
+ return 0;
+ if ((int) strlen (*mangled) >= n)
+ {
+ demangle_arm_hp_template (work, mangled, n, declp);
+ success = 1;
+ }
+
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_class -- demangle a mangled class sequence
+
+SYNOPSIS
+
+ static int
+ demangle_class (struct work_stuff *work, const char **mangled,
+ strint *declp)
+
+DESCRIPTION
+
+ DECLP points to the buffer into which demangling is being done.
+
+ *MANGLED points to the current token to be demangled. On input,
+ it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
+ On exit, it points to the next token after the mangled class on
+ success, or the first unconsumed token on failure.
+
+ If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
+ we are demangling a constructor or destructor. In this case
+ we prepend "class::class" or "class::~class" to DECLP.
+
+ Otherwise, we prepend "class::" to the current DECLP.
+
+ Reset the constructor/destructor flags once they have been
+ "consumed". This allows demangle_class to be called later during
+ the same demangling, to do normal class demangling.
+
+ Returns 1 if demangling is successful, 0 otherwise.
+
+*/
+
+static int
+demangle_class (struct work_stuff *work, const char **mangled, string *declp)
+{
+ int success = 0;
+ int btype;
+ string class_name;
+ char *save_class_name_end = 0;
+
+ string_init (&class_name);
+ btype = register_Btype (work);
+ if (demangle_class_name (work, mangled, &class_name))
+ {
+ save_class_name_end = class_name.p;
+ if ((work->constructor & 1) || (work->destructor & 1))
+ {
+ /* adjust so we don't include template args */
+ if (work->temp_start && (work->temp_start != -1))
+ {
+ class_name.p = class_name.b + work->temp_start;
+ }
+ string_prepends (declp, &class_name);
+ if (work -> destructor & 1)
+ {
+ string_prepend (declp, "~");
+ work -> destructor -= 1;
+ }
+ else
+ {
+ work -> constructor -= 1;
+ }
+ }
+ class_name.p = save_class_name_end;
+ remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
+ remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
+ string_prepend (declp, SCOPE_STRING (work));
+ string_prepends (declp, &class_name);
+ success = 1;
+ }
+ string_delete (&class_name);
+ return (success);
+}
+
+
+/* Called when there's a "__" in the mangled name, with `scan' pointing to
+ the rightmost guess.
+
+ Find the correct "__"-sequence where the function name ends and the
+ signature starts, which is ambiguous with GNU mangling.
+ Call demangle_signature here, so we can make sure we found the right
+ one; *mangled will be consumed so caller will not make further calls to
+ demangle_signature. */
+
+static int
+iterate_demangle_function (struct work_stuff *work, const char **mangled,
+ string *declp, const char *scan)
+{
+ const char *mangle_init = *mangled;
+ int success = 0;
+ string decl_init;
+ struct work_stuff work_init;
+
+ if (*(scan + 2) == '\0')
+ return 0;
+
+ /* Do not iterate for some demangling modes, or if there's only one
+ "__"-sequence. This is the normal case. */
+ if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING
+ || strstr (scan + 2, "__") == NULL)
+ return demangle_function_name (work, mangled, declp, scan);
+
+ /* Save state so we can restart if the guess at the correct "__" was
+ wrong. */
+ string_init (&decl_init);
+ string_appends (&decl_init, declp);
+ memset (&work_init, 0, sizeof work_init);
+ work_stuff_copy_to_from (&work_init, work);
+
+ /* Iterate over occurrences of __, allowing names and types to have a
+ "__" sequence in them. We must start with the first (not the last)
+ occurrence, since "__" most often occur between independent mangled
+ parts, hence starting at the last occurence inside a signature
+ might get us a "successful" demangling of the signature. */
+
+ while (scan[2])
+ {
+ if (demangle_function_name (work, mangled, declp, scan))
+ {
+ success = demangle_signature (work, mangled, declp);
+ if (success)
+ break;
+ }
+
+ /* Reset demangle state for the next round. */
+ *mangled = mangle_init;
+ string_clear (declp);
+ string_appends (declp, &decl_init);
+ work_stuff_copy_to_from (work, &work_init);
+
+ /* Leave this underscore-sequence. */
+ scan += 2;
+
+ /* Scan for the next "__" sequence. */
+ while (*scan && (scan[0] != '_' || scan[1] != '_'))
+ scan++;
+
+ /* Move to last "__" in this sequence. */
+ while (*scan && *scan == '_')
+ scan++;
+ scan -= 2;
+ }
+
+ /* Delete saved state. */
+ delete_work_stuff (&work_init);
+ string_delete (&decl_init);
+
+ return success;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_prefix -- consume the mangled name prefix and find signature
+
+SYNOPSIS
+
+ static int
+ demangle_prefix (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+DESCRIPTION
+
+ Consume and demangle the prefix of the mangled name.
+ While processing the function name root, arrange to call
+ demangle_signature if the root is ambiguous.
+
+ DECLP points to the string buffer into which demangled output is
+ placed. On entry, the buffer is empty. On exit it contains
+ the root function name, the demangled operator name, or in some
+ special cases either nothing or the completely demangled result.
+
+ MANGLED points to the current pointer into the mangled name. As each
+ token of the mangled name is consumed, it is updated. Upon entry
+ the current mangled name pointer points to the first character of
+ the mangled name. Upon exit, it should point to the first character
+ of the signature if demangling was successful, or to the first
+ unconsumed character if demangling of the prefix was unsuccessful.
+
+ Returns 1 on success, 0 otherwise.
+ */
+
+static int
+demangle_prefix (struct work_stuff *work, const char **mangled,
+ string *declp)
+{
+ int success = 1;
+ const char *scan;
+ int i;
+
+ if (strlen(*mangled) > 6
+ && (strncmp(*mangled, "_imp__", 6) == 0
+ || strncmp(*mangled, "__imp_", 6) == 0))
+ {
+ /* it's a symbol imported from a PE dynamic library. Check for both
+ new style prefix _imp__ and legacy __imp_ used by older versions
+ of dlltool. */
+ (*mangled) += 6;
+ work->dllimported = 1;
+ }
+ else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
+ {
+ char *marker = strchr (cplus_markers, (*mangled)[8]);
+ if (marker != NULL && *marker == (*mangled)[10])
+ {
+ if ((*mangled)[9] == 'D')
+ {
+ /* it's a GNU global destructor to be executed at program exit */
+ (*mangled) += 11;
+ work->destructor = 2;
+ if (gnu_special (work, mangled, declp))
+ return success;
+ }
+ else if ((*mangled)[9] == 'I')
+ {
+ /* it's a GNU global constructor to be executed at program init */
+ (*mangled) += 11;
+ work->constructor = 2;
+ if (gnu_special (work, mangled, declp))
+ return success;
+ }
+ }
+ }
+ else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0)
+ {
+ /* it's a ARM global destructor to be executed at program exit */
+ (*mangled) += 7;
+ work->destructor = 2;
+ }
+ else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0)
+ {
+ /* it's a ARM global constructor to be executed at program initial */
+ (*mangled) += 7;
+ work->constructor = 2;
+ }
+
+ /* This block of code is a reduction in strength time optimization
+ of:
+ scan = strstr (*mangled, "__"); */
+
+ {
+ scan = *mangled;
+
+ do {
+ scan = strchr (scan, '_');
+ } while (scan != NULL && *++scan != '_');
+
+ if (scan != NULL) --scan;
+ }
+
+ if (scan != NULL)
+ {
+ /* We found a sequence of two or more '_', ensure that we start at
+ the last pair in the sequence. */
+ i = strspn (scan, "_");
+ if (i > 2)
+ {
+ scan += (i - 2);
+ }
+ }
+
+ if (scan == NULL)
+ {
+ success = 0;
+ }
+ else if (work -> static_type)
+ {
+ if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't'))
+ {
+ success = 0;
+ }
+ }
+ else if ((scan == *mangled)
+ && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q')
+ || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H')))
+ {
+ /* The ARM says nothing about the mangling of local variables.
+ But cfront mangles local variables by prepending __<nesting_level>
+ to them. As an extension to ARM demangling we handle this case. */
+ if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING)
+ && ISDIGIT ((unsigned char)scan[2]))
+ {
+ *mangled = scan + 2;
+ consume_count (mangled);
+ string_append (declp, *mangled);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ else
+ {
+ /* A GNU style constructor starts with __[0-9Qt]. But cfront uses
+ names like __Q2_3foo3bar for nested type names. So don't accept
+ this style of constructor for cfront demangling. A GNU
+ style member-template constructor starts with 'H'. */
+ if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING))
+ work -> constructor += 1;
+ *mangled = scan + 2;
+ }
+ }
+ else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
+ {
+ /* Cfront-style parameterized type. Handled later as a signature. */
+ success = 1;
+
+ /* ARM template? */
+ demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
+ }
+ else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm')
+ || (scan[2] == 'p' && scan[3] == 's')
+ || (scan[2] == 'p' && scan[3] == 't')))
+ {
+ /* EDG-style parameterized type. Handled later as a signature. */
+ success = 1;
+
+ /* EDG template? */
+ demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
+ }
+ else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2])
+ && (scan[2] != 't'))
+ {
+ /* Mangled name starts with "__". Skip over any leading '_' characters,
+ then find the next "__" that separates the prefix from the signature.
+ */
+ if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
+ || (arm_special (mangled, declp) == 0))
+ {
+ while (*scan == '_')
+ {
+ scan++;
+ }
+ if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
+ {
+ /* No separator (I.E. "__not_mangled"), or empty signature
+ (I.E. "__not_mangled_either__") */
+ success = 0;
+ }
+ else
+ return iterate_demangle_function (work, mangled, declp, scan);
+ }
+ }
+ else if (*(scan + 2) != '\0')
+ {
+ /* Mangled name does not start with "__" but does have one somewhere
+ in there with non empty stuff after it. Looks like a global
+ function name. Iterate over all "__":s until the right
+ one is found. */
+ return iterate_demangle_function (work, mangled, declp, scan);
+ }
+ else
+ {
+ /* Doesn't look like a mangled name */
+ success = 0;
+ }
+
+ if (!success && (work->constructor == 2 || work->destructor == 2))
+ {
+ string_append (declp, *mangled);
+ *mangled += strlen (*mangled);
+ success = 1;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ gnu_special -- special handling of gnu mangled strings
+
+SYNOPSIS
+
+ static int
+ gnu_special (struct work_stuff *work, const char **mangled,
+ string *declp);
+
+
+DESCRIPTION
+
+ Process some special GNU style mangling forms that don't fit
+ the normal pattern. For example:
+
+ _$_3foo (destructor for class foo)
+ _vt$foo (foo virtual table)
+ _vt$foo$bar (foo::bar virtual table)
+ __vt_foo (foo virtual table, new style with thunks)
+ _3foo$varname (static data member)
+ _Q22rs2tu$vw (static data member)
+ __t6vector1Zii (constructor with template)
+ __thunk_4__$_7ostream (virtual function thunk)
+ */
+
+static int
+gnu_special (struct work_stuff *work, const char **mangled, string *declp)
+{
+ int n;
+ int success = 1;
+ const char *p;
+
+ if ((*mangled)[0] == '_'
+ && strchr (cplus_markers, (*mangled)[1]) != NULL
+ && (*mangled)[2] == '_')
+ {
+ /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
+ (*mangled) += 3;
+ work -> destructor += 1;
+ }
+ else if ((*mangled)[0] == '_'
+ && (((*mangled)[1] == '_'
+ && (*mangled)[2] == 'v'
+ && (*mangled)[3] == 't'
+ && (*mangled)[4] == '_')
+ || ((*mangled)[1] == 'v'
+ && (*mangled)[2] == 't'
+ && strchr (cplus_markers, (*mangled)[3]) != NULL)))
+ {
+ /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
+ and create the decl. Note that we consume the entire mangled
+ input string, which means that demangle_signature has no work
+ to do. */
+ if ((*mangled)[2] == 'v')
+ (*mangled) += 5; /* New style, with thunks: "__vt_" */
+ else
+ (*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
+ while (**mangled != '\0')
+ {
+ switch (**mangled)
+ {
+ case 'Q':
+ case 'K':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0, 1,
+ 1);
+ break;
+ default:
+ if (ISDIGIT((unsigned char)*mangled[0]))
+ {
+ n = consume_count(mangled);
+ /* We may be seeing a too-large size, or else a
+ ".<digits>" indicating a static local symbol. In
+ any case, declare victory and move on; *don't* try
+ to use n to allocate. */
+ if (n > (int) strlen (*mangled))
+ {
+ success = 1;
+ break;
+ }
+ }
+ else
+ {
+ n = strcspn (*mangled, cplus_markers);
+ }
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+
+ p = strpbrk (*mangled, cplus_markers);
+ if (success && ((p == NULL) || (p == *mangled)))
+ {
+ if (p != NULL)
+ {
+ string_append (declp, SCOPE_STRING (work));
+ (*mangled)++;
+ }
+ }
+ else
+ {
+ success = 0;
+ break;
+ }
+ }
+ if (success)
+ string_append (declp, " virtual table");
+ }
+ else if ((*mangled)[0] == '_'
+ && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
+ && (p = strpbrk (*mangled, cplus_markers)) != NULL)
+ {
+ /* static data member, "_3foo$varname" for example */
+ (*mangled)++;
+ switch (**mangled)
+ {
+ case 'Q':
+ case 'K':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0, 1, 1);
+ break;
+ default:
+ n = consume_count (mangled);
+ if (n < 0 || n > (long) strlen (*mangled))
+ {
+ success = 0;
+ break;
+ }
+
+ if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
+ && (*mangled)[9] == 'N'
+ && (*mangled)[8] == (*mangled)[10]
+ && strchr (cplus_markers, (*mangled)[8]))
+ {
+ /* A member of the anonymous namespace. There's information
+ about what identifier or filename it was keyed to, but
+ it's just there to make the mangled name unique; we just
+ step over it. */
+ string_append (declp, "{anonymous}");
+ (*mangled) += n;
+
+ /* Now p points to the marker before the N, so we need to
+ update it to the first marker after what we consumed. */
+ p = strpbrk (*mangled, cplus_markers);
+ break;
+ }
+
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+ if (success && (p == *mangled))
+ {
+ /* Consumed everything up to the cplus_marker, append the
+ variable name. */
+ (*mangled)++;
+ string_append (declp, SCOPE_STRING (work));
+ n = strlen (*mangled);
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+ }
+ else
+ {
+ success = 0;
+ }
+ }
+ else if (strncmp (*mangled, "__thunk_", 8) == 0)
+ {
+ int delta;
+
+ (*mangled) += 8;
+ delta = consume_count (mangled);
+ if (delta == -1)
+ success = 0;
+ else
+ {
+ char *method = internal_cplus_demangle (work, ++*mangled);
+
+ if (method)
+ {
+ char buf[50];
+ sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
+ string_append (declp, buf);
+ string_append (declp, method);
+ free (method);
+ n = strlen (*mangled);
+ (*mangled) += n;
+ }
+ else
+ {
+ success = 0;
+ }
+ }
+ }
+ else if (strncmp (*mangled, "__t", 3) == 0
+ && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
+ {
+ p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
+ (*mangled) += 4;
+ switch (**mangled)
+ {
+ case 'Q':
+ case 'K':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0, 1, 1);
+ break;
+ default:
+ success = do_type (work, mangled, declp);
+ break;
+ }
+ if (success && **mangled != '\0')
+ success = 0;
+ if (success)
+ string_append (declp, p);
+ }
+ else
+ {
+ success = 0;
+ }
+ return (success);
+}
+
+static void
+recursively_demangle(struct work_stuff *work, const char **mangled,
+ string *result, int namelength)
+{
+ char * recurse = (char *)NULL;
+ char * recurse_dem = (char *)NULL;
+
+ recurse = XNEWVEC (char, namelength + 1);
+ memcpy (recurse, *mangled, namelength);
+ recurse[namelength] = '\000';
+
+ recurse_dem = cplus_demangle (recurse, work->options);
+
+ if (recurse_dem)
+ {
+ string_append (result, recurse_dem);
+ free (recurse_dem);
+ }
+ else
+ {
+ string_appendn (result, *mangled, namelength);
+ }
+ free (recurse);
+ *mangled += namelength;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ arm_special -- special handling of ARM/lucid mangled strings
+
+SYNOPSIS
+
+ static int
+ arm_special (const char **mangled,
+ string *declp);
+
+
+DESCRIPTION
+
+ Process some special ARM style mangling forms that don't fit
+ the normal pattern. For example:
+
+ __vtbl__3foo (foo virtual table)
+ __vtbl__3foo__3bar (bar::foo virtual table)
+
+ */
+
+static int
+arm_special (const char **mangled, string *declp)
+{
+ int n;
+ int success = 1;
+ const char *scan;
+
+ if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
+ {
+ /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
+ and create the decl. Note that we consume the entire mangled
+ input string, which means that demangle_signature has no work
+ to do. */
+ scan = *mangled + ARM_VTABLE_STRLEN;
+ while (*scan != '\0') /* first check it can be demangled */
+ {
+ n = consume_count (&scan);
+ if (n == -1)
+ {
+ return (0); /* no good */
+ }
+ scan += n;
+ if (scan[0] == '_' && scan[1] == '_')
+ {
+ scan += 2;
+ }
+ }
+ (*mangled) += ARM_VTABLE_STRLEN;
+ while (**mangled != '\0')
+ {
+ n = consume_count (mangled);
+ if (n == -1
+ || n > (long) strlen (*mangled))
+ return 0;
+ string_prependn (declp, *mangled, n);
+ (*mangled) += n;
+ if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
+ {
+ string_prepend (declp, "::");
+ (*mangled) += 2;
+ }
+ }
+ string_append (declp, " virtual table");
+ }
+ else
+ {
+ success = 0;
+ }
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ demangle_qualified -- demangle 'Q' qualified name strings
+
+SYNOPSIS
+
+ static int
+ demangle_qualified (struct work_stuff *, const char *mangled,
+ string *result, int isfuncname, int append);
+
+DESCRIPTION
+
+ Demangle a qualified name, such as "Q25Outer5Inner" which is
+ the mangled form of "Outer::Inner". The demangled output is
+ prepended or appended to the result string according to the
+ state of the append flag.
+
+ If isfuncname is nonzero, then the qualified name we are building
+ is going to be used as a member function name, so if it is a
+ constructor or destructor function, append an appropriate
+ constructor or destructor name. I.E. for the above example,
+ the result for use as a constructor is "Outer::Inner::Inner"
+ and the result for use as a destructor is "Outer::Inner::~Inner".
+
+BUGS
+
+ Numeric conversion is ASCII dependent (FIXME).
+
+ */
+
+static int
+demangle_qualified (struct work_stuff *work, const char **mangled,
+ string *result, int isfuncname, int append)
+{
+ int qualifiers = 0;
+ int success = 1;
+ char num[2];
+ string temp;
+ string last_name;
+ int bindex = register_Btype (work);
+
+ /* We only make use of ISFUNCNAME if the entity is a constructor or
+ destructor. */
+ isfuncname = (isfuncname
+ && ((work->constructor & 1) || (work->destructor & 1)));
+
+ string_init (&temp);
+ string_init (&last_name);
+
+ if ((*mangled)[0] == 'K')
+ {
+ /* Squangling qualified name reuse */
+ int idx;
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1 || idx >= work -> numk)
+ success = 0;
+ else
+ string_append (&temp, work -> ktypevec[idx]);
+ }
+ else
+ switch ((*mangled)[1])
+ {
+ case '_':
+ /* GNU mangled name with more than 9 classes. The count is preceded
+ by an underscore (to distinguish it from the <= 9 case) and followed
+ by an underscore. */
+ (*mangled)++;
+ qualifiers = consume_count_with_underscores (mangled);
+ if (qualifiers == -1)
+ success = 0;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* The count is in a single digit. */
+ num[0] = (*mangled)[1];
+ num[1] = '\0';
+ qualifiers = atoi (num);
+
+ /* If there is an underscore after the digit, skip it. This is
+ said to be for ARM-qualified names, but the ARM makes no
+ mention of such an underscore. Perhaps cfront uses one. */
+ if ((*mangled)[2] == '_')
+ {
+ (*mangled)++;
+ }
+ (*mangled) += 2;
+ break;
+
+ case '0':
+ default:
+ success = 0;
+ }
+
+ if (!success)
+ return success;
+
+ /* Pick off the names and collect them in the temp buffer in the order
+ in which they are found, separated by '::'. */
+
+ while (qualifiers-- > 0)
+ {
+ int remember_K = 1;
+ string_clear (&last_name);
+
+ if (*mangled[0] == '_')
+ (*mangled)++;
+
+ if (*mangled[0] == 't')
+ {
+ /* Here we always append to TEMP since we will want to use
+ the template name without the template parameters as a
+ constructor or destructor name. The appropriate
+ (parameter-less) value is returned by demangle_template
+ in LAST_NAME. We do not remember the template type here,
+ in order to match the G++ mangling algorithm. */
+ success = demangle_template(work, mangled, &temp,
+ &last_name, 1, 0);
+ if (!success)
+ break;
+ }
+ else if (*mangled[0] == 'K')
+ {
+ int idx;
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1 || idx >= work->numk)
+ success = 0;
+ else
+ string_append (&temp, work->ktypevec[idx]);
+ remember_K = 0;
+
+ if (!success) break;
+ }
+ else
+ {
+ if (EDG_DEMANGLING)
+ {
+ int namelength;
+ /* Now recursively demangle the qualifier
+ * This is necessary to deal with templates in
+ * mangling styles like EDG */
+ namelength = consume_count (mangled);
+ if (namelength == -1)
+ {
+ success = 0;
+ break;
+ }
+ recursively_demangle(work, mangled, &temp, namelength);
+ }
+ else
+ {
+ string_delete (&last_name);
+ success = do_type (work, mangled, &last_name);
+ if (!success)
+ break;
+ string_appends (&temp, &last_name);
+ }
+ }
+
+ if (remember_K)
+ remember_Ktype (work, temp.b, LEN_STRING (&temp));
+
+ if (qualifiers > 0)
+ string_append (&temp, SCOPE_STRING (work));
+ }
+
+ remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
+
+ /* If we are using the result as a function name, we need to append
+ the appropriate '::' separated constructor or destructor name.
+ We do this here because this is the most convenient place, where
+ we already have a pointer to the name and the length of the name. */
+
+ if (isfuncname)
+ {
+ string_append (&temp, SCOPE_STRING (work));
+ if (work -> destructor & 1)
+ string_append (&temp, "~");
+ string_appends (&temp, &last_name);
+ }
+
+ /* Now either prepend the temp buffer to the result, or append it,
+ depending upon the state of the append flag. */
+
+ if (append)
+ string_appends (result, &temp);
+ else
+ {
+ if (!STRING_EMPTY (result))
+ string_append (&temp, SCOPE_STRING (work));
+ string_prepends (result, &temp);
+ }
+
+ string_delete (&last_name);
+ string_delete (&temp);
+ return (success);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ get_count -- convert an ascii count to integer, consuming tokens
+
+SYNOPSIS
+
+ static int
+ get_count (const char **type, int *count)
+
+DESCRIPTION
+
+ Assume that *type points at a count in a mangled name; set
+ *count to its value, and set *type to the next character after
+ the count. There are some weird rules in effect here.
+
+ If *type does not point at a string of digits, return zero.
+
+ If *type points at a string of digits followed by an
+ underscore, set *count to their value as an integer, advance
+ *type to point *after the underscore, and return 1.
+
+ If *type points at a string of digits not followed by an
+ underscore, consume only the first digit. Set *count to its
+ value as an integer, leave *type pointing after that digit,
+ and return 1.
+
+ The excuse for this odd behavior: in the ARM and HP demangling
+ styles, a type can be followed by a repeat count of the form
+ `Nxy', where:
+
+ `x' is a single digit specifying how many additional copies
+ of the type to append to the argument list, and
+
+ `y' is one or more digits, specifying the zero-based index of
+ the first repeated argument in the list. Yes, as you're
+ unmangling the name you can figure this out yourself, but
+ it's there anyway.
+
+ So, for example, in `bar__3fooFPiN51', the first argument is a
+ pointer to an integer (`Pi'), and then the next five arguments
+ are the same (`N5'), and the first repeat is the function's
+ second argument (`1').
+*/
+
+static int
+get_count (const char **type, int *count)
+{
+ const char *p;
+ int n;
+
+ if (!ISDIGIT ((unsigned char)**type))
+ return (0);
+ else
+ {
+ *count = **type - '0';
+ (*type)++;
+ if (ISDIGIT ((unsigned char)**type))
+ {
+ p = *type;
+ n = *count;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p++;
+ }
+ while (ISDIGIT ((unsigned char)*p));
+ if (*p == '_')
+ {
+ *type = p + 1;
+ *count = n;
+ }
+ }
+ }
+ return (1);
+}
+
+/* RESULT will be initialised here; it will be freed on failure. The
+ value returned is really a type_kind_t. */
+
+static int
+do_type (struct work_stuff *work, const char **mangled, string *result)
+{
+ int n;
+ int done;
+ int success;
+ string decl;
+ const char *remembered_type;
+ int type_quals;
+ type_kind_t tk = tk_none;
+
+ string_init (&decl);
+ string_init (result);
+
+ done = 0;
+ success = 1;
+ while (success && !done)
+ {
+ int member;
+ switch (**mangled)
+ {
+
+ /* A pointer type */
+ case 'P':
+ case 'p':
+ (*mangled)++;
+ if (! (work -> options & DMGL_JAVA))
+ string_prepend (&decl, "*");
+ if (tk == tk_none)
+ tk = tk_pointer;
+ break;
+
+ /* A reference type */
+ case 'R':
+ (*mangled)++;
+ string_prepend (&decl, "&");
+ if (tk == tk_none)
+ tk = tk_reference;
+ break;
+
+ /* An array */
+ case 'A':
+ {
+ ++(*mangled);
+ if (!STRING_EMPTY (&decl)
+ && (decl.b[0] == '*' || decl.b[0] == '&'))
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ string_append (&decl, "[");
+ if (**mangled != '_')
+ success = demangle_template_value_parm (work, mangled, &decl,
+ tk_integral);
+ if (**mangled == '_')
+ ++(*mangled);
+ string_append (&decl, "]");
+ break;
+ }
+
+ /* A back reference to a previously seen type */
+ case 'T':
+ (*mangled)++;
+ if (!get_count (mangled, &n) || n >= work -> ntypes)
+ {
+ success = 0;
+ }
+ else
+ {
+ remembered_type = work -> typevec[n];
+ mangled = &remembered_type;
+ }
+ break;
+
+ /* A function */
+ case 'F':
+ (*mangled)++;
+ if (!STRING_EMPTY (&decl)
+ && (decl.b[0] == '*' || decl.b[0] == '&'))
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ /* After picking off the function args, we expect to either find the
+ function return type (preceded by an '_') or the end of the
+ string. */
+ if (!demangle_nested_args (work, mangled, &decl)
+ || (**mangled != '_' && **mangled != '\0'))
+ {
+ success = 0;
+ break;
+ }
+ if (success && (**mangled == '_'))
+ (*mangled)++;
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ type_quals = TYPE_UNQUALIFIED;
+
+ member = **mangled == 'M';
+ (*mangled)++;
+
+ string_append (&decl, ")");
+
+ /* We don't need to prepend `::' for a qualified name;
+ demangle_qualified will do that for us. */
+ if (**mangled != 'Q')
+ string_prepend (&decl, SCOPE_STRING (work));
+
+ if (ISDIGIT ((unsigned char)**mangled))
+ {
+ n = consume_count (mangled);
+ if (n == -1
+ || (int) strlen (*mangled) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_prependn (&decl, *mangled, n);
+ *mangled += n;
+ }
+ else if (**mangled == 'X' || **mangled == 'Y')
+ {
+ string temp;
+ do_type (work, mangled, &temp);
+ string_prepends (&decl, &temp);
+ string_delete (&temp);
+ }
+ else if (**mangled == 't')
+ {
+ string temp;
+ string_init (&temp);
+ success = demangle_template (work, mangled, &temp,
+ NULL, 1, 1);
+ if (success)
+ {
+ string_prependn (&decl, temp.b, temp.p - temp.b);
+ string_delete (&temp);
+ }
+ else
+ break;
+ }
+ else if (**mangled == 'Q')
+ {
+ success = demangle_qualified (work, mangled, &decl,
+ /*isfuncnam=*/0,
+ /*append=*/0);
+ if (!success)
+ break;
+ }
+ else
+ {
+ success = 0;
+ break;
+ }
+
+ string_prepend (&decl, "(");
+ if (member)
+ {
+ switch (**mangled)
+ {
+ case 'C':
+ case 'V':
+ case 'u':
+ type_quals |= code_for_qualifier (**mangled);
+ (*mangled)++;
+ break;
+
+ default:
+ break;
+ }
+
+ if (*(*mangled)++ != 'F')
+ {
+ success = 0;
+ break;
+ }
+ }
+ if ((member && !demangle_nested_args (work, mangled, &decl))
+ || **mangled != '_')
+ {
+ success = 0;
+ break;
+ }
+ (*mangled)++;
+ if (! PRINT_ANSI_QUALIFIERS)
+ {
+ break;
+ }
+ if (type_quals != TYPE_UNQUALIFIED)
+ {
+ APPEND_BLANK (&decl);
+ string_append (&decl, qualifier_string (type_quals));
+ }
+ break;
+ }
+ case 'G':
+ (*mangled)++;
+ break;
+
+ case 'C':
+ case 'V':
+ case 'u':
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ if (!STRING_EMPTY (&decl))
+ string_prepend (&decl, " ");
+
+ string_prepend (&decl, demangle_qualifier (**mangled));
+ }
+ (*mangled)++;
+ break;
+ /*
+ }
+ */
+
+ /* fall through */
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ if (success) switch (**mangled)
+ {
+ /* A qualified name, such as "Outer::Inner". */
+ case 'Q':
+ case 'K':
+ {
+ success = demangle_qualified (work, mangled, result, 0, 1);
+ break;
+ }
+
+ /* A back reference to a previously seen squangled type */
+ case 'B':
+ (*mangled)++;
+ if (!get_count (mangled, &n) || n >= work -> numb)
+ success = 0;
+ else
+ string_append (result, work->btypevec[n]);
+ break;
+
+ case 'X':
+ case 'Y':
+ /* A template parm. We substitute the corresponding argument. */
+ {
+ int idx;
+
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+
+ if (idx == -1
+ || (work->tmpl_argvec && idx >= work->ntmpl_args)
+ || consume_count_with_underscores (mangled) == -1)
+ {
+ success = 0;
+ break;
+ }
+
+ if (work->tmpl_argvec)
+ string_append (result, work->tmpl_argvec[idx]);
+ else
+ string_append_template_idx (result, idx);
+
+ success = 1;
+ }
+ break;
+
+ default:
+ success = demangle_fund_type (work, mangled, result);
+ if (tk == tk_none)
+ tk = (type_kind_t) success;
+ break;
+ }
+
+ if (success)
+ {
+ if (!STRING_EMPTY (&decl))
+ {
+ string_append (result, " ");
+ string_appends (result, &decl);
+ }
+ }
+ else
+ string_delete (result);
+ string_delete (&decl);
+
+ if (success)
+ /* Assume an integral type, if we're not sure. */
+ return (int) ((tk == tk_none) ? tk_integral : tk);
+ else
+ return 0;
+}
+
+/* Given a pointer to a type string that represents a fundamental type
+ argument (int, long, unsigned int, etc) in TYPE, a pointer to the
+ string in which the demangled output is being built in RESULT, and
+ the WORK structure, decode the types and add them to the result.
+
+ For example:
+
+ "Ci" => "const int"
+ "Sl" => "signed long"
+ "CUs" => "const unsigned short"
+
+ The value returned is really a type_kind_t. */
+
+static int
+demangle_fund_type (struct work_stuff *work,
+ const char **mangled, string *result)
+{
+ int done = 0;
+ int success = 1;
+ char buf[INTBUF_SIZE + 5 /* 'int%u_t' */];
+ unsigned int dec = 0;
+ type_kind_t tk = tk_integral;
+
+ /* First pick off any type qualifiers. There can be more than one. */
+
+ while (!done)
+ {
+ switch (**mangled)
+ {
+ case 'C':
+ case 'V':
+ case 'u':
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ if (!STRING_EMPTY (result))
+ string_prepend (result, " ");
+ string_prepend (result, demangle_qualifier (**mangled));
+ }
+ (*mangled)++;
+ break;
+ case 'U':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "unsigned");
+ break;
+ case 'S': /* signed char only */
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "signed");
+ break;
+ case 'J':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "__complex");
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ /* Now pick off the fundamental type. There can be only one. */
+
+ switch (**mangled)
+ {
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "void");
+ break;
+ case 'x':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long long");
+ break;
+ case 'l':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long");
+ break;
+ case 'i':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "int");
+ break;
+ case 's':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "short");
+ break;
+ case 'b':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "bool");
+ tk = tk_bool;
+ break;
+ case 'c':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "char");
+ tk = tk_char;
+ break;
+ case 'w':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "wchar_t");
+ tk = tk_char;
+ break;
+ case 'r':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long double");
+ tk = tk_real;
+ break;
+ case 'd':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "double");
+ tk = tk_real;
+ break;
+ case 'f':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "float");
+ tk = tk_real;
+ break;
+ case 'G':
+ (*mangled)++;
+ if (!ISDIGIT ((unsigned char)**mangled))
+ {
+ success = 0;
+ break;
+ }
+ case 'I':
+ (*mangled)++;
+ if (**mangled == '_')
+ {
+ int i;
+ (*mangled)++;
+ for (i = 0;
+ i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_';
+ (*mangled)++, i++)
+ buf[i] = **mangled;
+ if (**mangled != '_')
+ {
+ success = 0;
+ break;
+ }
+ buf[i] = '\0';
+ (*mangled)++;
+ }
+ else
+ {
+ strncpy (buf, *mangled, 2);
+ buf[2] = '\0';
+ *mangled += min (strlen (*mangled), 2);
+ }
+ sscanf (buf, "%x", &dec);
+ sprintf (buf, "int%u_t", dec);
+ APPEND_BLANK (result);
+ string_append (result, buf);
+ break;
+
+ /* fall through */
+ /* An explicit type, such as "6mytype" or "7integer" */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int bindex = register_Btype (work);
+ string btype;
+ string_init (&btype);
+ if (demangle_class_name (work, mangled, &btype)) {
+ remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
+ APPEND_BLANK (result);
+ string_appends (result, &btype);
+ }
+ else
+ success = 0;
+ string_delete (&btype);
+ break;
+ }
+ case 't':
+ {
+ string btype;
+ string_init (&btype);
+ success = demangle_template (work, mangled, &btype, 0, 1, 1);
+ string_appends (result, &btype);
+ string_delete (&btype);
+ break;
+ }
+ default:
+ success = 0;
+ break;
+ }
+
+ return success ? ((int) tk) : 0;
+}
+
+
+/* Handle a template's value parameter for HP aCC (extension from ARM)
+ **mangled points to 'S' or 'U' */
+
+static int
+do_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED,
+ const char **mangled, string *result)
+{
+ int unsigned_const;
+
+ if (**mangled != 'U' && **mangled != 'S')
+ return 0;
+
+ unsigned_const = (**mangled == 'U');
+
+ (*mangled)++;
+
+ switch (**mangled)
+ {
+ case 'N':
+ string_append (result, "-");
+ /* fall through */
+ case 'P':
+ (*mangled)++;
+ break;
+ case 'M':
+ /* special case for -2^31 */
+ string_append (result, "-2147483648");
+ (*mangled)++;
+ return 1;
+ default:
+ return 0;
+ }
+
+ /* We have to be looking at an integer now */
+ if (!(ISDIGIT ((unsigned char)**mangled)))
+ return 0;
+
+ /* We only deal with integral values for template
+ parameters -- so it's OK to look only for digits */
+ while (ISDIGIT ((unsigned char)**mangled))
+ {
+ char_str[0] = **mangled;
+ string_append (result, char_str);
+ (*mangled)++;
+ }
+
+ if (unsigned_const)
+ string_append (result, "U");
+
+ /* FIXME? Some day we may have 64-bit (or larger :-) ) constants
+ with L or LL suffixes. pai/1997-09-03 */
+
+ return 1; /* success */
+}
+
+/* Handle a template's literal parameter for HP aCC (extension from ARM)
+ **mangled is pointing to the 'A' */
+
+static int
+do_hpacc_template_literal (struct work_stuff *work, const char **mangled,
+ string *result)
+{
+ int literal_len = 0;
+ char * recurse;
+ char * recurse_dem;
+
+ if (**mangled != 'A')
+ return 0;
+
+ (*mangled)++;
+
+ literal_len = consume_count (mangled);
+
+ if (literal_len <= 0)
+ return 0;
+
+ /* Literal parameters are names of arrays, functions, etc. and the
+ canonical representation uses the address operator */
+ string_append (result, "&");
+
+ /* Now recursively demangle the literal name */
+ recurse = XNEWVEC (char, literal_len + 1);
+ memcpy (recurse, *mangled, literal_len);
+ recurse[literal_len] = '\000';
+
+ recurse_dem = cplus_demangle (recurse, work->options);
+
+ if (recurse_dem)
+ {
+ string_append (result, recurse_dem);
+ free (recurse_dem);
+ }
+ else
+ {
+ string_appendn (result, *mangled, literal_len);
+ }
+ (*mangled) += literal_len;
+ free (recurse);
+
+ return 1;
+}
+
+static int
+snarf_numeric_literal (const char **args, string *arg)
+{
+ if (**args == '-')
+ {
+ char_str[0] = '-';
+ string_append (arg, char_str);
+ (*args)++;
+ }
+ else if (**args == '+')
+ (*args)++;
+
+ if (!ISDIGIT ((unsigned char)**args))
+ return 0;
+
+ while (ISDIGIT ((unsigned char)**args))
+ {
+ char_str[0] = **args;
+ string_append (arg, char_str);
+ (*args)++;
+ }
+
+ return 1;
+}
+
+/* Demangle the next argument, given by MANGLED into RESULT, which
+ *should be an uninitialized* string. It will be initialized here,
+ and free'd should anything go wrong. */
+
+static int
+do_arg (struct work_stuff *work, const char **mangled, string *result)
+{
+ /* Remember where we started so that we can record the type, for
+ non-squangling type remembering. */
+ const char *start = *mangled;
+
+ string_init (result);
+
+ if (work->nrepeats > 0)
+ {
+ --work->nrepeats;
+
+ if (work->previous_argument == 0)
+ return 0;
+
+ /* We want to reissue the previous type in this argument list. */
+ string_appends (result, work->previous_argument);
+ return 1;
+ }
+
+ if (**mangled == 'n')
+ {
+ /* A squangling-style repeat. */
+ (*mangled)++;
+ work->nrepeats = consume_count(mangled);
+
+ if (work->nrepeats <= 0)
+ /* This was not a repeat count after all. */
+ return 0;
+
+ if (work->nrepeats > 9)
+ {
+ if (**mangled != '_')
+ /* The repeat count should be followed by an '_' in this
+ case. */
+ return 0;
+ else
+ (*mangled)++;
+ }
+
+ /* Now, the repeat is all set up. */
+ return do_arg (work, mangled, result);
+ }
+
+ /* Save the result in WORK->previous_argument so that we can find it
+ if it's repeated. Note that saving START is not good enough: we
+ do not want to add additional types to the back-referenceable
+ type vector when processing a repeated type. */
+ if (work->previous_argument)
+ string_delete (work->previous_argument);
+ else
+ work->previous_argument = XNEW (string);
+
+ if (!do_type (work, mangled, work->previous_argument))
+ return 0;
+
+ string_appends (result, work->previous_argument);
+
+ remember_type (work, start, *mangled - start);
+ return 1;
+}
+
+static void
+remember_type (struct work_stuff *work, const char *start, int len)
+{
+ char *tem;
+
+ if (work->forgetting_types)
+ return;
+
+ if (work -> ntypes >= work -> typevec_size)
+ {
+ if (work -> typevec_size == 0)
+ {
+ work -> typevec_size = 3;
+ work -> typevec = XNEWVEC (char *, work->typevec_size);
+ }
+ else
+ {
+ work -> typevec_size *= 2;
+ work -> typevec
+ = XRESIZEVEC (char *, work->typevec, work->typevec_size);
+ }
+ }
+ tem = XNEWVEC (char, len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ work -> typevec[work -> ntypes++] = tem;
+}
+
+
+/* Remember a K type class qualifier. */
+static void
+remember_Ktype (struct work_stuff *work, const char *start, int len)
+{
+ char *tem;
+
+ if (work -> numk >= work -> ksize)
+ {
+ if (work -> ksize == 0)
+ {
+ work -> ksize = 5;
+ work -> ktypevec = XNEWVEC (char *, work->ksize);
+ }
+ else
+ {
+ work -> ksize *= 2;
+ work -> ktypevec
+ = XRESIZEVEC (char *, work->ktypevec, work->ksize);
+ }
+ }
+ tem = XNEWVEC (char, len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ work -> ktypevec[work -> numk++] = tem;
+}
+
+/* Register a B code, and get an index for it. B codes are registered
+ as they are seen, rather than as they are completed, so map<temp<char> >
+ registers map<temp<char> > as B0, and temp<char> as B1 */
+
+static int
+register_Btype (struct work_stuff *work)
+{
+ int ret;
+
+ if (work -> numb >= work -> bsize)
+ {
+ if (work -> bsize == 0)
+ {
+ work -> bsize = 5;
+ work -> btypevec = XNEWVEC (char *, work->bsize);
+ }
+ else
+ {
+ work -> bsize *= 2;
+ work -> btypevec
+ = XRESIZEVEC (char *, work->btypevec, work->bsize);
+ }
+ }
+ ret = work -> numb++;
+ work -> btypevec[ret] = NULL;
+ return(ret);
+}
+
+/* Store a value into a previously registered B code type. */
+
+static void
+remember_Btype (struct work_stuff *work, const char *start,
+ int len, int index)
+{
+ char *tem;
+
+ tem = XNEWVEC (char, len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ work -> btypevec[index] = tem;
+}
+
+/* Lose all the info related to B and K type codes. */
+static void
+forget_B_and_K_types (struct work_stuff *work)
+{
+ int i;
+
+ while (work -> numk > 0)
+ {
+ i = --(work -> numk);
+ if (work -> ktypevec[i] != NULL)
+ {
+ free (work -> ktypevec[i]);
+ work -> ktypevec[i] = NULL;
+ }
+ }
+
+ while (work -> numb > 0)
+ {
+ i = --(work -> numb);
+ if (work -> btypevec[i] != NULL)
+ {
+ free (work -> btypevec[i]);
+ work -> btypevec[i] = NULL;
+ }
+ }
+}
+/* Forget the remembered types, but not the type vector itself. */
+
+static void
+forget_types (struct work_stuff *work)
+{
+ int i;
+
+ while (work -> ntypes > 0)
+ {
+ i = --(work -> ntypes);
+ if (work -> typevec[i] != NULL)
+ {
+ free (work -> typevec[i]);
+ work -> typevec[i] = NULL;
+ }
+ }
+}
+
+/* Process the argument list part of the signature, after any class spec
+ has been consumed, as well as the first 'F' character (if any). For
+ example:
+
+ "__als__3fooRT0" => process "RT0"
+ "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i"
+
+ DECLP must be already initialised, usually non-empty. It won't be freed
+ on failure.
+
+ Note that g++ differs significantly from ARM and lucid style mangling
+ with regards to references to previously seen types. For example, given
+ the source fragment:
+
+ class foo {
+ public:
+ foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
+ };
+
+ foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
+ void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
+
+ g++ produces the names:
+
+ __3fooiRT0iT2iT2
+ foo__FiR3fooiT1iT1
+
+ while lcc (and presumably other ARM style compilers as well) produces:
+
+ foo__FiR3fooT1T2T1T2
+ __ct__3fooFiR3fooT1T2T1T2
+
+ Note that g++ bases its type numbers starting at zero and counts all
+ previously seen types, while lucid/ARM bases its type numbers starting
+ at one and only considers types after it has seen the 'F' character
+ indicating the start of the function args. For lucid/ARM style, we
+ account for this difference by discarding any previously seen types when
+ we see the 'F' character, and subtracting one from the type number
+ reference.
+
+ */
+
+static int
+demangle_args (struct work_stuff *work, const char **mangled,
+ string *declp)
+{
+ string arg;
+ int need_comma = 0;
+ int r;
+ int t;
+ const char *tem;
+ char temptype;
+
+ if (PRINT_ARG_TYPES)
+ {
+ string_append (declp, "(");
+ if (**mangled == '\0')
+ {
+ string_append (declp, "void");
+ }
+ }
+
+ while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
+ || work->nrepeats > 0)
+ {
+ if ((**mangled == 'N') || (**mangled == 'T'))
+ {
+ temptype = *(*mangled)++;
+
+ if (temptype == 'N')
+ {
+ if (!get_count (mangled, &r))
+ {
+ return (0);
+ }
+ }
+ else
+ {
+ r = 1;
+ }
+ if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10)
+ {
+ /* If we have 10 or more types we might have more than a 1 digit
+ index so we'll have to consume the whole count here. This
+ will lose if the next thing is a type name preceded by a
+ count but it's impossible to demangle that case properly
+ anyway. Eg if we already have 12 types is T12Pc "(..., type1,
+ Pc, ...)" or "(..., type12, char *, ...)" */
+ if ((t = consume_count(mangled)) <= 0)
+ {
+ return (0);
+ }
+ }
+ else
+ {
+ if (!get_count (mangled, &t))
+ {
+ return (0);
+ }
+ }
+ if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
+ {
+ t--;
+ }
+ /* Validate the type index. Protect against illegal indices from
+ malformed type strings. */
+ if ((t < 0) || (t >= work -> ntypes))
+ {
+ return (0);
+ }
+ while (work->nrepeats > 0 || --r >= 0)
+ {
+ tem = work -> typevec[t];
+ if (need_comma && PRINT_ARG_TYPES)
+ {
+ string_append (declp, ", ");
+ }
+ if (!do_arg (work, &tem, &arg))
+ {
+ return (0);
+ }
+ if (PRINT_ARG_TYPES)
+ {
+ string_appends (declp, &arg);
+ }
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma && PRINT_ARG_TYPES)
+ string_append (declp, ", ");
+ if (!do_arg (work, mangled, &arg))
+ return (0);
+ if (PRINT_ARG_TYPES)
+ string_appends (declp, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+
+ if (**mangled == 'e')
+ {
+ (*mangled)++;
+ if (PRINT_ARG_TYPES)
+ {
+ if (need_comma)
+ {
+ string_append (declp, ",");
+ }
+ string_append (declp, "...");
+ }
+ }
+
+ if (PRINT_ARG_TYPES)
+ {
+ string_append (declp, ")");
+ }
+ return (1);
+}
+
+/* Like demangle_args, but for demangling the argument lists of function
+ and method pointers or references, not top-level declarations. */
+
+static int
+demangle_nested_args (struct work_stuff *work, const char **mangled,
+ string *declp)
+{
+ string* saved_previous_argument;
+ int result;
+ int saved_nrepeats;
+
+ /* The G++ name-mangling algorithm does not remember types on nested
+ argument lists, unless -fsquangling is used, and in that case the
+ type vector updated by remember_type is not used. So, we turn
+ off remembering of types here. */
+ ++work->forgetting_types;
+
+ /* For the repeat codes used with -fsquangling, we must keep track of
+ the last argument. */
+ saved_previous_argument = work->previous_argument;
+ saved_nrepeats = work->nrepeats;
+ work->previous_argument = 0;
+ work->nrepeats = 0;
+
+ /* Actually demangle the arguments. */
+ result = demangle_args (work, mangled, declp);
+
+ /* Restore the previous_argument field. */
+ if (work->previous_argument)
+ {
+ string_delete (work->previous_argument);
+ free ((char *) work->previous_argument);
+ }
+ work->previous_argument = saved_previous_argument;
+ --work->forgetting_types;
+ work->nrepeats = saved_nrepeats;
+
+ return result;
+}
+
+/* Returns 1 if a valid function name was found or 0 otherwise. */
+
+static int
+demangle_function_name (struct work_stuff *work, const char **mangled,
+ string *declp, const char *scan)
+{
+ size_t i;
+ string type;
+ const char *tem;
+
+ string_appendn (declp, (*mangled), scan - (*mangled));
+ string_need (declp, 1);
+ *(declp -> p) = '\0';
+
+ /* Consume the function name, including the "__" separating the name
+ from the signature. We are guaranteed that SCAN points to the
+ separator. */
+
+ (*mangled) = scan + 2;
+ /* We may be looking at an instantiation of a template function:
+ foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a
+ following _F marks the start of the function arguments. Handle
+ the template arguments first. */
+
+ if (HP_DEMANGLING && (**mangled == 'X'))
+ {
+ demangle_arm_hp_template (work, mangled, 0, declp);
+ /* This leaves MANGLED pointing to the 'F' marking func args */
+ }
+
+ if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
+ {
+
+ /* See if we have an ARM style constructor or destructor operator.
+ If so, then just record it, clear the decl, and return.
+ We can't build the actual constructor/destructor decl until later,
+ when we recover the class name from the signature. */
+
+ if (strcmp (declp -> b, "__ct") == 0)
+ {
+ work -> constructor += 1;
+ string_clear (declp);
+ return 1;
+ }
+ else if (strcmp (declp -> b, "__dt") == 0)
+ {
+ work -> destructor += 1;
+ string_clear (declp);
+ return 1;
+ }
+ }
+
+ if (declp->p - declp->b >= 3
+ && declp->b[0] == 'o'
+ && declp->b[1] == 'p'
+ && strchr (cplus_markers, declp->b[2]) != NULL)
+ {
+ /* see if it's an assignment expression */
+ if (declp->p - declp->b >= 10 /* op$assign_ */
+ && memcmp (declp->b + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ int len = declp->p - declp->b - 10;
+ if ((int) strlen (optable[i].in) == len
+ && memcmp (optable[i].in, declp->b + 10, len) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ string_append (declp, "=");
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ int len = declp->p - declp->b - 3;
+ if ((int) strlen (optable[i].in) == len
+ && memcmp (optable[i].in, declp->b + 3, len) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ }
+ else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
+ && strchr (cplus_markers, declp->b[4]) != NULL)
+ {
+ /* type conversion operator */
+ tem = declp->b + 5;
+ if (do_type (work, &tem, &type))
+ {
+ string_clear (declp);
+ string_append (declp, "operator ");
+ string_appends (declp, &type);
+ string_delete (&type);
+ }
+ }
+ else if (declp->b[0] == '_' && declp->b[1] == '_'
+ && declp->b[2] == 'o' && declp->b[3] == 'p')
+ {
+ /* ANSI. */
+ /* type conversion operator. */
+ tem = declp->b + 4;
+ if (do_type (work, &tem, &type))
+ {
+ string_clear (declp);
+ string_append (declp, "operator ");
+ string_appends (declp, &type);
+ string_delete (&type);
+ }
+ }
+ else if (declp->b[0] == '_' && declp->b[1] == '_'
+ && ISLOWER((unsigned char)declp->b[2])
+ && ISLOWER((unsigned char)declp->b[3]))
+ {
+ if (declp->b[4] == '\0')
+ {
+ /* Operator. */
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ if (strlen (optable[i].in) == 2
+ && memcmp (optable[i].in, declp->b + 2, 2) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (declp->b[2] == 'a' && declp->b[5] == '\0')
+ {
+ /* Assignment. */
+ for (i = 0; i < ARRAY_SIZE (optable); i++)
+ {
+ if (strlen (optable[i].in) == 3
+ && memcmp (optable[i].in, declp->b + 2, 3) == 0)
+ {
+ string_clear (declp);
+ string_append (declp, "operator");
+ string_append (declp, optable[i].out);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* If a function name was obtained but it's not valid, we were not
+ successful. */
+ if (LEN_STRING (declp) == 1 && declp->b[0] == '.')
+ return 0;
+ else
+ return 1;
+}
+
+/* a mini string-handling package */
+
+static void
+string_need (string *s, int n)
+{
+ int tem;
+
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ {
+ n = 32;
+ }
+ s->p = s->b = XNEWVEC (char, n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = XRESIZEVEC (char, s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+string_delete (string *s)
+{
+ if (s->b != NULL)
+ {
+ free (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+string_init (string *s)
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static void
+string_clear (string *s)
+{
+ s->p = s->b;
+}
+
+#if 0
+
+static int
+string_empty (string *s)
+{
+ return (s->b == s->p);
+}
+
+#endif
+
+static void
+string_append (string *p, const char *s)
+{
+ int n;
+ if (s == NULL || *s == '\0')
+ return;
+ n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_appends (string *p, string *s)
+{
+ int n;
+
+ if (s->b != s->p)
+ {
+ n = s->p - s->b;
+ string_need (p, n);
+ memcpy (p->p, s->b, n);
+ p->p += n;
+ }
+}
+
+static void
+string_appendn (string *p, const char *s, int n)
+{
+ if (n != 0)
+ {
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+ }
+}
+
+static void
+string_prepend (string *p, const char *s)
+{
+ if (s != NULL && *s != '\0')
+ {
+ string_prependn (p, s, strlen (s));
+ }
+}
+
+static void
+string_prepends (string *p, string *s)
+{
+ if (s->b != s->p)
+ {
+ string_prependn (p, s->b, s->p - s->b);
+ }
+}
+
+static void
+string_prependn (string *p, const char *s, int n)
+{
+ char *q;
+
+ if (n != 0)
+ {
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ {
+ q[n] = q[0];
+ }
+ memcpy (p->b, s, n);
+ p->p += n;
+ }
+}
+
+static void
+string_append_template_idx (string *s, int idx)
+{
+ char buf[INTBUF_SIZE + 1 /* 'T' */];
+ sprintf(buf, "T%d", idx);
+ string_append (s, buf);
+}
diff --git a/linkers/libiberty/demangle.h b/linkers/libiberty/demangle.h
new file mode 100644
index 0000000..4b3565b
--- /dev/null
+++ b/linkers/libiberty/demangle.h
@@ -0,0 +1,616 @@
+/* Defs for interface to demanglers.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002,
+ 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2, or
+ (at your option) any later version.
+
+ In addition to the permissions in the GNU Library General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file into
+ combinations with other programs, and to distribute those
+ combinations without any restriction coming from the use of this
+ file. (The Library Public License restrictions do apply in other
+ respects; for example, they cover modification of the file, and
+ distribution when not linked into a combined executable.)
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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. */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#include "libiberty.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
+#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
+#define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when
+ present) after function signature */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+#define DMGL_HP (1 << 12) /* For the HP aCC compiler;
+ same as ARM except for
+ template arguments, etc. */
+#define DMGL_EDG (1 << 13)
+#define DMGL_GNU_V3 (1 << 14)
+#define DMGL_GNAT (1 << 15)
+
+/* If none of these are set, use 'current_demangling_style' as the default. */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT)
+
+/* Enumeration of possible demangling styles.
+
+ Lucid and ARM styles are still kept logically distinct, even though
+ they now both behave identically. The resulting style is actual the
+ union of both. I.E. either style recognizes both "__pt__" and "__rf__"
+ for operator "->", even though the first is lucid style and the second
+ is ARM style. (FIXME?) */
+
+extern enum demangling_styles
+{
+ no_demangling = -1,
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM,
+ hp_demangling = DMGL_HP,
+ edg_demangling = DMGL_EDG,
+ gnu_v3_demangling = DMGL_GNU_V3,
+ java_demangling = DMGL_JAVA,
+ gnat_demangling = DMGL_GNAT
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define NO_DEMANGLING_STYLE_STRING "none"
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+#define HP_DEMANGLING_STYLE_STRING "hp"
+#define EDG_DEMANGLING_STYLE_STRING "edg"
+#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3"
+#define JAVA_DEMANGLING_STYLE_STRING "java"
+#define GNAT_DEMANGLING_STYLE_STRING "gnat"
+
+/* Some macros to test what demangling style is active. */
+
+#define CURRENT_DEMANGLING_STYLE current_demangling_style
+#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
+#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
+#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
+#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM)
+#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP)
+#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG)
+#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
+#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
+#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
+
+/* Provide information about the available demangle styles. This code is
+ pulled from gdb into libiberty because it is useful to binutils also. */
+
+extern const struct demangler_engine
+{
+ const char *const demangling_style_name;
+ const enum demangling_styles demangling_style;
+ const char *const demangling_style_doc;
+} libiberty_demanglers[];
+
+extern char *
+cplus_demangle (const char *mangled, int options);
+
+extern int
+cplus_demangle_opname (const char *opname, char *result, int options);
+
+extern const char *
+cplus_mangle_opname (const char *opname, int options);
+
+/* Note: This sets global state. FIXME if you care about multi-threading. */
+
+extern void
+set_cplus_marker_for_demangling (int ch);
+
+extern enum demangling_styles
+cplus_demangle_set_style (enum demangling_styles style);
+
+extern enum demangling_styles
+cplus_demangle_name_to_style (const char *name);
+
+/* Callback typedef for allocation-less demangler interfaces. */
+typedef void (*demangle_callbackref) (const char *, size_t, void *);
+
+/* V3 ABI demangling entry points, defined in cp-demangle.c. Callback
+ variants return non-zero on success, zero on error. char* variants
+ return a string allocated by malloc on success, NULL on error. */
+extern int
+cplus_demangle_v3_callback (const char *mangled, int options,
+ demangle_callbackref callback, void *opaque);
+
+extern char*
+cplus_demangle_v3 (const char *mangled, int options);
+
+extern int
+java_demangle_v3_callback (const char *mangled,
+ demangle_callbackref callback, void *opaque);
+
+extern char*
+java_demangle_v3 (const char *mangled);
+
+enum gnu_v3_ctor_kinds {
+ gnu_v3_complete_object_ctor = 1,
+ gnu_v3_base_object_ctor,
+ gnu_v3_complete_object_allocating_ctor
+};
+
+/* Return non-zero iff NAME is the mangled form of a constructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_ctor_kinds' value indicating what kind of constructor
+ it is. */
+extern enum gnu_v3_ctor_kinds
+ is_gnu_v3_mangled_ctor (const char *name);
+
+
+enum gnu_v3_dtor_kinds {
+ gnu_v3_deleting_dtor = 1,
+ gnu_v3_complete_object_dtor,
+ gnu_v3_base_object_dtor
+};
+
+/* Return non-zero iff NAME is the mangled form of a destructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_dtor_kinds' value, indicating what kind of destructor
+ it is. */
+extern enum gnu_v3_dtor_kinds
+ is_gnu_v3_mangled_dtor (const char *name);
+
+/* The V3 demangler works in two passes. The first pass builds a tree
+ representation of the mangled name, and the second pass turns the
+ tree representation into a demangled string. Here we define an
+ interface to permit a caller to build their own tree
+ representation, which they can pass to the demangler to get a
+ demangled string. This can be used to canonicalize user input into
+ something which the demangler might output. It could also be used
+ by other demanglers in the future. */
+
+/* These are the component types which may be found in the tree. Many
+ component types have one or two subtrees, referred to as left and
+ right (a component type with only one subtree puts it in the left
+ subtree). */
+
+enum demangle_component_type
+{
+ /* A name, with a length and a pointer to a string. */
+ DEMANGLE_COMPONENT_NAME,
+ /* A qualified name. The left subtree is a class or namespace or
+ some such thing, and the right subtree is a name qualified by
+ that class. */
+ DEMANGLE_COMPONENT_QUAL_NAME,
+ /* A local name. The left subtree describes a function, and the
+ right subtree is a name which is local to that function. */
+ DEMANGLE_COMPONENT_LOCAL_NAME,
+ /* A typed name. The left subtree is a name, and the right subtree
+ describes that name as a function. */
+ DEMANGLE_COMPONENT_TYPED_NAME,
+ /* A template. The left subtree is a template name, and the right
+ subtree is a template argument list. */
+ DEMANGLE_COMPONENT_TEMPLATE,
+ /* A template parameter. This holds a number, which is the template
+ parameter index. */
+ DEMANGLE_COMPONENT_TEMPLATE_PARAM,
+ /* A function parameter. This holds a number, which is the index. */
+ DEMANGLE_COMPONENT_FUNCTION_PARAM,
+ /* A constructor. This holds a name and the kind of
+ constructor. */
+ DEMANGLE_COMPONENT_CTOR,
+ /* A destructor. This holds a name and the kind of destructor. */
+ DEMANGLE_COMPONENT_DTOR,
+ /* A vtable. This has one subtree, the type for which this is a
+ vtable. */
+ DEMANGLE_COMPONENT_VTABLE,
+ /* A VTT structure. This has one subtree, the type for which this
+ is a VTT. */
+ DEMANGLE_COMPONENT_VTT,
+ /* A construction vtable. The left subtree is the type for which
+ this is a vtable, and the right subtree is the derived type for
+ which this vtable is built. */
+ DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
+ /* A typeinfo structure. This has one subtree, the type for which
+ this is the tpeinfo structure. */
+ DEMANGLE_COMPONENT_TYPEINFO,
+ /* A typeinfo name. This has one subtree, the type for which this
+ is the typeinfo name. */
+ DEMANGLE_COMPONENT_TYPEINFO_NAME,
+ /* A typeinfo function. This has one subtree, the type for which
+ this is the tpyeinfo function. */
+ DEMANGLE_COMPONENT_TYPEINFO_FN,
+ /* A thunk. This has one subtree, the name for which this is a
+ thunk. */
+ DEMANGLE_COMPONENT_THUNK,
+ /* A virtual thunk. This has one subtree, the name for which this
+ is a virtual thunk. */
+ DEMANGLE_COMPONENT_VIRTUAL_THUNK,
+ /* A covariant thunk. This has one subtree, the name for which this
+ is a covariant thunk. */
+ DEMANGLE_COMPONENT_COVARIANT_THUNK,
+ /* A Java class. This has one subtree, the type. */
+ DEMANGLE_COMPONENT_JAVA_CLASS,
+ /* A guard variable. This has one subtree, the name for which this
+ is a guard variable. */
+ DEMANGLE_COMPONENT_GUARD,
+ /* A reference temporary. This has one subtree, the name for which
+ this is a temporary. */
+ DEMANGLE_COMPONENT_REFTEMP,
+ /* A hidden alias. This has one subtree, the encoding for which it
+ is providing alternative linkage. */
+ DEMANGLE_COMPONENT_HIDDEN_ALIAS,
+ /* A standard substitution. This holds the name of the
+ substitution. */
+ DEMANGLE_COMPONENT_SUB_STD,
+ /* The restrict qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT,
+ /* The volatile qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE,
+ /* The const qualifier. The one subtree is the type which is being
+ qualified. */
+ DEMANGLE_COMPONENT_CONST,
+ /* The restrict qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT_THIS,
+ /* The volatile qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE_THIS,
+ /* The const qualifier modifying a member function. The one subtree
+ is the type which is being qualified. */
+ DEMANGLE_COMPONENT_CONST_THIS,
+ /* A vendor qualifier. The left subtree is the type which is being
+ qualified, and the right subtree is the name of the
+ qualifier. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ /* A pointer. The one subtree is the type which is being pointed
+ to. */
+ DEMANGLE_COMPONENT_POINTER,
+ /* A reference. The one subtree is the type which is being
+ referenced. */
+ DEMANGLE_COMPONENT_REFERENCE,
+ /* C++0x: An rvalue reference. The one subtree is the type which is
+ being referenced. */
+ DEMANGLE_COMPONENT_RVALUE_REFERENCE,
+ /* A complex type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_COMPLEX,
+ /* An imaginary type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_IMAGINARY,
+ /* A builtin type. This holds the builtin type information. */
+ DEMANGLE_COMPONENT_BUILTIN_TYPE,
+ /* A vendor's builtin type. This holds the name of the type. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE,
+ /* A function type. The left subtree is the return type. The right
+ subtree is a list of ARGLIST nodes. Either or both may be
+ NULL. */
+ DEMANGLE_COMPONENT_FUNCTION_TYPE,
+ /* An array type. The left subtree is the dimension, which may be
+ NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an
+ expression. The right subtree is the element type. */
+ DEMANGLE_COMPONENT_ARRAY_TYPE,
+ /* A pointer to member type. The left subtree is the class type,
+ and the right subtree is the member type. CV-qualifiers appear
+ on the latter. */
+ DEMANGLE_COMPONENT_PTRMEM_TYPE,
+ /* A fixed-point type. */
+ DEMANGLE_COMPONENT_FIXED_TYPE,
+ /* An argument list. The left subtree is the current argument, and
+ the right subtree is either NULL or another ARGLIST node. */
+ DEMANGLE_COMPONENT_ARGLIST,
+ /* A template argument list. The left subtree is the current
+ template argument, and the right subtree is either NULL or
+ another TEMPLATE_ARGLIST node. */
+ DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
+ /* An operator. This holds information about a standard
+ operator. */
+ DEMANGLE_COMPONENT_OPERATOR,
+ /* An extended operator. This holds the number of arguments, and
+ the name of the extended operator. */
+ DEMANGLE_COMPONENT_EXTENDED_OPERATOR,
+ /* A typecast, represented as a unary operator. The one subtree is
+ the type to which the argument should be cast. */
+ DEMANGLE_COMPONENT_CAST,
+ /* A unary expression. The left subtree is the operator, and the
+ right subtree is the single argument. */
+ DEMANGLE_COMPONENT_UNARY,
+ /* A binary expression. The left subtree is the operator, and the
+ right subtree is a BINARY_ARGS. */
+ DEMANGLE_COMPONENT_BINARY,
+ /* Arguments to a binary expression. The left subtree is the first
+ argument, and the right subtree is the second argument. */
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ /* A trinary expression. The left subtree is the operator, and the
+ right subtree is a TRINARY_ARG1. */
+ DEMANGLE_COMPONENT_TRINARY,
+ /* Arguments to a trinary expression. The left subtree is the first
+ argument, and the right subtree is a TRINARY_ARG2. */
+ DEMANGLE_COMPONENT_TRINARY_ARG1,
+ /* More arguments to a trinary expression. The left subtree is the
+ second argument, and the right subtree is the third argument. */
+ DEMANGLE_COMPONENT_TRINARY_ARG2,
+ /* A literal. The left subtree is the type, and the right subtree
+ is the value, represented as a DEMANGLE_COMPONENT_NAME. */
+ DEMANGLE_COMPONENT_LITERAL,
+ /* A negative literal. Like LITERAL, but the value is negated.
+ This is a minor hack: the NAME used for LITERAL points directly
+ to the mangled string, but since negative numbers are mangled
+ using 'n' instead of '-', we want a way to indicate a negative
+ number which involves neither modifying the mangled string nor
+ allocating a new copy of the literal in memory. */
+ DEMANGLE_COMPONENT_LITERAL_NEG,
+ /* A libgcj compiled resource. The left subtree is the name of the
+ resource. */
+ DEMANGLE_COMPONENT_JAVA_RESOURCE,
+ /* A name formed by the concatenation of two parts. The left
+ subtree is the first part and the right subtree the second. */
+ DEMANGLE_COMPONENT_COMPOUND_NAME,
+ /* A name formed by a single character. */
+ DEMANGLE_COMPONENT_CHARACTER,
+ /* A decltype type. */
+ DEMANGLE_COMPONENT_DECLTYPE,
+ /* Global constructors keyed to name. */
+ DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS,
+ /* Global destructors keyed to name. */
+ DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS,
+ /* A pack expansion. */
+ DEMANGLE_COMPONENT_PACK_EXPANSION
+};
+
+/* Types which are only used internally. */
+
+struct demangle_operator_info;
+struct demangle_builtin_type_info;
+
+/* A node in the tree representation is an instance of a struct
+ demangle_component. Note that the field names of the struct are
+ not well protected against macros defined by the file including
+ this one. We can fix this if it ever becomes a problem. */
+
+struct demangle_component
+{
+ /* The type of this component. */
+ enum demangle_component_type type;
+
+ union
+ {
+ /* For DEMANGLE_COMPONENT_NAME. */
+ struct
+ {
+ /* A pointer to the name (which need not NULL terminated) and
+ its length. */
+ const char *s;
+ int len;
+ } s_name;
+
+ /* For DEMANGLE_COMPONENT_OPERATOR. */
+ struct
+ {
+ /* Operator. */
+ const struct demangle_operator_info *op;
+ } s_operator;
+
+ /* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
+ struct
+ {
+ /* Number of arguments. */
+ int args;
+ /* Name. */
+ struct demangle_component *name;
+ } s_extended_operator;
+
+ /* For DEMANGLE_COMPONENT_FIXED_TYPE. */
+ struct
+ {
+ /* The length, indicated by a C integer type name. */
+ struct demangle_component *length;
+ /* _Accum or _Fract? */
+ short accum;
+ /* Saturating or not? */
+ short sat;
+ } s_fixed;
+
+ /* For DEMANGLE_COMPONENT_CTOR. */
+ struct
+ {
+ /* Kind of constructor. */
+ enum gnu_v3_ctor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_ctor;
+
+ /* For DEMANGLE_COMPONENT_DTOR. */
+ struct
+ {
+ /* Kind of destructor. */
+ enum gnu_v3_dtor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_dtor;
+
+ /* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */
+ struct
+ {
+ /* Builtin type. */
+ const struct demangle_builtin_type_info *type;
+ } s_builtin;
+
+ /* For DEMANGLE_COMPONENT_SUB_STD. */
+ struct
+ {
+ /* Standard substitution string. */
+ const char* string;
+ /* Length of string. */
+ int len;
+ } s_string;
+
+ /* For DEMANGLE_COMPONENT_*_PARAM. */
+ struct
+ {
+ /* Parameter index. */
+ long number;
+ } s_number;
+
+ /* For DEMANGLE_COMPONENT_CHARACTER. */
+ struct
+ {
+ int character;
+ } s_character;
+
+ /* For other types. */
+ struct
+ {
+ /* Left (or only) subtree. */
+ struct demangle_component *left;
+ /* Right subtree. */
+ struct demangle_component *right;
+ } s_binary;
+
+ } u;
+};
+
+/* People building mangled trees are expected to allocate instances of
+ struct demangle_component themselves. They can then call one of
+ the following functions to fill them in. */
+
+/* Fill in most component types with a left subtree and a right
+ subtree. Returns non-zero on success, zero on failure, such as an
+ unrecognized or inappropriate component type. */
+
+extern int
+cplus_demangle_fill_component (struct demangle_component *fill,
+ enum demangle_component_type,
+ struct demangle_component *left,
+ struct demangle_component *right);
+
+/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_name (struct demangle_component *fill,
+ const char *, int);
+
+/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the
+ builtin type (e.g., "int", etc.). Returns non-zero on success,
+ zero if the type is not recognized. */
+
+extern int
+cplus_demangle_fill_builtin_type (struct demangle_component *fill,
+ const char *type_name);
+
+/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the
+ operator and the number of arguments which it takes (the latter is
+ used to disambiguate operators which can be both binary and unary,
+ such as '-'). Returns non-zero on success, zero if the operator is
+ not recognized. */
+
+extern int
+cplus_demangle_fill_operator (struct demangle_component *fill,
+ const char *opname, int args);
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the
+ number of arguments and the name. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_extended_operator (struct demangle_component *fill,
+ int numargs,
+ struct demangle_component *nm);
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_ctor (struct demangle_component *fill,
+ enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name);
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_dtor (struct demangle_component *fill,
+ enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name);
+
+/* This function translates a mangled name into a struct
+ demangle_component tree. The first argument is the mangled name.
+ The second argument is DMGL_* options. This returns a pointer to a
+ tree on success, or NULL on failure. On success, the third
+ argument is set to a block of memory allocated by malloc. This
+ block should be passed to free when the tree is no longer
+ needed. */
+
+extern struct demangle_component *
+cplus_demangle_v3_components (const char *mangled, int options, void **mem);
+
+/* This function takes a struct demangle_component tree and returns
+ the corresponding demangled string. The first argument is DMGL_*
+ options. The second is the tree to demangle. The third is a guess
+ at the length of the demangled string, used to initially allocate
+ the return buffer. The fourth is a pointer to a size_t. On
+ success, this function returns a buffer allocated by malloc(), and
+ sets the size_t pointed to by the fourth argument to the size of
+ the allocated buffer (not the length of the returned string). On
+ failure, this function returns NULL, and sets the size_t pointed to
+ by the fourth argument to 0 for an invalid tree, or to 1 for a
+ memory allocation error. */
+
+extern char *
+cplus_demangle_print (int options,
+ const struct demangle_component *tree,
+ int estimated_length,
+ size_t *p_allocated_size);
+
+/* This function takes a struct demangle_component tree and passes back
+ a demangled string in one or more calls to a callback function.
+ The first argument is DMGL_* options. The second is the tree to
+ demangle. The third is a pointer to a callback function; on each call
+ this receives an element of the demangled string, its length, and an
+ opaque value. The fourth is the opaque value passed to the callback.
+ The callback is called once or more to return the full demangled
+ string. The demangled element string is always nul-terminated, though
+ its length is also provided for convenience. In contrast to
+ cplus_demangle_print(), this function does not allocate heap memory
+ to grow output strings (except perhaps where alloca() is implemented
+ by malloc()), and so is normally safe for use where the heap has been
+ corrupted. On success, this function returns 1; on failure, 0. */
+
+extern int
+cplus_demangle_print_callback (int options,
+ const struct demangle_component *tree,
+ demangle_callbackref callback, void *opaque);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* DEMANGLE_H */
diff --git a/linkers/libiberty/libiberty.h b/linkers/libiberty/libiberty.h
new file mode 100644
index 0000000..d2dfb1b
--- /dev/null
+++ b/linkers/libiberty/libiberty.h
@@ -0,0 +1,342 @@
+/* Function declarations for libiberty.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+ Note - certain prototypes declared in this header file are for
+ functions whoes implementation copyright does not belong to the
+ FSF. Those prototypes are present in this file for reference
+ purposes only and their presence in this file should not construed
+ as an indication of ownership by the FSF of the implementation of
+ those functions in any way or form whatsoever.
+
+ This program 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, 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.
+
+ Written by Cygnus Support, 1994.
+
+ The libiberty library provides a number of functions which are
+ missing on some operating systems. We do not declare those here,
+ to avoid conflicts with the system header files on operating
+ systems that do support those functions. In this file we only
+ declare those functions which are specific to libiberty.
+
+ Hacked up libiberty.h file from the real one.
+*/
+
+#if !defined (_LIBIERTY_H_)
+#define _LIBIERTY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ansidecl.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+#define xstrdup strdup
+#define xstrerror strerror
+
+/* These macros provide a K&R/C89/C++-friendly way of allocating structures
+ with nice encapsulation. The XDELETE*() macros are technically
+ superfluous, but provided here for symmetry. Using them consistently
+ makes it easier to update client code to use different allocators such
+ as new/delete and new[]/delete[]. */
+
+/* Scalar allocators. */
+
+#define XALLOCA(T) ((T *) alloca (sizeof (T)))
+#define XNEW(T) ((T *) malloc (sizeof (T)))
+#define XCNEW(T) ((T *) calloc (1, sizeof (T)))
+#define XDUP(T, P) ((T *) memdup ((P), sizeof (T), sizeof (T)))
+#define XDELETE(P) free ((void*) (P))
+
+/* Array allocators. */
+
+#define XALLOCAVEC(T, N) ((T *) alloca (sizeof (T) * (N)))
+#define XNEWVEC(T, N) ((T *) malloc (sizeof (T) * (N)))
+#define XCNEWVEC(T, N) ((T *) calloc ((N), sizeof (T)))
+#define XDUPVEC(T, P, N) ((T *) memdup ((P), sizeof (T) * (N), sizeof (T) * (N)))
+#define XRESIZEVEC(T, P, N) ((T *) realloc ((void *) (P), sizeof (T) * (N)))
+#define XDELETEVEC(P) free ((void*) (P))
+
+/* Allocators for variable-sized structures and raw buffers. */
+
+#define XALLOCAVAR(T, S) ((T *) alloca ((S)))
+#define XNEWVAR(T, S) ((T *) malloc ((S)))
+#define XCNEWVAR(T, S) ((T *) calloc (1, (S)))
+#define XDUPVAR(T, P, S1, S2) ((T *) memdup ((P), (S1), (S2)))
+#define XRESIZEVAR(T, P, S) ((T *) realloc ((P), (S)))
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. */
+
+extern char *concat (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_SENTINEL;
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. The first argument is
+ not one of the strings to be concatenated, but if not NULL is a
+ pointer to be freed after the new string is created, similar to the
+ way xrealloc works. */
+
+extern char *reconcat (char *, const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_SENTINEL;
+
+/* Determine the length of concatenating an arbitrary number of
+ strings. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. */
+
+extern unsigned long concat_length (const char *, ...) ATTRIBUTE_SENTINEL;
+
+/* Concatenate an arbitrary number of strings into a SUPPLIED area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy (char *, const char *, ...) ATTRIBUTE_SENTINEL;
+
+/* Concatenate an arbitrary number of strings into a GLOBAL area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy2 (const char *, ...) ATTRIBUTE_SENTINEL;
+
+/* This is the global area used by concat_copy2. */
+
+extern char *libiberty_concat_ptr;
+
+/* Return a temporary file name or NULL if unable to create one. */
+
+extern char *make_temp_file (const char *) ATTRIBUTE_MALLOC;
+
+/* Flags for pex_init. These are bits to be or'ed together. */
+
+/* Record subprocess times, if possible. */
+#define PEX_RECORD_TIMES 0x1
+
+/* Use pipes for communication between processes, if possible. */
+#define PEX_USE_PIPES 0x2
+
+/* Save files used for communication between processes. */
+#define PEX_SAVE_TEMPS 0x4
+
+/* Prepare to execute one or more programs, with standard output of
+ each program fed to standard input of the next.
+ FLAGS As above.
+ PNAME The name of the program to report in error messages.
+ TEMPBASE A base name to use for temporary files; may be NULL to
+ use a random name.
+ Returns NULL on error. */
+
+extern struct pex_obj *pex_init (int flags, const char *pname,
+ const char *tempbase);
+
+/* Flags for pex_run. These are bits to be or'ed together. */
+
+/* Last program in pipeline. Standard output of program goes to
+ OUTNAME, or, if OUTNAME is NULL, to standard output of caller. Do
+ not set this if you want to call pex_read_output. After this is
+ set, pex_run may no longer be called with the same struct
+ pex_obj. */
+#define PEX_LAST 0x1
+
+/* Search for program in executable search path. */
+#define PEX_SEARCH 0x2
+
+/* OUTNAME is a suffix. */
+#define PEX_SUFFIX 0x4
+
+/* Send program's standard error to standard output. */
+#define PEX_STDERR_TO_STDOUT 0x8
+
+/* Input file should be opened in binary mode. This flag is ignored
+ on Unix. */
+#define PEX_BINARY_INPUT 0x10
+
+/* Output file should be opened in binary mode. This flag is ignored
+ on Unix. For proper behaviour PEX_BINARY_INPUT and
+ PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using
+ PEX_BINARY_OUTPUT should be followed by a call using
+ PEX_BINARY_INPUT. */
+#define PEX_BINARY_OUTPUT 0x20
+
+/* Capture stderr to a pipe. The output can be read by
+ calling pex_read_err and reading from the returned
+ FILE object. This flag may be specified only for
+ the last program in a pipeline.
+
+ This flag is supported only on Unix and Windows. */
+#define PEX_STDERR_TO_PIPE 0x40
+
+/* Capture stderr in binary mode. This flag is ignored
+ on Unix. */
+#define PEX_BINARY_ERROR 0x80
+
+
+/* Execute one program. Returns NULL on success. On error returns an
+ error string (typically just the name of a system call); the error
+ string is statically allocated.
+
+ OBJ Returned by pex_init.
+
+ FLAGS As above.
+
+ EXECUTABLE The program to execute.
+
+ ARGV NULL terminated array of arguments to pass to the program.
+
+ OUTNAME Sets the output file name as follows:
+
+ PEX_SUFFIX set (OUTNAME may not be NULL):
+ TEMPBASE parameter to pex_init not NULL:
+ Output file name is the concatenation of TEMPBASE
+ and OUTNAME.
+ TEMPBASE is NULL:
+ Output file name is a random file name ending in
+ OUTNAME.
+ PEX_SUFFIX not set:
+ OUTNAME not NULL:
+ Output file name is OUTNAME.
+ OUTNAME NULL, TEMPBASE not NULL:
+ Output file name is randomly chosen using
+ TEMPBASE.
+ OUTNAME NULL, TEMPBASE NULL:
+ Output file name is randomly chosen.
+
+ If PEX_LAST is not set, the output file name is the
+ name to use for a temporary file holding stdout, if
+ any (there will not be a file if PEX_USE_PIPES is set
+ and the system supports pipes). If a file is used, it
+ will be removed when no longer needed unless
+ PEX_SAVE_TEMPS is set.
+
+ If PEX_LAST is set, and OUTNAME is not NULL, standard
+ output is written to the output file name. The file
+ will not be removed. If PEX_LAST and PEX_SUFFIX are
+ both set, TEMPBASE may not be NULL.
+
+ ERRNAME If not NULL, this is the name of a file to which
+ standard error is written. If NULL, standard error of
+ the program is standard error of the caller.
+
+ ERR On an error return, *ERR is set to an errno value, or
+ to 0 if there is no relevant errno.
+*/
+
+extern const char *pex_run (struct pex_obj *obj, int flags,
+ const char *executable, char * const *argv,
+ const char *outname, const char *errname,
+ int *err);
+
+/* As for pex_run (), but takes an extra parameter to enable the
+ environment for the child process to be specified.
+
+ ENV The environment for the child process, specified as
+ an array of character pointers. Each element of the
+ array should point to a string of the form VAR=VALUE,
+ with the exception of the last element which must be
+ a null pointer.
+*/
+
+extern const char *pex_run_in_environment (struct pex_obj *obj, int flags,
+ const char *executable,
+ char * const *argv,
+ char * const *env,
+ const char *outname,
+ const char *errname, int *err);
+
+/* Return a stream for a temporary file to pass to the first program
+ in the pipeline as input. The file name is chosen as for pex_run.
+ pex_run closes the file automatically; don't close it yourself. */
+
+extern FILE *pex_input_file (struct pex_obj *obj, int flags,
+ const char *in_name);
+
+/* Return a stream for a pipe connected to the standard input of the
+ first program in the pipeline. You must have passed
+ `PEX_USE_PIPES' to `pex_init'. Close the returned stream
+ yourself. */
+
+extern FILE *pex_input_pipe (struct pex_obj *obj, int binary);
+
+/* Read the standard output of the last program to be executed.
+ pex_run can not be called after this. BINARY should be non-zero if
+ the file should be opened in binary mode; this is ignored on Unix.
+ Returns NULL on error. Don't call fclose on the returned FILE; it
+ will be closed by pex_free. */
+
+extern FILE *pex_read_output (struct pex_obj *, int binary);
+
+/* Read the standard error of the last program to be executed.
+ pex_run can not be called after this. BINARY should be non-zero if
+ the file should be opened in binary mode; this is ignored on Unix.
+ Returns NULL on error. Don't call fclose on the returned FILE; it
+ will be closed by pex_free. */
+
+extern FILE *pex_read_err (struct pex_obj *, int binary);
+
+/* Return exit status of all programs in VECTOR. COUNT indicates the
+ size of VECTOR. The status codes in the vector are in the order of
+ the calls to pex_run. Returns 0 on error, 1 on success. */
+
+extern int pex_get_status (struct pex_obj *, int count, int *vector);
+
+/* Return times of all programs in VECTOR. COUNT indicates the size
+ of VECTOR. struct pex_time is really just struct timeval, but that
+ is not portable to all systems. Returns 0 on error, 1 on
+ success. */
+
+struct pex_time
+{
+ unsigned long user_seconds;
+ unsigned long user_microseconds;
+ unsigned long system_seconds;
+ unsigned long system_microseconds;
+};
+
+extern int pex_get_times (struct pex_obj *, int count,
+ struct pex_time *vector);
+
+/* Clean up a pex_obj. If you have not called pex_get_times or
+ pex_get_status, this will try to kill the subprocesses. */
+
+extern void pex_free (struct pex_obj *);
+
+/* Just execute one program. Return value is as for pex_run.
+ FLAGS Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT.
+ EXECUTABLE As for pex_run.
+ ARGV As for pex_run.
+ PNAME As for pex_init.
+ OUTNAME As for pex_run when PEX_LAST is set.
+ ERRNAME As for pex_run.
+ STATUS Set to exit status on success.
+ ERR As for pex_run.
+*/
+
+extern const char *pex_one (int flags, const char *executable,
+ char * const *argv, const char *pname,
+ const char *outname, const char *errname,
+ int *status, int *err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/linkers/libiberty/make-temp-file.c b/linkers/libiberty/make-temp-file.c
new file mode 100644
index 0000000..7b74f81
--- /dev/null
+++ b/linkers/libiberty/make-temp-file.c
@@ -0,0 +1,217 @@
+/* Utility to pick a temporary filename prefix.
+ Copyright (C) 1996, 1997, 1998, 2001, 2009, 2010
+ Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h> /* May get P_tmpdir. */
+#include <sys/types.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h> /* May get R_OK, etc. on some systems. */
+#endif
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#endif
+
+#ifndef R_OK
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#endif
+
+#include "libiberty.h"
+extern int mkstemps (char *, int);
+
+/* '/' works just fine on MS-DOS based systems. */
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+/* Name of temporary file.
+ mktemp requires 6 trailing X's. */
+#define TEMP_FILE "ccXXXXXX"
+#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1)
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+
+/* Subroutine of choose_tmpdir.
+ If BASE is non-NULL, return it.
+ Otherwise it checks if DIR is a usable directory.
+ If success, DIR is returned.
+ Otherwise NULL is returned. */
+
+static inline const char *try_dir (const char *, const char *);
+
+static inline const char *
+try_dir (const char *dir, const char *base)
+{
+ if (base != 0)
+ return base;
+ if (dir != 0
+ && access (dir, R_OK | W_OK | X_OK) == 0)
+ return dir;
+ return 0;
+}
+
+static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
+static const char usrtmp[] =
+{ DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
+static const char vartmp[] =
+{ DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
+
+#endif
+
+static char *memoized_tmpdir;
+
+/*
+
+@deftypefn Replacement char* choose_tmpdir ()
+
+Returns a pointer to a directory path suitable for creating temporary
+files in.
+
+@end deftypefn
+
+*/
+
+char *
+choose_tmpdir (void)
+{
+ if (!memoized_tmpdir)
+ {
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ const char *base = 0;
+ char *tmpdir;
+ unsigned int len;
+
+#ifdef VMS
+ /* Try VMS standard temp logical. */
+ base = try_dir ("/sys$scratch", base);
+#else
+ base = try_dir (getenv ("TMPDIR"), base);
+ base = try_dir (getenv ("TMP"), base);
+ base = try_dir (getenv ("TEMP"), base);
+#endif
+
+#ifdef P_tmpdir
+ /* We really want a directory name here as if concatenated with say \dir
+ we do not end up with a double \\ which defines an UNC path. */
+ if (strcmp (P_tmpdir, "\\") == 0)
+ base = try_dir ("\\.", base);
+ else
+ base = try_dir (P_tmpdir, base);
+#endif
+
+ /* Try /var/tmp, /usr/tmp, then /tmp. */
+ base = try_dir (vartmp, base);
+ base = try_dir (usrtmp, base);
+ base = try_dir (tmp, base);
+
+ /* If all else fails, use the current directory! */
+ if (base == 0)
+ base = ".";
+ /* Append DIR_SEPARATOR to the directory we've chosen
+ and return it. */
+ len = strlen (base);
+ tmpdir = XNEWVEC (char, len + 2);
+ strcpy (tmpdir, base);
+ tmpdir[len] = DIR_SEPARATOR;
+ tmpdir[len+1] = '\0';
+ memoized_tmpdir = tmpdir;
+#else /* defined(_WIN32) && !defined(__CYGWIN__) */
+ DWORD len;
+
+ /* Figure out how much space we need. */
+ len = GetTempPath(0, NULL);
+ if (len)
+ {
+ memoized_tmpdir = XNEWVEC (char, len);
+ if (!GetTempPath(len, memoized_tmpdir))
+ {
+ XDELETEVEC (memoized_tmpdir);
+ memoized_tmpdir = NULL;
+ }
+ }
+ if (!memoized_tmpdir)
+ /* If all else fails, use the current directory. */
+ memoized_tmpdir = xstrdup (".\\");
+#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
+ }
+
+ return memoized_tmpdir;
+}
+
+/*
+
+@deftypefn Replacement char* make_temp_file (const char *@var{suffix})
+
+Return a temporary file name (as a string) or @code{NULL} if unable to
+create one. @var{suffix} is a suffix to append to the file name. The
+string is @code{malloc}ed, and the temporary file has been created.
+
+@end deftypefn
+
+*/
+
+char *
+make_temp_file (const char *suffix)
+{
+ const char *base = choose_tmpdir ();
+ char *temp_filename;
+ int base_len, suffix_len;
+ int fd;
+
+ if (suffix == 0)
+ suffix = "";
+
+ base_len = strlen (base);
+ suffix_len = strlen (suffix);
+
+ temp_filename = XNEWVEC (char, base_len
+ + TEMP_FILE_LEN
+ + suffix_len + 1);
+ strcpy (temp_filename, base);
+ strcpy (temp_filename + base_len, TEMP_FILE);
+ strcpy (temp_filename + base_len + TEMP_FILE_LEN, suffix);
+
+ fd = mkstemps (temp_filename, suffix_len);
+ /* Mkstemps failed. It may be EPERM, ENOSPC etc. */
+ if (fd == -1)
+ {
+ fprintf (stderr, "Cannot create temporary file in %s: %s\n",
+ base, strerror (errno));
+ abort ();
+ }
+ /* We abort on failed close out of sheer paranoia. */
+ if (close (fd))
+ abort ();
+ return temp_filename;
+}
diff --git a/linkers/libiberty/mkstemps.c b/linkers/libiberty/mkstemps.c
new file mode 100644
index 0000000..a0e68a7
--- /dev/null
+++ b/linkers/libiberty/mkstemps.c
@@ -0,0 +1,147 @@
+/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc.
+ This file is derived from mkstemp.c from the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include "ansidecl.h"
+
+/* We need to provide a type for gcc_uint64_t. */
+#ifdef __GNUC__
+__extension__ typedef unsigned long long gcc_uint64_t;
+#else
+typedef unsigned long gcc_uint64_t;
+#endif
+
+#ifndef TMP_MAX
+#define TMP_MAX 16384
+#endif
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/*
+
+@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len})
+
+Generate a unique temporary file name from @var{pattern}.
+@var{pattern} has the form:
+
+@example
+ @var{path}/ccXXXXXX@var{suffix}
+@end example
+
+@var{suffix_len} tells us how long @var{suffix} is (it can be zero
+length). The last six characters of @var{pattern} before @var{suffix}
+must be @samp{XXXXXX}; they are replaced with a string that makes the
+filename unique. Returns a file descriptor open on the file for
+reading and writing.
+
+@end deftypefn
+
+*/
+
+int
+mkstemps (char *pattern, int suffix_len)
+{
+ static const char letters[]
+ = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static gcc_uint64_t value;
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+#endif
+ char *XXXXXX;
+ size_t len;
+ int count;
+
+ len = strlen (pattern);
+
+ if ((int) len < 6 + suffix_len
+ || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6))
+ {
+ return -1;
+ }
+
+ XXXXXX = &pattern[len - 6 - suffix_len];
+
+#ifdef HAVE_GETTIMEOFDAY
+ /* Get some more or less random data. */
+ gettimeofday (&tv, NULL);
+ value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
+#else
+ value += getpid ();
+#endif
+
+ for (count = 0; count < TMP_MAX; ++count)
+ {
+ gcc_uint64_t v = value;
+ int fd;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (fd >= 0)
+ /* The file does not exist. */
+ return fd;
+ if (errno != EEXIST
+#ifdef EISDIR
+ && errno != EISDIR
+#endif
+ )
+ /* Fatal error (EPERM, ENOSPC etc). Doesn't make sense to loop. */
+ break;
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
+ }
+
+ /* We return the null string if we can't find a unique file name. */
+ pattern[0] = '\0';
+ return -1;
+}
diff --git a/linkers/libiberty/pex-common.c b/linkers/libiberty/pex-common.c
new file mode 100644
index 0000000..6fd3fde
--- /dev/null
+++ b/linkers/libiberty/pex-common.c
@@ -0,0 +1,646 @@
+/* Common code for executing a program in a sub-process.
+ Copyright (C) 2005, 2010 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@airs.com>.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "libiberty.h"
+#include "pex-common.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern int mkstemps (char *, int);
+
+/* This file contains subroutines for the program execution routines
+ (pex_init, pex_run, etc.). This file is compiled on all
+ systems. */
+
+static void pex_add_remove (struct pex_obj *, const char *, int);
+static int pex_get_status_and_time (struct pex_obj *, int, const char **,
+ int *);
+
+/* Initialize a pex_obj structure. */
+
+struct pex_obj *
+pex_init_common (int flags, const char *pname, const char *tempbase,
+ const struct pex_funcs *funcs)
+{
+ struct pex_obj *obj;
+
+ obj = XNEW (struct pex_obj);
+ obj->flags = flags;
+ obj->pname = pname;
+ obj->tempbase = tempbase;
+ obj->next_input = STDIN_FILE_NO;
+ obj->next_input_name = NULL;
+ obj->next_input_name_allocated = 0;
+ obj->stderr_pipe = -1;
+ obj->count = 0;
+ obj->children = NULL;
+ obj->status = NULL;
+ obj->time = NULL;
+ obj->number_waited = 0;
+ obj->input_file = NULL;
+ obj->read_output = NULL;
+ obj->read_err = NULL;
+ obj->remove_count = 0;
+ obj->remove = NULL;
+ obj->funcs = funcs;
+ obj->sysdep = NULL;
+ return obj;
+}
+
+/* Add a file to be removed when we are done. */
+
+static void
+pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
+{
+ char *add;
+
+ ++obj->remove_count;
+ obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
+ if (allocated)
+ add = (char *) name;
+ else
+ add = xstrdup (name);
+ obj->remove[obj->remove_count - 1] = add;
+}
+
+/* Generate a temporary file name based on OBJ, FLAGS, and NAME.
+ Return NULL if we were unable to reserve a temporary filename.
+
+ If non-NULL, the result is either allocated with malloc, or the
+ same pointer as NAME. */
+static char *
+temp_file (struct pex_obj *obj, int flags, char *name)
+{
+ if (name == NULL)
+ {
+ if (obj->tempbase == NULL)
+ {
+ name = make_temp_file (NULL);
+ }
+ else
+ {
+ int len = strlen (obj->tempbase);
+ int out;
+
+ if (len >= 6
+ && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
+ name = xstrdup (obj->tempbase);
+ else
+ name = concat (obj->tempbase, "XXXXXX", NULL);
+
+ out = mkstemps (name, 0);
+ if (out < 0)
+ {
+ free (name);
+ return NULL;
+ }
+
+ /* This isn't obj->funcs->close because we got the
+ descriptor from mkstemps, not from a function in
+ obj->funcs. Calling close here is just like what
+ make_temp_file does. */
+ close (out);
+ }
+ }
+ else if ((flags & PEX_SUFFIX) != 0)
+ {
+ if (obj->tempbase == NULL)
+ name = make_temp_file (name);
+ else
+ name = concat (obj->tempbase, name, NULL);
+ }
+
+ return name;
+}
+
+
+/* As for pex_run (), but permits the environment for the child process
+ to be specified. */
+
+const char *
+pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, char * const * env,
+ const char *orig_outname, const char *errname,
+ int *err)
+{
+ const char *errmsg;
+ int in, out, errdes;
+ char *outname;
+ int outname_allocated;
+ int p[2];
+ int toclose;
+ pid_t pid;
+
+ in = -1;
+ out = -1;
+ errdes = -1;
+ outname = (char *) orig_outname;
+ outname_allocated = 0;
+
+ /* If the user called pex_input_file, close the file now. */
+ if (obj->input_file)
+ {
+ if (fclose (obj->input_file) == EOF)
+ {
+ errmsg = "closing pipeline input file";
+ goto error_exit;
+ }
+ obj->input_file = NULL;
+ }
+
+ /* Set IN. */
+
+ if (obj->next_input_name != NULL)
+ {
+ /* We have to make sure that the previous process has completed
+ before we try to read the file. */
+ if (!pex_get_status_and_time (obj, 0, &errmsg, err))
+ goto error_exit;
+
+ in = obj->funcs->open_read (obj, obj->next_input_name,
+ (flags & PEX_BINARY_INPUT) != 0);
+ if (in < 0)
+ {
+ *err = errno;
+ errmsg = "open temporary file";
+ goto error_exit;
+ }
+ if (obj->next_input_name_allocated)
+ {
+ free (obj->next_input_name);
+ obj->next_input_name_allocated = 0;
+ }
+ obj->next_input_name = NULL;
+ }
+ else
+ {
+ in = obj->next_input;
+ if (in < 0)
+ {
+ *err = 0;
+ errmsg = "pipeline already complete";
+ goto error_exit;
+ }
+ }
+
+ /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME. */
+
+ if ((flags & PEX_LAST) != 0)
+ {
+ if (outname == NULL)
+ out = STDOUT_FILE_NO;
+ else if ((flags & PEX_SUFFIX) != 0)
+ {
+ outname = concat (obj->tempbase, outname, NULL);
+ outname_allocated = 1;
+ }
+ obj->next_input = -1;
+ }
+ else if ((obj->flags & PEX_USE_PIPES) == 0)
+ {
+ outname = temp_file (obj, flags, outname);
+ if (! outname)
+ {
+ *err = 0;
+ errmsg = "could not create temporary file";
+ goto error_exit;
+ }
+
+ if (outname != orig_outname)
+ outname_allocated = 1;
+
+ if ((obj->flags & PEX_SAVE_TEMPS) == 0)
+ {
+ pex_add_remove (obj, outname, outname_allocated);
+ outname_allocated = 0;
+ }
+
+ /* Hand off ownership of outname to the next stage. */
+ obj->next_input_name = outname;
+ obj->next_input_name_allocated = outname_allocated;
+ outname_allocated = 0;
+ }
+ else
+ {
+ if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
+ {
+ *err = errno;
+ errmsg = "pipe";
+ goto error_exit;
+ }
+
+ out = p[WRITE_PORT];
+ obj->next_input = p[READ_PORT];
+ }
+
+ if (out < 0)
+ {
+ out = obj->funcs->open_write (obj, outname,
+ (flags & PEX_BINARY_OUTPUT) != 0);
+ if (out < 0)
+ {
+ *err = errno;
+ errmsg = "open temporary output file";
+ goto error_exit;
+ }
+ }
+
+ if (outname_allocated)
+ {
+ free (outname);
+ outname_allocated = 0;
+ }
+
+ /* Set ERRDES. */
+
+ if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
+ {
+ *err = 0;
+ errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
+ goto error_exit;
+ }
+
+ if (obj->stderr_pipe != -1)
+ {
+ *err = 0;
+ errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
+ goto error_exit;
+ }
+
+ if (errname == NULL)
+ {
+ if (flags & PEX_STDERR_TO_PIPE)
+ {
+ if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
+ {
+ *err = errno;
+ errmsg = "pipe";
+ goto error_exit;
+ }
+
+ errdes = p[WRITE_PORT];
+ obj->stderr_pipe = p[READ_PORT];
+ }
+ else
+ {
+ errdes = STDERR_FILE_NO;
+ }
+ }
+ else
+ {
+ errdes = obj->funcs->open_write (obj, errname,
+ (flags & PEX_BINARY_ERROR) != 0);
+ if (errdes < 0)
+ {
+ *err = errno;
+ errmsg = "open error file";
+ goto error_exit;
+ }
+ }
+
+ /* If we are using pipes, the child process has to close the next
+ input pipe. */
+
+ if ((obj->flags & PEX_USE_PIPES) == 0)
+ toclose = -1;
+ else
+ toclose = obj->next_input;
+
+ /* Run the program. */
+
+ pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
+ in, out, errdes, toclose, &errmsg, err);
+ if (pid < 0)
+ goto error_exit;
+
+ ++obj->count;
+ obj->children = XRESIZEVEC (pid_t, obj->children, obj->count);
+ obj->children[obj->count - 1] = pid;
+
+ return NULL;
+
+ error_exit:
+ if (in >= 0 && in != STDIN_FILE_NO)
+ obj->funcs->close (obj, in);
+ if (out >= 0 && out != STDOUT_FILE_NO)
+ obj->funcs->close (obj, out);
+ if (errdes >= 0 && errdes != STDERR_FILE_NO)
+ obj->funcs->close (obj, errdes);
+ if (outname_allocated)
+ free (outname);
+ return errmsg;
+}
+
+/* Run a program. */
+
+const char *
+pex_run (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, const char *orig_outname, const char *errname,
+ int *err)
+{
+ return pex_run_in_environment (obj, flags, executable, argv, NULL,
+ orig_outname, errname, err);
+}
+
+/* Return a FILE pointer for a temporary file to fill with input for
+ the pipeline. */
+FILE *
+pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
+{
+ char *name = (char *) in_name;
+ FILE *f;
+
+ /* This must be called before the first pipeline stage is run, and
+ there must not have been any other input selected. */
+ if (obj->count != 0
+ || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ || obj->next_input_name)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ name = temp_file (obj, flags, name);
+ if (! name)
+ return NULL;
+
+ f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
+ if (! f)
+ {
+ free (name);
+ return NULL;
+ }
+
+ obj->input_file = f;
+ obj->next_input_name = name;
+ obj->next_input_name_allocated = (name != in_name);
+
+ return f;
+}
+
+/* Return a stream for a pipe connected to the standard input of the
+ first stage of the pipeline. */
+FILE *
+pex_input_pipe (struct pex_obj *obj, int binary)
+{
+ int p[2];
+ FILE *f;
+
+ /* You must call pex_input_pipe before the first pex_run or pex_one. */
+ if (obj->count > 0)
+ goto usage_error;
+
+ /* You must be using pipes. Implementations that don't support
+ pipes clear this flag before calling pex_init_common. */
+ if (! (obj->flags & PEX_USE_PIPES))
+ goto usage_error;
+
+ /* If we have somehow already selected other input, that's a
+ mistake. */
+ if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ || obj->next_input_name)
+ goto usage_error;
+
+ if (obj->funcs->pipe (obj, p, binary != 0) < 0)
+ return NULL;
+
+ f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
+ if (! f)
+ {
+ int saved_errno = errno;
+ obj->funcs->close (obj, p[READ_PORT]);
+ obj->funcs->close (obj, p[WRITE_PORT]);
+ errno = saved_errno;
+ return NULL;
+ }
+
+ obj->next_input = p[READ_PORT];
+
+ return f;
+
+ usage_error:
+ errno = EINVAL;
+ return NULL;
+}
+
+/* Return a FILE pointer for the output of the last program
+ executed. */
+
+FILE *
+pex_read_output (struct pex_obj *obj, int binary)
+{
+ if (obj->next_input_name != NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ /* We have to make sure that the process has completed before we
+ try to read the file. */
+ if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+ {
+ errno = err;
+ return NULL;
+ }
+
+ obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
+
+ if (obj->next_input_name_allocated)
+ {
+ free (obj->next_input_name);
+ obj->next_input_name_allocated = 0;
+ }
+ obj->next_input_name = NULL;
+ }
+ else
+ {
+ int o;
+
+ o = obj->next_input;
+ if (o < 0 || o == STDIN_FILE_NO)
+ return NULL;
+ obj->read_output = obj->funcs->fdopenr (obj, o, binary);
+ obj->next_input = -1;
+ }
+
+ return obj->read_output;
+}
+
+FILE *
+pex_read_err (struct pex_obj *obj, int binary)
+{
+ int o;
+
+ o = obj->stderr_pipe;
+ if (o < 0 || o == STDIN_FILE_NO)
+ return NULL;
+ obj->read_err = obj->funcs->fdopenr (obj, o, binary);
+ obj->stderr_pipe = -1;
+ return obj->read_err;
+}
+
+/* Get the exit status and, if requested, the resource time for all
+ the child processes. Return 0 on failure, 1 on success. */
+
+static int
+pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
+ int *err)
+{
+ int ret;
+ int i;
+
+ if (obj->number_waited == obj->count)
+ return 1;
+
+ obj->status = XRESIZEVEC (int, obj->status, obj->count);
+ if ((obj->flags & PEX_RECORD_TIMES) != 0)
+ obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
+
+ ret = 1;
+ for (i = obj->number_waited; i < obj->count; ++i)
+ {
+ if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
+ obj->time == NULL ? NULL : &obj->time[i],
+ done, errmsg, err) < 0)
+ ret = 0;
+ }
+ obj->number_waited = i;
+
+ return ret;
+}
+
+/* Get exit status of executed programs. */
+
+int
+pex_get_status (struct pex_obj *obj, int count, int *vector)
+{
+ if (obj->status == NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+ return 0;
+ }
+
+ if (count > obj->count)
+ {
+ memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
+ count = obj->count;
+ }
+
+ memcpy (vector, obj->status, count * sizeof (int));
+
+ return 1;
+}
+
+/* Get process times of executed programs. */
+
+int
+pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
+{
+ if (obj->status == NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+ return 0;
+ }
+
+ if (obj->time == NULL)
+ return 0;
+
+ if (count > obj->count)
+ {
+ memset (vector + obj->count, 0,
+ (count - obj->count) * sizeof (struct pex_time));
+ count = obj->count;
+ }
+
+ memcpy (vector, obj->time, count * sizeof (struct pex_time));
+
+ return 1;
+}
+
+/* Free a pex_obj structure. */
+
+void
+pex_free (struct pex_obj *obj)
+{
+ /* Close pipe file descriptors corresponding to child's stdout and
+ stderr so that the child does not hang trying to output something
+ while we're waiting for it. */
+ if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ obj->funcs->close (obj, obj->next_input);
+ if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO)
+ obj->funcs->close (obj, obj->stderr_pipe);
+ if (obj->read_output != NULL)
+ fclose (obj->read_output);
+ if (obj->read_err != NULL)
+ fclose (obj->read_err);
+
+ /* If the caller forgot to wait for the children, we do it here, to
+ avoid zombies. */
+ if (obj->status == NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ obj->flags &= ~ PEX_RECORD_TIMES;
+ pex_get_status_and_time (obj, 1, &errmsg, &err);
+ }
+
+ if (obj->next_input_name_allocated)
+ free (obj->next_input_name);
+ free (obj->children);
+ free (obj->status);
+ free (obj->time);
+
+ if (obj->remove_count > 0)
+ {
+ int i;
+
+ for (i = 0; i < obj->remove_count; ++i)
+ {
+ remove (obj->remove[i]);
+ free (obj->remove[i]);
+ }
+ free (obj->remove);
+ }
+
+ if (obj->funcs->cleanup != NULL)
+ obj->funcs->cleanup (obj);
+
+ free (obj);
+}
diff --git a/linkers/libiberty/pex-common.h b/linkers/libiberty/pex-common.h
new file mode 100644
index 0000000..af338e6
--- /dev/null
+++ b/linkers/libiberty/pex-common.h
@@ -0,0 +1,153 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it. Shared logic.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
+ Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#ifndef PEX_COMMON_H
+#define PEX_COMMON_H
+
+#include "config.h"
+#include "libiberty.h"
+#include <stdio.h>
+
+/* pid_t is may defined by config.h or sys/types.h needs to be
+ included. */
+#if !defined(pid_t) && defined(HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+#define install_error_msg "installation problem, cannot exec `%s'"
+
+/* stdin file number. */
+#define STDIN_FILE_NO 0
+
+/* stdout file number. */
+#define STDOUT_FILE_NO 1
+
+/* stderr file number. */
+#define STDERR_FILE_NO 2
+
+/* value of `pipe': port index for reading. */
+#define READ_PORT 0
+
+/* value of `pipe': port index for writing. */
+#define WRITE_PORT 1
+
+/* The structure used by pex_init and friends. */
+
+struct pex_obj
+{
+ /* Flags. */
+ int flags;
+ /* Name of calling program, for error messages. */
+ const char *pname;
+ /* Base name to use for temporary files. */
+ const char *tempbase;
+ /* Pipe to use as stdin for next process. */
+ int next_input;
+ /* File name to use as stdin for next process. */
+ char *next_input_name;
+ /* Whether next_input_name was allocated using malloc. */
+ int next_input_name_allocated;
+ /* If not -1, stderr pipe from the last process. */
+ int stderr_pipe;
+ /* Number of child processes. */
+ int count;
+ /* PIDs of child processes; array allocated using malloc. */
+ pid_t *children;
+ /* Exit statuses of child processes; array allocated using malloc. */
+ int *status;
+ /* Time used by child processes; array allocated using malloc. */
+ struct pex_time *time;
+ /* Number of children we have already waited for. */
+ int number_waited;
+ /* FILE created by pex_input_file. */
+ FILE *input_file;
+ /* FILE created by pex_read_output. */
+ FILE *read_output;
+ /* FILE created by pex_read_err. */
+ FILE *read_err;
+ /* Number of temporary files to remove. */
+ int remove_count;
+ /* List of temporary files to remove; array allocated using malloc
+ of strings allocated using malloc. */
+ char **remove;
+ /* Pointers to system dependent functions. */
+ const struct pex_funcs *funcs;
+ /* For use by system dependent code. */
+ void *sysdep;
+};
+
+/* Functions passed to pex_run_common. */
+
+struct pex_funcs
+{
+ /* Open file NAME for reading. If BINARY is non-zero, open in
+ binary mode. Return >= 0 on success, -1 on error. */
+ int (*open_read) (struct pex_obj *, const char */* name */, int /* binary */);
+ /* Open file NAME for writing. If BINARY is non-zero, open in
+ binary mode. Return >= 0 on success, -1 on error. */
+ int (*open_write) (struct pex_obj *, const char */* name */,
+ int /* binary */);
+ /* Execute a child process. FLAGS, EXECUTABLE, ARGV, ERR are from
+ pex_run. IN, OUT, ERRDES, TOCLOSE are all descriptors, from
+ open_read, open_write, or pipe, or they are one of STDIN_FILE_NO,
+ STDOUT_FILE_NO or STDERR_FILE_NO; if IN, OUT, and ERRDES are not
+ STD*_FILE_NO, they should be closed. If the descriptor TOCLOSE
+ is not -1, and the system supports pipes, TOCLOSE should be
+ closed in the child process. The function should handle the
+ PEX_STDERR_TO_STDOUT flag. Return >= 0 on success, or -1 on
+ error and set *ERRMSG and *ERR. */
+ pid_t (*exec_child) (struct pex_obj *, int /* flags */,
+ const char */* executable */, char * const * /* argv */,
+ char * const * /* env */,
+ int /* in */, int /* out */, int /* errdes */,
+ int /* toclose */, const char **/* errmsg */,
+ int */* err */);
+ /* Close a descriptor. Return 0 on success, -1 on error. */
+ int (*close) (struct pex_obj *, int);
+ /* Wait for a child to complete, returning exit status in *STATUS
+ and time in *TIME (if it is not null). CHILD is from fork. DONE
+ is 1 if this is called via pex_free. ERRMSG and ERR are as in
+ fork. Return 0 on success, -1 on error. */
+ pid_t (*wait) (struct pex_obj *, pid_t /* child */, int * /* status */,
+ struct pex_time * /* time */, int /* done */,
+ const char ** /* errmsg */, int * /* err */);
+ /* Create a pipe (only called if PEX_USE_PIPES is set) storing two
+ descriptors in P[0] and P[1]. If BINARY is non-zero, open in
+ binary mode. Return 0 on success, -1 on error. */
+ int (*pipe) (struct pex_obj *, int * /* p */, int /* binary */);
+ /* Get a FILE pointer to read from a file descriptor (only called if
+ PEX_USE_PIPES is set). If BINARY is non-zero, open in binary
+ mode. Return pointer on success, NULL on error. */
+ FILE * (*fdopenr) (struct pex_obj *, int /* fd */, int /* binary */);
+ /* Get a FILE pointer to write to the file descriptor FD (only
+ called if PEX_USE_PIPES is set). If BINARY is non-zero, open in
+ binary mode. Arrange for FD not to be inherited by the child
+ processes. Return pointer on success, NULL on error. */
+ FILE * (*fdopenw) (struct pex_obj *, int /* fd */, int /* binary */);
+ /* Free any system dependent data associated with OBJ. May be
+ NULL if there is nothing to do. */
+ void (*cleanup) (struct pex_obj *);
+};
+
+extern struct pex_obj *pex_init_common (int, const char *, const char *,
+ const struct pex_funcs *);
+
+#endif
diff --git a/linkers/libiberty/pex-djgpp.c b/linkers/libiberty/pex-djgpp.c
new file mode 100644
index 0000000..0721139
--- /dev/null
+++ b/linkers/libiberty/pex-djgpp.c
@@ -0,0 +1,294 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it. DJGPP specialization.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
+ Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "pex-common.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <process.h>
+
+/* Use ECHILD if available, otherwise use EINVAL. */
+#ifdef ECHILD
+#define PWAIT_ERROR ECHILD
+#else
+#define PWAIT_ERROR EINVAL
+#endif
+
+static int pex_djgpp_open_read (struct pex_obj *, const char *, int);
+static int pex_djgpp_open_write (struct pex_obj *, const char *, int);
+static pid_t pex_djgpp_exec_child (struct pex_obj *, int, const char *,
+ char * const *, char * const *,
+ int, int, int, int,
+ const char **, int *);
+static int pex_djgpp_close (struct pex_obj *, int);
+static pid_t pex_djgpp_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
+ int, const char **, int *);
+
+/* The list of functions we pass to the common routines. */
+
+const struct pex_funcs funcs =
+{
+ pex_djgpp_open_read,
+ pex_djgpp_open_write,
+ pex_djgpp_exec_child,
+ pex_djgpp_close,
+ pex_djgpp_wait,
+ NULL, /* pipe */
+ NULL, /* fdopenr */
+ NULL, /* fdopenw */
+ NULL /* cleanup */
+};
+
+/* Return a newly initialized pex_obj structure. */
+
+struct pex_obj *
+pex_init (int flags, const char *pname, const char *tempbase)
+{
+ /* DJGPP does not support pipes. */
+ flags &= ~ PEX_USE_PIPES;
+ return pex_init_common (flags, pname, tempbase, &funcs);
+}
+
+/* Open a file for reading. */
+
+static int
+pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED,
+ const char *name, int binary)
+{
+ return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT));
+}
+
+/* Open a file for writing. */
+
+static int
+pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED,
+ const char *name, int binary)
+{
+ /* Note that we can't use O_EXCL here because gcc may have already
+ created the temporary file via make_temp_file. */
+ return open (name,
+ (O_WRONLY | O_CREAT | O_TRUNC
+ | (binary ? O_BINARY : O_TEXT)),
+ S_IRUSR | S_IWUSR);
+}
+
+/* Close a file. */
+
+static int
+pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
+{
+ return close (fd);
+}
+
+/* Execute a child. */
+
+static pid_t
+pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes,
+ int toclose ATTRIBUTE_UNUSED, const char **errmsg,
+ int *err)
+{
+ int org_in, org_out, org_errdes;
+ int status;
+ int *statuses;
+
+ org_in = -1;
+ org_out = -1;
+ org_errdes = -1;
+
+ if (in != STDIN_FILE_NO)
+ {
+ org_in = dup (STDIN_FILE_NO);
+ if (org_in < 0)
+ {
+ *err = errno;
+ *errmsg = "dup";
+ return (pid_t) -1;
+ }
+ if (dup2 (in, STDIN_FILE_NO) < 0)
+ {
+ *err = errno;
+ *errmsg = "dup2";
+ return (pid_t) -1;
+ }
+ if (close (in) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+
+ if (out != STDOUT_FILE_NO)
+ {
+ org_out = dup (STDOUT_FILE_NO);
+ if (org_out < 0)
+ {
+ *err = errno;
+ *errmsg = "dup";
+ return (pid_t) -1;
+ }
+ if (dup2 (out, STDOUT_FILE_NO) < 0)
+ {
+ *err = errno;
+ *errmsg = "dup2";
+ return (pid_t) -1;
+ }
+ if (close (out) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+
+ if (errdes != STDERR_FILE_NO
+ || (flags & PEX_STDERR_TO_STDOUT) != 0)
+ {
+ org_errdes = dup (STDERR_FILE_NO);
+ if (org_errdes < 0)
+ {
+ *err = errno;
+ *errmsg = "dup";
+ return (pid_t) -1;
+ }
+ if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
+ STDERR_FILE_NO) < 0)
+ {
+ *err = errno;
+ *errmsg = "dup2";
+ return (pid_t) -1;
+ }
+ if (errdes != STDERR_FILE_NO)
+ {
+ if (close (errdes) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+ }
+
+ if (env)
+ status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve)
+ (P_WAIT, executable, argv, env));
+ else
+ status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv)
+ (P_WAIT, executable, argv));
+
+ if (status == -1)
+ {
+ *err = errno;
+ *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv";
+ }
+
+ if (in != STDIN_FILE_NO)
+ {
+ if (dup2 (org_in, STDIN_FILE_NO) < 0)
+ {
+ *err = errno;
+ *errmsg = "dup2";
+ return (pid_t) -1;
+ }
+ if (close (org_in) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+
+ if (out != STDOUT_FILE_NO)
+ {
+ if (dup2 (org_out, STDOUT_FILE_NO) < 0)
+ {
+ *err = errno;
+ *errmsg = "dup2";
+ return (pid_t) -1;
+ }
+ if (close (org_out) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+
+ if (errdes != STDERR_FILE_NO
+ || (flags & PEX_STDERR_TO_STDOUT) != 0)
+ {
+ if (dup2 (org_errdes, STDERR_FILE_NO) < 0)
+ {
+ *err = errno;
+ *errmsg = "dup2";
+ return (pid_t) -1;
+ }
+ if (close (org_errdes) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+
+ /* Save the exit status for later. When we are called, obj->count
+ is the number of children which have executed before this
+ one. */
+ statuses = (int *) obj->sysdep;
+ statuses = XRESIZEVEC (int, statuses, obj->count + 1);
+ statuses[obj->count] = status;
+ obj->sysdep = (void *) statuses;
+
+ return (pid_t) obj->count;
+}
+
+/* Wait for a child process to complete. Actually the child process
+ has already completed, and we just need to return the exit
+ status. */
+
+static pid_t
+pex_djgpp_wait (struct pex_obj *obj, pid_t pid, int *status,
+ struct pex_time *time, int done ATTRIBUTE_UNUSED,
+ const char **errmsg ATTRIBUTE_UNUSED,
+ int *err ATTRIBUTE_UNUSED)
+{
+ int *statuses;
+
+ if (time != NULL)
+ memset (time, 0, sizeof *time);
+
+ statuses = (int *) obj->sysdep;
+ *status = statuses[pid];
+
+ return 0;
+}
diff --git a/linkers/libiberty/pex-msdos.c b/linkers/libiberty/pex-msdos.c
new file mode 100644
index 0000000..fa0f40a
--- /dev/null
+++ b/linkers/libiberty/pex-msdos.c
@@ -0,0 +1,317 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it. Generic MSDOS specialization.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
+ Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "pex-common.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "safe-ctype.h"
+#include <process.h>
+
+/* The structure we keep in obj->sysdep. */
+
+#define PEX_MSDOS_FILE_COUNT 3
+
+#define PEX_MSDOS_FD_OFFSET 10
+
+struct pex_msdos
+{
+ /* An array of file names. We refer to these using file descriptors
+ of 10 + array index. */
+ const char *files[PEX_MSDOS_FILE_COUNT];
+ /* Exit statuses of programs which have been run. */
+ int *statuses;
+};
+
+static int pex_msdos_open (struct pex_obj *, const char *, int);
+static int pex_msdos_open (struct pex_obj *, const char *, int);
+static int pex_msdos_fdindex (struct pex_msdos *, int);
+static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *,
+ char * const *, char * const *,
+ int, int, int, int,
+ int, const char **, int *);
+static int pex_msdos_close (struct pex_obj *, int);
+static pid_t pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
+ int, const char **, int *);
+static void pex_msdos_cleanup (struct pex_obj *);
+
+/* The list of functions we pass to the common routines. */
+
+const struct pex_funcs funcs =
+{
+ pex_msdos_open,
+ pex_msdos_open,
+ pex_msdos_exec_child,
+ pex_msdos_close,
+ pex_msdos_wait,
+ NULL, /* pipe */
+ NULL, /* fdopenr */
+ NULL, /* fdopenw */
+ pex_msdos_cleanup
+};
+
+/* Return a newly initialized pex_obj structure. */
+
+struct pex_obj *
+pex_init (int flags, const char *pname, const char *tempbase)
+{
+ struct pex_obj *ret;
+ int i;
+
+ /* MSDOS does not support pipes. */
+ flags &= ~ PEX_USE_PIPES;
+
+ ret = pex_init_common (flags, pname, tempbase, funcs);
+
+ ret->sysdep = XNEW (struct pex_msdos);
+ for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
+ ret->files[i] = NULL;
+ ret->statuses = NULL;
+
+ return ret;
+}
+
+/* Open a file. FIXME: We ignore the binary argument, since we have
+ no way to handle it. */
+
+static int
+pex_msdos_open (struct pex_obj *obj, const char *name,
+ int binary ATTRIBUTE_UNUSED)
+{
+ struct pex_msdos *ms;
+ int i;
+
+ ms = (struct pex_msdos *) obj->sysdep;
+
+ for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
+ {
+ if (ms->files[i] == NULL)
+ {
+ ms->files[i] = xstrdup (name);
+ return i + PEX_MSDOS_FD_OFFSET;
+ }
+ }
+
+ abort ();
+}
+
+/* Get the index into msdos->files associated with an open file
+ descriptor. */
+
+static int
+pex_msdos_fdindex (struct pex_msdos *ms, int fd)
+{
+ fd -= PEX_MSDOS_FD_OFFSET;
+ if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
+ abort ();
+ return fd;
+}
+
+
+/* Close a file. */
+
+static int
+pex_msdos_close (struct pex_obj *obj, int fd)
+{
+ struct pex_msdos *ms;
+ int fdinex;
+
+ ms = (struct pex_msdos *) obj->sysdep;
+ fdindex = pe_msdos_fdindex (ms, fd);
+ free (ms->files[fdindex]);
+ ms->files[fdindex] = NULL;
+}
+
+/* Execute a child. */
+
+static pid_t
+pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, char * const * env, int in, int out,
+ int toclose ATTRIBUTE_UNUSED,
+ int errdes ATTRIBUTE_UNUSED, const char **errmsg,
+ int *err)
+{
+ struct pex_msdos *ms;
+ char *temp_base;
+ int temp_base_allocated;
+ char *rf;
+ int inindex;
+ char *infile;
+ int outindex;
+ char *outfile;
+ char *scmd;
+ FILE *argfile;
+ int i;
+ int status;
+
+ ms = (struct pex_msdos *) obj->sysdep;
+
+ /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
+ and PEX_STDERR_TO_STDOUT. */
+
+ temp_base = obj->temp_base;
+ if (temp_base != NULL)
+ temp_base_allocated = 0;
+ else
+ {
+ temp_base = choose_temp_base ();
+ temp_base_allocated = 1;
+ }
+
+ rf = concat (temp_base, ".gp", NULL);
+
+ if (temp_base_allocated)
+ free (temp_base);
+
+ if (in == STDIN_FILE_NO)
+ {
+ inindex = -1;
+ infile = "";
+ }
+ else
+ {
+ inindex = pex_msdos_fdindex (ms, in);
+ infile = ms->files[inindex];
+ }
+
+ if (out == STDOUT_FILE_NO)
+ {
+ outindex = -1;
+ outfile = "";
+ }
+ else
+ {
+ outindex = pex_msdos_fdindex (ms, out);
+ outfile = ms->files[outindex];
+ }
+
+ scmd = XNEWVEC (char, strlen (program)
+ + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
+ + strlen (rf)
+ + strlen (infile)
+ + strlen (outfile)
+ + 10);
+ sprintf (scmd, "%s%s @%s%s%s%s%s",
+ program,
+ (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
+ rf,
+ inindex != -1 ? " <" : "",
+ infile,
+ outindex != -1 ? " >" : "",
+ outfile);
+
+ argfile = fopen (rf, "w");
+ if (argfile == NULL)
+ {
+ *err = errno;
+ free (scmd);
+ free (rf);
+ *errmsg = "cannot open temporary command file";
+ return (pid_t) -1;
+ }
+
+ for (i = 1; argv[i] != NULL; ++i)
+ {
+ char *p;
+
+ for (p = argv[i]; *p != '\0'; ++p)
+ {
+ if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
+ putc ('\\', argfile);
+ putc (*p, argfile);
+ }
+ putc ('\n', argfile);
+ }
+
+ fclose (argfile);
+
+ status = system (scmd);
+
+ if (status == -1)
+ {
+ *err = errno;
+ remove (rf);
+ free (scmd);
+ free (rf);
+ *errmsg = "system";
+ return (pid_t) -1;
+ }
+
+ remove (rf);
+ free (scmd);
+ free (rf);
+
+ /* Save the exit status for later. When we are called, obj->count
+ is the number of children which have executed before this
+ one. */
+ ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
+ ms->statuses[obj->count] = status;
+
+ return (pid_t) obj->count;
+}
+
+/* Wait for a child process to complete. Actually the child process
+ has already completed, and we just need to return the exit
+ status. */
+
+static pid_t
+pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status,
+ struct pex_time *time, int done ATTRIBUTE_UNUSED,
+ const char **errmsg ATTRIBUTE_UNUSED,
+ int *err ATTRIBUTE_UNUSED)
+{
+ struct pex_msdos *ms;
+
+ ms = (struct pex_msdos *) obj->sysdep;
+
+ if (time != NULL)
+ memset (time, 0, sizeof *time);
+
+ *status = ms->statuses[pid];
+
+ return 0;
+}
+
+/* Clean up the pex_msdos structure. */
+
+static void
+pex_msdos_cleanup (struct pex_obj *obj)
+{
+ struct pex_msdos *ms;
+ int i;
+
+ ms = (struct pex_msdos *) obj->sysdep;
+ for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
+ free (msdos->files[i]);
+ free (msdos->statuses);
+ free (msdos);
+ obj->sysdep = NULL;
+}
diff --git a/linkers/libiberty/pex-one.c b/linkers/libiberty/pex-one.c
new file mode 100644
index 0000000..696b8bc
--- /dev/null
+++ b/linkers/libiberty/pex-one.c
@@ -0,0 +1,43 @@
+/* Execute a program and wait for a result.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "libiberty.h"
+
+const char *
+pex_one (int flags, const char *executable, char * const *argv,
+ const char *pname, const char *outname, const char *errname,
+ int *status, int *err)
+{
+ struct pex_obj *obj;
+ const char *errmsg;
+
+ obj = pex_init (0, pname, NULL);
+ errmsg = pex_run (obj, flags, executable, argv, outname, errname, err);
+ if (errmsg == NULL)
+ {
+ if (!pex_get_status (obj, 1, status))
+ {
+ *err = 0;
+ errmsg = "pex_get_status failed";
+ }
+ }
+ pex_free (obj);
+ return errmsg;
+}
diff --git a/linkers/libiberty/pex-unix.c b/linkers/libiberty/pex-unix.c
new file mode 100644
index 0000000..80a4770
--- /dev/null
+++ b/linkers/libiberty/pex-unix.c
@@ -0,0 +1,788 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it. Generic Unix version
+ (also used for UWIN and VMS).
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2009,
+ 2010 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "libiberty.h"
+#include "pex-common.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#ifdef vfork /* Autoconf may define this to fork for us. */
+# define VFORK_STRING "fork"
+#else
+# define VFORK_STRING "vfork"
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+#if defined(VMS) && defined (__LONG_POINTERS)
+#ifndef __CHAR_PTR32
+typedef char * __char_ptr32
+__attribute__ ((mode (SI)));
+#endif
+
+typedef __char_ptr32 *__char_ptr_char_ptr32
+__attribute__ ((mode (SI)));
+
+/* Return a 32 bit pointer to an array of 32 bit pointers
+ given a 64 bit pointer to an array of 64 bit pointers. */
+
+static __char_ptr_char_ptr32
+to_ptr32 (char **ptr64)
+{
+ int argc;
+ __char_ptr_char_ptr32 short_argv;
+
+ for (argc=0; ptr64[argc]; argc++);
+
+ /* Reallocate argv with 32 bit pointers. */
+ short_argv = (__char_ptr_char_ptr32) decc$malloc
+ (sizeof (__char_ptr32) * (argc + 1));
+
+ for (argc=0; ptr64[argc]; argc++)
+ short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
+
+ short_argv[argc] = (__char_ptr32) 0;
+ return short_argv;
+
+}
+#else
+#define to_ptr32(argv) argv
+#endif
+
+/* File mode to use for private and world-readable files. */
+
+#if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
+#define PUBLIC_MODE \
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
+#else
+#define PUBLIC_MODE 0666
+#endif
+
+/* Get the exit status of a particular process, and optionally get the
+ time that it took. This is simple if we have wait4, slightly
+ harder if we have waitpid, and is a pain if we only have wait. */
+
+static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
+
+#ifdef HAVE_WAIT4
+
+static pid_t
+pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
+ struct pex_time *time)
+{
+ pid_t ret;
+ struct rusage r;
+
+#ifdef HAVE_WAITPID
+ if (time == NULL)
+ return waitpid (pid, status, 0);
+#endif
+
+ ret = wait4 (pid, status, 0, &r);
+
+ if (time != NULL)
+ {
+ time->user_seconds = r.ru_utime.tv_sec;
+ time->user_microseconds= r.ru_utime.tv_usec;
+ time->system_seconds = r.ru_stime.tv_sec;
+ time->system_microseconds= r.ru_stime.tv_usec;
+ }
+
+ return ret;
+}
+
+#else /* ! defined (HAVE_WAIT4) */
+
+#ifdef HAVE_WAITPID
+
+#ifndef HAVE_GETRUSAGE
+
+static pid_t
+pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
+ struct pex_time *time)
+{
+ if (time != NULL)
+ memset (time, 0, sizeof (struct pex_time));
+ return waitpid (pid, status, 0);
+}
+
+#else /* defined (HAVE_GETRUSAGE) */
+
+static pid_t
+pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
+ struct pex_time *time)
+{
+ struct rusage r1, r2;
+ pid_t ret;
+
+ if (time == NULL)
+ return waitpid (pid, status, 0);
+
+ getrusage (RUSAGE_CHILDREN, &r1);
+
+ ret = waitpid (pid, status, 0);
+ if (ret < 0)
+ return ret;
+
+ getrusage (RUSAGE_CHILDREN, &r2);
+
+ time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
+ time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
+ if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
+ {
+ --time->user_seconds;
+ time->user_microseconds += 1000000;
+ }
+
+ time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
+ time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
+ if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
+ {
+ --time->system_seconds;
+ time->system_microseconds += 1000000;
+ }
+
+ return ret;
+}
+
+#endif /* defined (HAVE_GETRUSAGE) */
+
+#else /* ! defined (HAVE_WAITPID) */
+
+struct status_list
+{
+ struct status_list *next;
+ pid_t pid;
+ int status;
+ struct pex_time time;
+};
+
+static pid_t
+pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
+{
+ struct status_list **pp;
+
+ for (pp = (struct status_list **) &obj->sysdep;
+ *pp != NULL;
+ pp = &(*pp)->next)
+ {
+ if ((*pp)->pid == pid)
+ {
+ struct status_list *p;
+
+ p = *pp;
+ *status = p->status;
+ if (time != NULL)
+ *time = p->time;
+ *pp = p->next;
+ free (p);
+ return pid;
+ }
+ }
+
+ while (1)
+ {
+ pid_t cpid;
+ struct status_list *psl;
+ struct pex_time pt;
+#ifdef HAVE_GETRUSAGE
+ struct rusage r1, r2;
+#endif
+
+ if (time != NULL)
+ {
+#ifdef HAVE_GETRUSAGE
+ getrusage (RUSAGE_CHILDREN, &r1);
+#else
+ memset (&pt, 0, sizeof (struct pex_time));
+#endif
+ }
+
+ cpid = wait (status);
+
+#ifdef HAVE_GETRUSAGE
+ if (time != NULL && cpid >= 0)
+ {
+ getrusage (RUSAGE_CHILDREN, &r2);
+
+ pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
+ pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
+ if ((int) pt.user_microseconds < 0)
+ {
+ --pt.user_seconds;
+ pt.user_microseconds += 1000000;
+ }
+
+ pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
+ pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
+ if ((int) pt.system_microseconds < 0)
+ {
+ --pt.system_seconds;
+ pt.system_microseconds += 1000000;
+ }
+ }
+#endif
+
+ if (cpid < 0 || cpid == pid)
+ {
+ if (time != NULL)
+ *time = pt;
+ return cpid;
+ }
+
+ psl = XNEW (struct status_list);
+ psl->pid = cpid;
+ psl->status = *status;
+ if (time != NULL)
+ psl->time = pt;
+ psl->next = (struct status_list *) obj->sysdep;
+ obj->sysdep = (void *) psl;
+ }
+}
+
+#endif /* ! defined (HAVE_WAITPID) */
+#endif /* ! defined (HAVE_WAIT4) */
+
+static void pex_child_error (struct pex_obj *, const char *, const char *, int)
+ ATTRIBUTE_NORETURN;
+static int pex_unix_open_read (struct pex_obj *, const char *, int);
+static int pex_unix_open_write (struct pex_obj *, const char *, int);
+static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
+ char * const *, char * const *,
+ int, int, int, int,
+ const char **, int *);
+static int pex_unix_close (struct pex_obj *, int);
+static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
+ int, const char **, int *);
+static int pex_unix_pipe (struct pex_obj *, int *, int);
+static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
+static void pex_unix_cleanup (struct pex_obj *);
+
+/* The list of functions we pass to the common routines. */
+
+const struct pex_funcs funcs =
+{
+ pex_unix_open_read,
+ pex_unix_open_write,
+ pex_unix_exec_child,
+ pex_unix_close,
+ pex_unix_wait,
+ pex_unix_pipe,
+ pex_unix_fdopenr,
+ pex_unix_fdopenw,
+ pex_unix_cleanup
+};
+
+/* Return a newly initialized pex_obj structure. */
+
+struct pex_obj *
+pex_init (int flags, const char *pname, const char *tempbase)
+{
+ return pex_init_common (flags, pname, tempbase, &funcs);
+}
+
+/* Open a file for reading. */
+
+static int
+pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary ATTRIBUTE_UNUSED)
+{
+ return open (name, O_RDONLY);
+}
+
+/* Open a file for writing. */
+
+static int
+pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary ATTRIBUTE_UNUSED)
+{
+ /* Note that we can't use O_EXCL here because gcc may have already
+ created the temporary file via make_temp_file. */
+ return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE);
+}
+
+/* Close a file. */
+
+static int
+pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
+{
+ return close (fd);
+}
+
+/* Report an error from a child process. We don't use stdio routines,
+ because we might be here due to a vfork call. */
+
+static void
+pex_child_error (struct pex_obj *obj, const char *executable,
+ const char *errmsg, int err)
+{
+ int retval = 0;
+#define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 0)
+ writeerr (obj->pname);
+ writeerr (": error trying to exec '");
+ writeerr (executable);
+ writeerr ("': ");
+ writeerr (errmsg);
+ writeerr (": ");
+ writeerr (xstrerror (err));
+ writeerr ("\n");
+#undef writeerr
+ /* Exit with -2 if the error output failed, too. */
+ _exit (retval == 0 ? -1 : -2);
+}
+
+/* Execute a child. */
+
+extern char **environ;
+
+#if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE)
+/* Implementation of pex->exec_child using the Cygwin spawn operation. */
+
+/* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor
+ to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the
+ saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD
+ is -1, OLD_FD is to be closed. Return -1 on error. */
+
+static int
+save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd)
+{
+ int new_fd, flags;
+
+ flags = fcntl (old_fd, F_GETFD);
+
+ /* If we could not retrieve the flags, then OLD_FD was not open. */
+ if (flags < 0)
+ {
+ new_fd = -1, flags = 0;
+ if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0)
+ return -1;
+ }
+ /* If we wish to close OLD_FD, just mark it CLOEXEC. */
+ else if (child_fd == -1)
+ {
+ new_fd = old_fd;
+ if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0)
+ return -1;
+ }
+ /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */
+ else
+ {
+#ifdef F_DUPFD_CLOEXEC
+ new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3);
+ if (new_fd < 0)
+ return -1;
+#else
+ /* Prefer F_DUPFD over dup in order to avoid getting a new fd
+ in the range 0-2, right where a new stderr fd might get put. */
+ new_fd = fcntl (old_fd, F_DUPFD, 3);
+ if (new_fd < 0)
+ return -1;
+ if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0)
+ return -1;
+#endif
+ if (dup2 (child_fd, old_fd) < 0)
+ return -1;
+ }
+
+ *pflags = flags;
+ if (pnew_fd)
+ *pnew_fd = new_fd;
+ else if (new_fd != old_fd)
+ abort ();
+
+ return 0;
+}
+
+/* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD
+ restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */
+
+static int
+restore_fd(int old_fd, int save_fd, int flags)
+{
+ /* For SAVE_FD < 0, all we have to do is restore the
+ "closed-ness" of the original. */
+ if (save_fd < 0)
+ return close (old_fd);
+
+ /* For SAVE_FD == OLD_FD, all we have to do is restore the
+ original setting of the CLOEXEC flag. */
+ if (save_fd == old_fd)
+ {
+ if (flags & FD_CLOEXEC)
+ return 0;
+ return fcntl (old_fd, F_SETFD, flags);
+ }
+
+ /* Otherwise we have to move the descriptor back, restore the flags,
+ and close the saved copy. */
+#ifdef HAVE_DUP3
+ if (flags == FD_CLOEXEC)
+ {
+ if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0)
+ return -1;
+ }
+ else
+#endif
+ {
+ if (dup2 (save_fd, old_fd) < 0)
+ return -1;
+ if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0)
+ return -1;
+ }
+ return close (save_fd);
+}
+
+static pid_t
+pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
+ int flags, const char *executable,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes, int toclose,
+ const char **errmsg, int *err)
+{
+ int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0;
+ int save_in = -1, save_out = -1, save_err = -1;
+ int max, retries;
+ pid_t pid;
+
+ if (flags & PEX_STDERR_TO_STDOUT)
+ errdes = out;
+
+ /* We need the three standard file descriptors to be set up as for
+ the child before we perform the spawn. The file descriptors for
+ the parent need to be moved and marked for close-on-exec. */
+ if (in != STDIN_FILE_NO
+ && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0)
+ goto error_dup2;
+ if (out != STDOUT_FILE_NO
+ && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0)
+ goto error_dup2;
+ if (errdes != STDERR_FILE_NO
+ && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0)
+ goto error_dup2;
+ if (toclose >= 0
+ && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0)
+ goto error_dup2;
+
+ /* Now that we've moved the file descriptors for the child into place,
+ close the originals. Be careful not to close any of the standard
+ file descriptors that we just set up. */
+ max = -1;
+ if (errdes >= 0)
+ max = STDERR_FILE_NO;
+ else if (out >= 0)
+ max = STDOUT_FILE_NO;
+ else if (in >= 0)
+ max = STDIN_FILE_NO;
+ if (in > max)
+ close (in);
+ if (out > max)
+ close (out);
+ if (errdes > max && errdes != out)
+ close (errdes);
+
+ /* If we were not given an environment, use the global environment. */
+ if (env == NULL)
+ env = environ;
+
+ /* Launch the program. If we get EAGAIN (normally out of pid's), try
+ again a few times with increasing backoff times. */
+ retries = 0;
+ while (1)
+ {
+ typedef const char * const *cc_cp;
+
+ if (flags & PEX_SEARCH)
+ pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
+ else
+ pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
+
+ if (pid > 0)
+ break;
+
+ *err = errno;
+ *errmsg = "spawn";
+ if (errno != EAGAIN || ++retries == 4)
+ return (pid_t) -1;
+ sleep (1 << retries);
+ }
+
+ /* Success. Restore the parent's file descriptors that we saved above. */
+ if (toclose >= 0
+ && restore_fd (toclose, toclose, fl_tc) < 0)
+ goto error_dup2;
+ if (in != STDIN_FILE_NO
+ && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0)
+ goto error_dup2;
+ if (out != STDOUT_FILE_NO
+ && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0)
+ goto error_dup2;
+ if (errdes != STDERR_FILE_NO
+ && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0)
+ goto error_dup2;
+
+ return pid;
+
+ error_dup2:
+ *err = errno;
+ *errmsg = "dup2";
+ return (pid_t) -1;
+}
+
+#else
+/* Implementation of pex->exec_child using standard vfork + exec. */
+
+static pid_t
+pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes,
+ int toclose, const char **errmsg, int *err)
+{
+ pid_t pid;
+
+ /* We declare these to be volatile to avoid warnings from gcc about
+ them being clobbered by vfork. */
+ volatile int sleep_interval;
+ volatile int retries;
+
+ /* We vfork and then set environ in the child before calling execvp.
+ This clobbers the parent's environ so we need to restore it.
+ It would be nice to use one of the exec* functions that takes an
+ environment as a parameter, but that may have portability issues. */
+ char **save_environ = environ;
+
+ sleep_interval = 1;
+ pid = -1;
+ for (retries = 0; retries < 4; ++retries)
+ {
+ pid = vfork ();
+ if (pid >= 0)
+ break;
+ sleep (sleep_interval);
+ sleep_interval *= 2;
+ }
+
+ switch (pid)
+ {
+ case -1:
+ *err = errno;
+ *errmsg = VFORK_STRING;
+ return (pid_t) -1;
+
+ case 0:
+ /* Child process. */
+ if (in != STDIN_FILE_NO)
+ {
+ if (dup2 (in, STDIN_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ if (close (in) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if (out != STDOUT_FILE_NO)
+ {
+ if (dup2 (out, STDOUT_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ if (close (out) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if (errdes != STDERR_FILE_NO)
+ {
+ if (dup2 (errdes, STDERR_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ if (close (errdes) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if (toclose >= 0)
+ {
+ if (close (toclose) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if ((flags & PEX_STDERR_TO_STDOUT) != 0)
+ {
+ if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ }
+
+ if (env)
+ {
+ /* NOTE: In a standard vfork implementation this clobbers the
+ parent's copy of environ "too" (in reality there's only one copy).
+ This is ok as we restore it below. */
+ environ = (char**) env;
+ }
+
+ if ((flags & PEX_SEARCH) != 0)
+ {
+ execvp (executable, to_ptr32 (argv));
+ pex_child_error (obj, executable, "execvp", errno);
+ }
+ else
+ {
+ execv (executable, to_ptr32 (argv));
+ pex_child_error (obj, executable, "execv", errno);
+ }
+
+ /* NOTREACHED */
+ return (pid_t) -1;
+
+ default:
+ /* Parent process. */
+
+ /* Restore environ.
+ Note that the parent either doesn't run until the child execs/exits
+ (standard vfork behaviour), or if it does run then vfork is behaving
+ more like fork. In either case we needn't worry about clobbering
+ the child's copy of environ. */
+ environ = save_environ;
+
+ if (in != STDIN_FILE_NO)
+ {
+ if (close (in) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+ if (out != STDOUT_FILE_NO)
+ {
+ if (close (out) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+ if (errdes != STDERR_FILE_NO)
+ {
+ if (close (errdes) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return (pid_t) -1;
+ }
+ }
+
+ return pid;
+ }
+}
+#endif /* SPAWN */
+
+/* Wait for a child process to complete. */
+
+static int
+pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status,
+ struct pex_time *time, int done, const char **errmsg,
+ int *err)
+{
+ /* If we are cleaning up when the caller didn't retrieve process
+ status for some reason, encourage the process to go away. */
+ if (done)
+ kill (pid, SIGTERM);
+
+ if (pex_wait (obj, pid, status, time) < 0)
+ {
+ *err = errno;
+ *errmsg = "wait";
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Create a pipe. */
+
+static int
+pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
+ int binary ATTRIBUTE_UNUSED)
+{
+ return pipe (p);
+}
+
+/* Get a FILE pointer to read from a file descriptor. */
+
+static FILE *
+pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary ATTRIBUTE_UNUSED)
+{
+ return fdopen (fd, "r");
+}
+
+static FILE *
+pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary ATTRIBUTE_UNUSED)
+{
+ if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
+ return NULL;
+ return fdopen (fd, "w");
+}
+
+static void
+pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
+{
+#if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
+ while (obj->sysdep != NULL)
+ {
+ struct status_list *this;
+ struct status_list *next;
+
+ this = (struct status_list *) obj->sysdep;
+ next = this->next;
+ free (this);
+ obj->sysdep = (void *) next;
+ }
+#endif
+}
diff --git a/linkers/libiberty/pex-win32.c b/linkers/libiberty/pex-win32.c
new file mode 100644
index 0000000..f1d47c7
--- /dev/null
+++ b/linkers/libiberty/pex-win32.c
@@ -0,0 +1,943 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it. Generic Win32 specialization.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "pex-common.h"
+
+#include <windows.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <assert.h>
+#include <process.h>
+#include <io.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <malloc.h>
+
+/* mingw32 headers may not define the following. */
+
+#ifndef _P_WAIT
+# define _P_WAIT 0
+# define _P_NOWAIT 1
+# define _P_OVERLAY 2
+# define _P_NOWAITO 3
+# define _P_DETACH 4
+
+# define WAIT_CHILD 0
+# define WAIT_GRANDCHILD 1
+#endif
+
+#define MINGW_NAME "Minimalist GNU for Windows"
+#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
+
+extern char *stpcpy (char *dst, const char *src);
+
+/* Ensure that the executable pathname uses Win32 backslashes. This
+ is not necessary on NT, but on W9x, forward slashes causes
+ failure of spawn* and exec* functions (and probably any function
+ that calls CreateProcess) *iff* the executable pathname (argv[0])
+ is a quoted string. And quoting is necessary in case a pathname
+ contains embedded white space. You can't win. */
+static void
+backslashify (char *s)
+{
+ while ((s = strchr (s, '/')) != NULL)
+ *s = '\\';
+ return;
+}
+
+static int pex_win32_open_read (struct pex_obj *, const char *, int);
+static int pex_win32_open_write (struct pex_obj *, const char *, int);
+static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
+ char * const *, char * const *,
+ int, int, int, int,
+ const char **, int *);
+static int pex_win32_close (struct pex_obj *, int);
+static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
+ struct pex_time *, int, const char **, int *);
+static int pex_win32_pipe (struct pex_obj *, int *, int);
+static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
+
+/* The list of functions we pass to the common routines. */
+
+const struct pex_funcs funcs =
+{
+ pex_win32_open_read,
+ pex_win32_open_write,
+ pex_win32_exec_child,
+ pex_win32_close,
+ pex_win32_wait,
+ pex_win32_pipe,
+ pex_win32_fdopenr,
+ pex_win32_fdopenw,
+ NULL /* cleanup */
+};
+
+/* Return a newly initialized pex_obj structure. */
+
+struct pex_obj *
+pex_init (int flags, const char *pname, const char *tempbase)
+{
+ return pex_init_common (flags, pname, tempbase, &funcs);
+}
+
+/* Open a file for reading. */
+
+static int
+pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary)
+{
+ return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
+}
+
+/* Open a file for writing. */
+
+static int
+pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary)
+{
+ /* Note that we can't use O_EXCL here because gcc may have already
+ created the temporary file via make_temp_file. */
+ return _open (name,
+ (_O_WRONLY | _O_CREAT | _O_TRUNC
+ | (binary ? _O_BINARY : _O_TEXT)),
+ _S_IREAD | _S_IWRITE);
+}
+
+/* Close a file. */
+
+static int
+pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
+{
+ return _close (fd);
+}
+
+#ifdef USE_MINGW_MSYS
+static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
+
+/* Tack the executable on the end of a (possibly slash terminated) buffer
+ and convert everything to \. */
+static const char *
+tack_on_executable (char *buf, const char *executable)
+{
+ char *p = strchr (buf, '\0');
+ if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
+ p[-1] = '\0';
+ backslashify (strcat (buf, executable));
+ return buf;
+}
+
+/* Walk down a registry hierarchy until the end. Return the key. */
+static HKEY
+openkey (HKEY hStart, const char *keys[])
+{
+ HKEY hKey, hTmp;
+ for (hKey = hStart; *keys; keys++)
+ {
+ LONG res;
+ hTmp = hKey;
+ res = RegOpenKey (hTmp, *keys, &hKey);
+
+ if (hTmp != HKEY_LOCAL_MACHINE)
+ RegCloseKey (hTmp);
+
+ if (res != ERROR_SUCCESS)
+ return NULL;
+ }
+ return hKey;
+}
+
+/* Return the "mingw root" as derived from the mingw uninstall information. */
+static const char *
+mingw_rootify (const char *executable)
+{
+ HKEY hKey, hTmp;
+ DWORD maxlen;
+ char *namebuf, *foundbuf;
+ DWORD i;
+ LONG res;
+
+ /* Open the uninstall "directory". */
+ hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
+
+ /* Not found. */
+ if (!hKey)
+ return executable;
+
+ /* Need to enumerate all of the keys here looking for one the most recent
+ one for MinGW. */
+ if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
+ NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+ {
+ RegCloseKey (hKey);
+ return executable;
+ }
+ namebuf = XNEWVEC (char, ++maxlen);
+ foundbuf = XNEWVEC (char, maxlen);
+ foundbuf[0] = '\0';
+ if (!namebuf || !foundbuf)
+ {
+ RegCloseKey (hKey);
+ free (namebuf);
+ free (foundbuf);
+ return executable;
+ }
+
+ /* Look through all of the keys for one that begins with Minimal GNU...
+ Try to get the latest version by doing a string compare although that
+ string never really works with version number sorting. */
+ for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
+ {
+ int match = strcasecmp (namebuf, MINGW_NAME);
+ if (match < 0)
+ continue;
+ if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
+ continue;
+ if (strcasecmp (namebuf, foundbuf) > 0)
+ strcpy (foundbuf, namebuf);
+ }
+ free (namebuf);
+
+ /* If foundbuf is empty, we didn't find anything. Punt. */
+ if (!foundbuf[0])
+ {
+ free (foundbuf);
+ RegCloseKey (hKey);
+ return executable;
+ }
+
+ /* Open the key that we wanted */
+ res = RegOpenKey (hKey, foundbuf, &hTmp);
+ RegCloseKey (hKey);
+ free (foundbuf);
+
+ /* Don't know why this would fail, but you gotta check */
+ if (res != ERROR_SUCCESS)
+ return executable;
+
+ maxlen = 0;
+ /* Get the length of the value pointed to by InstallLocation */
+ if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
+ &maxlen) != ERROR_SUCCESS || maxlen == 0)
+ {
+ RegCloseKey (hTmp);
+ return executable;
+ }
+
+ /* Allocate space for the install location */
+ foundbuf = XNEWVEC (char, maxlen + strlen (executable));
+ if (!foundbuf)
+ {
+ free (foundbuf);
+ RegCloseKey (hTmp);
+ }
+
+ /* Read the install location into the buffer */
+ res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
+ &maxlen);
+ RegCloseKey (hTmp);
+ if (res != ERROR_SUCCESS)
+ {
+ free (foundbuf);
+ return executable;
+ }
+
+ /* Concatenate the install location and the executable, turn all slashes
+ to backslashes, and return that. */
+ return tack_on_executable (foundbuf, executable);
+}
+
+/* Read the install location of msys from it's installation file and
+ rootify the executable based on that. */
+static const char *
+msys_rootify (const char *executable)
+{
+ size_t bufsize = 64;
+ size_t execlen = strlen (executable) + 1;
+ char *buf;
+ DWORD res = 0;
+ for (;;)
+ {
+ buf = XNEWVEC (char, bufsize + execlen);
+ if (!buf)
+ break;
+ res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
+ buf, bufsize, "msys.ini");
+ if (!res)
+ break;
+ if (strlen (buf) < bufsize)
+ break;
+ res = 0;
+ free (buf);
+ bufsize *= 2;
+ if (bufsize > 65536)
+ {
+ buf = NULL;
+ break;
+ }
+ }
+
+ if (res)
+ return tack_on_executable (buf, executable);
+
+ /* failed */
+ free (buf);
+ return executable;
+}
+#endif
+
+/* Return the number of arguments in an argv array, not including the null
+ terminating argument. */
+
+static int
+argv_to_argc (char *const *argv)
+{
+ char *const *i = argv;
+ while (*i)
+ i++;
+ return i - argv;
+}
+
+/* Return a Windows command-line from ARGV. It is the caller's
+ responsibility to free the string returned. */
+
+static char *
+argv_to_cmdline (char *const *argv)
+{
+ char *cmdline;
+ char *p;
+ size_t cmdline_len;
+ int i, j, k;
+
+ cmdline_len = 0;
+ for (i = 0; argv[i]; i++)
+ {
+ /* We quote every last argument. This simplifies the problem;
+ we need only escape embedded double-quotes and immediately
+ preceeding backslash characters. A sequence of backslach characters
+ that is not follwed by a double quote character will not be
+ escaped. */
+ for (j = 0; argv[i][j]; j++)
+ {
+ if (argv[i][j] == '"')
+ {
+ /* Escape preceeding backslashes. */
+ for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
+ cmdline_len++;
+ /* Escape the qote character. */
+ cmdline_len++;
+ }
+ }
+ /* Trailing backslashes also need to be escaped because they will be
+ followed by the terminating quote. */
+ for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
+ cmdline_len++;
+ cmdline_len += j;
+ cmdline_len += 3; /* for leading and trailing quotes and space */
+ }
+ cmdline = XNEWVEC (char, cmdline_len);
+ p = cmdline;
+ for (i = 0; argv[i]; i++)
+ {
+ *p++ = '"';
+ for (j = 0; argv[i][j]; j++)
+ {
+ if (argv[i][j] == '"')
+ {
+ for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
+ *p++ = '\\';
+ *p++ = '\\';
+ }
+ *p++ = argv[i][j];
+ }
+ for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
+ *p++ = '\\';
+ *p++ = '"';
+ *p++ = ' ';
+ }
+ p[-1] = '\0';
+ return cmdline;
+}
+
+/* We'll try the passed filename with all the known standard
+ extensions, and then without extension. We try no extension
+ last so that we don't try to run some random extension-less
+ file that might be hanging around. We try both extension
+ and no extension so that we don't need any fancy logic
+ to determine if a file has extension. */
+static const char *const
+std_suffixes[] = {
+ ".com",
+ ".exe",
+ ".bat",
+ ".cmd",
+ "",
+ 0
+};
+
+/* Returns the full path to PROGRAM. If SEARCH is true, look for
+ PROGRAM in each directory in PATH. */
+
+static char *
+find_executable (const char *program, BOOL search)
+{
+ char *full_executable;
+ char *e;
+ size_t fe_len;
+ const char *path = 0;
+ const char *const *ext;
+ const char *p, *q;
+ size_t proglen = strlen (program);
+ int has_slash = (strchr (program, '/') || strchr (program, '\\'));
+ HANDLE h;
+
+ if (has_slash)
+ search = FALSE;
+
+ if (search)
+ path = getenv ("PATH");
+ if (!path)
+ path = "";
+
+ fe_len = 0;
+ for (p = path; *p; p = q)
+ {
+ q = p;
+ while (*q != ';' && *q != '\0')
+ q++;
+ if ((size_t)(q - p) > fe_len)
+ fe_len = q - p;
+ if (*q == ';')
+ q++;
+ }
+ fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
+ full_executable = XNEWVEC (char, fe_len);
+
+ p = path;
+ do
+ {
+ q = p;
+ while (*q != ';' && *q != '\0')
+ q++;
+
+ e = full_executable;
+ memcpy (e, p, q - p);
+ e += (q - p);
+ if (q - p)
+ *e++ = '\\';
+ strcpy (e, program);
+
+ if (*q == ';')
+ q++;
+
+ for (e = full_executable; *e; e++)
+ if (*e == '/')
+ *e = '\\';
+
+ /* At this point, e points to the terminating NUL character for
+ full_executable. */
+ for (ext = std_suffixes; *ext; ext++)
+ {
+ /* Remove any current extension. */
+ *e = '\0';
+ /* Add the new one. */
+ strcat (full_executable, *ext);
+
+ /* Attempt to open this file. */
+ h = CreateFile (full_executable, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (h != INVALID_HANDLE_VALUE)
+ goto found;
+ }
+ p = q;
+ }
+ while (*p);
+ free (full_executable);
+ return 0;
+
+ found:
+ CloseHandle (h);
+ return full_executable;
+}
+
+/* Low-level process creation function and helper. */
+
+static int
+env_compare (const void *a_ptr, const void *b_ptr)
+{
+ const char *a;
+ const char *b;
+ unsigned char c1;
+ unsigned char c2;
+
+ a = *(const char **) a_ptr;
+ b = *(const char **) b_ptr;
+
+ /* a and b will be of the form: VAR=VALUE
+ We compare only the variable name part here using a case-insensitive
+ comparison algorithm. It might appear that in fact strcasecmp () can
+ take the place of this whole function, and indeed it could, save for
+ the fact that it would fail in cases such as comparing A1=foo and
+ A=bar (because 1 is less than = in the ASCII character set).
+ (Environment variables containing no numbers would work in such a
+ scenario.) */
+
+ do
+ {
+ c1 = (unsigned char) tolower (*a++);
+ c2 = (unsigned char) tolower (*b++);
+
+ if (c1 == '=')
+ c1 = '\0';
+
+ if (c2 == '=')
+ c2 = '\0';
+ }
+ while (c1 == c2 && c1 != '\0');
+
+ return c1 - c2;
+}
+
+/* Execute a Windows executable as a child process. This will fail if the
+ * target is not actually an executable, such as if it is a shell script. */
+
+static pid_t
+win32_spawn (const char *executable,
+ BOOL search,
+ char *const *argv,
+ char *const *env, /* array of strings of the form: VAR=VALUE */
+ DWORD dwCreationFlags,
+ LPSTARTUPINFO si,
+ LPPROCESS_INFORMATION pi)
+{
+ char *full_executable;
+ char *cmdline;
+ char **env_copy;
+ char *env_block = NULL;
+
+ full_executable = NULL;
+ cmdline = NULL;
+
+ if (env)
+ {
+ int env_size;
+
+ /* Count the number of environment bindings supplied. */
+ for (env_size = 0; env[env_size]; env_size++)
+ continue;
+
+ /* Assemble an environment block, if required. This consists of
+ VAR=VALUE strings juxtaposed (with one null character between each
+ pair) and an additional null at the end. */
+ if (env_size > 0)
+ {
+ int var;
+ int total_size = 1; /* 1 is for the final null. */
+ char *bufptr;
+
+ /* Windows needs the members of the block to be sorted by variable
+ name. */
+ env_copy = (char **) alloca (sizeof (char *) * env_size);
+ memcpy (env_copy, env, sizeof (char *) * env_size);
+ qsort (env_copy, env_size, sizeof (char *), env_compare);
+
+ for (var = 0; var < env_size; var++)
+ total_size += strlen (env[var]) + 1;
+
+ env_block = XNEWVEC (char, total_size);
+ bufptr = env_block;
+ for (var = 0; var < env_size; var++)
+ bufptr = stpcpy (bufptr, env_copy[var]) + 1;
+
+ *bufptr = '\0';
+ }
+ }
+
+ full_executable = find_executable (executable, search);
+ if (!full_executable)
+ goto error;
+ cmdline = argv_to_cmdline (argv);
+ if (!cmdline)
+ goto error;
+
+ /* Create the child process. */
+ if (!CreateProcess (full_executable, cmdline,
+ /*lpProcessAttributes=*/NULL,
+ /*lpThreadAttributes=*/NULL,
+ /*bInheritHandles=*/TRUE,
+ dwCreationFlags,
+ (LPVOID) env_block,
+ /*lpCurrentDirectory=*/NULL,
+ si,
+ pi))
+ {
+ free (env_block);
+
+ free (full_executable);
+
+ return (pid_t) -1;
+ }
+
+ /* Clean up. */
+ CloseHandle (pi->hThread);
+ free (full_executable);
+ free (env_block);
+
+ return (pid_t) pi->hProcess;
+
+ error:
+ free (env_block);
+ free (cmdline);
+ free (full_executable);
+
+ return (pid_t) -1;
+}
+
+/* Spawn a script. This simulates the Unix script execution mechanism.
+ This function is called as a fallback if win32_spawn fails. */
+
+static pid_t
+spawn_script (const char *executable, char *const *argv,
+ char* const *env,
+ DWORD dwCreationFlags,
+ LPSTARTUPINFO si,
+ LPPROCESS_INFORMATION pi)
+{
+ pid_t pid = (pid_t) -1;
+ int save_errno = errno;
+ int fd = _open (executable, _O_RDONLY);
+
+ /* Try to open script, check header format, extract interpreter path,
+ and spawn script using that interpretter. */
+ if (fd >= 0)
+ {
+ char buf[MAX_PATH + 5];
+ int len = _read (fd, buf, sizeof (buf) - 1);
+ _close (fd);
+ if (len > 3)
+ {
+ char *eol;
+ buf[len] = '\0';
+ eol = strchr (buf, '\n');
+ if (eol && strncmp (buf, "#!", 2) == 0)
+ {
+
+ /* Header format is OK. */
+ char *executable1;
+ int new_argc;
+ const char **avhere;
+
+ /* Extract interpreter path. */
+ do
+ *eol = '\0';
+ while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
+ for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
+ continue;
+ backslashify (executable1);
+
+ /* Duplicate argv, prepending the interpreter path. */
+ new_argc = argv_to_argc (argv) + 1;
+ avhere = XNEWVEC (const char *, new_argc + 1);
+ *avhere = executable1;
+ memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
+ argv = (char *const *)avhere;
+
+ /* Spawn the child. */
+#ifndef USE_MINGW_MSYS
+ executable = strrchr (executable1, '\\') + 1;
+ if (!executable)
+ executable = executable1;
+ pid = win32_spawn (executable, TRUE, argv, env,
+ dwCreationFlags, si, pi);
+#else
+ if (strchr (executable1, '\\') == NULL)
+ pid = win32_spawn (executable1, TRUE, argv, env,
+ dwCreationFlags, si, pi);
+ else if (executable1[0] != '\\')
+ pid = win32_spawn (executable1, FALSE, argv, env,
+ dwCreationFlags, si, pi);
+ else
+ {
+ const char *newex = mingw_rootify (executable1);
+ *avhere = newex;
+ pid = win32_spawn (newex, FALSE, argv, env,
+ dwCreationFlags, si, pi);
+ if (executable1 != newex)
+ free ((char *) newex);
+ if (pid == (pid_t) -1)
+ {
+ newex = msys_rootify (executable1);
+ if (newex != executable1)
+ {
+ *avhere = newex;
+ pid = win32_spawn (newex, FALSE, argv, env,
+ dwCreationFlags, si, pi);
+ free ((char *) newex);
+ }
+ }
+ }
+#endif
+ free (avhere);
+ }
+ }
+ }
+ if (pid == (pid_t) -1)
+ errno = save_errno;
+ return pid;
+}
+
+/* Execute a child. */
+
+static pid_t
+pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
+ const char *executable, char * const * argv,
+ char* const* env,
+ int in, int out, int errdes,
+ int toclose ATTRIBUTE_UNUSED,
+ const char **errmsg,
+ int *err)
+{
+ pid_t pid;
+ HANDLE stdin_handle;
+ HANDLE stdout_handle;
+ HANDLE stderr_handle;
+ DWORD dwCreationFlags;
+ OSVERSIONINFO version_info;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ int orig_out, orig_in, orig_err;
+ BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
+
+ /* Ensure we have inheritable descriptors to pass to the child, and close the
+ original descriptors. */
+ orig_in = in;
+ in = _dup (orig_in);
+ if (orig_in != STDIN_FILENO)
+ _close (orig_in);
+
+ orig_out = out;
+ out = _dup (orig_out);
+ if (orig_out != STDOUT_FILENO)
+ _close (orig_out);
+
+ if (separate_stderr)
+ {
+ orig_err = errdes;
+ errdes = _dup (orig_err);
+ if (orig_err != STDERR_FILENO)
+ _close (orig_err);
+ }
+
+ stdin_handle = INVALID_HANDLE_VALUE;
+ stdout_handle = INVALID_HANDLE_VALUE;
+ stderr_handle = INVALID_HANDLE_VALUE;
+
+ stdin_handle = (HANDLE) _get_osfhandle (in);
+ stdout_handle = (HANDLE) _get_osfhandle (out);
+ if (separate_stderr)
+ stderr_handle = (HANDLE) _get_osfhandle (errdes);
+ else
+ stderr_handle = stdout_handle;
+
+ /* Determine the version of Windows we are running on. */
+ version_info.dwOSVersionInfoSize = sizeof (version_info);
+ GetVersionEx (&version_info);
+ if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
+ /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
+ supported, so we cannot avoid creating a console window. */
+ dwCreationFlags = 0;
+ else
+ {
+ HANDLE conout_handle;
+
+ /* Determine whether or not we have an associated console. */
+ conout_handle = CreateFile("CONOUT$",
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ /*lpSecurityAttributes=*/NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ /*hTemplateFile=*/NULL);
+ if (conout_handle == INVALID_HANDLE_VALUE)
+ /* There is no console associated with this process. Since
+ the child is a console process, the OS would normally
+ create a new console Window for the child. Since we'll be
+ redirecting the child's standard streams, we do not need
+ the console window. */
+ dwCreationFlags = CREATE_NO_WINDOW;
+ else
+ {
+ /* There is a console associated with the process, so the OS
+ will not create a new console. And, if we use
+ CREATE_NO_WINDOW in this situation, the child will have
+ no associated console. Therefore, if the child's
+ standard streams are connected to the console, the output
+ will be discarded. */
+ CloseHandle(conout_handle);
+ dwCreationFlags = 0;
+ }
+ }
+
+ /* Since the child will be a console process, it will, by default,
+ connect standard input/output to its console. However, we want
+ the child to use the handles specifically designated above. In
+ addition, if there is no console (such as when we are running in
+ a Cygwin X window), then we must redirect the child's
+ input/output, as there is no console for the child to use. */
+ memset (&si, 0, sizeof (si));
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = stdin_handle;
+ si.hStdOutput = stdout_handle;
+ si.hStdError = stderr_handle;
+
+ /* Create the child process. */
+ pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
+ argv, env, dwCreationFlags, &si, &pi);
+ if (pid == (pid_t) -1)
+ pid = spawn_script (executable, argv, env, dwCreationFlags,
+ &si, &pi);
+ if (pid == (pid_t) -1)
+ {
+ *err = ENOENT;
+ *errmsg = "CreateProcess";
+ }
+
+ /* Close the standard input, standard output and standard error handles
+ in the parent. */
+
+ _close (in);
+ _close (out);
+ if (separate_stderr)
+ _close (errdes);
+
+ return pid;
+}
+
+/* Wait for a child process to complete. MS CRTDLL doesn't return
+ enough information in status to decide if the child exited due to a
+ signal or not, rather it simply returns an integer with the exit
+ code of the child; eg., if the child exited with an abort() call
+ and didn't have a handler for SIGABRT, it simply returns with
+ status == 3. We fix the status code to conform to the usual WIF*
+ macros. Note that WIFSIGNALED will never be true under CRTDLL. */
+
+static pid_t
+pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
+ int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
+ const char **errmsg, int *err)
+{
+ DWORD termstat;
+ HANDLE h;
+
+ if (time != NULL)
+ memset (time, 0, sizeof *time);
+
+ h = (HANDLE) pid;
+
+ /* FIXME: If done is non-zero, we should probably try to kill the
+ process. */
+ if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
+ {
+ CloseHandle (h);
+ *err = ECHILD;
+ *errmsg = "WaitForSingleObject";
+ return -1;
+ }
+
+ GetExitCodeProcess (h, &termstat);
+ CloseHandle (h);
+
+ /* A value of 3 indicates that the child caught a signal, but not
+ which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we
+ report SIGABRT. */
+ if (termstat == 3)
+ *status = SIGABRT;
+ else
+ *status = (termstat & 0xff) << 8;
+
+ return 0;
+}
+
+/* Create a pipe. */
+
+static int
+pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
+ int binary)
+{
+ return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
+}
+
+/* Get a FILE pointer to read from a file descriptor. */
+
+static FILE *
+pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
+ return NULL;
+ return fdopen (fd, binary ? "rb" : "r");
+}
+
+static FILE *
+pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
+ return NULL;
+ return fdopen (fd, binary ? "wb" : "w");
+}
+
+#ifdef MAIN
+#include <stdio.h>
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char const *errmsg;
+ int err;
+ argv++;
+ printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
+ exit (0);
+}
+#endif
diff --git a/linkers/libiberty/safe-ctype.c b/linkers/libiberty/safe-ctype.c
new file mode 100644
index 0000000..0972b4b
--- /dev/null
+++ b/linkers/libiberty/safe-ctype.c
@@ -0,0 +1,255 @@
+/* <ctype.h> replacement macros.
+
+ Copyright (C) 2000, 2001, 2002, 2003, 2004,
+ 2005 Free Software Foundation, Inc.
+ Contributed by Zack Weinberg <zackw@stanford.edu>.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+/*
+
+@defvr Extension HOST_CHARSET
+This macro indicates the basic character set and encoding used by the
+host: more precisely, the encoding used for character constants in
+preprocessor @samp{#if} statements (the C "execution character set").
+It is defined by @file{safe-ctype.h}, and will be an integer constant
+with one of the following values:
+
+@ftable @code
+@item HOST_CHARSET_UNKNOWN
+The host character set is unknown - that is, not one of the next two
+possibilities.
+
+@item HOST_CHARSET_ASCII
+The host character set is ASCII.
+
+@item HOST_CHARSET_EBCDIC
+The host character set is some variant of EBCDIC. (Only one of the
+nineteen EBCDIC varying characters is tested; exercise caution.)
+@end ftable
+@end defvr
+
+@deffn Extension ISALPHA (@var{c})
+@deffnx Extension ISALNUM (@var{c})
+@deffnx Extension ISBLANK (@var{c})
+@deffnx Extension ISCNTRL (@var{c})
+@deffnx Extension ISDIGIT (@var{c})
+@deffnx Extension ISGRAPH (@var{c})
+@deffnx Extension ISLOWER (@var{c})
+@deffnx Extension ISPRINT (@var{c})
+@deffnx Extension ISPUNCT (@var{c})
+@deffnx Extension ISSPACE (@var{c})
+@deffnx Extension ISUPPER (@var{c})
+@deffnx Extension ISXDIGIT (@var{c})
+
+These twelve macros are defined by @file{safe-ctype.h}. Each has the
+same meaning as the corresponding macro (with name in lowercase)
+defined by the standard header @file{ctype.h}. For example,
+@code{ISALPHA} returns true for alphabetic characters and false for
+others. However, there are two differences between these macros and
+those provided by @file{ctype.h}:
+
+@itemize @bullet
+@item These macros are guaranteed to have well-defined behavior for all
+values representable by @code{signed char} and @code{unsigned char}, and
+for @code{EOF}.
+
+@item These macros ignore the current locale; they are true for these
+fixed sets of characters:
+@multitable {@code{XDIGIT}} {yada yada yada yada yada yada yada yada}
+@item @code{ALPHA} @tab @kbd{A-Za-z}
+@item @code{ALNUM} @tab @kbd{A-Za-z0-9}
+@item @code{BLANK} @tab @kbd{space tab}
+@item @code{CNTRL} @tab @code{!PRINT}
+@item @code{DIGIT} @tab @kbd{0-9}
+@item @code{GRAPH} @tab @code{ALNUM || PUNCT}
+@item @code{LOWER} @tab @kbd{a-z}
+@item @code{PRINT} @tab @code{GRAPH ||} @kbd{space}
+@item @code{PUNCT} @tab @kbd{`~!@@#$%^&*()_-=+[@{]@}\|;:'",<.>/?}
+@item @code{SPACE} @tab @kbd{space tab \n \r \f \v}
+@item @code{UPPER} @tab @kbd{A-Z}
+@item @code{XDIGIT} @tab @kbd{0-9A-Fa-f}
+@end multitable
+
+Note that, if the host character set is ASCII or a superset thereof,
+all these macros will return false for all values of @code{char} outside
+the range of 7-bit ASCII. In particular, both ISPRINT and ISCNTRL return
+false for characters with numeric values from 128 to 255.
+@end itemize
+@end deffn
+
+@deffn Extension ISIDNUM (@var{c})
+@deffnx Extension ISIDST (@var{c})
+@deffnx Extension IS_VSPACE (@var{c})
+@deffnx Extension IS_NVSPACE (@var{c})
+@deffnx Extension IS_SPACE_OR_NUL (@var{c})
+@deffnx Extension IS_ISOBASIC (@var{c})
+These six macros are defined by @file{safe-ctype.h} and provide
+additional character classes which are useful when doing lexical
+analysis of C or similar languages. They are true for the following
+sets of characters:
+
+@multitable {@code{SPACE_OR_NUL}} {yada yada yada yada yada yada yada yada}
+@item @code{IDNUM} @tab @kbd{A-Za-z0-9_}
+@item @code{IDST} @tab @kbd{A-Za-z_}
+@item @code{VSPACE} @tab @kbd{\r \n}
+@item @code{NVSPACE} @tab @kbd{space tab \f \v \0}
+@item @code{SPACE_OR_NUL} @tab @code{VSPACE || NVSPACE}
+@item @code{ISOBASIC} @tab @code{VSPACE || NVSPACE || PRINT}
+@end multitable
+@end deffn
+
+*/
+
+#include "ansidecl.h"
+#include <safe-ctype.h>
+#include <stdio.h> /* for EOF */
+
+#if EOF != -1
+ #error "<safe-ctype.h> requires EOF == -1"
+#endif
+
+/* Shorthand */
+#define bl _sch_isblank
+#define cn _sch_iscntrl
+#define di _sch_isdigit
+#define is _sch_isidst
+#define lo _sch_islower
+#define nv _sch_isnvsp
+#define pn _sch_ispunct
+#define pr _sch_isprint
+#define sp _sch_isspace
+#define up _sch_isupper
+#define vs _sch_isvsp
+#define xd _sch_isxdigit
+
+/* Masks. */
+#define L (const unsigned short) (lo|is |pr) /* lower case letter */
+#define XL (const unsigned short) (lo|is|xd|pr) /* lowercase hex digit */
+#define U (const unsigned short) (up|is |pr) /* upper case letter */
+#define XU (const unsigned short) (up|is|xd|pr) /* uppercase hex digit */
+#define D (const unsigned short) (di |xd|pr) /* decimal digit */
+#define P (const unsigned short) (pn |pr) /* punctuation */
+#define _ (const unsigned short) (pn|is |pr) /* underscore */
+
+#define C (const unsigned short) ( cn) /* control character */
+#define Z (const unsigned short) (nv |cn) /* NUL */
+#define M (const unsigned short) (nv|sp |cn) /* cursor movement: \f \v */
+#define V (const unsigned short) (vs|sp |cn) /* vertical space: \r \n */
+#define T (const unsigned short) (nv|sp|bl|cn) /* tab */
+#define S (const unsigned short) (nv|sp|bl|pr) /* space */
+
+/* Are we ASCII? */
+#if HOST_CHARSET == HOST_CHARSET_ASCII
+
+const unsigned short _sch_istable[256] =
+{
+ Z, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */
+ C, T, V, M, M, V, C, C, /* BS HT LF VT FF CR SO SI */
+ C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */
+ S, P, P, P, P, P, P, P, /* SP ! " # $ % & ' */
+ P, P, P, P, P, P, P, P, /* ( ) * + , - . / */
+ D, D, D, D, D, D, D, D, /* 0 1 2 3 4 5 6 7 */
+ D, D, P, P, P, P, P, P, /* 8 9 : ; < = > ? */
+ P, XU, XU, XU, XU, XU, XU, U, /* @ A B C D E F G */
+ U, U, U, U, U, U, U, U, /* H I J K L M N O */
+ U, U, U, U, U, U, U, U, /* P Q R S T U V W */
+ U, U, U, P, P, P, P, _, /* X Y Z [ \ ] ^ _ */
+ P, XL, XL, XL, XL, XL, XL, L, /* ` a b c d e f g */
+ L, L, L, L, L, L, L, L, /* h i j k l m n o */
+ L, L, L, L, L, L, L, L, /* p q r s t u v w */
+ L, L, L, P, P, P, P, C, /* x y z { | } ~ DEL */
+
+ /* high half of unsigned char is locale-specific, so all tests are
+ false in "C" locale */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+const unsigned char _sch_tolower[256] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64,
+
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+
+ 91, 92, 93, 94, 95, 96,
+
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+
+ 123,124,125,126,127,
+
+ 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
+ 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
+ 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175,
+ 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191,
+
+ 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
+ 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
+ 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
+ 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255,
+};
+
+const unsigned char _sch_toupper[256] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64,
+
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+
+ 91, 92, 93, 94, 95, 96,
+
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+
+ 123,124,125,126,127,
+
+ 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
+ 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
+ 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175,
+ 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191,
+
+ 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
+ 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
+ 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
+ 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255,
+};
+
+#else
+# if HOST_CHARSET == HOST_CHARSET_EBCDIC
+ #error "FIXME: write tables for EBCDIC"
+# else
+ #error "Unrecognized host character set"
+# endif
+#endif
diff --git a/linkers/libiberty/safe-ctype.h b/linkers/libiberty/safe-ctype.h
new file mode 100644
index 0000000..0266bf1
--- /dev/null
+++ b/linkers/libiberty/safe-ctype.h
@@ -0,0 +1,150 @@
+/* <ctype.h> replacement macros.
+
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Zack Weinberg <zackw@stanford.edu>.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+/* This is a compatible replacement of the standard C library's <ctype.h>
+ with the following properties:
+
+ - Implements all isxxx() macros required by C99.
+ - Also implements some character classes useful when
+ parsing C-like languages.
+ - Does not change behavior depending on the current locale.
+ - Behaves properly for all values in the range of a signed or
+ unsigned char.
+
+ To avoid conflicts, this header defines the isxxx functions in upper
+ case, e.g. ISALPHA not isalpha. */
+
+#ifndef SAFE_CTYPE_H
+#define SAFE_CTYPE_H
+
+/* Determine host character set. */
+#define HOST_CHARSET_UNKNOWN 0
+#define HOST_CHARSET_ASCII 1
+#define HOST_CHARSET_EBCDIC 2
+
+#if '\n' == 0x0A && ' ' == 0x20 && '0' == 0x30 \
+ && 'A' == 0x41 && 'a' == 0x61 && '!' == 0x21
+# define HOST_CHARSET HOST_CHARSET_ASCII
+#else
+# if '\n' == 0x15 && ' ' == 0x40 && '0' == 0xF0 \
+ && 'A' == 0xC1 && 'a' == 0x81 && '!' == 0x5A
+# define HOST_CHARSET HOST_CHARSET_EBCDIC
+# else
+# define HOST_CHARSET HOST_CHARSET_UNKNOWN
+# endif
+#endif
+
+/* Categories. */
+
+enum {
+ /* In C99 */
+ _sch_isblank = 0x0001, /* space \t */
+ _sch_iscntrl = 0x0002, /* nonprinting characters */
+ _sch_isdigit = 0x0004, /* 0-9 */
+ _sch_islower = 0x0008, /* a-z */
+ _sch_isprint = 0x0010, /* any printing character including ' ' */
+ _sch_ispunct = 0x0020, /* all punctuation */
+ _sch_isspace = 0x0040, /* space \t \n \r \f \v */
+ _sch_isupper = 0x0080, /* A-Z */
+ _sch_isxdigit = 0x0100, /* 0-9A-Fa-f */
+
+ /* Extra categories useful to cpplib. */
+ _sch_isidst = 0x0200, /* A-Za-z_ */
+ _sch_isvsp = 0x0400, /* \n \r */
+ _sch_isnvsp = 0x0800, /* space \t \f \v \0 */
+
+ /* Combinations of the above. */
+ _sch_isalpha = _sch_isupper|_sch_islower, /* A-Za-z */
+ _sch_isalnum = _sch_isalpha|_sch_isdigit, /* A-Za-z0-9 */
+ _sch_isidnum = _sch_isidst|_sch_isdigit, /* A-Za-z0-9_ */
+ _sch_isgraph = _sch_isalnum|_sch_ispunct, /* isprint and not space */
+ _sch_iscppsp = _sch_isvsp|_sch_isnvsp, /* isspace + \0 */
+ _sch_isbasic = _sch_isprint|_sch_iscppsp /* basic charset of ISO C
+ (plus ` and @) */
+};
+
+/* Character classification. */
+extern const unsigned short _sch_istable[256];
+
+#define _sch_test(c, bit) (_sch_istable[(c) & 0xff] & (unsigned short)(bit))
+
+#define ISALPHA(c) _sch_test(c, _sch_isalpha)
+#define ISALNUM(c) _sch_test(c, _sch_isalnum)
+#define ISBLANK(c) _sch_test(c, _sch_isblank)
+#define ISCNTRL(c) _sch_test(c, _sch_iscntrl)
+#define ISDIGIT(c) _sch_test(c, _sch_isdigit)
+#define ISGRAPH(c) _sch_test(c, _sch_isgraph)
+#define ISLOWER(c) _sch_test(c, _sch_islower)
+#define ISPRINT(c) _sch_test(c, _sch_isprint)
+#define ISPUNCT(c) _sch_test(c, _sch_ispunct)
+#define ISSPACE(c) _sch_test(c, _sch_isspace)
+#define ISUPPER(c) _sch_test(c, _sch_isupper)
+#define ISXDIGIT(c) _sch_test(c, _sch_isxdigit)
+
+#define ISIDNUM(c) _sch_test(c, _sch_isidnum)
+#define ISIDST(c) _sch_test(c, _sch_isidst)
+#define IS_ISOBASIC(c) _sch_test(c, _sch_isbasic)
+#define IS_VSPACE(c) _sch_test(c, _sch_isvsp)
+#define IS_NVSPACE(c) _sch_test(c, _sch_isnvsp)
+#define IS_SPACE_OR_NUL(c) _sch_test(c, _sch_iscppsp)
+
+/* Character transformation. */
+extern const unsigned char _sch_toupper[256];
+extern const unsigned char _sch_tolower[256];
+#define TOUPPER(c) _sch_toupper[(c) & 0xff]
+#define TOLOWER(c) _sch_tolower[(c) & 0xff]
+
+/* Prevent the users of safe-ctype.h from accidently using the routines
+ from ctype.h. Initially, the approach was to produce an error when
+ detecting that ctype.h has been included. But this was causing
+ trouble as ctype.h might get indirectly included as a result of
+ including another system header (for instance gnulib's stdint.h).
+ So we include ctype.h here and then immediately redefine its macros. */
+
+#include <ctype.h>
+#undef isalpha
+#define isalpha(c) do_not_use_isalpha_with_safe_ctype
+#undef isalnum
+#define isalnum(c) do_not_use_isalnum_with_safe_ctype
+#undef iscntrl
+#define iscntrl(c) do_not_use_iscntrl_with_safe_ctype
+#undef isdigit
+#define isdigit(c) do_not_use_isdigit_with_safe_ctype
+#undef isgraph
+#define isgraph(c) do_not_use_isgraph_with_safe_ctype
+#undef islower
+#define islower(c) do_not_use_islower_with_safe_ctype
+#undef isprint
+#define isprint(c) do_not_use_isprint_with_safe_ctype
+#undef ispunct
+#define ispunct(c) do_not_use_ispunct_with_safe_ctype
+#undef isspace
+#define isspace(c) do_not_use_isspace_with_safe_ctype
+#undef isupper
+#define isupper(c) do_not_use_isupper_with_safe_ctype
+#undef isxdigit
+#define isxdigit(c) do_not_use_isxdigit_with_safe_ctype
+#undef toupper
+#define toupper(c) do_not_use_toupper_with_safe_ctype
+#undef tolower
+#define tolower(c) do_not_use_tolower_with_safe_ctype
+
+#endif /* SAFE_CTYPE_H */
diff --git a/linkers/libiberty/stpcpy.c b/linkers/libiberty/stpcpy.c
new file mode 100644
index 0000000..57b32d1
--- /dev/null
+++ b/linkers/libiberty/stpcpy.c
@@ -0,0 +1,43 @@
+/* Implement the stpcpy function.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+/*
+
+@deftypefn Supplemental char* stpcpy (char *@var{dst}, const char *@var{src})
+
+Copies the string @var{src} into @var{dst}. Returns a pointer to
+@var{dst} + strlen(@var{src}).
+
+@end deftypefn
+
+*/
+
+#include <ansidecl.h>
+#include <stddef.h>
+
+extern size_t strlen (const char *);
+extern PTR memcpy (PTR, const PTR, size_t);
+
+char *
+stpcpy (char *dst, const char *src)
+{
+ const size_t len = strlen (src);
+ return (char *) memcpy (dst, src, len + 1) + len;
+}
diff --git a/linkers/main-page.cpp b/linkers/main-page.cpp
new file mode 100644
index 0000000..70d9b04
--- /dev/null
+++ b/linkers/main-page.cpp
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2011-2013, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @mainpage RTEMS Linker Tools
+ *
+ * The RTEMS Linker is a suite of tools that create and manage @subpage rtems-apps
+ * that are dynamically loadable by the @subpage rtems-rtl on target
+ * hardware. The target code uses the standard `dlopen`, `dlclose` type calls
+ * to load and manage modules, object files or archives on the target at
+ * runtime. The RTEMS Linker forms a part of this process by helping managing
+ * the object files, libraries and applications on a host machine. This host
+ * processing simplifies the demands on the target and avoids wastefull excess
+ * of files and data that may not be used at runtime.
+ *
+ * These tools are written in C++ with some 3rd party packages in C. The
+ * license for this RTEMS Tools code is a BSD type open source license. The
+ * package includes code from:
+ *
+ * -# @b efltoolchain - http://sourceforge.net/apps/trac/elftoolchain/
+ * -# @b libiberty - Libiberty code from GCC (GPL)
+ * -# @b fastlz - http://fastlz.org/
+ *
+ * The project uses a C++ demangler and PEX code from the GCC project. This
+ * code is GPL making this project GPL. A platform independent way to execute
+ * sub-processes and capture the output that is not GPL is most welcome.
+ *
+ * @subpage build-me details building this package with @subpage waf.
+ *
+ * The tools provided are:
+ *
+ * - @subpage rtems-ld
+ * - @subpage rtems-syms
+ * - @subpage rtems-rap
+ *
+ * ____________________________________________________________________________
+ * @copyright
+ * Copyright (c) 2011-2013, Chris Johns <chrisj@rtems.org>
+ * @copyright
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * @copyright
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/**
+ * @page rtems-apps RTEMS Applications
+ *
+ * The RTEMS Linker and @ref rtems-rtl provides RTEMS with the ability to
+ * support applications loaded and linked at runtime. RTEMS is a single address
+ * space real-time operating system designed for embedded systems that are
+ * statically linked therefore the idea of applications requires some extra
+ * understanding when applied to RTEMS. They are not essential, rather they are
+ * important in a range of systems that have the resources available to support
+ * them.
+ *
+ * Applications allow:
+ *
+ * - A team to create a single verified base kernel image that is used by all
+ * team developers. This kernel could be embedded on the target hardware and
+ * applications loaded over a network. The verified kernel binary used during
+ * development can be shipped without being changed.
+ *
+ * - Layered applications designed as modules that are loaded at runtime to
+ * create a specific target environment for a specific system. This approach
+ * allows development of modules that become verified components. An example
+ * is the NASA Core Flight Executive.
+ *
+ * - Runtime configuration and loading of features or drivers based on
+ * configuration data or detected hardware. This is important if your target
+ * hardware has an external bus such as PCI. You can add a new driver to a
+ * system without needing to rebuild the kernel and application lowering the
+ * verify and validation costs. If these are high the savings can be
+ * substantial.
+ *
+ * RTEMS is a single address space operating system therefore any code loaded
+ * is loaded into that address space. This means applications are not operating
+ * in a separate protected address space you typically get with host type
+ * operating systems. You need to control and manage what you allow to load on
+ * your system. This is no differerent to how single image RTEMS are currently
+ * created and managed. The point being RTEMS applications only changes the way
+ * you package and maintain your applications and do not provide any improved
+ * security or protection. You need to do this as your currently do with
+ * testing and careful design.
+ *
+ * RTEMS is statically linked to a fixed address and does not support dynamic
+ * ELF files. Dynamic ELF files are designed for use in virtual memory
+ * protected address space operating systems. They contain Position Independent
+ * Code (PIC) code, Procedure Linkage Tables (PLT) and Global Offset Tables
+ * (GOT) and are effective in not only allowing dynamic linking at runtime but
+ * also the sharing of the code between separate process address spaces. Using
+ * virtual memory and a memory management unit, a protected address space
+ * operating system can efficiently share code between processes with minimal
+ * performance overhead. RTEMS has no such need because it is a single address
+ * space and all code is shared therefore ELF dynamic files only add complexity
+ * and performance overhead. This means RTEMS needs a target based run-time
+ * link editor that can relocate and fix up static code when loading it and
+ * RTEMS loadable files need to contain the symbols and relocation records to
+ * allow relocation to happen.
+ *
+ * The @ref rtems-rtl supports the followiing file formats:
+ *
+ * -# Relocatable ELF (ELF)
+ * -# RTEMS Application (RAP)
+ * -# Archive (AR) Libraries with GNU extensions
+ *
+ * ### Relocation ELF Files
+ *
+ * The @ref rtems-rtl can load standard relocatable ELF format files. They can
+ * be stripped or unstripped. This ELF file is the standard output from the
+ * compiler and is contained in the standard libraries.
+ *
+ * ### RTEMS Application (RAP) Files.
+ *
+ * The @ref rtems-rtl can load RAP format files. This format is RTEMS specific
+ * and is designed to minimise the overhead and resources needed to load the
+ * file on the target. A RAP file is compressed using LZ77 compression and
+ * contains only the following sections:
+ *
+ * - `.text` - The executable code section.
+ * - `.const` - The constants and strings section.
+ * - `.ctor` - The constructor table section.
+ * - `.dtor` - The destructor table section.
+ * - `.data` - The initialised data section.
+ *
+ * The `.bss` uninitialised data section is only a size. A RAP file also
+ * contains a symbol string table and symbol table that are directly loadable
+ * into into the target memory. Finally the RAP contains the relocation
+ * records. The format is structured so it can be read and processed as a
+ * stream with the need to seek on the file.
+ *
+ * The @ref rtems-ld can output RAP format files suitable for loading. It will
+ * take the object files from the command line and the referenced files from
+ * the libraries and merge all the sections, symbols and relocation records to
+ * create the RAP format file.
+ *
+ * RAP format files are the most efficient way to load applications or modules
+ * because all object files are merged into an single image. Each file loaded
+ * on the target has and overhead therefore lowering the number of files loaded
+ * lowers the overhead. You could also use the standard linker to incrementally
+ * link the command line object files to archieve the same effect.
+ *
+ * ### Archive (AR) Library Files
+ *
+ * The @ref rtems-rtl can load from archive ior library type files. The file
+ * name syntax lets a user reference a file in an archive. The format is:
+ *
+ * @par
+ * `libme.a:foo.o@12345`
+ *
+ * where `libme.a` is the archive file name, `foo.o` is the file in the archive
+ * and `@12345` is optionally the offset in the archive where the file
+ * starts. The optional offset helps speed up load by avoiding the file name
+ * table search. If the archive is stable and known the offset will be
+ * fixed. If the file is located at the offset the file name table is searched.
+ *
+ * At this point in time only ELF files can be loaded from archives. Loading of
+ * RAP format files is planned.
+ *
+ * ## An Application
+ *
+ * Applications are created the same way you create standard host type
+ * programs. You compile the source files and link them using the @ref
+ * rtems-ld.
+ *
+ * @code
+ * $ rtems-ld --base my-rtems foo.o bar.o -o my-app.rap -L /lib/path -lstuff
+ * @endcode
+ *
+ * The command line of the @ref rtems-ld is similar to a standard linker with
+ * some extra features specific to RTEMS. You provide a list of object files,
+ * libraries and library paths plus you need to provide the RTEMS kernel image
+ * you will use to load the application. The RTEMS kernel image provides the
+ * symbols in the kernel to the linker. Errors will be generated if symbols are
+ * not located.
+ *
+ * The linker can output a archive of ELF files, a RAP file for a text script
+ * of files that need to be loaded.
+ *
+ * The script lets you load and link the application at runtime on the
+ * target. You need to copy the libraries referenced to the target.
+ *
+ * If you break your application into separate modules and each module
+ * references a symbol in a library that is not in the base image the linker
+ * will include the object file containing the symbol into each application
+ * module. This is only of concern for the RAP format because it merges the
+ * object files together. With the archive and scripts the loader will not load
+ * object files with duplicate symbols.
+ *
+ * @note In time the linker will gain an option to not pull object modules from
+ * libraries into the RAP file. Another option will be added that will
+ * copy referenced library object files into a target library all
+ * application modules can share.
+ *
+ * ## Linking
+ *
+ * The @ref rtems-ld places the command line object files in the output image
+ * and any reference object files found in libraries. If a symbol is located in
+ * the kernel base image it is not searched for in the libraries.
+ *
+ * The architecture is automatically detected by inspecting the first object
+ * file passed on the command line. All future object files loaded must match
+ * the architecture for an error is raised. The linker supports all
+ * architectures in a single binrary. It is not like the GNU tools which are
+ * specific to an architecture.
+ *
+ * The linker needs to be able to locate the C compiler for the architecture
+ * being linked. The compiler can be in the path for a command line option can
+ * explicitly set the compiler. The compiler is used to locate the standard
+ * libraries such as the C library.
+ *
+ *
+ */
+
+/**
+ * @page rtems-rtl RTEMS Target Link Editor
+ *
+ * The RTEMS Target link editor is a C module you link to the RTEMS kernel to
+ * provide the `dlopen`, `dlclose` etc family of calls. This code is a stand
+ * alone project:
+ *
+ * @par
+ * http://git.rtems.org/chrisj/rtl.git
+ */
+
+/**
+ * @page build-me Building The RTEMS Linker
+ *
+ * This package is written in C++ therefore you need a current working C++
+ * compiler for your host. The GCC or clang compilers can be used and clang was
+ * used during the development. The build system is @ref waf.
+ *
+ * -# Clone the git repository:
+ * @code
+ * $ git clone http://git.rtems.org/chrisj/rtl-host.git rtl-host.git
+ * @endcode
+ * -# Configure with the default C++ compiler, default options, and an install
+ * prefix of `$HOME/development/rtems/4.11`:
+ * @code
+ * $ waf configure --prefix=$HOME/development/rtems/4.11
+ * @endcode
+ * With @ref waf you build in the source directory and the @ref waf script
+ * (`wscript`) will create a host specific directory. On MacOS the output is in
+ * `build-darwin`. If you clean the build tree by deleting this directly you
+ * will need to run the configure stage again.
+ * @note The nominal RTEMS prefix is `/opt/rtems-4.11` where `4.11` is the
+ * version of RTEMS you are building the tools for. If you are using
+ * RTEMS 4.10 or a different version please use that version number. I
+ * always work under my home directory and under the `development/rtems`
+ * tree and then use the version number.
+ * -# Build the tools:
+ * @code
+ * $ waf
+ * @endcode
+ * -# Install the tools to the configured prefix:
+ * @code
+ * $ waf install
+ * @endcode
+ *
+ * You will now have the tools contained in this package build and installed.
+ *
+ * At this stage of the project's development there are no tests. I am wondering
+ * if this could be a suitable GSoC project.
+ *
+ * To build with `clang` use the documented @ref waf method:
+ * @code
+ * $ CC=clang waf configure --prefix=$HOME/development/rtems/4.11
+ * @endcode
+ *
+ * You can add some extra options to @ref waf's configure to change the
+ * configuration. The options are:
+ * @code
+ * --rtems-version=RTEMS_VERSION
+ * Set the RTEMS version
+ * --c-opts=C_OPTS Set build options, default: -O2.
+ * --show-commands Print the commands as strings.
+ * @endcode
+ *
+ * - @b --rtems-version Set the RTEMS version number.
+ * Not used.
+ * - @b --c-opts Set the C and C++ compiler flags the tools are built with. For
+ * example to disable all optimization flags to allow better debugging do:
+ * @code
+ * $ waf configure --prefix=$HOME/development/rtems/4.11 --c-opts=
+ * @endcode
+ * - @b --show-commands Prints the command string used to the invoke the
+ * compiler or linker. @ref waf normally prints a summary type line.
+ *
+ */
+
+/**
+ * @page waf Waf
+ *
+ * It is best you install waf by just downloading it from the Waf project
+ * website:
+ *
+ * @par
+ * http://code.google.com/p/waf/
+ *
+ * Waf is a Python program so you will also need to have a current Python
+ * version installed and in your path.
+ *
+ * I download the latest "run from writable folder" version named single waf
+ * file from http://code.google.com/p/waf/downloads/list to `$HOME/bin` and
+ * symlink it to `waf`. The directory `$HOME/bin` is in my path.
+ *
+ * @code
+ * $ cd $HOME/bin
+ * $ curl http://waf.googlecode.com/files/waf-1.7.9 > waf-1.7.9
+ * % Total % Received % Xferd Average Speed Time Time Time Current
+ * Dload Upload Total Spent Left Speed
+ * 100 90486 100 90486 0 0 39912 0 0:00:02 0:00:02 --:--:-- 79934
+ * $ rm -f waf
+ * $ chmod +x waf-1.7.9
+ * $ ln -s waf-1.7.9 waf
+ * $ ./waf --version
+ * waf 1.7.9 (9e92489dbc008e4abae9c147b1d63b48296797c2)
+ * @endcode
+ */
+
+/**
+ * @page rtems-ld RTEMS Linker
+ *
+ * The RTEMS Linker is a single tool that lets you create applications. It is a
+ * special kind of linker and does not perform all the functions found in a
+ * normal linker. RAP format output performs a partial increment link.
+ *
+ * ## Command
+ *
+ * `rtems-ld [options] objects`
+ *
+ * ## Options
+ *
+ * - @e Help (@b -h @b --help): \n
+ * Print the command line help then exit.
+ *
+ * - @e Version (@b -V @b --version): \n
+ * Print the linker's version then exit.
+ *
+ * - @e Verbose (@b -v @b --verbose): \n
+ * Control the trace output level. The RTEMS linker is always built with
+ * trace logic. The more times this appears on the command the more detailed
+ * the output becomes. The amount of output can be large at higher levels.
+ *
+ * - @e Warnings (@b -w @--warn): \n
+ * Print warnings.
+ *
+ * - @e Map (@b -M @b --map): \n
+ * Generate map output to stdout.
+ *
+ * - @e Output (@b -o @b --output): \n
+ * Set the output file name.
+ *
+ * - @e Output @e Format (@b -O @b --out-format): \n
+ * Set the output format. The valid formats are:
+ * Format | Description
+ * -----------|----------------------------------------
+ * @b rap |RTEMS application (LZ77, single image)
+ * @b elf |ELF application (script, ELF files)
+ * @b script |Script format (list of object files)
+ * @b archive |Archive format (collection of ELF files)
+ *
+ * - @e Library @e Path (@b -L @b --lib-path): \n
+ * Add a library path. More than one path can be added with multiple library
+ * path options.
+ *
+ * - @e Library (@b -l @b --lib): \n
+ * Add a library. More than one library can be added with multiple library
+ * paths.
+ *
+ * - @e No @e Standard @e Libraries (@b -n @b --no-stdlibs): \n
+ * Do not search the standard libraries. The linker uses the architecture C
+ * compiler to locate the installed standard libraries and these are
+ * automatically searched. If this option is used the C compiler is not
+ * called and the libraries are not added to the search list.
+ *
+ * - @e Entry @e Point (@b -e @b --entry): \n
+ * Set the entry point. This is used with the RAP format and defaults to
+ * `rtems`. The entry point is called when a RAP file is loaded by the
+ * target RAP loader.
+ *
+ * - @e Define @e Symbol (@b -d @b --define): \n
+ * Add a symbol to the symbol table. More than one symbol can be added
+ * with multiple define options.
+ *
+ * - @e Undefined @e Symbol (@b -u @b --undefined): \n
+ * Add an undefined symbol to the undefined symbol list. More than one
+ * undefined symbol can be added with multiple undefined options. This
+ * options will pull specific code into the output image.
+ *
+ * - @e RTEMS @e Kernel (@b -b @b --base): \n
+ * Set the RTEMS kernel image. This is the ELF file of the RTEMS kernel
+ * that will load the output from the linker. The RTEMS kernel is the
+ * @e base module or image. The linker does not pull the symbol from a
+ * library if the symbol is found in the base module. The kernel will
+ * load the target symbol table with these symbols so they can be
+ * resolved at runtime.
+ *
+ * - @e Architecture @e C @e Compiler (@b -C @b --cc): \n
+ * Set the architecture's C compiler. This is used to find the standard
+ * libraries.
+ *
+ * - @e Tool @e Prefix (@b -E @b --exec-prefix): \n
+ * Set the tool prefix. The tool prefix is the architecture and this is
+ * normally automatically set by inspecting the first object file
+ * loaded. This option allows the automatic detection to be overridden.
+ *
+ * - @e Machine @e Architecture (@b -a @b --march): \n
+ * Set the machine architecture.
+ *
+ * - @e Machine @e CPU (@b -c @b --mcpu): \n
+ * Set the machine architecture's CPU.
+ */
+
+/**
+ * @page rtems-syms RTEMS Symbols Utility
+ *
+ * The symbols tool lets you see symbols in various RTEMS support file formats.
+ */
+
+/**
+ * @page rtems-rap RTEMS Application (RAP) Utility
+ *
+ * The symbols tool lets you see symbols in various RTEMS support file formats.
+ */
diff --git a/linkers/mkapp.sh b/linkers/mkapp.sh
new file mode 100755
index 0000000..4954ab2
--- /dev/null
+++ b/linkers/mkapp.sh
@@ -0,0 +1,47 @@
+#! /bin/sh
+#
+# Make an application using the object files in the RTL application.
+# Please build the RTL application first.
+#
+
+if [ $# -ne 2 ]; then
+ echo "error: bad arguments: ./mkapp <path to RTL app> <path to C compiler>"
+ exit 2
+fi
+
+if [ ! -d $1 ]; then
+ echo "error: not a directory: $1"
+ exit 3
+fi
+
+if [ ! -f $2 ]; then
+ echo "error: not a file: $2"
+ exit 3
+fi
+
+o1="$1/xa.c.1.o"
+o2="$1/x-long-name-to-create-gnu-extension-in-archive.c.1.o"
+
+if [ ! -e ${o1} ]; then
+ echo "error: cannot find: ${o1}"
+ exit 4
+fi
+
+if [ ! -e ${o2} ]; then
+ echo "error: cannot find: ${o2}"
+ exit 4
+fi
+
+case $(uname -s) in
+ Darwin) platform="darwin" ;;
+ Linux) platform="linux2" ;;
+ WIN32) platform="win32" ;;
+ *)
+ echo "error: unsupported platform"
+ exit 5
+esac
+
+echo "./build-${platform}/rtems-ld -S --base $1/rtld --cc $2 -o rtl-app.rap ${o1} ${o2}"
+./build-${platform}/rtems-ld -S --base $1/rtld --cc $2 -o rtl-app.rap ${o1} ${o2}
+
+exit 0
diff --git a/linkers/pkgconfig.cpp b/linkers/pkgconfig.cpp
new file mode 100644
index 0000000..8481140
--- /dev/null
+++ b/linkers/pkgconfig.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <algorithm>
+#include <fstream>
+#include <string>
+
+#include <pkgconfig.h>
+
+namespace pkgconfig
+{
+ void tolower (std::string& str)
+ {
+ std::transform (str.begin (), str.end (), str.begin (), ::tolower);
+ }
+
+ package::package (void)
+ {
+ }
+
+ void
+ package::load (const std::string& name)
+ {
+ std::ifstream in (name.c_str (), std::ios::in);
+
+ while (!in.eof ())
+ {
+ char buffer[1024];
+
+ in.getline (buffer, sizeof (buffer));
+
+ std::string line (buffer);
+ size_t hash;
+
+ hash = line.find ('#');
+ if (hash != std::string::npos)
+ line.erase(hash);
+
+ if (line.size () > 0)
+ {
+ size_t eq = line.find_first_of ('=');
+ size_t dd = line.find_first_of (':');
+
+ size_t d = std::string::npos;
+ bool def = false;
+
+ if ((eq != std::string::npos) && (dd != std::string::npos))
+ {
+ if (eq < dd)
+ {
+ d = eq;
+ def = true;
+ }
+ else
+ {
+ d = dd;
+ def = false;
+ }
+ }
+ else if (eq != std::string::npos)
+ {
+ d = eq;
+ def = true;
+ }
+ else if (dd != std::string::npos)
+ {
+ d = dd;
+ def = false;
+ }
+
+ if (d != std::string::npos)
+ {
+ std::string lhs = line.substr (0, d);
+ std::string rhs = line.substr (d + 1);
+
+ tolower (lhs);
+
+ if (def)
+ defines[lhs] = rhs;
+ else
+ fields[lhs] = rhs;
+ }
+ }
+ }
+
+ in.close ();
+ }
+
+ bool
+ package::get (const std::string& label, std::string& result)
+ {
+ result.erase ();
+
+ std::string ll = label;
+ tolower (ll);
+
+ table::iterator ti = fields.find (ll);
+
+ if (ti == fields.end ())
+ return false;
+
+ /*
+ * Take a copy so we can expand the macros in it.
+ */
+ std::string s = ti->second;
+
+ /*
+ * Loop until there is nothing more to expand.
+ */
+ bool expanded = true;
+ while (expanded)
+ {
+ /*
+ * Need to perform a regular expression search for '\$\{[^\}]+\}'. This
+ * means look for every '${' then accept any character that is not a '}'
+ * and finish with a '}'.
+ */
+ size_t p = 0;
+ while (p < s.length ())
+ {
+ /*
+ * Find the start and end of the label.
+ */
+ size_t ms = s.find ("${", p);
+ if (ms != std::string::npos)
+ {
+ size_t me = s.find ('}', ms);
+ if (me != std::string::npos)
+ {
+ std::string ml = s.substr (ms, me);
+
+ }
+ }
+ else
+ {
+ p = s.length ();
+ }
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/linkers/pkgconfig.h b/linkers/pkgconfig.h
new file mode 100644
index 0000000..93c0972
--- /dev/null
+++ b/linkers/pkgconfig.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined (_PKGCONFIG_H_)
+#define _PKGCONFIG_H_
+
+#include <map>
+#include <string>
+
+namespace pkgconfig
+{
+ /**
+ * A simple class to parse a pkgconfig file as used in RTEMS. The RTEMS use
+ * is simple and basically provides a simplified method to manage the various
+ * flags used to build and link modules for a specific BSP.
+ */
+ class package
+ {
+ public:
+ /**
+ * The type of defines and fields parsed from a package config file.
+ */
+ typedef std::map < std::string, std::string > table;
+
+ package ();
+
+ /**
+ * Load a package configuration file.
+ *
+ * @param name The file name of the package.
+ */
+ void load (const std::string& name);
+
+ /**
+ * Get a field from the package.
+ *
+ * @param label The label to search for.
+ * @param result The result of the search.
+ * @retval true The field was found.
+ * @retval false The field was not found.
+ */
+ bool get (const std::string& label, std::string& result);
+
+ private:
+ table defines; ///< The defines.
+ table fields; ///< The fields.
+
+ };
+
+}
+
+#endif
diff --git a/linkers/rld-cc.cpp b/linkers/rld-cc.cpp
new file mode 100644
index 0000000..38d3093
--- /dev/null
+++ b/linkers/rld-cc.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include <fstream>
+
+#include <rld.h>
+#include <rld-cc.h>
+#include <rld-process.h>
+
+namespace rld
+{
+ namespace cc
+ {
+ std::string cc;
+ std::string exec_prefix;
+ std::string march;
+ std::string mcpu;
+ std::string install_path;
+ std::string programs_path;
+ std::string libraries_path;
+
+ /**
+ * The list of standard libraries.
+ */
+ #define RPS RLD_PATHSTR_SEPARATOR_STR
+ static const char* std_lib_c = "libgcc.a" RPS "libssp.a" RPS "libc.a";
+ static const char* std_lib_cplusplus = "libstdc++.a";
+
+ static void
+ make_cc_command (rld::process::arg_container& args)
+ {
+ /*
+ * Use the absolute path to CC is provided.
+ */
+ if (!cc.empty ())
+ args.push_back (cc);
+ else
+ {
+ std::string cmd = "gcc";
+ if (!exec_prefix.empty ())
+ cmd = exec_prefix + "-rtems" + rld::rtems_version () + '-' + cmd;
+ args.push_back (cmd);
+ }
+ if (!march.empty ())
+ args.push_back ("-march=" + march);
+ if (!mcpu.empty ())
+ args.push_back ("-mcpu=" + mcpu);
+ }
+
+ static bool
+ match_and_trim (const char* prefix, std::string& line, std::string& result)
+ {
+ std::string::size_type pos = ::strlen (prefix);
+ if (line.substr (0, pos) == prefix)
+ {
+ if (line[pos] == '=')
+ ++pos;
+ result = line.substr (pos, line.size () - pos - 1);
+ return true;
+ }
+ return false;
+ }
+
+ static void
+ search_dirs ()
+ {
+ rld::process::arg_container args;
+
+ make_cc_command (args);
+ args.push_back ("-print-search-dirs");
+
+ rld::process::tempfile out;
+ rld::process::tempfile err;
+ rld::process::status status;
+
+ status = rld::process::execute ("gcc", args, out.name (), err.name ());
+
+ if ((status.type == rld::process::status::normal) &&
+ (status.code == 0))
+ {
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ out.output ("gcc", std::cout, true);
+ out.open ();
+ while (true)
+ {
+ std::string line;
+ out.read_line (line);
+ if (line.size () == 0)
+ break;
+ if (match_and_trim ("install: ", line, install_path))
+ continue;
+ if (match_and_trim ("programs: ", line, programs_path))
+ continue;
+ if (match_and_trim ("libraries: ", line, libraries_path))
+ continue;
+ }
+ out.close ();
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ {
+ std::cout << "cc::install: " << install_path << std::endl
+ << "cc::programs: " << programs_path << std::endl
+ << "cc::libraries: " << libraries_path << std::endl;
+ }
+ }
+ else
+ {
+ err.output ("gcc", std::cout);
+ }
+ }
+
+ void
+ get_library_path (std::string& name, std::string& path)
+ {
+ rld::process::arg_container args;
+
+ make_cc_command (args);
+ args.push_back ("-print-file-name=" + name);
+
+ rld::process::tempfile out;
+ rld::process::tempfile err;
+ rld::process::status status;
+
+ status = rld::process::execute ("gcc", args, out.name (), err.name ());
+
+ if ((status.type == rld::process::status::normal) &&
+ (status.code == 0))
+ {
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ out.output ("cc", std::cout, true);
+ out.open ();
+ out.read (path);
+ out.close ();
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << "cc::libpath: " << name << " -> " << path << std::endl;
+ }
+ else
+ {
+ err.output ("cc", std::cout);
+ }
+ }
+
+ void
+ get_standard_libpaths (rld::files::paths& libpaths)
+ {
+ search_dirs ();
+ rld::split (libraries_path, libpaths, RLD_PATHSTR_SEPARATOR);
+ }
+
+ void
+ get_standard_libs (rld::files::paths& libs,
+ rld::files::paths& libpaths,
+ bool cplusplus)
+ {
+ strings libnames;
+
+ rld::split (std_lib_c, libnames, RLD_PATHSTR_SEPARATOR);
+ if (cplusplus)
+ rld::files::path_split (std_lib_cplusplus, libnames);
+
+ for (strings::iterator lni = libnames.begin ();
+ lni != libnames.end ();
+ ++lni)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "cc::stdlib: " << *lni << std::endl;
+
+ std::string path;
+
+ rld::files::find_file (path, *lni, libpaths);
+ if (path.empty ())
+ throw rld::error ("Library not found: " + *lni, "getting standard libs");
+
+ libs.push_back (path);
+ }
+ }
+ }
+}
diff --git a/linkers/rld-cc.h b/linkers/rld-cc.h
new file mode 100644
index 0000000..a914b2f
--- /dev/null
+++ b/linkers/rld-cc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief Various calls to CC.
+ *
+ */
+
+#if !defined (_RLD_CC_H_)
+#define _RLD_CC_H_
+
+#include <string>
+
+#include <rld-files.h>
+
+namespace rld
+{
+ namespace cc
+ {
+ extern std::string cc; //< The CC executable.
+ extern std::string exec_prefix; //< The CC executable prefix.
+ extern std::string march; //< The CC machine architecture.
+ extern std::string mcpu; //< The CC machine CPU.
+
+ extern std::string install_path; //< The CC reported install path.
+ extern std::string programs_path; //< The CC reported programs path.
+ extern std::string libraries_path; //< The CC reported libraries path.
+
+ /**
+ * Get the standard libraries paths from the compiler.
+ */
+ void get_standard_libpaths (rld::files::paths& libpaths);
+
+ /**
+ * Get the standard libraries. Optionally add the C++ library.
+ */
+ void get_standard_libs (rld::files::paths& libs,
+ rld::files::paths& libpaths,
+ bool cpp = false);
+
+ }
+}
+
+#endif
diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp
new file mode 100644
index 0000000..2abeff1
--- /dev/null
+++ b/linkers/rld-compression.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_ld
+ *
+ * @brief RTEMS Linker.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fstream>
+#include <iostream>
+
+#include <errno.h>
+#include <string.h>
+
+#include <rld.h>
+#include <rld-compression.h>
+
+#include "fastlz.h"
+
+namespace rld
+{
+ namespace compress
+ {
+ compressor::compressor (files::image& image,
+ size_t size,
+ bool out,
+ bool compress)
+ : image (image),
+ size (size),
+ out (out),
+ compress (compress),
+ buffer (0),
+ io (0),
+ level (0),
+ total (0),
+ total_compressed (0)
+ {
+ if (size > 0xffff)
+ throw rld::error ("Size too big, 16 bits only", "compression");
+
+ buffer = new uint8_t[size];
+ io = new uint8_t[size + (size / 10)];
+ }
+
+ compressor::~compressor ()
+ {
+ flush ();
+ delete [] buffer;
+ delete [] io;
+ }
+
+ void
+ compressor::write (const void* data_, size_t length)
+ {
+ if (!out)
+ throw rld::error ("Write on read-only", "compression");
+
+ const uint8_t* data = static_cast <const uint8_t*> (data_);
+
+ while (length)
+ {
+ size_t appending;
+
+ if (length > (size - level))
+ appending = size - level;
+ else
+ appending = length;
+
+ ::memcpy ((void*) (buffer + level), data, appending);
+
+ data += appending;
+ level += appending;
+ length -= appending;
+ total += appending;
+
+ output ();
+ }
+ }
+
+ void
+ compressor::write (files::image& input, off_t offset, size_t length)
+ {
+ if (!out)
+ throw rld::error ("Write on read-only", "compression");
+
+ input.seek (offset);
+
+ while (length)
+ {
+ size_t appending;
+
+ if (length > (size - level))
+ appending = size - level;
+ else
+ appending = length;
+
+ input.read ((void*) (buffer + level), appending);
+
+ level += appending;
+ length -= appending;
+ total += appending;
+
+ output ();
+ }
+ }
+
+ size_t
+ compressor::read (void* data_, size_t length)
+ {
+ if (out)
+ throw rld::error ("Read on write-only", "compression");
+
+ uint8_t* data = static_cast <uint8_t*> (data_);
+
+ size_t amount = 0;
+
+ while (length)
+ {
+ input ();
+
+ if (level == 0)
+ break;
+
+ size_t appending;
+
+ if (length > level)
+ appending = level;
+ else
+ appending = length;
+
+ ::memcpy (data, buffer, appending);
+ ::memmove (buffer, buffer + appending, level - appending);
+
+ data += appending;
+ level -= appending;
+ length -= appending;
+ total += appending;
+ amount += appending;
+ }
+
+ return amount;
+ }
+
+ size_t
+ compressor::read (files::image& output_, off_t offset, size_t length)
+ {
+ if (out)
+ throw rld::error ("Read on write-only", "compression");
+
+ output_.seek (offset);
+
+ return read (output_, length);
+ }
+
+ size_t
+ compressor::read (files::image& output_, size_t length)
+ {
+ if (out)
+ throw rld::error ("Read on write-only", "compression");
+
+ size_t amount = 0;
+
+ while (length)
+ {
+ input ();
+
+ if (level == 0)
+ break;
+
+ size_t appending;
+
+ if (length > level)
+ appending = level;
+ else
+ appending = length;
+
+ output_.write (buffer, appending);
+
+ ::memmove (buffer, buffer + appending, level - appending);
+
+ level -= appending;
+ length -= appending;
+ total += appending;
+ amount += appending;
+ }
+
+ return amount;
+ }
+
+ void
+ compressor::flush ()
+ {
+ output (true);
+ }
+
+ size_t
+ compressor::transferred () const
+ {
+ return total;
+ }
+
+ size_t
+ compressor::compressed () const
+ {
+ return total_compressed;
+ }
+
+ off_t
+ compressor::offset () const
+ {
+ return total;
+ }
+
+ void
+ compressor::output (bool forced)
+ {
+ if (out && ((forced && level) || (level >= size)))
+ {
+ if (compress)
+ {
+ int writing = ::fastlz_compress (buffer, level, io);
+ uint8_t header[2];
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rtl: comp: offset=" << total_compressed
+ << " block-size=" << writing << std::endl;
+
+ header[0] = writing >> 8;
+ header[1] = writing;
+
+ image.write (header, 2);
+ image.write (io, writing);
+
+ total_compressed += 2 + writing;
+ }
+ else
+ {
+ image.write (buffer, level);
+ }
+
+ level = 0;
+ }
+ }
+
+ void
+ compressor::input ()
+ {
+ if (!out && (level == 0))
+ {
+ if (compress)
+ {
+ uint8_t header[2];
+
+ if (image.read (header, 2) == 2)
+ {
+ uint32_t block_size =
+ (((uint32_t) header[0]) << 8) | (uint32_t) header[1];
+
+ if (block_size == 0)
+ throw rld::error ("Block size is invalid (0)", "compression");
+
+ total_compressed += 2 + block_size;
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rtl: decomp: block-size=" << block_size
+ << std::endl;
+
+ if (image.read (io, block_size) != block_size)
+ throw rld::error ("Read past end", "compression");
+
+ level = ::fastlz_decompress (io, block_size, buffer, size);
+ }
+ }
+ else
+ {
+ image.read (buffer, size);
+ level = size;
+ }
+ }
+ }
+
+ }
+}
diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h
new file mode 100644
index 0000000..4710845
--- /dev/null
+++ b/linkers/rld-compression.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker compression handles compressed images.
+ *
+ */
+
+#if !defined (_RLD_COMPRESSION_H_)
+#define _RLD_COMPRESSION_H_
+
+#include <rld-files.h>
+
+namespace rld
+{
+ namespace compress
+ {
+ /**
+ * A compressor.
+ */
+ class compressor
+ {
+ public:
+ /**
+ * Construct the compressor for the given image.
+ *
+ * @param image The image to read or write to.
+ * @param size The size of the input and output buffers.
+ * @param out The compressor is compressing.
+ * @param compress Set to false to disable compression.
+ */
+ compressor (files::image& image,
+ size_t size,
+ bool out = true,
+ bool compress = true);
+
+ /**
+ * Destruct the compressor.
+ */
+ ~compressor ();
+
+ /**
+ * Write the data to the output buffer and once the image buffer is full
+ * compress and write the compressed data to the image.
+ *
+ * @param data The data to write to the image compressed
+ * @param length The mount of data in bytes to write.
+ */
+ void write (const void* data, size_t length);
+
+ /**
+ * Write the section of the input image file to the output buffer and
+ * once the image buffer is full compress and write the compressed data
+ * to the image.
+ *
+ * @param input The input image.
+ * @param offset The input image offset to read from.
+ * @param length The mount of data in bytes to write.
+ */
+ void write (files::image& input, off_t offset, size_t length);
+
+ /**
+ * Flush the output buffer is data is present.
+ */
+ void flush ();
+
+ /**
+ * Read the compressed data into the input buffer and return the section
+ * requested.
+ *
+ * @param data Write the decompressed data here.
+ * @param length The mount of data in bytes to read.
+ * @return size_t The amount of data read.
+ */
+ size_t read (void* data, size_t length);
+
+ /**
+ * Read the decompressed data writing it to the image.
+ *
+ * @param output_ The output image.
+ * @param offset The output image offset to write from.
+ * @param length The mount of data in bytes to read.
+ * @return size_t The amount of data read.
+ */
+ size_t read (files::image& output_, off_t offset, size_t length);
+
+ /**
+ * Read the decompressed data writing it to the image.
+ *
+ * @param output_ The output image.
+ * @param length The mount of data in bytes to read.
+ * @return size_t The amount of data read.
+ */
+ size_t read (files::image& output_, size_t length);
+
+ /**
+ * The amount of uncompressed data transferred.
+ *
+ * @return size_t The amount of data tranferred.
+ */
+ size_t transferred () const;
+
+ /**
+ * The amount of compressed data transferred.
+ *
+ * @return size_t The amount of compressed data tranferred.
+ */
+ size_t compressed () const;
+
+ /**
+ * The current offset in the stream.
+ *
+ * @return off_t The current uncompressed offset.
+ */
+ off_t offset () const;
+
+ private:
+
+ /**
+ * Output the block of data to the output file with the block header.
+ *
+ * @param forced If true output the buffer.
+ */
+ void output (bool forced = false);
+
+ /**
+ * Input a block of compressed data and decompress it.
+ */
+ void input ();
+
+ files::image& image; //< The image to read or write to or from.
+ size_t size; //< The size of the buffer.
+ bool out; //< If true the it is compression.
+ bool compress; //< If true compress the data.
+ uint8_t* buffer; //< The decompressed buffer
+ uint8_t* io; //< The I/O buffer.
+ size_t level; //< The amount of data in the buffer.
+ size_t total; //< The amount of uncompressed data
+ // transferred.
+ size_t total_compressed; //< The amount of compressed data
+ // transferred.
+ };
+
+ /**
+ * Compressor template function for writing data to the compressor.
+ */
+ template < typename T >
+ void write (compressor& comp, const T value)
+ {
+ uint8_t bytes[sizeof (T)];
+ T v = value;
+ int b = sizeof (T) - 1;
+ while (b >= 0)
+ {
+ bytes[b--] = (uint8_t) v;
+ v >>= 8;
+ }
+ comp.write (bytes, sizeof (T));
+ }
+
+ /**
+ * Compressor template function for reading data from the compressor.
+ */
+ template < typename T >
+ T read (compressor& comp)
+ {
+ uint8_t bytes[sizeof (T)];
+ T v = 0;
+ uint32_t b = 0;
+ if (comp.read (bytes, sizeof (T)) != sizeof (T))
+ throw rld::error ("Reading of value failed", "compression");
+ while (b < sizeof (T))
+ {
+ v = (v << 8) | ((T) bytes[b++]);
+ }
+ return v;
+ }
+
+ }
+}
+
+static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp,
+ const uint64_t value) {
+ rld::compress::write < uint64_t > (comp, value);
+ return comp;
+}
+
+static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp,
+ const uint32_t value) {
+ rld::compress::write < uint32_t > (comp, value);
+ return comp;
+}
+
+static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp,
+ const std::string& str) {
+ comp.write (str.c_str (), str.size ());
+ return comp;
+}
+
+static inline rld::compress::compressor& operator>> (rld::compress::compressor& comp,
+ uint64_t& value) {
+ value = rld::compress::read < uint64_t > (comp);
+ return comp;
+}
+
+static inline rld::compress::compressor& operator>> (rld::compress::compressor& comp,
+ uint32_t& value) {
+ value = rld::compress::read < uint32_t > (comp);
+ return comp;
+}
+
+#endif
diff --git a/linkers/rld-config.cpp b/linkers/rld-config.cpp
new file mode 100644
index 0000000..ee619c8
--- /dev/null
+++ b/linkers/rld-config.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2014, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rld
+ *
+ * @brief INI Configuration reader.
+ *
+ */
+
+#include <errno.h>
+
+#include <rld-config.h>
+
+#include <SimpleIni.h>
+
+namespace rld
+{
+ namespace config
+ {
+ item::item (const std::string& text)
+ : text (text)
+ {
+ }
+
+ item::item (const char* text)
+ : text (text)
+ {
+ }
+
+ const record&
+ section::get_record (const std::string& name) const
+ {
+ for (records::const_iterator ri = recs.begin ();
+ ri != recs.end ();
+ ++ri)
+ {
+ if ((*ri).name == name)
+ return *ri;
+ }
+
+ throw error ("not found", "config record: " + this->name + '/' + name);
+ }
+
+ std::string
+ section::get_record_item (const std::string& rec_name) const
+ {
+ const record& rec = get_record (rec_name);
+ if (rec.items_.size () != 1)
+ throw rld::error ("duplicate", "record item: " + name + '/' + rec_name);
+ return rec.items_[0].text;
+ }
+
+ void
+ section::get_record_items (const std::string& rec_name, rld::strings& items) const
+ {
+ const record& rec = get_record (rec_name);
+ items.clear ();
+ for (rld::config::items::const_iterator ii = rec.items_.begin ();
+ ii != rec.items_.end ();
+ ++ii)
+ {
+ items.push_back ((*ii).text);
+ }
+ }
+
+ config::config()
+ {
+ }
+
+ config::~config()
+ {
+ }
+
+ void
+ config::clear ()
+ {
+ secs.clear ();
+ }
+
+ void
+ config::load (const std::string& path)
+ {
+ CSimpleIniCaseA ini (false, true, true);
+
+ if (ini.LoadFile (path.c_str ()) != SI_OK)
+ throw rld::error (::strerror (errno), "load config: " + path);
+
+ paths_.push_back (path);
+
+ /*
+ * Merge the loaded configuration into our configuration.
+ */
+
+ CSimpleIniCaseA::TNamesDepend skeys;
+
+ ini.GetAllSections(skeys);
+
+ for (CSimpleIniCaseA::TNamesDepend::const_iterator si = skeys.begin ();
+ si != skeys.end ();
+ ++si)
+ {
+ section sec;
+
+ sec.name = (*si).pItem;
+
+ CSimpleIniCaseA::TNamesDepend rkeys;
+
+ ini.GetAllKeys((*si).pItem, rkeys);
+
+ for (CSimpleIniCaseA::TNamesDepend::const_iterator ri = rkeys.begin ();
+ ri != rkeys.end ();
+ ++ri)
+ {
+ record rec;
+
+ rec.name = (*ri).pItem;
+
+ CSimpleIniCaseA::TNamesDepend vals;
+
+ ini.GetAllValues((*si).pItem, (*ri).pItem, vals);
+
+ for (CSimpleIniCaseA::TNamesDepend::const_iterator vi = vals.begin ();
+ vi != vals.end ();
+ ++vi)
+ {
+ rec.items_.push_back (item ((*vi).pItem));
+ }
+
+ sec.recs.push_back (rec);
+ }
+
+ secs.push_back (sec);
+ }
+ }
+
+
+ void
+ config::includes (const section& sec, bool must_exist)
+ {
+ bool have_includes = false;
+
+ try
+ {
+ rld::strings is;
+ parse_items (sec, "include", is);
+
+ have_includes = true;
+
+ /*
+ * Include records are a path which we can just load.
+ *
+ * @todo Add a search path. See 'rld::files' for details. We can default
+ * the search path to the install $prefix of this tool and we can
+ * then provide a default set of function signatures for RTEMS
+ * APIs.
+ */
+
+ for (rld::strings::const_iterator isi = is.begin ();
+ isi != is.end ();
+ ++isi)
+ {
+ load (*isi);
+ }
+ }
+ catch (rld::error re)
+ {
+ /*
+ * No include records, must be all inlined. If we have includes it must
+ * be another error so throw it.
+ */
+ if (have_includes || (!have_includes && must_exist))
+ throw;
+ }
+ }
+
+ const section&
+ config::get_section (const std::string& name) const
+ {
+ for (sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ if ((*si).name == name)
+ return *si;
+ }
+
+ throw error ("not found", "config section: " + name);
+ }
+
+ const paths&
+ config::get_paths () const
+ {
+ return paths_;
+ }
+ }
+}
diff --git a/linkers/rld-config.h b/linkers/rld-config.h
new file mode 100644
index 0000000..b8bd495
--- /dev/null
+++ b/linkers/rld-config.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2014, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rld
+ *
+ * @brief INI Configuration reader.
+ *
+ */
+
+#if !defined (_RLD_CONFIG_H_)
+#define _RLD_CONFIG_H_
+
+#include <string>
+#include <list>
+#include <vector>
+
+#include <rld.h>
+
+namespace rld
+{
+ namespace config
+ {
+ /**
+ * The configuration item. This is a data component of a record contained
+ * in a section.
+ */
+ struct item
+ {
+ std::string text; /**< The text as read from the configuration. */
+
+ /**
+ * Construct an item.
+ */
+ item (const std::string& text);
+ item (const char* text);
+ };
+
+ /**
+ * Configuration item container.
+ */
+ typedef std::vector < item > items;
+
+ /**
+ * Configuration record is a line in a section. There can be multiple
+ * records with the same key in a section. Keys are specific to a section.
+ */
+ struct record
+ {
+ std::string name; //< Name of the record.
+ items items_; //< The record's items.
+
+ /**
+ * Return true if there is only one item.
+ */
+ bool single () const {
+ return items_.size () == 1;
+ }
+ };
+
+ /**
+ * Configuration record container.
+ */
+ typedef std::list < record > records;
+
+ /**
+ * Configuration section. A section contains a number of records and the
+ * records contain [1..n] items.
+ */
+ struct section
+ {
+ std::string name; //< Name of the section.
+ records recs; //< The section's records.
+
+ /**
+ * Find a record and throw an error if not found.
+ */
+ const record& get_record (const std::string& name) const;
+
+ /**
+ * Return the single item in a record. If the record is duplicated an
+ * error is thrown.
+ */
+ std::string get_record_item (const std::string& name) const;
+
+ /**
+ * Return the list of items in a record in a strings container.
+ */
+ void get_record_items (const std::string& name, rld::strings& items_) const;
+ };
+
+ /**
+ * Configuration section container.
+ */
+ typedef std::list < section > sections;
+
+ /**
+ * Container of configuration file paths loaded.
+ */
+ typedef std::vector < std::string > paths;
+
+ /**
+ * The configuration.
+ */
+ class config
+ {
+ public:
+ /**
+ * Construct an empty configuration.
+ */
+ config();
+ virtual ~config();
+
+ /**
+ * Clear the current configuration.
+ */
+ void clear ();
+
+ /**
+ * Load a configuration.
+ */
+ void load (const std::string& name);
+
+ /**
+ * Process any include records in the section named. If the section has
+ * any records named 'include' split the items and include the
+ * configuration files.
+ */
+ void includes (const section& sec, bool must_exist = false);
+
+ /**
+ * Get the section and throw an error if not found.
+ */
+ const section& get_section (const std::string& name) const;
+
+ /**
+ * Get the paths of loaded configuration files.
+ */
+ const paths& get_paths () const;
+
+ private:
+
+ paths paths_; /**< The path's of the loaded files. */
+ sections secs; /**< The sections loaded from configuration files */
+ };
+
+ /**
+ * Return the items from a record.
+ */
+ template < typename T >
+ void parse_items (const rld::config::record& record,
+ T& items_,
+ bool clear = true,
+ bool split = true)
+ {
+ if (clear)
+ items_.clear ();
+ for (rld::config::items::const_iterator ii = record.items_.begin ();
+ ii != record.items_.end ();
+ ++ii)
+ {
+ if (split)
+ {
+ rld::strings ss;
+ rld::split (ss, (*ii).text, ',');
+ std::copy (ss.begin (), ss.end (), std::back_inserter (items_));
+ }
+ else
+ {
+ items_.push_back ((*ii).text);
+ }
+ }
+ }
+
+ /**
+ * Return the items from a record in a section. Optionally raise an error
+ * if the record is not found and it is to be present.
+ */
+ template < typename T >
+ void parse_items (const rld::config::section& section,
+ const std::string& name,
+ T& items_,
+ bool present = false,
+ bool clear = true,
+ bool split = true)
+ {
+ if (clear)
+ items_.clear ();
+ const rld::config::record* rec = 0;
+ try
+ {
+ const rld::config::record& rr = section.get_record (name);
+ rec = &rr;
+ }
+ catch (rld::error re)
+ {
+ /*
+ * Ignore the error if it does not need to exist.
+ */
+ if (present)
+ throw rld::error ("not found", "record: " + section.name + name);
+ }
+
+ if (rec)
+ parse_items (*rec, items_, clear, split);
+ }
+
+ /**
+ * Return the items from a record in a section in the
+ * configuration. Optionally raise an error if the section is not found and
+ * it is to be present.
+ */
+ template < typename T >
+ void parse_items (const rld::config::config& config,
+ const std::string& section,
+ const std::string& record,
+ T& items_,
+ bool present = false)
+ {
+ items_.clear ();
+ const rld::config::section* sec = 0;
+ try
+ {
+ const rld::config::section& sr = config.get_section (section);
+ sec = &sr;
+ }
+ catch (rld::error re)
+ {
+ /*
+ * Ignore the error if it does not need to exist.
+ */
+ if (present)
+ throw rld::error ("not found", "section: " + section);
+ }
+
+ if (sec)
+ parse_items (*sec, record, items_);
+ }
+ }
+}
+
+#endif
diff --git a/linkers/rld-elf-types.h b/linkers/rld-elf-types.h
new file mode 100644
index 0000000..c0da295
--- /dev/null
+++ b/linkers/rld-elf-types.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker ELF types.
+ *
+ */
+
+#if !defined (_RLD_ELF_TYPES_H_)
+#define _RLD_ELF_TYPES_H_
+
+#define __LIBELF_INTERNAL__ 1
+#include <gelf.h>
+#include <libelf.h>
+
+namespace rld
+{
+ namespace elf
+ {
+ /**
+ * Hide the types from libelf we use.
+ */
+ typedef ::GElf_Half elf_half;
+ typedef ::GElf_Word elf_word;
+ typedef ::GElf_Xword elf_xword;
+ typedef ::GElf_Sxword elf_sxword;
+ typedef ::Elf_Type elf_type;
+ typedef ::GElf_Addr elf_addr;
+ typedef ::GElf_Off elf_off;
+ typedef ::GElf_Sym elf_sym;
+ typedef ::Elf_Kind elf_kind;
+ typedef ::Elf_Scn elf_scn;
+ typedef ::GElf_Ehdr elf_ehdr;
+ typedef ::Elf32_Ehdr elf32_ehdr;
+ typedef ::GElf_Shdr elf_shdr;
+ typedef ::GElf_Phdr elf_phdr;
+ typedef ::Elf_Data elf_data;
+ typedef ::GElf_Rel elf_rel;
+ typedef ::GElf_Rela elf_rela;
+ typedef ::Elf elf;
+ }
+}
+
+#endif
diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp
new file mode 100644
index 0000000..8b2ac5e
--- /dev/null
+++ b/linkers/rld-elf.cpp
@@ -0,0 +1,1210 @@
+/*
+ * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker ELF module manages the ELF format images.
+ *
+ */
+
+#include <string.h>
+
+#include <rld.h>
+
+namespace rld
+{
+ namespace elf
+ {
+ /**
+ * Throw an ELF error.
+ *
+ * @param where Where the error is raised.
+ */
+ void libelf_error (const std::string& where)
+ {
+ throw rld::error (::elf_errmsg (-1), "libelf:" + where);
+ }
+
+ /**
+ * We record the first class, machine and .. type of object file we get the
+ * header of and all header must match. We cannot mix object module types.
+ */
+ static unsigned int elf_object_class = ELFCLASSNONE;
+ static unsigned int elf_object_machinetype = EM_NONE;
+ static unsigned int elf_object_datatype = ELFDATANONE;
+
+ /**
+ * A single place to initialise the libelf library. This must be called
+ * before any libelf API calls are made.
+ */
+ static void
+ libelf_initialise ()
+ {
+ static bool libelf_initialised = false;
+ if (!libelf_initialised)
+ {
+ if (::elf_version (EV_CURRENT) == EV_NONE)
+ libelf_error ("initialisation");
+ libelf_initialised = true;
+ }
+ }
+
+ relocation::relocation (const symbols::symbol& sym,
+ elf_addr offset,
+ elf_xword info,
+ elf_sxword addend)
+ : sym (&sym),
+ offset_ (offset),
+ info_ (info),
+ addend_ (addend)
+ {
+ }
+
+ relocation::relocation ()
+ : sym (0),
+ offset_ (0),
+ info_ (0),
+ addend_ (0)
+ {
+ }
+
+ elf_addr
+ relocation::offset () const
+ {
+ return offset_;
+ }
+
+ uint32_t
+ relocation::type () const
+ {
+ return GELF_R_TYPE (info_);
+ }
+
+ elf_xword
+ relocation::info () const
+ {
+ return info_;
+ }
+
+ elf_sxword
+ relocation::addend () const
+ {
+ return addend_;
+ }
+
+ const symbols::symbol&
+ relocation::symbol () const
+ {
+ if (sym)
+ return *sym;
+ throw rld::error ("no symbol", "elf:relocation");
+ }
+
+ section::section (file& file_,
+ int index_,
+ const std::string& name_,
+ elf_word type,
+ elf_xword alignment,
+ elf_xword flags,
+ elf_addr addr,
+ elf_off offset,
+ elf_xword size,
+ elf_word link,
+ elf_word info,
+ elf_xword entry_size)
+ : file_ (&file_),
+ index_ (index_),
+ name_ (name_),
+ scn (0),
+ data_ (0),
+ rela (false)
+ {
+ if (!file_.is_writable ())
+ throw rld::error ("not writable",
+ "elf:section" + file_.name () + " (" + name_ + ')');
+
+ scn = ::elf_newscn (file_.get_elf ());
+ if (!scn)
+ libelf_error ("elf_newscn: " + name_ + " (" + file_.name () + ')');
+
+ if (::gelf_getshdr(scn, &shdr) == 0)
+ libelf_error ("gelf_getshdr: " + name_ + " (" + file_.name () + ')');
+
+ shdr.sh_name = 0;
+ shdr.sh_type = type;
+ shdr.sh_flags = flags;
+ shdr.sh_addr = addr;
+ shdr.sh_offset = offset;
+ shdr.sh_size = size;
+ shdr.sh_link = link;
+ shdr.sh_info = info;
+ shdr.sh_addralign = alignment;
+ shdr.sh_entsize = entry_size;
+
+ if (type == SHT_NOBITS)
+ add_data (ELF_T_BYTE, alignment, size);
+
+ if (!gelf_update_shdr (scn, &shdr))
+ libelf_error ("gelf_update_shdr: " + name_ + " (" + file_.name () + ')');
+ }
+
+ section::section (file& file_, int index_)
+ : file_ (&file_),
+ index_ (index_),
+ scn (0),
+ data_ (0),
+ rela (false)
+ {
+ memset (&shdr, 0, sizeof (shdr));
+
+ scn = ::elf_getscn (file_.get_elf (), index_);
+ if (!scn)
+ libelf_error ("elf_getscn: " + file_.name ());
+
+ if (!::gelf_getshdr (scn, &shdr))
+ libelf_error ("gelf_getshdr: " + file_.name ());
+
+ if (shdr.sh_type != SHT_NULL)
+ {
+ name_ = file_.get_string (shdr.sh_name);
+ data_ = ::elf_getdata (scn, 0);
+ if (!data_)
+ {
+ data_ = ::elf_rawdata (scn, 0);
+ if (!data_)
+ libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')');
+ }
+ }
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf::section: index=" << index ()
+ << " name='" << name () << "'"
+ << " size=" << size ()
+ << " align=" << alignment ()
+ << " flags=0x" << std::hex << flags () << std::dec
+ << std::endl;
+ }
+
+ section::section (const section& orig)
+ : file_ (orig.file_),
+ index_ (orig.index_),
+ name_ (orig.name_),
+ scn (orig.scn),
+ shdr (orig.shdr),
+ data_ (orig.data_),
+ rela (orig.rela),
+ relocs (orig.relocs)
+ {
+ }
+
+ section::section ()
+ : file_ (0),
+ index_ (-1),
+ scn (0),
+ data_ (0),
+ rela (false)
+ {
+ memset (&shdr, 0, sizeof (shdr));
+ }
+
+ void
+ section::add_data (elf_type type,
+ elf_xword alignment,
+ elf_xword size,
+ void* buffer,
+ elf_off offset)
+ {
+ check_writable ("add_data");
+
+ data_ = ::elf_newdata(scn);
+ if (!data_)
+ libelf_error ("elf_newdata: " + name_ + " (" + file_->name () + ')');
+
+ data_->d_type = type;
+ data_->d_off = offset;
+ data_->d_size = size;
+ data_->d_align = alignment;
+ data_->d_version = EV_CURRENT;
+ data_->d_buf = buffer;
+
+ if (!gelf_update_shdr (scn, &shdr))
+ libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')');
+ }
+
+ int
+ section::index () const
+ {
+ check ("index");
+ return index_;
+ }
+
+ const std::string&
+ section::name () const
+ {
+ check ("name");
+ return name_;
+ }
+
+ elf_data*
+ section::data ()
+ {
+ check ("data");
+ return data_;
+ }
+
+ elf_word
+ section::type () const
+ {
+ check ("type");
+ return shdr.sh_type;
+ }
+
+ elf_xword
+ section::flags () const
+ {
+ check ("flags");
+ return shdr.sh_flags;
+ }
+
+ elf_addr
+ section::address () const
+ {
+ check ("address");
+ return shdr.sh_addr;
+ }
+
+ elf_xword
+ section::alignment () const
+ {
+ check ("alignment");
+ return shdr.sh_addralign;
+ }
+
+ elf_off
+ section::offset () const
+ {
+ check ("offset");
+ return shdr.sh_offset;
+ }
+
+ elf_word
+ section::link () const
+ {
+ check ("link");
+ return shdr.sh_link;
+ }
+
+ elf_word
+ section::info () const
+ {
+ check ("info");
+ return shdr.sh_info;
+ }
+
+ elf_xword
+ section::size () const
+ {
+ check ("size");
+ return shdr.sh_size;
+ }
+
+ elf_xword
+ section::entry_size () const
+ {
+ check ("entry_size");
+ return shdr.sh_entsize;
+ }
+
+ int
+ section::entries () const
+ {
+ return size () / entry_size ();
+ }
+
+ bool
+ section::get_reloc_type () const
+ {
+ return rela;
+ }
+
+ void
+ section::set_name (unsigned int index)
+ {
+ check_writable ("set_name");
+ shdr.sh_name = index;
+ if (!gelf_update_shdr (scn, &shdr))
+ libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')');
+ }
+
+ void
+ section::set_reloc_type (bool rela_)
+ {
+ rela = rela_;
+ }
+
+ void
+ section::add (const relocation& reloc)
+ {
+ relocs.push_back (reloc);
+ }
+
+ const relocations&
+ section::get_relocations () const
+ {
+ return relocs;
+ }
+
+ void
+ section::check (const char* where) const
+ {
+ if (!file_ || (index_ < 0) || !scn)
+ {
+ std::string w = where;
+ throw rld::error ("Section not initialised.", "section:check:" + w);
+ }
+ }
+
+ void
+ section::check_writable (const char* where) const
+ {
+ check (where);
+ if (!file_->is_writable ())
+ {
+ std::string w = where;
+ throw rld::error ("File is read-only.", "section:check:");
+ }
+ }
+
+ program_header::program_header ()
+ {
+ memset (&phdr, 0, sizeof (phdr));
+ }
+
+ program_header::~program_header ()
+ {
+ }
+
+ void
+ program_header::set (elf_word type,
+ elf_word flags,
+ elf_off offset,
+ elf_xword filesz,
+ elf_xword memsz,
+ elf_xword align,
+ elf_addr vaddr,
+ elf_addr paddr)
+ {
+ phdr.p_type = type;
+ phdr.p_flags = flags;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = vaddr;
+ phdr.p_paddr = paddr;
+ phdr.p_filesz = filesz;
+ phdr.p_memsz = memsz;
+ phdr.p_align = align;
+ }
+
+ file::file ()
+ : fd_ (-1),
+ archive (false),
+ writable (false),
+ elf_ (0),
+ oclass (0),
+ ident_str (0),
+ ident_size (0),
+ ehdr (0),
+ phdr (0)
+ {
+ }
+
+ file::~file ()
+ {
+ end ();
+ }
+
+ void
+ file::begin (const std::string& name__, int fd__, const bool writable_)
+ {
+ begin (name__, fd__, writable_, 0, 0);
+ }
+
+ void
+ file::begin (const std::string& name__, file& archive_, off_t offset)
+ {
+ archive_.check ("begin:archive");
+
+ if (archive_.writable)
+ throw rld::error ("archive is writable", "elf:file:begin");
+
+ begin (name__, archive_.fd_, false, &archive_, offset);
+ }
+
+ #define rld_archive_fhdr_size (60)
+
+ void
+ file::begin (const std::string& name__,
+ int fd__,
+ const bool writable_,
+ file* archive_,
+ off_t offset_)
+ {
+ if (fd__ < 0)
+ throw rld::error ("No file descriptor", "elf:file:begin");
+
+ /*
+ * Begin's are not nesting.
+ */
+ if (elf_ || (fd_ >= 0))
+ throw rld::error ("Already called", "elf:file:begin");
+
+ /*
+ * Cannot write directly into archive. Create a file then archive it.
+ */
+ if (archive_ && writable_)
+ throw rld::error ("Cannot write into archives directly",
+ "elf:file:begin");
+
+ libelf_initialise ();
+
+ /*
+ * Is this image part of an archive ?
+ */
+ if (archive_)
+ {
+ ssize_t offset = offset_ - rld_archive_fhdr_size;
+ if (::elf_rand (archive_->elf_, offset) != offset)
+ libelf_error ("rand: " + archive_->name_);
+ }
+
+ /*
+ * Note, the elf passed is either the archive or NULL.
+ */
+ elf* elf__ = ::elf_begin (fd__,
+ writable_ ? ELF_C_WRITE : ELF_C_READ,
+ archive_ ? archive_->elf_ : 0);
+ if (!elf__)
+ libelf_error ("begin: " + name__);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf::begin: " << elf__ << ' ' << name__ << std::endl;
+
+ elf_kind ek = ::elf_kind (elf__);
+
+ /*
+ * If this is inside an archive it must be an ELF file.
+ */
+
+ if (archive_ && (ek != ELF_K_ELF))
+ throw rld::error ("File format in archive not ELF",
+ "elf:file:begin: " + name__);
+ else
+ {
+ if (ek == ELF_K_AR)
+ archive = true;
+ else if (ek == ELF_K_ELF)
+ archive = false;
+ else
+ throw rld::error ("File format not ELF or archive",
+ "elf:file:begin: " + name__);
+ }
+
+ if (!writable_)
+ {
+ /*
+ * If an ELF file make sure they all match. On the first file that
+ * begins an ELF session record its settings.
+ */
+ if (ek == ELF_K_ELF)
+ {
+ oclass = ::gelf_getclass (elf__);
+ ident_str = elf_getident (elf__, &ident_size);
+ }
+ }
+
+ fd_ = fd__;
+ name_ = name__;
+ writable = writable_;
+ elf_ = elf__;
+
+ if (!archive && !writable)
+ {
+ load_header ();
+ load_sections ();
+ }
+ }
+
+ void
+ file::end ()
+ {
+ if (elf_)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "libelf::end: " << elf_
+ << ' ' << name_ << std::endl;
+ ::elf_end (elf_);
+ elf_ = 0;
+ }
+
+ if (fd_ >= 0)
+ {
+ if (!writable)
+ {
+ if (ehdr)
+ {
+ delete ehdr;
+ ehdr = 0;
+ }
+ if (phdr)
+ {
+ delete phdr;
+ phdr = 0;
+ }
+ }
+
+ fd_ = -1;
+ name_.clear ();
+ archive = false;
+ elf_ = 0;
+ oclass = 0;
+ ident_str = 0;
+ ident_size = 0;
+ writable = false;
+ secs.clear ();
+ }
+ }
+
+ void
+ file::write ()
+ {
+ check_writable ("write");
+
+ std::string shstrtab;
+
+ for (section_table::iterator sti = secs.begin ();
+ sti != secs.end ();
+ ++sti)
+ {
+ section& sec = (*sti).second;
+ int added_at = shstrtab.size ();
+ shstrtab += '\0' + sec.name ();
+ sec.set_name (added_at + 1);
+ }
+
+ unsigned int shstrtab_name = shstrtab.size () + 1;
+
+ /*
+ * Done this way to clang happy on darwin.
+ */
+ shstrtab += '\0';
+ shstrtab += ".shstrtab";
+
+ /*
+ * Create the string table section.
+ */
+ section shstrsec (*this,
+ secs.size () + 1, /* index */
+ ".shstrtab", /* name */
+ SHT_STRTAB, /* type */
+ 1, /* alignment */
+ SHF_STRINGS | SHF_ALLOC, /* flags */
+ 0, /* address */
+ 0, /* offset */
+ shstrtab.size ()); /* size */
+
+ shstrsec.add_data (ELF_T_BYTE,
+ 1,
+ shstrtab.size (),
+ (void*) shstrtab.c_str ());
+
+ shstrsec.set_name (shstrtab_name);
+
+ ::elf_setshstrndx (elf_, shstrsec.index ());
+ ::elf_flagehdr (elf_, ELF_C_SET, ELF_F_DIRTY);
+
+ if (elf_update (elf_, ELF_C_NULL) < 0)
+ libelf_error ("elf_update:layout: " + name_);
+
+ ::elf_flagphdr (elf_, ELF_C_SET, ELF_F_DIRTY);
+
+ if (::elf_update (elf_, ELF_C_WRITE) < 0)
+ libelf_error ("elf_update:write: " + name_);
+ }
+
+ void
+ file::load_header ()
+ {
+ check ("load_header");
+
+ if (!ehdr)
+ {
+ if (!writable)
+ ehdr = new elf_ehdr;
+ else
+ {
+ throw rld::error ("No ELF header; set the header first",
+ "elf:file:load_header: " + name_);
+ }
+ }
+
+ if (::gelf_getehdr (elf_, ehdr) == 0)
+ error ("gelf_getehdr");
+ }
+
+ unsigned int
+ file::machinetype () const
+ {
+ check_ehdr ("machinetype");
+ return ehdr->e_machine;
+ }
+
+ unsigned int
+ file::type () const
+ {
+ check_ehdr ("type");
+ return ehdr->e_type;
+ }
+
+ unsigned int
+ file::object_class () const
+ {
+ check ("object_class");
+ return oclass;
+ }
+
+ unsigned int
+ file::data_type () const
+ {
+ check ("data_type");
+ if (!ident_str)
+ throw rld::error ("No ELF ident str", "elf:file:data_type: " + name_);
+ return ident_str[EI_DATA];
+ }
+
+ bool
+ file::is_archive () const
+ {
+ check ("is_archive");
+ return archive;
+ }
+
+ bool
+ file::is_executable () const
+ {
+ check_ehdr ("is_executable");
+ return ehdr->e_type != ET_REL;
+ }
+
+ bool
+ file::is_relocatable() const
+ {
+ check_ehdr ("is_relocatable");
+ return ehdr->e_type == ET_REL;
+ }
+
+ int
+ file::section_count () const
+ {
+ check_ehdr ("section_count");
+ return ehdr->e_shnum;
+ }
+
+ void
+ file::load_sections ()
+ {
+ if (secs.empty ())
+ {
+ check ("load_sections_headers");
+ for (int sn = 0; sn < section_count (); ++sn)
+ {
+ section sec (*this, sn);
+ secs[sec.name ()] = sec;
+ }
+ }
+ }
+
+ void
+ file::get_sections (sections& filtered_secs, unsigned int type)
+ {
+ load_sections ();
+ for (section_table::iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ section& sec = (*si).second;
+ if ((type == 0) || (sec.type () == type))
+ filtered_secs.push_back (&sec);
+ }
+ }
+
+ section&
+ file::get_section (int index)
+ {
+ load_sections ();
+ for (section_table::iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ section& sec = (*si).second;
+ if (index == sec.index ())
+ return sec;
+ }
+
+ throw rld::error ("section index '" + rld::to_string (index) + "'not found",
+ "elf:file:get_section: " + name_);
+ }
+
+ int
+ file::strings_section () const
+ {
+ check_ehdr ("strings_sections");
+ return ehdr->e_shstrndx;
+ }
+
+ void
+ file::load_symbols ()
+ {
+ if (symbols.empty ())
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:symbol: " << name () << std::endl;
+
+ sections symbol_secs;
+
+ get_sections (symbol_secs, SHT_SYMTAB);
+
+ for (sections::iterator si = symbol_secs.begin ();
+ si != symbol_secs.end ();
+ ++si)
+ {
+ section& sec = *(*si);
+ int syms = sec.entries ();
+
+ for (int s = 0; s < syms; ++s)
+ {
+ elf_sym esym;
+
+ if (!::gelf_getsym (sec.data (), s, &esym))
+ error ("gelf_getsym");
+
+ std::string name = get_string (sec.link (), esym.st_name);
+ symbols::symbol sym (s, name, esym);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:symbol: " << sym << std::endl;
+
+ symbols.push_back (sym);
+ }
+ }
+ }
+ }
+
+ void
+ file::get_symbols (symbols::pointers& filtered_syms,
+ bool unresolved,
+ bool local,
+ bool weak,
+ bool global)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ std::cout << "elf:get-syms: unresolved:" << unresolved
+ << " local:" << local
+ << " weak:" << weak
+ << " global:" << global
+ << " " << name_
+ << std::endl;
+
+ load_symbols ();
+
+ filtered_syms.clear ();
+
+ for (symbols::bucket::iterator si = symbols.begin ();
+ si != symbols.end ();
+ ++si)
+ {
+ symbols::symbol& sym = *si;
+
+ int stype = sym.type ();
+ int sbind = sym.binding ();
+
+ /*
+ * If wanting unresolved symbols and the type is no-type and the
+ * section is undefined, or, the type is no-type or object or function
+ * and the bind is local and we want local symbols, or the bind is weak
+ * and we want weak symbols, or the bind is global and we want global
+ * symbols then add the filtered symbols container.
+ */
+ bool add = false;
+
+ if ((stype == STT_NOTYPE) &&
+ (sbind == STB_GLOBAL) &&
+ (sym.section_index () == SHN_UNDEF))
+ {
+ if (unresolved)
+ add = true;
+ }
+ else
+ {
+ if (((stype == STT_NOTYPE) ||
+ (stype == STT_OBJECT) ||
+ (stype == STT_FUNC)) &&
+ ((weak && (sbind == STB_WEAK)) ||
+ (!unresolved && ((local && (sbind == STB_LOCAL)) ||
+ (global && (sbind == STB_GLOBAL))))))
+ add = true;
+ }
+
+ if (add)
+ filtered_syms.push_back (&sym);
+ }
+ }
+
+ const symbols::symbol&
+ file::get_symbol (const int index) const
+ {
+ for (symbols::bucket::const_iterator si = symbols.begin ();
+ si != symbols.end ();
+ ++si)
+ {
+ const symbols::symbol& sym = *si;
+ if (index == sym.index ())
+ return sym;
+ }
+
+ throw rld::error ("symbol index '" + rld::to_string (index) + "' not found",
+ "elf:file:get_symbol: " + name_);
+ }
+
+ void
+ file::load_relocations ()
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: " << name () << std::endl;
+
+ sections rel_secs;
+
+ get_sections (rel_secs, SHT_REL);
+ get_sections (rel_secs, SHT_RELA);
+
+ for (sections::iterator si = rel_secs.begin ();
+ si != rel_secs.end ();
+ ++si)
+ {
+ section& sec = *(*si);
+ section& targetsec = get_section (sec.info ());
+ int rels = sec.entries ();
+ bool rela = sec.type () == SHT_RELA;
+
+ targetsec.set_reloc_type (rela);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: " << sec.name ()
+ << " -> " << targetsec.name ()
+ << std::endl;
+
+ for (int r = 0; r < rels; ++r)
+ {
+ if (rela)
+ {
+ elf_rela erela;
+
+ if (!::gelf_getrela (sec.data (), r, &erela))
+ error ("gelf_getrela");
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: rela: offset: " << erela.r_offset
+ << " sym:" << GELF_R_SYM (erela.r_info)
+ << " type:" << GELF_R_TYPE (erela.r_info)
+ << " addend:" << erela.r_addend
+ << std::endl;
+
+ /*
+ * The target section is updated with the fix up, and symbol
+ * section indicates the section offset being referenced by the
+ * fixup.
+ */
+
+ const symbols::symbol& sym = get_symbol (GELF_R_SYM (erela.r_info));
+
+ relocation reloc (sym,
+ erela.r_offset,
+ erela.r_info,
+ erela.r_addend);
+
+ targetsec.add (reloc);
+ }
+ else
+ {
+ elf_rel erel;
+
+ if (!::gelf_getrel (sec.data (), r, &erel))
+ error ("gelf_getrel");
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: rel: offset: " << erel.r_offset
+ << " sym:" << GELF_R_SYM (erel.r_info)
+ << " type:" << GELF_R_TYPE (erel.r_info)
+ << std::endl;
+
+ const symbols::symbol& sym = get_symbol (GELF_R_SYM (erel.r_info));
+
+ relocation reloc (sym, erel.r_offset, erel.r_info);
+
+ targetsec.add (reloc);
+ }
+ }
+ }
+ }
+
+ std::string
+ file::get_string (int section, size_t offset)
+ {
+ check ("get_string");
+ char* s = ::elf_strptr (elf_, section, offset);
+ if (!s)
+ error ("elf_strptr");
+ return s;
+ }
+
+ std::string
+ file::get_string (size_t offset)
+ {
+ check ("get_string");
+ char* s = ::elf_strptr (elf_, strings_section (), offset);
+ if (!s)
+ error ("elf_strptr");
+ return s;
+ }
+
+ void
+ file::set_header (elf_half type,
+ int class_,
+ elf_half machinetype,
+ unsigned char datatype)
+ {
+ check_writable ("set_header");
+
+ if (ehdr)
+ throw rld::error ("ELF header already set",
+ "elf:file:set_header: " + name_);
+
+ ehdr = (elf_ehdr*) ::gelf_newehdr (elf_, class_);
+ if (ehdr == 0)
+ error ("gelf_newehdr");
+
+ if (class_ == ELFCLASS32)
+ {
+ if((ehdr = (elf_ehdr*) ::elf32_getehdr (elf_)) == 0)
+ error ("elf32_getehdr");
+ }
+ else if (::gelf_getehdr (elf_, ehdr) == 0)
+ error ("gelf_getehdr");
+
+ if (class_ == ELFCLASS32)
+ {
+ ((elf32_ehdr*)ehdr)->e_type = type;
+ ((elf32_ehdr*)ehdr)->e_machine = machinetype;
+ ((elf32_ehdr*)ehdr)->e_flags = 0;
+ ((elf32_ehdr*)ehdr)->e_ident[EI_DATA] = datatype;
+ ((elf32_ehdr*)ehdr)->e_version = EV_CURRENT;
+ }
+ else
+ {
+ ehdr->e_type = type;
+ ehdr->e_machine = machinetype;
+ ehdr->e_flags = 0;
+ ehdr->e_ident[EI_DATA] = datatype;
+ ehdr->e_version = EV_CURRENT;
+ }
+
+ ::elf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY);
+ }
+
+ void
+ file::add (section& sec)
+ {
+ check_writable ("add");
+ secs[sec.name ()] = sec;
+ }
+
+ void
+ file::add (program_header& phdr)
+ {
+ check_writable ("add");
+ phdrs.push_back (phdr);
+ }
+
+ elf*
+ file::get_elf ()
+ {
+ return elf_;
+ }
+
+ const std::string&
+ file::name () const
+ {
+ return name_;
+ }
+
+ bool
+ file::is_writable () const
+ {
+ return writable;
+ }
+
+ void
+ file::check (const char* where) const
+ {
+ if (!elf_ || (fd_ < 0))
+ {
+ std::string w = where;
+ throw rld::error ("No ELF file or file descriptor", "elf:file:" + w);
+ }
+ }
+
+ void
+ file::check_ehdr (const char* where) const
+ {
+ check (where);
+ if (!ehdr)
+ {
+ std::string w = where;
+ throw rld::error ("no elf header", "elf:file:" + w);
+ }
+ }
+
+ void
+ file::check_phdr (const char* where) const
+ {
+ check (where);
+ if (!phdr)
+ {
+ std::string w = where;
+ throw rld::error ("no elf program header", "elf:file:" + w);
+ }
+ }
+
+ void
+ file::check_writable (const char* where) const
+ {
+ check (where);
+ if (!writable)
+ {
+ std::string w = where;
+ throw rld::error ("not writable", "elf:file:" + w);
+ }
+ }
+
+ void
+ file::error (const char* where) const
+ {
+ std::string w = where;
+ libelf_error (w + ": " + name_);
+ }
+
+ const std::string
+ machine_type (unsigned int machinetype)
+ {
+ struct types_and_labels
+ {
+ const char* name; //< The RTEMS label.
+ unsigned int machinetype; //< The machine type.
+ };
+ types_and_labels types_to_labels[] =
+ {
+ { "arm", EM_ARM },
+ { "avr", EM_AVR },
+ { "bfin", EM_BLACKFIN },
+ { "h8300", EM_H8_300 },
+ { "i386", EM_386 },
+ /* { "m32c", EM_M32C }, Not in libelf I imported */
+ { "m32r", EM_M32R },
+ { "m68k", EM_68K },
+ { "m68k", EM_COLDFIRE },
+ { "mips", EM_MIPS },
+ { "powerpc", EM_PPC },
+ { "sh", EM_SH },
+ { "sparc", EM_SPARC },
+ { "sparc64", EM_SPARC },
+ { 0, EM_NONE }
+ };
+
+ int m = 0;
+ while (types_to_labels[m].machinetype != EM_NONE)
+ {
+ if (machinetype == types_to_labels[m].machinetype)
+ return types_to_labels[m].name;
+ ++m;
+ }
+
+ std::ostringstream what;
+ what << "unknown machine type: " << elf_object_machinetype;
+ throw rld::error (what, "machine-type");
+ }
+
+ const std::string
+ machine_type ()
+ {
+ return machine_type (elf_object_machinetype);
+ }
+
+ unsigned int
+ object_class ()
+ {
+ return elf_object_class;
+ }
+
+ unsigned int
+ object_machine_type ()
+ {
+ return elf_object_machinetype;
+ }
+
+ unsigned int
+ object_datatype ()
+ {
+ return elf_object_datatype;
+ }
+
+ void
+ check_file(const file& file)
+ {
+ if (elf_object_machinetype == EM_NONE)
+ elf_object_machinetype = file.machinetype ();
+ else if (file.machinetype () != elf_object_machinetype)
+ {
+ std::ostringstream oss;
+ oss << "elf:check_file:" << file.name ()
+ << ": " << elf_object_machinetype << '/' << file.machinetype ();
+ throw rld::error ("Mixed machine types not supported.", oss.str ());
+ }
+
+ if (elf_object_class == ELFCLASSNONE)
+ elf_object_class = file.object_class ();
+ else if (file.object_class () != elf_object_class)
+ throw rld::error ("Mixed classes not allowed (32bit/64bit).",
+ "elf:check_file: " + file.name ());
+
+ if (elf_object_datatype == ELFDATANONE)
+ elf_object_datatype = file.data_type ();
+ else if (elf_object_datatype != file.data_type ())
+ throw rld::error ("Mixed data types not allowed (LSB/MSB).",
+ "elf:check_file: " + file.name ());
+ }
+
+ }
+}
diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h
new file mode 100644
index 0000000..fffe036
--- /dev/null
+++ b/linkers/rld-elf.h
@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker ELF module manages the libelf interface.
+ *
+ */
+
+#if !defined (_RLD_ELF_H_)
+#define _RLD_ELF_H_
+
+#include <list>
+#include <map>
+#include <vector>
+
+#include <rld.h>
+
+namespace rld
+{
+ namespace elf
+ {
+ /**
+ * Forward decl.
+ */
+ class file;
+
+ /**
+ * A relocation record.
+ */
+ class relocation
+ {
+ public:
+ /**
+ * Construct a relocation record.
+ *
+ * @param sym The symbol the relocation references.
+ * @param offset The offset in the section the relocation applies to.
+ * @param info The relocation info.
+ * @param addend The constant addend value.
+ */
+ relocation (const symbols::symbol& sym,
+ elf_addr offset,
+ elf_xword info,
+ elf_sxword addend = 0);
+
+ /**
+ * Default constructor.
+ */
+ relocation ();
+
+ /**
+ * The offset.
+ */
+ elf_addr offset () const;
+
+ /**
+ * The type of the relocation record.
+ */
+ uint32_t type () const;
+
+ /**
+ * The info.
+ */
+ elf_xword info () const;
+
+ /**
+ * The constant addend.
+ */
+ elf_sxword addend () const;
+
+ /**
+ * Return the symbol.
+ */
+ const symbols::symbol& symbol () const;
+
+ private:
+ const symbols::symbol* sym; //< The symbol reference.
+ elf_addr offset_; //< The offset in the section.
+ elf_xword info_; //< The record's information.
+ elf_sxword addend_; //< The constant addend value.
+ };
+
+ /**
+ * A container of relocation records.
+ */
+ typedef std::vector < relocation > relocations;
+
+ /**
+ * An ELF Section. The current implementation only supports a single data
+ * descriptor with a section.
+ */
+ class section
+ {
+ public:
+ /**
+ * Construct the section getting the details from the ELF file given the
+ * section index.
+ *
+ * The section types are (from elf(3)):
+ *
+ * Section Type Library Type Description
+ * ------------ ------------ -----------
+ * SHT_DYNAMIC ELF_T_DYN `.dynamic' section entries.
+ * SHT_DYNSYM ELF_T_SYM Symbols for dynamic linking.
+ * SHT_FINI_ARRAY ELF_T_ADDR Termination function pointers.
+ * SHT_GROUP ELF_T_WORD Section group marker.
+ * SHT_HASH ELF_T_HASH Symbol hashes.
+ * SHT_INIT_ARRAY ELF_T_ADDR Initialization function pointers.
+ * SHT_NOBITS ELF_T_BYTE Empty sections. See elf(5).
+ * SHT_NOTE ELF_T_NOTE ELF note records.
+ * SHT_PREINIT_ARRAY ELF_T_ADDR Pre-initialization function
+ * pointers.
+ * SHT_PROGBITS ELF_T_BYTE Machine code.
+ * SHT_REL ELF_T_REL ELF relocation records.
+ * SHT_RELA ELF_T_RELA Relocation records with addends.
+ * SHT_STRTAB ELF_T_BYTE String tables.
+ * SHT_SYMTAB ELF_T_SYM Symbol tables.
+ * SHT_SYMTAB_SHNDX ELF_T_WORD Used with extended section
+ * numbering.
+ * SHT_GNU_verdef ELF_T_VDEF Symbol version definitions.
+ * SHT_GNU_verneed ELF_T_VNEED Symbol versioning requirements.
+ * SHT_GNU_versym ELF_T_HALF Version symbols.
+ * SHT_SUNW_move ELF_T_MOVE ELF move records.
+ * SHT_SUNW_syminfo ELF_T_SYMINFO Additional symbol flags.
+ *
+ * @param file_ The ELF file this section is part of.
+ * @param index_ The section's index.
+ * @param name The section's name.
+ * @param type The section's type.
+ * @param alignment The section's alignment.
+ * @param flags The section's flags.
+ * @param addr The section's in-memory address.
+ * @param offset The section's offset in the file.
+ * @param size The section's file in bytes.
+ * @param link The section's header table link.
+ * @param info The section's extra information.
+ * @param entry_size The section's entry size.
+ */
+ section (file& file_,
+ int index_,
+ const std::string& name,
+ elf_word type,
+ elf_xword alignment,
+ elf_xword flags,
+ elf_addr addr,
+ elf_off offset,
+ elf_xword size,
+ elf_word link = 0,
+ elf_word info = 0,
+ elf_xword entry_size = 0);
+
+ /**
+ * Construct the section given the details. The ELF file must be
+ * writable.
+ *
+ * @param file_ The ELF file this section is part of.
+ * @param index The section's index in the ELF file.
+ */
+ section (file& file_, int index);
+
+ /**
+ * Copy constructor.
+ */
+ section (const section& orig);
+
+ /**
+ * Default constructor.
+ */
+ section ();
+
+ /**
+ * Add a data segment descriptor to the section if the file is writable.
+ *
+ * These are following data types (from elf(3)):
+ *
+ * ELF_T_ADDR Machine addresses.
+ * ELF_T_BYTE Byte data. The library will not attempt to translate
+ * byte data.
+ * ELF_T_CAP Software and hardware capability records.
+ * ELF_T_DYN Records used in a section of type SHT_DYNAMIC.
+ * ELF_T_EHDR ELF executable header.
+ * ELF_T_HALF 16-bit unsigned words.
+ * ELF_T_LWORD 64 bit unsigned words.
+ * ELF_T_MOVE ELF Move records.
+ * ELF_T_NOTE ELF Note structures.
+ * ELF_T_OFF File offsets.
+ * ELF_T_PHDR ELF program header table entries.
+ * ELF_T_REL ELF relocation entries.
+ * ELF_T_RELA ELF relocation entries with addends.
+ * ELF_T_SHDR ELF section header entries.
+ * ELF_T_SWORD Signed 32-bit words.
+ * ELF_T_SXWORD Signed 64-bit words.
+ * ELF_T_SYMINFO ELF symbol information.
+ * ELF_T_SYM ELF symbol table entries.
+ * ELF_T_VDEF Symbol version definition records.
+ * ELF_T_VNEED Symbol version requirement records.
+ * ELF_T_WORD Unsigned 32-bit words.
+ * ELF_T_XWORD Unsigned 64-bit words.
+ *
+ * @param type The type of data in the segment.
+ * @param alignment The in-file alignment of the data. Must be a power of 2.
+ * @param size The number of bytes in this data descriptor.
+ * @param buffer The data in memory.
+ * @param offset The offset within the containing section. Can be computed.
+ */
+ void add_data (elf_type type,
+ elf_xword alignment,
+ elf_xword size,
+ void* buffer = 0,
+ elf_off offset = 0);
+
+ /**
+ * The section's index in the ELF file.
+ *
+ * @return int The section number.
+ */
+ int index () const;
+
+ /**
+ * The name of the section.
+ *
+ * @return const std::string& The section's name.
+ */
+ const std::string& name () const;
+
+ /**
+ * The section's data.
+ */
+ elf_data* data ();
+
+ /**
+ * Get the type of the section.
+ */
+ elf_word type () const;
+
+ /**
+ * The section flags.
+ */
+ elf_xword flags () const;
+
+ /**
+ * In-memory address of the section.
+ */
+ elf_addr address () const;
+
+ /**
+ * Alignment constraint.
+ */
+ elf_xword alignment () const;
+
+ /**
+ * The file offset of the section.
+ */
+ elf_off offset () const;
+
+ /**
+ * The header table link.
+ */
+ elf_word link () const;
+
+ /**
+ * Extra information.
+ */
+ elf_word info () const;
+
+ /**
+ * Size of the section.
+ */
+ elf_xword size () const;
+
+ /**
+ * Size of the entries in the section.
+ */
+ elf_xword entry_size () const;
+
+ /**
+ * Number of entries.
+ */
+ int entries () const;
+
+ /**
+ * Return true if the relocation record have an addend field.
+ *
+ * @retval true The relocation record have the addend field.
+ */
+ bool get_reloc_type () const;
+
+ /**
+ * Set the name index if writable. This is normally done
+ * automatically when adding the section to the file.
+ */
+ void set_name (unsigned int index);
+
+ /**
+ * Set the type of relocation records.
+ *
+ * @param rela If true the records are rela type.
+ */
+ void set_reloc_type (bool rela);
+
+ /**
+ * Add a relocation.
+ *
+ * @param reloc The relocation record to add.
+ */
+ void add (const relocation& reloc);
+
+ /**
+ * Get the relocations.
+ */
+ const relocations& get_relocations () const;
+
+ private:
+
+ /**
+ * Check the section is valid.
+ *
+ * @param where Where the check is being made.
+ */
+ void check (const char* where) const;
+
+ /**
+ * Check the section is valid and writable.
+ *
+ * @param where Where the check is being made.
+ */
+ void check_writable (const char* where) const;
+
+ file* file_; //< The ELF file.
+ int index_; //< The section header index.
+ std::string name_; //< The section's name.
+ elf_scn* scn; //< ELF private section data.
+ elf_shdr shdr; //< The section header.
+ elf_data* data_; //< The section's data.
+ bool rela; //< The type of relocation records.
+ relocations relocs; //< The relocation records.
+ };
+
+ /**
+ * Container of ELF section pointers.
+ */
+ typedef std::list < section* > sections;
+
+ /**
+ * Container of ELF section as a map, ie associative array.
+ */
+ typedef std::map < std::string, section > section_table;
+
+ /**
+ * An ELF program header.
+ */
+ class program_header
+ {
+ public:
+ /**
+ * Construct a program header.
+ */
+ program_header ();
+
+ /**
+ * Desctruct a program header.
+ */
+ ~program_header ();
+
+ /**
+ * Set the program header.
+ *
+ * @param type The type of segment.
+ * @param flags The segment's flags.
+ * @param offset The offet to segment.
+ * @param filesz The segment size in the file.
+ * @param memsz The segment size in memory.
+ * @param align The segment alignment.
+ * @param vaddr The virtual address in memory.
+ * @param paddr The physical address if any.
+ */
+ void set (elf_word type,
+ elf_word flags,
+ elf_off offset,
+ elf_xword filesz,
+ elf_xword memsz,
+ elf_xword align,
+ elf_addr vaddr,
+ elf_addr paddr = 0);
+
+ private:
+
+ elf_phdr phdr; //< The ELF program header.
+ };
+
+ /**
+ * A container of program headers.
+ */
+ typedef std::list < program_header > program_headers;
+
+ /**
+ * An ELF file.
+ */
+ class file
+ {
+ public:
+ /**
+ * Construct an ELF file.
+ */
+ file ();
+
+ /**
+ * Destruct the ELF file object.
+ */
+ ~file ();
+
+ /**
+ * Begin using the ELF file.
+ *
+ * @param name The full name of the file.
+ * @param fd The file descriptor to read or write the file.
+ * @param writable The file is writeable. The default is false.
+ */
+ void begin (const std::string& name, int fd, const bool writable = false);
+
+ /**
+ * Begin using the ELF file in an archive.
+ *
+ * @param name The full name of the file.
+ * @param archive The file that is the archive.
+ * @param offset The offset of the ELF file in the archive.
+ */
+ void begin (const std::string& name, file& archive, off_t offset);
+
+ /**
+ * End using the ELF file.
+ */
+ void end ();
+
+ /**
+ * Write the ELF file creating it if it is writable. You should have
+ * added the sections and the data segment descriptors to the sections
+ * before calling write.
+ */
+ void write ();
+
+ /**
+ * Load the header. Done automatically.
+ */
+ void load_header ();
+
+ /**
+ * Get the machine type.
+ */
+ unsigned int machinetype () const;
+
+ /**
+ * Get the type of ELF file.
+ */
+ unsigned int type () const;
+
+ /**
+ * Get the class of the object file.
+ */
+ unsigned int object_class () const;
+
+ /**
+ * Get the data type, ie LSB or MSB.
+ */
+ unsigned int data_type () const;
+
+ /**
+ * Is the file an archive format file ?
+ */
+ bool is_archive () const;
+
+ /**
+ * Is the file an executable ?
+ */
+ bool is_executable () const;
+
+ /**
+ * Is the file relocatable ?
+ */
+ bool is_relocatable() const;
+
+ /**
+ * The number of sections in the file.
+ */
+ int section_count () const;
+
+ /**
+ * Load the sections.
+ */
+ void load_sections ();
+
+ /**
+ * Get a filtered container of the sections. The key is the section
+ * type. If the sections are not loaded they are loaded. If the type is 0
+ * all sections are returned.
+ *
+ * @param filtered_secs The container the copy of the filtered sections
+ * are placed in.
+ * @param type The type of sections to filter on. If 0 all sections are
+ * matched.
+ */
+ void get_sections (sections& filtered_secs, unsigned int type);
+
+ /**
+ * Return the section with given index.
+ *
+ * @param index The section's index to look for.
+ * @retval section The section matching the index.
+ */
+ section& get_section (int index);
+
+ /**
+ * Return the index of the string section.
+ */
+ int strings_section () const;
+
+ /**
+ * Get the string from the specified section at the requested offset.
+ *
+ * @param section The section to search for the string.
+ * @param offset The offset in the string section.
+ * @return std::string The string.
+ */
+ std::string get_string (int section, size_t offset);
+
+ /**
+ * Get the string from the ELF header declared string section at the
+ * requested offset.
+ *
+ * @param offset The offset in the string section.
+ * @return std::string The string.
+ */
+ std::string get_string (size_t offset);
+
+ /**
+ * Load the symbols.
+ */
+ void load_symbols ();
+
+ /**
+ * Get a filtered container of symbols given the various types. If the
+ * symbols are not loaded they are loaded.
+ *
+ * @param filtered_syms The filtered symbols found in the file. This is a
+ * container of pointers.
+ * @param unresolved Return unresolved symbols.
+ * @param local Return local symbols.
+ * @param weak Return weak symbols.
+ * @param global Return global symbols.
+ */
+ void get_symbols (rld::symbols::pointers& filtered_syms,
+ bool unresolved = false,
+ bool local = false,
+ bool weak = true,
+ bool global = true);
+
+ /**
+ * Get the symbol by index in the symtabl section.
+ */
+ const symbols::symbol& get_symbol (const int index) const;
+
+ /**
+ * Load the relocation records.
+ */
+ void load_relocations ();
+
+ /**
+ * Clear the relocation records.
+ */
+ void clear_relocations ();
+
+ /**
+ * Set the ELF header. Must be writable.
+ *
+ * The classes are:
+ * ELFCLASSNONE This class is invalid.
+ * ELFCLASS32 This defines the 32-bit architecture. It sup- ports
+ * machines with files and virtual address spa- ces up to
+ * 4 Gigabytes.
+ * ELFCLASS64 This defines the 64-bit architecture.
+ *
+ * The types are:
+ * ET_NONE An unknown type.
+ * ET_REL A relocatable file.
+ * ET_EXEC An executable file.
+ * ET_DYN A shared object.
+ * ET_CORE A core file.
+ *
+ * The machine types are:
+ * TDB
+ *
+ * The datatypes are:
+ * ELFDATA2LSB Two's complement, little-endian.
+ * ELFDATA2MSB Two's complement, big-endian.
+ *
+ * @param type The type of ELF file, ie executable, relocatable etc.
+ * @param class_ The files ELF class.
+ * @param machinetype The type of machine code present in the ELF file.
+ * @param datatype The data type, ie LSB or MSB.
+ */
+ void set_header (elf_half type,
+ int class_,
+ elf_half machinetype,
+ unsigned char datatype);
+
+ /**
+ * Add a section to the ELF file if writable.
+ */
+ void add (section& sec);
+
+ /**
+ * Add a program header to the ELF file if writable.
+ */
+ void add (program_header& phdr);
+
+ /**
+ * Get the ELF reference.
+ */
+ elf* get_elf ();
+
+ /**
+ * Get the name of the file.
+ */
+ const std::string& name () const;
+
+ /**
+ * Is the file writable ?
+ */
+ bool is_writable () const;
+
+ private:
+
+ /**
+ * Begin using the ELF file.
+ *
+ * @param name The full name of the file.
+ * @param fd The file descriptor to read or write the file.
+ * @param writable The file is writeable. It cannot be part of an archive.
+ * @param archive The archive's ELF handle or 0 if not an archive.
+ * @param offset The offset of the ELF file in the archive if elf is non-zero.
+ */
+ void begin (const std::string& name,
+ int fd,
+ const bool writable,
+ file* archive,
+ off_t offset);
+
+ /**
+ * Check if the file is usable. Throw an exception if not.
+ *
+ * @param where Where the check is performed.
+ */
+ void check (const char* where) const;
+
+ /**
+ * Check if the file is usable and writable. Throw an exception if not.
+ *
+ * @param where Where the check is performed.
+ */
+ void check_writable (const char* where) const;
+
+ /**
+ * Check if the ELF header is valid. Throw an exception if not.
+ *
+ * @param where Where the check is performed.
+ */
+ void check_ehdr (const char* where) const;
+
+ /**
+ * Check if the ELF program header is valid. Throw an exception if not.
+ *
+ * @param where Where the check is performed.
+ */
+ void check_phdr (const char* where) const;
+
+ /**
+ * Generate libelf error.
+ *
+ * @param where Where the error is generated.
+ */
+ void error (const char* where) const;
+
+ int fd_; //< The file handle.
+ std::string name_; //< The name of the file.
+ bool archive; //< The ELF file is part of an archive.
+ bool writable; //< The file is writeable.
+ elf* elf_; //< The ELF handle.
+ unsigned int mtype; //< The machine type.
+ unsigned int oclass; //< The object class.
+ const char* ident_str; //< The ELF file's ident string.
+ size_t ident_size; //< The size of the ident.
+ elf_ehdr* ehdr; //< The ELF header.
+ elf_phdr* phdr; //< The ELF program header.
+ section_table secs; //< The sections as a table.
+ program_headers phdrs; //< The program headers when creating
+ // ELF files.
+ rld::symbols::bucket symbols; //< The symbols. All tables point here.
+ };
+
+ /**
+ * Return the machine type label given the machine type.
+ *
+ * @param machinetype The ELF machine type.
+ */
+ const std::string machine_type (unsigned int machinetype);
+
+ /**
+ * Return the global machine type set by the check_file call as a string.
+ */
+ const std::string machine_type ();
+
+ /**
+ * Return the global class set by the check_file call.
+ */
+ unsigned int object_class ();
+
+ /**
+ * Return the global machine type set by the check_file call.
+ */
+ unsigned int object_machine_type ();
+
+ /**
+ * Return the global data type set by the check_file call.
+ */
+ unsigned int object_datatype ();
+
+ /**
+ * Check the file against the global machine type, object class and data
+ * type. If this is the first file checked it becomes the default all
+ * others are checked against. This is a simple way to make sure all files
+ * are the same type.
+ *
+ * @param file The check to check.
+ */
+ void check_file(const file& file);
+
+ }
+}
+
+#endif
diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp
new file mode 100644
index 0000000..63255b8
--- /dev/null
+++ b/linkers/rld-files.cpp
@@ -0,0 +1,1675 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <algorithm>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rld.h>
+
+#if __WIN32__
+#define CREATE_MODE (S_IRUSR | S_IWUSR)
+#define OPEN_FLAGS (O_BINARY)
+#else
+#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
+#define OPEN_FLAGS (0)
+#endif
+
+namespace rld
+{
+ namespace files
+ {
+ /**
+ * Scan the decimal number returning the value found.
+ */
+ uint64_t
+ scan_decimal (const uint8_t* string, size_t len)
+ {
+ uint64_t value = 0;
+
+ while (len && (*string != ' '))
+ {
+ value *= 10;
+ value += *string - '0';
+ ++string;
+ --len;
+ }
+
+ return value;
+ }
+
+ void
+ set_number (uint32_t value, uint8_t* string, size_t len, bool octal = false)
+ {
+ std::ostringstream oss;
+ if (octal)
+ oss << std::oct;
+ oss << value;
+ size_t l = oss.str ().length ();
+ if (l > len)
+ l = len;
+ memcpy (string, oss.str ().c_str (), l);
+ }
+
+ std::string
+ basename (const std::string& name)
+ {
+ size_t b = name.find_last_of (RLD_PATH_SEPARATOR);
+ if (b != std::string::npos)
+ return name.substr (b + 1);
+ return name;
+ }
+
+ std::string
+ dirname (const std::string& name)
+ {
+ size_t b = name.find_last_of (RLD_PATH_SEPARATOR);
+ if (b != std::string::npos)
+ return name.substr (0, b - 1);
+ return name;
+ }
+
+ std::string
+ extension (const std::string& name)
+ {
+ size_t b = name.find_last_of ('.');
+ if (b != std::string::npos)
+ return name.substr (b);
+ return name;
+ }
+
+ void
+ path_split (const std::string& path, rld::files::paths& paths)
+ {
+ strings ps;
+ rld::split (path, ps, RLD_PATHSTR_SEPARATOR);
+ if (ps.size ())
+ {
+ for (strings::iterator psi = ps.begin ();
+ psi != ps.end ();
+ ++psi)
+ {
+ if (check_directory (*psi))
+ paths.push_back (*psi);
+ }
+ }
+ }
+
+ void
+ path_join (const std::string& path_, const std::string& file_, std::string& joined)
+ {
+ if ((path_[path_.size () - 1] != RLD_PATH_SEPARATOR) &&
+ (file_[0] != RLD_PATH_SEPARATOR))
+ joined = path_ + RLD_PATH_SEPARATOR + file_;
+ else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) &&
+ (file_[0] == RLD_PATH_SEPARATOR))
+ joined = path_ + &file_[1];
+ else
+ joined = path_ + file_;
+ }
+
+ bool
+ check_file (const std::string& path)
+ {
+ struct stat sb;
+ if (::stat (path.c_str (), &sb) == 0)
+ if (S_ISREG (sb.st_mode))
+ return true;
+ return false;
+ }
+
+ bool
+ check_directory (const std::string& path)
+ {
+ struct stat sb;
+ if (::stat (path.c_str (), &sb) == 0)
+ if (S_ISDIR (sb.st_mode))
+ return true;
+ return false;
+ }
+
+ void
+ find_file (std::string& path, const std::string& name, paths& search_paths)
+ {
+ for (rld::files::paths::iterator pi = search_paths.begin ();
+ pi != search_paths.end ();
+ ++pi)
+ {
+ path_join (*pi, name, path);
+ if (check_file (path))
+ return;
+ }
+ path.clear ();
+ }
+
+ file::file (const std::string& aname,
+ const std::string& oname,
+ off_t offset,
+ size_t size)
+ : aname_ (aname),
+ oname_ (oname),
+ offset_ (offset),
+ size_ (size)
+ {
+ }
+
+ file::file (const std::string& path, bool is_object)
+ : offset_ (0),
+ size_ (0)
+ {
+ set (path, is_object);
+ }
+
+ file::file ()
+ : offset_ (0),
+ size_ (0)
+ {
+ }
+
+ void
+ file::set (const std::string& path, bool is_object)
+ {
+ /*
+ * If there is a path look for a colon. If there is no colon we assume
+ * it is an object file. If the colon is the last character in the path
+ * it is just an archive.
+ */
+ if (!path.empty ())
+ {
+ bool get_size = false;
+ if (is_object)
+ {
+ size_t colon = path.find_last_of (':');
+ if ((colon != std::string::npos) && (colon > RLD_DRIVE_SEPARATOR))
+ {
+ aname_ = path.substr (0, colon - 1);
+ oname_ = path.substr (colon + 1);
+ // @todo Add offset scanning.
+ }
+ else
+ {
+ oname_ = path;
+ get_size = true;
+ }
+ }
+ else
+ {
+ aname_ = path;
+ get_size = true;
+ }
+
+ if (get_size)
+ {
+ struct stat sb;
+ if (::stat (path.c_str (), &sb) == 0)
+ size_ = sb.st_size;
+ }
+ }
+ }
+
+ bool
+ file::is_archive () const
+ {
+ return !aname_.empty () && oname_.empty ();
+ }
+
+ bool
+ file::is_object () const
+ {
+ return !oname_.empty ();
+ }
+
+ bool
+ file::is_valid () const
+ {
+ return !aname_.empty () || ~oname_.empty ();
+ }
+
+ bool
+ file::exists () const
+ {
+ /*
+ * No name set returns false.
+ */
+ bool result = false;
+ const std::string p = path ();
+ if (!p.empty ())
+ result = check_file (p);
+ return result;
+ }
+
+ const std::string
+ file::path () const
+ {
+ if (!aname_.empty ())
+ return aname_;
+ return oname_;
+ }
+
+ const std::string
+ file::full () const
+ {
+ std::string f;
+ if (!aname_.empty ())
+ {
+ f = aname_;
+ if (!oname_.empty ())
+ f += ':';
+ }
+ if (!oname_.empty ())
+ f += oname_;
+ if (!aname_.empty () && !oname_.empty ())
+ f += '@' + rld::to_string (offset_);
+ return f;
+ }
+
+ const std::string
+ file::basename () const
+ {
+ return rld::files::basename (full ());
+ }
+
+ const std::string&
+ file::aname () const
+ {
+ return aname_;
+ }
+
+ const std::string&
+ file::oname () const
+ {
+ return oname_;
+ }
+
+ off_t
+ file::offset () const
+ {
+ return offset_;
+ }
+
+ size_t
+ file::size () const
+ {
+ return size_;
+ }
+
+ image::image (file& name)
+ : name_ (name),
+ references_ (0),
+ fd_ (-1),
+ symbol_refs (0),
+ writable (false)
+ {
+ }
+
+ image::image (const std::string& path, bool is_object)
+ : name_ (path, is_object),
+ references_ (0),
+ fd_ (-1),
+ symbol_refs (0),
+ writable (false)
+ {
+ }
+
+ image::image ()
+ : references_ (0),
+ fd_ (-1),
+ symbol_refs (0),
+ writable (false)
+ {
+ }
+
+ image::~image ()
+ {
+ if (references_)
+ throw rld_error_at ("references when destructing image");
+ if (fd_ >= 0)
+ ::close (fd_);
+ }
+
+ void
+ image::open (file& name)
+ {
+ name_ = name;
+ open ();
+ }
+
+ void
+ image::open (bool writable_)
+ {
+ const std::string path = name_.path ();
+
+ if (path.empty ())
+ throw rld::error ("No file name", "open:" + path);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
+ std::cout << "image::open: " << name (). full ()
+ << " refs:" << references_ + 1
+ << " writable:" << (char*) (writable_ ? "yes" : "no")
+ << std::endl;
+
+ if (fd_ < 0)
+ {
+ writable = writable_;
+
+ if (writable)
+ fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE);
+ else
+ fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY);
+ if (fd_ < 0)
+ throw rld::error (::strerror (errno), "open:" + path);
+ }
+ else
+ {
+ if (writable_ != writable)
+ throw rld::error ("Cannot change write status", "open:" + path);
+ }
+
+ ++references_;
+ }
+
+ void
+ image::close ()
+ {
+ if (references_ > 0)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
+ std::cout << "image::close: " << name ().full ()
+ << " refs:" << references_ << std::endl;
+
+ --references_;
+ if (references_ == 0)
+ {
+ ::close (fd_);
+ fd_ = -1;
+ }
+ }
+ }
+
+ ssize_t
+ image::read (void* buffer_, size_t size)
+ {
+ uint8_t* buffer = static_cast <uint8_t*> (buffer_);
+ size_t have_read = 0;
+ size_t to_read = size;
+ while (have_read < size)
+ {
+ const ssize_t rsize = ::read (fd (), buffer, to_read);
+ if (rsize < 0)
+ throw rld::error (strerror (errno), "read:" + name ().path ());
+ if (rsize == 0)
+ break;
+ have_read += rsize;
+ to_read -= rsize;
+ buffer += rsize;
+ }
+ return have_read;
+ }
+
+ ssize_t
+ image::write (const void* buffer_, size_t size)
+ {
+ const uint8_t* buffer = static_cast <const uint8_t*> (buffer_);
+ size_t have_written = 0;
+ size_t to_write = size;
+ while (have_written < size)
+ {
+ const ssize_t wsize = ::write (fd (), buffer, to_write);
+ if (wsize < 0)
+ throw rld::error (strerror (errno), "write:" + name ().path ());
+ have_written += wsize;
+ to_write -= wsize;
+ buffer += wsize;
+ }
+ return have_written;
+ }
+
+ void
+ image::seek (off_t offset)
+ {
+ if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0)
+ throw rld::error (strerror (errno), "lseek:" + name ().path ());
+ }
+
+ bool
+ image::seek_read (off_t offset, uint8_t* buffer, size_t size)
+ {
+ seek (offset);
+ return size == (size_t) read (buffer, size);
+ }
+
+ bool
+ image::seek_write (off_t offset, const void* buffer, size_t size)
+ {
+ seek (offset);
+ return size == (size_t) write (buffer, size);
+ }
+
+ const file&
+ image::name () const
+ {
+ return name_;
+ }
+
+ int
+ image::references () const
+ {
+ return references_;
+ }
+
+ size_t
+ image::size () const
+ {
+ return name ().size ();
+ }
+
+ int
+ image::fd () const
+ {
+ return fd_;
+ }
+
+ rld::elf::file&
+ image::elf ()
+ {
+ return elf_;
+ }
+
+ void
+ image::symbol_referenced ()
+ {
+ ++symbol_refs;
+ }
+
+ int
+ image::symbol_references () const
+ {
+ return symbol_refs;
+ }
+
+ void
+ copy_file (image& in, image& out, size_t size)
+ {
+ #define COPY_FILE_BUFFER_SIZE (8 * 1024)
+ uint8_t* buffer = 0;
+
+ if (size == 0)
+ size = in.name ().size ();
+
+ try
+ {
+ buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
+ while (size)
+ {
+ /*
+ * @fixme the reading and writing are not POSIX; sigints could split them.
+ */
+
+ size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE;
+ ssize_t r = ::read (in.fd (), buffer, l);
+
+ if (r < 0)
+ throw rld::error (::strerror (errno), "reading: " + in.name ().full ());
+
+ if (r == 0)
+ {
+ std::ostringstream oss;
+ oss << "reading: " + in.name ().full () << " (" << size << ')';
+ throw rld::error ("input too short", oss.str ());
+ }
+
+ ssize_t w = ::write (out.fd (), buffer, r);
+
+ if (w < 0)
+ throw rld::error (::strerror (errno), "writing: " + out.name ().full ());
+
+ if (w != r)
+ throw rld::error ("output trucated", "writing: " + out.name ().full ());
+
+ size -= r;
+ }
+ }
+ catch (...)
+ {
+ delete [] buffer;
+ throw;
+ }
+
+ if (buffer)
+ delete [] buffer;
+ }
+
+ /**
+ * Defines for the header of an archive.
+ */
+ #define rld_archive_ident "!<arch>\n"
+ #define rld_archive_ident_size (sizeof (rld_archive_ident) - 1)
+ #define rld_archive_fhdr_base rld_archive_ident_size
+ #define rld_archive_fname (0)
+ #define rld_archive_fname_size (16)
+ #define rld_archive_mtime (16)
+ #define rld_archive_mtime_size (12)
+ #define rld_archive_uid (28)
+ #define rld_archive_uid_size (6)
+ #define rld_archive_gid (34)
+ #define rld_archive_gid_size (6)
+ #define rld_archive_mode (40)
+ #define rld_archive_mode_size (8)
+ #define rld_archive_size (48)
+ #define rld_archive_size_size (10)
+ #define rld_archive_magic (58)
+ #define rld_archive_magic_size (2)
+ #define rld_archive_fhdr_size (60)
+ #define rld_archive_max_file_size (1024)
+
+ archive::archive (const std::string& path)
+ : image (path, false)
+ {
+ if (!name ().is_valid ())
+ throw rld_error_at ("name is empty");
+ if (!name ().is_archive ())
+ throw rld_error_at ("name is not an archive: " + name ().oname ());
+ }
+
+ archive::~archive ()
+ {
+ end ();
+ close ();
+ }
+
+ void
+ archive::begin ()
+ {
+ if (references () == 1)
+ {
+ elf ().begin (name ().full (), fd ());
+
+ /*
+ * Make sure it is an archive.
+ */
+ if (!elf ().is_archive ())
+ throw rld::error ("Not an archive.",
+ "archive-begin:" + name ().full ());
+ }
+ }
+
+ void
+ archive::end ()
+ {
+ if (references () == 1)
+ elf ().end ();
+ }
+
+ bool
+ archive::is (const std::string& path) const
+ {
+ return name ().path () == path;
+ }
+
+ bool
+ archive::is_valid ()
+ {
+ open ();
+ uint8_t header[rld_archive_ident_size];
+ seek_read (0, &header[0], rld_archive_ident_size);
+ bool result = ::memcmp (header, rld_archive_ident,
+ rld_archive_ident_size) == 0 ? true : false;
+ close ();
+ return result;
+ }
+
+ void
+ archive::load_objects (objects& objs)
+ {
+ off_t extended_file_names = 0;
+ off_t offset = rld_archive_fhdr_base;
+ size_t size = 0;
+
+ while (true)
+ {
+ uint8_t header[rld_archive_fhdr_size];
+
+ if (!read_header (offset, &header[0]))
+ break;
+
+ /*
+ * The archive file headers are always aligned to an even address.
+ */
+ size =
+ (scan_decimal (&header[rld_archive_size],
+ rld_archive_size_size) + 1) & ~1;
+
+ /*
+ * Check for the GNU extensions.
+ */
+ if (header[0] == '/')
+ {
+ off_t extended_off;
+
+ switch (header[1])
+ {
+ case ' ':
+ /*
+ * Symbols table. Ignore the table.
+ */
+ break;
+ case '/':
+ /*
+ * Extended file names table. Remember.
+ */
+ extended_file_names = offset + rld_archive_fhdr_size;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /*
+ * Offset into the extended file name table. If we do not have the
+ * offset to the extended file name table find it.
+ */
+ extended_off = scan_decimal (&header[1], rld_archive_fname_size);
+
+ if (extended_file_names == 0)
+ {
+ off_t off = offset;
+ while (extended_file_names == 0)
+ {
+ size_t esize =
+ (scan_decimal (&header[rld_archive_size],
+ rld_archive_size_size) + 1) & ~1;
+ off += esize + rld_archive_fhdr_size;
+
+ if (!read_header (off, &header[0]))
+ throw rld::error ("No GNU extended file name section found",
+ "get-names:" + name ().path ());
+
+ if ((header[0] == '/') && (header[1] == '/'))
+ {
+ extended_file_names = off + rld_archive_fhdr_size;
+ break;
+ }
+ }
+ }
+
+ if (extended_file_names)
+ {
+ /*
+ * We know the offset in the archive to the extended file. Read
+ * the name from the table and compare with the name we are
+ * after.
+ */
+ char cname[rld_archive_max_file_size];
+ seek_read (extended_file_names + extended_off,
+ (uint8_t*) &cname[0], rld_archive_max_file_size);
+ add_object (objs, cname,
+ offset + rld_archive_fhdr_size, size);
+ }
+ break;
+ default:
+ /*
+ * Ignore the file because we do not know what it it.
+ */
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Normal archive name.
+ */
+ add_object (objs,
+ (char*) &header[rld_archive_fname],
+ offset + rld_archive_fhdr_size, size);
+ }
+
+ offset += size + rld_archive_fhdr_size;
+ }
+ }
+
+ bool
+ archive::operator< (const archive& rhs) const
+ {
+ return name ().path () < rhs.name ().path ();
+ }
+
+ bool
+ archive::read_header (off_t offset, uint8_t* header)
+ {
+ if (!seek_read (offset, header, rld_archive_fhdr_size))
+ return false;
+
+ if ((header[rld_archive_magic] != 0x60) ||
+ (header[rld_archive_magic + 1] != 0x0a))
+ throw rld::error ("Invalid header magic numbers at " +
+ rld::to_string (offset), "read-header:" + name ().path ());
+
+ return true;
+ }
+
+ void
+ archive::add_object (objects& objs, const char* path, off_t offset, size_t size)
+ {
+ const char* end = path;
+ while ((*end != '\0') && (*end != '/') && (*end != '\n'))
+ ++end;
+
+ std::string str;
+ str.append (path, end - path);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "archive::add-object: " << str << std::endl;
+
+ file n (name ().path (), str, offset, size);
+ objs[n.full()] = new object (*this, n);
+ }
+
+ void
+ archive::write_header (const std::string& name,
+ uint32_t mtime,
+ int uid,
+ int gid,
+ int mode,
+ size_t size)
+ {
+ uint8_t header[rld_archive_fhdr_size];
+
+ memset (header, ' ', sizeof (header));
+
+ size_t len = name.length ();
+ if (len > rld_archive_fname_size)
+ len = rld_archive_fname_size;
+ memcpy (&header[rld_archive_fname], &name[0], len);
+
+ set_number (mtime, header + rld_archive_mtime, rld_archive_mtime_size);
+ set_number (uid, header + rld_archive_uid, rld_archive_uid_size);
+ set_number (gid, header + rld_archive_gid, rld_archive_gid_size);
+ set_number (mode, header + rld_archive_mode, rld_archive_mode_size, true);
+ set_number (size, header + rld_archive_size, rld_archive_size_size);
+
+ header[rld_archive_magic] = 0x60;
+ header[rld_archive_magic + 1] = 0x0a;
+
+ write (header, sizeof (header));
+ }
+
+ void
+ archive::create (object_list& objects)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << "archive::create: " << name ().full ()
+ << ", objects: " << objects.size () << std::endl;
+
+ open (true);
+
+ try
+ {
+ seek_write (0, rld_archive_ident, rld_archive_ident_size);
+
+ /*
+ * GNU extended filenames.
+ */
+ std::string extended_file_names;
+
+ for (object_list::iterator oi = objects.begin ();
+ oi != objects.end ();
+ ++oi)
+ {
+ object& obj = *(*oi);
+ const std::string& oname = basename (obj.name ().oname ());
+ if (oname.length () >= rld_archive_fname_size)
+ extended_file_names += oname + '\n';
+ }
+
+ if (!extended_file_names.empty ())
+ {
+ if (extended_file_names.length () & 1)
+ {
+ extended_file_names += ' ';
+ }
+ write_header ("//", 0, 0, 0, 0, extended_file_names.length ());
+ write (extended_file_names.c_str (), extended_file_names.length ());
+ }
+
+ for (object_list::iterator oi = objects.begin ();
+ oi != objects.end ();
+ ++oi)
+ {
+ object& obj = *(*oi);
+
+ obj.open ();
+
+ try
+ {
+ std::string oname = basename (obj.name ().oname ());
+
+ /*
+ * Convert the file name to an offset into the extended file name
+ * table if the file name is too long for the header.
+ */
+
+ if (oname.length () >= rld_archive_fname_size)
+ {
+ size_t pos = extended_file_names.find (oname + '\n');
+ if (pos == std::string::npos)
+ throw rld_error_at ("extended file name not found");
+ std::ostringstream oss;
+ oss << '/' << pos;
+ oname = oss.str ();
+ }
+ else oname += '/';
+
+ write_header (oname, 0, 0, 0, 0666, (obj.name ().size () + 1) & ~1);
+ obj.seek (0);
+ copy_file (obj, *this);
+ if (obj.name ().size () & 1)
+ write ("\n", 1);
+ }
+ catch (...)
+ {
+ obj.close ();
+ throw;
+ }
+
+ obj.close ();
+ }
+ }
+ catch (...)
+ {
+ close ();
+ throw;
+ }
+
+ close ();
+ }
+
+ relocation::relocation (const elf::relocation& er)
+ : offset (er.offset ()),
+ type (er.type ()),
+ info (er.info ()),
+ addend (er.addend ()),
+ symname (er.symbol ().name ()),
+ symtype (er.symbol ().type ()),
+ symsect (er.symbol ().section_index ()),
+ symvalue (er.symbol ().value ()),
+ symbinding (er.symbol ().binding ())
+ {
+ }
+
+ section::section (const elf::section& es)
+ : name (es.name ()),
+ index (es.index ()),
+ type (es.type ()),
+ size (es.size ()),
+ alignment (es.alignment ()),
+ link (es.link ()),
+ info (es.info ()),
+ flags (es.flags ()),
+ offset (es.offset ()),
+ rela (es.get_reloc_type ())
+ {
+ }
+
+ void
+ section::load_relocations (const elf::section& es)
+ {
+ const elf::relocations& es_relocs = es.get_relocations ();
+ for (elf::relocations::const_iterator ri = es_relocs.begin ();
+ ri != es_relocs.end ();
+ ++ri)
+ {
+ relocs.push_back (relocation (*ri));
+ }
+ rela = es.get_reloc_type ();
+ }
+
+ size_t
+ sum_sizes (const sections& secs)
+ {
+ size_t size = 0;
+
+ for (sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ const section& sec = *si;
+
+ if ((size % sec.alignment) != 0)
+ size -= (size % sec.alignment) + sec.alignment;
+ size += sec.size;
+ }
+
+ return size;
+ }
+
+ const section*
+ find (const sections& secs, const int index)
+ {
+ for (sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ const section& sec = *si;
+
+ if (index == sec.index)
+ return &sec;
+ }
+
+ return 0;
+ }
+
+ object::object (archive& archive_, file& name_)
+ : image (name_),
+ archive_ (&archive_),
+ valid_ (false),
+ resolving_ (false),
+ resolved_ (false)
+ {
+ if (!name ().is_valid ())
+ throw rld_error_at ("name is empty");
+ }
+
+ object::object (const std::string& path)
+ : image (path),
+ archive_ (0),
+ valid_ (false),
+ resolving_ (false),
+ resolved_ (false)
+ {
+ if (!name ().is_valid ())
+ throw rld_error_at ("name is empty");
+ }
+
+ object::object ()
+ : archive_ (0),
+ valid_ (false),
+ resolving_ (false),
+ resolved_ (false)
+ {
+ }
+
+ object::~object ()
+ {
+ end ();
+ close ();
+ }
+
+ void
+ object::open (bool writable)
+ {
+ if (archive_)
+ {
+ if (writable)
+ throw rld_error_at ("object files in archives are not writable");
+ archive_->open ();
+ }
+ else
+ image::open (writable);
+ }
+
+ void
+ object::close ()
+ {
+ if (archive_)
+ {
+ archive_->end ();
+ archive_->close ();
+ }
+ else
+ {
+ end ();
+ image::close ();
+ }
+ }
+
+ void
+ object::begin ()
+ {
+ /*
+ * Begin a session.
+ */
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
+ std::cout << "object:begin: " << name ().full () << " in-archive:"
+ << ((char*) (archive_ ? "yes" : "no")) << std::endl;
+
+ if (archive_)
+ elf ().begin (name ().full (), archive_->elf(), name ().offset ());
+ else
+ elf ().begin (name ().full (), fd (), is_writable ());
+
+ /*
+ * Cannot be an archive.
+ */
+ if (elf ().is_archive ())
+ throw rld::error ("Is an archive not an object file.",
+ "object-begin:" + name ().full ());
+
+ /*
+ * We only support executable or relocatable ELF files.
+ */
+ if (!is_writable ())
+ {
+ if (!elf ().is_executable () && !elf ().is_relocatable ())
+ throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
+ "object-begin:" + name ().full ());
+
+ elf::check_file (elf ());
+
+ /**
+ * We assume the ELF file is invariant over the linking process.
+ */
+
+ if (secs.empty ())
+ {
+ elf::sections elf_secs;
+
+ elf ().get_sections (elf_secs, 0);
+
+ for (elf::sections::const_iterator esi = elf_secs.begin ();
+ esi != elf_secs.end ();
+ ++esi)
+ {
+ secs.push_back (section (*(*esi)));
+ }
+ }
+ }
+
+ /*
+ * This is a valid object file. The file format checks out.
+ */
+ valid_ = true;
+ }
+
+ void
+ object::end ()
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
+ std::cout << "object:end: " << name ().full () << std::endl;
+
+ elf ().end ();
+ }
+
+ bool
+ object::valid () const
+ {
+ return valid_;
+ }
+
+ void
+ object::load_symbols (rld::symbols::table& symbols, bool local)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ std::cout << "object:load-sym: " << name ().full () << std::endl;
+
+ rld::symbols::pointers syms;
+
+ elf ().get_symbols (syms, false, local, false, true);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ std::cout << "object:load-sym: exported: total "
+ << syms.size () << std::endl;
+
+ for (symbols::pointers::iterator si = syms.begin ();
+ si != syms.end ();
+ ++si)
+ {
+ symbols::symbol& sym = *(*si);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ std::cout << "object:load-sym: exported: " << sym << std::endl;
+
+ sym.set_object (*this);
+ symbols.add_external (sym);
+ externals.push_back (&sym);
+ }
+
+ elf ().get_symbols (syms, false, false, true, false);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ std::cout << "object:load-sym: weak: total "
+ << syms.size () << std::endl;
+
+ for (symbols::pointers::iterator si = syms.begin ();
+ si != syms.end ();
+ ++si)
+ {
+ symbols::symbol& sym = *(*si);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ std::cout << "object:load-sym: weak: " << sym << std::endl;
+
+ sym.set_object (*this);
+ symbols.add_weak (sym);
+ externals.push_back (&sym);
+ }
+
+ elf ().get_symbols (syms, true, false, true, true);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ std::cout << "object:load-sym: unresolved: total "
+ << syms.size () << std::endl;
+
+ for (symbols::pointers::iterator si = syms.begin ();
+ si != syms.end ();
+ ++si)
+ {
+ symbols::symbol& sym = *(*si);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
+ {
+ std::cout << "object:load-sym: unresolved: ";
+ sym.output (std::cout);
+ std::cout << std::endl;
+ }
+
+ unresolved[sym.name ()] = &sym;
+ }
+ }
+
+ void
+ object::load_relocations ()
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "object:load-relocs: " << name ().full () << std::endl;
+
+ elf ().load_relocations ();
+
+ for (sections::iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ section& sec = *si;
+ const elf::section& elf_sec = elf ().get_section (sec.index);
+ sec.load_relocations (elf_sec);
+ }
+ }
+
+ int
+ object::references () const
+ {
+ if (archive_)
+ return archive_->references ();
+ return image::references ();
+ }
+
+ size_t
+ object::size () const
+ {
+ if (archive_)
+ return archive_->size ();
+ return image::size ();
+ }
+
+ int
+ object::fd () const
+ {
+ if (archive_)
+ return archive_->fd ();
+ return image::fd ();
+ }
+
+ void
+ object::symbol_referenced ()
+ {
+ image::symbol_referenced ();
+ if (archive_)
+ archive_->symbol_referenced ();
+ }
+
+ archive*
+ object::get_archive ()
+ {
+ return archive_;
+ }
+
+ rld::symbols::symtab&
+ object::unresolved_symbols ()
+ {
+ return unresolved;
+ }
+
+ rld::symbols::pointers&
+ object::external_symbols ()
+ {
+ return externals;
+ }
+
+ void
+ object::get_sections (sections& filtered_secs,
+ uint32_t type,
+ uint64_t flags_in,
+ uint64_t flags_out)
+ {
+ for (sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ const section& sec = *si;
+ if ((type == 0) || (type == sec.type))
+ {
+ if ((flags_in == 0) ||
+ (((sec.flags & flags_in) == flags_in) &&
+ ((sec.flags & flags_out) == 0)))
+ {
+ filtered_secs.push_back (sec);
+ }
+ }
+ }
+ }
+
+ void
+ object::get_sections (sections& filtered_secs, const std::string& matching_name)
+ {
+ for (sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ const section& sec = *si;
+ if (sec.name == matching_name)
+ {
+ filtered_secs.push_back (sec);
+ }
+ }
+ }
+
+ const section&
+ object::get_section (int index) const
+ {
+ for (sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ const section& sec = *si;
+ if (sec.index == index)
+ return sec;
+ }
+
+ throw rld::error ("Section index '" + rld::to_string (index) +
+ "' not found: " + name ().full (), "object::get-section");
+ }
+
+ void
+ object::resolve_set ()
+ {
+ resolving_ = true;
+ }
+
+ void
+ object::resolve_clear ()
+ {
+ resolving_ = false;
+ }
+
+ bool
+ object::resolving () const
+ {
+ return resolving_;
+ }
+
+ void
+ object::resolved_set ()
+ {
+ resolved_ = true;
+ }
+
+ bool
+ object::resolved () const
+ {
+ return resolved_;
+ }
+
+ cache::cache ()
+ : opened (false)
+ {
+ }
+
+ cache::~cache ()
+ {
+ close ();
+ }
+
+ void
+ cache::open ()
+ {
+ if (!opened)
+ {
+ collect_object_files ();
+ archives_begin ();
+ opened = true;
+ }
+ }
+
+ void
+ cache::close ()
+ {
+ if (opened)
+ {
+ /*
+ * Must delete the object first as they could depend on archives.
+ */
+ for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
+ delete (*oi).second;
+ for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
+ delete (*ai).second;
+ opened = false;
+ }
+ }
+
+ void
+ cache::add (const std::string& path)
+ {
+ paths_.push_back (path);
+ input (path);
+ }
+
+ void
+ cache::add (paths& paths__)
+ {
+ for (paths::iterator pi = paths__.begin();
+ pi != paths__.end();
+ ++pi)
+ add (*pi);
+ }
+
+ void
+ cache::add_libraries (paths& paths__)
+ {
+ for (paths::iterator pi = paths__.begin();
+ pi != paths__.end();
+ ++pi)
+ input (*pi);
+ }
+
+ void
+ cache::archive_begin (const std::string& path)
+ {
+ archives::iterator ai = archives_.find (path);
+ if (ai != archives_.end ())
+ {
+ archive* ar = (*ai).second;
+ if (!ar->is_open ())
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "cache:archive-begin: " << path << std::endl;
+ ar->open ();
+ ar->begin ();
+ }
+ }
+ }
+
+ void
+ cache::archive_end (const std::string& path)
+ {
+ archives::iterator ai = archives_.find (path);
+ if (ai != archives_.end ())
+ {
+ archive* ar = (*ai).second;
+ if (ar->is_open ())
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "cache:archive-end: " << path << std::endl;
+ ar->end ();
+ ar->close ();
+ }
+ }
+ }
+
+ void
+ cache::archives_begin ()
+ {
+ for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
+ archive_begin (((*ai).second)->path ());
+ }
+
+ void
+ cache::archives_end ()
+ {
+ for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
+ archive_end (((*ai).second)->path ());
+ }
+
+ void
+ cache::collect_object_files ()
+ {
+ for (paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
+ collect_object_files (*ni);
+ }
+
+ void
+ cache::collect_object_files (const std::string& path)
+ {
+ archive* ar = new archive (path);
+
+ if (ar->is_valid ())
+ {
+ try
+ {
+ ar->open ();
+ ar->load_objects (objects_);
+ ar->close ();
+ archives_[path] = ar;
+ }
+ catch (...)
+ {
+ delete ar;
+ throw;
+ }
+ }
+ else
+ {
+ delete ar;
+ object* obj = new object (path);
+ if (!obj->name ().exists ())
+ {
+ delete obj;
+ throw rld::error ("'" + path + "', Not found or a regular file.",
+ "file-check");
+ }
+ try
+ {
+ obj->open ();
+ obj->begin ();
+ obj->end ();
+ obj->close ();
+ objects_[path] = obj;
+ }
+ catch (...)
+ {
+ delete obj;
+ throw;
+ }
+ }
+ }
+
+ void
+ cache::load_symbols (rld::symbols::table& symbols, bool local)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "cache:load-sym: object files: " << objects_.size ()
+ << std::endl;
+
+ for (objects::iterator oi = objects_.begin ();
+ oi != objects_.end ();
+ ++oi)
+ {
+ object* obj = (*oi).second;
+ obj->open ();
+ obj->begin ();
+ obj->load_symbols (symbols, local);
+ obj->end ();
+ obj->close ();
+ }
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "cache:load-sym: symbols: " << symbols.size ()
+ << std::endl;
+ }
+
+ void
+ cache::output_unresolved_symbols (std::ostream& out)
+ {
+ for (objects::iterator oi = objects_.begin ();
+ oi != objects_.end ();
+ ++oi)
+ {
+ object* obj = (*oi).second;
+ if (obj)
+ {
+ out << obj->name ().full () << ':' << std::endl;
+ rld::symbols::output (out, obj->unresolved_symbols ());
+ }
+ }
+ }
+
+ archives&
+ cache::get_archives ()
+ {
+ return archives_;
+ }
+
+ objects&
+ cache::get_objects ()
+ {
+ return objects_;
+ }
+
+ void
+ cache::get_objects (object_list& list) const
+ {
+ list.clear ();
+ for (paths::const_iterator pi = paths_.begin ();
+ pi != paths_.end ();
+ ++pi)
+ {
+ objects::const_iterator oi = objects_.find (*pi);
+ if (oi == objects_.end ())
+ throw rld_error_at ("path not found in objects");
+ list.push_back ((*oi).second);
+ }
+ }
+
+ const paths&
+ cache::get_paths () const
+ {
+ return paths_;
+ }
+
+ int
+ cache::archive_count () const
+ {
+ return archives_.size ();
+ }
+
+ int
+ cache::object_count () const
+ {
+ return objects_.size ();
+ }
+
+ int
+ cache::path_count () const
+ {
+ return paths_.size ();
+ }
+
+ void
+ cache::get_archive_files (files& afiles)
+ {
+ for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
+ afiles.push_back ((*ai).second->name ().full ());
+ }
+
+ void
+ cache::get_object_files (files& ofiles)
+ {
+ for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
+ ofiles.push_back ((*oi).second->name ());
+ }
+
+ void
+ cache::output_archive_files (std::ostream& out)
+ {
+ for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
+ out << ' ' << (*ai).second->name ().full () << std::endl;
+ }
+
+ void
+ cache::output_object_files (std::ostream& out)
+ {
+ for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
+ out << ' ' << (*oi).second->name ().full () << std::endl;
+ }
+
+ void
+ cache::input (const std::string& path)
+ {
+ if (opened)
+ {
+ collect_object_files (path);
+ archive_begin (path);
+ }
+ }
+
+ void
+ find_libraries (paths& libraries, paths& libpaths, paths& libs)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "Finding libraries:." << std::endl;
+ libraries.clear ();
+ for (paths::size_type l = 0; l < libs.size (); ++l)
+ {
+ std::string lib = "lib" + libs[l] + ".a";
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << " searching: " << lib << std::endl;
+ bool found = false;
+ for (paths::size_type p = 0; p < libpaths.size (); ++p)
+ {
+ std::string plib;
+ path_join (libpaths[p], lib, plib);
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << " checking: " << plib << std::endl;
+ if (check_file (plib))
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << " found: " << plib << std::endl;
+ libraries.push_back (plib);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ throw rld::error ("Not found", lib);
+ }
+ }
+
+ }
+}
diff --git a/linkers/rld-files.h b/linkers/rld-files.h
new file mode 100644
index 0000000..019357e
--- /dev/null
+++ b/linkers/rld-files.h
@@ -0,0 +1,1065 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker file manages access the image contained in various file
+ * formats.
+ *
+ * The base element is a file. It references a object file that is either
+ * inside an archive or stand alone. You access a object file by constructing a
+ * handle. A handle is the object file with the specific file descriptor
+ * created when the archive or object file was opened.
+ *
+ *
+ */
+
+#if !defined (_RLD_FILES_H_)
+#define _RLD_FILES_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <rld.h>
+
+namespace rld
+{
+ namespace files
+ {
+ /**
+ * Container of file paths.
+ */
+ typedef std::vector < std::string > paths;
+
+ /**
+ * Container of files.
+ */
+ typedef std::vector < file > files;
+
+ /**
+ * Container of archive files.
+ */
+ typedef std::map < const std::string, archive* > archives;
+
+ /**
+ * Container of object files.
+ */
+ typedef std::map < const std::string, object* > objects;
+
+ /**
+ * Container list of object files.
+ */
+ typedef std::list < object* > object_list;
+
+ /**
+ * Return the basename of the file name.
+ *
+ * @param name The full file name.
+ * @return std::string The basename of the file.
+ */
+ std::string basename (const std::string& name);
+
+ /**
+ * Return the dirname of the file name.
+ *
+ * @param name The full file name.
+ * @return std::string The dirname of the file.
+ */
+ std::string dirname (const std::string& name);
+
+ /**
+ * Return the extension of the file name.
+ *
+ * @param name The full file name.
+ * @return std::string The extension of the file.
+ */
+ std::string extension (const std::string& name);
+
+ /**
+ * Split a path from a string with a delimiter to the path container. Add
+ * only the paths that exist and ignore those that do not.
+ *
+ * @param path The paths as a single string delimited by the path
+ * separator.
+ * @param paths The split path paths.
+ */
+ void path_split (const std::string& path,
+ paths& paths);
+
+ /**
+ * Make a path by joining the parts with required separator.
+ *
+ * @param path_ The path component to be joined.
+ * @param file_ The file name to add to the path.
+ * @param joined The joined path and file name with a path separator.
+ */
+ void path_join (const std::string& path_,
+ const std::string& file_,
+ std::string& joined);
+
+ /**
+ * Check the path is a file using a stat call.
+ *
+ * @param path The path to check.
+ * @retval true The path is valid.
+ * @retval false The path is not valid.
+ */
+ bool check_file (const std::string& path);
+
+ /**
+ * Check if the path is a directory.
+ *
+ * @param path The path to check.
+ * @retval false The path is not a directory.
+ * @retval true The path is a directory.
+ */
+ bool check_directory (const std::string& path);
+
+ /**
+ * Find the file given a container of paths and file names.
+ *
+ * @param path The path of the file if found else empty.
+ * @param name The name of the file to search for.
+ * @param search_paths The container of paths to search.
+ */
+ void find_file (std::string& path,
+ const std::string& name,
+ paths& search_paths);
+
+ /**
+ * A file is a single object file that is either in an @ref archive or
+ * a separate stand alone @ref object file.
+ */
+ class file
+ {
+ public:
+ /**
+ * Construct the file from the component parts when part of an archive.
+ *
+ * @param aname The archive name.
+ * @param oname The object file name.
+ * @param offset The offset in the archive the object file starts.
+ * @param size The size of the archive the object file starts.
+ */
+ file (const std::string& aname,
+ const std::string& oname,
+ off_t offset,
+ size_t size);
+
+ /**
+ * Construct the name by splitting the full path into an archive,
+ * object file name and offset.
+ *
+ * @param path The path to the image.
+ * @param is_object If true (default) the name is for an object file.
+ */
+ file (const std::string& path, bool is_object = true);
+
+ /**
+ * Contruct an empty file.
+ */
+ file ();
+
+ /**
+ * Set a name from the path.
+ *
+ * @param path The path to the image.
+ * @param is_object If true (default) the name is for an object file.
+ */
+ void set (const std::string& path, bool is_object = true);
+
+ /**
+ * Is an archive returns true if the file is in an archive.
+ *
+ * @retval true The object file is in an archive.
+ * @retval false The object file is stand alone.
+ */
+ bool is_archive () const;
+
+ /**
+ * Is object file stand alone.
+ *
+ * @retval true The object file is stand alone.
+ * @retval false The object could be part of an archive.
+ */
+ bool is_object () const;
+
+ /**
+ * Valid returns true if there is a valid name.
+ *
+ * @retval true There is a valid name.
+ * @retval false There is not name assigned.
+ */
+ bool is_valid () const;
+
+ /**
+ * Exists returns true if the archive or object file is present on disk
+ * and a regular file.
+ *
+ * @retval true The file is valid and a regular file.
+ * @retval false The file is either not present, not accessable or not a
+ * regular file.
+ */
+ bool exists () const;
+
+ /**
+ * The path maps to the real file on disk. The file may not be valid.
+ *
+ * @return const std::string The real path to the file on disk.
+ */
+ const std::string path () const;
+
+ /**
+ * The full path.
+ *
+ * @return const std::string The full path to the image.
+ */
+ const std::string full () const;
+
+ /**
+ * The base path. It is the basename of the full path.
+ *
+ * @return const std::string The basename of the full path to the image.
+ */
+ const std::string basename () const;
+
+ /**
+ * The archive name component. A length of 0 means there was not
+ * archive component.
+ *
+ * @return const std::string& The archive name.
+ */
+ const std::string& aname () const;
+
+ /**
+ * The object name. There is always an object name.
+ *
+ * @return const std::string& The object name.
+ */
+ const std::string& oname () const;
+
+ /**
+ * The object's offset in the archive or on disk.
+ *
+ * @return off_t The offset part of the file name.
+ */
+ off_t offset () const;
+
+ /**
+ * The object's size in the archive.
+ *
+ * @return size_t The size of the file in bytes.
+ */
+ size_t size () const;
+
+ private:
+ std::string aname_; //< The archive name.
+ std::string oname_; //< The object name.
+ off_t offset_; //< The object's offset in the archive.
+ size_t size_; //< The object's size in the archive or on disk.
+ };
+
+ /**
+ * Image is the base file type and lets us have a single container to hold
+ * the types of images we need to support.
+ */
+ class image
+ {
+ public:
+ /**
+ * Construct the image.
+ *
+ * @param name The name of the image.
+ */
+ image (file& name);
+
+ /**
+ * Construct the image.
+ *
+ * @param path The file path.
+ * @param is_object If true (default) the name is for an object file.
+ */
+ image (const std::string& path, bool is_object = true);
+
+ /**
+ * Construct the image.
+ */
+ image ();
+
+ /**
+ * Destruct the image.
+ */
+ virtual ~image ();
+
+ /**
+ * Open the image. You can open the image more than once but you need to
+ * close it the same number of times.
+ *
+ * @param name The @ref file name.
+ */
+ virtual void open (file& name);
+
+ /**
+ * Open the image. You can open the image more than once but you need to
+ * close it the same number of times.
+ *
+ * @param writeable If true the image is open as writable. The default is
+ * false.
+ */
+ virtual void open (bool writable = false);
+
+ /**
+ * Close the image.
+ */
+ virtual void close ();
+
+ /**
+ * Read a block from the file.
+ *
+ * @param buffer The buffer to read the data into.
+ * @param size The amount of data to read.
+ * @return ssize_t The amount of data read.
+ */
+ virtual ssize_t read (void* buffer, size_t size);
+
+ /**
+ * Write a block from the file.
+ *
+ * @param buffer The buffer of data to write.
+ * @param size The amount of data to write.
+ * @return ssize_t The amount of data written.
+ */
+ virtual ssize_t write (const void* buffer, size_t size);
+
+ /**
+ * Seek to the offset in the image.
+ *
+ * @param offset The offset to seek too.
+ */
+ virtual void seek (off_t offset);
+
+ /**
+ * Seek and then read.
+ *
+ * @param offset The offset to seek too before reading.
+ * @param buffer The buffer to read the data into.
+ * @param size The amount of data to read.
+ * @retval true The data requested was read.
+ * @retval false The request data was not read.
+ */
+ virtual bool seek_read (off_t offset, uint8_t* buffer, size_t size);
+
+ /**
+ * Seek and then write.
+ *
+ * @param offset The offset to seek too before writing.
+ * @param buffer The buffer of data to write.
+ * @param size The amount of data to write.
+ * @retval true The data requested was written.
+ * @retval false The request data was not written.
+ */
+ virtual bool seek_write (off_t offset, const void* buffer, size_t size);
+
+ /**
+ * The name of the image.
+ *
+ * @param const file& The @ref file name of the image.
+ */
+ const file& name () const;
+
+ /**
+ * References to the image.
+ *
+ * @return int The number of references the image has.
+ */
+ virtual int references () const;
+
+ /**
+ * The file size.
+ *
+ * @return size_t The size of the image.
+ */
+ virtual size_t size () const;
+
+ /**
+ * The file descriptor.
+ *
+ * @return int The operating system file descriptor handle.
+ */
+ virtual int fd () const;
+
+ /**
+ * The ELF reference.
+ *
+ * @return elf::file& The @ref elf::file object of the image.
+ */
+ elf::file& elf ();
+
+ /**
+ * A symbol in the image has been referenced.
+ */
+ virtual void symbol_referenced ();
+
+ /**
+ * Return the number of symbol references.
+ *
+ * @return int The symbol references count.
+ */
+ virtual int symbol_references () const;
+
+ /**
+ * The path maps to the real file on disk. The file may not be valid.
+ *
+ * @return const std::string The real path to the file on disk.
+ */
+ const std::string path () const {
+ return name ().path ();
+ }
+
+ /**
+ * Is the image open ?
+ *
+ * @retval true The image is open.
+ * @retval false The image is not open.
+ */
+ bool is_open () const {
+ return fd () != -1;
+ }
+
+ /**
+ * Is the image writable ?
+ *
+ * @retval true The image is writable.
+ * @retval false The image is not writable.
+ */
+ bool is_writable () const {
+ return writable;
+ }
+
+ private:
+
+ file name_; //< The name of the file.
+ int references_; //< The number of handles open.
+ int fd_; //< The file descriptor of the archive.
+ elf::file elf_; //< The libelf reference.
+ int symbol_refs; //< The number of symbols references made.
+ bool writable; //< The image is writable.
+ };
+
+ /**
+ * Copy the input section of the image to the output section. The file
+ * positions in the images must be set before making the call.
+ *
+ * @param in The input image.
+ * @param out The output image.
+ * @param size The amouint of data to copy.
+ */
+ void copy (image& in, image& out, size_t size);
+
+ /**
+ * The archive class proivdes access to object files that are held in a AR
+ * format file. GNU AR extensions are supported. The archive is a kind of
+ * @ref image and provides the container for the @ref object's that it
+ * contains.
+ */
+ class archive:
+ public image
+ {
+ public:
+ /**
+ * Open a archive format file that contains ELF object files.
+ *
+ * @param name The name of the @ref archive.
+ */
+ archive (const std::string& name);
+
+ /**
+ * Close the archive.
+ */
+ virtual ~archive ();
+
+ /**
+ * Begin the ELF session.
+ */
+ void begin ();
+
+ /**
+ * End the ELF session.
+ */
+ void end ();
+
+ /**
+ * Match the archive name.
+ *
+ * @param name The name of the archive to check.
+ * @retval true The name matches.
+ * @retval false The name does not match.
+ */
+ bool is (const std::string& name) const;
+
+ /**
+ * Check this is a valid archive.
+ *
+ * @retval true It is a valid archive.
+ * @retval false It is not a valid archive.
+ */
+ bool is_valid ();
+
+ /**
+ * Load @ref object's from the @ref archive adding each to the provided
+ * @ref objects container.
+ *
+ * @param objs The container the loaded object files are added too.
+ */
+ void load_objects (objects& objs);
+
+ /**
+ * Get the name.
+ *
+ * @return const std::string& Return a reference to the archive's name.
+ */
+ const std::string& get_name () const;
+
+ /**
+ * Less than operator for the map container. It compares the name of the
+ * the @ref archive.
+ *
+ * @param rhs The right hand side of the '<' operator.
+ * @return true The right hand side is less than this archive.
+ * @return false The right hand side is greater than or equal to this
+ * archive.
+ */
+ bool operator< (const archive& rhs) const;
+
+ /**
+ * Create a new archive containing the given set of objects. If
+ * referening an existing archive it is overwritten.
+ *
+ * @param objects The list of objects to place in the archive.
+ */
+ void create (object_list& objects);
+
+ private:
+
+ /**
+ * Read the archive header and check the magic number is valid.
+ *
+ * @param offset The offset in the file to read the header.
+ * @param header Read the header into here. There must be enough space.
+ * @retval true The header was read successfull and the magic number
+ * matched.
+ * @retval false The header could not be read from the @ref image.
+ */
+ bool read_header (off_t offset, uint8_t* header);
+
+ /**
+ * Add the object file from the archive to the object's container.
+ *
+ * @param objs The container to add the object to.
+ * @param name The name of the object file being added.
+ * @param offset The offset in the @ref archive of the object file.
+ * @param size The size of the object file.
+ */
+ void add_object (objects& objs,
+ const char* name,
+ off_t offset,
+ size_t size);
+
+ /**
+ * Write a file header into the archive.
+ *
+ * @param name The name of the archive.
+ * @param mtime The modified time of the archive.
+ * @param uid The user id of the archive.
+ * @param gid The group id of the archive.
+ * @param mode The mode of the archive.
+ * @param size The size of the archive.
+ */
+ void write_header (const std::string& name,
+ uint32_t mtime,
+ int uid,
+ int gid,
+ int mode,
+ size_t size);
+
+ /**
+ * Cannot copy via a copy constructor.
+ */
+ archive (const archive& orig);
+
+ /**
+ * Cannot assign using the assignment operator.
+ */
+ archive& operator= (const archive& rhs);
+ };
+
+ /**
+ * A relocation record. We extract what we want because the elf::section
+ * class requires the image be left open as references are alive. We
+ * extract and keep the data we need to create the image.
+ */
+ struct relocation
+ {
+ const uint32_t offset; //< The section offset.
+ const uint32_t type; //< The type of relocation record.
+ const uint32_t info; //< The ELF info field.
+ const int32_t addend; //< The constant addend.
+ const std::string symname; //< The name of the symbol.
+ const uint32_t symtype; //< The type of symbol.
+ const int symsect; //< The symbol's section symbol.
+ const uint32_t symvalue; //< The symbol's value.
+ const uint32_t symbinding;//< The symbol's binding.
+
+ /**
+ * Construct from an ELF relocation record.
+ */
+ relocation (const elf::relocation& er);
+
+ private:
+ /**
+ * The default constructor is not allowed due to all elements being
+ * const.
+ */
+ relocation ();
+ };
+
+ /**
+ * A container of relocations.
+ */
+ typedef std::list < relocation > relocations;
+
+ /**
+ * The sections attributes. We extract what we want because the
+ * elf::section class requires the image be left open as references are
+ * alive. We extract and keep the data we need to create the image.
+ */
+ struct section
+ {
+ const std::string name; //< The name of the section.
+ const int index; //< The section's index in the object file.
+ const uint32_t type; //< The type of section.
+ const size_t size; //< The size of the section.
+ const uint32_t alignment; //< The alignment of the section.
+ const uint32_t link; //< The ELF link field.
+ const uint32_t info; //< The ELF info field.
+ const uint32_t flags; //< The ELF flags.
+ const off_t offset; //< The ELF file offset.
+ bool rela; //< Relocation records have the addend field.
+ relocations relocs; //< The sections relocations.
+
+ /**
+ * Construct from an ELF section.
+ *
+ * @param es The ELF section to load the object file section from.
+ */
+ section (const elf::section& es);
+
+ /**
+ * Load the ELF relocations.
+ *
+ * @param es The ELF section to load the relocations from.
+ */
+ void load_relocations (const elf::section& es);
+
+ private:
+ /**
+ * The default constructor is not allowed due to all elements being
+ * const.
+ */
+ section ();
+ };
+
+ /**
+ * A container of sections.
+ */
+ typedef std::list < section > sections;
+
+ /**
+ * Sum the sizes of a container of sections.
+ */
+ size_t sum_sizes (const sections& secs);
+
+ /**
+ * Find the section that matches the index in the sections provided.
+ */
+ const section* find (const sections& secs, const int index);
+
+ /**
+ * The object file cab be in an archive or a file.
+ */
+ class object:
+ public image
+ {
+ public:
+ /**
+ * Construct an object image that is part of an archive.
+ *
+ * @param archive_ The archive the object file is part of.
+ * @param file_ The image file.
+ */
+ object (archive& archive_, file& file_);
+
+ /**
+ * Construct the object file.
+ *
+ * @param path The object file path.
+ */
+ object (const std::string& path);
+
+ /**
+ * Construct the object file.
+ */
+ object ();
+
+ /**
+ * Destruct the object file.
+ */
+ virtual ~object ();
+
+ /**
+ * Open the object file.
+ */
+ virtual void open (bool writable = false);
+
+ /**
+ * Close the object.
+ */
+ virtual void close ();
+
+ /**
+ * Begin the object file session.
+ */
+ void begin ();
+
+ /**
+ * End the object file session.
+ */
+ void end ();
+
+ /**
+ * If valid returns true the begin has been called and the object has
+ * been validated as being in a suitable format.
+ */
+ bool valid () const;
+
+ /**
+ * Load the symbols into the symbols table.
+ *
+ * @param symbols The symbol table to load.
+ * @param local Include local symbols. The default is not to.
+ */
+ void load_symbols (symbols::table& symbols, bool local = false);
+
+ /**
+ * Load the relocations.
+ */
+ void load_relocations ();
+
+ /**
+ * References to the image.
+ */
+ virtual int references () const;
+
+ /**
+ * The file size.
+ */
+ virtual size_t size () const;
+
+ /**
+ * The file descriptor.
+ */
+ virtual int fd () const;
+
+ /**
+ * A symbol in the image has been referenced.
+ */
+ virtual void symbol_referenced ();
+
+ /**
+ * The archive the object file is contained in. If 0 the object file is
+ * not contained in an archive.
+ */
+ archive* get_archive ();
+
+ /**
+ * Return the unresolved symbol table for this object file.
+ */
+ symbols::symtab& unresolved_symbols ();
+
+ /**
+ * Return the list external symbols.
+ */
+ symbols::pointers& external_symbols ();
+
+ /**
+ * Return a container sections that match the requested type and
+ * flags. The filtered section container is not cleared so any matching
+ * sections are appended.
+ *
+ * @param filtered_secs The container of the matching sections.
+ * @param type The section type. Must match. If 0 matches any.
+ * @param flags_in The sections flags that must be set. This is a
+ * mask. If 0 matches any.
+ * @param flags_out The sections flags that must be clear. This is a
+ * mask. If 0 this value is ignored.
+ */
+ void get_sections (sections& filtered_secs,
+ uint32_t type = 0,
+ uint64_t flags_in = 0,
+ uint64_t flags_out = 0);
+
+ /**
+ * Return a container sections that match the requested name. The
+ * filtered section container is not cleared so any matching sections are
+ * appended.
+ *
+ * @param filtered_secs The container of the matching sections.
+ * @param name The name of the section.
+ */
+ void get_sections (sections& filtered_secs, const std::string& name);
+
+ /**
+ * Get a section given an index number.
+ *
+ * @param index The section index to search for.
+ */
+ const section& get_section (int index) const;
+
+ /**
+ * Set the object file's resolving flag.
+ */
+ void resolve_set ();
+
+ /**
+ * Clear the object file's resolving flag.
+ */
+ void resolve_clear ();
+
+ /**
+ * The resolving state.
+ */
+ bool resolving () const;
+
+ /**
+ * Set the object file resolved flag.
+ */
+ void resolved_set ();
+
+ /**
+ * The resolved state.
+ */
+ bool resolved () const;
+
+ private:
+ archive* archive_; //< Points to the archive if part of an
+ // archive.
+ bool valid_; //< If true begin has run and finished.
+ symbols::symtab unresolved; //< This object's unresolved symbols.
+ symbols::pointers externals; //< This object's external symbols.
+ sections secs; //< The sections.
+ bool resolving_; //< The object is being resolved.
+ bool resolved_; //< The object has been resolved.
+
+ /**
+ * Cannot copy via a copy constructor.
+ */
+ object (const object& orig);
+
+ /**
+ * Cannot assign using the assignment operator.
+ */
+ object& operator= (const object& rhs);
+ };
+
+ /**
+ * A collection of objects files as a cache. This currently is not a cache
+ * but it could become one.
+ */
+ class cache
+ {
+ public:
+ /**
+ * Construct the cache.
+ */
+ cache ();
+
+ /**
+ * Destruct the objects.
+ */
+ virtual ~cache ();
+
+ /**
+ * Open the cache by collecting the file names, loading object headers
+ * and loading the archive file names.
+ */
+ void open ();
+
+ /**
+ * Close the cache.
+ */
+ void close ();
+
+ /**
+ * Add a file path to the cache.
+ */
+ void add (const std::string& path);
+
+ /**
+ * Add a container of path to the cache.
+ */
+ void add (paths& paths__);
+
+ /**
+ * Add a container of path to the cache.
+ */
+ void add_libraries (paths& paths__);
+
+ /**
+ * Being a session on an archive.
+ */
+ void archive_begin (const std::string& path);
+
+ /**
+ * End a session on an archive.
+ */
+ void archive_end (const std::string& path);
+
+ /**
+ * Being sessions on all archives.
+ */
+ void archives_begin ();
+
+ /**
+ * End the archive sessions.
+ */
+ void archives_end ();
+
+ /**
+ * Collect the object names and add them to the cache.
+ */
+ void collect_object_files ();
+
+ /**
+ * Collect the object file names by verifing the paths to the files are
+ * valid or read the object file names contained in any archives.
+ */
+ void collect_object_files (const std::string& path);
+
+ /**
+ * Load the symbols into the symbol table.
+ *
+ * @param symbols The symbol table to load.
+ * @param locals Include local symbols. The default does not include them.
+ */
+ void load_symbols (symbols::table& symbols, bool locals = false);
+
+ /**
+ * Output the unresolved symbol table to the output stream.
+ */
+ void output_unresolved_symbols (std::ostream& out);
+
+ /**
+ * Get the archives.
+ */
+ archives& get_archives ();
+
+ /**
+ * Get the objects inlcuding those in archives.
+ */
+ objects& get_objects ();
+
+ /**
+ * Get the added objects. Does not include the ones in th archives.
+ */
+ void get_objects (object_list& list) const;
+
+ /**
+ * Get the paths.
+ */
+ const paths& get_paths () const;
+
+ /**
+ * Get the archive files.
+ */
+ void get_archive_files (files& afiles);
+
+ /**
+ * Get the object files including those in archives.
+ */
+ void get_object_files (files& ofiles);
+
+ /**
+ * Get the archive count.
+ */
+ int archive_count () const;
+
+ /**
+ * Get the object count.
+ */
+ int object_count () const;
+
+ /**
+ * Get the path count.
+ */
+ int path_count () const;
+
+ /**
+ * Output archive files.
+ */
+ void output_archive_files (std::ostream& out);
+
+ /**
+ * Output archive files.
+ */
+ void output_object_files (std::ostream& out);
+
+ protected:
+
+ /**
+ * Input a path into the cache.
+ */
+ virtual void input (const std::string& path);
+
+ private:
+ paths paths_; //< The names of the files to process.
+ archives archives_; //< The archive files.
+ objects objects_; //< The object files.
+ bool opened; //< The cache is open.
+ };
+
+ /**
+ * Copy the in file to the out file.
+ *
+ * @param in The input file.
+ * @param out The output file.
+ * @param size The amount to copy. If 0 the whole on in is copied.
+ */
+ void copy_file (image& in, image& out, size_t size = 0);
+
+ /**
+ * Find the libraries given the list of libraries as bare name which
+ * have 'lib' and '.a' added.
+ */
+ void find_libraries (paths& libraries, paths& libpaths, paths& libs);
+
+ }
+}
+
+#endif
diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp
new file mode 100644
index 0000000..ff9032c
--- /dev/null
+++ b/linkers/rld-outputter.cpp
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_ld
+ *
+ * @brief RTEMS Linker.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fstream>
+#include <iostream>
+
+#include <errno.h>
+#include <string.h>
+
+#include <rld.h>
+#include <rld-rap.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "rld-process.h"
+
+namespace rld
+{
+ namespace outputter
+ {
+ int unlink (const char* path)
+ {
+#if _WIN32
+ return ::remove(path);
+#else
+ return ::unlink (path);
+#endif
+ }
+
+ int link (const char* path1, const char* path2)
+ {
+#if _WIN32
+ return ::rename(path1, path2);
+#else
+ return ::link (path1, path2);
+#endif
+ }
+
+ const std::string
+ script_text (const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache,
+ bool not_in_archive)
+ {
+ std::ostringstream out;
+ files::object_list objects;
+ files::object_list dep_copy (dependents);
+
+ cache.get_objects (objects);
+ objects.merge (dep_copy);
+ objects.unique ();
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << " E: " << entry << std::endl;
+
+ out << "E: " << entry << std::endl;
+
+ if (!exit.empty ())
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << " e: " << exit << std::endl;
+ out << "e: " << exit << std::endl;
+ }
+
+ for (files::object_list::iterator oi = objects.begin ();
+ oi != objects.end ();
+ ++oi)
+ {
+ files::object& obj = *(*oi);
+ std::string name = obj.name ().basename ();
+
+ if (not_in_archive)
+ {
+ size_t pos = name.find (':');
+ if (pos != std::string::npos)
+ name[pos] = '_';
+ pos = name.find ('@');
+ if (pos != std::string::npos)
+ name = name.substr (0, pos);
+ }
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << " o: " << name << std::endl;
+
+ out << "o:" << name << std::endl;
+
+ symbols::symtab& unresolved = obj.unresolved_symbols ();
+
+ int count = 0;
+ for (symbols::symtab::iterator ursi = unresolved.begin ();
+ ursi != unresolved.begin ();
+ ++ursi)
+ {
+ symbols::symbol& urs = *((*ursi).second);
+
+ ++count;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << " u: " << count << ':' << urs.name () << std::endl;
+
+ out << " u:" << count << ':' << urs.name () << std::endl;
+ }
+ }
+
+ return out.str ();
+ }
+
+ void
+ metadata_object (files::object& metadata,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "metadata: " << metadata.name ().full () << std::endl;
+
+ const std::string script =
+ script_text (entry, exit, dependents, cache, true);
+
+ metadata.open (true);
+ metadata.begin ();
+
+ elf::file& elf = metadata.elf ();
+
+ elf.set_header (ET_EXEC,
+ elf::object_class (),
+ elf::object_datatype (),
+ elf::object_machine_type ());
+
+ elf::section md (elf,
+ elf.section_count () + 1,
+ ".rtemsmd",
+ SHT_STRTAB,
+ 1,
+ 0,
+ 0,
+ 0,
+ script.length ());
+
+ md.add_data (ELF_T_BYTE,
+ 1,
+ script.length (),
+ (void*) script.c_str ());
+
+ elf.add (md);
+ elf.write ();
+
+ metadata.end ();
+ metadata.close ();
+ }
+
+ void
+ archive (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "outputter:archive: " << name
+ << ", dependents: " << dependents.size () << std::endl;
+
+ std::string ext = files::extension (name);
+ std::string mdname =
+ name.substr (0, name.length () - ext.length ()) + "-metadata.o";
+
+ files::object metadata (mdname);
+
+ metadata_object (metadata, entry, exit, dependents, cache);
+
+ files::object_list dep_copy (dependents);
+ files::object_list objects;
+
+ cache.get_objects (objects);
+ objects.merge (dep_copy);
+ objects.push_front (&metadata);
+ objects.unique ();
+
+ files::archive arch (name);
+ arch.create (objects);
+ }
+
+ void
+ archivera (const std::string& name,
+ const files::object_list& dependents,
+ files::cache& cache,
+ bool ra_exist,
+ bool ra_rap)
+ {
+ files::object_list dep_copy (dependents);
+ files::object_list objects;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "outputter:archivera: " << name
+ << ", dependents: " << dependents.size () << std::endl;
+
+ objects.clear ();
+
+ files::object_list::iterator oli;
+ for (oli = dep_copy.begin (); oli != dep_copy.end (); ++oli)
+ {
+ files::object& object = *(*oli);
+
+ if (ra_rap)
+ objects.push_back (&object);
+ else
+ {
+ if (object.get_archive ())
+ objects.push_back (&object);
+ }
+ }
+
+ bool exist = false;
+ files::object_list objects_tmp;
+ files::objects& objs = cache.get_objects ();
+ objects_tmp.clear ();
+ for (files::objects::iterator obi = objs.begin ();
+ obi != objs.end ();
+ ++obi)
+ {
+ files::object* obj = (*obi).second;
+ exist = false;
+
+ /**
+ * Replace the elf object file in ra file with elf object file
+ * in collected object files, if exist.
+ */
+ if (!ra_rap)
+ {
+ for (oli = objects.begin (); oli != objects.end (); ++oli)
+ {
+ files::object& object = *(*oli);
+ if (obj->name ().oname () == object.name ().oname ())
+ {
+ exist = true;
+ break;
+ }
+ }
+ }
+
+ if (!exist)
+ objects_tmp.push_back (obj);
+ }
+
+ objects.merge (objects_tmp);
+ objects.unique ();
+
+ if (objects.size ())
+ {
+ if (ra_exist)
+ {
+ std::string new_name = "rld_XXXXXX";
+ files::archive arch (new_name);
+ struct stat sb;
+
+ arch.create (objects);
+
+ if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode))
+ {
+ if (unlink (name.c_str ()) < 0)
+ std::cerr << "error: unlinking temp file: " << name << std::endl;
+ }
+ if (link (new_name.c_str (), name.c_str ()) < 0)
+ {
+ std::cerr << "error: linking temp file: " << name << std::endl;
+ }
+ if ((::stat (new_name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode))
+ {
+ if (unlink (new_name.c_str ()) < 0)
+ std::cerr << "error: unlinking temp file: " << new_name << std::endl;
+ }
+ }
+ else
+ {
+ /* Create */
+ files::archive arch (name);
+ arch.create (objects);
+ }
+ }
+ }
+
+ void
+ script (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "outputter:script: " << name << std::endl;
+
+ std::fstream out (name.c_str (),
+ std::ios_base::out | std::ios_base::trunc);
+
+ /*
+ * Tag for the shell to use.
+ */
+ out << "!# rls" << std::endl;
+
+ try
+ {
+ out << script_text (entry, exit, dependents, cache, false);
+ }
+ catch (...)
+ {
+ out.close ();
+ throw;
+ }
+
+ out.close ();
+ }
+
+ void
+ elf_application (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "outputter:application: " << name << std::endl;
+
+ files::object_list dep_copy (dependents);
+ files::object_list objects;
+ std::string header;
+ std::string script;
+ files::image app (name);
+
+ header = "RELF,00000000,0001,none,00000000\n";
+ header += '\0';
+
+ script = script_text (entry, exit, dependents, cache, true);
+
+ cache.get_objects (objects);
+ objects.merge (dep_copy);
+ objects.unique ();
+
+ app.open (true);
+ app.write (header.c_str (), header.size ());
+
+ #define APP_BUFFER_SIZE (128 * 1024)
+
+ uint8_t* buffer = 0;
+
+ try
+ {
+ buffer = new uint8_t[APP_BUFFER_SIZE];
+
+ for (files::object_list::iterator oi = objects.begin ();
+ oi != objects.end ();
+ ++oi)
+ {
+ files::object& obj = *(*oi);
+
+ obj.open ();
+
+ try
+ {
+ obj.seek (0);
+
+ size_t in_size = obj.name ().size ();
+
+ while (in_size)
+ {
+ size_t reading =
+ in_size < APP_BUFFER_SIZE ? in_size : APP_BUFFER_SIZE;
+
+ app.write (buffer, obj.read (buffer, reading));
+
+ in_size -= reading;
+ }
+ }
+ catch (...)
+ {
+ obj.close ();
+ throw;
+ }
+
+ obj.close ();
+ }
+ }
+ catch (...)
+ {
+ delete [] buffer;
+ app.close ();
+ throw;
+ }
+
+ delete [] buffer;
+
+ app.close ();
+ }
+
+ bool in_archive (files::object* object)
+ {
+ if (object->get_archive ())
+ return true;
+ return false;
+ }
+
+ void
+ application (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache,
+ const symbols::table& symbols,
+ bool one_file)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "outputter:application: " << name << std::endl;
+
+ files::object_list dep_copy (dependents);
+ files::object_list objects;
+ files::image app (name);
+
+ if (!one_file)
+ dep_copy.remove_if (in_archive);
+
+ cache.get_objects (objects);
+ objects.merge (dep_copy);
+ objects.sort ();
+ objects.unique ();
+
+ app.open (true);
+
+ try
+ {
+ rap::write (app, entry, exit, objects, symbols);
+ }
+ catch (...)
+ {
+ app.close ();
+ throw;
+ }
+
+ app.close ();
+ }
+
+ }
+}
diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h
new file mode 100644
index 0000000..7fe52b2
--- /dev/null
+++ b/linkers/rld-outputter.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker outputter handles the various output formats.
+ *
+ */
+
+#if !defined (_RLD_OUTPUTTER_H_)
+#define _RLD_OUTPUTTER_H_
+
+#include <rld-files.h>
+
+namespace rld
+{
+ namespace outputter
+ {
+ /**
+ * Output the object file list as a string.
+ *
+ * @param entry The name of the entry point symbol.
+ * @param exit The name of the exit point symbol.
+ * @param dependents The list of dependent object files
+ * @param cache The file cache for the link. Includes the object list
+ * the user requested.
+ * @return std::string The list as a text string.
+ */
+ std::string script_text (const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache);
+ /**
+ * Output the object files as an archive format file with the metadata as
+ * the first ELF file.
+ *
+ * @param name The name of the archive.
+ * @param entry The name of the entry point symbol.
+ * @param exit The name of the exit point symbol.
+ * @param dependents The list of dependent object files
+ * @param cache The file cache for the link. Includes the object list
+ * the user requested.
+ */
+ void archive (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache);
+
+ void archivera (const std::string& name,
+ const files::object_list& dependents,
+ files::cache& cache,
+ bool ra_exist,
+ bool ra_rap);
+
+ /**
+ * Output the object file list as a script.
+ *
+ * @param name The name of the script.
+ * @param entry The name of the entry point symbol.
+ * @param exit The name of the exit point symbol.
+ * @param dependents The list of dependent object files
+ * @param cache The file cache for the link. Includes the object list
+ * the user requested.
+ */
+ void script (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache);
+
+ /**
+ * Output the object files in an archive with the metadata.
+ *
+ * @param name The name of the script.
+ * @param entry The name of the entry point symbol.
+ * @param exit The name of the exit point symbol.
+ * @param dependents The list of dependent object files
+ * @param cache The file cache for the link. Includes the object list
+ * the user requested.
+ */
+ void elf_application (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache);
+
+ /**
+ * Output the object files in an archive with the metadata.
+ *
+ * @param name The name of the script.
+ * @param entry The name of the entry point symbol.
+ * @param exit The name of the exit point symbol.
+ * @param dependents The list of dependent object files
+ * @param cache The file cache for the link. Includes the object list
+ * the user requested.
+ * @param symbols The symbol table used to resolve the application.
+ */
+ void application (const std::string& name,
+ const std::string& entry,
+ const std::string& exit,
+ const files::object_list& dependents,
+ const files::cache& cache,
+ const symbols::table& symbols,
+ bool one_file);
+
+ }
+}
+
+#endif
diff --git a/linkers/rld-process.cpp b/linkers/rld-process.cpp
new file mode 100644
index 0000000..2032404
--- /dev/null
+++ b/linkers/rld-process.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifndef WIFEXITED
+#define WIFEXITED(S) (((S) & 0xff) == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(S) ((S) & 0x7f)
+#endif
+#ifndef WIFSTOPPED
+#define WIFSTOPPED WIFEXITED
+#endif
+#ifndef WSTOPSIG
+#define WSTOPSIG WEXITSTATUS
+#endif
+
+#include <iostream>
+
+#include "rld.h"
+#include "rld-process.h"
+
+#include <libiberty.h>
+
+namespace rld
+{
+ namespace process
+ {
+ /**
+ * Keep the temporary files if true. Used to help debug a system.
+ */
+ bool keep_temporary_files = false;
+
+ /**
+ * The temporary files.
+ */
+ temporary_files temporaries;
+
+ temporary_files::temporary_files ()
+ {
+ }
+
+ temporary_files::~temporary_files ()
+ {
+ clean_up ();
+ }
+
+ const std::string
+ temporary_files::get (const std::string& suffix)
+ {
+ char* temp = ::make_temp_file (suffix.c_str ());
+
+ if (!temp)
+ throw rld::error ("bad temp name", "temp-file");
+
+ std::string name = temp;
+
+ tempfiles.push_back (name);
+
+ return name;
+ }
+
+ void
+ temporary_files::unlink (const std::string& name)
+ {
+ if (!keep_temporary_files)
+ {
+ struct stat sb;
+ if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode))
+ {
+ int r;
+#if _WIN32
+ r = ::remove(name.c_str ());
+#else
+ r = ::unlink (name.c_str ());
+#endif
+ if (r < 0)
+ {
+ std::cerr << "error: unlinking temp file: " << name << std::endl;
+ ::exit (100);
+ }
+ }
+ }
+ }
+
+ void
+ temporary_files::erase (const std::string& name)
+ {
+ for (tempfile_container::iterator tfi = tempfiles.begin ();
+ tfi != tempfiles.end ();
+ ++tfi)
+ {
+ if (*tfi == name)
+ {
+ unlink (name);
+ tempfiles.erase (tfi);
+ break;
+ }
+ }
+ }
+
+ void
+ temporary_files::clean_up ()
+ {
+ for (tempfile_container::iterator tfi = tempfiles.begin ();
+ tfi != tempfiles.end ();
+ ++tfi)
+ {
+ unlink (*tfi);
+ }
+ }
+
+ tempfile::tempfile (const std::string& suffix)
+ : suffix (suffix),
+ fd (-1),
+ level (0)
+ {
+ _name = temporaries.get (suffix);
+ }
+
+ tempfile::~tempfile ()
+ {
+ close ();
+ temporaries.erase (_name);
+ }
+
+ void
+ tempfile::open (bool writable)
+ {
+ if ((fd < 0) && rld::files::check_file (_name))
+ {
+ level = 0;
+ fd = ::open (_name.c_str (), writable ? O_RDWR : O_RDONLY);
+ if (fd < 0)
+ throw rld::error (::strerror (errno), "tempfile open:" + _name);
+ }
+ }
+
+ void
+ tempfile::close ()
+ {
+ if (fd != -1)
+ {
+ ::close (fd);
+ fd = -1;
+ level = 0;
+ }
+ }
+
+ const std::string&
+ tempfile::name () const
+ {
+ return _name;
+ }
+
+ size_t
+ tempfile::size ()
+ {
+ if (fd < 0)
+ return 0;
+
+ struct stat sb;
+ if (::stat (_name.c_str (), &sb) == 0)
+ return sb.st_size;
+
+ return 0;
+ }
+
+ void
+ tempfile::read (std::string& all)
+ {
+ all.clear ();
+ if (fd != -1)
+ {
+ if (level)
+ all.append (buf, level);
+ level = 0;
+ while (true)
+ {
+ int read = ::read (fd, buf, sizeof (buf) );
+ if (read < 0)
+ throw rld::error (::strerror (errno), "tempfile get read:" + _name);
+ else if (read == 0)
+ break;
+ else
+ all.append (buf, read);
+ }
+ }
+ }
+
+ void
+ tempfile::read_line (std::string& line)
+ {
+ line.clear ();
+ if (fd != -1)
+ {
+ if (level)
+ line.append (buf, level);
+ level = 0;
+ while (true)
+ {
+ int read = ::read (fd, buf, sizeof (buf));
+ if (read < 0)
+ throw rld::error (::strerror (errno), "tempfile read:" + _name);
+ else if (read == 0)
+ break;
+ else
+ {
+ char* lf = ::strchr (buf, '\n');
+ if (lf)
+ {
+ int len = lf - &buf[0] + 1;
+ line.append (buf, len);
+ level = read - len;
+ if (level)
+ ::memmove (buf, &buf[len], level);
+ break;
+ }
+ line.append (buf, read);
+ }
+ }
+ }
+ }
+
+ void
+ tempfile::write (const std::string& s)
+ {
+ const char* p = s.c_str ();
+ size_t l = s.length ();
+ while (l)
+ {
+ int written = ::write (fd, p, l);
+ if (written < 0)
+ throw rld::error (::strerror (errno), "tempfile write:" + _name);
+ if (written == 0)
+ break;
+ l -= written;
+ }
+ }
+
+ void
+ tempfile::write_line (const std::string& s)
+ {
+ write (s);
+ write (RLD_LINE_SEPARATOR);
+ }
+
+ void
+ tempfile::write_lines (const rld::strings& ss)
+ {
+ for (rld::strings::const_iterator ssi = ss.begin ();
+ ssi != ss.end ();
+ ++ssi)
+ {
+ write_line (*ssi);
+ }
+ }
+
+ void
+ tempfile::output (std::ostream& out)
+ {
+ std::string prefix;
+ output (prefix, out);
+ }
+
+ void
+ tempfile::output (const std::string& prefix,
+ std::ostream& out,
+ bool line_numbers)
+ {
+ if (fd == -1)
+ {
+ std::string line;
+ int lc = 0;
+ open ();
+ while (true)
+ {
+ read_line (line);
+ ++lc;
+ if (line.empty ())
+ break;
+ if (!prefix.empty ())
+ out << prefix << ':';
+ if (line_numbers)
+ out << lc << ':';
+ out << line;
+ }
+ close ();
+ }
+ }
+
+ void
+ set_keep_temporary_files ()
+ {
+ keep_temporary_files = true;
+ }
+
+ void
+ temporaries_clean_up ()
+ {
+ temporaries.clean_up ();
+ }
+
+ status
+ execute (const std::string& pname,
+ const std::string& command,
+ const std::string& outname,
+ const std::string& errname)
+ {
+ arg_container args;
+ parse_command_line (command, args);
+ return execute (pname, args, outname, errname);
+ }
+
+ status
+ execute (const std::string& pname,
+ const arg_container& args,
+ const std::string& outname,
+ const std::string& errname)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "execute: ";
+ for (size_t a = 0; a < args.size (); ++a)
+ std::cout << args[a] << ' ';
+ std::cout << std::endl;
+ }
+
+ const char** cargs = new const char* [args.size () + 1];
+
+ for (size_t a = 0; a < args.size (); ++a)
+ cargs[a] = args[a].c_str ();
+ cargs[args.size ()] = 0;
+
+ int err = 0;
+ int s = 0;
+
+ const char* serr = pex_one (PEX_LAST | PEX_SEARCH,
+ args[0].c_str (),
+ (char* const*) cargs,
+ pname.c_str (),
+ outname.c_str (),
+ errname.c_str (),
+ &s,
+ &err);
+
+ delete [] cargs;
+
+ if (serr)
+ throw rld::error ("execute: " + args[0], serr);
+ else if (err)
+ throw rld::error ("execute: " + args[0], ::strerror (err));
+
+ status _status;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "execute: status: ";
+
+ if (WIFEXITED (s))
+ {
+ _status.type = status::normal;
+ _status.code = WEXITSTATUS (s);
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << _status.code << std::endl;
+ }
+ else if (WIFSIGNALED (s))
+ {
+ _status.type = status::signal;
+ _status.code = WTERMSIG (s);
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "signal: " << _status.code << std::endl;
+ }
+ else if (WIFSTOPPED (s))
+ {
+ _status.type = status::stopped;
+ _status.code = WSTOPSIG (s);
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "stopped: " << _status.code << std::endl;
+ }
+ else
+ throw rld::error ("execute: " + args[0], "unknown status returned");
+
+ return _status;
+ }
+
+ /*
+ * The code is based on this C file:
+ * http://cybertiggyr.com/pcm/src/parse.c
+ */
+ void
+ parse_command_line (const std::string& command, arg_container& args)
+ {
+ enum pstate
+ {
+ pstate_discard_space,
+ pstate_accumulate_quoted,
+ pstate_accumulate_raw
+ };
+
+ args.clear ();
+
+ const char quote = '"';
+ const char escape = '\\';
+ pstate state = pstate_discard_space;
+ size_t start = 0;
+ size_t i = 0;
+
+ while (i < command.size ())
+ {
+ switch (state)
+ {
+ case pstate_discard_space:
+ if (command[i] == quote)
+ {
+ ++i;
+ start = i;
+ state = pstate_accumulate_quoted;
+ }
+ else if (::isspace (command[i]))
+ {
+ ++i;
+ }
+ else /* includes escape */
+ {
+ start = i;
+ state = pstate_accumulate_raw;
+ }
+ break;
+
+ case pstate_accumulate_quoted:
+ if (command[i] == quote)
+ {
+ args.push_back (command.substr (start, i - 1));
+ ++i;
+ state = pstate_discard_space;
+ }
+ else if ((command[i] == escape) && (command[i + 1] == quote))
+ {
+ i += 2;
+ }
+ else /* includes space */
+ {
+ ++i;
+ }
+ break;
+
+ case pstate_accumulate_raw:
+ if (command[i] == quote)
+ {
+ throw rld::error ("quote in token", "command parse");
+ }
+ else if ((command[i] == escape) && (command[i + 1] == quote))
+ {
+ i += 2;
+ }
+ else if (::isspace (command[i]))
+ {
+ args.push_back (command.substr (start, i - 1));
+ ++i;
+ state = pstate_discard_space;
+ }
+ else
+ {
+ ++i;
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/linkers/rld-process.h b/linkers/rld-process.h
new file mode 100644
index 0000000..c50bb08
--- /dev/null
+++ b/linkers/rld-process.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief Process execute and various supporting parts.
+ *
+ */
+
+#if !defined (_RLD_PEX_H_)
+#define _RLD_PEX_H_
+
+#include <list>
+#include <string>
+#include <vector>
+
+namespace rld
+{
+ namespace process
+ {
+ /**
+ * Manage temporary files. We keep these so we can delete them when
+ * we exit.
+ */
+ class temporary_files
+ {
+ public:
+ /**
+ * Container of temporary file names.
+ */
+ typedef std::list < std::string > tempfile_container;
+
+ /**
+ * Construct the temporary files.
+ */
+ temporary_files ();
+
+ /**
+ * Destruct cleaning up.
+ */
+ ~temporary_files ();
+
+ /**
+ * Get a new temporary file name.
+ */
+ const std::string get (const std::string& suffix = ".rldxx");
+
+ /**
+ * Remove the temporary file.
+ */
+ void erase (const std::string& name);
+
+ /**
+ * Remove all temporary files.
+ */
+ void clean_up ();
+
+ private:
+
+ /*
+ * Delete the file.
+ */
+ void unlink (const std::string& name);
+
+ tempfile_container tempfiles; //< The temporary files.
+
+ };
+
+ /**
+ * Handle the output files from the process.
+ */
+ class tempfile
+ {
+ public:
+
+ /**
+ * Get a temporary file name.
+ */
+ tempfile (const std::string& suffix = ".rldxx");
+
+ /**
+ * Clean up the temporary file.
+ */
+ ~tempfile ();
+
+ /**
+ * Open the temporary file. It can optionally be written too.
+ */
+ void open (bool writable = false);
+
+ /**
+ * Close the temporary file.
+ */
+ void close ();
+
+ /**
+ * The name of the temp file.
+ */
+ const std::string& name () const;
+
+ /**
+ * Size of the file.
+ */
+ size_t size ();
+
+ /**
+ * Read all the file.
+ */
+ void read (std::string& all);
+
+ /**
+ * Read a line at a time.
+ */
+ void read_line (std::string& line);
+
+ /**
+ * Write the string to the file.
+ */
+ void write (const std::string& s);
+
+ /**
+ * Write the string as a line to the file.
+ */
+ void write_line (const std::string& s);
+
+ /**
+ * Write the strings to the file using a suitable line separator.
+ */
+ void write_lines (const rld::strings& ss);
+
+ /**
+ * Output the file.
+ */
+ void output (const std::string& prefix,
+ std::ostream& out,
+ bool line_numbers = false);
+
+ /**
+ * Output the file.
+ */
+ void output (std::ostream& out);
+
+ private:
+
+ std::string _name; //< The name of the file.
+ const std::string suffix; //< The temp file's suffix.
+ int fd; //< The file descriptor
+ char buf[256]; //< The read buffer.
+ int level; //< The level of data in the buffer.
+ };
+
+ /**
+ * Keep the temporary files.
+ */
+ void set_keep_temporary_files ();
+
+ /**
+ * Clean up the temporaryes.
+ */
+ void temporaries_clean_up ();
+
+ /**
+ * The arguments containter has a single argument per element.
+ */
+ typedef std::vector < std::string > arg_container;
+
+ /**
+ * Execute result.
+ */
+ struct status
+ {
+ enum types
+ {
+ normal, //< The process terminated normally by a call to _exit(2) or exit(3).
+ signal, //< The process terminated due to receipt of a signal.
+ stopped //< The process has not terminated, but has stopped and can be restarted.
+ };
+
+ types type; //< Type of status.
+ int code; //< The status code returned.
+ };
+
+ /**
+ * Execute a process and capture stdout and stderr. The first element is
+ * the program name to run. Return an error code.
+ */
+ status execute (const std::string& pname,
+ const arg_container& args,
+ const std::string& outname,
+ const std::string& errname);
+
+ /**
+ * Execute a process and capture stdout and stderr given a command line
+ * string. Return an error code.
+ */
+ status execute (const std::string& pname,
+ const std::string& command,
+ const std::string& outname,
+ const std::string& errname);
+
+ /**
+ * Parse a command line into arguments. It support quoting.
+ */
+ void parse_command_line (const std::string& command, arg_container& args);
+ }
+}
+
+#endif
diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp
new file mode 100644
index 0000000..9b87279
--- /dev/null
+++ b/linkers/rld-rap.cpp
@@ -0,0 +1,1668 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_ld
+ *
+ * @brief RTEMS Linker.
+ *
+ * @todo Set the RAP alignment as the max of all alignments.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <algorithm>
+#include <list>
+#include <iomanip>
+
+#include <rld.h>
+#include <rld-compression.h>
+#include <rld-rap.h>
+
+namespace rld
+{
+ namespace rap
+ {
+
+ /**
+ * Output details or not.
+ */
+ bool add_obj_details = true;
+
+ /**
+ * Store the path of object files.
+ */
+ std::string rpath;
+
+ /**
+ * The names of the RAP sections.
+ */
+ static const char* section_names[rap_secs] =
+ {
+ ".text",
+ ".const",
+ ".ctor",
+ ".dtor",
+ ".data",
+ ".bss"
+ };
+
+ /**
+ * RAP relocation record. This one does not have const fields.
+ */
+ struct relocation
+ {
+ uint32_t offset; //< The offset in the section to apply the fixup.
+ uint32_t info; //< The ELF info record.
+ uint32_t addend; //< The ELF constant addend.
+ std::string symname; //< The symbol name if there is one.
+ uint32_t symtype; //< The type of symbol.
+ int symsect; //< The symbol's RAP section.
+ uint32_t symvalue; //< The symbol's default value.
+ uint32_t symbinding;//< The symbol's binding.
+
+ /**
+ * Construct the relocation using the file relocation, the offset of the
+ * section in the target RAP section and the RAP section of the symbol.
+ */
+ relocation (const files::relocation& reloc, const uint32_t offset);
+ };
+
+ /**
+ * Relocation records.
+ */
+ typedef std::vector < relocation > relocations;
+
+ /**
+ * Relocation symname sorter for the relocations container.
+ */
+ class reloc_symname_compare
+ {
+ public:
+ bool operator () (const relocation& lhs,
+ const relocation& rhs) const {
+ return lhs.symname < rhs.symname;
+ }
+ };
+
+ /**
+ * Relocation offset sorter for the relocations container.
+ */
+ class reloc_offset_compare
+ {
+ public:
+ bool operator () (const relocation& lhs,
+ const relocation& rhs) const {
+ if (lhs.symname == rhs.symname)
+ return lhs.offset < rhs.offset;
+ else return false;
+ }
+ };
+
+ /**
+ * An object section's offset, size and alignment.
+ */
+ struct osection
+ {
+ std::string name; //< The name of the section.
+ uint32_t offset; //< The offset in the object file.
+ uint32_t size; //< The size of this section.
+ uint32_t align; //< The alignment.
+ uint32_t relocs; //< The number of relocations.
+ uint64_t flags; //< The flags.
+
+ /**
+ * Construct the object section.
+ */
+ osection (const std::string& name,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t align,
+ uint32_t relocs,
+ uint64_t flags);
+
+ /**
+ * Default constructor.
+ */
+ osection ();
+ };
+
+ /**
+ * Map of object file section offsets keyed by the object file section
+ * index. This is used when adding the external symbols so the symbol's
+ * value can be adjusted by the offset of the section in the RAP section.
+ */
+ typedef std::map < int, osection > osections;
+
+ /**
+ * An ordered container of object section indexes. We need the same
+ * order so the alignments match up with the layout.
+ */
+ typedef std::vector < int > osecindexes;
+
+ /**
+ * Section detail will be written into RAP file
+ */
+ struct section_detail
+ {
+ uint32_t name; //< The offset in the strtable.
+ uint32_t offset; //< The offset in the rap section.
+ uint32_t id; //< The rap id.
+ uint32_t size; //< The size of the section.
+
+ /* Constructor */
+ section_detail (uint32_t name, uint32_t offset, uint32_t id, uint32_t size);
+ };
+
+ /*
+ * A container of section detail
+ */
+ typedef std::list < section_detail > section_details;
+
+ /**
+ * The RAP section data.
+ */
+ struct section
+ {
+ std::string name; //< The name of the section.
+ uint32_t offset; //< The offset of the section.
+ bool rela; //< The relocation record has an addend field.
+ relocations relocs; //< The relocations for this section.
+ osections osecs; //< The object section index.
+ osecindexes osindexes; //< The object section indexes in order.
+
+ /**
+ * Default constructor.
+ */
+ section ();
+
+ /**
+ * Clear the section.
+ */
+ void clear ();
+
+ /**
+ * The size of the section given the offset.
+ */
+ uint32_t size (uint32_t offset = 0) const;
+
+ /**
+ * The alignment of the first section.
+ */
+ uint32_t alignment () const;
+
+ /**
+ * The alignment of the object section given its index.
+ */
+ uint32_t alignment (int index) const;
+
+ /**
+ * Set the offset of this section based on the previous section.
+ */
+ void set_offset (const section& sec);
+
+ /**
+ * Return the object section given the index.
+ */
+ const osection& get_osection (int index) const;
+
+ /**
+ * Output helper function to report the sections in an object file. This
+ * is useful when seeing the flags in the sections.
+ */
+ void output ();
+ };
+
+ /**
+ * A symbol. This matches the symbol structure 'rtems_rtl_obj_sym_t' in the
+ * target code.
+ */
+ struct external
+ {
+ /**
+ * Size of an external in the RAP file.
+ */
+ static const uint32_t rap_size = sizeof (uint32_t) * 3;
+
+ const uint32_t name; //< The string table's name index.
+ const sections sec; //< The section the symbols belongs to.
+ const uint32_t value; //< The offset from the section base.
+ const uint32_t data; //< The ELF st.info field.
+
+ /**
+ * The constructor.
+ */
+ external (const uint32_t name,
+ const sections sec,
+ const uint32_t value,
+ const uint32_t data);
+
+ /**
+ * Copy constructor.
+ */
+ external (const external& orig);
+
+ };
+
+ /**
+ * A container of externals.
+ */
+ typedef std::list < external > externals;
+
+ /**
+ * The specific data for each object we need to collect to create the RAP
+ * format file.
+ */
+ struct object
+ {
+ files::object& obj; //< The object file.
+ files::sections text; //< All executable code.
+ files::sections const_; //< All read only data.
+ files::sections ctor; //< The static constructor table.
+ files::sections dtor; //< The static destructor table.
+ files::sections data; //< All initialised read/write data.
+ files::sections bss; //< All uninitialised read/write data
+ files::sections symtab; //< All exported symbols.
+ files::sections strtab; //< All exported strings.
+ section secs[rap_secs]; //< The sections of interest.
+
+ /**
+ * The constructor. Need to have an object file to create.
+ */
+ object (files::object& obj);
+
+ /**
+ * The copy constructor.
+ */
+ object (const object& orig);
+
+ /**
+ * Find the section type that matches the section index.
+ */
+ sections find (const uint32_t index) const;
+
+ /**
+ * The total number of relocations in the object file.
+ */
+ uint32_t get_relocations () const;
+
+ /**
+ * The total number of relocations for a specific RAP section in the
+ * object file.
+ */
+ uint32_t get_relocations (int sec) const;
+
+ /**
+ * Output the object file details..
+ */
+ void output ();
+
+ private:
+ /**
+ * No default constructor allowed.
+ */
+ object ();
+ };
+
+ /**
+ * A container of objects.
+ */
+ typedef std::list < object > objects;
+
+ /**
+ * The RAP image.
+ */
+ class image
+ {
+ public:
+ /**
+ * Construct the image.
+ */
+ image ();
+
+ /**
+ * Load the layout data from the object files.
+ *
+ * @param app_objects The object files in the application.
+ * @param init The initialisation entry point label.
+ * @param fini The finish entry point label.
+ */
+ void layout (const files::object_list& app_objects,
+ const std::string& init,
+ const std::string& fini);
+
+ /**
+ * Collection the symbols from the object file.
+ *
+ * @param obj The object file to collection the symbol from.
+ */
+ void collect_symbols (object& obj);
+
+ /**
+ * Write the compressed output file. This is the top level write
+ * interface.
+ *
+ * @param comp The compressor.
+ */
+ void write (compress::compressor& comp);
+
+ /**
+ * Write the RAP section to the compressed output file given the object files.
+ * Check to make sure the size in the layout and the size written match.
+ *
+ * @param comp The compressor.
+ * @param sec The RAP setion to write.
+ */
+ void write (compress::compressor& comp, sections sec);
+
+ /**
+ * Write the sections to the compressed output file. The file sections
+ * are used to ensure the alignment. The offset is used to ensure the
+ * alignment of the first section of the object when it is written.
+ *
+ * @param comp The compressor.
+ * @param obj The object file the sections are part of.
+ * @param secs The container of file sections to write.
+ * @param offset The current offset in the RAP section.
+ */
+ void write (compress::compressor& comp,
+ files::object& obj,
+ const files::sections& secs,
+ uint32_t& offset);
+
+ /**
+ * Write the external symbols.
+ */
+ void write_externals (compress::compressor& comp);
+
+ /**
+ * Write the relocation records for all the object files.
+ */
+ void write_relocations (compress::compressor& comp);
+
+ /**
+ * Write the details of the files.
+ */
+ void write_details (compress::compressor& comp);
+
+ /**
+ * The total number of relocations for a specific RAP section in the
+ * image.
+ */
+ uint32_t get_relocations (int sec) const;
+
+ /**
+ * Clear the image values.
+ */
+ void clear ();
+
+ /**
+ * Report the RAP section's size.
+ */
+ uint32_t section_size (sections sec) const;
+
+ /**
+ * Find a symbol name in the string table.
+ */
+ std::size_t find_in_strtab (const std::string& symname);
+
+ private:
+
+ objects objs; //< The RAP objects
+ uint32_t sec_size[rap_secs]; //< The sections of interest.
+ uint32_t sec_align[rap_secs]; //< The sections of interest.
+ bool sec_rela[rap_secs]; //< The sections of interest.
+ externals externs; //< The symbols in the image
+ uint32_t symtab_size; //< The size of the symbols.
+ std::string strtab; //< The strings table.
+ uint32_t relocs_size; //< The relocations size.
+ uint32_t init_off; //< The strtab offset to the init label.
+ uint32_t fini_off; //< The strtab offset to the fini label.
+ };
+
+ const char*
+ section_name (int sec)
+ {
+ if (sec < rap_secs)
+ return section_names[sec];
+ throw rld::error ("Invalid section '" + rld::to_string (sec) + "'",
+ "rap::section-name");
+ }
+
+ /**
+ * Update the offset taking into account the alignment.
+ *
+ * @param offset The current offset.
+ * @param size The size to move the offset by.
+ * @param alignment The alignment of the offset.
+ * @return uint32_t The new aligned offset.
+ */
+ uint32_t align_offset (uint32_t offset, uint32_t size, uint32_t alignment)
+ {
+ offset += size;
+
+ if (alignment > 1)
+ {
+ uint32_t mask = alignment - 1;
+ if (offset & mask)
+ {
+ offset &= ~mask;
+ offset += alignment;
+ }
+ }
+
+ return offset;
+ }
+
+ relocation::relocation (const files::relocation& reloc,
+ const uint32_t offset)
+ : offset (reloc.offset + offset),
+ info (reloc.info),
+ addend (reloc.addend),
+ symname (reloc.symname),
+ symtype (reloc.symtype),
+ symsect (reloc.symsect),
+ symvalue (reloc.symvalue),
+ symbinding (reloc.symbinding)
+ {
+ }
+
+ section_detail::section_detail (uint32_t name,
+ uint32_t offset,
+ uint32_t id,
+ uint32_t size)
+ : name (name),
+ offset (offset),
+ id (id),
+ size (size)
+ {
+ }
+
+ osection::osection (const std::string& name,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t align,
+ uint32_t relocs,
+ uint64_t flags)
+ : name (name),
+ offset (offset),
+ size (size),
+ align (align),
+ relocs (relocs),
+ flags (flags)
+ {
+ }
+
+ osection::osection ()
+ : offset (0),
+ size (0),
+ align (0),
+ relocs (0),
+ flags (0)
+ {
+ }
+
+ section::section ()
+ : offset (0),
+ rela (false)
+ {
+ }
+
+ void
+ section::clear ()
+ {
+ offset = 0;
+ rela = false;
+ }
+
+ uint32_t
+ section::size (uint32_t offset_) const
+ {
+ uint32_t end = offset_;
+ if (end == 0)
+ end = offset;
+ for (size_t si = 0; si < osindexes.size (); ++si)
+ {
+ const osection& osec = get_osection (osindexes[si]);
+ end = align_offset (end, 0, osec.align);
+ end += osec.size;
+ }
+ return end - offset;
+ }
+
+ uint32_t
+ section::alignment () const
+ {
+ if (!osindexes.empty ())
+ {
+ const osection& osec = get_osection (osindexes[0]);
+ return osec.align;
+ }
+ return 0;
+ }
+
+ uint32_t
+ section::alignment (int index) const
+ {
+ const osection& osec = get_osection (index);
+ return osec.align;
+ }
+
+ void
+ section::set_offset (const section& sec)
+ {
+ uint32_t align = alignment ();
+ offset = align_offset (sec.offset, sec.size (), align);
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:section::set-offset: " << name
+ << " offset=" << offset
+ << " size=" << size ()
+ << " align=" << align
+ << " sec.offset=" << sec.offset
+ << " sec.size=" << sec.size (sec.offset)
+ << std::endl;
+ }
+
+ const osection&
+ section::get_osection (int index) const
+ {
+ osections::const_iterator osi = osecs.find (index);
+ if (osi == osecs.end ())
+ throw rld::error ("Invalid object seciton index in '" + name +"': index=" +
+ rld::to_string (index),
+ "rap::section");
+ return (*osi).second;
+ }
+
+ /**
+ * Output helper function to report the sections in an object file. This is
+ * useful when seeing the flags in the sections.
+ */
+ void
+ section::output ()
+ {
+ if (!osindexes.empty ())
+ {
+ std::cout << ' ' << name
+ << ": size: " << size (offset)
+ << " offset: " << offset
+ << " rela: " << (rela ? "yes" : "no")
+ << std::endl;
+
+ for (osecindexes::const_iterator osi = osindexes.begin ();
+ osi != osindexes.end ();
+ ++osi)
+ {
+ const osection& osec = get_osection (*osi);
+
+ if (osec.size)
+ {
+ #define SF(f, i, c) if (osec.flags & (f)) flags[i] = c
+
+ std::string flags ("--------------");
+
+ SF (SHF_WRITE, 0, 'W');
+ SF (SHF_ALLOC, 1, 'A');
+ SF (SHF_EXECINSTR, 2, 'E');
+ SF (SHF_MERGE, 3, 'M');
+ SF (SHF_STRINGS, 4, 'S');
+ SF (SHF_INFO_LINK, 5, 'I');
+ SF (SHF_LINK_ORDER, 6, 'L');
+ SF (SHF_OS_NONCONFORMING, 7, 'N');
+ SF (SHF_GROUP, 8, 'G');
+ SF (SHF_TLS, 9, 'T');
+ SF (SHF_AMD64_LARGE, 10, 'a');
+ SF (SHF_ENTRYSECT, 11, 'e');
+ SF (SHF_COMDEF, 12, 'c');
+ SF (SHF_ORDERED, 13, 'O');
+
+ std::cout << " " << std::left
+ << std::setw (15) << osec.name
+ << " " << flags
+ << " size: " << std::setw (5) << osec.size
+ << " align: " << std::setw (3) << osec.align
+ << " relocs: " << std::setw (4) << osec.relocs
+ << " offset: " << std::setw (5) << osec.offset
+ << std::hex
+ << " image: 0x" << offset + osec.offset
+ << std::dec << std::right << std::endl;
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper for for_each to merge the related object sections into the RAP
+ * section.
+ */
+ class section_merge:
+ public std::unary_function < const files::section, void >
+ {
+ public:
+
+ section_merge (object& obj, section& sec);
+
+ ~section_merge ();
+
+ void operator () (const files::section& fsec);
+
+ private:
+
+ object& obj;
+ section& sec;
+ };
+
+ section_merge::section_merge (object& obj, section& sec)
+ : obj (obj),
+ sec (sec)
+ {
+ sec.offset = 0;
+ sec.rela = false;
+ }
+
+ section_merge::~section_merge ()
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:section-merge: " << sec.name
+ << " size=" << sec.size ()
+ << " offset=" << sec.offset
+ << " " << obj.obj.name ().full () << std::endl;
+ }
+
+ void
+ section_merge::operator () (const files::section& fsec)
+ {
+ /*
+ * Align the size up to the next alignment boundary and use that as the
+ * offset for this object file section.
+ */
+ uint32_t offset = align_offset (sec.size (), 0, fsec.alignment);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:section-merge: " << fsec.name
+ << " sec-size=" << sec.size ()
+ << " relocs=" << fsec.relocs.size ()
+ << " offset=" << offset
+ << " fsec.size=" << fsec.size
+ << " fsec.alignment=" << fsec.alignment
+ << " fsec.rela=" << fsec.rela
+ << " " << obj.obj.name ().full () << std::endl;
+
+ /*
+ * Add the object file's section offset to the map. This is needed
+ * to adjust the external symbol offsets.
+ */
+ osection osec (fsec.name,
+ offset,
+ fsec.size,
+ fsec.alignment,
+ fsec.relocs.size (),
+ fsec.flags);
+ sec.osecs[fsec.index] = osec;
+ sec.osindexes.push_back (fsec.index);
+
+ uint32_t rc = 0;
+
+ for (files::relocations::const_iterator fri = fsec.relocs.begin ();
+ fri != fsec.relocs.end ();
+ ++fri, ++rc)
+ {
+ const files::relocation& freloc = *fri;
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << " " << std::setw (2) << sec.relocs.size ()
+ << '/' << std::setw (2) << rc
+ << std::hex << ": reloc.info=0x" << freloc.info << std::dec
+ << " reloc.offset=" << freloc.offset
+ << " reloc.addend=" << freloc.addend
+ << " reloc.symtype=" << freloc.symtype
+ << " reloc.symsect=" << freloc.symsect
+ << " reloc.symbinding=" << freloc.symbinding
+ << std::endl;
+
+ sec.relocs.push_back (relocation (freloc, offset));
+ }
+
+ std::stable_sort (sec.relocs.begin (),
+ sec.relocs.end (),
+ reloc_symname_compare ());
+ std::stable_sort (sec.relocs.begin (),
+ sec.relocs.end (),
+ reloc_offset_compare ());
+
+ if (fsec.rela == true)
+ sec.rela = fsec.rela;
+ }
+
+ external::external (const uint32_t name,
+ const sections sec,
+ const uint32_t value,
+ const uint32_t data)
+ : name (name),
+ sec (sec),
+ value (value),
+ data (data)
+ {
+ }
+
+ external::external (const external& orig)
+ : name (orig.name),
+ sec (orig.sec),
+ value (orig.value),
+ data (orig.data)
+ {
+ }
+
+ object::object (files::object& obj)
+ : obj (obj)
+ {
+ /*
+ * Set up the names of the sections.
+ */
+ for (int s = 0; s < rap_secs; ++s)
+ secs[s].name = section_names[s];
+
+ /*
+ * Get the relocation records. Collect the various section types from the
+ * object file into the RAP sections. Merge those sections into the RAP
+ * sections.
+ */
+
+ obj.open ();
+ try
+ {
+ obj.begin ();
+ obj.load_relocations ();
+ obj.end ();
+ }
+ catch (...)
+ {
+ obj.close ();
+ throw;
+ }
+ obj.close ();
+
+ obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
+ obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC, SHF_WRITE | SHF_EXECINSTR);
+ obj.get_sections (ctor, ".ctors");
+ obj.get_sections (dtor, ".dtors");
+ obj.get_sections (data, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
+ obj.get_sections (bss, SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ obj.get_sections (symtab, SHT_SYMTAB);
+ obj.get_sections (strtab, ".strtab");
+
+ std::for_each (text.begin (), text.end (),
+ section_merge (*this, secs[rap_text]));
+ std::for_each (const_.begin (), const_.end (),
+ section_merge (*this, secs[rap_const]));
+ std::for_each (ctor.begin (), ctor.end (),
+ section_merge (*this, secs[rap_ctor]));
+ std::for_each (dtor.begin (), dtor.end (),
+ section_merge (*this, secs[rap_dtor]));
+ std::for_each (data.begin (), data.end (),
+ section_merge (*this, secs[rap_data]));
+ std::for_each (bss.begin (), bss.end (),
+ section_merge (*this, secs[rap_bss]));
+ }
+
+ object::object (const object& orig)
+ : obj (orig.obj),
+ text (orig.text),
+ const_ (orig.const_),
+ ctor (orig.ctor),
+ dtor (orig.dtor),
+ data (orig.data),
+ bss (orig.bss),
+ symtab (orig.symtab),
+ strtab (orig.strtab)
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ secs[s] = orig.secs[s];
+ }
+
+ sections
+ object::find (const uint32_t index) const
+ {
+ const files::section* sec;
+
+ sec = files::find (text, index);
+ if (sec)
+ return rap_text;
+
+ sec = files::find (const_, index);
+ if (sec)
+ return rap_const;
+
+ sec = files::find (ctor, index);
+ if (sec)
+ return rap_ctor;
+
+ sec = files::find (dtor, index);
+ if (sec)
+ return rap_dtor;
+
+ sec = files::find (data, index);
+ if (sec)
+ return rap_data;
+
+ sec = files::find (bss, index);
+ if (sec)
+ return rap_bss;
+
+ throw rld::error ("Section index '" + rld::to_string (index) +
+ "' not found: " + obj.name ().full (), "rap::object");
+ }
+
+ uint32_t
+ object::get_relocations () const
+ {
+ uint32_t relocs = 0;
+ for (int s = 0; s < rap_secs; ++s)
+ relocs += secs[s].relocs.size ();
+ return relocs;
+ }
+
+ uint32_t
+ object::get_relocations (int sec) const
+ {
+ if ((sec < 0) || (sec >= rap_secs))
+ throw rld::error ("Invalid section index '" + rld::to_string (sec),
+ "rap::relocations");
+ return secs[sec].relocs.size ();
+ }
+
+ void
+ object::output ()
+ {
+ std::cout << "rap:object: " << obj.name ().full () << std::endl;
+ secs[rap_text].output ();
+ secs[rap_const].output ();
+ secs[rap_ctor].output ();
+ secs[rap_dtor].output ();
+ secs[rap_data].output ();
+ if (secs[rap_bss].size ())
+ std::cout << " bss: size: " << secs[rap_bss].size () << std::endl;
+ }
+
+ image::image ()
+ {
+ clear ();
+ }
+
+ void
+ image::layout (const files::object_list& app_objects,
+ const std::string& init,
+ const std::string& fini)
+ {
+ clear ();
+
+ /*
+ * Create the local objects which contain the layout information.
+ */
+ for (files::object_list::const_iterator aoi = app_objects.begin ();
+ aoi != app_objects.end ();
+ ++aoi)
+ {
+ files::object& app_obj = *(*aoi);
+
+ if (!app_obj.valid ())
+ throw rld::error ("Not valid: " + app_obj.name ().full (),
+ "rap::layout");
+
+ objs.push_back (object (app_obj));
+ }
+
+ for (objects::iterator oi = objs.begin (), poi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+
+ /*
+ * Update the offsets in the object file. We need the object's offset
+ * to set the relocation offset's correctly as they are relative to the
+ * object file.
+ */
+ if (oi != objs.begin ())
+ {
+ object& pobj = *poi;
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ obj.secs[s].set_offset (pobj.secs[s]);
+ sec_size[s] = obj.secs[s].offset + obj.secs[s].size ();
+ sec_align[s] = obj.secs[s].alignment ();
+ if (obj.secs[s].rela == true)
+ sec_rela[s] = obj.secs[s].rela;
+ }
+ ++poi;
+ }
+ else
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ sec_size[s] = obj.secs[s].size ();
+ sec_align[s] = obj.secs[s].alignment ();
+ if (obj.secs[s].rela == true)
+ sec_rela[s] = true;
+ }
+ }
+
+ collect_symbols (obj);
+
+ relocs_size += obj.get_relocations ();
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ obj.output ();
+ }
+
+ init_off = strtab.size () + 1;
+ strtab += '\0';
+ strtab += init;
+
+ fini_off = strtab.size () + 1;
+ strtab += '\0';
+ strtab += fini;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ {
+ uint32_t total = (sec_size[rap_text] + sec_size[rap_const] +
+ sec_size[rap_data] + sec_size[rap_bss] +
+ symtab_size + strtab.size() + relocs_size);
+ std::cout << "rap::layout: total:" << total
+ << " text:" << sec_size[rap_text]
+ << " const:" << sec_size[rap_const]
+ << " ctor:" << sec_size[rap_ctor]
+ << " dtor:" << sec_size[rap_dtor]
+ << " data:" << sec_size[rap_data]
+ << " bss:" << sec_size[rap_bss]
+ << " symbols:" << symtab_size << " (" << externs.size () << ')'
+ << " strings:" << strtab.size () + 1
+ << " relocs:" << relocs_size
+ << std::endl;
+ }
+ }
+
+ void
+ image::collect_symbols (object& obj)
+ {
+ symbols::pointers& esyms = obj.obj.external_symbols ();
+ for (symbols::pointers::const_iterator ei = esyms.begin ();
+ ei != esyms.end ();
+ ++ei)
+ {
+ const symbols::symbol& sym = *(*ei);
+
+ if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC) || (sym.type () == STT_NOTYPE))
+ {
+ if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK))
+ {
+ int symsec = sym.section_index ();
+
+ /* Ignore section index 0 */
+ if (symsec == 0)
+ continue;
+ /* Ignore sparc common section */
+ if ((elf::object_machine_type () == EM_SPARC) && (symsec == 65522))
+ continue;
+
+ sections rap_sec = obj.find (symsec);
+ section& sec = obj.secs[rap_sec];
+ std::size_t name;
+
+ /*
+ * See if the name is already in the string table.
+ */
+ name = find_in_strtab (sym.name ());
+
+ if (name == std::string::npos)
+ {
+ name = strtab.size () + 1;
+ strtab += '\0';
+ strtab += sym.name ();
+ }
+
+ /*
+ * The symbol's value is the symbols value plus the offset of the
+ * object file's section offset in the RAP section.
+ */
+ externs.push_back (external (name,
+ rap_sec,
+ sec.offset + sec.osecs[symsec].offset +
+ sym.value (),
+ sym.info ()));
+
+ symtab_size += external::rap_size;
+ }
+ }
+ }
+ }
+
+ void
+ image::write (compress::compressor& comp)
+ {
+ /*
+ * Start with the machine type so the target can check the applicatiion
+ * is ok and can be loaded. Add the init and fini labels to the string
+ * table and add the references to the string table next. Follow this
+ * with the section details then the string table and symbol table then
+ * finally the relocation records.
+ */
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: machine=" << comp.transferred () << std::endl;
+
+ comp << elf::object_machine_type ()
+ << elf::object_datatype ()
+ << elf::object_class ();
+
+ /*
+ * The init and fini label offsets. Then the symbol table and string
+ * table sizes.
+ */
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: header=" << comp.transferred () << std::endl;
+
+ comp << init_off
+ << fini_off
+ << symtab_size
+ << (uint32_t) strtab.size () + 1
+ << (uint32_t) 0;
+
+ /*
+ * Output file details
+ */
+ if (add_obj_details)
+ {
+ write_details (comp);
+ }
+ else
+ {
+ comp << (uint32_t)0; /* No file details */
+ }
+
+ /*
+ * The sections.
+ */
+ for (int s = 0; s < rap_secs; ++s)
+ comp << sec_size[s]
+ << sec_align[s];
+
+ /*
+ * Output the sections from each object file.
+ */
+ write (comp, rap_text);
+ write (comp, rap_const);
+ write (comp, rap_ctor);
+ write (comp, rap_dtor);
+ write (comp, rap_data);
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: strtab=" << comp.transferred () << std::endl;
+
+ strtab += '\0';
+ comp << strtab;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: symbols=" << comp.transferred () << std::endl;
+
+ write_externals (comp);
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: relocs=" << comp.transferred () << std::endl;
+
+ write_relocations (comp);
+ }
+
+ /**
+ * Helper for for_each to write out the various sections.
+ */
+ class section_writer:
+ public std::unary_function < object, void >
+ {
+ public:
+
+ section_writer (image& img,
+ compress::compressor& comp,
+ sections sec);
+
+ void operator () (object& obj);
+
+ private:
+
+ image& img;
+ compress::compressor& comp;
+ sections sec;
+ uint32_t offset;
+ };
+
+ section_writer::section_writer (image& img,
+ compress::compressor& comp,
+ sections sec)
+ : img (img),
+ comp (comp),
+ sec (sec),
+ offset (0)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: " << section_names[sec]
+ << ": offset=" << comp.transferred ()
+ << " size=" << img.section_size (sec) << std::endl;
+ }
+
+ void
+ section_writer::operator () (object& obj)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:writing: " << section_names[sec] << std::endl;
+
+ switch (sec)
+ {
+ case rap_text:
+ img.write (comp, obj.obj, obj.text, offset);
+ break;
+ case rap_const:
+ img.write (comp, obj.obj, obj.const_, offset);
+ break;
+ case rap_ctor:
+ img.write (comp, obj.obj, obj.ctor, offset);
+ break;
+ case rap_dtor:
+ img.write (comp, obj.obj, obj.dtor, offset);
+ break;
+ case rap_data:
+ img.write (comp, obj.obj, obj.data, offset);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void
+ image::write (compress::compressor& comp, sections sec)
+ {
+ uint32_t image_offset = comp.transferred ();
+
+ std::for_each (objs.begin (), objs.end (),
+ section_writer (*this, comp, sec));
+
+ uint32_t written = comp.transferred () - image_offset;
+
+ if (written != sec_size[sec])
+ {
+ std::string msg = "Image output size does not match layout size: ";
+ msg += section_names[sec];
+ msg += ": layout-size=" + rld::to_string (sec_size[sec]);
+ msg += " image-size=" + rld::to_string (written);
+ throw rld::error (msg, "rap::write");
+ }
+ }
+
+ void
+ image::write (compress::compressor& comp,
+ files::object& obj,
+ const files::sections& secs,
+ uint32_t& offset)
+ {
+ uint32_t size = 0;
+
+ obj.open ();
+
+ try
+ {
+ obj.begin ();
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:write sections: " << obj.name ().full () << std::endl;
+
+ for (files::sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ const files::section& sec = *si;
+ uint32_t unaligned_offset = offset + size;
+
+ offset = align_offset (offset, size, sec.alignment);
+
+ if (offset != unaligned_offset)
+ {
+ char ee = '\xee';
+ for (uint32_t p = 0; p < (offset - unaligned_offset); ++p)
+ comp.write (&ee, 1);
+ }
+
+ comp.write (obj, sec.offset, sec.size);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << " sec: " << sec.index << ' ' << sec.name
+ << " offset=" << offset
+ << " size=" << sec.size
+ << " align=" << sec.alignment
+ << " padding=" << (offset - unaligned_offset) << std::endl;
+
+ size = sec.size;
+ }
+
+ offset += size;
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << " total size=" << offset << std::endl;
+
+ obj.end ();
+ }
+ catch (...)
+ {
+ obj.close ();
+ throw;
+ }
+
+ obj.close ();
+ }
+
+ void
+ image::write_externals (compress::compressor& comp)
+ {
+ int count = 0;
+ for (externals::const_iterator ei = externs.begin ();
+ ei != externs.end ();
+ ++ei, ++count)
+ {
+ const external& ext = *ei;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "rap:externs: " << count
+ << " name=" << &strtab[ext.name] << " (" << ext.name << ')'
+ << " section=" << section_names[ext.sec]
+ << " data=" << ext.data
+ << " value=0x" << std::hex << ext.value << std::dec
+ << std::endl;
+
+ if ((ext.data & 0xffff0000) != 0)
+ throw rld::error ("Data value has data in bits higher than 15",
+ "rap::write-externs");
+
+ comp << (uint32_t) ((ext.sec << 16) | ext.data)
+ << ext.name
+ << ext.value;
+ }
+ }
+
+ void
+ image::write_relocations (compress::compressor& comp)
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ uint32_t count = get_relocations (s);
+ uint32_t sr = 0;
+ uint32_t header;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "rap:relocation: section:" << section_names[s]
+ << " relocs=" << count
+ << " rela=" << (char*) (sec_rela[s] ? "yes" : "no")
+ << std::endl;
+
+ header = count;
+ header |= sec_rela[s] ? RAP_RELOC_RELA : 0;
+
+ comp << header;
+
+ for (objects::iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+ section& sec = obj.secs[s];
+ relocations& relocs = sec.relocs;
+ uint32_t rc = 0;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << " relocs=" << sec.relocs.size ()
+ << " sec.offset=" << sec.offset
+ << " sec.size=" << sec.size ()
+ << " sec.align=" << sec.alignment ()
+ << " " << obj.obj.name ().full () << std::endl;
+
+ for (relocations::const_iterator ri = relocs.begin ();
+ ri != relocs.end ();
+ ++ri, ++sr, ++rc)
+ {
+ const relocation& reloc = *ri;
+ uint32_t info = GELF_R_TYPE (reloc.info);
+ uint32_t offset;
+ uint32_t addend = reloc.addend;
+ bool write_addend = sec.rela;
+ bool write_symname = false;
+
+ offset = sec.offset + reloc.offset;
+
+ if ((reloc.symtype == STT_SECTION) || (reloc.symbinding == STB_LOCAL))
+ {
+ int rap_symsect = obj.find (reloc.symsect);
+
+ /*
+ * Bit 31 clear, bits 30:8 RAP section index.
+ */
+ info |= rap_symsect << 8;
+
+ addend += (obj.secs[rap_symsect].offset +
+ obj.secs[rap_symsect].osecs[reloc.symsect].offset +
+ reloc.symvalue);
+
+ write_addend = true;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << " " << std::setw (2) << sr
+ << '/' << std::setw (2) << rc
+ <<": rsym: sect=" << section_names[rap_symsect]
+ << " rap_symsect=" << rap_symsect
+ << " sec.offset=" << obj.secs[rap_symsect].offset
+ << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect].offset
+ << " (" << obj.obj.get_section (reloc.symsect).name << ')'
+ << " reloc.symsect=" << reloc.symsect
+ << " reloc.symvalue=" << reloc.symvalue
+ << " reloc.addend=" << reloc.addend
+ << " addend=" << addend
+ << std::endl;
+ }
+ else
+ {
+ /*
+ * Bit 31 must be set. Bit 30 determines the type of string and
+ * bits 29:8 the strtab offset or the size of the appended
+ * string.
+ */
+
+ info |= RAP_RELOC_STRING;
+
+ std::size_t size = find_in_strtab (reloc.symname);
+
+ if (size == std::string::npos)
+ {
+ /*
+ * Bit 30 clear, the size of the symbol name.
+ */
+ info |= reloc.symname.size () << 8;
+ write_symname = true;
+ }
+ else
+ {
+ /*
+ * Bit 30 set, the offset in the strtab.
+ */
+ info |= RAP_RELOC_STRING_EMBED | (size << 8);
+ }
+ }
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << " " << std::setw (2) << sr << '/'
+ << std::setw (2) << rc
+ << std::hex << ": reloc: info=0x" << info << std::dec
+ << " offset=" << offset;
+ if (write_addend)
+ std::cout << " addend=" << addend;
+ if ((info & RAP_RELOC_STRING) != 0)
+ {
+ std::cout << " symname=" << reloc.symname;
+ if (write_symname)
+ std::cout << " (appended)";
+ }
+ std::cout << std::hex
+ << " reloc.info=0x" << reloc.info << std::dec
+ << " reloc.offset=" << reloc.offset
+ << " reloc.symtype=" << reloc.symtype
+ << std::endl;
+ }
+
+ comp << info << offset;
+
+ if (write_addend)
+ comp << addend;
+
+ if (write_symname)
+ comp << reloc.symname;
+ }
+ }
+ }
+ }
+
+ void image::write_details (compress::compressor& comp)
+ {
+
+ std::string strtable;
+ uint32_t pos = 0;
+
+ section_details s_details;
+
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "rap:file details" << std::endl
+ << " total " << objs.size () <<" files" << std::endl;
+ }
+
+ comp << (uint32_t)(objs.size ());
+
+ /* rpath for rap file */
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "rap:file rpath=" << rld::rap::rpath << std::endl;
+ }
+
+ comp << (uint32_t)rld::rap::rpath.length ();
+
+ if (rld::rap::rpath.length () > 0)
+ {
+ strtable += rld::rap::rpath;
+ }
+
+ for (objects::iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+
+ /* obj full name */
+ strtable += obj.obj.name ().full ();
+ strtable += '\0';
+ }
+
+ pos = strtable.length ();
+
+ uint32_t sec_num = 0;
+ for (objects::iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "file:" << obj.obj.name ().full () << std::endl;
+
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ section& sec = obj.secs[s];
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "rap:section: " << sec.name << " "
+ "offset= " << sec.offset << std::endl;
+ }
+
+ for (size_t si = 0; si < sec.osindexes.size (); ++si)
+ {
+ const osection& osec = sec.get_osection (sec.osindexes[si]);
+
+ strtable += osec.name;
+ strtable += '\0';
+
+ /* sec.offset + osec.offset is the offset in the rap section */
+ s_details.push_back (section_detail (pos,
+ sec.offset + osec.offset,
+ s,
+ osec.size));
+
+ pos = strtable.length ();
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "osec.name=" << osec.name << " "
+ << "osec.offset=" << osec.offset << " "
+ << "osec.size=" << osec.size << std::endl;
+ }
+ }
+ }
+
+ /* Output section numbers*/
+ comp << (uint32_t)((s_details.size () - sec_num));
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "sec_num:" << s_details.size () - sec_num << std::endl;
+ sec_num = s_details.size ();
+ }
+
+ comp << (uint32_t)(strtable.size ());
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "total detail size:" << strtable.size () << std::endl;
+
+ comp << strtable;
+
+ for (section_details::const_iterator si = s_details.begin ();
+ si != s_details.end ();
+ ++si)
+ {
+ const section_detail& sec_detail = *si;
+ comp << (uint32_t)(sec_detail.name);
+
+ if (sec_detail.id > 0xf)
+ std::cout << "Out max rap section id 15\n" << std::endl;
+
+ comp << (uint32_t)((sec_detail.id << 28) | sec_detail.offset);
+ comp << (uint32_t)(sec_detail.size);
+ }
+ }
+
+ uint32_t
+ image::get_relocations (int sec) const
+ {
+ if ((sec < 0) || (sec >= rap_secs))
+ throw rld::error ("Invalid section index '" + rld::to_string (sec),
+ "rap::image::relocations");
+
+ uint32_t relocs = 0;
+
+ for (objects::const_iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ const object& obj = *oi;
+ relocs += obj.get_relocations (sec);
+ }
+
+ return relocs;
+ }
+
+ void
+ image::clear ()
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ sec_size[s] = 0;
+ sec_align[s] = 0;
+ sec_rela[s] = false;
+ }
+ symtab_size = 0;
+ strtab.clear ();
+ relocs_size = 0;
+ init_off = 0;
+ fini_off = 0;
+ }
+
+ uint32_t
+ image::section_size (sections sec) const
+ {
+ if ((sec < 0) || (sec >= rap_secs))
+ throw rld::error ("Invalid section index '" + rld::to_string (sec),
+ "rap::image::section_size");
+ return sec_size[sec];
+ }
+
+ std::size_t
+ image::find_in_strtab (const std::string& symname)
+ {
+ std::size_t pos = 0;
+ while (pos < strtab.size ())
+ {
+ std::size_t off = strtab.find (symname, pos);
+ if (off == std::string::npos)
+ break;
+ if (::strlen (strtab.c_str () + off) == symname.size ())
+ return off;
+ pos = off + 1;
+ }
+ return std::string::npos;
+ }
+
+ void
+ write (files::image& app,
+ const std::string& init,
+ const std::string& fini,
+ const files::object_list& app_objects,
+ const symbols::table& /* symbols */) /* Add back for incremental
+ * linking */
+ {
+ std::string header;
+
+ header = "RAP,00000000,0002,LZ77,00000000\n";
+ app.write (header.c_str (), header.size ());
+
+ compress::compressor compressor (app, 2 * 1024);
+ image rap;
+
+ rap.layout (app_objects, init, fini);
+ rap.write (compressor);
+
+ compressor.flush ();
+
+ std::ostringstream length;
+
+ length << std::setfill ('0') << std::setw (8)
+ << header.size () + compressor.compressed ();
+
+ header.replace (4, 8, length.str ());
+
+ app.seek (0);
+ app.write (header.c_str (), header.size ());
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ {
+ int pcent = (compressor.compressed () * 100) / compressor.transferred ();
+ int premand = (((compressor.compressed () * 1000) + 500) /
+ compressor.transferred ()) % 10;
+ std::cout << "rap: objects: " << app_objects.size ()
+ << ", size: " << compressor.compressed ()
+ << ", compression: " << pcent << '.' << premand << '%'
+ << std::endl;
+ }
+ }
+
+ }
+}
diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h
new file mode 100644
index 0000000..19969e3
--- /dev/null
+++ b/linkers/rld-rap.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker RTEMS Application (RAP) Format management.
+ *
+ */
+
+#if !defined (_RLD_RAP_H_)
+#define _RLD_RAP_H_
+
+#include <rld-files.h>
+
+namespace rld
+{
+ namespace rap
+ {
+ /**
+ * Output details or not.
+ */
+ extern bool add_obj_details;
+
+ /**
+ * Store the path of object files.
+ */
+ extern std::string rpath;
+
+ /**
+ * The RAP relocation bit masks.
+ */
+ #define RAP_RELOC_RELA (1UL << 31)
+ #define RAP_RELOC_STRING (1UL << 31)
+ #define RAP_RELOC_STRING_EMBED (1UL << 30)
+
+ /**
+ * The sections of interest in a RAP file.
+ */
+ enum sections
+ {
+ rap_text = 0,
+ rap_const = 1,
+ rap_ctor = 2,
+ rap_dtor = 3,
+ rap_data = 4,
+ rap_bss = 5,
+ rap_secs = 6
+ };
+
+ /**
+ * Return the name of a section.
+ */
+ const char* section_name (int sec);
+
+ /**
+ * Write a RAP format file.
+ *
+ * The symbol table is provided to allow incremental linking at some point
+ * in the future. I suspect this will also require extra options being
+ * added to control symbol visibility in the RAP file. For example an
+ * "application" may be self contained and does not need to export any
+ * symbols therefore no symbols are added and the only ones are part of the
+ * relocation records to bind to base image symbols. Another case is the
+ * need for an application to export symbols because it is using dlopen to
+ * load modules. Here the symbols maybe 'all' or it could be a user
+ * maintained list that are exported.
+ *
+ * @param app The application image to write too.
+ * @param init The application's initialisation entry point.
+ * @param fini The application's finish entry point .
+ * @param objects The list of object files in the application.
+ * @param symbols The symbol table used to create the application.
+ */
+ void write (files::image& app,
+ const std::string& init,
+ const std::string& fini,
+ const files::object_list& objects,
+ const symbols::table& symbols);
+ }
+}
+
+#endif
diff --git a/linkers/rld-resolver.cpp b/linkers/rld-resolver.cpp
new file mode 100644
index 0000000..31a6779
--- /dev/null
+++ b/linkers/rld-resolver.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_ld
+ *
+ * @brief RTEMS Linker.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iomanip>
+#include <iostream>
+
+#include <sys/stat.h>
+
+#include <rld.h>
+#include <rld.h>
+
+namespace rld
+{
+ namespace resolver
+ {
+ static files::object*
+ get_object (files::cache& cache,
+ const std::string& fullname)
+ {
+ files::objects& objects = cache.get_objects ();
+ files::objects::iterator oi = objects.find (fullname);
+ if (oi == objects.end ())
+ return 0;
+ return (*oi).second;
+ }
+
+ static void
+ resolve_symbols (files::object_list& dependents,
+ files::cache& cache,
+ symbols::table& base_symbols,
+ symbols::table& symbols,
+ symbols::symtab& unresolved,
+ const std::string& fullname)
+ {
+ const std::string name = files::basename (fullname);
+
+ static int nesting = 0;
+
+ ++nesting;
+
+ /*
+ * Find each unresolved symbol in the symbol table pointing the
+ * unresolved symbol's object file to the file that resolves the
+ * symbol. Record each object file that is found and when all unresolved
+ * symbols in this object file have been found iterate over the found
+ * object files resolving them. The 'urs' is the unresolved symbol and
+ * 'es' is the exported symbol.
+ */
+
+ files::object* object = get_object (cache, fullname);
+
+ if (object)
+ {
+ if (object->resolved () || object->resolving ())
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "resolver:resolving: "
+ << std::setw (nesting - 1) << ' '
+ << name
+ << " is resolved or resolving"
+ << std::endl;
+ return;
+ }
+ object->resolve_set ();
+ }
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "resolver:resolving: "
+ << std::setw (nesting - 1) << ' '
+ << name
+ << ", unresolved: "
+ << unresolved.size ()
+ << std::endl;
+
+ files::object_list objects;
+
+ for (symbols::symtab::iterator ursi = unresolved.begin ();
+ ursi != unresolved.end ();
+ ++ursi)
+ {
+ symbols::symbol& urs = *((*ursi).second);
+
+ if ((urs.binding () != STB_WEAK) && urs.object ())
+ continue;
+
+ symbols::symbol* es = base_symbols.find_external (urs.name ());
+ bool base = true;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ {
+ std::cout << "resolver:resolve : "
+ << std::setw (nesting + 1) << ' '
+ << " |- " << urs.name () << std::endl;
+ }
+
+ if (!es)
+ {
+ es = symbols.find_external (urs.name ());
+ if (!es)
+ {
+ es = symbols.find_weak (urs.name ());
+ if (!es)
+ throw rld::error ("symbol not found: " + urs.name (), name);
+ }
+ base = false;
+ }
+
+ symbols::symbol& esym = *es;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ {
+ std::cout << "resolver:resolved : "
+ << std::setw (nesting + 1) << ' '
+ << " | `--> ";
+ if (esym.object())
+ {
+ std::cout << esym.object()->name ().basename ();
+ if (esym.object()->resolving ())
+ std::cout << " (resolving)";
+ else if (esym.object()->resolved ())
+ std::cout << " (resolved)";
+ else if (base)
+ std::cout << " (base)";
+ else
+ std::cout << " (unresolved: " << objects.size () + 1 << ')';
+ }
+ else
+ std::cout << "null";
+ std::cout << std::endl;
+ }
+
+ if (!base)
+ {
+ files::object& eobj = *esym.object ();
+ urs.set_object (eobj);
+ if (!eobj.resolved () && !eobj.resolving ())
+ {
+ objects.push_back (&eobj);
+ objects.unique ();
+ }
+ }
+
+ esym.referenced ();
+ }
+
+ if (object)
+ {
+ object->resolve_clear ();
+ object->resolved_set ();
+ }
+
+ /*
+ * Recurse into any references object files.
+ */
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "resolver:resolved : "
+ << std::setw (nesting + 1) << ' '
+ << " +-- referenced objects: " << objects.size ()
+ << std::endl;
+
+ for (files::object_list::iterator oli = objects.begin ();
+ oli != objects.end ();
+ ++oli)
+ {
+ files::object& obj = *(*oli);
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "resolver:resolving: "
+ << std::setw (nesting) << ' '
+ << "] " << name << " ==> "
+ << obj.name ().basename () << std::endl;
+ resolve_symbols (dependents, cache, base_symbols, symbols,
+ obj.unresolved_symbols (),
+ obj.name ().full ());
+ }
+
+ --nesting;
+
+ dependents.merge (objects);
+ dependents.unique ();
+ }
+
+ void
+ resolve (files::object_list& dependents,
+ files::cache& cache,
+ symbols::table& base_symbols,
+ symbols::table& symbols,
+ symbols::symtab& undefined)
+ {
+ files::object_list objects;
+ cache.get_objects (objects);
+
+ /*
+ * First resolve any undefined symbols that are forced by the linker or
+ * the user.
+ */
+ resolver::resolve_symbols (dependents, cache, base_symbols, symbols,
+ undefined, "undefines");
+
+ /*
+ * Resolve the symbols in the object files.
+ */
+ for (files::object_list::iterator oi = objects.begin ();
+ oi != objects.end ();
+ ++oi)
+ {
+ files::object& object = *(*oi);
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "resolver:resolving: top: "
+ << object.name ().basename () << std::endl;
+ resolver::resolve_symbols (dependents, cache, base_symbols, symbols,
+ object.unresolved_symbols (),
+ object.name ().full ());
+ }
+ }
+ }
+
+}
diff --git a/linkers/rld-resolver.h b/linkers/rld-resolver.h
new file mode 100644
index 0000000..3771f18
--- /dev/null
+++ b/linkers/rld-resolver.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker resolver determines which object files are needed.
+ *
+ */
+
+#if !defined (_RLD_RESOLVER_H_)
+#define _RLD_RESOLVER_H_
+
+#include <rld-files.h>
+#include <rld-symbols.h>
+
+namespace rld
+{
+ namespace resolver
+ {
+ /**
+ * Resolve the dependences between object files.
+ *
+ * @param dependents The object modules dependent on the object files we
+ * are linking.
+ * @param cache The file cache.
+ * @param base_symbols The base image symbol table
+ * @param symbols The object file and library symbols
+ * @param undefined Extra undefined symbols dependent object files are
+ * added for.
+ */
+ void resolve (files::object_list& dependents,
+ files::cache& cache,
+ symbols::table& base_symbols,
+ symbols::table& symbols,
+ symbols::symtab& undefined);
+ }
+}
+
+#endif
diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp
new file mode 100644
index 0000000..3464017
--- /dev/null
+++ b/linkers/rld-symbols.cpp
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker symbols manages the symbols from all the object files.
+ *
+ */
+
+#include <string.h>
+
+#include <iomanip>
+
+#include <rld.h>
+
+#include <libiberty/demangle.h>
+
+namespace rld
+{
+ namespace symbols
+ {
+ /**
+ * Get the demangled name.
+ */
+ static void
+ denamgle_name (std::string& name, std::string& demangled)
+ {
+ char* demangled_name = ::cplus_demangle (name.c_str (),
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name)
+ {
+ demangled = demangled_name;
+ ::free (demangled_name);
+ }
+ }
+
+ symbol::symbol ()
+ : index_ (-1),
+ object_ (0),
+ references_ (0)
+ {
+ memset (&esym_, 0, sizeof (esym_));
+ }
+
+ symbol::symbol (int index,
+ const std::string& name,
+ files::object& object,
+ const elf::elf_sym& esym)
+ : index_ (index),
+ name_ (name),
+ object_ (&object),
+ esym_ (esym),
+ references_ (0)
+ {
+ if (!object_)
+ throw rld_error_at ("object pointer is 0");
+ if (is_cplusplus ())
+ denamgle_name (name_, demangled_);
+ }
+
+ symbol::symbol (int index,
+ const std::string& name,
+ const elf::elf_sym& esym)
+ : index_ (index),
+ name_ (name),
+ object_ (0),
+ esym_ (esym),
+ references_ (0)
+ {
+ if (is_cplusplus ())
+ denamgle_name (name_, demangled_);
+ }
+
+ symbol::symbol (const std::string& name,
+ const elf::elf_addr value)
+ : index_ (-1),
+ name_ (name),
+ object_ (0),
+ references_ (0)
+ {
+ memset (&esym_, 0, sizeof (esym_));
+ esym_.st_value = value;
+ }
+
+ symbol::symbol (const char* name,
+ const elf::elf_addr value)
+ : index_ (-1),
+ name_ (name),
+ object_ (0),
+ references_ (0)
+ {
+ memset (&esym_, 0, sizeof (esym_));
+ esym_.st_value = value;
+ }
+
+ int
+ symbol::index () const
+ {
+ return index_;
+ }
+
+ const std::string&
+ symbol::name () const
+ {
+ return name_;
+ }
+
+ const std::string&
+ symbol::demangled () const
+ {
+ return demangled_;
+ }
+
+ bool
+ symbol::is_cplusplus () const
+ {
+ return (name_[0] == '_') && (name_[1] == 'Z');
+ }
+
+ int
+ symbol::type () const
+ {
+ return GELF_ST_TYPE (esym_.st_info);
+ }
+
+ int
+ symbol::binding () const
+ {
+ return GELF_ST_BIND (esym_.st_info);
+ }
+
+ int
+ symbol::section_index () const
+ {
+ return esym_.st_shndx;
+ }
+
+ elf::elf_addr
+ symbol::value () const
+ {
+ return esym_.st_value;
+ }
+
+ uint32_t
+ symbol::info () const
+ {
+ return esym_.st_info;
+ }
+
+ rld::files::object*
+ symbol::object () const
+ {
+ return object_;
+ }
+
+ void
+ symbol::set_object (rld::files::object& obj)
+ {
+ object_ = &obj;
+ }
+
+ const elf::elf_sym&
+ symbol::esym () const
+ {
+ return esym_;
+ }
+
+ void
+ symbol::referenced ()
+ {
+ ++references_;
+ if (object_)
+ object_->symbol_referenced ();
+ }
+
+ bool
+ symbol::operator< (const symbol& rhs) const
+ {
+ return name_ < rhs.name_;
+ }
+
+ void
+ symbol::output (std::ostream& out) const
+ {
+ const elf::elf_sym& es = esym ();
+
+ std::string binding;
+ int binding_val = GELF_ST_BIND (es.st_info);
+ switch (binding_val)
+ {
+ case STB_LOCAL:
+ binding = "STB_LOCAL ";
+ break;
+ case STB_GLOBAL:
+ binding = "STB_GLOBAL";
+ break;
+ case STB_WEAK:
+ binding = "STB_WEAK ";
+ break;
+ default:
+ if ((binding_val >= STB_LOPROC) && (binding_val <= STB_HIPROC))
+ binding = "STB_LOPROC(" + rld::to_string (binding_val) + ")";
+ else
+ binding = "STB_INVALID(" + rld::to_string (binding_val) + ")";
+ break;
+ }
+
+ std::string type;
+ int type_val = GELF_ST_TYPE (es.st_info);
+ switch (type_val)
+ {
+ case STT_NOTYPE:
+ type = "STT_NOTYPE ";
+ break;
+ case STT_OBJECT:
+ type = "STT_OBJECT ";
+ break;
+ case STT_FUNC:
+ type = "STT_FUNC ";
+ break;
+ case STT_SECTION:
+ type = "STT_SECTION";
+ break;
+ case STT_FILE:
+ type = "STT_FILE ";
+ break;
+ default:
+ if ((type_val >= STT_LOPROC) && (type_val <= STT_HIPROC))
+ type = "STT_LOPROC(" + rld::to_string (type_val) + ")";
+ else
+ type = "STT_INVALID(" + rld::to_string (type_val) + ")";
+ break;
+ }
+
+ out << std::setw (4) << index_
+ << ' ' << binding
+ << ' ' << type
+ << ' ' << std::setw(6) << es.st_shndx
+ << " 0x" << std::setw (8) << std::setfill ('0') << std::hex
+ << es.st_value
+ << std::dec << std::setfill (' ')
+ << ' ' << std::setw (7) << es.st_size
+ << ' ';
+
+ if (is_cplusplus ())
+ out << demangled ();
+ else
+ out << name ();
+
+ if (object ())
+ out << " (" << object ()->name ().basename () << ')';
+ }
+
+ table::table ()
+ {
+ }
+
+ table::~table ()
+ {
+ }
+
+ void
+ table::add_external (symbol& sym)
+ {
+ _externals[sym.name ()] = &sym;
+ }
+
+ void
+ table::add_weak (symbol& sym)
+ {
+ _weaks[sym.name ()] = &sym;
+ }
+
+ symbol*
+ table::find_external (const std::string& name)
+ {
+ symtab::iterator sti = _externals.find (name);
+ if (sti == _externals.end ())
+ return 0;
+ return (*sti).second;
+ }
+
+ symbol*
+ table::find_weak (const std::string& name)
+ {
+ symtab::iterator sti = _weaks.find (name);
+ if (sti == _weaks.end ())
+ return 0;
+ return (*sti).second;
+ }
+
+ size_t
+ table::size () const
+ {
+ return _externals.size () + _weaks.size ();
+ }
+
+ const symtab&
+ table::externals () const
+ {
+ return _externals;
+ }
+
+ const symtab&
+ table::weaks () const
+ {
+ return _weaks;
+ }
+
+ void
+ load (bucket& bucket_, table& table_)
+ {
+ for (bucket::iterator sbi = bucket_.begin ();
+ sbi != bucket_.end ();
+ ++sbi)
+ {
+ table_.add_external (*sbi);
+ }
+ }
+
+ void
+ load (bucket& bucket_, symtab& table_)
+ {
+ for (bucket::iterator sbi = bucket_.begin ();
+ sbi != bucket_.end ();
+ ++sbi)
+ {
+ symbol& sym = *sbi;
+ table_[sym.name ()] = &sym;
+ }
+ }
+
+ size_t
+ referenced (pointers& symbols)
+ {
+ size_t used = 0;
+ for (pointers::iterator sli = symbols.begin ();
+ sli != symbols.end ();
+ ++sli)
+ {
+ symbol& sym = *(*sli);
+ if (sym.references ())
+ ++used;
+ }
+
+ return used;
+ }
+
+ void
+ output (std::ostream& out, const table& symbols)
+ {
+ out << "Externals:" << std::endl;
+ output (out, symbols.externals ());
+ out << "Weaks:" << std::endl;
+ output (out, symbols.weaks ());
+ }
+
+ void
+ output (std::ostream& out, const symtab& symbols)
+ {
+ std::cout << " No. Scope Type Address Size Name" << std::endl;
+ int index = 0;
+ for (symtab::const_iterator si = symbols.begin ();
+ si != symbols.end ();
+ ++si)
+ {
+ const symbol& sym = *((*si).second);
+ out << std::setw (5) << index << ' ' << sym << std::endl;
+ ++index;
+ }
+ }
+
+ }
+}
diff --git a/linkers/rld-symbols.h b/linkers/rld-symbols.h
new file mode 100644
index 0000000..5405d2f
--- /dev/null
+++ b/linkers/rld-symbols.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker symbols manages the symbols from all the object files.
+ *
+ */
+
+#if !defined (_RLD_SYMBOLS_H_)
+#define _RLD_SYMBOLS_H_
+
+#include <iostream>
+#include <list>
+#include <map>
+#include <string>
+
+#include <rld-elf-types.h>
+
+namespace rld
+{
+ /**
+ * Forward declarations.
+ */
+ namespace files
+ {
+ class object;
+ }
+
+ namespace symbols
+ {
+ /**
+ * A symbol.
+ */
+ class symbol
+ {
+ public:
+ /**
+ * Default constructor. No symbol has been defined.
+ */
+ symbol ();
+
+ /**
+ * Construct an exported symbol with a object file.
+ */
+ symbol (int index,
+ const std::string& name,
+ files::object& object,
+ const elf::elf_sym& esym);
+
+ /**
+ * Construct a symbol with no object file and an ELF index.
+ */
+ symbol (int index, const std::string& name, const elf::elf_sym& esym);
+
+ /**
+ * Construct a linker symbol that is internally created.
+ */
+ symbol (const std::string& name,
+ const elf::elf_addr value = 0);
+
+ /**
+ * Construct a linker symbol that is internally created.
+ */
+ symbol (const char* name,
+ elf::elf_addr value = 0);
+
+ /**
+ * The symbol's index in the symtab section of the ELF file.
+ */
+ int index () const;
+
+ /**
+ * The symbol's name.
+ */
+ const std::string& name () const;
+
+ /**
+ * The symbol's demangled name.
+ */
+ const std::string& demangled () const;
+
+ /**
+ * Is the symbol a C++ name ?
+ */
+ bool is_cplusplus () const;
+
+ /**
+ * The symbol's type.
+ */
+ int type () const;
+
+ /**
+ * The symbol's binding, ie local, weak, or global.
+ */
+ int binding () const;
+
+ /**
+ * The symbol's section index.
+ */
+ int section_index () const;
+
+ /**
+ * The value of the symbol.
+ */
+ elf::elf_addr value () const;
+
+ /**
+ * The data of the symbol.
+ */
+ uint32_t info () const;
+
+ /**
+ * The symbol's object file name.
+ */
+ files::object* object () const;
+
+ /**
+ * Set the symbol's object file name. Used when resolving unresolved
+ * symbols.
+ */
+ void set_object (files::object& obj);
+
+ /**
+ * The ELF symbol.
+ */
+ const elf::elf_sym& esym () const;
+
+ /**
+ * Return the number of references.
+ */
+ int references () const {
+ return references_;
+ }
+
+ /**
+ * Return the number of references.
+ */
+ void referenced ();
+
+ /**
+ * Less than operator for the map container.
+ */
+ bool operator< (const symbol& rhs) const;
+
+ /**
+ * Output to the a stream.
+ */
+ void output (std::ostream& out) const;
+
+ private:
+
+ int index_; //< The symbol's index in the ELF file.
+ std::string name_; //< The name of the symbol.
+ std::string demangled_; //< If a C++ symbol the demangled name.
+ files::object* object_; //< The object file containing the symbol.
+ elf::elf_sym esym_; //< The ELF symbol.
+ int references_; //< The number of times if it referenced.
+ };
+
+ /**
+ * Container of symbols. A bucket of symbols.
+ */
+ typedef std::list < symbol > bucket;
+
+ /**
+ * References to symbols. Should always point to symbols held in a bucket.
+ */
+ typedef std::list < symbol* > pointers;
+
+ /**
+ * A symbols table is a map container of symbols. Should always point to
+ * symbols held in a bucket.
+ */
+ typedef std::map < std::string, symbol* > symtab;
+
+ /**
+ * A symbols contains a symbol table of externals and weak symbols.
+ */
+ class table
+ {
+ public:
+ /**
+ * Construct a table.
+ */
+ table ();
+
+ /**
+ * Destruct a table.
+ */
+ ~table ();
+
+ /**
+ * Add an external symbol.
+ */
+ void add_external (symbol& sym);
+
+ /**
+ * Add a weak symbol.
+ */
+ void add_weak (symbol& sym);
+
+ /**
+ * Find an external symbol.
+ */
+ symbol* find_external (const std::string& name);
+
+ /**
+ * Find an weak symbol.
+ */
+ symbol* find_weak (const std::string& name);
+
+ /**
+ * Return the size of the symbols loaded.
+ */
+ size_t size () const;
+
+ /**
+ * Return the externals symbol table.
+ */
+ const symtab& externals () const;
+
+ /**
+ * Return the weaks symbol table.
+ */
+ const symtab& weaks () const;
+
+ private:
+
+ /**
+ * Cannot copy a table.
+ */
+ table (const table& orig);
+
+ /**
+ * A table of external symbols.
+ */
+ symtab _externals;
+
+ /**
+ * A table of weak symbols.
+ */
+ symtab _weaks;
+ };
+
+ /**
+ * Load a table from a buckey.
+ */
+ void load (bucket& bucket_, table& table_);
+
+ /**
+ * Load a table from a buckey.
+ */
+ void load (bucket& bucket_, symtab& table_);
+
+ /**
+ * Given a container of symbols return how many are referenced.
+ */
+ size_t referenced (pointers& symbols);
+
+ /**
+ * Output the symbol table.
+ */
+ void output (std::ostream& out, const table& symbols);
+
+ /**
+ * Output the symbol table.
+ */
+ void output (std::ostream& out, const symtab& symbols);
+ }
+}
+
+/**
+ * Output stream operator.
+ */
+static inline std::ostream& operator<< (std::ostream& out,
+ const rld::symbols::symbol& sym) {
+ sym.output (out);
+ return out;
+}
+
+#endif
diff --git a/linkers/rld.cpp b/linkers/rld.cpp
new file mode 100644
index 0000000..997291d
--- /dev/null
+++ b/linkers/rld.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_ld
+ *
+ * @brief RTEMS Linker.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+
+#include <sys/stat.h>
+
+#include <rld.h>
+
+#define RLD_VERSION_MAJOR (1)
+#define RLD_VERSION_MINOR (0)
+#define RLD_VERSION_RELEASE (0)
+
+namespace rld
+{
+ static int verbose_level = 0;
+
+ /**
+ * The option container.
+ */
+ typedef std::vector < std::string > library_container;
+
+ /**
+ * The libraries the user provided on the command line.
+ */
+ static library_container libpaths;
+
+ /**
+ * The libraries pass on the command line.
+ */
+ static library_container libs;
+
+ /**
+ * The libraries.
+ */
+ static library_container libraries;
+
+ /**
+ * The output passed on the command line.
+ */
+ static std::string output;
+
+ void
+ verbose_inc ()
+ {
+ ++verbose_level;
+ }
+
+ int
+ verbose ()
+ {
+ return verbose_level;
+ }
+
+ const std::string
+ version ()
+ {
+ std::string v = (rld::to_string (RLD_VERSION_MAJOR) + '.' +
+ rld::to_string (RLD_VERSION_MINOR) + '.' +
+ rld::to_string (RLD_VERSION_RELEASE));
+ return v;
+ }
+
+ const std::string
+ rtems_version ()
+ {
+ return rld::to_string (RTEMS_VERSION);
+ }
+
+ void
+ split (const std::string& str, strings& strs, char separator)
+ {
+ if (str.size ())
+ {
+ std::string::size_type start = 0;
+ std::string::size_type end = 0;
+ while (start != std::string::npos)
+ {
+ end = str.find_first_of (separator, start);
+ if (end == std::string::npos)
+ end = str.size ();
+ strs.push_back (str.substr (start, end - start));
+ start = str.find_first_not_of (separator, end);
+ }
+ }
+ }
+
+ void
+ map (rld::files::cache& cache, rld::symbols::table& symbols)
+ {
+ std::cout << "Archive files : " << cache.archive_count () << std::endl;
+ std::cout << "Object files : " << cache.object_count () << std::endl;
+ std::cout << "Exported symbols : " << symbols.size () << std::endl;
+
+ std::cout << "Archives:" << std::endl;
+ cache.output_archive_files (std::cout);
+ std::cout << "Objects:" << std::endl;
+ cache.output_object_files (std::cout);
+
+ std::cout << "Exported symbols:" << std::endl;
+ rld::symbols::output (std::cout, symbols);
+ std::cout << "Unresolved symbols:" << std::endl;
+ cache.output_unresolved_symbols (std::cout);
+ }
+
+ void
+ warn_unused_externals (rld::files::object_list& objects)
+ {
+ bool first = true;
+ for (rld::files::object_list::iterator oli = objects.begin ();
+ oli != objects.end ();
+ ++oli)
+ {
+ rld::files::object& object = *(*oli);
+ rld::symbols::pointers& externals = object.external_symbols ();
+
+ if (rld::symbols::referenced (externals) != externals.size ())
+ {
+ if (first)
+ {
+ std::cout << "Unreferenced externals in object files:" << std::endl;
+ first = false;
+ }
+
+ std::cout << ' ' << object.name ().basename () << std::endl;
+
+ for (rld::symbols::pointers::iterator sli = externals.begin ();
+ sli != externals.end ();
+ ++sli)
+ {
+ rld::symbols::symbol& sym = *(*sli);
+ if (sym.references () == 0)
+ std::cout << " " << sym.name () << std::endl;
+ }
+ }
+ }
+ }
+
+}
diff --git a/linkers/rld.h b/linkers/rld.h
new file mode 100644
index 0000000..1f5e60b
--- /dev/null
+++ b/linkers/rld.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker readies the RTEMS object files for dynamic linking.
+ *
+ */
+
+#if !defined (_RLD_H_)
+#define _RLD_H_
+
+#include <algorithm>
+#include <cctype>
+#include <functional>
+#include <iostream>
+#include <locale>
+#include <sstream>
+#include <string>
+
+/**
+ * Path handling for Windows.
+ */
+#if __WIN32__
+#define RLD_PATH_SEPARATOR '\\'
+#define RLD_PATHSTR_SEPARATOR ';'
+#define RLD_PATHSTR_SEPARATOR_STR ";"
+#define RLD_DRIVE_SEPARATOR (1)
+#define RLD_LINE_SEPARATOR "\r\n"
+#else
+#define RLD_PATH_SEPARATOR '/'
+#define RLD_PATHSTR_SEPARATOR ':'
+#define RLD_PATHSTR_SEPARATOR_STR ":"
+#define RLD_DRIVE_SEPARATOR (0)
+#define RLD_LINE_SEPARATOR "\n"
+#endif
+
+namespace rld
+{
+ /**
+ * Forward declarations.
+ */
+ namespace files
+ {
+ class file;
+ class image;
+ class archive;
+ class object;
+ }
+}
+
+#include <rld-elf-types.h>
+#include <rld-symbols.h>
+#include <rld-elf.h>
+#include <rld-files.h>
+
+/**
+ * The debug levels.
+ */
+#define RLD_VERBOSE_OFF (0)
+#define RLD_VERBOSE_INFO (1)
+#define RLD_VERBOSE_DETAILS (2)
+#define RLD_VERBOSE_TRACE (3)
+#define RLD_VERBOSE_TRACE_SYMS (4)
+#define RLD_VERBOSE_TRACE_FILE (5)
+#define RLD_VERBOSE_FULL_DEBUG (6)
+
+namespace rld
+{
+ /**
+ * General error.
+ */
+ struct error
+ {
+ const std::string what;
+ const std::string where;
+
+ error (const std::ostringstream& what, const std::string& where) :
+ what (what.str ()), where (where) {
+ }
+
+ error (const std::string& what, const std::string& where) :
+ what (what), where (where) {
+ }
+ };
+
+ /**
+ * A convenience macro to make where a file and line number.
+ */
+ #define rld_error_at(_what) \
+ rld::error (_what, std::string (__FILE__) + ":" + to_string (__LINE__))
+
+ /**
+ * Convert a supported type to a string.
+ */
+ template <class T>
+ std::string to_string (T t, std::ios_base & (*f)(std::ios_base&) = std::dec)
+ {
+ std::ostringstream oss;
+ oss << f << t;
+ return oss.str();
+ }
+
+ /**
+ * A container of strings.
+ */
+ typedef std::vector < std::string > strings;
+
+ /**
+ * Trim from start.
+ */
+ inline std::string& ltrim (std::string &s)
+ {
+ s.erase (s.begin (),
+ std::find_if (s.begin (), s.end (),
+ std::not1 (std::ptr_fun < int, int > (std::isspace))));
+ return s;
+ }
+
+ /**
+ * Trim from end.
+ */
+ inline std::string& rtrim (std::string &s)
+ {
+ s.erase (std::find_if (s.rbegin (), s.rend (),
+ std::not1 (std::ptr_fun < int, int > (std::isspace))).base(),
+ s.end());
+ return s;
+ }
+
+ /**
+ * Trim from both ends.
+ */
+ inline std::string& trim (std::string &s)
+ {
+ return ltrim (rtrim (s));
+ }
+
+ /**
+ * Dequote a string.
+ */
+ inline std::string dequote (const std::string& s)
+ {
+ if (!s.empty ())
+ {
+ char front = s[0];
+ char back = s[s.length () - 1];
+ if ((front == '"') || (front == '\''))
+ {
+ if (front != back)
+ throw rld::error ("invalid quoting", "string: " + s);
+ return s.substr (1, s.length () - (1 + 1));
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Find and replace.
+ */
+ inline std::string find_replace(const std::string& sin,
+ const std::string& out,
+ const std::string& in)
+ {
+ std::string s = sin;
+ size_t pos = 0;
+ while ((pos = s.find (out, pos)) != std::string::npos)
+ {
+ s.replace (pos, out.length (), in);
+ pos += in.length ();
+ }
+ return s;
+ }
+
+ /**
+ * Split the string in a contain of strings based on the the
+ * delimiter. Optionally trim any white space or include empty string.
+ *
+ * @todo The split should optionally honour string quoting.
+ */
+ inline strings& split (strings& se,
+ const std::string& s,
+ char delimiter,
+ bool strip_quotes = true,
+ bool strip_whitespace = true,
+ bool empty = false)
+ {
+ std::stringstream ss(s);
+ std::string e;
+ se.clear ();
+ while (std::getline (ss, e, delimiter))
+ {
+ if (strip_whitespace)
+ trim (e);
+ if (strip_quotes)
+ e = dequote (e);
+ if (empty || !e.empty ())
+ {
+ se.push_back (e);
+ }
+ }
+ return se;
+ }
+
+ /**
+ * Join the strings together with the separator.
+ */
+ inline std::string join (const strings& ss,
+ const std::string& separator)
+ {
+ std::string s;
+ for (strings::const_iterator ssi = ss.begin ();
+ ssi != ss.end ();
+ ++ssi)
+ {
+ s += *ssi;
+ if ((ssi != ss.begin ()) && (ssi != ss.end ()))
+ s += separator;
+ }
+ return s;
+ }
+
+ /**
+ * Increment the verbose level.
+ */
+ void verbose_inc ();
+
+ /**
+ * Return the verbose level. Setting the flag more than once raises the
+ * level.
+ */
+ int verbose ();
+
+ /**
+ * The version string.
+ */
+ const std::string version ();
+
+ /**
+ * The RTEMS version string.
+ */
+ const std::string rtems_version ();
+
+ /**
+ * Container of strings to hold the results of a split.
+ */
+ typedef std::vector < std::string > strings;
+
+ /**
+ * Split a string into strings by the separator.
+ */
+ void split (const std::string& str, strings& strs, char separator);
+
+ /**
+ * Map of the symbol table.
+ */
+ void map (rld::files::cache& cache, rld::symbols::table& symbols);
+
+ /**
+ * Warn is externals in referenced object files are not used.
+ */
+ void warn_unused_externals (rld::files::object_list& objects);
+}
+
+#endif
diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp
new file mode 100644
index 0000000..944afc3
--- /dev/null
+++ b/linkers/rtems-ld.cpp
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rld
+ *
+ * @brief RTEMS Linker Main manages opions, sequence of operations and exceptions.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+
+#include <cxxabi.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <getopt.h>
+
+#include <rld.h>
+#include <rld-cc.h>
+#include <rld-rap.h>
+#include <rld-outputter.h>
+#include <rld-process.h>
+#include <rld-resolver.h>
+
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
+
+/**
+ * RTEMS Linker options. This needs to be rewritten to be like cc where only a
+ * single '-' and long options is present.
+ */
+static struct option rld_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "warn", no_argument, NULL, 'w' },
+ { "map", no_argument, NULL, 'M' },
+ { "output", required_argument, NULL, 'o' },
+ { "out-format", required_argument, NULL, 'O' },
+ { "lib-path", required_argument, NULL, 'L' },
+ { "lib", required_argument, NULL, 'l' },
+ { "no-stdlibs", no_argument, NULL, 'n' },
+ { "entry", required_argument, NULL, 'e' },
+ { "define", required_argument, NULL, 'd' },
+ { "undefined", required_argument, NULL, 'u' },
+ { "base", required_argument, NULL, 'b' },
+ { "cc", required_argument, NULL, 'C' },
+ { "exec-prefix", required_argument, NULL, 'E' },
+ { "march", required_argument, NULL, 'a' },
+ { "mcpu", required_argument, NULL, 'c' },
+ { "rap-strip", no_argument, NULL, 'S' },
+ { "rpath", required_argument, NULL, 'R' },
+ { "runtime-lib", required_argument, NULL, 'P' },
+ { "one-file", no_argument, NULL, 's' },
+ { NULL, 0, NULL, 0 }
+};
+
+#if TO_BE_USED_FOR_THE_UNDEFINES
+void
+split_on_equals (const std::string& opt, std::string& left, std::string& right)
+{
+ std::string::size_type eq = opt.find_first_of('=');
+}
+#endif
+
+void
+usage (int exit_code)
+{
+ std::cout << "rtems-ld [options] objects" << std::endl
+ << "Options and arguments:" << std::endl
+ << " -h : help (also --help)" << std::endl
+ << " -V : print linker version number and exit (also --version)" << std::endl
+ << " -v : verbose (trace import parts), can supply multiple times" << std::endl
+ << " to increase verbosity (also --verbose)" << std::endl
+ << " -w : generate warnings (also --warn)" << std::endl
+ << " -M : generate map output (also --map)" << std::endl
+ << " -o file : linker output is written to file (also --output)" << std::endl
+ << " -O format : linker output format, default is 'rap' (also --out-format)" << std::endl
+ << " -L path : path to a library, add multiple for more than" << std::endl
+ << " one path (also --lib-path)" << std::endl
+ << " -l lib : add lib to the libraries searched, add multiple" << std::endl
+ << " for more than one library (also --lib)" << std::endl
+ << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl
+ << " -e entry : entry point symbol (also --entry)" << std::endl
+ << " -d sym : add the symbol definition, add multiple with" << std::endl
+ << " more than one define (also --define)" << std::endl
+ << " -u sym : add the undefined symbol definition, add multiple" << std::endl
+ << " for more than one undefined symbol (also --undefined)" << std::endl
+ << " -b elf : read the ELF file symbols as the base RTEMS kernel" << std::endl
+ << " image (also --base)" << std::endl
+ << " -C file : execute file as the target C compiler (also --cc)" << std::endl
+ << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
+ << " -a march : machine architecture (also --march)" << std::endl
+ << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl
+ << " -S : do not include file details (also --rap-strip)" << std::endl
+ << " -R : include file paths (also --rpath)" << std::endl
+ << " -P : place objects from archives (also --runtime-lib)" << std::endl
+ << " -s : Include archive elf object files (also --one-file)" << std::endl
+ << " -Wl,opts : link compatible flags, ignored" << std::endl
+ << "Output Formats:" << std::endl
+ << " rap - RTEMS application (LZ77, single image)" << std::endl
+ << " elf - ELF application (script, ELF files)" << std::endl
+ << " script - Script format (list of object files)" << std::endl
+ << " archive - Archive format (collection of ELF files)" << std::endl;
+ ::exit (exit_code);
+}
+
+static void
+fatal_signal (int signum)
+{
+ signal (signum, SIG_DFL);
+
+ rld::process::temporaries_clean_up ();
+
+ /*
+ * Get the same signal again, this time not handled, so its normal effect
+ * occurs.
+ */
+ kill (getpid (), signum);
+}
+
+static void
+setup_signals (void)
+{
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_signal);
+#ifdef SIGHUP
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_signal);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_signal);
+#ifdef SIGPIPE
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, fatal_signal);
+#endif
+#ifdef SIGCHLD
+ signal (SIGCHLD, SIG_DFL);
+#endif
+}
+
+int
+main (int argc, char* argv[])
+{
+ int ec = 0;
+
+ setup_signals ();
+
+ try
+ {
+ rld::files::cache cache;
+ rld::files::cache base;
+ rld::files::cache cachera;
+ rld::files::paths libpaths;
+ rld::files::paths libs;
+ rld::files::paths objects;
+ rld::files::paths libraries;
+ rld::symbols::bucket defines;
+ rld::symbols::bucket undefines;
+ rld::symbols::table base_symbols;
+ rld::symbols::table symbols;
+ rld::symbols::symtab undefined;
+ std::string entry = "rtems";
+ std::string exit;
+ std::string output = "a.out";
+ std::string outra;
+ std::string base_name;
+ std::string cc_name;
+ std::string output_type = "rap";
+ bool standard_libs = true;
+ bool exec_prefix_set = false;
+ bool map = false;
+ bool warnings = false;
+ bool one_file = false;
+
+ libpaths.push_back (".");
+
+ while (true)
+ {
+ int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:W:R:P", rld_opts, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt)
+ {
+ case 'V':
+ std::cout << "rtems-ld (RTEMS Linker) " << rld::version ()
+ << std::endl;
+ ::exit (0);
+ break;
+
+ case 'v':
+ rld::verbose_inc ();
+ break;
+
+ case 'M':
+ map = true;
+ break;
+
+ case 'w':
+ warnings = true;
+ break;
+
+ case 'o':
+ if (output != "a.out")
+ std::cerr << "warning: output already set" << std::endl;
+ output = optarg;
+ break;
+
+ case 'O':
+ output_type = optarg;
+ break;
+
+ case 'l':
+ /*
+ * The order is important. It is the search order.
+ */
+ libs.push_back (optarg);
+ break;
+
+ case 'P':
+ if (!outra.empty ())
+ std::cerr << "warning: output ra alreay set" << std::endl;
+ outra = "lib";
+ outra += optarg;
+ outra += ".ra";
+ break;
+
+ case 's':
+ one_file = true;
+ break;
+
+ case 'L':
+ if ((optarg[::strlen (optarg) - 1] == '/') ||
+ (optarg[::strlen (optarg) - 1] == '\\'))
+ optarg[::strlen (optarg) - 1] = '\0';
+ libpaths.push_back (optarg);
+ break;
+
+ case 'n':
+ standard_libs = false;
+ break;
+
+ case 'C':
+ if (exec_prefix_set == true)
+ std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
+ rld::cc::cc = optarg;
+ break;
+
+ case 'E':
+ exec_prefix_set = true;
+ rld::cc::exec_prefix = optarg;
+ break;
+
+ case 'a':
+ rld::cc::march = optarg;
+ break;
+
+ case 'c':
+ rld::cc::mcpu = optarg;
+ break;
+
+ case 'e':
+ entry = optarg;
+ break;
+
+ case 'd':
+ defines.push_back (rld::symbols::symbol (optarg));
+ break;
+
+ case 'u':
+ undefines.push_back (rld::symbols::symbol (optarg));
+ break;
+
+ case 'b':
+ base_name = optarg;
+ break;
+
+ case 'S':
+ rld::rap::add_obj_details = false;
+ break;
+
+ case 'R':
+ rld::rap::rpath += optarg;
+ rld::rap::rpath += '\0';
+ break;
+
+ case 'W':
+ /* ignore linker compatiable flags */
+ break;
+
+ case '?':
+ usage (3);
+ break;
+
+ case 'h':
+ usage (0);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (rld::verbose () || map)
+ std::cout << "RTEMS Linker " << rld::version () << std::endl;
+
+ /*
+ * If there are no object files there is nothing to link.
+ */
+ if ((argc == 0) && !map)
+ throw rld::error ("no object files", "options");
+
+ /*
+ * Check the output format is valid.
+ */
+ if ((output_type != "rap") &&
+ (output_type != "elf") &&
+ (output_type != "script") &&
+ (output_type != "archive"))
+ throw rld::error ("invalid output format", "options");
+
+ /*
+ * Load the remaining command line arguments into the cache as object
+ * files.
+ */
+ while (argc--)
+ objects.push_back (*argv++);
+
+ /*
+ * The 'entry' point symbol needs to be added to the undefines so it is
+ * resolved.
+ */
+ undefines.push_back (rld::symbols::symbol (entry));
+
+ /*
+ * Load the symbol table with the defined symbols from the defines bucket.
+ */
+ rld::symbols::load (defines, symbols);
+
+ /*
+ * Load the undefined table with the undefined symbols from the undefines
+ * bucket.
+ */
+ rld::symbols::load (undefines, undefined);
+
+ /*
+ * Add the object files to the cache.
+ */
+ cache.add (objects);
+
+ /*
+ * Open the cache.
+ */
+ cache.open ();
+
+ /*
+ * If the full path to CC is not provided and the exec-prefix is not set by
+ * the command line see if it can be detected from the object file
+ * types. This must be after we have added the object files because they
+ * are used when detecting.
+ */
+ if (rld::cc::cc.empty () && !exec_prefix_set)
+ rld::cc::exec_prefix = rld::elf::machine_type ();
+
+ /*
+ * If we have a base image add it.
+ */
+ if (base_name.length ())
+ {
+ if (rld::verbose ())
+ std::cout << "base-image: " << base_name << std::endl;
+ base.open ();
+ base.add (base_name);
+ base.load_symbols (base_symbols, true);
+ }
+
+ /*
+ * Get the standard library paths
+ */
+ if (standard_libs)
+ rld::cc::get_standard_libpaths (libpaths);
+
+ /*
+ * Get the command line libraries.
+ */
+ rld::files::find_libraries (libraries, libpaths, libs);
+
+ /*
+ * Are we to load standard libraries ?
+ */
+ if (standard_libs)
+ rld::cc::get_standard_libs (libraries, libpaths);
+
+ /*
+ * Load the library to the cache.
+ */
+ cache.add_libraries (libraries);
+
+ /*
+ * Begin the archive session. This opens the archives and leaves them open
+ * while we the symbol table is being used. The symbols reference object
+ * files and the object files may reference archives and it is assumed they
+ * are open and available. It is also assumed the number of library
+ * archives being managed is less than the maximum file handles this
+ * process can have open at any one time. If this is not the case this
+ * approach would need to be reconsidered and the overhead of opening and
+ * closing archives added.
+ */
+ try
+ {
+ cache.archives_begin ();
+
+ /*
+ * Load the symbol table.
+ */
+ cache.load_symbols (symbols);
+
+ /*
+ * Map ?
+ */
+ if (map)
+ {
+ if (base_name.length ())
+ rld::map (base, base_symbols);
+ rld::map (cache, symbols);
+ }
+
+ if (cache.path_count ())
+ {
+ /*
+ * This structure allows us to add different operations with the same
+ * structure.
+ */
+ rld::files::object_list dependents;
+ rld::resolver::resolve (dependents, cache,
+ base_symbols, symbols, undefined);
+
+ /**
+ * Output the file.
+ */
+ if (output_type == "script")
+ rld::outputter::script (output, entry, exit, dependents, cache);
+ else if (output_type == "archive")
+ rld::outputter::archive (output, entry, exit, dependents, cache);
+ else if (output_type == "elf")
+ rld::outputter::elf_application (output, entry, exit,
+ dependents, cache);
+ else if (output_type == "rap")
+ {
+ rld::outputter::application (output, entry, exit,
+ dependents, cache, symbols,
+ one_file);
+ if (!outra.empty ())
+ {
+ rld::files::paths ra_libs;
+ bool ra_exist = false;
+
+ /**
+ * If exist, search it, else create a new one.
+ */
+ if ((ra_exist = ::access (outra.c_str (), 0)) == 0)
+ {
+ ra_libs.push_back (outra);
+ cachera.open ();
+ cachera.add_libraries (ra_libs);
+ cachera.archives_begin ();
+ }
+
+ rld::outputter::archivera (outra, dependents, cachera,
+ !ra_exist, false);
+ }
+ }
+ else
+ throw rld::error ("invalid output type", "output");
+
+ /**
+ * Check for warnings.
+ */
+ if (warnings)
+ {
+ rld::warn_unused_externals (dependents);
+ }
+ }
+ }
+ catch (...)
+ {
+ cache.archives_end ();
+ throw;
+ }
+
+ cache.archives_end ();
+ }
+ catch (rld::error re)
+ {
+ std::cerr << "error: "
+ << re.where << ": " << re.what
+ << std::endl;
+ ec = 10;
+ }
+ catch (std::exception e)
+ {
+ int status;
+ char* realname;
+ realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
+ std::cerr << "error: exception: " << realname << " [";
+ ::free (realname);
+ const std::type_info &ti = typeid (e);
+ realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
+ std::cerr << realname << "] " << e.what () << std::endl << std::flush;
+ ::free (realname);
+ ec = 11;
+ }
+ catch (...)
+ {
+ /*
+ * Helps to know if this happens.
+ */
+ std::cerr << "error: unhandled exception" << std::endl;
+ ec = 12;
+ }
+
+ return ec;
+}
diff --git a/linkers/rtems-ra.cpp b/linkers/rtems-ra.cpp
new file mode 100644
index 0000000..0900ccc
--- /dev/null
+++ b/linkers/rtems-ra.cpp
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rld
+ *
+ * @brief RTEMS RA Linker Main manages opions, sequence of operations and exceptions.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+
+#include <cxxabi.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <getopt.h>
+
+#include <rld.h>
+#include <rld-cc.h>
+#include <rld-rap.h>
+#include <rld-outputter.h>
+#include <rld-process.h>
+#include <rld-resolver.h>
+
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
+
+/**
+ * RTEMS Linker options. This needs to be rewritten to be like cc where only a
+ * single '-' and long options is present.
+ */
+static struct option rld_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "output-path", required_argument, NULL, 'p' },
+ { "output", required_argument, NULL, 'o' },
+ { "lib-path", required_argument, NULL, 'L' },
+ { "lib", required_argument, NULL, 'l' },
+ { "no-stdlibs", no_argument, NULL, 'n' },
+ { "cc", required_argument, NULL, 'C' },
+ { "exec-prefix", required_argument, NULL, 'E' },
+ { "march", required_argument, NULL, 'a' },
+ { "mcpu", required_argument, NULL, 'c' },
+ { "rap-strip", no_argument, NULL, 'S' },
+ { "rpath", required_argument, NULL, 'R' },
+ { "add-rap", required_argument, NULL, 'A' },
+ { "replace-rap", required_argument, NULL, 'r' },
+ { "delete-rap", required_argument, NULL, 'd' },
+ { NULL, 0, NULL, 0 }
+};
+
+#if TO_BE_USED_FOR_THE_UNDEFINES
+void
+split_on_equals (const std::string& opt, std::string& left, std::string& right)
+{
+ std::string::size_type eq = opt.find_first_of('=');
+}
+#endif
+
+void
+usage (int exit_code)
+{
+ std::cout << "rtems-ra [options] objects" << std::endl
+ << "Options and arguments:" << std::endl
+ << " -h : help (also --help)" << std::endl
+ << " -V : print linker version number and exit (also --version)" << std::endl
+ << " -v : verbose (trace import parts), can supply multiple times" << std::endl
+ << " to increase verbosity (also --verbose)" << std::endl
+ << " -o name : linker output, this options is just" << std::endl
+ << " for waf, it will not output to file (also --output)" << std::endl
+ << " -p path : output path (also --output-path)" << std::endl
+ << " -L path : path to a library, add multiple for more than" << std::endl
+ << " one path (also --lib-path)" << std::endl
+ << " -l lib : add lib to the libraries searched, add multiple" << std::endl
+ << " for more than one library (also --lib)" << std::endl
+ << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl
+ << " -C file : execute file as the target C compiler (also --cc)" << std::endl
+ << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
+ << " -a march : machine architecture (also --march)" << std::endl
+ << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl
+ << " -S : do not include file details (also --rap-strip)" << std::endl
+ << " -R : include file paths (also --rpath)" << std::endl
+ << " -A : Add rap files (also --Add-rap)" << std::endl
+ << " -r : replace rap files (also --replace-rap)" << std::endl
+ << " -d : delete rap files (also --delete-rap)" << std::endl
+ << " -Wl,opts : link compatible flags, ignored" << std::endl
+ << "Output Formats:" << std::endl
+ << " ra - RTEMS archive container of rap files" << std::endl;
+ ::exit (exit_code);
+}
+
+static void
+fatal_signal (int signum)
+{
+ signal (signum, SIG_DFL);
+
+ rld::process::temporaries_clean_up ();
+
+ /*
+ * Get the same signal again, this time not handled, so its normal effect
+ * occurs.
+ */
+ kill (getpid (), signum);
+}
+
+static void
+setup_signals (void)
+{
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_signal);
+#ifdef SIGHUP
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_signal);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_signal);
+#ifdef SIGPIPE
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, fatal_signal);
+#endif
+#ifdef SIGCHLD
+ signal (SIGCHLD, SIG_DFL);
+#endif
+}
+
+int
+main (int argc, char* argv[])
+{
+ int ec = 0;
+
+ setup_signals ();
+
+ try
+ {
+ rld::files::paths libpaths;
+ rld::files::paths libs;
+ rld::files::paths libraries;
+ rld::files::paths outra;
+ rld::files::paths raps_add;
+ rld::files::paths raps_replace;
+ rld::files::paths raps_delete;
+ std::string cc_name;
+ std::string entry;
+ std::string exit;
+ std::string output_path = "./";
+ std::string output = "a.ra";
+ bool standard_libs = true;
+ bool exec_prefix_set = false;
+ bool convert = true;
+ rld::files::object_list dependents;
+
+ libpaths.push_back (".");
+ dependents.clear ();
+
+ while (true)
+ {
+ int opt = ::getopt_long (argc, argv, "hVvnS:a:p:L:l:o:C:E:c:R:W:A:r:d", rld_opts, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt)
+ {
+ case 'V':
+ std::cout << "rtems-ra (RTEMS Linker) " << rld::version ()
+ << std::endl;
+ ::exit (0);
+ break;
+
+ case 'v':
+ rld::verbose_inc ();
+ break;
+
+ case 'l':
+ libs.push_back (optarg);
+ break;
+
+ case 'A':
+ /*
+ * Add rap files to ra file.
+ */
+ raps_add.push_back (optarg);
+ convert = false;
+ break;
+
+ case 'r':
+ /*
+ * replace rap files to ra file.
+ */
+ raps_replace.push_back (optarg);
+ convert = false;
+ break;
+
+ case 'd':
+ /*
+ * delete rap files to ra file.
+ */
+ raps_delete.push_back (optarg);
+ convert = false;
+ break;
+
+ case 'L':
+ if ((optarg[::strlen (optarg) - 1] == '/') ||
+ (optarg[::strlen (optarg) - 1] == '\\'))
+ optarg[::strlen (optarg) - 1] = '\0';
+ libpaths.push_back (optarg);
+ break;
+
+ case 'n':
+ standard_libs = false;
+ break;
+
+ case 'p':
+ std::cout << "Output path: " << optarg << std::endl;
+ output_path = optarg;
+ break;
+
+ case 'o':
+ output = optarg;
+ break;
+
+ case 'C':
+ if (exec_prefix_set == true)
+ std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
+ rld::cc::cc = optarg;
+ break;
+
+ case 'E':
+ exec_prefix_set = true;
+ rld::cc::exec_prefix = optarg;
+ break;
+
+ case 'a':
+ rld::cc::march = optarg;
+ break;
+
+ case 'c':
+ rld::cc::mcpu = optarg;
+ break;
+
+ case 'S':
+ rld::rap::add_obj_details = false;
+ break;
+
+ case 'R':
+ rld::rap::rpath += optarg;
+ rld::rap::rpath += '\0';
+ break;
+
+ case 'W':
+ /* ignore linker compatiable flags */
+ break;
+
+ case '?':
+ usage (3);
+ break;
+
+ case 'h':
+ usage (0);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (rld::verbose ())
+ std::cout << "RTEMS RAP RA Linker " << rld::version () << std::endl;
+
+ /*
+ * libs can be elf archive and rap archive
+ */
+ while (argc--)
+ libs.push_back (*argv++);
+
+ /*
+ * If the full path to CC is not provided and the exec-prefix is not set by
+ * the command line see if it can be detected from the object file
+ * types. This must be after we have added the object files because they
+ * are used when detecting.
+ */
+ if (rld::cc::cc.empty () && !exec_prefix_set)
+ rld::cc::exec_prefix = rld::elf::machine_type ();
+
+ if (convert)
+ {
+ /*
+ * Get the standard library paths
+ */
+ if (standard_libs)
+ rld::cc::get_standard_libpaths (libpaths);
+ /*
+ * Get the command line libraries.
+ */
+ rld::files::find_libraries (libraries, libpaths, libs);
+
+ /*
+ * Are we to load standard libraries ?
+ */
+ if (standard_libs)
+ rld::cc::get_standard_libs (libraries, libpaths);
+
+ /*
+ * Convert ar file to ra file
+ */
+ for (rld::files::paths::iterator p = libraries.begin (); p != libraries.end (); ++p)
+ {
+ rld::files::paths library;
+ rld::symbols::table symbols;
+ rld::files::cache* cache = new rld::files::cache ();
+
+ library.clear ();
+ library.push_back (*p);
+
+ /*
+ * Open the cache.
+ */
+ cache->open ();
+
+ /*
+ * Load the library to the cache.
+ */
+ cache->add_libraries (library);
+
+ cache->load_symbols (symbols);
+
+ try
+ {
+
+ rld::files::objects& objs = cache->get_objects ();
+ rld::files::paths raobjects;
+
+ int pos = -1;
+ std::string rap_name;
+ for (rld::files::objects::iterator obi = objs.begin ();
+ obi != objs.end ();
+ ++obi)
+ {
+ rld::files::object* obj = (*obi).second;
+
+ dependents.clear ();
+
+ rap_name = obj->name ().oname ();
+
+ pos = obj->name ().oname ().rfind ('.', rap_name.length ());
+ if (pos != -1)
+ {
+ rap_name.erase (pos, rap_name.length ());
+ }
+
+ rap_name += ".rap";
+
+ dependents.push_back (obj);
+
+ raobjects.push_back (rap_name);
+
+ /* Todo: include absolute name for rap_name */
+
+ rld::outputter::application (rap_name, entry, exit,
+ dependents, *cache, symbols,
+ true);
+ }
+
+ dependents.clear ();
+ for (rld::files::paths::iterator ni = raobjects.begin (); ni != raobjects.end (); ++ni)
+ {
+ rld::files::object* obj = new rld::files::object (*ni);
+ dependents.push_back (obj);
+ }
+
+ bool ra_rap = true;
+ bool ra_exist = false;
+ rld::files::cache cachera;
+ std::string raname = *p;
+
+ pos = -1;
+ pos = raname.rfind ('/', raname.length ());
+ if (pos != -1)
+ {
+ raname.erase (0, pos);
+ }
+
+ pos = -1;
+ pos = raname.rfind ('.', raname.length ());
+ if (pos != -1)
+ {
+ raname.erase (pos, raname.length ());
+ }
+ raname += ".ra";
+
+ raname = output_path + raname;
+
+ rld::outputter::archivera (raname, dependents, cachera,
+ ra_exist, ra_rap);
+ std::cout << "Generated: " << raname << std::endl;
+
+
+ for (rld::files::object_list::iterator oi = dependents.begin ();
+ oi != dependents.end ();
+ ++oi)
+ {
+ rld::files::object& obj = *(*oi);
+ ::unlink (obj.name ().oname ().c_str ());
+ }
+ }
+ catch (...)
+ {
+ cache->archives_end ();
+ throw;
+ }
+
+ cache->archives_end ();
+ delete cache;
+ }
+ }
+ else
+ {
+ /*
+ * Add, replace, delete files from the ra file.
+ */
+ for (rld::files::paths::iterator pl = libs.begin (); pl != libs.end (); ++pl)
+ {
+ rld::files::paths library;
+ rld::files::cache* cache = new rld::files::cache ();
+
+ library.clear ();
+ library.push_back (*pl);
+
+ /*
+ * Open the cache.
+ */
+ cache->open ();
+
+ /*
+ * Load the library to the cache.
+ */
+ cache->add_libraries (library);
+
+ rld::files::objects& objs = cache->get_objects ();
+ rld::files::paths raobjects;
+
+ std::string rap_name;
+ bool rap_delete = false;
+
+ dependents.clear ();
+ /*
+ * Delete rap files in ra file.
+ */
+ for (rld::files::objects::iterator obi = objs.begin ();
+ obi != objs.end ();
+ ++obi)
+ {
+ rld::files::object* obj = (*obi).second;
+
+ rap_name = obj->name ().oname ();
+ rap_delete = false;
+
+ for (rld::files::paths::iterator pa = raps_delete.begin ();
+ pa != raps_delete.end ();
+ ++pa)
+ {
+ if (*pa == rap_name)
+ {
+ rap_delete = true;
+ break;
+ }
+ }
+
+ if (!rap_delete)
+ dependents.push_back (obj);
+ }
+
+ /*
+ * Add rap files into ra file, add supports replace.
+ */
+ bool rap_exist = false;
+ rld::files::paths rap_objects;
+ for (rld::files::paths::iterator pa = raps_add.begin ();
+ pa != raps_add.end ();
+ ++pa)
+ {
+ rap_exist = false;
+
+ for (rld::files::object_list::iterator oi = dependents.begin ();
+ oi != dependents.end ();
+ ++oi)
+ {
+ rld::files::object& obj = *(*oi);
+ if (*pa == obj.name ().oname ())
+ {
+ rap_exist = true;
+ raps_replace.push_back (*pa);
+ break;
+ }
+ }
+
+ if (!rap_exist)
+ rap_objects.push_back (*pa);
+ }
+
+ for (rld::files::paths::iterator pa = rap_objects.begin ();
+ pa != rap_objects.end ();
+ ++pa)
+ {
+ rld::files::object* obj = new rld::files::object (*pa);
+ if (!obj->name ().exists ())
+ {
+ delete obj;
+ throw rld::error ("file not exist", "rap-add");
+ }
+ else dependents.push_back (obj);
+ }
+
+ /*
+ * Replace rap files in ra file
+ */
+ bool rap_replace = false;
+ rld::files::cache cachera;
+
+ rap_objects.clear ();
+ cachera.open ();
+
+ for (rld::files::paths::iterator pa = raps_replace.begin ();
+ pa != raps_replace.end ();
+ ++pa)
+ {
+ rap_replace = false;
+
+ for (rld::files::object_list::iterator oi = dependents.begin ();
+ oi != dependents.end ();
+ )
+ {
+ rld::files::object& obj = *(*oi);
+ if (*pa == obj.name ().oname ())
+ {
+ rap_replace = true;
+ dependents.erase (oi++);
+ break;
+ }
+ ++oi;
+ }
+
+ if (rap_replace)
+ rap_objects.push_back (*pa);
+ }
+
+ for (rld::files::paths::iterator pa = rap_objects.begin ();
+ pa != rap_objects.end ();
+ ++pa)
+ {
+ rld::files::object* obj = new rld::files::object (*pa);
+ if (!obj->name ().exists ())
+ {
+ delete obj;
+ throw rld::error ("file not exist", "rap-add");
+ }
+ else dependents.push_back (obj);
+ }
+
+ rld::outputter::archivera (*pl, dependents, cachera,
+ true, true);
+ std::cout << "End" << std::endl;
+
+ cache->archives_end ();
+ delete cache;
+ }
+ }
+ }
+ catch (rld::error re)
+ {
+ std::cerr << "error: "
+ << re.where << ": " << re.what
+ << std::endl;
+ ec = 10;
+ }
+ catch (std::exception e)
+ {
+ int status;
+ char* realname;
+ realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
+ std::cerr << "error: exception: " << realname << " [";
+ ::free (realname);
+ const std::type_info &ti = typeid (e);
+ realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
+ std::cerr << realname << "] " << e.what () << std::endl << std::flush;
+ ::free (realname);
+ ec = 11;
+ }
+ catch (...)
+ {
+ /*
+ * Helps to know if this happens.
+ */
+ std::cerr << "error: unhandled exception" << std::endl;
+ ec = 12;
+ }
+
+ return ec;
+}
diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp
new file mode 100644
index 0000000..2e3d2cf
--- /dev/null
+++ b/linkers/rtems-rapper.cpp
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rld
+ *
+ * @brief RTEMS RAP Manager lets you look at and play with RAP files.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <vector>
+
+#include <cxxabi.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <getopt.h>
+
+#include <rld.h>
+#include <rld-compression.h>
+#include <rld-files.h>
+#include <rld-process.h>
+#include <rld-rap.h>
+
+#include <rtems-utils.h>
+
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
+
+/**
+ * RTEMS Application.
+ */
+namespace rap
+{
+ /**
+ * The names of the RAP sections.
+ */
+ static const char* section_names[6] =
+ {
+ ".text",
+ ".const",
+ ".ctor",
+ ".dtor",
+ ".data",
+ ".bss"
+ };
+
+ /**
+ * A relocation record.
+ */
+ struct relocation
+ {
+ uint32_t info;
+ uint32_t offset;
+ uint32_t addend;
+ std::string symname;
+ off_t rap_off;
+
+ relocation ();
+
+ void output ();
+ };
+
+ typedef std::vector < relocation > relocations;
+
+ /**
+ * Relocation offset sorter for the relocations container.
+ */
+ class reloc_offset_compare
+ {
+ public:
+ bool operator () (const relocation& lhs,
+ const relocation& rhs) const {
+ return lhs.offset < rhs.offset;
+ }
+ };
+
+ /**
+ * A RAP section.
+ */
+ struct section
+ {
+ std::string name;
+ uint32_t size;
+ uint32_t alignment;
+ uint8_t* data;
+ uint32_t relocs_size;
+ relocations relocs;
+ bool rela;
+ off_t rap_off;
+
+ section ();
+ ~section ();
+
+ void load_data (rld::compress::compressor& comp);
+ void load_relocs (rld::compress::compressor& comp);
+ };
+
+ /**
+ * Section detail
+ */
+ struct section_detail
+ {
+ uint32_t name; //< The offset in the strtable.
+ uint32_t offset; //< The offset in the rap section.
+ uint32_t id; //< The rap id.
+ uint32_t size; //< The size of the elf section.
+ uint32_t obj; //< The obj id.
+
+ /* Constructor */
+ section_detail (const section_detail& s);
+ section_detail ();
+ };
+
+ section_detail::section_detail (const section_detail& s)
+ : name (s.name),
+ offset (s.offset),
+ id (s.id),
+ size (s.size),
+ obj (s.obj)
+ {
+ }
+
+ section_detail::section_detail ()
+ : name (0),
+ offset (0),
+ id (0),
+ size (0),
+ obj (0)
+ {
+ }
+
+ /**
+ * A container of section_detail
+ */
+ typedef std::list < section_detail > section_details;
+
+ /**
+ * A RAP file.
+ */
+ struct file
+ {
+ enum {
+ rap_comp_buffer = 2 * 1024
+ };
+
+ std::string header;
+ size_t rhdr_len;
+ uint32_t rhdr_length;
+ uint32_t rhdr_version;
+ std::string rhdr_compression;
+ uint32_t rhdr_checksum;
+
+ off_t machine_rap_off;
+ uint32_t machinetype;
+ uint32_t datatype;
+ uint32_t class_;
+
+ off_t layout_rap_off;
+ std::string init;
+ uint32_t init_off;
+ std::string fini;
+ uint32_t fini_off;
+
+ off_t strtab_rap_off;
+ uint32_t strtab_size;
+ uint8_t* strtab;
+
+ off_t symtab_rap_off;
+ uint32_t symtab_size;
+ uint8_t* symtab;
+
+ off_t relocs_rap_off;
+ uint32_t relocs_size; /* not used */
+
+ off_t detail_rap_off;
+ uint32_t obj_num;
+ uint8_t** obj_name;
+ uint32_t* sec_num;
+ uint8_t* rpath;
+ uint32_t rpathlen;
+ uint8_t* str_detail;
+ section_details sec_details;
+
+ section secs[rld::rap::rap_secs];
+
+ /**
+ * Open a RAP file and read the header.
+ */
+ file (const std::string& name, bool warnings);
+
+ /**
+ * Close the RAP file.
+ */
+ ~file ();
+
+ /**
+ * Parse header.
+ */
+ void parse_header ();
+
+ /**
+ * Load the file.
+ */
+ void load ();
+
+ /**
+ * Expand the image.
+ */
+ void expand ();
+
+ /**
+ * Load details.
+ */
+ void load_details(rld::compress::compressor& comp);
+
+ /**
+ * The name.
+ */
+ const std::string name () const;
+
+ /**
+ * The number of symbols in the symbol table.
+ */
+ int symbols () const;
+
+ /**
+ * Return a symbol given an index.
+ */
+ void symbol (int index,
+ uint32_t& data,
+ uint32_t& name,
+ uint32_t& value) const;
+
+ /**
+ * Return the string from the string table.
+ */
+ const char* string (int index);
+
+ private:
+
+ bool warnings;
+ rld::files::image image;
+ };
+
+ template < typename T > T
+ get_value (const uint8_t* data)
+ {
+ T v = 0;
+ for (size_t b = 0; b < sizeof (T); ++b)
+ {
+ v <<= 8;
+ v |= (T) data[b];
+ }
+ return v;
+ }
+
+ relocation::relocation ()
+ : info (0),
+ offset (0),
+ addend (0),
+ rap_off (0)
+ {
+ }
+
+ void
+ relocation::output ()
+ {
+ std::cout << std::hex << std::setfill ('0')
+ << "0x" << std::setw (8) << info
+ << " 0x" << std::setw (8) << offset
+ << " 0x" << std::setw(8) << addend
+ << std::dec << std::setfill (' ')
+ << " " << symname;
+ }
+
+ section::section ()
+ : size (0),
+ alignment (0),
+ data (0),
+ relocs_size (0),
+ relocs (0),
+ rela (false),
+ rap_off (0)
+ {
+ }
+
+ section::~section ()
+ {
+ if (data)
+ delete [] data;
+ }
+
+ void
+ section::load_data (rld::compress::compressor& comp)
+ {
+ rap_off = comp.offset ();
+ if (size)
+ {
+ data = new uint8_t[size];
+ if (comp.read (data, size) != size)
+ throw rld::error ("Reading section data failed", "rapper");
+ }
+ }
+
+ void
+ section::load_relocs (rld::compress::compressor& comp)
+ {
+ uint32_t header;
+ comp >> header;
+
+ rela = header & RAP_RELOC_RELA ? true : false;
+ relocs_size = header & ~RAP_RELOC_RELA;
+
+ if (relocs_size)
+ {
+ for (uint32_t r = 0; r < relocs_size; ++r)
+ {
+ relocation reloc;
+
+ reloc.rap_off = comp.offset ();
+
+ comp >> reloc.info
+ >> reloc.offset;
+
+ if (((reloc.info & RAP_RELOC_STRING) == 0) || rela)
+ comp >> reloc.addend;
+
+ if ((reloc.info & RAP_RELOC_STRING) != 0)
+ {
+ if ((reloc.info & RAP_RELOC_STRING_EMBED) == 0)
+ {
+ size_t symname_size = (reloc.info & ~(3 << 30)) >> 8;
+ reloc.symname.resize (symname_size);
+ size_t symname_read = comp.read ((void*) reloc.symname.c_str (), symname_size);
+ if (symname_read != symname_size)
+ throw rld::error ("Reading reloc symbol name failed", "rapper");
+ }
+ }
+
+ relocs.push_back (reloc);
+ }
+
+ std::stable_sort (relocs.begin (), relocs.end (), reloc_offset_compare ());
+ }
+ }
+
+ file::file (const std::string& name, bool warnings)
+ : rhdr_len (0),
+ rhdr_length (0),
+ rhdr_version (0),
+ rhdr_checksum (0),
+ machine_rap_off (0),
+ machinetype (0),
+ datatype (0),
+ class_ (0),
+ layout_rap_off (0),
+ init_off (0),
+ fini_off (0),
+ strtab_rap_off (0),
+ strtab_size (0),
+ strtab (0),
+ symtab_rap_off (0),
+ symtab_size (0),
+ symtab (0),
+ relocs_rap_off (0),
+ relocs_size (0),
+ detail_rap_off (0),
+ obj_num (0),
+ obj_name (0),
+ sec_num (0),
+ rpath (0),
+ rpathlen (0),
+ str_detail (0),
+ warnings (warnings),
+ image (name)
+ {
+ for (int s = 0; s < rld::rap::rap_secs; ++s)
+ secs[s].name = rld::rap::section_name (s);
+ image.open ();
+ parse_header ();
+ }
+
+ file::~file ()
+ {
+ image.close ();
+
+ if (symtab)
+ delete [] symtab;
+ if (strtab)
+ delete [] strtab;
+ if (obj_name)
+ delete [] obj_name;
+ if (sec_num)
+ delete [] sec_num;
+ if (str_detail)
+ delete [] str_detail;
+
+ }
+
+ void
+ file::parse_header ()
+ {
+ std::string name = image.name ().full ();
+
+ char rhdr[64];
+
+ image.seek_read (0, (uint8_t*) rhdr, 64);
+
+ if ((rhdr[0] != 'R') || (rhdr[1] != 'A') || (rhdr[2] != 'P') || (rhdr[3] != ','))
+ throw rld::error ("Invalid RAP file", "open: " + name);
+
+ char* sptr = rhdr + 4;
+ char* eptr;
+
+ rhdr_length = ::strtoul (sptr, &eptr, 10);
+
+ if (*eptr != ',')
+ throw rld::error ("Cannot parse RAP header", "open: " + name);
+
+ sptr = eptr + 1;
+
+ rhdr_version = ::strtoul (sptr, &eptr, 10);
+
+ if (*eptr != ',')
+ throw rld::error ("Cannot parse RAP header", "open: " + name);
+
+ sptr = eptr + 1;
+
+ if ((sptr[0] == 'N') &&
+ (sptr[1] == 'O') &&
+ (sptr[2] == 'N') &&
+ (sptr[3] == 'E'))
+ {
+ rhdr_compression = "NONE";
+ eptr = sptr + 4;
+ }
+ else if ((sptr[0] == 'L') &&
+ (sptr[1] == 'Z') &&
+ (sptr[2] == '7') &&
+ (sptr[3] == '7'))
+ {
+ rhdr_compression = "LZ77";
+ eptr = sptr + 4;
+ }
+ else
+ throw rld::error ("Cannot parse RAP header", "open: " + name);
+
+ if (*eptr != ',')
+ throw rld::error ("Cannot parse RAP header", "open: " + name);
+
+ sptr = eptr + 1;
+
+ rhdr_checksum = ::strtoul (sptr, &eptr, 16);
+
+ if (*eptr != '\n')
+ throw rld::error ("Cannot parse RAP header", "open: " + name);
+
+ rhdr_len = eptr - rhdr + 1;
+
+ if (warnings && (rhdr_length != image.size ()))
+ std::cout << " warning: header length does not match file size: header="
+ << rhdr_length
+ << " file-size=" << image.size ()
+ << std::endl;
+
+ header.insert (0, rhdr, rhdr_len);
+
+ image.seek (rhdr_len);
+ }
+
+ void
+ file::load_details (rld::compress::compressor& comp)
+ {
+ uint32_t tmp;
+
+ comp >> rpathlen;
+
+ obj_name = new uint8_t*[obj_num];
+
+ sec_num = new uint32_t[obj_num];
+
+ /* how many sections of each object file */
+ for (uint32_t i = 0; i < obj_num; i++)
+ {
+ comp >> tmp;
+ sec_num[i] = tmp;
+ }
+
+ /* strtable size */
+ comp >> tmp;
+ str_detail = new uint8_t[tmp];
+ if (comp.read (str_detail, tmp) != tmp)
+ throw rld::error ("Reading file str details error", "rapper");
+
+ if (rpathlen > 0)
+ rpath = (uint8_t*)str_detail;
+ else rpath = NULL;
+
+ section_detail sec;
+
+ for (uint32_t i = 0; i < obj_num; i++)
+ {
+ sec.obj = i;
+ for (uint32_t j = 0; j < sec_num[i]; j++)
+ {
+ comp >> sec.name;
+ comp >> tmp;
+ sec.offset = tmp & 0xfffffff;
+ sec.id = tmp >> 28;
+ comp >> sec.size;
+
+ sec_details.push_back (section_detail (sec));
+ }
+ }
+ }
+ void
+ file::load ()
+ {
+ image.seek (rhdr_len);
+
+ rld::compress::compressor comp (image, rap_comp_buffer, false);
+
+ /*
+ * uint32_t: machinetype
+ * uint32_t: datatype
+ * uint32_t: class
+ */
+ machine_rap_off = comp.offset ();
+ comp >> machinetype
+ >> datatype
+ >> class_;
+
+ /*
+ * uint32_t: init
+ * uint32_t: fini
+ * uint32_t: symtab_size
+ * uint32_t: strtab_size
+ * uint32_t: relocs_size
+ */
+ layout_rap_off = comp.offset ();
+ comp >> init_off
+ >> fini_off
+ >> symtab_size
+ >> strtab_size
+ >> relocs_size;
+
+ /*
+ * Load the file details.
+ */
+ detail_rap_off = comp.offset ();
+
+ comp >> obj_num;
+
+ if (obj_num > 0)
+ load_details(comp);
+
+ /*
+ * uint32_t: text_size
+ * uint32_t: text_alignment
+ * uint32_t: const_size
+ * uint32_t: const_alignment
+ * uint32_t: ctor_size
+ * uint32_t: ctor_alignment
+ * uint32_t: dtor_size
+ * uint32_t: dtor_alignment
+ * uint32_t: data_size
+ * uint32_t: data_alignment
+ * uint32_t: bss_size
+ * uint32_t: bss_alignment
+ */
+ for (int s = 0; s < rld::rap::rap_secs; ++s)
+ comp >> secs[s].size
+ >> secs[s].alignment;
+
+ /*
+ * Load sections.
+ */
+ for (int s = 0; s < rld::rap::rap_secs; ++s)
+ if (s != rld::rap::rap_bss)
+ secs[s].load_data (comp);
+
+ /*
+ * Load the string table.
+ */
+ strtab_rap_off = comp.offset ();
+ if (strtab_size)
+ {
+ strtab = new uint8_t[strtab_size];
+ if (comp.read (strtab, strtab_size) != strtab_size)
+ throw rld::error ("Reading string table failed", "rapper");
+ }
+
+ /*
+ * Load the symbol table.
+ */
+ symtab_rap_off = comp.offset ();
+ if (symtab_size)
+ {
+ symtab = new uint8_t[symtab_size];
+ if (comp.read (symtab, symtab_size) != symtab_size)
+ throw rld::error ("Reading symbol table failed", "rapper");
+ }
+
+ /*
+ * Load the relocation tables.
+ */
+ relocs_rap_off = comp.offset ();
+ for (int s = 0; s < rld::rap::rap_secs; ++s)
+ secs[s].load_relocs (comp);
+ }
+
+ void
+ file::expand ()
+ {
+ std::string name = image.name ().full ();
+ std::string extension = rld::files::extension (image.name ().full ());
+
+ name = name.substr (0, name.size () - extension.size ()) + ".xrap";
+
+ image.seek (rhdr_len);
+
+ rld::compress::compressor comp (image, rap_comp_buffer, false);
+ rld::files::image out (name);
+
+ out.open (true);
+ out.seek (0);
+ while (true)
+ {
+ if (comp.read (out, rap_comp_buffer) != rap_comp_buffer)
+ break;
+ }
+ out.close ();
+ }
+
+ const std::string
+ file::name () const
+ {
+ return image.name ().full ();
+ }
+
+ int
+ file::symbols () const
+ {
+ return symtab_size / (3 * sizeof (uint32_t));
+ }
+
+ void
+ file::symbol (int index, uint32_t& data, uint32_t& name, uint32_t& value) const
+ {
+ if (index < symbols ())
+ {
+ uint8_t* sym = symtab + (index * 3 * sizeof (uint32_t));
+ data = get_value < uint32_t > (sym);
+ name = get_value < uint32_t > (sym + (1 * sizeof (uint32_t)));
+ value = get_value < uint32_t > (symtab + (2 * sizeof (uint32_t)));
+ }
+ }
+
+ const char*
+ file::string (int index)
+ {
+ std::string name = image.name ().full ();
+
+ if (strtab_size == 0)
+ throw rld::error ("No string table", "string: " + name);
+
+ uint32_t offset = 0;
+ int count = 0;
+ while (offset < strtab_size)
+ {
+ if (count++ == index)
+ return (const char*) &strtab[offset];
+ offset = ::strlen ((const char*) &strtab[offset]) + 1;
+ }
+
+ throw rld::error ("Invalid string index", "string: " + name);
+ }
+}
+
+void
+rap_show (rld::files::paths& raps,
+ bool warnings,
+ bool show_header,
+ bool show_machine,
+ bool show_layout,
+ bool show_strings,
+ bool show_symbols,
+ bool show_relocs,
+ bool show_details)
+{
+ for (rld::files::paths::iterator pi = raps.begin();
+ pi != raps.end();
+ ++pi)
+ {
+ std::cout << *pi << ':' << std::endl;
+
+ rap::file r (*pi, warnings);
+
+ try
+ {
+ r.load ();
+ }
+ catch (rld::error re)
+ {
+ std::cout << " error: "
+ << re.where << ": " << re.what
+ << std::endl
+ << " warning: file read failed, some data may be corrupt or not present."
+ << std::endl;
+ }
+
+ if (show_header)
+ {
+ std::cout << " Header:" << std::endl
+ << " string: " << r.header
+ << " length: " << r.rhdr_len << std::endl
+ << " version: " << r.rhdr_version << std::endl
+ << " compression: " << r.rhdr_compression << std::endl
+ << std::hex << std::setfill ('0')
+ << " checksum: " << std::setw (8) << r.rhdr_checksum << std::endl
+ << std::dec << std::setfill(' ');
+ }
+
+ if (show_machine)
+ {
+ std::cout << " Machine: 0x"
+ << std::hex << std::setfill ('0')
+ << std::setw (8) << r.machine_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.machine_rap_off << ')' << std::endl
+ << " machinetype: "<< r.machinetype << std::endl
+ << " datatype: "<< r.datatype << std::endl
+ << " class: "<< r.class_ << std::endl;
+ }
+
+ if (show_layout)
+ {
+ std::cout << " Layout: 0x"
+ << std::hex << std::setfill ('0')
+ << std::setw (8) << r.layout_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.layout_rap_off << ')' << std::endl
+ << std::setw (18) << " "
+ << " size align offset " << std::endl;
+ uint32_t relocs_size = 0;
+ for (int s = 0; s < rld::rap::rap_secs; ++s)
+ {
+ relocs_size += r.secs[s].relocs.size ();
+ std::cout << std::setw (16) << rld::rap::section_name (s)
+ << ": " << std::setw (6) << r.secs[s].size
+ << std::setw (7) << r.secs[s].alignment;
+ if (s != rld::rap::rap_bss)
+ std::cout << std::hex << std::setfill ('0')
+ << " 0x" << std::setw (8) << r.secs[s].rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.secs[s].rap_off << ')';
+ else
+ std::cout << " -";
+ std::cout << std::endl;
+ }
+ std::cout << std::setw (16) << "strtab" << ": "
+ << std::setw (6) << r.strtab_size
+ << std::setw (7) << '-'
+ << std::hex << std::setfill ('0')
+ << " 0x" << std::setw (8) << r.strtab_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.strtab_rap_off << ')' << std::endl
+ << std::setw (16) << "symtab" << ": "
+ << std::setw (6) << r.symtab_size
+ << std::setw (7) << '-'
+ << std::hex << std::setfill ('0')
+ << " 0x" << std::setw (8) << r.symtab_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.symtab_rap_off << ')' << std::endl
+ << std::setw (16) << "relocs" << ": "
+ << std::setw (6) << (relocs_size * 3 * sizeof (uint32_t))
+ << std::setw (7) << '-'
+ << std::hex << std::setfill ('0')
+ << " 0x" << std::setw (8) << r.relocs_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.relocs_rap_off << ')' << std::endl;
+ }
+
+ if (show_details)
+ {
+ std::cout << " Details: 0x"
+ << std::hex << std::setfill ('0')
+ << std::setw (8) << r.detail_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.detail_rap_off << ')' << std::endl;
+
+ uint32_t pos = 0;
+ if (r.rpath != NULL)
+ {
+ std::cout << " rpath:" << std::endl;
+ while (pos < r.rpathlen)
+ {
+ std::cout << " " << r.rpath + pos << std::endl;
+ pos = std::string ((char*)(r.rpath + pos)).length () + pos + 1;
+ }
+ }
+
+ if (r.obj_num == 0)
+ std::cout << " No details" << std::endl;
+ else
+ std::cout << ' ' << r.obj_num <<" Files" << std::endl;
+
+ for (uint32_t i = 0; i < r.obj_num; ++i)
+ {
+ r.obj_name[i] = (uint8_t*) &r.str_detail[pos];
+ pos += ::strlen ((char*) &r.str_detail[pos]) + 1;
+ }
+
+ for (uint32_t i = 0; i < r.obj_num; ++i)
+ {
+ std::cout << " File: " << r.obj_name[i] << std::endl;
+
+ for (rap::section_details::const_iterator sd = r.sec_details.begin ();
+ sd != r.sec_details.end ();
+ ++sd)
+ {
+ rap::section_detail tmp = *sd;
+ if (tmp.obj == i)
+ {
+ std::cout << std::setw (12) << "name:"
+ << std::setw (16) << (char*)&r.str_detail[tmp.name]
+ << " rap_section:"<< std::setw (8)
+ << rap::section_names[tmp.id]
+ << std::hex << std::setfill ('0')
+ << " offset:0x" << std::setw (8) << tmp.offset
+ << " size:0x" << std::setw (8) << tmp.size << std::dec
+ << std::setfill (' ') << std::endl;
+
+ }
+ }
+ }
+ }
+
+ if (show_strings)
+ {
+ std::cout << " Strings: 0x"
+ << std::hex << std::setfill ('0')
+ << std::setw (8) << r.strtab_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.strtab_rap_off << ')'
+ << " size: " << r.strtab_size
+ << std::endl;
+ if (r.strtab_size)
+ {
+ uint32_t offset = 0;
+ int count = 0;
+ while (offset < r.strtab_size)
+ {
+ std::cout << std::setw (16) << count++
+ << std::hex << std::setfill ('0')
+ << " (0x" << std::setw (6) << offset << "): "
+ << std::dec << std::setfill (' ')
+ << (char*) &r.strtab[offset] << std::endl;
+ offset += ::strlen ((char*) &r.strtab[offset]) + 1;
+ }
+ }
+ else
+ {
+ std::cout << std::setw (16) << " "
+ << "No string table found." << std::endl;
+ }
+ }
+
+ if (show_symbols)
+ {
+ std::cout << " Symbols: 0x"
+ << std::hex << std::setfill ('0')
+ << std::setw (8) << r.symtab_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.symtab_rap_off << ')'
+ << " size: " << r.symtab_size
+ << std::endl;
+ if (r.symtab_size)
+ {
+ std::cout << std::setw (18) << " "
+ << " data section value name" << std::endl;
+ for (int s = 0; s < r.symbols (); ++s)
+ {
+ uint32_t data;
+ uint32_t name;
+ uint32_t value;
+ r.symbol (s, data, name, value);
+ std::cout << std::setw (16) << s << ": "
+ << std::hex << std::setfill ('0')
+ << "0x" << std::setw (4) << (data & 0xffff)
+ << std::dec << std::setfill (' ')
+ << " " << std::setw (8) << rld::rap::section_name (data >> 16)
+ << std::hex << std::setfill ('0')
+ << " 0x" << std::setw(8) << value
+ << " " << &r.strtab[name]
+ << std::dec << std::setfill (' ')
+ << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << std::setw (16) << " "
+ << "No symbol table found." << std::endl;
+ }
+ }
+
+ if (show_relocs)
+ {
+ std::cout << " Relocations: 0x"
+ << std::hex << std::setfill ('0')
+ << std::setw (8) << r.relocs_rap_off
+ << std::setfill (' ') << std::dec
+ << " (" << r.relocs_rap_off << ')' << std::endl;
+ int count = 0;
+ for (int s = 0; s < rld::rap::rap_secs; ++s)
+ {
+ if (r.secs[s].relocs.size ())
+ {
+ const char* rela = r.secs[s].rela ? "(A)" : " ";
+ std::cout << std::setw (16) << r.secs[s].name
+ << ": info offset addend "
+ << rela
+ << " symbol name" << std::endl;
+ for (size_t f = 0; f < r.secs[s].relocs.size (); ++f)
+ {
+ rap::relocation& reloc = r.secs[s].relocs[f];
+ std::cout << std::setw (16) << count++ << ": ";
+ reloc.output ();
+ std::cout << std::endl;
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+rap_overlay (rld::files::paths& raps, bool warnings)
+{
+ std::cout << "Overlay .... " << std::endl;
+ for (rld::files::paths::iterator pi = raps.begin();
+ pi != raps.end();
+ ++pi)
+ {
+ rap::file r (*pi, warnings);
+ std::cout << r.name () << std::endl;
+
+ r.load ();
+
+ for (int s = 0; s < rld::rap::rap_secs; ++s)
+ {
+ rap::section& sec = r.secs[s];
+
+ if (sec.size && sec.data)
+ {
+ std::cout << rld::rap::section_name (s) << ':' << std::endl;
+
+ size_t line_length = 16;
+ uint32_t offset = 0;
+ size_t reloc = 0;
+
+ while (offset < sec.size)
+ {
+ size_t length = sec.size - offset;
+
+ if (reloc < sec.relocs.size ())
+ length = sec.relocs[reloc].offset - offset;
+
+ if ((offset + length) < sec.size)
+ {
+ length += line_length;
+ length -= length % line_length;
+ }
+
+ rtems::utils::dump (sec.data + offset,
+ length,
+ sizeof (uint8_t),
+ false,
+ line_length,
+ offset);
+
+ const int indent = 8;
+ std::ostringstream line;
+
+ line << std::setw (indent) << ' ';
+
+ while ((reloc < sec.relocs.size ()) &&
+ (sec.relocs[reloc].offset >= offset) &&
+ (sec.relocs[reloc].offset < (offset + length)))
+ {
+ int spaces = ((((sec.relocs[reloc].offset + 1) % line_length) * 3) +
+ indent - 1);
+
+ spaces -= line.str ().size ();
+
+ line << std::setw (spaces) << " ^" << reloc
+ << ':' << std::hex
+ << sec.relocs[reloc].addend
+ << std::dec;
+
+ ++reloc;
+ }
+
+ std::cout << line.str () << std::endl;
+
+ offset += length;
+ }
+
+ if (sec.relocs.size ())
+ {
+ int count = 0;
+ std::cout << " info offset addend symbol name" << std::endl;
+ for (size_t f = 0; f < r.secs[s].relocs.size (); ++f)
+ {
+ rap::relocation& reloc = r.secs[s].relocs[f];
+ std::cout << std::setw (4) << count++ << ' ';
+ reloc.output ();
+ std::cout << std::endl;
+ }
+ }
+
+ }
+ }
+ }
+}
+
+void
+rap_expander (rld::files::paths& raps, bool warnings)
+{
+ std::cout << "Expanding .... " << std::endl;
+ for (rld::files::paths::iterator pi = raps.begin();
+ pi != raps.end();
+ ++pi)
+ {
+ rap::file r (*pi, warnings);
+ std::cout << ' ' << r.name () << std::endl;
+ r.expand ();
+ }
+}
+
+/**
+ * RTEMS RAP options.
+ */
+static struct option rld_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "no-warn", no_argument, NULL, 'n' },
+ { "all", no_argument, NULL, 'a' },
+ { "header", no_argument, NULL, 'H' },
+ { "machine", no_argument, NULL, 'm' },
+ { "layout", no_argument, NULL, 'l' },
+ { "strings", no_argument, NULL, 's' },
+ { "symbols", no_argument, NULL, 'S' },
+ { "relocs", no_argument, NULL, 'r' },
+ { "overlay", no_argument, NULL, 'o' },
+ { "expand", no_argument, NULL, 'x' },
+ { NULL, 0, NULL, 0 }
+};
+
+void
+usage (int exit_code)
+{
+ std::cout << "rtems-rap [options] objects" << std::endl
+ << "Options and arguments:" << std::endl
+ << " -h : help (also --help)" << std::endl
+ << " -V : print linker version number and exit (also --version)" << std::endl
+ << " -v : verbose (trace import parts), can supply multiple times" << std::endl
+ << " to increase verbosity (also --verbose)" << std::endl
+ << " -n : no warnings (also --no-warn)" << std::endl
+ << " -a : show all (also --all)" << std::endl
+ << " -H : show header (also --header)" << std::endl
+ << " -m : show machine details (also --machine)" << std::endl
+ << " -l : show layout (also --layout)" << std::endl
+ << " -s : show strings (also --strings)" << std::endl
+ << " -S : show symbols (also --symbols)" << std::endl
+ << " -r : show relocations (also --relocs)" << std::endl
+ << " -o : linkage overlay (also --overlay)" << std::endl
+ << " -x : expand (also --expand)" << std::endl
+ << " -f : show file details" << std::endl;
+ ::exit (exit_code);
+}
+
+static void
+fatal_signal (int signum)
+{
+ signal (signum, SIG_DFL);
+
+ rld::process::temporaries_clean_up ();
+
+ /*
+ * Get the same signal again, this time not handled, so its normal effect
+ * occurs.
+ */
+ kill (getpid (), signum);
+}
+
+static void
+setup_signals (void)
+{
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_signal);
+#ifdef SIGHUP
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_signal);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_signal);
+#ifdef SIGPIPE
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, fatal_signal);
+#endif
+#ifdef SIGCHLD
+ signal (SIGCHLD, SIG_DFL);
+#endif
+}
+
+int
+main (int argc, char* argv[])
+{
+ int ec = 0;
+
+ setup_signals ();
+
+ try
+ {
+ rld::files::paths raps;
+ bool warnings = true;
+ bool show = false;
+ bool show_header = false;
+ bool show_machine = false;
+ bool show_layout = false;
+ bool show_strings = false;
+ bool show_symbols = false;
+ bool show_relocs = false;
+ bool show_details = false;
+ bool overlay = false;
+ bool expand = false;
+
+ while (true)
+ {
+ int opt = ::getopt_long (argc, argv, "hvVnaHlsSroxf", rld_opts, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt)
+ {
+ case 'V':
+ std::cout << "rtems-rap (RTEMS RAP Manager) " << rld::version ()
+ << std::endl;
+ ::exit (0);
+ break;
+
+ case 'v':
+ rld::verbose_inc ();
+ break;
+
+ case 'n':
+ warnings = false;
+ break;
+
+ case 'a':
+ show = true;
+ show_header = true;
+ show_machine = true;
+ show_layout = true;
+ show_strings = true;
+ show_symbols = true;
+ show_relocs = true;
+ show_details = true;
+ break;
+
+ case 'H':
+ show = true;
+ show_header = true;
+ break;
+
+ case 'm':
+ show = true;
+ show_machine = true;
+ break;
+
+ case 'l':
+ show = true;
+ show_layout = true;
+ break;
+
+ case 's':
+ show = true;
+ show_strings = true;
+ break;
+
+ case 'S':
+ show = true;
+ show_symbols = true;
+ break;
+
+ case 'r':
+ show = true;
+ show_relocs = true;
+ break;
+
+ case 'o':
+ overlay = true;
+ break;
+
+ case 'x':
+ expand = true;
+ break;
+
+ case 'f':
+ show_details = true;
+ break;
+
+ case '?':
+ case 'h':
+ usage (0);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ std::cout << "RTEMS RAP " << rld::version () << std::endl << std::endl;
+
+ /*
+ * If there are no RAP files so there is nothing to do.
+ */
+ if (argc == 0)
+ throw rld::error ("no RAP files", "options");
+
+ /*
+ * Load the remaining command line arguments into a container.
+ */
+ while (argc--)
+ raps.push_back (*argv++);
+
+ if (show)
+ rap_show (raps,
+ warnings,
+ show_header,
+ show_machine,
+ show_layout,
+ show_strings,
+ show_symbols,
+ show_relocs,
+ show_details);
+
+ if (overlay)
+ rap_overlay (raps, warnings);
+
+ if (expand)
+ rap_expander (raps, warnings);
+ }
+ catch (rld::error re)
+ {
+ std::cerr << "error: "
+ << re.where << ": " << re.what
+ << std::endl;
+ ec = 10;
+ }
+ catch (std::exception e)
+ {
+ int status;
+ char* realname;
+ realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
+ std::cerr << "error: exception: " << realname << " [";
+ ::free (realname);
+ const std::type_info &ti = typeid (e);
+ realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
+ std::cerr << realname << "] " << e.what () << std::endl;
+ ::free (realname);
+ ec = 11;
+ }
+ catch (...)
+ {
+ /*
+ * Helps to know if this happens.
+ */
+ std::cout << "error: unhandled exception" << std::endl;
+ ec = 12;
+ }
+
+ return ec;
+}
diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp
new file mode 100644
index 0000000..437884c
--- /dev/null
+++ b/linkers/rtems-syms.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rld
+ *
+ * @brief RTEMS Symbols Main manages opions, sequence of operations and exceptions.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+
+#include <cxxabi.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <getopt.h>
+
+#include <rld.h>
+#include <rld-cc.h>
+#include <rld-outputter.h>
+#include <rld-process.h>
+#include <rld-resolver.h>
+
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
+
+/**
+ * RTEMS Linker options. This needs to be rewritten to be like cc where only a
+ * single '-' and long options is present.
+ */
+static struct option rld_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "warn", no_argument, NULL, 'w' },
+ { "lib-path", required_argument, NULL, 'L' },
+ { "lib", required_argument, NULL, 'l' },
+ { "no-stdlibs", no_argument, NULL, 'n' },
+ { "cc", required_argument, NULL, 'C' },
+ { "exec-prefix", required_argument, NULL, 'E' },
+ { "march", required_argument, NULL, 'a' },
+ { "mcpu", required_argument, NULL, 'c' },
+ { NULL, 0, NULL, 0 }
+};
+
+void
+usage (int exit_code)
+{
+ std::cout << "rtems-syms [options] objects" << std::endl
+ << "Options and arguments:" << std::endl
+ << " -h : help (also --help)" << std::endl
+ << " -V : print linker version number and exit (also --version)" << std::endl
+ << " -v : verbose (trace import parts), can supply multiple times" << std::endl
+ << " to increase verbosity (also --verbose)" << std::endl
+ << " -w : generate warnings (also --warn)" << std::endl
+ << " -L path : path to a library, add multiple for more than" << std::endl
+ << " one path (also --lib-path)" << std::endl
+ << " -l lib : add lib to the libraries searched, add multiple" << std::endl
+ << " for more than one library (also --lib)" << std::endl
+ << " -S : search standard libraries (also --stdlibs)" << std::endl
+ << " -C file : execute file as the target C compiler (also --cc)" << std::endl
+ << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
+ << " -a march : machine architecture (also --march)" << std::endl
+ << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl;
+ ::exit (exit_code);
+}
+
+static void
+fatal_signal (int signum)
+{
+ signal (signum, SIG_DFL);
+
+ rld::process::temporaries_clean_up ();
+
+ /*
+ * Get the same signal again, this time not handled, so its normal effect
+ * occurs.
+ */
+ kill (getpid (), signum);
+}
+
+static void
+setup_signals (void)
+{
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_signal);
+#ifdef SIGHUP
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_signal);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_signal);
+#ifdef SIGPIPE
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, fatal_signal);
+#endif
+#ifdef SIGCHLD
+ signal (SIGCHLD, SIG_DFL);
+#endif
+}
+
+int
+main (int argc, char* argv[])
+{
+ int ec = 0;
+
+ setup_signals ();
+
+ try
+ {
+ rld::files::cache cache;
+ rld::files::paths libpaths;
+ rld::files::paths libs;
+ rld::files::paths objects;
+ rld::files::paths libraries;
+ rld::symbols::table symbols;
+ std::string base_name;
+ std::string cc_name;
+ bool standard_libs = false;
+ bool exec_prefix_set = false;
+#if HAVE_WARNINGS
+ bool warnings = false;
+#endif
+
+ libpaths.push_back (".");
+
+ while (true)
+ {
+ int opt = ::getopt_long (argc, argv, "hvwVSE:L:l:a:c:C:", rld_opts, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt)
+ {
+ case 'V':
+ std::cout << "rtems-syms (RTEMS Symbols) " << rld::version ()
+ << std::endl;
+ ::exit (0);
+ break;
+
+ case 'v':
+ rld::verbose_inc ();
+ break;
+
+ case 'w':
+#if HAVE_WARNINGS
+ warnings = true;
+#endif
+ break;
+
+ case 'l':
+ /*
+ * The order is important. It is the search order.
+ */
+ libs.push_back (optarg);
+ break;
+
+ case 'L':
+ if ((optarg[::strlen (optarg) - 1] == '/') ||
+ (optarg[::strlen (optarg) - 1] == '\\'))
+ optarg[::strlen (optarg) - 1] = '\0';
+ libpaths.push_back (optarg);
+ break;
+
+ case 'S':
+ standard_libs = true;
+ break;
+
+ case 'C':
+ if (exec_prefix_set == true)
+ std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
+ rld::cc::cc = optarg;
+ break;
+
+ case 'E':
+ exec_prefix_set = true;
+ rld::cc::exec_prefix = optarg;
+ break;
+
+ case 'a':
+ rld::cc::march = optarg;
+ break;
+
+ case 'c':
+ rld::cc::mcpu = optarg;
+ break;
+
+ case '?':
+ usage (3);
+ break;
+
+ case 'h':
+ usage (0);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ std::cout << "RTEMS Symbols " << rld::version () << std::endl;
+
+ /*
+ * If there are no object files there is nothing to link.
+ */
+ if (argc == 0)
+ throw rld::error ("no object files", "options");
+
+ /*
+ * Load the remaining command line arguments into the cache as object
+ * files.
+ */
+ while (argc--)
+ objects.push_back (*argv++);
+
+ /*
+ * Add the object files to the cache.
+ */
+ cache.add (objects);
+
+ /*
+ * Open the cache.
+ */
+ cache.open ();
+
+ /*
+ * If the full path to CC is not provided and the exec-prefix is not set by
+ * the command line see if it can be detected from the object file
+ * types. This must be after we have added the object files because they
+ * are used when detecting.
+ */
+ if (rld::cc::cc.empty () && !exec_prefix_set)
+ rld::cc::exec_prefix = rld::elf::machine_type ();
+
+ /*
+ * Get the standard library paths
+ */
+ if (standard_libs)
+ rld::cc::get_standard_libpaths (libpaths);
+
+ /*
+ * Get the command line libraries.
+ */
+ rld::files::find_libraries (libraries, libpaths, libs);
+
+ /*
+ * Are we to load standard libraries ?
+ */
+ if (standard_libs)
+ rld::cc::get_standard_libs (libraries, libpaths);
+
+ /*
+ * Load the library to the cache.
+ */
+ cache.add_libraries (libraries);
+
+ /*
+ * Begin the archive session. This opens the archives and leaves them open
+ * while we the symbol table is being used. The symbols reference object
+ * files and the object files may reference archives and it is assumed they
+ * are open and available. It is also assumed the number of library
+ * archives being managed is less than the maximum file handles this
+ * process can have open at any one time. If this is not the case this
+ * approach would need to be reconsidered and the overhead of opening and
+ * closing archives added.
+ */
+ try
+ {
+ /*
+ * Load the symbol table.
+ */
+ cache.load_symbols (symbols);
+
+ rld::map (cache, symbols);
+ }
+ catch (...)
+ {
+ cache.archives_end ();
+ throw;
+ }
+
+ cache.archives_end ();
+ }
+ catch (rld::error re)
+ {
+ std::cerr << "error: "
+ << re.where << ": " << re.what
+ << std::endl;
+ ec = 10;
+ }
+ catch (std::exception e)
+ {
+ int status;
+ char* realname;
+ realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
+ std::cerr << "error: exception: " << realname << " [";
+ ::free (realname);
+ const std::type_info &ti = typeid (e);
+ realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
+ std::cerr << realname << "] " << e.what () << std::endl;
+ ::free (realname);
+ ec = 11;
+ }
+ catch (...)
+ {
+ /*
+ * Helps to know if this happens.
+ */
+ std::cout << "error: unhandled exception" << std::endl;
+ ec = 12;
+ }
+
+ return ec;
+}
diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp
new file mode 100644
index 0000000..d206da7
--- /dev/null
+++ b/linkers/rtems-tld.cpp
@@ -0,0 +1,940 @@
+/*
+ * Copyright (c) 2014, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rld
+ *
+ * @brief RTEMS Trace Linker manages creating a tracable RTEMS executable.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <algorithm>
+#include <cctype>
+#include <functional>
+#include <iostream>
+#include <locale>
+#include <sstream>
+
+#include <cxxabi.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <getopt.h>
+
+#include <rld.h>
+#include <rld-cc.h>
+#include <rld-config.h>
+#include <rld-process.h>
+
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
+
+namespace rld
+{
+ /**
+ * RTEMS Trace Linker.
+ */
+ namespace trace
+ {
+ /**
+ * A container of arguments.
+ */
+ typedef std::vector < std::string > function_args;
+
+ /**
+ * The return value.
+ */
+ typedef std::string function_return;
+
+ /**
+ * A function's signature.
+ */
+ struct signature
+ {
+ std::string name; /**< The function's name. */
+ function_args args; /**< The function's list of arguments. */
+ function_return ret; /**< The fuctions return value. */
+
+ /**
+ * The default constructor.
+ */
+ signature ();
+
+ /**
+ * Construct the signature loading it from the configuration.
+ */
+ signature (const rld::config::record& record);
+
+ /**
+ * Return the function's declaration.
+ */
+ const std::string decl () const;
+ };
+
+ /**
+ * A container of signatures.
+ */
+ typedef std::map < std::string, signature > signatures;
+
+ /**
+ * A function is list of function signatures headers and defines that allow
+ * a function to be wrapped.
+ */
+ struct function
+ {
+ std::string name; /**< The name of this wrapper. */
+ rld::strings headers; /**< Include statements. */
+ rld::strings defines; /**< Define statements. */
+ signatures signatures_; /**< Signatures in this function. */
+
+ /**
+ * Load the function.
+ */
+ function (rld::config::config& config,
+ const std::string& name);
+
+ /**
+ * Dump the function.
+ */
+ void dump (std::ostream& out) const;
+ };
+
+ /**
+ * A container of functions.
+ */
+ typedef std::vector < function > functions;
+
+ /**
+ * A generator and that contains the functions used to trace arguments and
+ * return values. It also provides the implementation of those functions.
+ */
+ struct generator
+ {
+ std::string name; /**< The name of this wrapper. */
+ rld::strings headers; /**< Include statements. */
+ rld::strings defines; /**< Define statements. */
+ std::string map_sym_prefix; /**< Mapping symbol prefix. */
+ std::string arg_trace; /**< Code template to trace an argument. */
+ std::string ret_trace; /**< Code template to trace the return value. */
+ rld::strings code; /**< Code block inserted before the trace code. */
+
+ /**
+ * Default constructor.
+ */
+ generator ();
+
+ /**
+ * Load the generator.
+ */
+ generator (rld::config::config& config,
+ const std::string& name);
+
+ /**
+ * Dump the generator.
+ */
+ void dump (std::ostream& out) const;
+ };
+
+ /**
+ * Tracer.
+ */
+ class tracer
+ {
+ public:
+ tracer ();
+
+ /**
+ * Load the user's configuration.
+ */
+ void load (rld::config::config& config,
+ const std::string& section);
+
+ /**
+ * The the functions for the trace.
+ */
+ void load_functions (rld::config::config& config,
+ const rld::config::section& section);
+
+ /**
+ * The the traces for the tracer.
+ */
+ void load_traces (rld::config::config& config,
+ const rld::config::section& section);
+
+ /**
+ * Generate the wrapper object file.
+ */
+ void generate ();
+
+ /**
+ * Generate the trace functions.
+ */
+ void generate_traces (rld::process::tempfile& c);
+
+ /**
+ * Dump the wrapper.
+ */
+ void dump (std::ostream& out) const;
+
+ private:
+
+ std::string name; /**< The name of the trace. */
+ std::string bsp; /**< The BSP we are linking to. */
+ rld::strings traces; /**< The functions to trace. */
+ functions functions_; /**< The functions that can be traced. */
+ generator generator_; /**< The tracer's generator. */
+ };
+
+ /**
+ * Trace Linker.
+ */
+ class linker
+ {
+ public:
+ linker ();
+
+ /**
+ * Load the user's configuration.
+ */
+ void load_config (const std::string& path,
+ const std::string& trace);
+
+ /**
+ * Generate the C file.
+ */
+ void generate_wrapper ();
+
+ /**
+ * Dump the linker.
+ */
+ void dump (std::ostream& out) const;
+
+ private:
+
+ rld::config::config config; /**< User configuration. */
+ tracer tracer_; /**< The tracer */
+ };
+
+ /**
+ * Recursive parser for strings.
+ */
+ void
+ parse (rld::config::config& config,
+ const rld::config::section& section,
+ const std::string& sec_name,
+ const std::string& rec_name,
+ rld::strings& items,
+ bool split = true,
+ int depth = 0)
+ {
+ if (depth > 32)
+ throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name);
+
+ rld::config::parse_items (section, rec_name, items, false, false, split);
+
+ rld::strings sl;
+
+ rld::config::parse_items (section, sec_name, sl);
+
+ for (rld::strings::iterator sli = sl.begin ();
+ sli != sl.end ();
+ ++sli)
+ {
+ const rld::config::section& sec = config.get_section (*sli);
+ parse (config, sec, sec_name, rec_name, items, split, depth + 1);
+ }
+
+ /*
+ * Make the items unique.
+ */
+ rld::strings::iterator ii;
+ ii = std::unique (items.begin (), items.end ());
+ items.resize (std::distance (items.begin (), ii));
+ }
+
+ signature::signature ()
+ {
+ }
+
+ signature::signature (const rld::config::record& record)
+ {
+ /*
+ * There can only be one function signature in the configuration.
+ */
+ if (!record.single ())
+ throw rld::error ("duplicate", "signature: " + record.name);
+
+ name = record.name;
+
+ /*
+ * Signatures are defined as the return value then the arguments
+ * delimited by a comma and white space. No checking is made of the
+ * return value or arguments.
+ */
+ rld::strings si;
+ rld::config::parse_items (record, si);
+
+ if (si.size () == 0)
+ throw rld::error ("no return value", "signature: " + record.name);
+ if (si.size () == 1)
+ throw rld::error ("no arguments", "signature: " + record.name);
+
+ ret = si[0];
+ args.resize (si.size () - 1);
+ std::copy (si.begin () + 1, si.end (), args.begin ());
+ }
+
+ const std::string
+ signature::decl () const
+ {
+ std::string ds = ret + ' ' + name + '(';
+ int arg = 0;
+ for (function_args::const_iterator ai = args.begin ();
+ ai != args.end ();
+ ++ai)
+ {
+ if (ai != args.begin ())
+ ds += ", ";
+ ds += (*ai) + " a" + rld::to_string (++arg);
+ }
+ ds += ')';
+ return ds;
+ }
+
+ function::function (rld::config::config& config,
+ const std::string& name)
+ : name (name)
+ {
+ /*
+ * A function section optionally contain one or more records of:
+ *
+ * # headers A list of sections containing headers or header records.
+ * # header A list of include string that are single or double quoted.
+ * # defines A list of sections containing defines or define record.
+ * # defines A list of define string that are single or double quoted.
+ * # signatures A list of section names of signatures.
+ * # includes A list of files to include.
+ *
+ * @note The quoting and list spliting is a little weak because a delimiter
+ * in a quote should not be seen as a delimiter.
+ */
+ const rld::config::section& section = config.get_section (name);
+
+ config.includes (section);
+
+ parse (config, section, "headers", "header", headers);
+ parse (config, section, "defines", "define", defines);
+
+ rld::strings sig_list;
+ section.get_record_items ("signatures", sig_list);
+
+ for (rld::strings::const_iterator sli = sig_list.begin ();
+ sli != sig_list.end ();
+ ++sli)
+ {
+ const rld::config::section& sig_sec = config.get_section (*sli);
+ for (rld::config::records::const_iterator si = sig_sec.recs.begin ();
+ si != sig_sec.recs.end ();
+ ++si)
+ {
+ signature sig (*si);
+ signatures_[sig.name] = sig;
+ }
+ }
+ }
+
+ void
+ function::dump (std::ostream& out) const
+ {
+ out << " Function: " << name << std::endl
+ << " Headers: " << headers.size () << std::endl;
+ for (rld::strings::const_iterator hi = headers.begin ();
+ hi != headers.end ();
+ ++hi)
+ {
+ out << " " << (*hi) << std::endl;
+ }
+ out << " Defines: " << defines.size () << std::endl;
+ for (rld::strings::const_iterator di = defines.begin ();
+ di != defines.end ();
+ ++di)
+ {
+ out << " " << (*di) << std::endl;
+ }
+ out << " Signatures: " << signatures_.size () << std::endl;
+ for (signatures::const_iterator si = signatures_.begin ();
+ si != signatures_.end ();
+ ++si)
+ {
+ const signature& sig = (*si).second;
+ out << " " << sig.name << ": " << sig.decl () << ';' << std::endl;
+ }
+ }
+
+ generator::generator ()
+ {
+ }
+
+ generator::generator (rld::config::config& config,
+ const std::string& name)
+ : name (name)
+ {
+ /*
+ * A generator section optionally contain one or more records of:
+ *
+ * # headers A list of sections containing headers or header records.
+ * # header A list of include string that are single or double quoted.
+ * # defines A list of sections containing defines or define record.
+ * # defines A list of define string that are single or double quoted.
+ * # code-blocks A list of section names of code blocks.
+ * # includes A list of files to include.
+ *
+ * @note The quoting and list spliting is a little weak because a delimiter
+ * in a quote should not be seen as a delimiter.
+ */
+ const rld::config::section& section = config.get_section (name);
+
+ config.includes (section);
+
+ parse (config, section, "headers", "header", headers);
+ parse (config, section, "defines", "define", defines);
+ parse (config, section, "code-blocks", "code", code, false);
+
+ map_sym_prefix = section.get_record_item ("map-sym-prefix");
+ arg_trace = rld::dequote (section.get_record_item ("arg-trace"));
+ ret_trace = rld::dequote (section.get_record_item ("ret-trace"));
+ }
+
+ void
+ generator::dump (std::ostream& out) const
+ {
+ out << " Generator: " << name << std::endl
+ << " Headers: " << headers.size () << std::endl;
+ for (rld::strings::const_iterator hi = headers.begin ();
+ hi != headers.end ();
+ ++hi)
+ {
+ out << " " << (*hi) << std::endl;
+ }
+ out << " Defines: " << defines.size () << std::endl;
+ for (rld::strings::const_iterator di = defines.begin ();
+ di != defines.end ();
+ ++di)
+ {
+ out << " " << (*di) << std::endl;
+ }
+ out << " Mapping Symbol Prefix: " << map_sym_prefix << std::endl
+ << " Arg Trace Code: " << arg_trace << std::endl
+ << " Return Trace Code: " << ret_trace << std::endl
+ << " Code blocks: " << std::endl;
+ for (rld::strings::const_iterator ci = code.begin ();
+ ci != code.end ();
+ ++ci)
+ {
+ out << " > "
+ << rld::find_replace (*ci, "\n", "\n | ") << std::endl;
+ }
+ }
+
+ tracer::tracer ()
+ {
+ }
+
+ void
+ tracer::load (rld::config::config& config,
+ const std::string& tname)
+ {
+ /*
+ * The configuration must contain a "section" section. This is the top level
+ * configuration and may contain:
+ *
+ * # name The name of trace being linked.
+ * # bsp The architecture/bsp name of the BSP.
+ * # options A list of options as per the long command line args.
+ * # traces The list of sections containing function lists to trace.
+ * # functions The list of sections containing function details.
+ * # include The list of files to include.
+ *
+ * The following records are required:
+ *
+ * # name
+ * # bsp
+ * # trace
+ * # functions
+ */
+ const rld::config::section& section = config.get_section (tname);
+
+ config.includes (section);
+
+ name = section.get_record_item ("name");
+ bsp = section.get_record_item ("bsp");
+
+ load_functions (config, section);
+ load_traces (config, section);
+ }
+
+ void
+ tracer::load_functions (rld::config::config& config,
+ const rld::config::section& section)
+ {
+ rld::strings fl;
+ rld::config::parse_items (section, "functions", fl, true);
+ for (rld::strings::const_iterator fli = fl.begin ();
+ fli != fl.end ();
+ ++fli)
+ {
+ functions_.push_back (function (config, *fli));
+ }
+ }
+
+ void
+ tracer::load_traces (rld::config::config& config,
+ const rld::config::section& section)
+ {
+ parse (config, section, "traces", "trace", traces);
+
+ rld::strings gens;
+ std::string gen;
+
+ parse (config, section, "traces", "generator", gens);
+
+ if (gens.size () > 1)
+ throw rld::error ("duplicate generators", "tracer: " + section.name);
+
+ if (gens.size () == 0)
+ {
+ gen =
+ config.get_section ("default-generator").get_record_item ("generator");
+ }
+ else
+ {
+ gen = gens[0];
+ }
+
+ generator_ = generator (config, gen);
+ }
+
+ void
+ tracer::generate ()
+ {
+ rld::process::tempfile c (".c");
+
+ c.open (true);
+
+ if (rld::verbose ())
+ std::cout << "wrapper C file: " << c.name () << std::endl;
+
+ try
+ {
+ c.write_line ("/*");
+ c.write_line (" * RTEMS Trace Linker Wrapper");
+ c.write_line (" * Automatically generated.");
+ c.write_line (" */");
+
+ c.write_line ("");
+ c.write_line ("/*");
+ c.write_line (" * Generator: " + generator_.name);
+ c.write_line (" */");
+ c.write_lines (generator_.defines);
+ c.write_lines (generator_.headers);
+ c.write_line ("");
+ c.write_lines (generator_.code);
+
+ generate_traces (c);
+ }
+ catch (...)
+ {
+ c.close ();
+ throw;
+ }
+
+ c.close ();
+ }
+
+ void
+ tracer::generate_traces (rld::process::tempfile& c)
+ {
+ for (functions::const_iterator fi = functions_.begin ();
+ fi != functions_.end ();
+ ++fi)
+ {
+ const function& funcs = *fi;
+
+ for (rld::strings::const_iterator ti = traces.begin ();
+ ti != traces.end ();
+ ++ti)
+ {
+ const std::string& trace = *ti;
+ signatures::const_iterator si = funcs.signatures_.find (trace);
+
+ if (si != funcs.signatures_.end ())
+ {
+ c.write_line ("");
+ c.write_line ("/*");
+ c.write_line (" * Function: " + funcs.name);
+ c.write_line (" */");
+ c.write_lines (funcs.defines);
+ c.write_lines (funcs.headers);
+ break;
+ }
+ }
+ }
+
+ c.write_line ("");
+ c.write_line ("/*");
+ c.write_line (" * Wrappers.");
+ c.write_line (" */");
+
+ for (rld::strings::const_iterator ti = traces.begin ();
+ ti != traces.end ();
+ ++ti)
+ {
+ const std::string& trace = *ti;
+ bool found = false;
+
+ for (functions::const_iterator fi = functions_.begin ();
+ fi != functions_.end ();
+ ++fi)
+ {
+ const function& funcs = *fi;
+ signatures::const_iterator si = funcs.signatures_.find (trace);
+
+ if (si != funcs.signatures_.end ())
+ {
+ found = true;
+
+ const signature& sig = (*si).second;
+
+ c.write_line("");
+ c.write_line(sig.decl ());
+ c.write_line("{");
+
+ std::string l;
+
+ /*
+ * @todo Need to define as part of the function signature if ret
+ * processing is required.
+ */
+ if (sig.ret != "void")
+ {
+ c.write_line(" " + sig.ret + " ret;");
+ l = " ret =";
+ }
+
+ l += " " + generator_.map_sym_prefix + sig.name + '(';
+ for (size_t a = 0; a < sig.args.size (); ++a)
+ {
+ if (a)
+ l += ", ";
+ l += "a" + rld::to_string ((int) (a + 1));
+ }
+ l += ");";
+ c.write_line(l);
+
+ if (sig.ret != "void")
+ {
+ c.write_line(" return ret;");
+ }
+
+ c.write_line("}");
+ }
+ }
+
+ if (!found)
+ throw rld::error ("not found", "trace function: " + trace);
+ }
+ }
+
+ void
+ tracer::dump (std::ostream& out) const
+ {
+ out << " Tracer: " << name << std::endl
+ << " BSP: " << bsp << std::endl
+ << " Traces: " << traces.size () << std::endl;
+ for (rld::strings::const_iterator ti = traces.begin ();
+ ti != traces.end ();
+ ++ti)
+ {
+ out << " " << (*ti) << std::endl;
+ }
+ out << " Functions: " << functions_.size () << std::endl;
+ for (functions::const_iterator fi = functions_.begin ();
+ fi != functions_.end ();
+ ++fi)
+ {
+ (*fi).dump (out);
+ }
+ out << " Generator: " << std::endl;
+ generator_.dump (out);
+ }
+
+ linker::linker ()
+ {
+ }
+
+ void
+ linker::load_config (const std::string& path,
+ const std::string& trace)
+ {
+ config.clear ();
+ config.load (path);
+ tracer_.load (config, trace);
+ }
+
+ void
+ linker::generate_wrapper ()
+ {
+ tracer_.generate ();
+ }
+
+ void
+ linker::dump (std::ostream& out) const
+ {
+ const rld::config::paths& cpaths = config.get_paths ();
+ out << " Configuration Files: " << cpaths.size () << std::endl;
+ for (rld::config::paths::const_iterator pi = cpaths.begin ();
+ pi != cpaths.end ();
+ ++pi)
+ {
+ out << " " << (*pi) << std::endl;
+ }
+
+ tracer_.dump (out);
+ }
+ }
+}
+
+/**
+ * RTEMS Trace Linker options. This needs to be rewritten to be like cc where
+ * only a single '-' and long options is present. Anything after '--' is passed
+ * to RTEMS's real linker.
+ */
+static struct option rld_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "warn", no_argument, NULL, 'w' },
+ { "keep", no_argument, NULL, 'k' },
+ { "exec-prefix", required_argument, NULL, 'E' },
+ { "march", required_argument, NULL, 'a' },
+ { "mcpu", required_argument, NULL, 'c' },
+ { "config", required_argument, NULL, 'C' },
+ { NULL, 0, NULL, 0 }
+};
+
+void
+usage (int exit_code)
+{
+ std::cout << "rtems-trace-ld [options] objects" << std::endl
+ << "Options and arguments:" << std::endl
+ << " -h : help (also --help)" << std::endl
+ << " -V : print linker version number and exit (also --version)" << std::endl
+ << " -v : verbose (trace import parts), can supply multiple times" << std::endl
+ << " to increase verbosity (also --verbose)" << std::endl
+ << " -w : generate warnings (also --warn)" << std::endl
+ << " -k : keep temporary files (also --keep)" << std::endl
+ << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
+ << " -a march : machine architecture (also --march)" << std::endl
+ << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl
+ << " -C ini : user configuration INI file (also --config)" << std::endl;
+ ::exit (exit_code);
+}
+
+static void
+fatal_signal (int signum)
+{
+ signal (signum, SIG_DFL);
+
+ rld::process::temporaries_clean_up ();
+
+ /*
+ * Get the same signal again, this time not handled, so its normal effect
+ * occurs.
+ */
+ kill (getpid (), signum);
+}
+
+static void
+setup_signals (void)
+{
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_signal);
+#ifdef SIGHUP
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_signal);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_signal);
+#ifdef SIGPIPE
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, fatal_signal);
+#endif
+#ifdef SIGCHLD
+ signal (SIGCHLD, SIG_DFL);
+#endif
+}
+
+int
+main (int argc, char* argv[])
+{
+ int ec = 0;
+
+ setup_signals ();
+
+ try
+ {
+ rld::trace::linker linker;
+ std::string ld_cmd;
+ std::string configuration;
+ std::string trace = "tracer";
+ bool exec_prefix_set = false;
+#if HAVE_WARNINGS
+ bool warnings = false;
+#endif
+
+ while (true)
+ {
+ int opt = ::getopt_long (argc, argv, "hvwkVE:a:c:C:", rld_opts, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt)
+ {
+ case 'V':
+ std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
+ << std::endl;
+ ::exit (0);
+ break;
+
+ case 'v':
+ rld::verbose_inc ();
+ break;
+
+ case 'w':
+#if HAVE_WARNINGS
+ warnings = true;
+#endif
+ break;
+
+ case 'k':
+ rld::process::set_keep_temporary_files ();
+ break;
+
+ case 'E':
+ exec_prefix_set = true;
+ rld::cc::exec_prefix = optarg;
+ break;
+
+ case 'a':
+ rld::cc::march = optarg;
+ break;
+
+ case 'c':
+ rld::cc::mcpu = optarg;
+ break;
+
+ case 'C':
+ configuration = optarg;
+ break;
+
+ case '?':
+ usage (3);
+ break;
+
+ case 'h':
+ usage (0);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (rld::verbose ())
+ std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
+
+ /*
+ * Load the remaining command line arguments into the linker command line.
+ */
+ while (argc--)
+ {
+ if (ld_cmd.length () != 0)
+ ld_cmd += " ";
+ ld_cmd += *argv++;
+ }
+
+ /*
+ * If there are no object files there is nothing to link.
+ */
+ if (ld_cmd.empty ())
+ throw rld::error ("no trace linker options", "options");
+
+ /*
+ * Perform a trace link.
+ */
+ try
+ {
+ linker.load_config (configuration, trace);
+ linker.generate_wrapper ();
+
+ if (rld::verbose ())
+ linker.dump (std::cout);
+ }
+ catch (...)
+ {
+ throw;
+ }
+
+ }
+ catch (rld::error re)
+ {
+ std::cerr << "error: "
+ << re.where << ": " << re.what
+ << std::endl;
+ ec = 10;
+ }
+ catch (std::exception e)
+ {
+ int status;
+ char* realname;
+ realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
+ std::cerr << "error: exception: " << realname << " [";
+ ::free (realname);
+ const std::type_info &ti = typeid (e);
+ realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
+ std::cerr << realname << "] " << e.what () << std::endl;
+ ::free (realname);
+ ec = 11;
+ }
+ catch (...)
+ {
+ /*
+ * Helps to know if this happens.
+ */
+ std::cout << "error: unhandled exception" << std::endl;
+ ec = 12;
+ }
+
+ return ec;
+}
diff --git a/linkers/rtems-utils.cpp b/linkers/rtems-utils.cpp
new file mode 100644
index 0000000..8fda105
--- /dev/null
+++ b/linkers/rtems-utils.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup RLD
+ *
+ * @brief A memory dump routine.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iomanip>
+#include <iostream>
+#include <vector>
+
+#include <rtems-utils.h>
+
+namespace rtems
+{
+ namespace utils
+ {
+ void
+ dump (const void* addr,
+ size_t length,
+ size_t size,
+ bool real,
+ size_t line_length,
+ uint32_t offset)
+ {
+ char* data;
+ size_t b = 0;
+ uint8_t d8 = 0;
+ uint16_t d16 = 0;
+ uint32_t d32 = 0;
+ uint64_t d64 = 0;
+
+ const uint8_t* addr8 = static_cast <const uint8_t*> (addr);
+
+ data = new char[line_length];
+
+ try
+ {
+ std::cout << std::hex << std::setfill ('0');
+
+ while (true)
+ {
+ if (((b % line_length) == 0) || (b >= length))
+ {
+ if (b)
+ {
+ size_t line = b % line_length;
+
+ if (line)
+ {
+ size_t remaining = line_length - line;
+ remaining = (remaining * 2) + (remaining / size);
+ std::cout << std::setfill (' ')
+ << std::setw (remaining) << ' '
+ << std::setfill ('0');
+ }
+ else
+ line = line_length;
+
+ std::cout << ' ';
+
+ for (size_t c = 0; c < line; c++)
+ {
+ if ((data[c] < 0x20) || (data[c] > 0x7e))
+ std::cout << '.';
+ else
+ std::cout << data[c];
+ }
+
+ if (b >= length)
+ {
+ std::cout << std::dec << std::setfill (' ')
+ << std::endl << std::flush;
+ break;
+ }
+
+ std::cout << std::endl;
+ }
+
+ if (real)
+ std::cout << std::setw (sizeof(void*)) << (uint64_t) (addr8 + b);
+ else
+ std::cout << std::setw (8) << (uint32_t) (offset + b);
+ }
+
+ if ((b & (line_length - 1)) == (line_length >> 1))
+ std::cout << "-";
+ else
+ std::cout << " ";
+
+ switch (size)
+ {
+ case sizeof (uint8_t):
+ default:
+ d8 = *(addr8 + b);
+ std::cout << std::setw (2) << (uint32_t) d8;
+ data[(b % line_length) + 0] = d8;
+ break;
+
+ case sizeof (uint16_t):
+ d16 = *((const uint16_t*) (addr8 + b));
+ std::cout << std::setw (4) << d16;
+ data[(b % line_length) + 0] = (uint8_t) (d16 >> 8);
+ data[(b % line_length) + 1] = (uint8_t) d16;
+ break;
+
+ case sizeof (uint32_t):
+ d32 = *((const uint32_t*) (addr8 + b));
+ std::cout << std::setw (8) << d32;
+ for (int i = sizeof (uint32_t); i > 0; --i)
+ {
+ data[(b % line_length) + i] = (uint8_t) d32;
+ d32 >>= 8;
+ }
+ break;
+
+ case sizeof (uint64_t):
+ d64 = *((const uint64_t*) (addr8 + b));
+ std::cout << std::setw (16) << d64;
+ for (int i = sizeof (uint64_t); i > 0; --i)
+ {
+ data[(b % line_length) + i] = (uint8_t) d64;
+ d64 >>= 8;
+ }
+ break;
+ }
+ b += size;
+ }
+ }
+ catch (...)
+ {
+ delete [] data;
+ throw;
+ }
+
+ delete [] data;
+
+ std::cout << std::dec << std::setfill (' ');
+ }
+ }
+}
diff --git a/linkers/rtems-utils.h b/linkers/rtems-utils.h
new file mode 100644
index 0000000..9918570
--- /dev/null
+++ b/linkers/rtems-utils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup RLD
+ *
+ * @brief A memory dump routine.
+ *
+ */
+
+#if !defined (_MEMORY_DUMP_H_)
+#define _MEMORY_DUMP_H_
+
+#include <stdint.h>
+
+namespace rtems
+{
+ namespace utils
+ {
+ /**
+ * Hex display memory.
+ *
+ * @param addr The address of the memory to display.
+ * @param length The number of elements to display.
+ * @param size The size of the data element.
+ * @param real Use the real address based on addr.
+ * @param line_length Number of elements per line.
+ * @param offset The printed offset.
+ */
+ void dump (const void* addr,
+ size_t length,
+ size_t size,
+ bool real = false,
+ size_t line_length = 16,
+ uint32_t offset = 0);
+ }
+}
+
+#endif
diff --git a/linkers/rtems.ini b/linkers/rtems.ini
new file mode 100644
index 0000000..f2de480
--- /dev/null
+++ b/linkers/rtems.ini
@@ -0,0 +1,20 @@
+;
+; RTEMS API Trace Configurations
+;
+[rtems-api]
+headers = rtems-api-headers
+defines = rtems-api-defines
+signatures = rtems-api-signatures
+
+[rtems-api-headers]
+header = "#include <rtems.h>"
+
+[rtems-api-defines]
+; Currently empty
+
+[rtems-api-task]
+trace = rtems_task_create
+
+[rtems-api-signatures]
+rtems_task_create = rtems_status_code, rtems_name, rtems_task_priority, size_t, rtems_mode, rtems_attribute, rtems_id*
+
diff --git a/linkers/rtl-host.conf b/linkers/rtl-host.conf
new file mode 100644
index 0000000..93eae3c
--- /dev/null
+++ b/linkers/rtl-host.conf
@@ -0,0 +1,1664 @@
+# Doxyfile 1.7.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "RTEMS Linker"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.0.1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "RTEMS Tools Project"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = YES
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [0,1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+# Note that a value of 0 will completely suppress the enum values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, svg, gif or svg.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/linkers/rtld-base.ini b/linkers/rtld-base.ini
new file mode 100644
index 0000000..b574e0b
--- /dev/null
+++ b/linkers/rtld-base.ini
@@ -0,0 +1,36 @@
+;
+; RTEMS Trace Linker Base configuration.
+;
+; Copyright 2014 Chris Johns <chrisj@rtems.org>
+;
+
+;
+; The default generartor is used if a function set does provide a generator record.
+;
+[default-generator]
+generator = printf-generator
+
+;
+; A printf generator prints to stdout the trace functions.
+;
+[printf-generator]
+map-sym-prefix = rtld_pg__
+headers = printf-generator-headers
+arg-trace = "rtld_pg_print_arg(@ARG_NUM@, @ARG_TYPE@, @ARG_SIZE@, &@ARG_LABEL@);"
+ret-trace = "rtld_pg_print_ret(@RET_TYPE@, @RETG_SIZE@, &@RET_LABEL@);"
+code = <<<CODE
+static inline void rtld_pg_print_arg(int arg_num,
+ const char* arg_type,
+ int arg_size,
+ void* arg
+{
+ const char* p = arg;
+ int i;
+ printf (" %2d] %s(%d) = ", arg_num, arg_type, arg_size);
+ for (i = 0; i < arg_size; ++i, ++p) printf ("%02x", (unsigned int) *p);
+ printf ("\n");
+}
+CODE
+
+[printf-generator-headers]
+header = "#include <stdio.h>"
diff --git a/linkers/test-trace.ini b/linkers/test-trace.ini
new file mode 100644
index 0000000..a6205d2
--- /dev/null
+++ b/linkers/test-trace.ini
@@ -0,0 +1,60 @@
+;
+; RTEMS Trace Linker Test Configuration.
+;
+; We must provide a top level trace section.
+;
+[tracer]
+;
+; Name of the trace.
+;
+name = RTEMS Trace Linker Test
+;
+; The BSP.
+;
+bsp = sparc/sis
+;
+; Options can be defined here or on the command line.
+;
+options = all-funcs, verbose
+;
+; Functions to trace.
+;
+traces = test-trace, test-trace-funcs, rtems-api-task
+;
+; Define the function sets. These are the function's that can be
+; added to the trace lists.
+;
+functions = test-trace-funcs, rtems-api
+;
+; Include RTEMS Trace support.
+;
+include = rtems.ini, rtld-base.ini
+
+;
+; User application trace example.
+;
+[test-trace]
+generator = printf-generator
+; Just here for testing.
+trace = test_trace_3
+
+[test-trace-funcs]
+; Parsed via the 'function-set', not parse as a 'trace'.
+headers = test-headers
+header = '#include "test-trace-2.h"'
+defines = test-defines
+define = "#define TEST_TRACE_2 2"
+signatures = test-signatures
+; Parsed via the 'trace', not parsed as a function-set
+trace = test_trace_1, test_trace_2
+
+[test-headers]
+header = '#include "test-trace-1.h"'
+
+[test-defines]
+define = "#define TEST_TRACE_1 1"
+
+[test-signatures]
+test_trace_1 = void, int
+test_trace_2 = test_type_2, test_type_1
+test_trace_3 = float, float*
diff --git a/linkers/waf-tools/doxygen.py b/linkers/waf-tools/doxygen.py
new file mode 100644
index 0000000..bcb3280
--- /dev/null
+++ b/linkers/waf-tools/doxygen.py
@@ -0,0 +1,164 @@
+#! /usr/bin/env python
+# encoding: UTF-8
+# Thomas Nagy 2008-2010 (ita)
+
+"""
+
+Doxygen support
+
+Variables passed to bld():
+* doxyfile -- the Doxyfile to use
+
+ported from waf 1.5 (incomplete)
+"""
+
+from fnmatch import fnmatchcase
+import os, os.path, re, stat
+from waflib import Task, Utils, Node, Logs
+from waflib.TaskGen import feature
+
+DOXY_STR = '${DOXYGEN} - '
+DOXY_FMTS = 'html latex man rft xml'.split()
+DOXY_FILE_PATTERNS = '*.' + ' *.'.join('''
+c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx hpp h++ idl odl cs php php3
+inc m mm py f90c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx
+'''.split())
+
+re_nl = re.compile('\\\\\r*\n', re.MULTILINE)
+
+class doxygen(Task.Task):
+ vars = ['DOXYGEN', 'DOXYFLAGS']
+ color = 'BLUE'
+
+ def runnable_status(self):
+ '''
+ self.pars are populated in runnable_status - because this function is being
+ run *before* both self.pars "consumers" - scan() and run()
+
+ set output_dir (node) for the output
+ '''
+
+ for x in self.run_after:
+ if not x.hasrun:
+ return Task.ASK_LATER
+
+ if not getattr(self, 'pars', None):
+ txt = self.inputs[0].read()
+ txt = re_nl.sub('', txt)
+ self.pars = Utils.str_to_dict(txt)
+ if not self.pars.get('OUTPUT_DIRECTORY'):
+ self.pars['OUTPUT_DIRECTORY'] = self.inputs[0].parent.get_bld().abspath()
+ if not self.pars.get('INPUT'):
+ self.pars['INPUT'] = self.inputs[0].parent.abspath()
+
+ if not getattr(self, 'output_dir', None):
+ bld = self.generator.bld
+ # First try to find an absolute path, then find or declare a relative path
+ self.output_dir = bld.root.find_dir(self.pars['OUTPUT_DIRECTORY'])
+ if not self.output_dir:
+ self.output_dir = bld.path.find_or_declare(self.pars['OUTPUT_DIRECTORY'])
+
+
+ self.signature()
+ return Task.Task.runnable_status(self)
+
+ def scan(self):
+ if self.pars.get('RECURSIVE') == 'YES':
+ Logs.warn("Doxygen RECURSIVE dependencies are not supported")
+
+ inputs = self.pars.get('INPUT').split()
+ exclude_patterns = self.pars.get('EXCLUDE_PATTERNS', '').split()
+ file_patterns = self.pars.get('FILE_PATTERNS', '').split()
+ if not file_patterns:
+ file_patterns = DOXY_FILE_PATTERNS
+
+ nodes = []
+ names = []
+ for i in inputs:
+ node = self.generator.bld.root.make_node(i)
+ if node:
+ if os.path.isdir(node.abspath()):
+ for m in node.ant_glob(file_patterns):
+ nodes.append(self.generator.bld.root.make_node(m.abspath()))
+ else:
+ nodes.append(node)
+ else:
+ names.append(i)
+
+ return (nodes, names)
+
+ def run(self):
+ code = '\n'.join(['%s = %s' % (x, self.pars[x]) for x in self.pars])
+ code = code.encode() # for python 3
+ #fmt = DOXY_STR % (self.inputs[0].parent.abspath())
+ cmd = Utils.subst_vars(DOXY_STR, self.env)
+ env = self.env.env or None
+ proc = Utils.subprocess.Popen(cmd, shell=True, stdin=Utils.subprocess.PIPE, env=env, cwd=self.generator.bld.path.get_bld().abspath())
+ proc.communicate(code)
+ return proc.returncode
+
+ def post_run(self):
+ nodes = self.output_dir.ant_glob('**/*')
+ for x in nodes:
+ x.sig = Utils.h_file(x.abspath())
+ self.outputs += nodes
+ return Task.Task.post_run(self)
+
+ #def install(self):
+ # if getattr(self.generator, 'install_to', None):
+ # update_build_dir(self.inputs[0].parent, self.env)
+ # pattern = getattr(self, 'instype', 'html/*')
+ # self.generator.bld.install_files(self.generator.install_to, self.generator.path.ant_glob(pattern, dir=0, src=0))
+
+class tar(Task.Task):
+ "quick tar creation"
+ run_str = '${TAR} ${TAROPTS} ${TGT} ${SRC}'
+ color = 'RED'
+ after = ['doxygen']
+ def runnable_status(self):
+ for x in getattr(self, 'input_tasks', []):
+ if not x.hasrun:
+ return Task.ASK_LATER
+
+ if not getattr(self, 'tar_done_adding', None):
+ # execute this only once
+ self.tar_done_adding = True
+ for x in getattr(self, 'input_tasks', []):
+ self.set_inputs(x.outputs)
+ if not self.inputs:
+ return Task.SKIP_ME
+ return Task.Task.runnable_status(self)
+
+ def __str__(self):
+ tgt_str = ' '.join([a.nice_path(self.env) for a in self.outputs])
+ return '%s: %s\n' % (self.__class__.__name__, tgt_str)
+
+@feature('doxygen')
+def process_doxy(self):
+ if not getattr(self, 'doxyfile', None):
+ self.generator.bld.fatal('no doxyfile??')
+
+ node = self.doxyfile
+ if not isinstance(node, Node.Node):
+ node = self.path.find_resource(node)
+ if not node:
+ raise ValueError('doxygen file not found')
+
+ # the task instance
+ dsk = self.create_task('doxygen', node)
+
+ if getattr(self, 'doxy_tar', None):
+ tsk = self.create_task('tar')
+ tsk.input_tasks = [dsk]
+ tsk.set_outputs(self.path.find_or_declare(self.doxy_tar))
+ if self.doxy_tar.endswith('bz2'):
+ tsk.env['TAROPTS'] = ['cjf']
+ elif self.doxy_tar.endswith('gz'):
+ tsk.env['TAROPTS'] = ['czf']
+ else:
+ tsk.env['TAROPTS'] = ['cf']
+
+def configure(conf):
+ conf.find_program('doxygen', var='DOXYGEN')
+ conf.find_program('tar', var='TAR')
+
diff --git a/linkers/win32/ar.h b/linkers/win32/ar.h
new file mode 100644
index 0000000..e04874f
--- /dev/null
+++ b/linkers/win32/ar.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Hugh Smith at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)ar.h 8.2 (Berkeley) 1/21/94
+ */
+
+#ifndef _AR_H_
+#define _AR_H_
+
+/* Pre-4BSD archives had these magic numbers in them. */
+#define OARMAG1 0177555
+#define OARMAG2 0177545
+
+#define ARMAG "!<arch>\n" /* ar "magic number" */
+#define SARMAG 8 /* strlen(ARMAG); */
+
+#define AR_EFMT1 "#1/" /* extended format #1 */
+
+struct ar_hdr {
+ char ar_name[16]; /* name */
+ char ar_date[12]; /* modification time */
+ char ar_uid[6]; /* user id */
+ char ar_gid[6]; /* group id */
+ char ar_mode[8]; /* octal file permissions */
+ char ar_size[10]; /* size in bytes */
+#define ARFMAG "`\n"
+ char ar_fmag[2]; /* consistency check */
+};
+
+#endif /* !_AR_H_ */
diff --git a/linkers/win32/sys/cdefs.h b/linkers/win32/sys/cdefs.h
new file mode 100644
index 0000000..c96b517
--- /dev/null
+++ b/linkers/win32/sys/cdefs.h
@@ -0,0 +1,64 @@
+#ifndef _CDEFS_H_
+#define _CDEFS_H_
+
+#include <stddef.h>
+
+/*
+ * Taken from FreeBSD 9.
+ */
+
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS }
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+/*
+ * Macro to test if we're using a specific version of gcc or later.
+ */
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+#define __GNUC_PREREQ__(ma, mi) \
+ (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi))
+#else
+#define __GNUC_PREREQ__(ma, mi) 0
+#endif
+
+/*
+ * We define this here since <stddef.h>, <sys/queue.h>, and <sys/types.h>
+ * require it.
+ */
+#if __GNUC_PREREQ__(4, 1)
+#define __offsetof(type, field) __builtin_offsetof(type, field)
+#else
+#ifndef __cplusplus
+#define __offsetof(type, field) ((size_t)(&((type *)0)->field))
+#else
+#define __offsetof(type, field) \
+ (__offsetof__ (reinterpret_cast <size_t> \
+ (&reinterpret_cast <const volatile char &> \
+ (static_cast<type *> (0)->field))))
+#endif
+#endif
+#define __rangeof(type, start, end) \
+ (__offsetof(type, end) - __offsetof(type, start))
+
+/*
+ * Hack. Have to put this somewhere.
+ */
+typedef int gid_t;
+typedef int uid_t;
+
+/* Macros for counting and rounding. */
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define rounddown(x, y) (((x)/(y))*(y))
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */
+#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
+#define powerof2(x) ((((x)-1)&(x))==0)
+
+#define S_ISSOCK(_m) (0)
+
+#endif
diff --git a/linkers/win32/sys/errno.h b/linkers/win32/sys/errno.h
new file mode 100644
index 0000000..339f4fc
--- /dev/null
+++ b/linkers/win32/sys/errno.h
@@ -0,0 +1 @@
+#include <errno.h>
diff --git a/linkers/win32/sys/mman.h b/linkers/win32/sys/mman.h
new file mode 100644
index 0000000..1882085
--- /dev/null
+++ b/linkers/win32/sys/mman.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)mman.h 8.2 (Berkeley) 1/9/95
+ * $FreeBSD: releng/9.0/sys/sys/mman.h 211937 2010-08-28 16:57:07Z alc $
+ */
+
+#ifndef _SYS_MMAN_H_
+#define _SYS_MMAN_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/*
+ * Protections are chosen from these bits, or-ed together
+ */
+#define PROT_NONE 0x00 /* no permissions */
+#define PROT_READ 0x01 /* pages can be read */
+#define PROT_WRITE 0x02 /* pages can be written */
+#define PROT_EXEC 0x04 /* pages can be executed */
+
+/*
+ * Flags contain sharing type and options.
+ * Sharing types; choose one.
+ */
+#define MAP_SHARED 0x0001 /* share changes */
+#define MAP_PRIVATE 0x0002 /* changes are private */
+
+/*
+ * Other flags
+ */
+#define MAP_FIXED 0x0010 /* map addr must be exactly as requested */
+
+/*
+ * Mapping type
+ */
+#define MAP_FILE 0x0000 /* map from file (default) */
+#define MAP_ANON 0x1000 /* allocated from memory, swap space */
+
+/*
+ * Error return from mmap()
+ */
+#define MAP_FAILED ((void *)-1)
+
+/*
+ * msync() flags
+ */
+#define MS_SYNC 0x0000 /* msync synchronously */
+#define MS_ASYNC 0x0001 /* return immediately */
+#define MS_INVALIDATE 0x0002 /* invalidate all cached data */
+
+__BEGIN_DECLS
+#ifndef _MMAP_DECLARED
+#define _MMAP_DECLARED
+void * mmap(void *, size_t, int, int, int, off_t);
+#endif
+#if NOT_IMPLEMENTED
+int mprotect(const void *, size_t, int);
+int msync(void *, size_t, int);
+int munlock(const void *, size_t);
+#endif
+int munmap(void *, size_t);
+__END_DECLS
+
+#endif /* !_SYS_MMAN_H_ */
diff --git a/linkers/win32/sys/queue.h b/linkers/win32/sys/queue.h
new file mode 100644
index 0000000..4ff0883
--- /dev/null
+++ b/linkers/win32/sys/queue.h
@@ -0,0 +1,637 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ * $FreeBSD: releng/9.0/sys/sys/queue.h 221843 2011-05-13 15:49:23Z mdf $
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+#include <sys/cdefs.h>
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ * SLIST LIST STAILQ TAILQ
+ * _HEAD + + + +
+ * _HEAD_INITIALIZER + + + +
+ * _ENTRY + + + +
+ * _INIT + + + +
+ * _EMPTY + + + +
+ * _FIRST + + + +
+ * _NEXT + + + +
+ * _PREV - - - +
+ * _LAST - - + +
+ * _FOREACH + + + +
+ * _FOREACH_SAFE + + + +
+ * _FOREACH_REVERSE - - - +
+ * _FOREACH_REVERSE_SAFE - - - +
+ * _INSERT_HEAD + + + +
+ * _INSERT_BEFORE - + - +
+ * _INSERT_AFTER + + + +
+ * _INSERT_TAIL - - + +
+ * _CONCAT - - + +
+ * _REMOVE_AFTER + - + -
+ * _REMOVE_HEAD + - + -
+ * _REMOVE + + + +
+ * _SWAP + + + +
+ *
+ */
+#ifdef QUEUE_MACRO_DEBUG
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace {
+ char * lastfile;
+ int lastline;
+ char * prevfile;
+ int prevline;
+};
+
+#define TRACEBUF struct qm_trace trace;
+#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
+#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
+
+#define QMD_TRACE_HEAD(head) do { \
+ (head)->trace.prevline = (head)->trace.lastline; \
+ (head)->trace.prevfile = (head)->trace.lastfile; \
+ (head)->trace.lastline = __LINE__; \
+ (head)->trace.lastfile = __FILE__; \
+} while (0)
+
+#define QMD_TRACE_ELEM(elem) do { \
+ (elem)->trace.prevline = (elem)->trace.lastline; \
+ (elem)->trace.prevfile = (elem)->trace.lastfile; \
+ (elem)->trace.lastline = __LINE__; \
+ (elem)->trace.lastfile = __FILE__; \
+} while (0)
+
+#else
+#define QMD_TRACE_ELEM(elem)
+#define QMD_TRACE_HEAD(head)
+#define QMD_SAVELINK(name, link)
+#define TRACEBUF
+#define TRASHIT(x)
+#endif /* QUEUE_MACRO_DEBUG */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var) && ((tvar) = SLIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
+ for ((varp) = &SLIST_FIRST((head)); \
+ ((var) = *(varp)) != NULL; \
+ (varp) = &SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do { \
+ SLIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+ SLIST_FIRST((head)) = (elm); \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
+ if (SLIST_FIRST((head)) == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = SLIST_FIRST((head)); \
+ while (SLIST_NEXT(curelm, field) != (elm)) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_REMOVE_AFTER(curelm, field); \
+ } \
+ TRASHIT(*oldnext); \
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do { \
+ SLIST_NEXT(elm, field) = \
+ SLIST_NEXT(SLIST_NEXT(elm, field), field); \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
+#define SLIST_SWAP(head1, head2, type) do { \
+ struct type *swap_first = SLIST_FIRST(head1); \
+ SLIST_FIRST(head1) = SLIST_FIRST(head2); \
+ SLIST_FIRST(head2) = swap_first; \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first;/* first element */ \
+ struct type **stqh_last;/* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_CONCAT(head1, head2) do { \
+ if (!STAILQ_EMPTY((head2))) { \
+ *(head1)->stqh_last = (head2)->stqh_first; \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_INIT((head2)); \
+ } \
+} while (0)
+
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for((var) = STAILQ_FIRST((head)); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_INIT(head) do { \
+ STAILQ_FIRST((head)) = NULL; \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_NEXT((tqelm), field) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ STAILQ_NEXT((elm), field) = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *)(void *) \
+ ((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
+ if (STAILQ_FIRST((head)) == (elm)) { \
+ STAILQ_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = STAILQ_FIRST((head)); \
+ while (STAILQ_NEXT(curelm, field) != (elm)) \
+ curelm = STAILQ_NEXT(curelm, field); \
+ STAILQ_REMOVE_AFTER(head, curelm, field); \
+ } \
+ TRASHIT(*oldnext); \
+} while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
+ if ((STAILQ_NEXT(elm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if ((STAILQ_FIRST((head)) = \
+ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_SWAP(head1, head2, type) do { \
+ struct type *swap_first = STAILQ_FIRST(head1); \
+ struct type **swap_last = (head1)->stqh_last; \
+ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_FIRST(head2) = swap_first; \
+ (head2)->stqh_last = swap_last; \
+ if (STAILQ_EMPTY(head1)) \
+ (head1)->stqh_last = &STAILQ_FIRST(head1); \
+ if (STAILQ_EMPTY(head2)) \
+ (head2)->stqh_last = &STAILQ_FIRST(head2); \
+} while (0)
+
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_LIST_CHECK_HEAD(head, field) do { \
+ if (LIST_FIRST((head)) != NULL && \
+ LIST_FIRST((head))->field.le_prev != \
+ &LIST_FIRST((head))) \
+ panic("Bad list head %p first->prev != head", (head)); \
+} while (0)
+
+#define QMD_LIST_CHECK_NEXT(elm, field) do { \
+ if (LIST_NEXT((elm), field) != NULL && \
+ LIST_NEXT((elm), field)->field.le_prev != \
+ &((elm)->field.le_next)) \
+ panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+#define QMD_LIST_CHECK_PREV(elm, field) do { \
+ if (*(elm)->field.le_prev != (elm)) \
+ panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_LIST_CHECK_HEAD(head, field)
+#define QMD_LIST_CHECK_NEXT(elm, field)
+#define QMD_LIST_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = LIST_FIRST((head)); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST((head)); \
+ (var) && ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_INIT(head) do { \
+ LIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ QMD_LIST_CHECK_NEXT(listelm, field); \
+ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+ LIST_NEXT((listelm), field)->field.le_prev = \
+ &LIST_NEXT((elm), field); \
+ LIST_NEXT((listelm), field) = (elm); \
+ (elm)->field.le_prev = &LIST_NEXT((listelm), field); \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ QMD_LIST_CHECK_PREV(listelm, field); \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ LIST_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &LIST_NEXT((elm), field); \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ QMD_LIST_CHECK_HEAD((head), field); \
+ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
+ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+ LIST_FIRST((head)) = (elm); \
+ (elm)->field.le_prev = &LIST_FIRST((head)); \
+} while (0)
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.le_next); \
+ QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
+ QMD_LIST_CHECK_NEXT(elm, field); \
+ QMD_LIST_CHECK_PREV(elm, field); \
+ if (LIST_NEXT((elm), field) != NULL) \
+ LIST_NEXT((elm), field)->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = LIST_NEXT((elm), field); \
+ TRASHIT(*oldnext); \
+ TRASHIT(*oldprev); \
+} while (0)
+
+#define LIST_SWAP(head1, head2, type, field) do { \
+ struct type *swap_tmp = LIST_FIRST((head1)); \
+ LIST_FIRST((head1)) = LIST_FIRST((head2)); \
+ LIST_FIRST((head2)) = swap_tmp; \
+ if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
+ swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
+ if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
+ swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+ TRACEBUF \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+ TRACEBUF \
+}
+
+/*
+ * Tail queue functions.
+ */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
+ if (!TAILQ_EMPTY(head) && \
+ TAILQ_FIRST((head))->field.tqe_prev != \
+ &TAILQ_FIRST((head))) \
+ panic("Bad tailq head %p first->prev != head", (head)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
+ if (*(head)->tqh_last != NULL) \
+ panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
+ if (TAILQ_NEXT((elm), field) != NULL && \
+ TAILQ_NEXT((elm), field)->field.tqe_prev != \
+ &((elm)->field.tqe_next)) \
+ panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
+ if (*(elm)->field.tqe_prev != (elm)) \
+ panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_TAILQ_CHECK_HEAD(head, field)
+#define QMD_TAILQ_CHECK_TAIL(head, headname)
+#define QMD_TAILQ_CHECK_NEXT(elm, field)
+#define QMD_TAILQ_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define TAILQ_CONCAT(head1, head2, field) do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ QMD_TRACE_HEAD(head1); \
+ QMD_TRACE_HEAD(head2); \
+ } \
+} while (0)
+
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_INIT(head) do { \
+ TAILQ_FIRST((head)) = NULL; \
+ (head)->tqh_last = &TAILQ_FIRST((head)); \
+ QMD_TRACE_HEAD(head); \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ QMD_TAILQ_CHECK_NEXT(listelm, field); \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else { \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ QMD_TRACE_HEAD(head); \
+ } \
+ TAILQ_NEXT((listelm), field) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+ QMD_TRACE_ELEM(&listelm->field); \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ QMD_TAILQ_CHECK_PREV(listelm, field); \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ TAILQ_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+ QMD_TRACE_ELEM(&listelm->field); \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ QMD_TAILQ_CHECK_HEAD(head, field); \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
+ TAILQ_FIRST((head))->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_FIRST((head)) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
+ QMD_TRACE_HEAD(head); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ QMD_TAILQ_CHECK_TAIL(head, field); \
+ TAILQ_NEXT((elm), field) = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ QMD_TRACE_HEAD(head); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+} while (0)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
+ QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
+ QMD_TAILQ_CHECK_NEXT(elm, field); \
+ QMD_TAILQ_CHECK_PREV(elm, field); \
+ if ((TAILQ_NEXT((elm), field)) != NULL) \
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else { \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ QMD_TRACE_HEAD(head); \
+ } \
+ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
+ TRASHIT(*oldnext); \
+ TRASHIT(*oldprev); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+} while (0)
+
+#define TAILQ_SWAP(head1, head2, type, field) do { \
+ struct type *swap_first = (head1)->tqh_first; \
+ struct type **swap_last = (head1)->tqh_last; \
+ (head1)->tqh_first = (head2)->tqh_first; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ (head2)->tqh_first = swap_first; \
+ (head2)->tqh_last = swap_last; \
+ if ((swap_first = (head1)->tqh_first) != NULL) \
+ swap_first->field.tqe_prev = &(head1)->tqh_first; \
+ else \
+ (head1)->tqh_last = &(head1)->tqh_first; \
+ if ((swap_first = (head2)->tqh_first) != NULL) \
+ swap_first->field.tqe_prev = &(head2)->tqh_first; \
+ else \
+ (head2)->tqh_last = &(head2)->tqh_first; \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/linkers/wscript b/linkers/wscript
new file mode 100644
index 0000000..c6d1d31
--- /dev/null
+++ b/linkers/wscript
@@ -0,0 +1,392 @@
+#
+# RTEMS Linker build script.
+#
+import sys
+
+version_major = 1
+version_minor = 0
+version_revision = 0
+
+#
+# Waf system setup. Allow more than one build in the same tree.
+#
+top = '.'
+out = 'build-' + sys.platform
+
+def options(opt):
+ opt.load("g++")
+ opt.load("gcc")
+ opt.add_option('--rtems-version',
+ default = '4.11',
+ dest='rtems_version',
+ help = 'Set the RTEMS version')
+ opt.add_option('--c-opts',
+ default = '-O2',
+ dest='c_opts',
+ help = 'Set build options, default: -O2.')
+ opt.add_option('--show-commands',
+ action = 'store_true',
+ default = False,
+ dest = 'show_commands',
+ help = 'Print the commands as strings.')
+
+def configure(conf):
+ try:
+ conf.load("doxygen", tooldir = 'waf-tools')
+ except:
+ pass
+ conf.load("g++")
+ conf.load("gcc")
+ conf_libiberty(conf)
+ conf_libelf(conf)
+
+ conf.check(header_name='sys/wait.h', features = 'c', mandatory = False)
+ conf.check_cc(function_name='kill', header_name="signal.h",
+ features = 'c', mandatory = False)
+ conf.write_config_header('config.h')
+
+ conf.env.C_OPTS = conf.options.c_opts.split(',')
+ conf.env.RTEMS_VERSION = conf.options.rtems_version
+
+ if conf.options.show_commands:
+ show_commands = 'yes'
+ else:
+ show_commands = 'no'
+ conf.env.SHOW_COMMANDS = show_commands
+
+def build(bld):
+ #
+ # Build the doxygen documentation.
+ #
+ if bld.cmd == 'doxy':
+ bld(features = 'doxygen',
+ doxyfile = 'rtl-host.conf')
+ return
+
+ if bld.env.SHOW_COMMANDS == 'yes':
+ output_command_line()
+
+ #
+ # The include paths.
+ #
+ bld.includes = ['elftoolchain/libelf', 'elftoolchain/common', 'libiberty']
+ if sys.platform == 'win32':
+ bld.includes += ['win32']
+
+ #
+ # Build flags.
+ #
+ bld.warningflags = ['-Wall', '-Wextra', '-pedantic']
+ bld.optflags = bld.env.C_OPTS
+ bld.cflags = ['-pipe', '-g'] + bld.optflags
+ bld.cxxflags = ['-pipe', '-g'] + bld.optflags
+ bld.linkflags = ['-g']
+
+ #
+ # Create each of the modules as object files each with their own
+ # configurations.
+ #
+ bld_fastlz(bld)
+ bld_libelf(bld)
+ bld_libiberty(bld)
+
+ #
+ # RLD source.
+ #
+ rld_source = ['ConvertUTF.c',
+ 'rld-config.cpp',
+ 'rld-elf.cpp',
+ 'rld-files.cpp',
+ 'rld-cc.cpp',
+ 'rld-compression.cpp',
+ 'rld-outputter.cpp',
+ 'rld-process.cpp',
+ 'rld-resolver.cpp',
+ 'rld-symbols.cpp',
+ 'rld-rap.cpp',
+ 'rld.cpp']
+
+ #
+ # RTEMS Utilities.
+ #
+ rtems_utils = ['rtems-utils.cpp']
+
+ #
+ # RTL static library
+ #
+ bld.stlib(target = 'rld',
+ source = rld_source + rtems_utils,
+ defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
+ includes = ['.'] + bld.includes,
+ cflags = bld.cflags + bld.warningflags,
+ cxxflags = bld.cxxflags + bld.warningflags,
+ linkflags = bld.linkflags)
+
+ #
+ # The list of modules.
+ #
+ modules = ['rld', 'fastlz', 'elf', 'iberty']
+
+ #
+ # Build the linker.
+ #
+ bld.program(target = 'rtems-ld',
+ source = ['rtems-ld.cpp', 'pkgconfig.cpp'],
+ defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
+ includes = ['.'] + bld.includes,
+ cflags = bld.cflags + bld.warningflags,
+ cxxflags = bld.cxxflags + bld.warningflags,
+ linkflags = bld.linkflags,
+ use = modules)
+
+ #
+ # Build the ra linker.
+ #
+ bld.program(target = 'rtems-ra',
+ source = ['rtems-ra.cpp', 'pkgconfig.cpp'],
+ defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
+ includes = ['.'] + bld.includes,
+ cflags = bld.cflags + bld.warningflags,
+ cxxflags = bld.cxxflags + bld.warningflags,
+ linkflags = bld.linkflags,
+ use = modules)
+
+ #
+ # Build the trace linker.
+ #
+ bld.program(target = 'rtems-tld',
+ source = ['rtems-tld.cpp'],
+ defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
+ includes = ['.'] + bld.includes,
+ cflags = bld.cflags + bld.warningflags,
+ cxxflags = bld.cxxflags + bld.warningflags,
+ linkflags = bld.linkflags,
+ use = modules)
+
+ #
+ # Build the symbols.
+ #
+ bld.program(target = 'rtems-syms',
+ source = ['rtems-syms.cpp'],
+ defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
+ includes = ['.'] + bld.includes,
+ cflags = bld.cflags + bld.warningflags,
+ cxxflags = bld.cxxflags + bld.warningflags,
+ linkflags = bld.linkflags,
+ use = modules)
+
+ #
+ # Build the RAP utility.
+ #
+ bld.program(target = 'rtems-rap',
+ source = ['rtems-rapper.cpp'],
+ defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
+ includes = ['.'] + bld.includes,
+ cflags = bld.cflags + bld.warningflags,
+ cxxflags = bld.cxxflags + bld.warningflags,
+ linkflags = bld.linkflags,
+ use = modules)
+
+def rebuild(ctx):
+ import waflib.Options
+ waflib.Options.commands.extend(['clean', 'build'])
+
+def tags(ctx):
+ ctx.exec_command('etags $(find . -name \*.[sSch])', shell = True)
+
+#
+# Libelf module.
+#
+def conf_libelf(conf):
+ pass
+
+def bld_fastlz(bld):
+ bld(target = 'fastlz',
+ features = 'c',
+ source = 'fastlz.c',
+ cflags = bld.cflags,
+ defines = ['FASTLZ_LEVEL=1'])
+
+def bld_libelf(bld):
+ libelf = 'elftoolchain/libelf/'
+
+ #
+ # Work around the ${SRC} having Windows slashes which the MSYS m4 does not
+ # understand.
+ #
+ if sys.platform == 'win32':
+ m4_rule = 'type ${SRC} | m4 -D SRCDIR=../' + libelf[:-1] + '> ${TGT}"'
+ includes = ['win32']
+ else:
+ m4_rule = 'm4 -D SRCDIR=../' + libelf[:-1] + ' ${SRC} > ${TGT}'
+ includes = []
+
+ bld(target = 'libelf_convert.c', source = libelf + 'libelf_convert.m4', rule = m4_rule)
+ bld(target = 'libelf_fsize.c', source = libelf + 'libelf_fsize.m4', rule = m4_rule)
+ bld(target = 'libelf_msize.c', source = libelf + 'libelf_msize.m4', rule = m4_rule)
+
+ host_source = []
+
+ if sys.platform == 'linux2':
+ common = 'elftoolchain/common/'
+ bld(target = common + 'native-elf-format.h',
+ source = common + 'native-elf-format',
+ name = 'native-elf-format',
+ rule = './${SRC} > ${TGT}')
+ bld.add_group ()
+ elif sys.platform == 'win32':
+ host_source += [libelf + 'mmap_win32.c']
+
+ bld.stlib(target = 'elf',
+ features = 'c',
+ uses = ['native-elf-format'],
+ includes = [bld.bldnode.abspath(), 'elftoolchain/libelf', 'elftoolchain/common'] + includes,
+ cflags = bld.cflags,
+ source =[libelf + 'elf.c',
+ libelf + 'elf_begin.c',
+ libelf + 'elf_cntl.c',
+ libelf + 'elf_end.c',
+ libelf + 'elf_errmsg.c',
+ libelf + 'elf_errno.c',
+ libelf + 'elf_data.c',
+ libelf + 'elf_fill.c',
+ libelf + 'elf_flag.c',
+ libelf + 'elf_getarhdr.c',
+ libelf + 'elf_getarsym.c',
+ libelf + 'elf_getbase.c',
+ libelf + 'elf_getident.c',
+ libelf + 'elf_hash.c',
+ libelf + 'elf_kind.c',
+ libelf + 'elf_memory.c',
+ libelf + 'elf_next.c',
+ libelf + 'elf_rand.c',
+ libelf + 'elf_rawfile.c',
+ libelf + 'elf_phnum.c',
+ libelf + 'elf_shnum.c',
+ libelf + 'elf_shstrndx.c',
+ libelf + 'elf_scn.c',
+ libelf + 'elf_strptr.c',
+ libelf + 'elf_update.c',
+ libelf + 'elf_version.c',
+ libelf + 'gelf_cap.c',
+ libelf + 'gelf_checksum.c',
+ libelf + 'gelf_dyn.c',
+ libelf + 'gelf_ehdr.c',
+ libelf + 'gelf_getclass.c',
+ libelf + 'gelf_fsize.c',
+ libelf + 'gelf_move.c',
+ libelf + 'gelf_phdr.c',
+ libelf + 'gelf_rel.c',
+ libelf + 'gelf_rela.c',
+ libelf + 'gelf_shdr.c',
+ libelf + 'gelf_sym.c',
+ libelf + 'gelf_syminfo.c',
+ libelf + 'gelf_symshndx.c',
+ libelf + 'gelf_xlate.c',
+ libelf + 'libelf_align.c',
+ libelf + 'libelf_allocate.c',
+ libelf + 'libelf_ar.c',
+ libelf + 'libelf_ar_util.c',
+ libelf + 'libelf_checksum.c',
+ libelf + 'libelf_data.c',
+ libelf + 'libelf_ehdr.c',
+ libelf + 'libelf_extended.c',
+ libelf + 'libelf_phdr.c',
+ libelf + 'libelf_shdr.c',
+ libelf + 'libelf_xlate.c',
+ 'libelf_convert.c',
+ 'libelf_fsize.c',
+ 'libelf_msize.c'] + host_source)
+
+#
+# Libiberty module.
+#
+def conf_libiberty(conf):
+ conf.check(header_name='alloca.h', features = 'c', mandatory = False)
+ conf.check(header_name='fcntl.h', features = 'c', mandatory = False)
+ conf.check(header_name='process.h', features = 'c', mandatory = False)
+ conf.check(header_name='stdlib.h', features = 'c')
+ conf.check(header_name='string.h', features = 'c')
+ conf.check(header_name='strings.h', features = 'c', mandatory = False)
+ conf.check(header_name='sys/file.h', features = 'c', mandatory = False)
+ conf.check(header_name='sys/stat.h', features = 'c', mandatory = False)
+ conf.check(header_name='sys/time.h', features = 'c', mandatory = False)
+ conf.check(header_name='sys/types.h', features = 'c', mandatory = False)
+ conf.check(header_name='sys/wait.h', features = 'c', mandatory = False)
+ conf.check(header_name='unistd.h', features = 'c', mandatory = False)
+ conf.check(header_name='vfork.h', features = 'c', mandatory = False)
+
+ conf.check_cc(function_name='getrusage',
+ header_name="sys/time.h sys/resource.h",
+ features = 'c', mandatory = False)
+
+ conf.write_config_header('libiberty/config.h')
+
+def bld_libiberty(bld):
+ if sys.platform == 'win32':
+ pex_host = 'libiberty/pex-win32.c'
+ else:
+ pex_host = 'libiberty/pex-unix.c'
+ bld.stlib(target = 'iberty',
+ features = 'c',
+ includes = ['libiberty'],
+ cflags = bld.cflags,
+ defines = ['HAVE_CONFIG_H=1'],
+ source =['libiberty/concat.c',
+ 'libiberty/cplus-dem.c',
+ 'libiberty/cp-demangle.c',
+ 'libiberty/make-temp-file.c',
+ 'libiberty/mkstemps.c',
+ 'libiberty/safe-ctype.c',
+ 'libiberty/stpcpy.c',
+ 'libiberty/pex-common.c',
+ 'libiberty/pex-one.c',
+ pex_host])
+
+#
+# From the demos. Use this to get the command to cut+paste to play.
+#
+def output_command_line():
+ # first, display strings, people like them
+ from waflib import Utils, Logs
+ from waflib.Context import Context
+ def exec_command(self, cmd, **kw):
+ subprocess = Utils.subprocess
+ kw['shell'] = isinstance(cmd, str)
+ if isinstance(cmd, str):
+ Logs.info('%s' % cmd)
+ else:
+ Logs.info('%s' % ' '.join(cmd)) # here is the change
+ Logs.debug('runner_env: kw=%s' % kw)
+ try:
+ if self.logger:
+ self.logger.info(cmd)
+ kw['stdout'] = kw['stderr'] = subprocess.PIPE
+ p = subprocess.Popen(cmd, **kw)
+ (out, err) = p.communicate()
+ if out:
+ self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1'))
+ if err:
+ self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1'))
+ return p.returncode
+ else:
+ p = subprocess.Popen(cmd, **kw)
+ return p.wait()
+ except OSError:
+ return -1
+ Context.exec_command = exec_command
+
+ # Change the outputs for tasks too
+ from waflib.Task import Task
+ def display(self):
+ return '' # no output on empty strings
+
+ Task.__str__ = display
+
+#
+# The doxy command.
+#
+from waflib import Build
+class doxy(Build.BuildContext):
+ fun = 'build'
+ cmd = 'doxy'