blob: ab979788514c5f50c0039802d4fbaf974560d15d [file] [log] [blame]
/* 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 implementation of a class DwarfCU, that encapsulates a compilation
* unit in the .debug_info section of the mapped ELF file.
*/
#include "string.h"
#include "stdio.h"
#include "elf_file.h"
#include "dwarf_cu.h"
#include "dwarf_utils.h"
DwarfCU::DwarfCU(ElfFile* elf)
: elf_file_(elf),
cu_die_(NULL),
prev_cu_(NULL) {
}
DwarfCU::~DwarfCU() {
if (cu_die_ != NULL) {
delete cu_die_;
}
abbrs_.empty();
}
DwarfCU* DwarfCU::create_instance(ElfFile* elf, const void* hdr) {
DwarfCU* ret;
/* 64-bit DWARF CU has first 4 bytes in its header set to 0xFFFFFFFF. */
if (*reinterpret_cast<const Elf_Word*>(hdr) == 0xFFFFFFFF) {
ret = new(elf) DwarfCUImpl<Dwarf64_CUHdr, Dwarf64_Off>
(elf, reinterpret_cast<const Dwarf64_CUHdr*>(hdr));
} else {
ret = new(elf) DwarfCUImpl<Dwarf32_CUHdr, Dwarf32_Off>
(elf, reinterpret_cast<const Dwarf32_CUHdr*>(hdr));
}
assert(ret != NULL);
if (ret == NULL) {
_set_errno(ENOMEM);
}
return ret;
}
const Elf_Byte* DwarfCU::process_attrib(const Elf_Byte* prop,
Dwarf_Form form,
Dwarf_Value* attr_value) const {
assert(form != 0);
Dwarf_Value tmp_val;
Dwarf_Value leb128;
attr_value->type = DWARF_VALUE_UNKNOWN;
attr_value->encoded_size = 0;
attr_value->u64 = 0;
switch (form) {
/* Property is a block of data, contained in .debug_info section. Block
* size is encoded with 1 byte value, and block data immediately follows
* block size. */
case DW_FORM_block1:
attr_value->type = DWARF_VALUE_BLOCK;
attr_value->block.block_size = *prop;
attr_value->block.block_ptr = prop + 1;
attr_value->encoded_size =
static_cast<Elf_Word>(attr_value->block.block_size + 1);
break;
/* Property is a block of data, contained in .debug_info section. Block
* size is encoded with 2 bytes value, and block data immediately follows
* block size. */
case DW_FORM_block2:
attr_value->type = DWARF_VALUE_BLOCK;
attr_value->block.block_size =
elf_file_->pull_val(reinterpret_cast<const Elf_Half*>(prop));
attr_value->block.block_ptr = prop + 2;
attr_value->encoded_size =
static_cast<Elf_Word>(attr_value->block.block_size + 2);
break;
/* Property is a block of data, contained in .debug_info section. Block
* size is encoded with 4 bytes value, and block data immediately follows
* block size. */
case DW_FORM_block4:
attr_value->type = DWARF_VALUE_BLOCK;
attr_value->block.block_size =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
attr_value->block.block_ptr = prop + 4;
attr_value->encoded_size =
static_cast<Elf_Word>(attr_value->block.block_size + 4);
break;
/* Property is a block of data, contained in .debug_info section. Block
* size is encoded with unsigned LEB128 value, and block data immediately
* follows block size. */
case DW_FORM_block:
reinterpret_cast<const Dwarf_Leb128*>(prop)->process_unsigned(&leb128);
attr_value->type = DWARF_VALUE_BLOCK;
attr_value->block.block_size = leb128.u32;
attr_value->block.block_ptr = prop + leb128.encoded_size;
attr_value->encoded_size =
static_cast<Elf_Word>(attr_value->block.block_size +
leb128.encoded_size);
break;
/* Property is unsigned 1 byte value. */
case DW_FORM_flag:
case DW_FORM_data1:
case DW_FORM_ref1:
attr_value->type = DWARF_VALUE_U8;
attr_value->u8 = *prop;
attr_value->encoded_size = 1;
break;
/* Property is unsigned 2 bytes value. */
case DW_FORM_data2:
case DW_FORM_ref2:
attr_value->type = DWARF_VALUE_U16;
attr_value->u16 =
elf_file_->pull_val(reinterpret_cast<const Elf_Half*>(prop));
attr_value->encoded_size = 2;
break;
/* Property is unsigned 4 bytes value. */
case DW_FORM_data4:
case DW_FORM_ref4:
attr_value->type = DWARF_VALUE_U32;
attr_value->u32 =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
attr_value->encoded_size = 4;
break;
/* Property is unsigned 8 bytes value. */
case DW_FORM_data8:
case DW_FORM_ref8:
case DW_FORM_ref_sig8:
attr_value->type = DWARF_VALUE_U64;
attr_value->u64 =
elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));
attr_value->encoded_size = 8;
break;
/* Property is signed LEB128 value. */
case DW_FORM_sdata:
reinterpret_cast<const Dwarf_Leb128*>(prop)->process_signed(attr_value);
break;
/* Property is unsigned LEB128 value. */
case DW_FORM_ref_udata:
case DW_FORM_udata:
reinterpret_cast<const Dwarf_Leb128*>(prop)->process_unsigned(attr_value);
break;
/* Property is a string contained directly in .debug_info section. */
case DW_FORM_string:
attr_value->type = DWARF_VALUE_STR;
attr_value->str = reinterpret_cast<const char*>(prop);
attr_value->encoded_size = strlen(attr_value->str) + 1;
break;
/* Property is an offset of a string contained in .debug_str section.
* We will process the reference here, converting it into the actual
* string value. */
case DW_FORM_strp:
attr_value->type = DWARF_VALUE_STR;
if (elf_file_->is_DWARF_64()) {
Elf_Xword str_offset =
elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));
attr_value->str = elf_file_->get_debug_str(str_offset);
attr_value->encoded_size = 8;
} else {
Elf_Word str_offset =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
attr_value->str = elf_file_->get_debug_str(str_offset);
attr_value->encoded_size = 4;
}
break;
/* Property is an address. */
case DW_FORM_addr:
if (addr_sizeof_ == 4) {
attr_value->type = DWARF_VALUE_PTR32;
attr_value->u32 =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
} else {
attr_value->type = DWARF_VALUE_PTR64;
attr_value->u64 =
elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));
}
attr_value->encoded_size = addr_sizeof_;
break;
/* Reference from the beginning of .debug_info section. */
case DW_FORM_ref_addr:
/* DWARF3+ requires that encoding size of this property must be 4 bytes
* in 32-bit DWARF, and 8 bytes in 64-bit DWARF, while DWARF2- requires
* encoding size to be equal to CU's pointer size. */
if (is_DWARF3_or_higher()) {
if (elf_file_->is_DWARF_64()) {
attr_value->type = DWARF_VALUE_U64;
attr_value->u64 =
elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));
attr_value->encoded_size = 4;
} else {
attr_value->type = DWARF_VALUE_U32;
attr_value->u32 =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
attr_value->encoded_size = 8;
}
} else {
if (addr_sizeof_ == 4) {
attr_value->type = DWARF_VALUE_U32;
attr_value->u32 =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
} else {
attr_value->type = DWARF_VALUE_U64;
attr_value->u64 =
elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));
}
attr_value->encoded_size = addr_sizeof_;
}
break;
/* Reference to a section, other than .debug_info, or .debug_str */
case DW_FORM_sec_offset:
if (elf_file_->is_DWARF_64()) {
attr_value->type = DWARF_VALUE_U64;
attr_value->u64 =
elf_file_->pull_val(reinterpret_cast<const Elf_Xword*>(prop));
attr_value->encoded_size = 4;
} else {
attr_value->type = DWARF_VALUE_U32;
attr_value->u32 =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
attr_value->encoded_size = 8;
}
break;
/* This is a replacement for DW_FORM_flag, which doesn't consume memory
* in .debug_info section, and only by the fact of its existence it is
* equal to DW_FORM_flag with value set to 1. */
case DW_FORM_flag_present:
attr_value->type = DWARF_VALUE_U8;
attr_value->u8 = 1;
attr_value->encoded_size = 0;
break;
/* Encodes the actual form to be used. */
case DW_FORM_indirect:
// Starts with ULEB128
prop = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>
(prop)->process_unsigned(&tmp_val));
/* ULEB128 encodes the actual form to be used to process this entry. */
process_attrib(prop, tmp_val.u16, attr_value);
attr_value->encoded_size += tmp_val.encoded_size;
break;
/* This form is defined for DWARF4, and has no documentation whatsoever. */
case DW_FORM_exprloc:
default:
attr_value->type = DWARF_VALUE_U32;
attr_value->u32 =
elf_file_->pull_val(reinterpret_cast<const Elf_Word*>(prop));
attr_value->encoded_size = 4;
break;
}
return prop + attr_value->encoded_size;
}
void DwarfCU::dump() const {
printf("\n\n>>>>>>>>>>>>>>> CU %p (version %u, address size %u)\n",
cu_die_->die(), static_cast<Elf_Word>(version_),
static_cast<Elf_Word>(addr_sizeof_));
printf(">>>>> Build dir path: %s\n", comp_dir_path());
printf(">>>>> Build file path: %s\n", rel_cu_path());
if (cu_die_ != NULL) {
cu_die_->dump(false);
}
}
//=============================================================================
// DwarfCUImpl implementation
//=============================================================================
template <typename Dwarf_CUHdr, typename Dwarf_Off>
DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::DwarfCUImpl(ElfFile* elf,
const Dwarf_CUHdr* hdr)
: DwarfCU(elf),
cu_header_(hdr) {
/* Cache CU's DIE abbreviation descriptor in the array. This MUST be done
* BEFORE first call to array's cache_to() method. */
const Dwarf_Abbr_DIE* cu_abbr_die = reinterpret_cast<const Dwarf_Abbr_DIE*>
(INC_CPTR(elf->get_debug_abbrev_data(),
elf->pull_val(hdr->abbrev_offset)));
abbrs_.add(cu_abbr_die);
cu_size_ = elf->pull_val(hdr->size_hdr.size);
version_ = elf->pull_val(hdr->version);
addr_sizeof_ = hdr->address_size;
memset(&stmtl_header_, 0, sizeof(stmtl_header_));
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::parse(
const DwarfParseContext* parse_context,
const void** next_cu_die) {
/* Start parsing with the DIE for this CU. */
if (process_DIE(parse_context, get_DIE(), NULL) == NULL) {
return false;
}
/* CU area size (thus, next CU header offset) in .debug_info section equals
* to CU size, plus number of bytes, required to encode CU size in CU header
* (4 for 32-bit CU, and 12 for 64-bit CU. */
*next_cu_die =
INC_CPTR(cu_header_, cu_size_ + ELFF_FIELD_OFFSET(Dwarf_CUHdr, version));
return true;
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
const Elf_Byte* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::process_DIE(
const DwarfParseContext* parse_context,
const Dwarf_DIE* die,
DIEObject* parent_obj) {
while (is_attrib_ptr_valid(die) && !die->is_separator()) {
Dwarf_AbbrNum abbr_num;
Dwarf_Tag die_tag;
Elf_Word sibling_off = 0;
/* Get DIE's abbreviation number, and advance to DIE's properties. */
const Elf_Byte* die_attr = die->process(&abbr_num);
/* Get abbreviation for the current DIE. */
const Dwarf_Abbr_DIE* die_abbr = abbrs_.cache_to(abbr_num);
if (die_abbr == NULL) {
return NULL;
}
/* Get base DIE properties, and advance to the DIE's
* attribute descriptors. */
const Dwarf_Abbr_AT* at_abbr = die_abbr->process(NULL, &die_tag);
/* Instantiate DIE object for this DIE, and get list of properties,
* that should be collected while processing that DIE. */
DIEObject* die_obj =
create_die_object(parse_context, die, parent_obj, die_tag);
if (die_obj == NULL && errno != 0) {
return NULL;
}
if (die_obj != NULL) {
if (parent_obj != NULL) {
/* Update list of parent's children. */
die_obj->link_sibling(parent_obj->last_child());
parent_obj->link_child(die_obj);
} else {
/* NULL parent object is allowed only for CU DIE itself. */
assert(cu_die_ == NULL && die_tag == DW_TAG_compile_unit);
if (cu_die_ == NULL && die_tag != DW_TAG_compile_unit) {
_set_errno(EINVAL);
return NULL;
}
cu_die_ = die_obj;
/* This CU DIE object will be used as a parent for all DIE
* objects, created in this method. */
parent_obj = cu_die_;
}
}
// Loop through all DIE properties.
while (elf_file_->is_valid_abbr_ptr(at_abbr, sizeof(Dwarf_Abbr_AT)) &&
!at_abbr->is_separator()) {
Dwarf_At at_value;
Dwarf_Form at_form;
Dwarf_Value attr_value;
// Obtain next property value.
at_abbr = at_abbr->process(&at_value, &at_form);
die_attr = process_attrib(die_attr, at_form, &attr_value);
if (at_value == DW_AT_sibling) {
/* DW_AT_sibling means that next DIE is a child of the one that's
* being currently processed. We need to cache value of this property
* in order to correctly calculate next sibling of this DIE after
* child's DIE has been processed. */
assert(sibling_off == 0);
sibling_off = attr_value.u32;
}
}
/* Next DIE immediately follows last property for the current DIE. */
die = reinterpret_cast<const Dwarf_DIE*>(die_attr);
if (sibling_off != 0) {
// Process child DIE.
process_DIE(parse_context, die, die_obj != NULL ? die_obj : parent_obj);
// Next sibling DIE offset is relative to this CU's header beginning.
die = INC_CPTR_T(Dwarf_DIE, cu_header_, sibling_off);
}
}
return INC_CPTR_T(Elf_Byte, die, 1);
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
DIEObject* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::create_die_object(
const DwarfParseContext* parse_context,
const Dwarf_DIE* die,
DIEObject* parent,
Dwarf_Tag tag) {
DIEObject* ret = NULL;
/* We will always create a DIE object for CU DIE. */
if (tag == DW_TAG_compile_unit || collect_die(parse_context, tag)) {
ret = new(elf_file_) DIEObject(die, this, parent);
assert(ret != NULL);
if (ret == NULL) {
_set_errno(ENOMEM);
}
} else {
_set_errno(0);
}
return ret;
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::init_stmtl() {
if (stmtl_header_.unit_length != 0) {
return true;
}
assert(cu_die_ != NULL);
if (cu_die_ == NULL) {
_set_errno(EINVAL);
return false;
}
DIEAttrib stmtl;
if (!cu_die()->get_attrib(DW_AT_stmt_list, &stmtl)) {
_set_errno(EINVAL);
return false;
}
const void* stmtl_start =
INC_CPTR(elf_file()->get_debug_line_data(), stmtl.value()->u32);
if (*reinterpret_cast<const Elf_Word*>(stmtl_start) == 0xFFFFFFFF) {
cache_stmtl<Dwarf64_STMTLHdr>(reinterpret_cast<const Dwarf64_STMTLHdr*>(stmtl_start));
} else {
cache_stmtl<Dwarf32_STMTLHdr>(reinterpret_cast<const Dwarf32_STMTLHdr*>(stmtl_start));
}
return true;
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::get_pc_address_file_info(
Elf_Xword address,
Dwarf_AddressInfo* info) {
/* Make sure STMTL header is cached. */
if (!init_stmtl()) {
return false;
}
/* Flags address match, that should trigger return next time
* source line gets adjusted. */
bool found = false;
/* Create new state machine. */
DwarfStateMachine state(stmtl_header_.default_is_stmt != 0);
/* Start the "Line Number Program" */
const Elf_Byte* go = stmtl_header_.start;
while (go < stmtl_header_.end) {
const Elf_Byte op = *go;
go++;
if (op == 0) {
/* This is an extended opcode. */
Dwarf_Value op_size;
/* First ULEB128 contains opcode size, (excluding ULEB128 itself). */
go = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&op_size));
/* Next is the extended opcode. */
const Elf_Byte* ex_op_ptr = go;
switch (*ex_op_ptr) {
case DW_LNE_end_sequence:
state.end_sequence_ = true;
state.reset(stmtl_header_.default_is_stmt != 0);
found = false;
break;
case DW_LNE_set_address: {
Elf_Xword prev_address = state.address_;
if (is_CU_address_64()) {
state.address_ =
elf_file()->pull_val(reinterpret_cast<const Elf_Xword*>(ex_op_ptr + 1));
} else {
state.address_ =
elf_file()->pull_val(reinterpret_cast<const Elf_Word*>(ex_op_ptr + 1));
}
if (prev_address != 0 &&
address >= prev_address && address < state.address_) {
return set_source_info(&state, info);
} else if (address == state.address_) {
found = true;
}
break;
}
case DW_LNE_define_file: {
/* Parameters start with the directly encoded zero-terminated
* file name. */
state.set_file_info_ = INC_CPTR_T(Dwarf_STMTL_FileDesc, ex_op_ptr, 1);
assert(state.set_file_info_ != NULL);
if (state.set_file_info_ != NULL) {
ex_op_ptr = reinterpret_cast<const Elf_Byte*>(state.set_file_info_->process(NULL));
}
break;
}
case DW_LNE_set_discriminator: {
Dwarf_Value discr_val;
/* One parameter: discriminator's ULEB128 value. */
reinterpret_cast<const Dwarf_Leb128*>(ex_op_ptr + 1)->process_unsigned(&discr_val);
state.discriminator_ = discr_val.u32;
break;
}
default:
assert(0);
return false;
}
go += op_size.u32;
} else if (op < stmtl_header_.opcode_base) {
/* This is a standard opcode. */
switch (op) {
case DW_LNS_copy:
/* No parameters. */
state.basic_block_ = false;
state.prologue_end_ = false;
state.epilogue_begin_ = false;
break;
case DW_LNS_advance_pc: {
/* One parameter: ULEB128 value to add to the current address value
* in the state machine. */
Dwarf_Value addr_add;
go = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&addr_add));
Elf_Xword prev_address = state.address_;
state.address_ += addr_add.u64;
if (prev_address != 0 &&
address >= prev_address && address < state.address_) {
return set_source_info(&state, info);
} else if (address == state.address_) {
found = true;
}
break;
}
case DW_LNS_advance_line: {
/* One parameter: signed LEB128 value to add to the current line
* number in the state machine. */
Dwarf_Value line_add;
go = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>(go)->process_signed(&line_add));
state.line_ += line_add.s32;
if (found) {
return set_source_info(&state, info);
}
break;
}
case DW_LNS_set_file: {
/* One parameter: ULEB128 value encoding current file number. */
Dwarf_Value file_num;
go = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&file_num));
state.file_ = file_num.u32;
/* This operation should discard previously saved file information. */
state.set_file_info_ = NULL;
break;
}
case DW_LNS_set_column: {
/* One parameter: ULEB128 value encoding current column number. */
Dwarf_Value column_num;
go = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&column_num));
state.column_ = column_num.u32;
break;
}
case DW_LNS_negate_stmt:
/* No parameters. */
state.is_stmt_ = !state.is_stmt_;
break;
case DW_LNS_set_basic_block:
/* No parameters. */
state.basic_block_ = true;
break;
case DW_LNS_const_add_pc: {
Elf_Xword prev_address = state.address_;
/* No parameters. This operation does the same thing, as special
* opcode 255 would do to the current address. */
Elf_Word adjusted =
static_cast<Elf_Word>(255) - stmtl_header_.opcode_base;
state.address_ += (adjusted / stmtl_header_.line_range) *
stmtl_header_.min_instruction_len;
if (prev_address != 0 &&
address >= prev_address && address < state.address_) {
return set_source_info(&state, info);
} else if (address == state.address_) {
found = true;
}
break;
}
case DW_LNS_fixed_advance_pc: {
Elf_Xword prev_address = state.address_;
/* One parameter: directly encoded 16-bit value to add to the
* current address. */
state.address_ +=
elf_file()->pull_val(reinterpret_cast<const Elf_Half*>(go));
if (prev_address != 0 &&
address >= prev_address && address < state.address_) {
return set_source_info(&state, info);
} else if (address == state.address_) {
found = true;
}
go += sizeof(Elf_Half);
break;
}
case DW_LNS_set_prologue_end:
/* No parameters. */
state.prologue_end_ = true;
break;
case DW_LNS_set_epilogue_begin:
/* No parameters. */
state.epilogue_begin_ = true;
break;
case DW_LNS_set_isa: {
/* One parameter: ISA value encoded as ULEB128. */
Dwarf_Value isa_val;
go = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&isa_val));
state.isa_ = isa_val.u32;
break;
}
default:
/* Unknown opcode. Just skip it. */
for (Elf_Byte uleb = 0;
uleb < stmtl_header_.standard_opcode_lengths[op - 1]; uleb++) {
Dwarf_Value tmp;
go = reinterpret_cast<const Elf_Byte*>
(reinterpret_cast<const Dwarf_Leb128*>(go)->process_unsigned(&tmp));
}
break;
}
} else {
Elf_Xword prev_address = state.address_;
/* This is a special opcode. */
const Elf_Word adjusted = op - stmtl_header_.opcode_base;
/* Advance address. */
state.address_ += (adjusted / stmtl_header_.line_range) *
stmtl_header_.min_instruction_len;
if (prev_address != 0 &&
address >= prev_address && address < state.address_) {
return set_source_info(&state, info);
}
/* Advance line. */
state.line_ += stmtl_header_.line_base +
(adjusted % stmtl_header_.line_range);
if (state.address_ == address) {
return set_source_info(&state, info);
}
/* Do the woodoo. */
state.basic_block_ = false;
state.prologue_end_ = false;
state.epilogue_begin_ = false;
}
}
return false;
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
const Dwarf_STMTL_FileDesc* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::get_stmt_file_info(
Elf_Word index) {
/* Index must be 1-based. */
if (index == 0) {
return NULL;
}
const Dwarf_STMTL_FileDesc* cur_desc = stmtl_header_.file_infos;
while (index != 1 && !cur_desc->is_last_entry()) {
cur_desc = cur_desc->process(NULL);
index--;
}
assert(!cur_desc->is_last_entry());
return cur_desc->is_last_entry() ? NULL : cur_desc;
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
const char* DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::get_stmt_dir_name(
Elf_Word dir_index) {
if (dir_index == 0) {
/* Requested is current compilation directory. */
return comp_dir_path();
}
if (dir_index > stmtl_header_.inc_dir_num) {
return NULL;
}
const char* cur_dir = stmtl_header_.include_directories;
while (dir_index != 1) {
cur_dir += strlen(cur_dir) + 1;
dir_index--;
}
return cur_dir;
}
template <typename Dwarf_CUHdr, typename Dwarf_Off>
bool DwarfCUImpl<Dwarf_CUHdr, Dwarf_Off>::set_source_info(
const DwarfStateMachine* state,
Dwarf_AddressInfo* info) {
info->line_number = state->line_;
const Dwarf_STMTL_FileDesc* file_info = state->set_file_info_;
if (file_info == NULL) {
file_info = get_stmt_file_info(state->file_);
if (file_info == NULL) {
info->file_name = rel_cu_path();
info->dir_name = comp_dir_path();
return true;
}
}
info->file_name = file_info->get_file_name();
const Elf_Word dir_index = file_info->get_dir_index();
info->dir_name = get_stmt_dir_name(dir_index);
return true;
}