/* 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 declaration of a class DwarfCU, that encapsulates a compilation | |
* unit in the .debug_info section of the mapped ELF file. | |
*/ | |
#ifndef ELFF_DWARF_CU_H_ | |
#define ELFF_DWARF_CU_H_ | |
#include "dwarf_defs.h" | |
#include "dwarf_die.h" | |
/* Address information descriptor. */ | |
typedef struct Dwarf_AddressInfo { | |
/* Routine DIE containing the address. */ | |
const DIEObject* die_obj; | |
/* Source file name for the address. */ | |
const char* file_name; | |
/* Source file directory path for the address. */ | |
const char* dir_name; | |
/* Source file line number for the address. */ | |
Elf_Word line_number; | |
} Dwarf_AddressInfo; | |
/* STMTL header cached by compilation unit. This header is contained in | |
* the .debug_line section of the ELF file. */ | |
typedef struct Dwarf_STMTL_Hdr { | |
/* The size in bytes of the line number information for this compilation | |
* unit, not including the unit_length field itself. */ | |
Elf_Xword 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_Xword 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; | |
/* Points to standard_opcode_lengths array in the actual STMTL header in | |
* the mapped .debug_line section. */ | |
const Elf_Byte* standard_opcode_lengths; | |
/* Pointer to the beginning of the list of include directories in the mapped | |
* .debug_line section. */ | |
const char* include_directories; | |
/* Number of include directories in the list that begins with | |
* include_directories. */ | |
Elf_Word inc_dir_num; | |
/* Pointer to the beginning of the list of file information in the mapped | |
* .debug_line section. Each entry in this list begins with zero-terminated | |
* file name, followed by ULEB128 encoding directory index for the file, | |
* followed by ULEB128 encoding last modification time, followed by ULEB128 | |
* encoding length of file in bytes. */ | |
const Dwarf_STMTL_FileDesc* file_infos; | |
/* Start of the "Line Number Program" in the mapped .debug_line section. */ | |
const Elf_Byte* start; | |
/* End of the "Line Number Program" in the mapped .debug_line section. */ | |
const Elf_Byte* end; | |
} Dwarf_STMTL_Hdr; | |
/* Encapsulates architecture-independent functionality of a | |
* compilation unit. | |
*/ | |
class DwarfCU : public DwarfAllocBase { | |
friend class ElfFile; | |
public: | |
/* Constructs DwarfCU instance. | |
* Param: | |
* elf - Instance of ElfFile containing this compilation unit. | |
*/ | |
explicit DwarfCU(ElfFile* elf); | |
/* Destructs DwarfCU instance. */ | |
virtual ~DwarfCU(); | |
/* Creates DwarfCUImpl instance, depending on DWARF format. | |
* Param: | |
* elf - Instance of ElfFile containing this compilation unit. | |
* hdr - Pointer to compilation unit header inside mapped .debug_info | |
* section of the ELF file. Actual data addressed by this pointer | |
* must be Dwarf32_CUHdr for 32 bit DWARFs, or Dwarf64_CUHdr for | |
* 64 bit DWARFs. | |
* Return: | |
* Created DwarfCUImpl instance (typecasted back to DwarfCU) on success, | |
* or NULL on failure. | |
*/ | |
static DwarfCU* create_instance(ElfFile* elf, const void* hdr); | |
/* Process a DIE attribute. | |
* Param: | |
* attr - Attribute list inside the mapped .debug_info section of the ELF | |
* file. | |
* form - Attribute's form, definig representation of attribute value in the | |
* mapped .debug_info section of the ELF file. | |
* attr_value - Upon return contains attribute value. | |
* Return: | |
* Pointer to the next DIE attribute inside the mapped .debug_info section | |
* of the ELF file. | |
*/ | |
const Elf_Byte* process_attrib(const Elf_Byte* attr, | |
Dwarf_Form form, | |
Dwarf_Value* attr_value) const; | |
/* Dumps this compilation unit to the stdout. */ | |
void dump() const; | |
/* Gets instance of ElfFile containing this compilation unit. */ | |
ElfFile* elf_file() const { | |
return elf_file_; | |
} | |
/* Gets DIE object for this CU. */ | |
DIEObject* cu_die() const { | |
return cu_die_; | |
} | |
/* Gets byte size of the pointer type for this compilation unit. */ | |
Elf_Byte addr_sizeof() const { | |
return addr_sizeof_; | |
} | |
/* Gets full path to the compilation directory (DW_AT_comp_dir attribute). | |
* Return: | |
* Full path to the compilation directory (DW_AT_comp_dir attribute), | |
* or NULL, if that attribute was missing in CU's attribute list. | |
*/ | |
const char* comp_dir_path() const { | |
DIEAttrib attr; | |
return cu_die()->get_attrib(DW_AT_comp_dir, &attr) ? attr.value()->str : | |
NULL; | |
} | |
/* Gets relative (from the compilation directory) path to the compiled file. | |
* (DW_AT_name attribute). | |
* Return: | |
* Relative path to the compiled file (DW_AT_name attribute), or NULL, if | |
* that attribute was missing in CU's attribute list. | |
*/ | |
const char* rel_cu_path() const { | |
DIEAttrib attr; | |
return cu_die()->get_attrib(DW_AT_name, &attr) ? attr.value()->str : | |
NULL; | |
} | |
/* Gets next compilation unit in the list. NULL indicates the last CU. */ | |
DwarfCU* prev_cu() const { | |
return prev_cu_; | |
} | |
/* Links this CU to the list of prevoiusly discovered CUs. */ | |
void set_prev_cu(DwarfCU* prev) { | |
prev_cu_ = prev; | |
} | |
/* Checks if DWARF version for this CU is higher than 2. */ | |
bool is_DWARF3_or_higher() const { | |
return version_ >= 3; | |
} | |
/* Gets DIE abbreviation for given abbreviation number. | |
* See DwarfAbbrDieArray::get() */ | |
const Dwarf_Abbr_DIE* get_die_abbr(Dwarf_AbbrNum num) const { | |
return abbrs_.get(num); | |
} | |
/* Gets DIE object containing given address. | |
* DIE address ranges may overlap (for instance, address range for an inlined | |
* routine will be contained within the address range of a routine where it | |
* was inlined). This method will return a DIE object that is a "leaf" in | |
* that inlining tree. I.e the returned DIE object represents the last DIE | |
* in the branch of all DIEs containing given address. | |
* Param: | |
* address - Address to get a DIE for. NOTE: for the sake of simplicity we | |
* explicitly use 64-bit type for an address. | |
* Return: | |
* Leaf DIE containing given address, or NULL if this CU doesn't contain | |
* the given address. | |
*/ | |
DIEObject* get_leaf_die_for_address(Elf_Xword address) const { | |
return cu_die_->get_leaf_for_address(address); | |
} | |
/* Checks if this CU contains 64, or 32-bit addresses. */ | |
bool is_CU_address_64() const { | |
return addr_sizeof_ == 8; | |
} | |
bool is_CU_address_32() const { | |
return addr_sizeof_ == 4; | |
} | |
//============================================================================= | |
// DWARF format dependent methods | |
//============================================================================= | |
public: | |
/* Parses this compilation unit in .debug_info section, collecting children | |
* DIEs of this compilation unit. | |
* Param: | |
* parse_context - Parsing context that lists tags for DIEs that should be | |
* collected during parsing. NULL passed in this parameter indicates DIEs | |
* for all tags should be collected. | |
* next_cu_die - Upon successful return contains pointer to the next | |
* compilation unit descriptor inside mapped .debug_info section of | |
* the ELF file. | |
* Return: | |
* true on success, false on failure. | |
*/ | |
virtual bool parse(const DwarfParseContext* parse_context, | |
const void** next_cu_die) = 0; | |
/* Gets a DIE object referenced by an offset from the beginning of | |
* this CU in the mapped .debug_info section. | |
*/ | |
virtual DIEObject* get_referenced_die_object(Elf_Word ref) const = 0; | |
/* Gets a reference to a DIE object (offset of the DIE from the | |
* beginning of this CU in the mapped .debug_info section. | |
*/ | |
virtual Elf_Word get_die_reference(const Dwarf_DIE* die) const = 0; | |
/* Gets PC address information. | |
* Param: | |
* address - PC address to get information for. | |
* info - Upon success contains information about routine that belongs to | |
* this compilation unit, containing the given address. | |
* Return: | |
* true on success, or false if this CU doesn't contain the given address. | |
*/ | |
virtual bool get_pc_address_file_info(Elf_Xword address, | |
Dwarf_AddressInfo* info) = 0; | |
/* Gets file descriptor in the mapped .debug_line section of ELF file for a | |
* given index in the file descriptor list. | |
* Param: | |
* index - 1-based index of file descriptor in the file descriptor list. | |
* Return: | |
* File descriptor for the given index, or NULL if index was too big. | |
* NOTE: pointer returned from this method addressed mapped section of | |
* ELF file. | |
*/ | |
virtual const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index) = 0; | |
/* Gets directory name by an index in the mapped .debug_line section of | |
* ELF file. | |
* Param: | |
* dir_index - Index of the directory in the file descriptor list. If this | |
* parameter is zero, compilation directory (DW_AT_comp_dir) for this CU | |
* will be returned. | |
* Return: | |
* Directory name for the given index, or NULL if index was too big. | |
* NOTE: pointer returned from this method addressed mapped section of | |
* ELF file. | |
*/ | |
virtual const char* get_stmt_dir_name(Elf_Word dir_index) = 0; | |
protected: | |
/* DIE abbreviation descriptors, cached for this compilation unit. */ | |
DwarfAbbrDieArray abbrs_; | |
/* Instance of an ELF file that contains this compilation unit. */ | |
ElfFile* elf_file_; | |
/* DIE object for this CU. */ | |
DIEObject* cu_die_; | |
/* Next compilation unit in the list (previous in the order they've been | |
* discovered during ELF file parsing). | |
*/ | |
DwarfCU* prev_cu_; | |
/* DWARF version for this CU. */ | |
Elf_Half version_; | |
/* Byte size of the pointer type for this compilation unit. */ | |
Elf_Byte addr_sizeof_; | |
}; | |
/* Encapsulates architecture-dependent functionality of a compilation unit. | |
* Template param: | |
* Dwarf_CUHdr - type compilation unit header in the mapped .debug_info | |
* section of ELF file. Must be: | |
* - Dwarf32_CUHdr for 32-bit DWARF, or | |
* - Dwarf64_CUHdr for 64-bit DWARF. | |
* Dwarf_Off - type for an offset field in DWARF data format. Must be: | |
* - Dwarf32_Off for 32-bit DWARF, or | |
* - Dwarf64_Off for 64-bit DWARF. | |
*/ | |
template <typename Dwarf_CUHdr, typename Dwarf_Off> | |
class DwarfCUImpl : public DwarfCU { | |
public: | |
/* Constructs DwarfCU instance. | |
* Param: | |
* elf - Instance of ElfFile containing this compilation unit. | |
* hdr - Pointer to compilation unit header inside mapped .debug_info | |
* section of the ELF file. | |
*/ | |
DwarfCUImpl(ElfFile* elf, const Dwarf_CUHdr* hdr); | |
/* Destructs DwarfCU instance. */ | |
~DwarfCUImpl() { | |
} | |
/* Parses this compilation unit in .debug_info section, collecting children | |
* DIEs of this compilation unit. This is an implementation of DwarfCU's | |
* abstract metod. | |
* See DwarfCU::parse(). | |
*/ | |
bool parse(const DwarfParseContext* parse_context, | |
const void** next_cu_die); | |
/* Gets PC address information. | |
* This is an implementation of DwarfCU's abstract metod. | |
* See DwarfCU::get_pc_address_file_info(). | |
*/ | |
bool get_pc_address_file_info(Elf_Xword address, Dwarf_AddressInfo* info); | |
/* Gets file descriptor in the mapped .debug_line section of ELF file for a | |
* given index in the file descriptor list. | |
* This is an implementation of DwarfCU's abstract metod. | |
* See DwarfCU::get_stmt_file_info(). | |
*/ | |
const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index); | |
/* Gets directory name by an index in the mapped .debug_line section of | |
* ELF file. | |
* This is an implementation of DwarfCU's abstract metod. | |
* See DwarfCU::get_stmt_dir_name(). | |
*/ | |
const char* get_stmt_dir_name(Elf_Word dir_index); | |
/* Gets a DIE object referenced by an offset from the beginning of | |
* this CU. This is an implementation of DwarfCU's abstract metod. | |
*/ | |
DIEObject* get_referenced_die_object(Elf_Word ref) const { | |
const Dwarf_DIE* die = get_referenced_die(ref); | |
return cu_die_->find_die_object(die); | |
} | |
/* Gets a reference to a DIE object (offset of the DIE from the | |
* beginning of this CU in the mapped .debug_info section. | |
* This is an implementation of DwarfCU's abstract metod. | |
*/ | |
Elf_Word get_die_reference(const Dwarf_DIE* die) const { | |
return static_cast<Elf_Word>(diff_ptr(cu_header_, die)); | |
} | |
protected: | |
/* Process a child DIE (and all its children) in this compilation unit. | |
* Param: | |
* parse_context - See DwarfCU::parse(). | |
* die - DIE descriptor of the child to process in this method. | |
* parent_obj - Parent object of the child to process in this method. | |
* NOTE: this parameter can be NULL only for a DIE that represents this | |
* compilation unit itself. | |
* Return: | |
* Pointer to the end of child's attribute list in the mapped .debug_info | |
* section on success, or NULL on failure. Usually, pointer returned from | |
* this method is simply discarded, since parent calculates address of the | |
* next sibling's DIE based on DW_AT_sibling attribute of the DIE preceding | |
* child's DIE. | |
*/ | |
const Elf_Byte* process_DIE(const DwarfParseContext* parse_context, | |
const Dwarf_DIE* die, | |
DIEObject* parent_obj); | |
/* Creates a DIE object for the given DIE. | |
* Param: | |
* parse_context See DwarfCU::parse(). | |
* die - DIE to create an object for. | |
* parent - Parent DIE object for the one that's being created in this | |
* method. | |
* tag - Tag of the DIE object that's being created in this method. | |
* Return: | |
* Created DIE object. This method may returns NULL in two cases: | |
* - We're not interested in this DIE (decided by looking at 'tag' | |
* parameter. In this case errno should be set to zero. | |
* - Memory allocation has failed. In this case errno should be | |
* set to ENOMEM. | |
*/ | |
DIEObject* create_die_object(const DwarfParseContext* parse_context, | |
const Dwarf_DIE* die, | |
DIEObject* parent, | |
Dwarf_Tag tag); | |
/* Initializes (caches) STMT lines header for this CU. */ | |
bool init_stmtl(); | |
/* Saves current source file information, collected in the state machine by | |
* the "Line Number Program". | |
* Param: | |
* state - State machine collected "Line Number Program" results. | |
* info - Upon success contains source file information, copied over from | |
* the state machine. | |
* Return: | |
* true on success, or false on failure. | |
*/ | |
bool set_source_info(const DwarfStateMachine* state, | |
Dwarf_AddressInfo* info); | |
/* Gets pointer to the DIE descriptor for this CU. */ | |
const Dwarf_DIE* get_DIE() const { | |
/* CU's DIE descriptor immediately follows CU header. */ | |
return INC_CPTR_T(Dwarf_DIE, cu_header_, sizeof(Dwarf_CUHdr)); | |
} | |
/* Caches STMTL header from .debug_line section to stmtl_header_. | |
* Template param: | |
* Dwarf_STMTL_Hdr - Dwarf_STMTL_Hdr32, or Dwarf_STMTL_Hdr64, depending | |
* on the header type. | |
* Param: | |
* stmtl_hdr - STMTL header in the mapped .debug_line section to cache. | |
*/ | |
template <typename Dwarf_STMTL_Hdr> | |
void cache_stmtl(const Dwarf_STMTL_Hdr* stmtl_hdr) { | |
stmtl_header_.unit_length = elf_file()->pull_val(stmtl_hdr->unit_length.size); | |
stmtl_header_.version = elf_file()->pull_val(stmtl_hdr->version); | |
stmtl_header_.header_length = elf_file()->pull_val(stmtl_hdr->header_length); | |
stmtl_header_.min_instruction_len = stmtl_hdr->min_instruction_len; | |
stmtl_header_.default_is_stmt = stmtl_hdr->default_is_stmt; | |
stmtl_header_.line_base = stmtl_hdr->line_base; | |
stmtl_header_.line_range = stmtl_hdr->line_range; | |
stmtl_header_.opcode_base = stmtl_hdr->opcode_base; | |
stmtl_header_.standard_opcode_lengths = &stmtl_hdr->standard_opcode_lengths; | |
stmtl_header_.start = INC_CPTR_T(Elf_Byte, &stmtl_hdr->min_instruction_len, | |
stmtl_header_.header_length); | |
stmtl_header_.end = INC_CPTR_T(Elf_Byte, &stmtl_hdr->version, | |
stmtl_header_.unit_length); | |
stmtl_header_.include_directories = | |
INC_CPTR_T(char, stmtl_header_.standard_opcode_lengths, | |
stmtl_header_.opcode_base - 1); | |
const char* dir = stmtl_header_.include_directories; | |
while (*dir != '\0') { | |
dir += strlen(dir) + 1; | |
stmtl_header_.inc_dir_num++; | |
} | |
stmtl_header_.file_infos = INC_CPTR_T(Dwarf_STMTL_FileDesc, dir, 1); | |
} | |
/* Gets a DIE referenced by an offset from the beginning of this CU | |
* in the mapped .debug_info section. | |
*/ | |
const Dwarf_DIE* get_referenced_die(Elf_Word ref) const { | |
return INC_CPTR_T(Dwarf_DIE, cu_header_, ref); | |
} | |
/* Checks if pointer to the DIE attribute is contained within the CU's area | |
* of the mapped .debug_info section. | |
* Param: | |
* ptr - Pointer to the DIE attribute to check. | |
* Return: | |
* true, if pointer to the DIE attribute is contained within the CU's area | |
* of the mapped .debug_info section, or false if attribute pointer goes | |
* beyond CU's area of the mapped .debug_info section. | |
*/ | |
bool is_attrib_ptr_valid(const void* ptr) const { | |
return diff_ptr(cu_header_, ptr) < cu_size_; | |
} | |
protected: | |
/* Pointer to this compilation unit header inside the mapped .debug_info | |
* section of the ELF file. | |
*/ | |
const Dwarf_CUHdr* cu_header_; | |
/* Size of this compilation unit area in the mapped .debug_info section. | |
* This value has been cached off the CU header in order to avoid | |
* endianness conversions. | |
*/ | |
Dwarf_Off cu_size_; | |
/* STMT lines header, cached off mapped .debug_line section. */ | |
Dwarf_STMTL_Hdr stmtl_header_; | |
}; | |
#endif // ELFF_DWARF_CU_H_ |