summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2015-04-08 19:37:39 +0100
committerDavid Srbecky <dsrbecky@google.com>2015-04-09 23:55:05 +0100
commitb536247b1ce5de640eec81dddac47802cd074363 (patch)
tree22568fd953bfc92deb3378c3d5b31fb04b9948cc
parent8b3c1b6526ff6b44dd724826b8e9e6d0a2067f6e (diff)
downloadart-b536247b1ce5de640eec81dddac47802cd074363.zip
art-b536247b1ce5de640eec81dddac47802cd074363.tar.gz
art-b536247b1ce5de640eec81dddac47802cd074363.tar.bz2
Extend the DWARF library to support .debug_info section.
Change-Id: I9916abd8db227e7a73a3311294e675be5222a709
-rw-r--r--compiler/cfi_test.h9
-rw-r--r--compiler/dwarf/debug_frame_writer.h118
-rw-r--r--compiler/dwarf/debug_info_entry_writer.h248
-rw-r--r--compiler/dwarf/debug_line_writer.h87
-rw-r--r--compiler/dwarf/dwarf_test.cc87
-rw-r--r--compiler/dwarf/headers.h167
-rw-r--r--compiler/dwarf/writer.h14
-rw-r--r--compiler/elf_writer_quick.cc218
-rw-r--r--runtime/leb128.h13
-rw-r--r--runtime/leb128_test.cc19
10 files changed, 571 insertions, 409 deletions
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index f550395..9181792 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -22,8 +22,8 @@
#include <sstream>
#include "arch/instruction_set.h"
-#include "dwarf/debug_frame_writer.h"
#include "dwarf/dwarf_test.h"
+#include "dwarf/headers.h"
#include "disassembler/disassembler.h"
#include "gtest/gtest.h"
@@ -43,9 +43,10 @@ class CFITest : public dwarf::DwarfTest {
HexDump(f, actual_cfi);
fprintf(f, "\n};\n");
// Pretty-print CFI opcodes.
- dwarf::DebugFrameWriter<> eh_frame(&eh_frame_data_, false);
- eh_frame.WriteCIE(dwarf::Reg(8), {});
- eh_frame.WriteFDE(0, actual_asm.size(), actual_cfi.data(), actual_cfi.size());
+ constexpr bool is64bit = false;
+ dwarf::DebugFrameOpCodeWriter<> initial_opcodes;
+ dwarf::WriteEhFrameCIE(is64bit, dwarf::Reg(8), initial_opcodes, &eh_frame_data_);
+ dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi, &eh_frame_data_);
ReformatCfi(Objdump(false, "-W"), &lines);
// Pretty-print assembly.
auto* opts = new DisassemblerOptions(false, actual_asm.data(), true);
diff --git a/compiler/dwarf/debug_frame_writer.h b/compiler/dwarf/debug_frame_writer.h
deleted file mode 100644
index 3502906..0000000
--- a/compiler/dwarf/debug_frame_writer.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2015 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_DWARF_DEBUG_FRAME_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_
-
-#include "debug_frame_opcode_writer.h"
-#include "dwarf.h"
-#include "writer.h"
-
-namespace art {
-namespace dwarf {
-
-// Writer for the .eh_frame section (which extends .debug_frame specification).
-template<typename Allocator = std::allocator<uint8_t>>
-class DebugFrameWriter FINAL : private Writer<Allocator> {
- public:
- void WriteCIE(Reg return_address_register,
- const uint8_t* initial_opcodes,
- int initial_opcodes_size) {
- DCHECK(cie_header_start_ == ~0u);
- cie_header_start_ = this->data()->size();
- if (use_64bit_address_) {
- // TODO: This is not related to being 64bit.
- this->PushUint32(0xffffffff);
- this->PushUint64(0); // Length placeholder.
- this->PushUint64(0); // CIE id.
- } else {
- this->PushUint32(0); // Length placeholder.
- this->PushUint32(0); // CIE id.
- }
- this->PushUint8(1); // Version.
- this->PushString("zR");
- this->PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor);
- this->PushSleb128(DebugFrameOpCodeWriter<Allocator>::kDataAlignmentFactor);
- this->PushUleb128(return_address_register.num()); // ubyte in DWARF2.
- this->PushUleb128(1); // z: Augmentation data size.
- if (use_64bit_address_) {
- this->PushUint8(0x04); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8).
- } else {
- this->PushUint8(0x03); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
- }
- this->PushData(initial_opcodes, initial_opcodes_size);
- this->Pad(use_64bit_address_ ? 8 : 4);
- if (use_64bit_address_) {
- this->UpdateUint64(cie_header_start_ + 4, this->data()->size() - cie_header_start_ - 12);
- } else {
- this->UpdateUint32(cie_header_start_, this->data()->size() - cie_header_start_ - 4);
- }
- }
-
- void WriteCIE(Reg return_address_register,
- const DebugFrameOpCodeWriter<Allocator>& opcodes) {
- WriteCIE(return_address_register, opcodes.data()->data(), opcodes.data()->size());
- }
-
- void WriteFDE(uint64_t initial_address,
- uint64_t address_range,
- const uint8_t* unwind_opcodes,
- int unwind_opcodes_size) {
- DCHECK(cie_header_start_ != ~0u);
- size_t fde_header_start = this->data()->size();
- if (use_64bit_address_) {
- // TODO: This is not related to being 64bit.
- this->PushUint32(0xffffffff);
- this->PushUint64(0); // Length placeholder.
- this->PushUint64(this->data()->size() - cie_header_start_); // 'CIE_pointer'
- } else {
- this->PushUint32(0); // Length placeholder.
- this->PushUint32(static_cast<uint32_t>(this->data()->size() - cie_header_start_)); // 'CIE_pointer'
- }
- if (use_64bit_address_) {
- this->PushUint64(initial_address);
- this->PushUint64(address_range);
- } else {
- this->PushUint32(initial_address);
- this->PushUint32(address_range);
- }
- this->PushUleb128(0); // Augmentation data size.
- this->PushData(unwind_opcodes, unwind_opcodes_size);
- this->Pad(use_64bit_address_ ? 8 : 4);
- if (use_64bit_address_) {
- this->UpdateUint64(fde_header_start + 4, this->data()->size() - fde_header_start - 12);
- } else {
- this->UpdateUint32(fde_header_start, this->data()->size() - fde_header_start - 4);
- }
- }
-
- DebugFrameWriter(std::vector<uint8_t, Allocator>* buffer, bool use_64bit_address)
- : Writer<Allocator>(buffer),
- use_64bit_address_(use_64bit_address),
- cie_header_start_(~0u) {
- }
-
- private:
- bool use_64bit_address_;
- size_t cie_header_start_;
-
- DISALLOW_COPY_AND_ASSIGN(DebugFrameWriter);
-};
-
-} // namespace dwarf
-} // namespace art
-
-#endif // ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/dwarf/debug_info_entry_writer.h
new file mode 100644
index 0000000..c0350b6
--- /dev/null
+++ b/compiler/dwarf/debug_info_entry_writer.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2014 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_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+
+#include <unordered_map>
+
+#include "dwarf.h"
+#include "leb128.h"
+#include "writer.h"
+
+namespace art {
+namespace dwarf {
+
+// 32-bit FNV-1a hash function which we use to find duplicate abbreviations.
+// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
+template< typename Allocator >
+struct FNVHash {
+ size_t operator()(const std::vector<uint8_t, Allocator>& v) const {
+ uint32_t hash = 2166136261u;
+ for (size_t i = 0; i < v.size(); i++) {
+ hash = (hash ^ v[i]) * 16777619u;
+ }
+ return hash;
+ }
+};
+
+/*
+ * Writer for debug information entries (DIE).
+ * It also handles generation of abbreviations.
+ *
+ * Usage:
+ * StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes);
+ * WriteStrp(DW_AT_producer, "Compiler name", debug_str);
+ * StartTag(DW_TAG_subprogram, DW_CHILDREN_no);
+ * WriteStrp(DW_AT_name, "Foo", debug_str);
+ * EndTag();
+ * EndTag();
+ */
+template< typename Allocator = std::allocator<uint8_t> >
+class DebugInfoEntryWriter FINAL : private Writer<Allocator> {
+ public:
+ // Start debugging information entry.
+ void StartTag(Tag tag, Children children) {
+ DCHECK(has_children) << "This tag can not have nested tags";
+ if (inside_entry_) {
+ // Write abbrev code for the previous entry.
+ this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
+ inside_entry_ = false;
+ }
+ StartAbbrev(tag, children);
+ // Abbrev code placeholder of sufficient size.
+ abbrev_code_offset_ = this->data()->size();
+ this->PushUleb128(NextAbbrevCode());
+ depth_++;
+ inside_entry_ = true;
+ has_children = (children == DW_CHILDREN_yes);
+ }
+
+ // End debugging information entry.
+ void EndTag() {
+ DCHECK_GT(depth_, 0);
+ if (inside_entry_) {
+ // Write abbrev code for this tag.
+ this->UpdateUleb128(abbrev_code_offset_, EndAbbrev());
+ inside_entry_ = false;
+ }
+ if (has_children) {
+ this->PushUint8(0); // End of children.
+ }
+ depth_--;
+ has_children = true; // Parent tag obviously has children.
+ }
+
+ void WriteAddr(Attribute attrib, uint64_t value) {
+ AddAbbrevAttribute(attrib, DW_FORM_addr);
+ if (is64bit_) {
+ this->PushUint64(value);
+ } else {
+ this->PushUint32(value);
+ }
+ }
+
+ void WriteBlock(Attribute attrib, const void* ptr, int size) {
+ AddAbbrevAttribute(attrib, DW_FORM_block);
+ this->PushUleb128(size);
+ this->PushData(ptr, size);
+ }
+
+ void WriteData1(Attribute attrib, uint8_t value) {
+ AddAbbrevAttribute(attrib, DW_FORM_data1);
+ this->PushUint8(value);
+ }
+
+ void WriteData2(Attribute attrib, uint16_t value) {
+ AddAbbrevAttribute(attrib, DW_FORM_data2);
+ this->PushUint16(value);
+ }
+
+ void WriteData4(Attribute attrib, uint32_t value) {
+ AddAbbrevAttribute(attrib, DW_FORM_data4);
+ this->PushUint32(value);
+ }
+
+ void WriteData8(Attribute attrib, uint64_t value) {
+ AddAbbrevAttribute(attrib, DW_FORM_data8);
+ this->PushUint64(value);
+ }
+
+ void WriteSdata(Attribute attrib, int value) {
+ AddAbbrevAttribute(attrib, DW_FORM_sdata);
+ this->PushSleb128(value);
+ }
+
+ void WriteUdata(Attribute attrib, int value) {
+ AddAbbrevAttribute(attrib, DW_FORM_udata);
+ this->PushUleb128(value);
+ }
+
+ void WriteUdata(Attribute attrib, uint32_t value) {
+ AddAbbrevAttribute(attrib, DW_FORM_udata);
+ this->PushUleb128(value);
+ }
+
+ void WriteFlag(Attribute attrib, bool value) {
+ AddAbbrevAttribute(attrib, DW_FORM_flag);
+ this->PushUint8(value ? 1 : 0);
+ }
+
+ void WriteRef4(Attribute attrib, int cu_offset) {
+ AddAbbrevAttribute(attrib, DW_FORM_ref4);
+ this->PushUint32(cu_offset);
+ }
+
+ void WriteRef(Attribute attrib, int cu_offset) {
+ AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
+ this->PushUleb128(cu_offset);
+ }
+
+ void WriteString(Attribute attrib, const char* value) {
+ AddAbbrevAttribute(attrib, DW_FORM_string);
+ this->PushString(value);
+ }
+
+ void WriteStrp(Attribute attrib, int address) {
+ AddAbbrevAttribute(attrib, DW_FORM_strp);
+ this->PushUint32(address);
+ }
+
+ void WriteStrp(Attribute attrib, const char* value, std::vector<uint8_t>* debug_str) {
+ AddAbbrevAttribute(attrib, DW_FORM_strp);
+ int address = debug_str->size();
+ debug_str->insert(debug_str->end(), value, value + strlen(value) + 1);
+ this->PushUint32(address);
+ }
+
+ bool is64bit() const { return is64bit_; }
+
+ using Writer<Allocator>::data;
+
+ DebugInfoEntryWriter(bool is64bitArch,
+ std::vector<uint8_t, Allocator>* debug_abbrev,
+ const Allocator& alloc = Allocator())
+ : Writer<Allocator>(&entries_),
+ debug_abbrev_(debug_abbrev),
+ current_abbrev_(alloc),
+ abbrev_codes_(alloc),
+ entries_(alloc),
+ is64bit_(is64bitArch) {
+ debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
+ }
+
+ ~DebugInfoEntryWriter() {
+ DCHECK_EQ(depth_, 0);
+ }
+
+ private:
+ // Start abbreviation declaration.
+ void StartAbbrev(Tag tag, Children children) {
+ DCHECK(!inside_entry_);
+ current_abbrev_.clear();
+ EncodeUnsignedLeb128(&current_abbrev_, tag);
+ current_abbrev_.push_back(children);
+ }
+
+ // Add attribute specification.
+ void AddAbbrevAttribute(Attribute name, Form type) {
+ DCHECK(inside_entry_) << "Call StartTag before adding attributes.";
+ EncodeUnsignedLeb128(&current_abbrev_, name);
+ EncodeUnsignedLeb128(&current_abbrev_, type);
+ }
+
+ int NextAbbrevCode() {
+ return 1 + abbrev_codes_.size();
+ }
+
+ // End abbreviation declaration and return its code.
+ int EndAbbrev() {
+ DCHECK(inside_entry_);
+ auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_),
+ NextAbbrevCode()));
+ int abbrev_code = it.first->second;
+ if (UNLIKELY(it.second)) { // Inserted new entry.
+ const std::vector<uint8_t, Allocator>& abbrev = it.first->first;
+ debug_abbrev_.Pop(); // Remove abbrev table terminator.
+ debug_abbrev_.PushUleb128(abbrev_code);
+ debug_abbrev_.PushData(abbrev.data(), abbrev.size());
+ debug_abbrev_.PushUint8(0); // Attribute list end.
+ debug_abbrev_.PushUint8(0); // Attribute list end.
+ debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
+ }
+ return abbrev_code;
+ }
+
+ private:
+ // Fields for writing and deduplication of abbrevs.
+ Writer<Allocator> debug_abbrev_;
+ std::vector<uint8_t, Allocator> current_abbrev_;
+ std::unordered_map<std::vector<uint8_t, Allocator>, int,
+ FNVHash<Allocator> > abbrev_codes_;
+
+ // Fields for writing of debugging information entries.
+ std::vector<uint8_t, Allocator> entries_;
+ bool is64bit_;
+ int depth_ = 0;
+ size_t abbrev_code_offset_ = 0; // Location to patch once we know the code.
+ bool inside_entry_ = false; // Entry ends at first child (if any).
+ bool has_children = true;
+};
+
+} // namespace dwarf
+} // namespace art
+
+#endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
diff --git a/compiler/dwarf/debug_line_writer.h b/compiler/dwarf/debug_line_writer.h
deleted file mode 100644
index 4b7d8d9..0000000
--- a/compiler/dwarf/debug_line_writer.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2015 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_DWARF_DEBUG_LINE_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_LINE_WRITER_H_
-
-#include "debug_line_opcode_writer.h"
-#include "dwarf.h"
-#include "writer.h"
-#include <string>
-
-namespace art {
-namespace dwarf {
-
-// Writer for the .debug_line section (DWARF-3).
-template<typename Allocator = std::allocator<uint8_t>>
-class DebugLineWriter FINAL : private Writer<Allocator> {
- public:
- struct FileEntry {
- std::string file_name;
- int directory_index;
- int modification_time;
- int file_size;
- };
-
- void WriteTable(const std::vector<std::string>& include_directories,
- const std::vector<FileEntry>& files,
- const DebugLineOpCodeWriter<Allocator>& opcodes) {
- size_t header_start = this->data()->size();
- this->PushUint32(0); // Section-length placeholder.
- // Claim DWARF-2 version even though we use some DWARF-3 features.
- // DWARF-2 consumers will ignore the unknown opcodes.
- // This is what clang currently does.
- this->PushUint16(2); // .debug_line version.
- size_t header_length_pos = this->data()->size();
- this->PushUint32(0); // Header-length placeholder.
- this->PushUint8(1 << opcodes.GetCodeFactorBits());
- this->PushUint8(DebugLineOpCodeWriter<Allocator>::kDefaultIsStmt ? 1 : 0);
- this->PushInt8(DebugLineOpCodeWriter<Allocator>::kLineBase);
- this->PushUint8(DebugLineOpCodeWriter<Allocator>::kLineRange);
- this->PushUint8(DebugLineOpCodeWriter<Allocator>::kOpcodeBase);
- static const int opcode_lengths[DebugLineOpCodeWriter<Allocator>::kOpcodeBase] = {
- 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 };
- for (int i = 1; i < DebugLineOpCodeWriter<Allocator>::kOpcodeBase; i++) {
- this->PushUint8(opcode_lengths[i]);
- }
- for (const std::string& directory : include_directories) {
- this->PushData(directory.data(), directory.size() + 1);
- }
- this->PushUint8(0); // Terminate include_directories list.
- for (const FileEntry& file : files) {
- this->PushData(file.file_name.data(), file.file_name.size() + 1);
- this->PushUleb128(file.directory_index);
- this->PushUleb128(file.modification_time);
- this->PushUleb128(file.file_size);
- }
- this->PushUint8(0); // Terminate file list.
- this->UpdateUint32(header_length_pos, this->data()->size() - header_length_pos - 4);
- this->PushData(opcodes.data()->data(), opcodes.data()->size());
- this->UpdateUint32(header_start, this->data()->size() - header_start - 4);
- }
-
- explicit DebugLineWriter(std::vector<uint8_t, Allocator>* buffer)
- : Writer<Allocator>(buffer) {
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DebugLineWriter);
-};
-
-} // namespace dwarf
-} // namespace art
-
-#endif // ART_COMPILER_DWARF_DEBUG_LINE_WRITER_H_
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc
index 2b051c9..ec18e96 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/dwarf/dwarf_test.cc
@@ -17,9 +17,9 @@
#include "dwarf_test.h"
#include "dwarf/debug_frame_opcode_writer.h"
-#include "dwarf/debug_frame_writer.h"
+#include "dwarf/debug_info_entry_writer.h"
#include "dwarf/debug_line_opcode_writer.h"
-#include "dwarf/debug_line_writer.h"
+#include "dwarf/headers.h"
#include "gtest/gtest.h"
namespace art {
@@ -118,23 +118,20 @@ TEST_F(DwarfTest, DebugFrame) {
DW_CHECK_NEXT("DW_CFA_restore: r2 (edx)");
DW_CHECK_NEXT("DW_CFA_restore: r5 (ebp)");
- DebugFrameWriter<> eh_frame(&eh_frame_data_, is64bit);
DebugFrameOpCodeWriter<> initial_opcodes;
- eh_frame.WriteCIE(Reg(is64bit ? 16 : 8), // Return address register.
- initial_opcodes); // Initial opcodes.
- eh_frame.WriteFDE(0x01000000, 0x01000000,
- opcodes.data()->data(), opcodes.data()->size());
+ WriteEhFrameCIE(is64bit, Reg(is64bit ? 16 : 8), initial_opcodes, &eh_frame_data_);
+ WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(), &eh_frame_data_);
CheckObjdumpOutput(is64bit, "-W");
}
// TODO: objdump seems to have trouble with 64bit CIE length.
TEST_F(DwarfTest, DISABLED_DebugFrame64) {
- const bool is64bit = true;
- DebugFrameWriter<> eh_frame(&eh_frame_data_, is64bit);
- DebugFrameOpCodeWriter<> no_opcodes;
- eh_frame.WriteCIE(Reg(16), no_opcodes);
- eh_frame.WriteFDE(0x0100000000000000, 0x0200000000000000,
- no_opcodes.data()->data(), no_opcodes.data()->size());
+ constexpr bool is64bit = true;
+ DebugFrameOpCodeWriter<> initial_opcodes;
+ WriteEhFrameCIE(is64bit, Reg(16), initial_opcodes, &eh_frame_data_);
+ DebugFrameOpCodeWriter<> opcodes;
+ WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
+ opcodes.data(), &eh_frame_data_);
DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
CheckObjdumpOutput(is64bit, "-W");
}
@@ -148,7 +145,7 @@ TEST_F(DwarfTest, DebugLine) {
include_directories.push_back("/path/to/source");
DW_CHECK("/path/to/source");
- std::vector<DebugLineWriter<>::FileEntry> files {
+ std::vector<FileEntry> files {
{ "file0.c", 0, 1000, 2000 },
{ "file1.c", 1, 1000, 2000 },
{ "file2.c", 1, 1000, 2000 },
@@ -187,8 +184,7 @@ TEST_F(DwarfTest, DebugLine) {
DW_CHECK_NEXT("Entry\tDir\tTime\tSize\tName");
DW_CHECK_NEXT("1\t0\t1000\t2000\tfile.c");
- DebugLineWriter<> debug_line(&debug_line_data_);
- debug_line.WriteTable(include_directories, files, opcodes);
+ WriteDebugLineTable(include_directories, files, opcodes, &debug_line_data_);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -222,14 +218,63 @@ TEST_F(DwarfTest, DebugLineSpecialOpcodes) {
EXPECT_LT(opcodes.data()->size(), num_rows * 3);
std::vector<std::string> directories;
- std::vector<DebugLineWriter<>::FileEntry> files {
- { "file.c", 0, 1000, 2000 },
- };
- DebugLineWriter<> debug_line(&debug_line_data_);
- debug_line.WriteTable(directories, files, opcodes);
+ std::vector<FileEntry> files { { "file.c", 0, 1000, 2000 } }; // NOLINT
+ WriteDebugLineTable(directories, files, opcodes, &debug_line_data_);
CheckObjdumpOutput(is64bit, "-W -WL");
}
+TEST_F(DwarfTest, DebugInfo) {
+ constexpr bool is64bit = false;
+ DebugInfoEntryWriter<> info(is64bit, &debug_abbrev_data_);
+ DW_CHECK("Contents of the .debug_info section:");
+ info.StartTag(dwarf::DW_TAG_compile_unit, dwarf::DW_CHILDREN_yes);
+ DW_CHECK("Abbrev Number: 1 (DW_TAG_compile_unit)");
+ info.WriteStrp(dwarf::DW_AT_producer, "Compiler name", &debug_str_data_);
+ DW_CHECK_NEXT("DW_AT_producer : (indirect string, offset: 0x0): Compiler name");
+ info.WriteAddr(dwarf::DW_AT_low_pc, 0x01000000);
+ DW_CHECK_NEXT("DW_AT_low_pc : 0x1000000");
+ info.WriteAddr(dwarf::DW_AT_high_pc, 0x02000000);
+ DW_CHECK_NEXT("DW_AT_high_pc : 0x2000000");
+ info.StartTag(dwarf::DW_TAG_subprogram, dwarf::DW_CHILDREN_no);
+ DW_CHECK("Abbrev Number: 2 (DW_TAG_subprogram)");
+ info.WriteStrp(dwarf::DW_AT_name, "Foo", &debug_str_data_);
+ DW_CHECK_NEXT("DW_AT_name : (indirect string, offset: 0xe): Foo");
+ info.WriteAddr(dwarf::DW_AT_low_pc, 0x01010000);
+ DW_CHECK_NEXT("DW_AT_low_pc : 0x1010000");
+ info.WriteAddr(dwarf::DW_AT_high_pc, 0x01020000);
+ DW_CHECK_NEXT("DW_AT_high_pc : 0x1020000");
+ info.EndTag(); // DW_TAG_subprogram
+ info.StartTag(dwarf::DW_TAG_subprogram, dwarf::DW_CHILDREN_no);
+ DW_CHECK("Abbrev Number: 2 (DW_TAG_subprogram)");
+ info.WriteStrp(dwarf::DW_AT_name, "Bar", &debug_str_data_);
+ DW_CHECK_NEXT("DW_AT_name : (indirect string, offset: 0x12): Bar");
+ info.WriteAddr(dwarf::DW_AT_low_pc, 0x01020000);
+ DW_CHECK_NEXT("DW_AT_low_pc : 0x1020000");
+ info.WriteAddr(dwarf::DW_AT_high_pc, 0x01030000);
+ DW_CHECK_NEXT("DW_AT_high_pc : 0x1030000");
+ info.EndTag(); // DW_TAG_subprogram
+ info.EndTag(); // DW_TAG_compile_unit
+ // Test that previous list was properly terminated and empty children.
+ info.StartTag(dwarf::DW_TAG_compile_unit, dwarf::DW_CHILDREN_yes);
+ info.EndTag(); // DW_TAG_compile_unit
+
+ // The abbrev table is just side product, but check it as well.
+ DW_CHECK("Abbrev Number: 3 (DW_TAG_compile_unit)");
+ DW_CHECK("Contents of the .debug_abbrev section:");
+ DW_CHECK("1 DW_TAG_compile_unit [has children]");
+ DW_CHECK_NEXT("DW_AT_producer DW_FORM_strp");
+ DW_CHECK_NEXT("DW_AT_low_pc DW_FORM_addr");
+ DW_CHECK_NEXT("DW_AT_high_pc DW_FORM_addr");
+ DW_CHECK("2 DW_TAG_subprogram [no children]");
+ DW_CHECK_NEXT("DW_AT_name DW_FORM_strp");
+ DW_CHECK_NEXT("DW_AT_low_pc DW_FORM_addr");
+ DW_CHECK_NEXT("DW_AT_high_pc DW_FORM_addr");
+ DW_CHECK("3 DW_TAG_compile_unit [has children]");
+
+ dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info, &debug_info_data_);
+ CheckObjdumpOutput(is64bit, "-W");
+}
+
#endif // HAVE_ANDROID_OS
} // namespace dwarf
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
new file mode 100644
index 0000000..d866b91
--- /dev/null
+++ b/compiler/dwarf/headers.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 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_DWARF_HEADERS_H_
+#define ART_COMPILER_DWARF_HEADERS_H_
+
+#include "debug_frame_opcode_writer.h"
+#include "debug_info_entry_writer.h"
+#include "debug_line_opcode_writer.h"
+#include "register.h"
+#include "writer.h"
+
+namespace art {
+namespace dwarf {
+
+// Write common information entry (CIE) to .eh_frame section.
+template<typename Allocator>
+void WriteEhFrameCIE(bool is64bit, Reg return_address_register,
+ const DebugFrameOpCodeWriter<Allocator>& opcodes,
+ std::vector<uint8_t>* eh_frame) {
+ Writer<> writer(eh_frame);
+ size_t cie_header_start_ = writer.data()->size();
+ if (is64bit) {
+ // TODO: This is not related to being 64bit.
+ writer.PushUint32(0xffffffff);
+ writer.PushUint64(0); // Length placeholder.
+ writer.PushUint64(0); // CIE id.
+ } else {
+ writer.PushUint32(0); // Length placeholder.
+ writer.PushUint32(0); // CIE id.
+ }
+ writer.PushUint8(1); // Version.
+ writer.PushString("zR");
+ writer.PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor);
+ writer.PushSleb128(DebugFrameOpCodeWriter<Allocator>::kDataAlignmentFactor);
+ writer.PushUleb128(return_address_register.num()); // ubyte in DWARF2.
+ writer.PushUleb128(1); // z: Augmentation data size.
+ if (is64bit) {
+ writer.PushUint8(0x04); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8).
+ } else {
+ writer.PushUint8(0x03); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
+ }
+ writer.PushData(opcodes.data());
+ writer.Pad(is64bit ? 8 : 4);
+ if (is64bit) {
+ writer.UpdateUint64(cie_header_start_ + 4, writer.data()->size() - cie_header_start_ - 12);
+ } else {
+ writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
+ }
+}
+
+// Write frame description entry (FDE) to .eh_frame section.
+template<typename Allocator>
+void WriteEhFrameFDE(bool is64bit, size_t cie_offset,
+ uint64_t initial_address, uint64_t address_range,
+ const std::vector<uint8_t, Allocator>* opcodes,
+ std::vector<uint8_t>* eh_frame) {
+ Writer<> writer(eh_frame);
+ size_t fde_header_start = writer.data()->size();
+ if (is64bit) {
+ // TODO: This is not related to being 64bit.
+ writer.PushUint32(0xffffffff);
+ writer.PushUint64(0); // Length placeholder.
+ uint64_t cie_pointer = writer.data()->size() - cie_offset;
+ writer.PushUint64(cie_pointer);
+ } else {
+ writer.PushUint32(0); // Length placeholder.
+ uint32_t cie_pointer = writer.data()->size() - cie_offset;
+ writer.PushUint32(cie_pointer);
+ }
+ if (is64bit) {
+ writer.PushUint64(initial_address);
+ writer.PushUint64(address_range);
+ } else {
+ writer.PushUint32(initial_address);
+ writer.PushUint32(address_range);
+ }
+ writer.PushUleb128(0); // Augmentation data size.
+ writer.PushData(opcodes);
+ writer.Pad(is64bit ? 8 : 4);
+ if (is64bit) {
+ writer.UpdateUint64(fde_header_start + 4, writer.data()->size() - fde_header_start - 12);
+ } else {
+ writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4);
+ }
+}
+
+// Write compilation unit (CU) to .debug_info section.
+template<typename Allocator>
+void WriteDebugInfoCU(uint32_t debug_abbrev_offset,
+ const DebugInfoEntryWriter<Allocator>& entries,
+ std::vector<uint8_t>* debug_info) {
+ Writer<> writer(debug_info);
+ size_t start = writer.data()->size();
+ writer.PushUint32(0); // Length placeholder.
+ writer.PushUint16(3); // Version.
+ writer.PushUint32(debug_abbrev_offset);
+ writer.PushUint8(entries.is64bit() ? 8 : 4);
+ writer.PushData(entries.data());
+ writer.UpdateUint32(start, writer.data()->size() - start - 4);
+}
+
+struct FileEntry {
+ std::string file_name;
+ int directory_index;
+ int modification_time;
+ int file_size;
+};
+
+// Write line table to .debug_line section.
+template<typename Allocator>
+void WriteDebugLineTable(const std::vector<std::string>& include_directories,
+ const std::vector<FileEntry>& files,
+ const DebugLineOpCodeWriter<Allocator>& opcodes,
+ std::vector<uint8_t>* debug_line) {
+ Writer<> writer(debug_line);
+ size_t header_start = writer.data()->size();
+ writer.PushUint32(0); // Section-length placeholder.
+ // Claim DWARF-2 version even though we use some DWARF-3 features.
+ // DWARF-2 consumers will ignore the unknown opcodes.
+ // This is what clang currently does.
+ writer.PushUint16(2); // .debug_line version.
+ size_t header_length_pos = writer.data()->size();
+ writer.PushUint32(0); // Header-length placeholder.
+ writer.PushUint8(1 << opcodes.GetCodeFactorBits());
+ writer.PushUint8(DebugLineOpCodeWriter<Allocator>::kDefaultIsStmt ? 1 : 0);
+ writer.PushInt8(DebugLineOpCodeWriter<Allocator>::kLineBase);
+ writer.PushUint8(DebugLineOpCodeWriter<Allocator>::kLineRange);
+ writer.PushUint8(DebugLineOpCodeWriter<Allocator>::kOpcodeBase);
+ static const int opcode_lengths[DebugLineOpCodeWriter<Allocator>::kOpcodeBase] = {
+ 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 };
+ for (int i = 1; i < DebugLineOpCodeWriter<Allocator>::kOpcodeBase; i++) {
+ writer.PushUint8(opcode_lengths[i]);
+ }
+ for (const std::string& directory : include_directories) {
+ writer.PushData(directory.data(), directory.size() + 1);
+ }
+ writer.PushUint8(0); // Terminate include_directories list.
+ for (const FileEntry& file : files) {
+ writer.PushData(file.file_name.data(), file.file_name.size() + 1);
+ writer.PushUleb128(file.directory_index);
+ writer.PushUleb128(file.modification_time);
+ writer.PushUleb128(file.file_size);
+ }
+ writer.PushUint8(0); // Terminate file list.
+ writer.UpdateUint32(header_length_pos, writer.data()->size() - header_length_pos - 4);
+ writer.PushData(opcodes.data()->data(), opcodes.data()->size());
+ writer.UpdateUint32(header_start, writer.data()->size() - header_start - 4);
+}
+
+} // namespace dwarf
+} // namespace art
+
+#endif // ART_COMPILER_DWARF_HEADERS_H_
diff --git a/compiler/dwarf/writer.h b/compiler/dwarf/writer.h
index d8e29f0..3b9c558 100644
--- a/compiler/dwarf/writer.h
+++ b/compiler/dwarf/writer.h
@@ -116,6 +116,11 @@ class Writer {
data_->insert(data_->end(), p, p + size);
}
+ template<typename Allocator2>
+ void PushData(const std::vector<uint8_t, Allocator2>* buffer) {
+ data_->insert(data_->end(), buffer->begin(), buffer->end());
+ }
+
void UpdateUint32(size_t offset, uint32_t value) {
DCHECK_LT(offset + 3, data_->size());
(*data_)[offset + 0] = (value >> 0) & 0xFF;
@@ -136,6 +141,15 @@ class Writer {
(*data_)[offset + 7] = (value >> 56) & 0xFF;
}
+ void UpdateUleb128(size_t offset, uint32_t value) {
+ DCHECK_LE(offset + UnsignedLeb128Size(value), data_->size());
+ UpdateUnsignedLeb128(data_->data() + offset, value);
+ }
+
+ void Pop() {
+ return data_->pop_back();
+ }
+
void Pad(int alignment) {
DCHECK_NE(alignment, 0);
data_->resize(RoundUp(data_->size(), alignment), 0);
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 2756af1..f780dea 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -26,8 +26,7 @@
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "dwarf.h"
-#include "dwarf/debug_frame_writer.h"
-#include "dwarf/debug_line_writer.h"
+#include "dwarf/headers.h"
#include "elf_builder.h"
#include "elf_file.h"
#include "elf_utils.h"
@@ -40,42 +39,6 @@
namespace art {
-static void PushByte(std::vector<uint8_t>* buf, int data) {
- buf->push_back(data & 0xff);
-}
-
-static uint32_t PushStr(std::vector<uint8_t>* buf, const char* str, const char* def = nullptr) {
- if (str == nullptr) {
- str = def;
- }
-
- uint32_t offset = buf->size();
- for (size_t i = 0; str[i] != '\0'; ++i) {
- buf->push_back(str[i]);
- }
- buf->push_back('\0');
- return offset;
-}
-
-static uint32_t PushStr(std::vector<uint8_t>* buf, const std::string &str) {
- uint32_t offset = buf->size();
- buf->insert(buf->end(), str.begin(), str.end());
- buf->push_back('\0');
- return offset;
-}
-
-static void UpdateWord(std::vector<uint8_t>* buf, int offset, int data) {
- (*buf)[offset+0] = data;
- (*buf)[offset+1] = data >> 8;
- (*buf)[offset+2] = data >> 16;
- (*buf)[offset+3] = data >> 24;
-}
-
-static void PushHalf(std::vector<uint8_t>* buf, int data) {
- buf->push_back(data & 0xff);
- buf->push_back((data >> 8) & 0xff);
-}
-
template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr,
typename Elf_Phdr, typename Elf_Shdr>
@@ -90,7 +53,8 @@ bool ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-void WriteCIE(dwarf::DebugFrameWriter<>* cfi, InstructionSet isa) {
+void WriteCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) {
+ const bool is64bit = Is64BitInstructionSet(isa);
// Scratch registers should be marked as undefined. This tells the
// debugger that its value in the previous frame is not recoverable.
switch (isa) {
@@ -115,7 +79,7 @@ void WriteCIE(dwarf::DebugFrameWriter<>* cfi, InstructionSet isa) {
}
}
auto return_address_reg = dwarf::Reg::ArmCore(14); // R14(LR).
- cfi->WriteCIE(return_address_reg, opcodes);
+ dwarf::WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
return;
}
case kArm64: {
@@ -138,7 +102,7 @@ void WriteCIE(dwarf::DebugFrameWriter<>* cfi, InstructionSet isa) {
}
}
auto return_address_reg = dwarf::Reg::Arm64Core(30); // R30(LR).
- cfi->WriteCIE(return_address_reg, opcodes);
+ dwarf::WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
return;
}
case kMips:
@@ -154,7 +118,7 @@ void WriteCIE(dwarf::DebugFrameWriter<>* cfi, InstructionSet isa) {
}
}
auto return_address_reg = dwarf::Reg::MipsCore(31); // R31(RA).
- cfi->WriteCIE(return_address_reg, opcodes);
+ dwarf::WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
return;
}
case kX86: {
@@ -176,7 +140,7 @@ void WriteCIE(dwarf::DebugFrameWriter<>* cfi, InstructionSet isa) {
opcodes.Undefined(dwarf::Reg::X86Fp(reg));
}
auto return_address_reg = dwarf::Reg::X86Core(8); // R8(EIP).
- cfi->WriteCIE(return_address_reg, opcodes);
+ dwarf::WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
return;
}
case kX86_64: {
@@ -202,7 +166,7 @@ void WriteCIE(dwarf::DebugFrameWriter<>* cfi, InstructionSet isa) {
}
}
auto return_address_reg = dwarf::Reg::X86_64Core(16); // R16(RIP).
- cfi->WriteCIE(return_address_reg, opcodes);
+ dwarf::WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
return;
}
case kNone:
@@ -298,123 +262,29 @@ bool ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
* @param dbg_str Debug strings.
*/
static void FillInCFIInformation(OatWriter* oat_writer,
- std::vector<uint8_t>* dbg_info,
- std::vector<uint8_t>* dbg_abbrev,
- std::vector<uint8_t>* dbg_str,
- std::vector<uint8_t>* dbg_line,
+ std::vector<uint8_t>* debug_info_data,
+ std::vector<uint8_t>* debug_abbrev_data,
+ std::vector<uint8_t>* debug_str_data,
+ std::vector<uint8_t>* debug_line_data,
uint32_t text_section_offset) {
const std::vector<OatWriter::DebugInfo>& method_infos = oat_writer->GetCFIMethodInfo();
- uint32_t producer_str_offset = PushStr(dbg_str, "Android dex2oat");
-
- constexpr bool use_64bit_addresses = false;
-
- // Create the debug_abbrev section with boilerplate information.
- // We only care about low_pc and high_pc right now for the compilation
- // unit and methods.
-
- // Tag 1: Compilation unit: DW_TAG_compile_unit.
- PushByte(dbg_abbrev, 1);
- PushByte(dbg_abbrev, dwarf::DW_TAG_compile_unit);
-
- // There are children (the methods).
- PushByte(dbg_abbrev, dwarf::DW_CHILDREN_yes);
-
- // DW_AT_producer DW_FORM_data1.
- // REVIEW: we can get rid of dbg_str section if
- // DW_FORM_string (immediate string) was used everywhere instead of
- // DW_FORM_strp (ref to string from .debug_str section).
- // DW_FORM_strp makes sense only if we reuse the strings.
- PushByte(dbg_abbrev, dwarf::DW_AT_producer);
- PushByte(dbg_abbrev, dwarf::DW_FORM_strp);
-
- // DW_LANG_Java DW_FORM_data1.
- PushByte(dbg_abbrev, dwarf::DW_AT_language);
- PushByte(dbg_abbrev, dwarf::DW_FORM_data1);
-
- // DW_AT_low_pc DW_FORM_addr.
- PushByte(dbg_abbrev, dwarf::DW_AT_low_pc);
- PushByte(dbg_abbrev, dwarf::DW_FORM_addr);
-
- // DW_AT_high_pc DW_FORM_addr.
- PushByte(dbg_abbrev, dwarf::DW_AT_high_pc);
- PushByte(dbg_abbrev, dwarf::DW_FORM_addr);
-
- if (dbg_line != nullptr) {
- // DW_AT_stmt_list DW_FORM_sec_offset.
- PushByte(dbg_abbrev, dwarf::DW_AT_stmt_list);
- PushByte(dbg_abbrev, dwarf::DW_FORM_data4);
- }
-
- // End of DW_TAG_compile_unit.
- PushByte(dbg_abbrev, 0); // DW_AT.
- PushByte(dbg_abbrev, 0); // DW_FORM.
-
- // Tag 2: Compilation unit: DW_TAG_subprogram.
- PushByte(dbg_abbrev, 2);
- PushByte(dbg_abbrev, dwarf::DW_TAG_subprogram);
-
- // There are no children.
- PushByte(dbg_abbrev, dwarf::DW_CHILDREN_no);
-
- // Name of the method.
- PushByte(dbg_abbrev, dwarf::DW_AT_name);
- PushByte(dbg_abbrev, dwarf::DW_FORM_strp);
-
- // DW_AT_low_pc DW_FORM_addr.
- PushByte(dbg_abbrev, dwarf::DW_AT_low_pc);
- PushByte(dbg_abbrev, dwarf::DW_FORM_addr);
-
- // DW_AT_high_pc DW_FORM_addr.
- PushByte(dbg_abbrev, dwarf::DW_AT_high_pc);
- PushByte(dbg_abbrev, dwarf::DW_FORM_addr);
-
- // End of DW_TAG_subprogram.
- PushByte(dbg_abbrev, 0); // DW_AT.
- PushByte(dbg_abbrev, 0); // DW_FORM.
-
- // End of abbrevs for compilation unit
- PushByte(dbg_abbrev, 0);
-
- // Start the debug_info section with the header information
- // 'unit_length' will be filled in later.
- int cunit_length = dbg_info->size();
- Push32(dbg_info, 0);
-
- // 'version' - 3.
- PushHalf(dbg_info, 3);
-
- // Offset into .debug_abbrev section (always 0).
- Push32(dbg_info, 0);
-
- // Address size: 4 or 8.
- PushByte(dbg_info, use_64bit_addresses ? 8 : 4);
-
- // Start the description for the compilation unit.
- // This uses tag 1.
- PushByte(dbg_info, 1);
-
- // The producer is Android dex2oat.
- Push32(dbg_info, producer_str_offset);
-
- // The language is Java.
- PushByte(dbg_info, dwarf::DW_LANG_Java);
-
- // low_pc and high_pc.
uint32_t cunit_low_pc = static_cast<uint32_t>(-1);
uint32_t cunit_high_pc = 0;
for (auto method_info : method_infos) {
cunit_low_pc = std::min(cunit_low_pc, method_info.low_pc_);
cunit_high_pc = std::max(cunit_high_pc, method_info.high_pc_);
}
- Push32(dbg_info, cunit_low_pc + text_section_offset);
- Push32(dbg_info, cunit_high_pc + text_section_offset);
- if (dbg_line != nullptr) {
- // Line number table offset.
- Push32(dbg_info, dbg_line->size());
+ dwarf::DebugInfoEntryWriter<> info(false /* 32 bit */, debug_abbrev_data);
+ info.StartTag(dwarf::DW_TAG_compile_unit, dwarf::DW_CHILDREN_yes);
+ info.WriteStrp(dwarf::DW_AT_producer, "Android dex2oat", debug_str_data);
+ info.WriteData1(dwarf::DW_AT_language, dwarf::DW_LANG_Java);
+ info.WriteAddr(dwarf::DW_AT_low_pc, cunit_low_pc + text_section_offset);
+ info.WriteAddr(dwarf::DW_AT_high_pc, cunit_high_pc + text_section_offset);
+ if (debug_line_data != nullptr) {
+ info.WriteData4(dwarf::DW_AT_stmt_list, debug_line_data->size());
}
-
for (auto method_info : method_infos) {
std::string method_name = PrettyMethod(method_info.dex_method_index_,
*method_info.dex_file_, true);
@@ -423,17 +293,16 @@ static void FillInCFIInformation(OatWriter* oat_writer,
// so that it will show up in a debuggerd crash report.
method_name += " [ DEDUPED ]";
}
-
- // Start a new TAG: subroutine (2).
- PushByte(dbg_info, 2);
-
- // Enter name, low_pc, high_pc.
- Push32(dbg_info, PushStr(dbg_str, method_name));
- Push32(dbg_info, method_info.low_pc_ + text_section_offset);
- Push32(dbg_info, method_info.high_pc_ + text_section_offset);
+ info.StartTag(dwarf::DW_TAG_subprogram, dwarf::DW_CHILDREN_no);
+ info.WriteStrp(dwarf::DW_AT_name, method_name.data(), debug_str_data);
+ info.WriteAddr(dwarf::DW_AT_low_pc, method_info.low_pc_ + text_section_offset);
+ info.WriteAddr(dwarf::DW_AT_high_pc, method_info.high_pc_ + text_section_offset);
+ info.EndTag(); // DW_TAG_subprogram
}
+ info.EndTag(); // DW_TAG_compile_unit
+ dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info, debug_info_data);
- if (dbg_line != nullptr) {
+ if (debug_line_data != nullptr) {
// TODO: in gdb info functions <regexp> - reports Java functions, but
// source file is <unknown> because .debug_line is formed as one
// compilation unit. To fix this it is possible to generate
@@ -441,7 +310,7 @@ static void FillInCFIInformation(OatWriter* oat_writer,
// Each of the these compilation units can have several non-adjacent
// method ranges.
- std::vector<dwarf::DebugLineWriter<>::FileEntry> files;
+ std::vector<dwarf::FileEntry> files;
std::unordered_map<std::string, size_t> files_map;
std::vector<std::string> directories;
std::unordered_map<std::string, size_t> directories_map;
@@ -465,7 +334,7 @@ static void FillInCFIInformation(OatWriter* oat_writer,
break;
}
- dwarf::DebugLineOpCodeWriter<> opcodes(use_64bit_addresses, code_factor_bits_);
+ dwarf::DebugLineOpCodeWriter<> opcodes(false /* 32bit */, code_factor_bits_);
opcodes.SetAddress(text_section_offset + cunit_low_pc);
if (isa != -1) {
opcodes.SetISA(isa);
@@ -529,7 +398,7 @@ static void FillInCFIInformation(OatWriter* oat_writer,
if (it2 == files_map.end()) {
file_index = 1 + files.size();
files_map.emplace(full_path, file_index);
- files.push_back(dwarf::DebugLineWriter<>::FileEntry {
+ files.push_back(dwarf::FileEntry {
file_name,
directory_index,
0, // Modification time - NA.
@@ -574,19 +443,10 @@ static void FillInCFIInformation(OatWriter* oat_writer,
opcodes.AddRow(low_pc, 0);
}
}
-
opcodes.AdvancePC(text_section_offset + cunit_high_pc);
opcodes.EndSequence();
-
- dwarf::DebugLineWriter<> dbg_line_writer(dbg_line);
- dbg_line_writer.WriteTable(directories, files, opcodes);
+ dwarf::WriteDebugLineTable(directories, files, opcodes, debug_line_data);
}
-
- // One byte terminator.
- PushByte(dbg_info, 0);
-
- // We have now walked all the methods. Fill in lengths.
- UpdateWord(dbg_info, cunit_length, dbg_info->size() - cunit_length - 4);
}
template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
@@ -599,9 +459,9 @@ static void WriteDebugSymbols(const CompilerDriver* compiler_driver,
Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder,
OatWriter* oat_writer) {
std::vector<uint8_t> cfi_data;
- bool is_64bit = Is64BitInstructionSet(compiler_driver->GetInstructionSet());
- dwarf::DebugFrameWriter<> cfi(&cfi_data, is_64bit);
- WriteCIE(&cfi, compiler_driver->GetInstructionSet());
+ const int cie_offset = 0;
+ bool is64bit = Is64BitInstructionSet(compiler_driver->GetInstructionSet());
+ WriteCIE(compiler_driver->GetInstructionSet(), &cfi_data);
Elf_Addr text_section_address = builder->GetTextBuilder().GetSection()->sh_addr;
@@ -632,12 +492,12 @@ static void WriteDebugSymbols(const CompilerDriver* compiler_driver,
// Include FDE for compiled method, if possible.
DCHECK(it->compiled_method_ != nullptr);
- const SwapVector<uint8_t>* unwind_opcodes = it->compiled_method_->GetCFIInfo();
- if (unwind_opcodes != nullptr) {
+ const SwapVector<uint8_t>* opcodes = it->compiled_method_->GetCFIInfo();
+ if (opcodes != nullptr) {
// TUNING: The headers take a lot of space. Can we have 1 FDE per file?
// TUNING: Some tools support compressed DWARF sections (.zdebug_*).
- cfi.WriteFDE(text_section_address + it->low_pc_, it->high_pc_ - it->low_pc_,
- unwind_opcodes->data(), unwind_opcodes->size());
+ dwarf::WriteEhFrameFDE(is64bit, cie_offset, text_section_address + it->low_pc_,
+ it->high_pc_ - it->low_pc_, opcodes, &cfi_data);
}
}
diff --git a/runtime/leb128.h b/runtime/leb128.h
index d36b690..2e27b8e 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -136,6 +136,19 @@ static inline void EncodeUnsignedLeb128(std::vector<uint8_t, Allocator>* dest, u
dest->push_back(out);
}
+// Overwrite encoded Leb128 with a new value. The new value must be less than
+// or equal to the old value to ensure that it fits the allocated space.
+static inline void UpdateUnsignedLeb128(uint8_t* dest, uint32_t value) {
+ const uint8_t* old_end = dest;
+ uint32_t old_value = DecodeUnsignedLeb128(&old_end);
+ DCHECK_LE(value, old_value);
+ for (uint8_t* end = EncodeUnsignedLeb128(dest, value); end < old_end; end++) {
+ // Use longer encoding than necessary to fill the allocated space.
+ end[-1] |= 0x80;
+ end[0] = 0;
+ }
+}
+
static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) {
uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
uint8_t out = value & 0x7f;
diff --git a/runtime/leb128_test.cc b/runtime/leb128_test.cc
index 5d157dc..87e13ff 100644
--- a/runtime/leb128_test.cc
+++ b/runtime/leb128_test.cc
@@ -252,6 +252,25 @@ TEST(Leb128Test, SignedStream) {
EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data));
}
+TEST(Leb128Test, UnsignedUpdate) {
+ for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
+ for (size_t j = 0; j < arraysize(uleb128_tests); ++j) {
+ uint32_t old_value = uleb128_tests[i].decoded;
+ uint32_t new_value = uleb128_tests[j].decoded;
+ // We can only make the encoded value smaller.
+ if (new_value <= old_value) {
+ uint8_t encoded_data[5];
+ uint8_t* old_end = EncodeUnsignedLeb128(encoded_data, old_value);
+ UpdateUnsignedLeb128(encoded_data, new_value);
+ const uint8_t* new_end = encoded_data;
+ EXPECT_EQ(DecodeUnsignedLeb128(&new_end), new_value);
+ // Even if the new value needs fewer bytes, we should fill the space.
+ EXPECT_EQ(new_end, old_end);
+ }
+ }
+ }
+}
+
TEST(Leb128Test, Speed) {
std::unique_ptr<Histogram<uint64_t>> enc_hist(new Histogram<uint64_t>("Leb128EncodeSpeedTest", 5));
std::unique_ptr<Histogram<uint64_t>> dec_hist(new Histogram<uint64_t>("Leb128DecodeSpeedTest", 5));