blob: e5c09aa379ed20471407df2d7d237d9e55aebcf0 [file] [log] [blame]
David Srbeckyc5bfa972016-02-05 15:49:10 +00001/*
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
David Srbeckybe50f9a2018-12-05 10:48:42 +000019#include <type_traits>
David Srbecky56da23c2017-09-08 19:59:15 +010020#include <unordered_map>
David Srbeckybe50f9a2018-12-05 10:48:42 +000021#include <vector>
David Srbeckyc5bfa972016-02-05 15:49:10 +000022
David Brazdild9c90372016-09-14 16:53:55 +010023#include "base/array_ref.h"
David Srbecky0b21e412018-12-05 13:24:06 +000024#include "base/stl_util.h"
David Srbeckyc5bfa972016-02-05 15:49:10 +000025#include "debug/dwarf/dwarf_constants.h"
26#include "debug/elf_compilation_unit.h"
27#include "debug/elf_debug_frame_writer.h"
28#include "debug/elf_debug_info_writer.h"
29#include "debug/elf_debug_line_writer.h"
30#include "debug/elf_debug_loc_writer.h"
David Srbecky0b21e412018-12-05 13:24:06 +000031#include "debug/elf_debug_reader.h"
David Srbeckyc5bfa972016-02-05 15:49:10 +000032#include "debug/elf_symtab_writer.h"
33#include "debug/method_debug_info.h"
David Srbecky154c57f2018-06-03 12:00:27 +010034#include "debug/xz_utils.h"
David Srbeckybe50f9a2018-12-05 10:48:42 +000035#include "elf.h"
Vladimir Marko74527972016-11-29 15:57:32 +000036#include "linker/elf_builder.h"
David Srbeckyc5bfa972016-02-05 15:49:10 +000037#include "linker/vector_output_stream.h"
Andreas Gamped4901292017-05-30 18:41:34 -070038#include "oat.h"
David Srbeckyc5bfa972016-02-05 15:49:10 +000039
40namespace art {
41namespace debug {
42
David Srbeckybe50f9a2018-12-05 10:48:42 +000043using ElfRuntimeTypes = std::conditional<sizeof(void*) == 4, ElfTypes32, ElfTypes64>::type;
44
David Srbeckyc5bfa972016-02-05 15:49:10 +000045template <typename ElfTypes>
Vladimir Marko74527972016-11-29 15:57:32 +000046void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder,
David Srbecky32210b92017-12-04 14:39:21 +000047 const DebugInfo& debug_info,
David Srbeckyc5bfa972016-02-05 15:49:10 +000048 dwarf::CFIFormat cfi_format,
49 bool write_oat_patches) {
David Srbecky09c2a6b2016-03-11 17:11:44 +000050 // Write .strtab and .symtab.
Andreas Gampe3db70682018-12-26 15:12:03 -080051 WriteDebugSymbols(builder, /* mini-debug-info= */ false, debug_info);
David Srbeckyc5bfa972016-02-05 15:49:10 +000052
David Srbecky09c2a6b2016-03-11 17:11:44 +000053 // Write .debug_frame.
David Srbecky32210b92017-12-04 14:39:21 +000054 WriteCFISection(builder, debug_info.compiled_methods, cfi_format, write_oat_patches);
David Srbecky09c2a6b2016-03-11 17:11:44 +000055
David Srbecky56da23c2017-09-08 19:59:15 +010056 // Group the methods into compilation units based on class.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -080057 std::unordered_map<const dex::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
David Srbecky32210b92017-12-04 14:39:21 +000058 for (const MethodDebugInfo& mi : debug_info.compiled_methods) {
David Srbecky09c2a6b2016-03-11 17:11:44 +000059 if (mi.dex_file != nullptr) {
60 auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
David Srbecky56da23c2017-09-08 19:59:15 +010061 ElfCompilationUnit& cu = class_to_compilation_unit[&dex_class_def];
David Srbecky09c2a6b2016-03-11 17:11:44 +000062 cu.methods.push_back(&mi);
63 // All methods must have the same addressing mode otherwise the min/max below does not work.
64 DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
65 cu.is_code_address_text_relative = mi.is_code_address_text_relative;
66 cu.code_address = std::min(cu.code_address, mi.code_address);
67 cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
David Srbeckyc5bfa972016-02-05 15:49:10 +000068 }
David Srbeckyc5bfa972016-02-05 15:49:10 +000069 }
70
David Srbecky56da23c2017-09-08 19:59:15 +010071 // Sort compilation units to make the compiler output deterministic.
72 std::vector<ElfCompilationUnit> compilation_units;
73 compilation_units.reserve(class_to_compilation_unit.size());
74 for (auto& it : class_to_compilation_unit) {
75 // The .debug_line section requires the methods to be sorted by code address.
76 std::stable_sort(it.second.methods.begin(),
77 it.second.methods.end(),
78 [](const MethodDebugInfo* a, const MethodDebugInfo* b) {
79 return a->code_address < b->code_address;
80 });
81 compilation_units.push_back(std::move(it.second));
82 }
83 std::sort(compilation_units.begin(),
84 compilation_units.end(),
85 [](ElfCompilationUnit& a, ElfCompilationUnit& b) {
86 // Sort by index of the first method within the method_infos array.
87 // This assumes that the order of method_infos is deterministic.
88 // Code address is not good for sorting due to possible duplicates.
89 return a.methods.front() < b.methods.front();
90 });
91
David Srbeckyc5bfa972016-02-05 15:49:10 +000092 // Write .debug_line section.
93 if (!compilation_units.empty()) {
94 ElfDebugLineWriter<ElfTypes> line_writer(builder);
95 line_writer.Start();
96 for (auto& compilation_unit : compilation_units) {
97 line_writer.WriteCompilationUnit(compilation_unit);
98 }
99 line_writer.End(write_oat_patches);
100 }
101
102 // Write .debug_info section.
103 if (!compilation_units.empty()) {
104 ElfDebugInfoWriter<ElfTypes> info_writer(builder);
105 info_writer.Start();
106 for (const auto& compilation_unit : compilation_units) {
107 ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
108 cu_writer.Write(compilation_unit);
109 }
110 info_writer.End(write_oat_patches);
111 }
112}
113
David Srbecky154c57f2018-06-03 12:00:27 +0100114template <typename ElfTypes>
115static std::vector<uint8_t> MakeMiniDebugInfoInternal(
116 InstructionSet isa,
117 const InstructionSetFeatures* features,
118 typename ElfTypes::Addr text_section_address,
119 size_t text_section_size,
120 typename ElfTypes::Addr dex_section_address,
121 size_t dex_section_size,
122 const DebugInfo& debug_info) {
123 std::vector<uint8_t> buffer;
124 buffer.reserve(KB);
125 linker::VectorOutputStream out("Mini-debug-info ELF file", &buffer);
126 std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
127 new linker::ElfBuilder<ElfTypes>(isa, features, &out));
Andreas Gampe3db70682018-12-26 15:12:03 -0800128 builder->Start(/* write_program_headers= */ false);
David Srbecky154c57f2018-06-03 12:00:27 +0100129 // Mirror ELF sections as NOBITS since the added symbols will reference them.
David Srbecky49b2b202019-02-01 13:35:48 +0000130 if (text_section_size != 0) {
131 builder->GetText()->AllocateVirtualMemory(text_section_address, text_section_size);
132 }
David Srbecky154c57f2018-06-03 12:00:27 +0100133 if (dex_section_size != 0) {
134 builder->GetDex()->AllocateVirtualMemory(dex_section_address, dex_section_size);
135 }
David Srbecky49b2b202019-02-01 13:35:48 +0000136 if (!debug_info.Empty()) {
137 WriteDebugSymbols(builder.get(), /* mini-debug-info= */ true, debug_info);
138 }
139 if (!debug_info.compiled_methods.empty()) {
140 WriteCFISection(builder.get(),
141 debug_info.compiled_methods,
142 dwarf::DW_DEBUG_FRAME_FORMAT,
143 /* write_oat_patches= */ false);
144 }
David Srbecky154c57f2018-06-03 12:00:27 +0100145 builder->End();
146 CHECK(builder->Good());
147 std::vector<uint8_t> compressed_buffer;
148 compressed_buffer.reserve(buffer.size() / 4);
David Srbeckycf1af732018-12-04 14:31:32 +0000149 XzCompress(ArrayRef<const uint8_t>(buffer), &compressed_buffer);
David Srbecky154c57f2018-06-03 12:00:27 +0100150 return compressed_buffer;
151}
152
David Srbeckyc5bfa972016-02-05 15:49:10 +0000153std::vector<uint8_t> MakeMiniDebugInfo(
154 InstructionSet isa,
David Srbecky5d811202016-03-08 13:21:22 +0000155 const InstructionSetFeatures* features,
David Srbecky32210b92017-12-04 14:39:21 +0000156 uint64_t text_section_address,
157 size_t text_section_size,
158 uint64_t dex_section_address,
159 size_t dex_section_size,
160 const DebugInfo& debug_info) {
David Srbeckyc5bfa972016-02-05 15:49:10 +0000161 if (Is64BitInstructionSet(isa)) {
David Srbecky5d811202016-03-08 13:21:22 +0000162 return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
163 features,
David Srbecky32210b92017-12-04 14:39:21 +0000164 text_section_address,
165 text_section_size,
166 dex_section_address,
167 dex_section_size,
168 debug_info);
David Srbeckyc5bfa972016-02-05 15:49:10 +0000169 } else {
David Srbecky5d811202016-03-08 13:21:22 +0000170 return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
171 features,
David Srbecky32210b92017-12-04 14:39:21 +0000172 text_section_address,
173 text_section_size,
174 dex_section_address,
175 dex_section_size,
176 debug_info);
David Srbeckyc5bfa972016-02-05 15:49:10 +0000177 }
178}
179
David Srbeckybe50f9a2018-12-05 10:48:42 +0000180std::vector<uint8_t> MakeElfFileForJIT(
David Srbeckyfe736b72016-03-09 11:44:44 +0000181 InstructionSet isa,
David Srbecky5d811202016-03-08 13:21:22 +0000182 const InstructionSetFeatures* features,
David Srbeckyf4886df2017-12-11 16:06:29 +0000183 bool mini_debug_info,
David Srbeckybe50f9a2018-12-05 10:48:42 +0000184 const MethodDebugInfo& method_info) {
185 using ElfTypes = ElfRuntimeTypes;
186 CHECK_EQ(sizeof(ElfTypes::Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa)));
187 CHECK_EQ(method_info.is_code_address_text_relative, false);
David Srbecky32210b92017-12-04 14:39:21 +0000188 DebugInfo debug_info{};
David Srbeckybe50f9a2018-12-05 10:48:42 +0000189 debug_info.compiled_methods = ArrayRef<const MethodDebugInfo>(&method_info, 1);
David Srbeckyc5bfa972016-02-05 15:49:10 +0000190 std::vector<uint8_t> buffer;
191 buffer.reserve(KB);
Vladimir Marko74527972016-11-29 15:57:32 +0000192 linker::VectorOutputStream out("Debug ELF file", &buffer);
193 std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
194 new linker::ElfBuilder<ElfTypes>(isa, features, &out));
David Srbeckyc5bfa972016-02-05 15:49:10 +0000195 // No program headers since the ELF file is not linked and has no allocated sections.
Andreas Gampe3db70682018-12-26 15:12:03 -0800196 builder->Start(/* write_program_headers= */ false);
David Srbeckybe50f9a2018-12-05 10:48:42 +0000197 builder->GetText()->AllocateVirtualMemory(method_info.code_address, method_info.code_size);
David Srbeckyf4886df2017-12-11 16:06:29 +0000198 if (mini_debug_info) {
David Srbeckybe50f9a2018-12-05 10:48:42 +0000199 // The compression is great help for multiple methods but it is not worth it for a
200 // single method due to the overheads so skip the compression here for performance.
Andreas Gampe3db70682018-12-26 15:12:03 -0800201 WriteDebugSymbols(builder.get(), /* mini-debug-info= */ true, debug_info);
David Srbeckybe50f9a2018-12-05 10:48:42 +0000202 WriteCFISection(builder.get(),
203 debug_info.compiled_methods,
204 dwarf::DW_DEBUG_FRAME_FORMAT,
Andreas Gampe3db70682018-12-26 15:12:03 -0800205 /* write_oat_patches= */ false);
David Srbeckyf4886df2017-12-11 16:06:29 +0000206 } else {
David Srbeckyf4886df2017-12-11 16:06:29 +0000207 WriteDebugInfo(builder.get(),
David Srbecky32210b92017-12-04 14:39:21 +0000208 debug_info,
David Srbeckyf4886df2017-12-11 16:06:29 +0000209 dwarf::DW_DEBUG_FRAME_FORMAT,
Andreas Gampe3db70682018-12-26 15:12:03 -0800210 /* write_oat_patches= */ false);
David Srbeckyf4886df2017-12-11 16:06:29 +0000211 }
David Srbeckyc5bfa972016-02-05 15:49:10 +0000212 builder->End();
213 CHECK(builder->Good());
David Srbecky0b21e412018-12-05 13:24:06 +0000214 // Verify the ELF file by reading it back using the trivial reader.
215 if (kIsDebugBuild) {
216 using Elf_Sym = typename ElfTypes::Sym;
217 using Elf_Addr = typename ElfTypes::Addr;
218 size_t num_syms = 0;
219 size_t num_cfis = 0;
220 ReadElfSymbols<ElfTypes>(
221 buffer.data(),
222 [&](Elf_Sym sym, const char*) {
223 DCHECK_EQ(sym.st_value, method_info.code_address + CompiledMethod::CodeDelta(isa));
224 DCHECK_EQ(sym.st_size, method_info.code_size);
225 num_syms++;
226 },
227 [&](Elf_Addr addr, Elf_Addr size, ArrayRef<const uint8_t> opcodes) {
228 DCHECK_EQ(addr, method_info.code_address);
229 DCHECK_EQ(size, method_info.code_size);
230 DCHECK_GE(opcodes.size(), method_info.cfi.size());
231 DCHECK_EQ(memcmp(opcodes.data(), method_info.cfi.data(), method_info.cfi.size()), 0);
232 num_cfis++;
233 });
234 DCHECK_EQ(num_syms, 1u);
David Srbecky51bc7522019-01-05 15:41:06 +0000235 // CFI might be missing. TODO: Ensure we have CFI for all methods.
236 DCHECK_LE(num_cfis, 1u);
David Srbecky0b21e412018-12-05 13:24:06 +0000237 }
Vladimir Marko93205e32016-04-13 11:59:46 +0100238 return buffer;
David Srbeckyc5bfa972016-02-05 15:49:10 +0000239}
240
David Srbecky0b21e412018-12-05 13:24:06 +0000241// Combine several mini-debug-info ELF files into one, while filtering some symbols.
242std::vector<uint8_t> PackElfFileForJIT(
243 InstructionSet isa,
244 const InstructionSetFeatures* features,
245 std::vector<const uint8_t*>& added_elf_files,
246 std::vector<const void*>& removed_symbols,
247 /*out*/ size_t* num_symbols) {
248 using ElfTypes = ElfRuntimeTypes;
249 using Elf_Addr = typename ElfTypes::Addr;
250 using Elf_Sym = typename ElfTypes::Sym;
251 CHECK_EQ(sizeof(Elf_Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa)));
252 const bool is64bit = Is64BitInstructionSet(isa);
253 auto is_removed_symbol = [&removed_symbols](Elf_Addr addr) {
254 const void* code_ptr = reinterpret_cast<const void*>(addr);
255 return std::binary_search(removed_symbols.begin(), removed_symbols.end(), code_ptr);
256 };
257 uint64_t min_address = std::numeric_limits<uint64_t>::max();
258 uint64_t max_address = 0;
259
260 // Produce the inner ELF file.
261 // It will contain the symbols (.symtab) and unwind information (.debug_frame).
262 std::vector<uint8_t> inner_elf_file;
263 {
264 inner_elf_file.reserve(1 * KB); // Approximate size of ELF file with a single symbol.
265 linker::VectorOutputStream out("Mini-debug-info ELF file for JIT", &inner_elf_file);
266 std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
267 new linker::ElfBuilder<ElfTypes>(isa, features, &out));
268 builder->Start(/*write_program_headers=*/ false);
269 auto* text = builder->GetText();
270 auto* strtab = builder->GetStrTab();
271 auto* symtab = builder->GetSymTab();
272 auto* debug_frame = builder->GetDebugFrame();
273 std::deque<Elf_Sym> symbols;
274 std::vector<uint8_t> debug_frame_buffer;
275 WriteCIE(isa, dwarf::DW_DEBUG_FRAME_FORMAT, &debug_frame_buffer);
276
277 // Write symbols names. All other data is buffered.
278 strtab->Start();
279 strtab->Write(""); // strtab should start with empty string.
280 for (const uint8_t* added_elf_file : added_elf_files) {
281 ReadElfSymbols<ElfTypes>(
282 added_elf_file,
283 [&](Elf_Sym sym, const char* name) {
284 if (is_removed_symbol(sym.st_value)) {
285 return;
286 }
287 sym.st_name = strtab->Write(name);
288 symbols.push_back(sym);
289 min_address = std::min<uint64_t>(min_address, sym.st_value);
290 max_address = std::max<uint64_t>(max_address, sym.st_value + sym.st_size);
291 },
292 [&](Elf_Addr addr, Elf_Addr size, ArrayRef<const uint8_t> opcodes) {
293 if (is_removed_symbol(addr)) {
294 return;
295 }
296 WriteFDE(is64bit,
297 /*section_address=*/ 0,
298 /*cie_address=*/ 0,
299 addr,
300 size,
301 opcodes,
302 dwarf::DW_DEBUG_FRAME_FORMAT,
303 debug_frame_buffer.size(),
304 &debug_frame_buffer,
305 /*patch_locations=*/ nullptr);
306 });
307 }
308 strtab->End();
309
310 // Create .text covering the code range. Needed for gdb to find the symbols.
311 if (max_address > min_address) {
312 text->AllocateVirtualMemory(min_address, max_address - min_address);
313 }
314
315 // Add the symbols.
316 *num_symbols = symbols.size();
317 for (; !symbols.empty(); symbols.pop_front()) {
318 symtab->Add(symbols.front(), text);
319 }
320 symtab->WriteCachedSection();
321
322 // Add the CFI/unwind section.
323 debug_frame->Start();
324 debug_frame->WriteFully(debug_frame_buffer.data(), debug_frame_buffer.size());
325 debug_frame->End();
326
327 builder->End();
328 CHECK(builder->Good());
329 }
330
331 // Produce the outer ELF file.
332 // It contains only the inner ELF file compressed as .gnu_debugdata section.
333 // This extra wrapping is not necessary but the compression saves space.
334 std::vector<uint8_t> outer_elf_file;
335 {
336 std::vector<uint8_t> gnu_debugdata;
337 gnu_debugdata.reserve(inner_elf_file.size() / 4);
338 XzCompress(ArrayRef<const uint8_t>(inner_elf_file), &gnu_debugdata);
339
340 outer_elf_file.reserve(KB + gnu_debugdata.size());
341 linker::VectorOutputStream out("Mini-debug-info ELF file for JIT", &outer_elf_file);
342 std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
343 new linker::ElfBuilder<ElfTypes>(isa, features, &out));
344 builder->Start(/*write_program_headers=*/ false);
345 if (max_address > min_address) {
346 builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address);
347 }
348 builder->WriteSection(".gnu_debugdata", &gnu_debugdata);
349 builder->End();
350 CHECK(builder->Good());
351 }
352
353 return outer_elf_file;
354}
355
David Srbeckybe50f9a2018-12-05 10:48:42 +0000356std::vector<uint8_t> WriteDebugElfFileForClasses(
David Srbeckyfe736b72016-03-09 11:44:44 +0000357 InstructionSet isa,
David Srbecky5d811202016-03-08 13:21:22 +0000358 const InstructionSetFeatures* features,
359 const ArrayRef<mirror::Class*>& types)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700360 REQUIRES_SHARED(Locks::mutator_lock_) {
David Srbeckybe50f9a2018-12-05 10:48:42 +0000361 using ElfTypes = ElfRuntimeTypes;
362 CHECK_EQ(sizeof(ElfTypes::Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa)));
David Srbeckyc5bfa972016-02-05 15:49:10 +0000363 std::vector<uint8_t> buffer;
364 buffer.reserve(KB);
Vladimir Marko74527972016-11-29 15:57:32 +0000365 linker::VectorOutputStream out("Debug ELF file", &buffer);
366 std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
367 new linker::ElfBuilder<ElfTypes>(isa, features, &out));
David Srbeckyc5bfa972016-02-05 15:49:10 +0000368 // No program headers since the ELF file is not linked and has no allocated sections.
Andreas Gampe3db70682018-12-26 15:12:03 -0800369 builder->Start(/* write_program_headers= */ false);
David Srbeckyc5bfa972016-02-05 15:49:10 +0000370 ElfDebugInfoWriter<ElfTypes> info_writer(builder.get());
371 info_writer.Start();
372 ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
373 cu_writer.Write(types);
Andreas Gampe3db70682018-12-26 15:12:03 -0800374 info_writer.End(/* write_oat_patches= */ false);
David Srbeckyc5bfa972016-02-05 15:49:10 +0000375
376 builder->End();
377 CHECK(builder->Good());
Vladimir Marko93205e32016-04-13 11:59:46 +0100378 return buffer;
David Srbeckyc5bfa972016-02-05 15:49:10 +0000379}
380
David Srbeckyc5bfa972016-02-05 15:49:10 +0000381// Explicit instantiations
382template void WriteDebugInfo<ElfTypes32>(
Vladimir Marko74527972016-11-29 15:57:32 +0000383 linker::ElfBuilder<ElfTypes32>* builder,
David Srbecky32210b92017-12-04 14:39:21 +0000384 const DebugInfo& debug_info,
David Srbeckyc5bfa972016-02-05 15:49:10 +0000385 dwarf::CFIFormat cfi_format,
386 bool write_oat_patches);
387template void WriteDebugInfo<ElfTypes64>(
Vladimir Marko74527972016-11-29 15:57:32 +0000388 linker::ElfBuilder<ElfTypes64>* builder,
David Srbecky32210b92017-12-04 14:39:21 +0000389 const DebugInfo& debug_info,
David Srbeckyc5bfa972016-02-05 15:49:10 +0000390 dwarf::CFIFormat cfi_format,
391 bool write_oat_patches);
392
393} // namespace debug
394} // namespace art