/* * 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. */ #ifndef ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_ #define ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_ #include <vector> #include "arch/instruction_set.h" #include "elf_builder.h" #include "linker/vector_output_stream.h" // liblzma. #include "7zCrc.h" #include "XzCrc64.h" #include "XzEnc.h" namespace art { namespace debug { 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> static std::vector<uint8_t> MakeMiniDebugInfoInternal( InstructionSet isa, const InstructionSetFeatures* features, size_t rodata_section_size, size_t text_section_size, const ArrayRef<const MethodDebugInfo>& method_infos) { 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, features, &out)); builder->Start(); // Mirror .rodata and .text as NOBITS sections. // It is needed to detected relocations after compression. builder->GetRoData()->WriteNoBitsSection(rodata_section_size); builder->GetText()->WriteNoBitsSection(text_section_size); WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */); WriteCFISection(builder.get(), method_infos, dwarf::DW_DEBUG_FRAME_FORMAT, false /* write_oat_paches */); builder->End(); CHECK(builder->Good()); std::vector<uint8_t> compressed_buffer; compressed_buffer.reserve(buffer.size() / 4); XzCompress(&buffer, &compressed_buffer); return compressed_buffer; } } // namespace debug } // namespace art #endif // ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_