1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "elf_debug_writer.h"
18
19#include <vector>
20
21#include "debug/dwarf/dwarf_constants.h"
22#include "debug/elf_compilation_unit.h"
23#include "debug/elf_debug_frame_writer.h"
24#include "debug/elf_debug_info_writer.h"
25#include "debug/elf_debug_line_writer.h"
26#include "debug/elf_debug_loc_writer.h"
27#include "debug/elf_gnu_debugdata_writer.h"
28#include "debug/elf_symtab_writer.h"
29#include "debug/method_debug_info.h"
30#include "elf_builder.h"
31#include "linker/vector_output_stream.h"
32#include "utils/array_ref.h"
33
34namespace art {
35namespace debug {
36
37template <typename ElfTypes>
38void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
39                    const ArrayRef<const MethodDebugInfo>& method_infos,
40                    dwarf::CFIFormat cfi_format,
41                    bool write_oat_patches) {
42  // Write .strtab and .symtab.
43  WriteDebugSymbols(builder, method_infos, true /* with_signature */);
44
45  // Write .debug_frame.
46  WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
47
48  // Group the methods into compilation units based on source file.
49  std::vector<ElfCompilationUnit> compilation_units;
50  const char* last_source_file = nullptr;
51  for (const MethodDebugInfo& mi : method_infos) {
52    if (mi.dex_file != nullptr) {
53      auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
54      const char* source_file = mi.dex_file->GetSourceFile(dex_class_def);
55      if (compilation_units.empty() || source_file != last_source_file) {
56        compilation_units.push_back(ElfCompilationUnit());
57      }
58      ElfCompilationUnit& cu = compilation_units.back();
59      cu.methods.push_back(&mi);
60      // All methods must have the same addressing mode otherwise the min/max below does not work.
61      DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
62      cu.is_code_address_text_relative = mi.is_code_address_text_relative;
63      cu.code_address = std::min(cu.code_address, mi.code_address);
64      cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
65      last_source_file = source_file;
66    }
67  }
68
69  // Write .debug_line section.
70  if (!compilation_units.empty()) {
71    ElfDebugLineWriter<ElfTypes> line_writer(builder);
72    line_writer.Start();
73    for (auto& compilation_unit : compilation_units) {
74      line_writer.WriteCompilationUnit(compilation_unit);
75    }
76    line_writer.End(write_oat_patches);
77  }
78
79  // Write .debug_info section.
80  if (!compilation_units.empty()) {
81    ElfDebugInfoWriter<ElfTypes> info_writer(builder);
82    info_writer.Start();
83    for (const auto& compilation_unit : compilation_units) {
84      ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
85      cu_writer.Write(compilation_unit);
86    }
87    info_writer.End(write_oat_patches);
88  }
89}
90
91std::vector<uint8_t> MakeMiniDebugInfo(
92    InstructionSet isa,
93    const InstructionSetFeatures* features,
94    size_t rodata_size,
95    size_t text_size,
96    const ArrayRef<const MethodDebugInfo>& method_infos) {
97  if (Is64BitInstructionSet(isa)) {
98    return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
99                                                 features,
100                                                 rodata_size,
101                                                 text_size,
102                                                 method_infos);
103  } else {
104    return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
105                                                 features,
106                                                 rodata_size,
107                                                 text_size,
108                                                 method_infos);
109  }
110}
111
112template <typename ElfTypes>
113static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal(
114    InstructionSet isa,
115    const InstructionSetFeatures* features,
116    const ArrayRef<const MethodDebugInfo>& method_infos) {
117  std::vector<uint8_t> buffer;
118  buffer.reserve(KB);
119  VectorOutputStream out("Debug ELF file", &buffer);
120  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out));
121  // No program headers since the ELF file is not linked and has no allocated sections.
122  builder->Start(false /* write_program_headers */);
123  WriteDebugInfo(builder.get(),
124                 method_infos,
125                 dwarf::DW_DEBUG_FRAME_FORMAT,
126                 false /* write_oat_patches */);
127  builder->End();
128  CHECK(builder->Good());
129  return buffer;
130}
131
132std::vector<uint8_t> WriteDebugElfFileForMethods(
133    InstructionSet isa,
134    const InstructionSetFeatures* features,
135    const ArrayRef<const MethodDebugInfo>& method_infos) {
136  if (Is64BitInstructionSet(isa)) {
137    return WriteDebugElfFileForMethodsInternal<ElfTypes64>(isa, features, method_infos);
138  } else {
139    return WriteDebugElfFileForMethodsInternal<ElfTypes32>(isa, features, method_infos);
140  }
141}
142
143template <typename ElfTypes>
144static std::vector<uint8_t> WriteDebugElfFileForClassesInternal(
145    InstructionSet isa,
146    const InstructionSetFeatures* features,
147    const ArrayRef<mirror::Class*>& types)
148    SHARED_REQUIRES(Locks::mutator_lock_) {
149  std::vector<uint8_t> buffer;
150  buffer.reserve(KB);
151  VectorOutputStream out("Debug ELF file", &buffer);
152  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out));
153  // No program headers since the ELF file is not linked and has no allocated sections.
154  builder->Start(false /* write_program_headers */);
155  ElfDebugInfoWriter<ElfTypes> info_writer(builder.get());
156  info_writer.Start();
157  ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
158  cu_writer.Write(types);
159  info_writer.End(false /* write_oat_patches */);
160
161  builder->End();
162  CHECK(builder->Good());
163  return buffer;
164}
165
166std::vector<uint8_t> WriteDebugElfFileForClasses(InstructionSet isa,
167                                                 const InstructionSetFeatures* features,
168                                                 const ArrayRef<mirror::Class*>& types) {
169  if (Is64BitInstructionSet(isa)) {
170    return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, features, types);
171  } else {
172    return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, features, types);
173  }
174}
175
176std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& header) {
177  std::map<const char*, uint32_t> trampolines = {
178    { "interpreterToInterpreterBridge", header.GetInterpreterToInterpreterBridgeOffset() },
179    { "interpreterToCompiledCodeBridge", header.GetInterpreterToCompiledCodeBridgeOffset() },
180    { "jniDlsymLookup", header.GetJniDlsymLookupOffset() },
181    { "quickGenericJniTrampoline", header.GetQuickGenericJniTrampolineOffset() },
182    { "quickImtConflictTrampoline", header.GetQuickImtConflictTrampolineOffset() },
183    { "quickResolutionTrampoline", header.GetQuickResolutionTrampolineOffset() },
184    { "quickToInterpreterBridge", header.GetQuickToInterpreterBridgeOffset() },
185  };
186  std::vector<MethodDebugInfo> result;
187  for (const auto& it : trampolines) {
188    if (it.second != 0) {
189      MethodDebugInfo info = MethodDebugInfo();
190      info.trampoline_name = it.first;
191      info.isa = header.GetInstructionSet();
192      info.is_code_address_text_relative = true;
193      info.code_address = it.second - header.GetExecutableOffset();
194      info.code_size = 0;  // The symbol lasts until the next symbol.
195      result.push_back(std::move(info));
196    }
197  }
198  return result;
199}
200
201// Explicit instantiations
202template void WriteDebugInfo<ElfTypes32>(
203    ElfBuilder<ElfTypes32>* builder,
204    const ArrayRef<const MethodDebugInfo>& method_infos,
205    dwarf::CFIFormat cfi_format,
206    bool write_oat_patches);
207template void WriteDebugInfo<ElfTypes64>(
208    ElfBuilder<ElfTypes64>* builder,
209    const ArrayRef<const MethodDebugInfo>& method_infos,
210    dwarf::CFIFormat cfi_format,
211    bool write_oat_patches);
212
213}  // namespace debug
214}  // namespace art
215