summaryrefslogtreecommitdiffstats
path: root/compiler/debug/elf_debug_reader.h
blob: 91b1b3ea819136efbbf5463a8c30215db761bf14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_
#define ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_

#include "base/array_ref.h"
#include "debug/dwarf/headers.h"
#include "elf.h"
#include "xz_utils.h"

namespace art {
namespace debug {

// Trivial ELF file reader.
//
// It is the bare minimum needed to read mini-debug-info symbols for unwinding.
// We use it to merge JIT mini-debug-infos together or to prune them after GC.
// The consumed ELF file comes from ART JIT.
template <typename ElfTypes, typename VisitSym, typename VisitFde>
static void ReadElfSymbols(const uint8_t* elf, VisitSym visit_sym, VisitFde visit_fde) {
  // Note that the input buffer might be misaligned.
  typedef typename ElfTypes::Ehdr ALIGNED(1) Elf_Ehdr;
  typedef typename ElfTypes::Shdr ALIGNED(1) Elf_Shdr;
  typedef typename ElfTypes::Sym ALIGNED(1) Elf_Sym;
  typedef typename ElfTypes::Addr ALIGNED(1) Elf_Addr;

  // Read and check the elf header.
  const Elf_Ehdr* header = reinterpret_cast<const Elf_Ehdr*>(elf);
  CHECK(header->checkMagic());

  // Find sections that we are interested in.
  const Elf_Shdr* sections = reinterpret_cast<const Elf_Shdr*>(elf + header->e_shoff);
  const Elf_Shdr* strtab = nullptr;
  const Elf_Shdr* symtab = nullptr;
  const Elf_Shdr* debug_frame = nullptr;
  const Elf_Shdr* gnu_debugdata = nullptr;
  for (size_t i = 1 /* skip null section */; i < header->e_shnum; i++) {
    const Elf_Shdr* section = sections + i;
    const char* name = reinterpret_cast<const char*>(
        elf + sections[header->e_shstrndx].sh_offset + section->sh_name);
    if (strcmp(name, ".strtab") == 0) {
      strtab = section;
    } else if (strcmp(name, ".symtab") == 0) {
      symtab = section;
    } else if (strcmp(name, ".debug_frame") == 0) {
      debug_frame = section;
    } else if (strcmp(name, ".gnu_debugdata") == 0) {
      gnu_debugdata = section;
    }
  }

  // Visit symbols.
  if (symtab != nullptr && strtab != nullptr) {
    const Elf_Sym* symbols = reinterpret_cast<const Elf_Sym*>(elf + symtab->sh_offset);
    DCHECK_EQ(symtab->sh_entsize, sizeof(Elf_Sym));
    size_t count = symtab->sh_size / sizeof(Elf_Sym);
    for (size_t i = 1 /* skip null symbol */; i < count; i++) {
      Elf_Sym symbol = symbols[i];
      if (symbol.getBinding() != STB_LOCAL) {  // Ignore local symbols (e.g. "$t").
        const uint8_t* name = elf + strtab->sh_offset + symbol.st_name;
        visit_sym(symbol, reinterpret_cast<const char*>(name));
      }
    }
  }

  // Visit CFI (unwind) data.
  if (debug_frame != nullptr) {
    const uint8_t* data = elf + debug_frame->sh_offset;
    const uint8_t* end = data + debug_frame->sh_size;
    while (data < end) {
      Elf_Addr addr, size;
      ArrayRef<const uint8_t> opcodes;
      if (dwarf::ReadFDE<Elf_Addr>(&data, &addr, &size, &opcodes)) {
        visit_fde(addr, size, opcodes);
      }
    }
  }

  // Process embedded compressed ELF file.
  if (gnu_debugdata != nullptr) {
    ArrayRef<const uint8_t> compressed(elf + gnu_debugdata->sh_offset, gnu_debugdata->sh_size);
    std::vector<uint8_t> decompressed;
    XzDecompress(compressed, &decompressed);
    ReadElfSymbols<ElfTypes>(decompressed.data(), visit_sym, visit_fde);
  }
}

}  // namespace debug
}  // namespace art
#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_