diff options
author | Chris Johns <chrisj@rtems.org> | 2014-08-27 04:34:34 +0000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2014-08-27 04:34:34 +0000 |
commit | df4a99d166c666c3c05af40ac05c038afc03cc5c (patch) | |
tree | ced658e63df818ddae19f43bdcc47ed5e2754f3f | |
parent | 3162858a3a0ec414d2b5ce3d9153ca0efb2c9d27 (diff) | |
parent | 097f1fdf569e631f5fae95f27e0ec2a2f626bcbc (diff) |
linkers: Merge branch 'chrisj/rtl-host.git' into rtems-tools.git.
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 = ∅ + 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 = ¶m; + 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' |