普通文本  |  759行  |  25.69 KB

/* 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;
}