Revert "Revert "Add option to generate compressed backtrace info.""
This reverts commit 8546cc9aeb05e866e1fb6a9e4130d53ea330baa8.
Change-Id: I676fdf9af27fa3b16fa8921778ff8832ab8c437d
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index d68835a..af6f91f 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1076,7 +1076,7 @@
pc_rel_temp_(nullptr),
dex_cache_arrays_min_offset_(std::numeric_limits<uint32_t>::max()),
cfi_(&last_lir_insn_,
- cu->compiler_driver->GetCompilerOptions().GetGenerateDebugInfo(),
+ cu->compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo(),
arena),
in_to_reg_storage_mapping_(arena) {
switch_tables_.reserve(4);
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 2644528..e0b1d8b 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -37,6 +37,7 @@
debuggable_(false),
native_debuggable_(kDefaultNativeDebuggable),
generate_debug_info_(kDefaultGenerateDebugInfo),
+ generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
implicit_null_checks_(true),
implicit_so_checks_(true),
implicit_suspend_checks_(false),
@@ -91,6 +92,7 @@
debuggable_(debuggable),
native_debuggable_(kDefaultNativeDebuggable),
generate_debug_info_(generate_debug_info),
+ generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
implicit_null_checks_(implicit_null_checks),
implicit_so_checks_(implicit_so_checks),
implicit_suspend_checks_(implicit_suspend_checks),
@@ -215,6 +217,10 @@
generate_debug_info_ = true;
} else if (option == "--no-generate-debug-info") {
generate_debug_info_ = false;
+ } else if (option == "--generate-mini-debug-info") {
+ generate_mini_debug_info_ = true;
+ } else if (option == "--no-generate-mini-debug-info") {
+ generate_mini_debug_info_ = false;
} else if (option == "--debuggable") {
debuggable_ = true;
} else if (option == "--native-debuggable") {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index d47fc2a..5294af8 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -51,6 +51,7 @@
static constexpr double kDefaultTopKProfileThreshold = 90.0;
static const bool kDefaultNativeDebuggable = false;
static const bool kDefaultGenerateDebugInfo = false;
+ static const bool kDefaultGenerateMiniDebugInfo = false;
static const bool kDefaultIncludePatchInformation = false;
static const size_t kDefaultInlineDepthLimit = 3;
static const size_t kDefaultInlineMaxCodeUnits = 32;
@@ -170,10 +171,20 @@
return native_debuggable_;
}
+ // This flag controls whether the compiler collects debugging information.
+ // The other flags control how the information is written to disk.
+ bool GenerateAnyDebugInfo() const {
+ return GetGenerateDebugInfo() || GetGenerateMiniDebugInfo();
+ }
+
bool GetGenerateDebugInfo() const {
return generate_debug_info_;
}
+ bool GetGenerateMiniDebugInfo() const {
+ return generate_mini_debug_info_;
+ }
+
bool GetImplicitNullChecks() const {
return implicit_null_checks_;
}
@@ -266,6 +277,7 @@
bool debuggable_;
bool native_debuggable_;
bool generate_debug_info_;
+ bool generate_mini_debug_info_;
bool implicit_null_checks_;
bool implicit_so_checks_;
bool implicit_suspend_checks_;
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 46484b1..3d24d19 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -165,10 +165,15 @@
}
}
- // Set desired allocation size for .bss section.
- void SetSize(Elf_Word size) {
- CHECK_EQ(header_.sh_type, (Elf_Word)SHT_NOBITS);
+ // Write this section as "NOBITS" section. (used for the .bss section)
+ // This means that the ELF file does not contain the initial data for this section
+ // and it will be zero-initialized when the ELF file is loaded in the running program.
+ void WriteNoBitsSection(Elf_Word size) {
+ DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
+ Start();
+ header_.sh_type = SHT_NOBITS;
header_.sh_size = size;
+ End();
}
// This function always succeeds to simplify code.
@@ -346,6 +351,12 @@
other_sections_.push_back(std::move(s));
}
+ // Set where the next section will be allocated in the virtual address space.
+ void SetVirtualAddress(Elf_Addr address) {
+ DCHECK_GE(address, virtual_address_);
+ virtual_address_ = address;
+ }
+
void Start() {
// Reserve space for ELF header and program headers.
// We do not know the number of headers until later, so
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index a64c9f1..94e5d76 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -40,6 +40,11 @@
#include "stack_map.h"
#include "utils.h"
+// liblzma.
+#include "XzEnc.h"
+#include "7zCrc.h"
+#include "XzCrc64.h"
+
namespace art {
namespace dwarf {
@@ -1405,6 +1410,76 @@
WriteDebugSections(builder, method_infos);
}
+static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) {
+ // Configure the compression library.
+ CrcGenerateTable();
+ Crc64GenerateTable();
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+ lzma2Props.lzmaProps.level = 1; // Fast compression.
+ Lzma2EncProps_Normalize(&lzma2Props);
+ CXzProps props;
+ XzProps_Init(&props);
+ props.lzma2Props = &lzma2Props;
+ // Implement the required interface for communication (written in C so no virtual methods).
+ struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress {
+ static SRes ReadImpl(void* p, void* buf, size_t* size) {
+ auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p));
+ *size = std::min(*size, ctx->src_->size() - ctx->src_pos_);
+ memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size);
+ ctx->src_pos_ += *size;
+ return SZ_OK;
+ }
+ static size_t WriteImpl(void* p, const void* buf, size_t size) {
+ auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p));
+ const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf);
+ ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size);
+ return size;
+ }
+ static SRes ProgressImpl(void* , UInt64, UInt64) {
+ return SZ_OK;
+ }
+ size_t src_pos_;
+ const std::vector<uint8_t>* src_;
+ std::vector<uint8_t>* dst_;
+ };
+ XzCallbacks callbacks;
+ callbacks.Read = XzCallbacks::ReadImpl;
+ callbacks.Write = XzCallbacks::WriteImpl;
+ callbacks.Progress = XzCallbacks::ProgressImpl;
+ callbacks.src_pos_ = 0;
+ callbacks.src_ = src;
+ callbacks.dst_ = dst;
+ // Compress.
+ SRes res = Xz_Encode(&callbacks, &callbacks, &props, &callbacks);
+ CHECK_EQ(res, SZ_OK);
+}
+
+template <typename ElfTypes>
+void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* parent_builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos) {
+ const InstructionSet isa = parent_builder->GetIsa();
+ std::vector<uint8_t> buffer;
+ buffer.reserve(KB);
+ VectorOutputStream out("Mini-debug-info ELF file", &buffer);
+ std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
+ builder->Start();
+ // Write .rodata and .text as NOBITS sections.
+ // This allows tools to detect virtual address relocation of the parent ELF file.
+ builder->SetVirtualAddress(parent_builder->GetRoData()->GetAddress());
+ builder->GetRoData()->WriteNoBitsSection(parent_builder->GetRoData()->GetSize());
+ builder->SetVirtualAddress(parent_builder->GetText()->GetAddress());
+ builder->GetText()->WriteNoBitsSection(parent_builder->GetText()->GetSize());
+ WriteDebugSymbols(builder.get(), method_infos);
+ WriteCFISection(builder.get(), method_infos, DW_DEBUG_FRAME_FORMAT);
+ builder->End();
+ CHECK(builder->Good());
+ std::vector<uint8_t> compressed_buffer;
+ compressed_buffer.reserve(buffer.size() / 4);
+ XzCompress(&buffer, &compressed_buffer);
+ parent_builder->WriteSection(".gnu_debugdata", &compressed_buffer);
+}
+
template <typename ElfTypes>
static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal(
const dwarf::MethodDebugInfo& method_info) {
@@ -1477,6 +1552,12 @@
ElfBuilder<ElfTypes64>* builder,
const ArrayRef<const MethodDebugInfo>& method_infos,
CFIFormat cfi_format);
+template void WriteMiniDebugInfo<ElfTypes32>(
+ ElfBuilder<ElfTypes32>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos);
+template void WriteMiniDebugInfo<ElfTypes64>(
+ ElfBuilder<ElfTypes64>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos);
} // namespace dwarf
} // namespace art
diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h
index e4bc856..e19da08 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/elf_writer_debug.h
@@ -35,6 +35,10 @@
const ArrayRef<const MethodDebugInfo>& method_infos,
CFIFormat cfi_format);
+template <typename ElfTypes>
+void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos);
+
ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info);
ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 7b1bdd7..6bf080a 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -137,9 +137,7 @@
void ElfWriterQuick<ElfTypes>::SetBssSize(size_t bss_size) {
auto* bss = builder_->GetBss();
if (bss_size != 0u) {
- bss->Start();
- bss->SetSize(bss_size);
- bss->End();
+ bss->WriteNoBitsSection(bss_size);
}
}
@@ -152,8 +150,13 @@
void ElfWriterQuick<ElfTypes>::WriteDebugInfo(
const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) {
if (compiler_options_->GetGenerateDebugInfo()) {
+ // Generate all the debug information we can.
dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat);
}
+ if (compiler_options_->GetGenerateMiniDebugInfo()) {
+ // Generate only some information and compress it.
+ dwarf::WriteMiniDebugInfo(builder_.get(), method_infos);
+ }
}
template <typename ElfTypes>
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 52a2382..e920460 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -95,7 +95,7 @@
// Assembler that holds generated instructions
std::unique_ptr<Assembler> jni_asm(Assembler::Create(instruction_set, instruction_set_features));
- jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GetGenerateDebugInfo());
+ jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GenerateAnyDebugInfo());
// Offsets into data structures
// TODO: if cross compiling these offsets are for the host not the target
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index a542162..569e0f4 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -806,7 +806,7 @@
}
}
- if (writer_->compiler_driver_->GetCompilerOptions().GetGenerateDebugInfo()) {
+ if (writer_->compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo()) {
// Record debug information for this function if we are doing that.
const uint32_t quick_code_start = quick_code_offset -
writer_->oat_header_->GetExecutableOffset() - thumb_offset;
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index fffd005..3fac914 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -676,7 +676,7 @@
return nullptr;
}
codegen->GetAssembler()->cfi().SetEnabled(
- compiler_driver->GetCompilerOptions().GetGenerateDebugInfo());
+ compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo());
PassObserver pass_observer(graph,
codegen.get(),