215 lines
8.3 KiB
C++
215 lines
8.3 KiB
C++
/*
|
|
* Copyright (C) 2016 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.
|
|
*/
|
|
|
|
#include "elf_debug_writer.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "base/array_ref.h"
|
|
#include "debug/dwarf/dwarf_constants.h"
|
|
#include "debug/elf_compilation_unit.h"
|
|
#include "debug/elf_debug_frame_writer.h"
|
|
#include "debug/elf_debug_info_writer.h"
|
|
#include "debug/elf_debug_line_writer.h"
|
|
#include "debug/elf_debug_loc_writer.h"
|
|
#include "debug/elf_gnu_debugdata_writer.h"
|
|
#include "debug/elf_symtab_writer.h"
|
|
#include "debug/method_debug_info.h"
|
|
#include "elf_builder.h"
|
|
#include "linker/vector_output_stream.h"
|
|
#include "oat.h"
|
|
|
|
namespace art {
|
|
namespace debug {
|
|
|
|
template <typename ElfTypes>
|
|
void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
|
|
const ArrayRef<const MethodDebugInfo>& method_infos,
|
|
dwarf::CFIFormat cfi_format,
|
|
bool write_oat_patches) {
|
|
// Write .strtab and .symtab.
|
|
WriteDebugSymbols(builder, method_infos, true /* with_signature */);
|
|
|
|
// Write .debug_frame.
|
|
WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
|
|
|
|
// Group the methods into compilation units based on source file.
|
|
std::vector<ElfCompilationUnit> compilation_units;
|
|
const char* last_source_file = nullptr;
|
|
for (const MethodDebugInfo& mi : method_infos) {
|
|
if (mi.dex_file != nullptr) {
|
|
auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
|
|
const char* source_file = mi.dex_file->GetSourceFile(dex_class_def);
|
|
if (compilation_units.empty() || source_file != last_source_file) {
|
|
compilation_units.push_back(ElfCompilationUnit());
|
|
}
|
|
ElfCompilationUnit& cu = compilation_units.back();
|
|
cu.methods.push_back(&mi);
|
|
// All methods must have the same addressing mode otherwise the min/max below does not work.
|
|
DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
|
|
cu.is_code_address_text_relative = mi.is_code_address_text_relative;
|
|
cu.code_address = std::min(cu.code_address, mi.code_address);
|
|
cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
|
|
last_source_file = source_file;
|
|
}
|
|
}
|
|
|
|
// Write .debug_line section.
|
|
if (!compilation_units.empty()) {
|
|
ElfDebugLineWriter<ElfTypes> line_writer(builder);
|
|
line_writer.Start();
|
|
for (auto& compilation_unit : compilation_units) {
|
|
line_writer.WriteCompilationUnit(compilation_unit);
|
|
}
|
|
line_writer.End(write_oat_patches);
|
|
}
|
|
|
|
// Write .debug_info section.
|
|
if (!compilation_units.empty()) {
|
|
ElfDebugInfoWriter<ElfTypes> info_writer(builder);
|
|
info_writer.Start();
|
|
for (const auto& compilation_unit : compilation_units) {
|
|
ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
|
|
cu_writer.Write(compilation_unit);
|
|
}
|
|
info_writer.End(write_oat_patches);
|
|
}
|
|
}
|
|
|
|
std::vector<uint8_t> MakeMiniDebugInfo(
|
|
InstructionSet isa,
|
|
const InstructionSetFeatures* features,
|
|
size_t rodata_size,
|
|
size_t text_size,
|
|
const ArrayRef<const MethodDebugInfo>& method_infos) {
|
|
if (Is64BitInstructionSet(isa)) {
|
|
return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
|
|
features,
|
|
rodata_size,
|
|
text_size,
|
|
method_infos);
|
|
} else {
|
|
return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
|
|
features,
|
|
rodata_size,
|
|
text_size,
|
|
method_infos);
|
|
}
|
|
}
|
|
|
|
template <typename ElfTypes>
|
|
static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal(
|
|
InstructionSet isa,
|
|
const InstructionSetFeatures* features,
|
|
const ArrayRef<const MethodDebugInfo>& method_infos) {
|
|
std::vector<uint8_t> buffer;
|
|
buffer.reserve(KB);
|
|
VectorOutputStream out("Debug ELF file", &buffer);
|
|
std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out));
|
|
// No program headers since the ELF file is not linked and has no allocated sections.
|
|
builder->Start(false /* write_program_headers */);
|
|
WriteDebugInfo(builder.get(),
|
|
method_infos,
|
|
dwarf::DW_DEBUG_FRAME_FORMAT,
|
|
false /* write_oat_patches */);
|
|
builder->End();
|
|
CHECK(builder->Good());
|
|
return buffer;
|
|
}
|
|
|
|
std::vector<uint8_t> WriteDebugElfFileForMethods(
|
|
InstructionSet isa,
|
|
const InstructionSetFeatures* features,
|
|
const ArrayRef<const MethodDebugInfo>& method_infos) {
|
|
if (Is64BitInstructionSet(isa)) {
|
|
return WriteDebugElfFileForMethodsInternal<ElfTypes64>(isa, features, method_infos);
|
|
} else {
|
|
return WriteDebugElfFileForMethodsInternal<ElfTypes32>(isa, features, method_infos);
|
|
}
|
|
}
|
|
|
|
template <typename ElfTypes>
|
|
static std::vector<uint8_t> WriteDebugElfFileForClassesInternal(
|
|
InstructionSet isa,
|
|
const InstructionSetFeatures* features,
|
|
const ArrayRef<mirror::Class*>& types)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) {
|
|
std::vector<uint8_t> buffer;
|
|
buffer.reserve(KB);
|
|
VectorOutputStream out("Debug ELF file", &buffer);
|
|
std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out));
|
|
// No program headers since the ELF file is not linked and has no allocated sections.
|
|
builder->Start(false /* write_program_headers */);
|
|
ElfDebugInfoWriter<ElfTypes> info_writer(builder.get());
|
|
info_writer.Start();
|
|
ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
|
|
cu_writer.Write(types);
|
|
info_writer.End(false /* write_oat_patches */);
|
|
|
|
builder->End();
|
|
CHECK(builder->Good());
|
|
return buffer;
|
|
}
|
|
|
|
std::vector<uint8_t> WriteDebugElfFileForClasses(InstructionSet isa,
|
|
const InstructionSetFeatures* features,
|
|
const ArrayRef<mirror::Class*>& types) {
|
|
if (Is64BitInstructionSet(isa)) {
|
|
return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, features, types);
|
|
} else {
|
|
return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, features, types);
|
|
}
|
|
}
|
|
|
|
std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& header) {
|
|
std::map<const char*, uint32_t> trampolines = {
|
|
{ "interpreterToInterpreterBridge", header.GetInterpreterToInterpreterBridgeOffset() },
|
|
{ "interpreterToCompiledCodeBridge", header.GetInterpreterToCompiledCodeBridgeOffset() },
|
|
{ "jniDlsymLookup", header.GetJniDlsymLookupOffset() },
|
|
{ "quickGenericJniTrampoline", header.GetQuickGenericJniTrampolineOffset() },
|
|
{ "quickImtConflictTrampoline", header.GetQuickImtConflictTrampolineOffset() },
|
|
{ "quickResolutionTrampoline", header.GetQuickResolutionTrampolineOffset() },
|
|
{ "quickToInterpreterBridge", header.GetQuickToInterpreterBridgeOffset() },
|
|
};
|
|
std::vector<MethodDebugInfo> result;
|
|
for (const auto& it : trampolines) {
|
|
if (it.second != 0) {
|
|
MethodDebugInfo info = MethodDebugInfo();
|
|
info.trampoline_name = it.first;
|
|
info.isa = header.GetInstructionSet();
|
|
info.is_code_address_text_relative = true;
|
|
info.code_address = it.second - header.GetExecutableOffset();
|
|
info.code_size = 0; // The symbol lasts until the next symbol.
|
|
result.push_back(std::move(info));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Explicit instantiations
|
|
template void WriteDebugInfo<ElfTypes32>(
|
|
ElfBuilder<ElfTypes32>* builder,
|
|
const ArrayRef<const MethodDebugInfo>& method_infos,
|
|
dwarf::CFIFormat cfi_format,
|
|
bool write_oat_patches);
|
|
template void WriteDebugInfo<ElfTypes64>(
|
|
ElfBuilder<ElfTypes64>* builder,
|
|
const ArrayRef<const MethodDebugInfo>& method_infos,
|
|
dwarf::CFIFormat cfi_format,
|
|
bool write_oat_patches);
|
|
|
|
} // namespace debug
|
|
} // namespace art
|