| /* Copyright (C) 2007-2010 The Android Open Source Project | |
| ** | |
| ** This software is licensed under the terms of the GNU General Public | |
| ** License version 2, as published by the Free Software Foundation, and | |
| ** may be copied, distributed, and modified under those terms. | |
| ** | |
| ** 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. | |
| */ | |
| /* | |
| * Contains declarations of types, constants and structures | |
| * describing DWARF format. | |
| */ | |
| #ifndef ELFF_DWARF_DEFS_H_ | |
| #define ELFF_DWARF_DEFS_H_ | |
| #include "dwarf.h" | |
| #include "elf_defs.h" | |
| /* DWARF structures are packed to 1 byte. */ | |
| #define ELFF_PACKED __attribute__ ((packed)) | |
| /* | |
| * Helper types for misc. DWARF variables. | |
| */ | |
| /* Type for DWARF abbreviation number. */ | |
| typedef uint32_t Dwarf_AbbrNum; | |
| /* Type for DWARF tag ID. */ | |
| typedef uint16_t Dwarf_Tag; | |
| /* Type for DWARF attribute ID. */ | |
| typedef uint16_t Dwarf_At; | |
| /* Type for DWARF form ID. */ | |
| typedef uint16_t Dwarf_Form; | |
| /* Type for offset in 32-bit DWARF. */ | |
| typedef uint32_t Dwarf32_Off; | |
| /* Type for offset in 64-bit DWARF. */ | |
| typedef uint64_t Dwarf64_Off; | |
| /* Enumerates types of values, obtained during DWARF attribute decoding. */ | |
| typedef enum DwarfValueType { | |
| /* Undefined */ | |
| DWARF_VALUE_UNKNOWN = 1, | |
| /* uint8_t */ | |
| DWARF_VALUE_U8, | |
| /* int8_t */ | |
| DWARF_VALUE_S8, | |
| /* uint16_t */ | |
| DWARF_VALUE_U16, | |
| /* int16_t */ | |
| DWARF_VALUE_S16, | |
| /* uint32_t */ | |
| DWARF_VALUE_U32, | |
| /* int32_t */ | |
| DWARF_VALUE_S32, | |
| /* uint64_t */ | |
| DWARF_VALUE_U64, | |
| /* int64_t */ | |
| DWARF_VALUE_S64, | |
| /* const char* */ | |
| DWARF_VALUE_STR, | |
| /* 32-bit address */ | |
| DWARF_VALUE_PTR32, | |
| /* 64-bit address */ | |
| DWARF_VALUE_PTR64, | |
| /* Dwarf_Block */ | |
| DWARF_VALUE_BLOCK, | |
| } DwarfValueType; | |
| /* Describes block of data, stored directly in the mapped .debug_info | |
| * section. This type is used to represent an attribute encoded with | |
| * DW_FORM_block# form. | |
| */ | |
| typedef struct Dwarf_Block { | |
| /* Pointer to the block data inside mapped .debug_info section. */ | |
| const void* block_ptr; | |
| /* Byte size of the block data. */ | |
| Elf_Word block_size; | |
| } Dwarf_Block; | |
| /* Describes a value, obtained from the mapped .debug_info section | |
| * during DWARF attribute decoding. | |
| */ | |
| typedef struct Dwarf_Value { | |
| /* Unites all possible data types for the value. | |
| * See DwarfValueType for the list of types. | |
| */ | |
| union { | |
| Elf_Byte u8; | |
| Elf_Sbyte s8; | |
| Elf_Half u16; | |
| Elf_Shalf s16; | |
| Elf_Word u32; | |
| Elf_Sword s32; | |
| Elf_Xword u64; | |
| Elf_Sxword s64; | |
| Elf_Word ptr32; | |
| Elf_Xword ptr64; | |
| const char* str; | |
| Dwarf_Block block; | |
| }; | |
| /* Value type (defines which variable in the union abowe | |
| * contains the value). | |
| */ | |
| DwarfValueType type; | |
| /* Number of bytes that encode this value in .debug_info section | |
| * of ELF file. | |
| */ | |
| Elf_Word encoded_size; | |
| } Dwarf_Value; | |
| /* DWARF's LEB128 data type. LEB128 is defined as: | |
| * Variable Length Data. "Little Endian Base 128" (LEB128) numbers. LEB128 is | |
| * a scheme for encoding integers densely that exploits the assumption that | |
| * most integers are small in magnitude. (This encoding is equally suitable | |
| * whether the target machine architecture represents data in big-endian or | |
| * littleendian order. It is "little endian" only in the sense that it avoids | |
| * using space to represent the "big" end of an unsigned integer, when the big | |
| * end is all zeroes or sign extension bits). | |
| * | |
| * Unsigned LEB128 numbers are encoded as follows: start at the low order end | |
| * of an unsigned integer and chop it into 7-bit chunks. Place each chunk into | |
| * the low order 7 bits of a byte. Typically, several of the high order bytes | |
| * will be zero; discard them. Emit the remaining bytes in a stream, starting | |
| * with the low order byte; set the high order bit on each byte except the last | |
| * emitted byte. The high bit of zero on the last byte indicates to the decoder | |
| * that it has encountered the last byte. The integer zero is a special case, | |
| * consisting of a single zero byte. | |
| * | |
| * The encoding for signed LEB128 numbers is similar, except that the criterion | |
| * for discarding high order bytes is not whether they are zero, but whether | |
| * they consist entirely of sign extension bits. Consider the 32-bit integer | |
| * -2. The three high level bytes of the number are sign extension, thus LEB128 | |
| * would represent it as a single byte containing the low order 7 bits, with | |
| * the high order bit cleared to indicate the end of the byte stream. Note that | |
| * there is nothing within the LEB128 representation that indicates whether an | |
| * encoded number is signed or unsigned. The decoder must know what type of | |
| * number to expect. | |
| * | |
| * NOTE: It's assumed that LEB128 will not contain encodings for integers, | |
| * larger than 64 bit. | |
| */ | |
| typedef struct ELFF_PACKED Dwarf_Leb128 { | |
| /* Beginning of the LEB128 block. */ | |
| Elf_Byte val; | |
| /* Pulls actual value, encoded with this LEB128 block. | |
| * Param: | |
| * value - Upon return will contain value, encoded with this LEB128 block. | |
| * sign - If true, the caller expects the LEB128 to contain a signed | |
| * integer, otherwise, caller expects an unsigned integer value to be | |
| * encoded with this LEB128 block. | |
| */ | |
| void get_common(Dwarf_Value* value, bool sign) const { | |
| value->u64 = 0; | |
| /* Integer zero is a special case. */ | |
| if (val == 0) { | |
| value->type = sign ? DWARF_VALUE_S32 : DWARF_VALUE_U32; | |
| value->encoded_size = 1; | |
| return; | |
| } | |
| /* We've got to reconstruct the integer. */ | |
| value->type = DWARF_VALUE_UNKNOWN; | |
| value->encoded_size = 0; | |
| /* Byte by byte loop though the LEB128, reconstructing the integer from | |
| * 7-bits chunks. Byte with 8-th bit set to zero indicates the end | |
| * of the LEB128 block. For signed integers, 7-th bit of the last LEB128 | |
| * byte controls the sign. If 7-th bit of the last LEB128 byte is set, | |
| * the integer is negative. If 7-th bit of the last LEB128 byte is not | |
| * set, the integer is positive. | |
| */ | |
| const Elf_Byte* cur = &val; | |
| Elf_Word shift = 0; | |
| while ((*cur & 0x80) != 0) { | |
| value->u64 |= (static_cast<Elf_Xword>(*cur) & 0x7F) << shift; | |
| shift += 7; | |
| value->encoded_size++; | |
| cur++; | |
| } | |
| value->u64 |= (static_cast<Elf_Xword>(*cur) & 0x7F) << shift; | |
| value->encoded_size++; | |
| /* LEB128 format doesn't carry any info of the sizeof of the integer it | |
| * represents. We well guess it, judging by the highest bit set in the | |
| * reconstucted integer. | |
| */ | |
| if ((value->u64 & 0xFFFFFFFF00000000LL) == 0) { | |
| /* 32-bit integer. */ | |
| if (sign) { | |
| value->type = DWARF_VALUE_S32; | |
| if (((*cur) & 0x40) != 0) { | |
| // Value is negative. | |
| value->u64 |= - (1 << (shift + 7)); | |
| } else if ((value->u32 & 0x80000000) != 0) { | |
| // Make sure we don't report negative value in this case. | |
| value->type = DWARF_VALUE_S64; | |
| } | |
| } else { | |
| value->type = DWARF_VALUE_U32; | |
| } | |
| } else { | |
| /* 64-bit integer. */ | |
| if (sign) { | |
| value->type = DWARF_VALUE_S64; | |
| if (((*cur) & 0x40) != 0) { | |
| // Value is negative. | |
| value->u64 |= - (1 << (shift + 7)); | |
| } | |
| } else { | |
| value->type = DWARF_VALUE_U64; | |
| } | |
| } | |
| } | |
| /* Pulls actual unsigned value, encoded with this LEB128 block. | |
| * See get_common() for more info. | |
| * Param: | |
| * value - Upon return will contain unsigned value, encoded with | |
| * this LEB128 block. | |
| */ | |
| void get_unsigned(Dwarf_Value* value) const { | |
| get_common(value, false); | |
| } | |
| /* Pulls actual signed value, encoded with this LEB128 block. | |
| * See get_common() for more info. | |
| * Param: | |
| * value - Upon return will contain signed value, encoded with | |
| * this LEB128 block. | |
| */ | |
| void get_signed(Dwarf_Value* value) const { | |
| get_common(value, true); | |
| } | |
| /* Pulls LEB128 value, advancing past this LEB128 block. | |
| * See get_common() for more info. | |
| * Return: | |
| * Pointer to the byte past this LEB128 block. | |
| */ | |
| const void* process(Dwarf_Value* value, bool sign) const { | |
| get_common(value, sign); | |
| return INC_CPTR(&val, value->encoded_size); | |
| } | |
| /* Pulls LEB128 unsigned value, advancing past this LEB128 block. | |
| * See process() for more info. | |
| */ | |
| const void* process_unsigned(Dwarf_Value* value) const { | |
| return process(value, false); | |
| } | |
| /* Pulls LEB128 signed value, advancing past this LEB128 block. | |
| * See process() for more info. | |
| */ | |
| const void* process_signed(Dwarf_Value* value) const { | |
| return process(value, true); | |
| } | |
| } Dwarf_Leb128; | |
| /* DIE attribute descriptor in the .debug_abbrev section. | |
| * Attribute descriptor contains two LEB128 values. First one provides | |
| * attribute ID (one of DW_AT_XXX values), and the second one provides | |
| * format (one of DW_FORMAT_XXX values), in which attribute value is | |
| * encoded in the .debug_info section of the ELF file. | |
| */ | |
| typedef struct ELFF_PACKED Dwarf_Abbr_AT { | |
| /* Attribute ID (DW_AT_XXX). | |
| * Attribute format (DW_FORMAT_XXX) follows immediately. | |
| */ | |
| Dwarf_Leb128 at; | |
| /* Checks if this is a separator descriptor. | |
| * Zero is an invalid attribute ID, indicating the end of attribute | |
| * list for the current DIE. | |
| */ | |
| bool is_separator() const { | |
| return at.val == 0; | |
| } | |
| /* Pulls attribute data, advancing past this descriptor. | |
| * Param: | |
| * at_value - Upon return contains attribute value of this descriptor. | |
| * form - Upon return contains form value of this descriptor. | |
| * Return: | |
| * Pointer to the byte past this descriptor block (usually, next | |
| * attribute decriptor). | |
| */ | |
| const Dwarf_Abbr_AT* process(Dwarf_At* at_value, Dwarf_Form* form) const { | |
| if (is_separator()) { | |
| /* Size of separator descriptor is always 2 bytes. */ | |
| *at_value = 0; | |
| *form = 0; | |
| return INC_CPTR_T(Dwarf_Abbr_AT, &at.val, 2); | |
| } | |
| Dwarf_Value val; | |
| /* Process attribute ID. */ | |
| const Dwarf_Leb128* next = | |
| reinterpret_cast<const Dwarf_Leb128*>(at.process_unsigned(&val)); | |
| *at_value = val.u16; | |
| /* Follow with processing the form. */ | |
| next = reinterpret_cast<const Dwarf_Leb128*>(next->process_unsigned(&val)); | |
| *form = val.u16; | |
| return reinterpret_cast<const Dwarf_Abbr_AT*>(next); | |
| } | |
| } Dwarf_Abbr_AT; | |
| /* DIE abbreviation descriptor in the .debug_abbrev section. | |
| * DIE abbreviation descriptor contains three parameters. The first one is a | |
| * LEB128 value, that encodes 1 - based abbreviation descriptor number. | |
| * Abbreviation descriptor numbers seems to be always in sequential order, and | |
| * are counted on per-compilation unit basis. I.e. abbreviation number for the | |
| * first DIE abbreviation descriptor of each compilation unit is always 1. | |
| * | |
| * Besides abbreviation number, DIE abbreviation descriptor contains two more | |
| * values. The first one (after abbr_num) is a LEB128 value containing DIE's | |
| * tag value, and the second one is one byte flag specifying whether or not | |
| * the DIE contains any cildren. | |
| * | |
| * This descriptor is immediately followed by a list of attribute descriptors | |
| * (see Dwarf_Abbr_AT) for the DIE represented by this abbreviation descriptor. | |
| */ | |
| typedef struct ELFF_PACKED Dwarf_Abbr_DIE { | |
| /* 1 - based abbreviation number for the DIE. */ | |
| Dwarf_Leb128 abbr_num; | |
| /* Gets abbreviation number for this descriptor. */ | |
| Dwarf_AbbrNum get_abbr_num() const { | |
| Dwarf_Value val; | |
| abbr_num.get_unsigned(&val); | |
| return val.u16; | |
| } | |
| /* Gets DIE tag for this descriptor. */ | |
| Dwarf_Tag get_tag() const { | |
| Dwarf_Tag tag; | |
| process(NULL, &tag); | |
| return tag; | |
| } | |
| /* Pulls DIE abbreviation descriptor data, advancing past this descriptor. | |
| * Param: | |
| * abbr_index - Upon return contains abbreviation number for this | |
| * descriptor. This parameter can be NULL, if the caller is not interested | |
| * in this value. | |
| * tag - Upon return contains tag of the DIE for this descriptor. This | |
| * parameter can be NULL, if the caller is not interested in this value. | |
| * form - Upon return contains form of the DIE for this descriptor. | |
| * Return: | |
| * Pointer to the list of attribute descriptors for the DIE. | |
| */ | |
| const Dwarf_Abbr_AT* process(Dwarf_AbbrNum* abbr_index, | |
| Dwarf_Tag* tag) const { | |
| Dwarf_Value val; | |
| const Dwarf_Leb128* next = | |
| reinterpret_cast<const Dwarf_Leb128*>(abbr_num.process_unsigned(&val)); | |
| if (abbr_index != NULL) { | |
| *abbr_index = val.u32; | |
| } | |
| /* Next one is a "tag". */ | |
| next = reinterpret_cast<const Dwarf_Leb128*>(next->process_unsigned(&val)); | |
| if (tag != NULL) { | |
| *tag = val.u16; | |
| } | |
| /* Next one is a "has children" one byte flag. We're not interested in it, | |
| * so jump to the list of attribute descriptors that immediately follows | |
| * this DIE descriptor. */ | |
| return INC_CPTR_T(Dwarf_Abbr_AT, next, 1); | |
| } | |
| } Dwarf_Abbr_DIE; | |
| /* DIE descriptor in the .debug_info section. | |
| * DIE descriptor contains one LEB128-encoded value, containing DIE's | |
| * abbreviation descriptor number in the .debug_abbrev section. | |
| * | |
| * DIE descriptor is immediately followed by the list of DIE attribute values, | |
| * format of wich is defined by the list of attribute descriptors in the | |
| * .debug_abbrev section, that immediately follow the DIE attribute descriptor, | |
| * addressed by this descriptor's abbr_num LEB128. | |
| */ | |
| typedef struct ELFF_PACKED Dwarf_DIE { | |
| /* 1 - based index of DIE abbreviation descriptor (Dwarf_Abbr_DIE) for this | |
| * DIE in the .debug_abbrev section. | |
| * | |
| * NOTE: DIE abbreviation descriptor indexes are tied to the compilation | |
| * unit. In other words, each compilation unit restarts counting DIE | |
| * abbreviation descriptors from 1. | |
| * | |
| * NOTE: Zero is invalid value for this field, indicating that this DIE is a | |
| * separator (usually it ends a list of "child" DIEs) | |
| */ | |
| Dwarf_Leb128 abbr_num; | |
| /* Checks if this is a separator DIE. */ | |
| bool is_separator() const { | |
| return abbr_num.val == 0; | |
| } | |
| /* Gets (1 - based) abbreviation number for this DIE. */ | |
| Dwarf_AbbrNum get_abbr_num() const { | |
| Dwarf_Value val; | |
| abbr_num.get_unsigned(&val); | |
| return val.u16; | |
| } | |
| /* Pulls DIE information, advancing past this descriptor to DIE attributes. | |
| * Param: | |
| * abbr_num - Upon return contains abbreviation number for this DIE. This | |
| * parameter can be NULL, if the caller is not interested in this value. | |
| * Return: | |
| * Pointer to the byte past this descriptor (the list of DIE attributes). | |
| */ | |
| const Elf_Byte* process(Dwarf_AbbrNum* abbr_number) const { | |
| if (is_separator()) { | |
| if (abbr_number != NULL) { | |
| *abbr_number = 0; | |
| } | |
| // Size of a separator DIE is 1 byte. | |
| return INC_CPTR_T(Elf_Byte, &abbr_num.val, 1); | |
| } | |
| Dwarf_Value val; | |
| const void* ret = abbr_num.process_unsigned(&val); | |
| if (abbr_number != NULL) { | |
| *abbr_number = val.u32; | |
| } | |
| return reinterpret_cast<const Elf_Byte*>(ret); | |
| } | |
| } Dwarf_DIE; | |
| /* | |
| * Variable size headers. | |
| * When encoding size value in DWARF, the first 32 bits of a "size" header | |
| * define header type. If first 32 bits of the header contain 0xFFFFFFFF | |
| * value, this is 64-bit size header with the following 64 bits encoding | |
| * the size. Otherwise, if first 32 bits are not 0xFFFFFFFF, they contain | |
| * 32-bit size value. | |
| */ | |
| /* Size header for 32-bit DWARF. */ | |
| typedef struct ELFF_PACKED Dwarf32_SizeHdr { | |
| /* Size value. */ | |
| Elf_Word size; | |
| } Dwarf32_SizeHdr; | |
| /* Size header for 64-bit DWARF. */ | |
| typedef struct ELFF_PACKED Dwarf64_SizeHdr { | |
| /* Size selector. For 64-bit DWARF this field is set to 0xFFFFFFFF */ | |
| Elf_Word size_selector; | |
| /* Actual size value. */ | |
| Elf_Xword size; | |
| } Dwarf64_SizeHdr; | |
| /* Compilation unit header in the .debug_info section. | |
| * Template param: | |
| * Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr | |
| * for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF. | |
| * Elf_Off - Type for abbrev_offset field. Must be Elf_Word for for 32-bit | |
| * DWARF, or Elf_Xword for 64-bit DWARF. | |
| */ | |
| template <typename Dwarf_SizeHdr, typename Elf_Off> | |
| struct ELFF_PACKED Dwarf_CUHdr { | |
| /* Size of the compilation unit data in .debug_info section. */ | |
| Dwarf_SizeHdr size_hdr; | |
| /* Compilation unit's DWARF version stamp. */ | |
| Elf_Half version; | |
| /* Relative (to the beginning of .debug_abbrev section data) offset of the | |
| * beginning of abbreviation sequence for this compilation unit. | |
| */ | |
| Elf_Off abbrev_offset; | |
| /* Pointer size for this compilation unit (should be 4, or 8). */ | |
| Elf_Byte address_size; | |
| }; | |
| /* Compilation unit header in the .debug_info section for 32-bit DWARF. */ | |
| typedef Dwarf_CUHdr<Dwarf32_SizeHdr, Elf_Word> Dwarf32_CUHdr; | |
| /* Compilation unit header in the .debug_info section for 64-bit DWARF. */ | |
| typedef Dwarf_CUHdr<Dwarf64_SizeHdr, Elf_Xword> Dwarf64_CUHdr; | |
| /* CU STMTL header in the .debug_line section. | |
| * Template param: | |
| * Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr | |
| * for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF. | |
| * Elf_Size - Type for header_length field. Must be Elf_Word for for 32-bit | |
| * DWARF, or Elf_Xword for 64-bit DWARF. | |
| */ | |
| template <typename Dwarf_SizeHdr, typename Elf_Size> | |
| struct ELFF_PACKED Dwarf_STMTLHdr { | |
| /* The size in bytes of the line number information for this compilation | |
| * unit, not including the unit_length field itself. */ | |
| Dwarf_SizeHdr unit_length; | |
| /* A version number. This number is specific to the line number information | |
| * and is independent of the DWARF version number. */ | |
| Elf_Half version; | |
| /* The number of bytes following the header_length field to the beginning of | |
| * the first byte of the line number program itself. In the 32-bit DWARF | |
| * format, this is a 4-byte unsigned length; in the 64-bit DWARF format, | |
| * this field is an 8-byte unsigned length. */ | |
| Elf_Size header_length; | |
| /* The size in bytes of the smallest target machine instruction. Line number | |
| * program opcodes that alter the address register first multiply their | |
| * operands by this value. */ | |
| Elf_Byte min_instruction_len; | |
| /* The initial value of the is_stmt register. */ | |
| Elf_Byte default_is_stmt; | |
| /* This parameter affects the meaning of the special opcodes. */ | |
| Elf_Sbyte line_base; | |
| /* This parameter affects the meaning of the special opcodes. */ | |
| Elf_Byte line_range; | |
| /* The number assigned to the first special opcode. */ | |
| Elf_Byte opcode_base; | |
| /* This is first opcode in an array specifying the number of LEB128 operands | |
| * for each of the standard opcodes. The first element of the array | |
| * corresponds to the opcode whose value is 1, and the last element | |
| * corresponds to the opcode whose value is opcode_base - 1. By increasing | |
| * opcode_base, and adding elements to this array, new standard opcodes can | |
| * be added, while allowing consumers who do not know about these new opcodes | |
| * to be able to skip them. NOTE: this array points to the mapped | |
| * .debug_line section. */ | |
| Elf_Byte standard_opcode_lengths; | |
| }; | |
| /* CU STMTL header in the .debug_line section for 32-bit DWARF. */ | |
| typedef Dwarf_STMTLHdr<Dwarf32_SizeHdr, Elf_Word> Dwarf32_STMTLHdr; | |
| /* CU STMTL header in the .debug_line section for 64-bit DWARF. */ | |
| typedef Dwarf_STMTLHdr<Dwarf64_SizeHdr, Elf_Xword> Dwarf64_STMTLHdr; | |
| /* Source file descriptor in the .debug_line section. | |
| * Descriptor begins with zero-terminated file name, followed by an ULEB128, | |
| * encoding directory index in the list of included directories, followed by | |
| * an ULEB12, encoding file modification time, followed by an ULEB12, encoding | |
| * file size. | |
| */ | |
| typedef struct ELFF_PACKED Dwarf_STMTL_FileDesc { | |
| /* Zero-terminated file name. */ | |
| char file_name[1]; | |
| /* Checks of this descriptor ends the list. */ | |
| bool is_last_entry() const { | |
| return file_name[0] == '\0'; | |
| } | |
| /* Gets file name. */ | |
| const char* get_file_name() const { | |
| return file_name; | |
| } | |
| /* Processes this descriptor, advancing to the next one. | |
| * Param: | |
| * dir_index - Upon return contains index of the parent directory in the | |
| * list of included directories. Can be NULL if caller is not interested | |
| * in this value. | |
| * Return: | |
| * Pointer to the next source file descriptor in the list. | |
| */ | |
| const Dwarf_STMTL_FileDesc* process(Elf_Word* dir_index) const { | |
| if (is_last_entry()) { | |
| return this; | |
| } | |
| /* First parameter: include directory index. */ | |
| Dwarf_Value tmp; | |
| const Dwarf_Leb128* leb = | |
| INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1); | |
| leb = reinterpret_cast<const Dwarf_Leb128*>(leb->process_unsigned(&tmp)); | |
| if (dir_index != NULL) { | |
| *dir_index = tmp.u32; | |
| } | |
| /* Process file time. */ | |
| leb = reinterpret_cast<const Dwarf_Leb128*>(leb->process_unsigned(&tmp)); | |
| /* Process file size. */ | |
| return reinterpret_cast<const Dwarf_STMTL_FileDesc*>(leb->process_unsigned(&tmp)); | |
| } | |
| /* Gets directory index for this descriptor. */ | |
| Elf_Word get_dir_index() const { | |
| assert(!is_last_entry()); | |
| if (is_last_entry()) { | |
| return 0; | |
| } | |
| /* Get directory index. */ | |
| Dwarf_Value ret; | |
| const Dwarf_Leb128* leb = | |
| INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1); | |
| leb->process_unsigned(&ret); | |
| return ret.u32; | |
| } | |
| } Dwarf_STMTL_FileDesc; | |
| /* Encapsulates a DIE attribute, collected during ELF file parsing. | |
| */ | |
| class DIEAttrib { | |
| public: | |
| /* Constructs DIEAttrib intance. */ | |
| DIEAttrib() | |
| : at_(0), | |
| form_(0) { | |
| value_.type = DWARF_VALUE_UNKNOWN; | |
| } | |
| /* Destructs DIEAttrib intance. */ | |
| ~DIEAttrib() { | |
| } | |
| /* Gets DWARF attribute ID (DW_AT_Xxx) for this property. */ | |
| Dwarf_At at() const { | |
| return at_; | |
| } | |
| /* Gets DWARF form ID (DW_FORM_Xxx) for this property. */ | |
| Dwarf_Form form() const { | |
| return form_; | |
| } | |
| /* Gets value of this property. */ | |
| const Dwarf_Value* value() const { | |
| return &value_; | |
| } | |
| /* Value of this property. */ | |
| Dwarf_Value value_; | |
| /* DWARF attribute ID (DW_AT_Xxx) for this property. */ | |
| Dwarf_At at_; | |
| /* DWARF form ID (DW_FORM_Xxx) for this property. */ | |
| Dwarf_Form form_; | |
| }; | |
| /* Parse tag context. | |
| * This structure is used as an ELF file parsing parameter, limiting collected | |
| * DIEs by the list of tags. | |
| */ | |
| typedef struct DwarfParseContext { | |
| /* Zero-terminated list of tags to collect DIEs for. If this field is NULL, | |
| * DIEs for all tags will be collected during the parsing. */ | |
| const Dwarf_Tag* tags; | |
| } DwarfParseContext; | |
| /* Checks if a DIE with the given tag should be collected during the parsing. | |
| * Param: | |
| * parse_context - Parse context to check the tag against. This parameter can | |
| * be NULL, indicating that all tags should be collected. | |
| * tag - Tag to check. | |
| * Return: | |
| * true if a DIE with the given tag should be collected during the parsing, | |
| * or false, if the DIE should not be collected. | |
| */ | |
| static inline bool | |
| collect_die(const DwarfParseContext* parse_context, Dwarf_Tag tag) { | |
| if (parse_context == NULL || parse_context->tags == NULL) { | |
| return true; | |
| } | |
| for (const Dwarf_Tag* tags = parse_context->tags; *tags != 0; tags++) { | |
| if (*tags == tag) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| /* Encapsulates an array of Dwarf_Abbr_DIE pointers, cached for a compilation | |
| * unit. Although Dwarf_Abbr_DIE descriptors in the .debug_abbrev section of | |
| * the ELF file seems to be always in sequential order, DIE descriptors may | |
| * reference them randomly. So, to provide better performance, we will cache | |
| * all Dwarf_Abbr_DIE pointers, that were found for each DIE. Since all of the | |
| * Dwarf_Abbr_DIE are sequential, an array is the best way to cache them. | |
| * | |
| * NOTE: Objects of this class are instantiated one per each CU, as all DIE | |
| * abbreviation numberation is restarted from 1 for each new CU. | |
| */ | |
| class DwarfAbbrDieArray { | |
| public: | |
| /* Constructs DwarfAbbrDieArray instance. | |
| * Most of the CUs don't have too many unique Dwarf_Abbr_DIEs, so, in order | |
| * to decrease the amount of memory allocation calls, we will preallocate | |
| * a relatively small array for them along with the instance of this class, | |
| * hopping, that all Dwarf_Abbr_DIEs for the CU will fit into it. | |
| */ | |
| DwarfAbbrDieArray() | |
| : array_(&small_array_[0]), | |
| array_size_(ELFF_ARRAY_SIZE(small_array_)), | |
| count_(0) { | |
| } | |
| /* Destructs DwarfAbbrDieArray instance. */ | |
| ~DwarfAbbrDieArray() { | |
| if (array_ != &small_array_[0]) { | |
| delete[] array_; | |
| } | |
| } | |
| /* Adds new entry to the array | |
| * Param: | |
| * abbr - New entry to add. | |
| * num - Abbreviation number for the adding entry. | |
| * NOTE: before adding, this method will verify that descriptor for the | |
| * given abbreviation number has not been cached yet. | |
| * NOTE: due to the nature of this array, entries MUST be added strictly | |
| * in sequential order. | |
| * Return: | |
| * true on success, false on failure. | |
| */ | |
| bool add(const Dwarf_Abbr_DIE* abbr, Dwarf_AbbrNum num) { | |
| assert(num != 0); | |
| if (num == 0) { | |
| // Zero is illegal DIE abbreviation number. | |
| _set_errno(EINVAL); | |
| return false; | |
| } | |
| if (num <= count_) { | |
| // Already cached. | |
| return true; | |
| } | |
| // Enforce strict sequential order. | |
| assert(num == (count_ + 1)); | |
| if (num != (count_ + 1)) { | |
| _set_errno(EINVAL); | |
| return false; | |
| } | |
| if (num >= array_size_) { | |
| /* Expand the array. Make it 64 entries bigger than adding entry number. | |
| * NOTE: that we don't check for an overflow here, since we secured | |
| * ourselves from that by enforcing strict sequential order. So, an | |
| * overflow may happen iff number of entries cached in this array is | |
| * close to 4G, which is a) totally unreasonable, and b) we would die | |
| * long before this amount of entries is cached. | |
| */ | |
| Dwarf_AbbrNum new_size = num + 64; | |
| // Reallocate. | |
| const Dwarf_Abbr_DIE** new_array = new const Dwarf_Abbr_DIE*[new_size]; | |
| assert(new_array != NULL); | |
| if (new_array == NULL) { | |
| _set_errno(ENOMEM); | |
| return false; | |
| } | |
| memcpy(new_array, array_, count_ * sizeof(const Dwarf_Abbr_DIE*)); | |
| if (array_ != &small_array_[0]) { | |
| delete[] array_; | |
| } | |
| array_ = new_array; | |
| array_size_ = new_size; | |
| } | |
| // Abbreviation numbers are 1-based. | |
| array_[num - 1] = abbr; | |
| count_++; | |
| return true; | |
| } | |
| /* Adds new entry to the array | |
| * Param: | |
| * abbr - New entry to add. | |
| * Return: | |
| * true on success, false on failure. | |
| */ | |
| bool add(const Dwarf_Abbr_DIE* abbr) { | |
| return add(abbr, abbr->get_abbr_num()); | |
| } | |
| /* Gets an entry from the array | |
| * Param: | |
| * num - 1-based index of an entry to get. | |
| * Return: | |
| * Entry on success, or NULL if num exceeds the number of entries | |
| * contained in the array. | |
| */ | |
| const Dwarf_Abbr_DIE* get(Dwarf_AbbrNum num) const { | |
| assert(num != 0 && num <= count_); | |
| if (num != 0 && num <= count_) { | |
| return array_[num - 1]; | |
| } else { | |
| _set_errno(EINVAL); | |
| return NULL; | |
| } | |
| } | |
| /* Caches Dwarf_Abbr_DIEs into this array up to the requested number. | |
| * NOTE: This method cannot be called on an empty array. Usually, first | |
| * entry is inserted into this array when CU object is initialized. | |
| * Param: | |
| * num - Entry number to cache entries up to. | |
| * Return: | |
| * Last cached entry (actually, an entry for the 'num' index). | |
| */ | |
| const Dwarf_Abbr_DIE* cache_to(Dwarf_AbbrNum num) { | |
| /* Last cached DIE abbreviation. We always should have cached at least one | |
| * abbreviation for the CU DIE itself, added via "add" method when CU | |
| * object was initialized. */ | |
| const Dwarf_Abbr_DIE* cur_abbr = get(count_); | |
| assert(cur_abbr != NULL); | |
| if (cur_abbr == NULL) { | |
| return NULL; | |
| } | |
| /* Starting with the last cached DIE abbreviation, loop through the | |
| * remaining DIE abbreviations in the .debug_abbrev section of the | |
| * mapped ELF file, caching them until we reach the requested | |
| * abbreviation descriptor number. Normally, the very next DIE | |
| * abbreviation will stop the loop. */ | |
| while (num > count_) { | |
| Dwarf_AbbrNum abbr_num; | |
| Dwarf_Tag tmp2; | |
| Dwarf_Form tmp3; | |
| Dwarf_At tmp4; | |
| /* Process all AT abbreviations for the current DIE entry, reaching next | |
| * DIE abbreviation. */ | |
| const Dwarf_Abbr_AT* abbr_at = cur_abbr->process(&abbr_num, &tmp2); | |
| while (!abbr_at->is_separator()) { | |
| abbr_at = abbr_at->process(&tmp4, &tmp3); | |
| } | |
| // Next DIE abbreviation is right after the separator AT abbreviation. | |
| cur_abbr = reinterpret_cast<const Dwarf_Abbr_DIE*> | |
| (abbr_at->process(&tmp4, &tmp3)); | |
| if (!add(cur_abbr)) { | |
| return NULL; | |
| } | |
| } | |
| return array_[num - 1]; | |
| } | |
| /* Empties array and frees allocations. */ | |
| void empty() { | |
| if (array_ != &small_array_[0]) { | |
| delete[] array_; | |
| array_ = &small_array_[0]; | |
| array_size_ = sizeof(small_array_) / sizeof(small_array_[0]); | |
| } | |
| count_ = 0; | |
| } | |
| protected: | |
| /* Array, preallocated in anticipation of relatively small number of | |
| * DIE abbreviations in compilation unit. */ | |
| const Dwarf_Abbr_DIE* small_array_[64]; | |
| /* Array of Dwarf_Abbr_DIE pointers, cached for a compilation unit. */ | |
| const Dwarf_Abbr_DIE** array_; | |
| /* Current size of the array. */ | |
| Dwarf_AbbrNum array_size_; | |
| /* Number of entries, cached in the array. */ | |
| Dwarf_AbbrNum count_; | |
| }; | |
| /* Encapsulates a state machine for the "Line Number Program", that is run | |
| * on data conained in the mapped .debug_line section. | |
| */ | |
| class DwarfStateMachine { | |
| public: | |
| /* Constructs DwarfStateMachine instance. | |
| * Param: | |
| * set_is_stmt - Matches value of default_is_stmt field in the STMTL header. | |
| * see Dwarf_STMTL_HdrXX. | |
| */ | |
| explicit DwarfStateMachine(bool set_is_stmt) | |
| : address_(0), | |
| file_(1), | |
| line_(1), | |
| column_(0), | |
| discriminator_(0), | |
| is_stmt_(set_is_stmt), | |
| basic_block_(false), | |
| end_sequence_(false), | |
| prologue_end_(false), | |
| epilogue_begin_(false), | |
| isa_(0), | |
| set_file_info_(NULL) { | |
| } | |
| /* Destructs DwarfStateMachine instance. */ | |
| ~DwarfStateMachine() { | |
| } | |
| /* Resets the state to default. | |
| * Param: | |
| * set_is_stmt - Matches value of default_is_stmt field in the STMTL header. | |
| * see Dwarf_STMTL_HdrXX. | |
| */ | |
| void reset(bool set_is_stmt) { | |
| address_ = 0; | |
| file_ = 1; | |
| line_ = 1; | |
| column_ = 0; | |
| discriminator_ = 0; | |
| is_stmt_ = set_is_stmt; | |
| basic_block_ = false; | |
| end_sequence_ = false; | |
| prologue_end_ = false; | |
| epilogue_begin_ = false; | |
| isa_ = 0; | |
| set_file_info_ = NULL; | |
| } | |
| /* | |
| * Machine state. | |
| */ | |
| /* Current address (current PC value). */ | |
| Elf_Xword address_; | |
| /* Current index of source file descriptor. */ | |
| Elf_Word file_; | |
| /* Current line in the current source file. */ | |
| Elf_Word line_; | |
| /* Current column. */ | |
| Elf_Word column_; | |
| /* Current discriminator value. */ | |
| Elf_Word discriminator_; | |
| /* Current STMT flag. */ | |
| bool is_stmt_; | |
| /* Current basic block flag. */ | |
| bool basic_block_; | |
| /* Current end of sequence flag. */ | |
| bool end_sequence_; | |
| /* Current end of prologue flag. */ | |
| bool prologue_end_; | |
| /* Current epilogue begin flag. */ | |
| bool epilogue_begin_; | |
| /* Current ISA value. */ | |
| Elf_Word isa_; | |
| /* Current value for explicitly set current source file descriptor. | |
| * If not NULL, this descriptor has priority over the descriptor, addressed | |
| * by the file_ member of this class. */ | |
| const Dwarf_STMTL_FileDesc* set_file_info_; | |
| }; | |
| /* Checks if given tag belongs to a routine. */ | |
| static inline bool | |
| dwarf_tag_is_routine(Dwarf_Tag tag) { | |
| return tag == DW_TAG_inlined_subroutine || | |
| tag == DW_TAG_subprogram || | |
| tag == DW_AT_main_subprogram; | |
| } | |
| /* Checks if given tag belongs to a compilation unit. */ | |
| static inline bool | |
| dwarf_tag_is_cu(Dwarf_Tag tag) { | |
| return tag == DW_TAG_compile_unit || | |
| tag == DW_TAG_partial_unit; | |
| } | |
| #endif // ELFF_DWARF_DEFS_H_ |