summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.gtest.mk2
-rw-r--r--compiler/Android.mk2
-rw-r--r--compiler/cfi_test.h6
-rw-r--r--compiler/debug/dwarf/debug_abbrev_writer.h (renamed from compiler/dwarf/debug_abbrev_writer.h)10
-rw-r--r--compiler/debug/dwarf/debug_frame_opcode_writer.h (renamed from compiler/dwarf/debug_frame_opcode_writer.h)12
-rw-r--r--compiler/debug/dwarf/debug_info_entry_writer.h (renamed from compiler/dwarf/debug_info_entry_writer.h)14
-rw-r--r--compiler/debug/dwarf/debug_line_opcode_writer.h (renamed from compiler/dwarf/debug_line_opcode_writer.h)10
-rw-r--r--compiler/debug/dwarf/dwarf_constants.h (renamed from compiler/dwarf/dwarf_constants.h)6
-rw-r--r--compiler/debug/dwarf/dwarf_test.cc (renamed from compiler/dwarf/dwarf_test.cc)10
-rw-r--r--compiler/debug/dwarf/dwarf_test.h (renamed from compiler/dwarf/dwarf_test.h)6
-rw-r--r--compiler/debug/dwarf/expression.h (renamed from compiler/dwarf/expression.h)10
-rw-r--r--compiler/debug/dwarf/headers.h (renamed from compiler/dwarf/headers.h)18
-rw-r--r--compiler/debug/dwarf/register.h (renamed from compiler/dwarf/register.h)6
-rw-r--r--compiler/debug/dwarf/writer.h (renamed from compiler/dwarf/writer.h)6
-rw-r--r--compiler/debug/elf_compilation_unit.h (renamed from compiler/dwarf/method_debug_info.h)35
-rw-r--r--compiler/debug/elf_debug_frame_writer.h290
-rw-r--r--compiler/debug/elf_debug_info_writer.h649
-rw-r--r--compiler/debug/elf_debug_line_writer.h247
-rw-r--r--compiler/debug/elf_debug_loc_writer.h298
-rw-r--r--compiler/debug/elf_debug_writer.cc183
-rw-r--r--compiler/debug/elf_debug_writer.h (renamed from compiler/elf_writer_debug.h)18
-rw-r--r--compiler/debug/elf_gnu_debugdata_writer.h111
-rw-r--r--compiler/debug/elf_symtab_writer.h115
-rw-r--r--compiler/debug/method_debug_info.h48
-rw-r--r--compiler/dex/quick/lazy_debug_frame_opcode_writer.h2
-rw-r--r--compiler/elf_writer.h8
-rw-r--r--compiler/elf_writer_debug.cc1666
-rw-r--r--compiler/elf_writer_quick.cc20
-rw-r--r--compiler/image_test.cc2
-rw-r--r--compiler/jit/jit_compiler.cc6
-rw-r--r--compiler/oat_test.cc4
-rw-r--r--compiler/oat_writer.cc6
-rw-r--r--compiler/oat_writer.h10
-rw-r--r--compiler/optimizing/intrinsics_arm.cc262
-rw-r--r--compiler/optimizing/optimizing_compiler.cc17
-rw-r--r--compiler/utils/arm/managed_register_arm.h2
-rw-r--r--compiler/utils/arm64/managed_register_arm64.h2
-rw-r--r--compiler/utils/assembler.h4
-rw-r--r--compiler/utils/mips/managed_register_mips.h2
-rw-r--r--compiler/utils/mips64/managed_register_mips64.h2
-rw-r--r--compiler/utils/x86/managed_register_x86.h2
-rw-r--r--compiler/utils/x86_64/managed_register_x86_64.h2
-rw-r--r--dex2oat/dex2oat.cc10
-rw-r--r--runtime/arch/arm/entrypoints_init_arm.cc19
-rw-r--r--runtime/dex_file_verifier.cc154
-rw-r--r--runtime/dex_file_verifier.h7
-rw-r--r--runtime/dex_file_verifier_test.cc18
-rw-r--r--runtime/gc/heap.cc4
-rw-r--r--runtime/mem_map.cc18
-rw-r--r--runtime/mem_map.h5
-rw-r--r--runtime/native/java_lang_Class.cc2
-rw-r--r--runtime/openjdkjvm/OpenjdkJvm.cc71
-rw-r--r--test/048-reflect-v8/expected.txt9
-rw-r--r--test/048-reflect-v8/src/DefaultDeclared.java71
-rw-r--r--test/048-reflect-v8/src/Main.java1
55 files changed, 2602 insertions, 1918 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index e3f0c24414..704d69a37a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -239,13 +239,13 @@ COMPILER_GTEST_COMMON_SRC_FILES := \
runtime/proxy_test.cc \
runtime/reflection_test.cc \
compiler/compiled_method_test.cc \
+ compiler/debug/dwarf/dwarf_test.cc \
compiler/dex/gvn_dead_code_elimination_test.cc \
compiler/dex/global_value_numbering_test.cc \
compiler/dex/local_value_numbering_test.cc \
compiler/dex/mir_graph_test.cc \
compiler/dex/mir_optimization_test.cc \
compiler/dex/type_inference_test.cc \
- compiler/dwarf/dwarf_test.cc \
compiler/driver/compiled_method_storage_test.cc \
compiler/driver/compiler_driver_test.cc \
compiler/elf_writer_test.cc \
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 87eff82982..b16494248f 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -20,6 +20,7 @@ include art/build/Android.common_build.mk
LIBART_COMPILER_SRC_FILES := \
compiled_method.cc \
+ debug/elf_debug_writer.cc \
dex/global_value_numbering.cc \
dex/gvn_dead_code_elimination.cc \
dex/local_value_numbering.cc \
@@ -105,7 +106,6 @@ LIBART_COMPILER_SRC_FILES := \
utils/swap_space.cc \
compiler.cc \
elf_writer.cc \
- elf_writer_debug.cc \
elf_writer_quick.cc \
image_writer.cc \
oat_writer.cc \
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index 508b04a16f..230cb9aeea 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -22,9 +22,9 @@
#include <sstream>
#include "arch/instruction_set.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/dwarf_test.h"
-#include "dwarf/headers.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/dwarf_test.h"
+#include "debug/dwarf/headers.h"
#include "disassembler/disassembler.h"
#include "gtest/gtest.h"
diff --git a/compiler/dwarf/debug_abbrev_writer.h b/compiler/debug/dwarf/debug_abbrev_writer.h
index 71367e85ad..0fc843cdf9 100644
--- a/compiler/dwarf/debug_abbrev_writer.h
+++ b/compiler/debug/dwarf/debug_abbrev_writer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_ABBREV_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_ABBREV_WRITER_H_
#include <cstdint>
#include <type_traits>
@@ -23,8 +23,8 @@
#include "base/casts.h"
#include "base/stl_util.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/writer.h"
#include "leb128.h"
namespace art {
@@ -95,4 +95,4 @@ class DebugAbbrevWriter FINAL : private Writer<Vector> {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
+#endif // ART_COMPILER_DEBUG_DWARF_DEBUG_ABBREV_WRITER_H_
diff --git a/compiler/dwarf/debug_frame_opcode_writer.h b/compiler/debug/dwarf/debug_frame_opcode_writer.h
index f74f37ce8a..7c75c9bf37 100644
--- a/compiler/dwarf/debug_frame_opcode_writer.h
+++ b/compiler/debug/dwarf/debug_frame_opcode_writer.h
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
#include "base/bit_utils.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/register.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/register.h"
+#include "debug/dwarf/writer.h"
namespace art {
namespace dwarf {
@@ -338,4 +338,4 @@ class DebugFrameOpCodeWriter : private Writer<Vector> {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
+#endif // ART_COMPILER_DEBUG_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/debug/dwarf/debug_info_entry_writer.h
index 1e298595a1..85f021ec52 100644
--- a/compiler/dwarf/debug_info_entry_writer.h
+++ b/compiler/debug/dwarf/debug_info_entry_writer.h
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
#include <cstdint>
#include <unordered_map>
#include "base/casts.h"
-#include "dwarf/debug_abbrev_writer.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/expression.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/debug_abbrev_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/expression.h"
+#include "debug/dwarf/writer.h"
#include "leb128.h"
namespace art {
@@ -225,4 +225,4 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#endif // ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
diff --git a/compiler/dwarf/debug_line_opcode_writer.h b/compiler/debug/dwarf/debug_line_opcode_writer.h
index 201f0b40bc..58502a3f9c 100644
--- a/compiler/dwarf/debug_line_opcode_writer.h
+++ b/compiler/debug/dwarf/debug_line_opcode_writer.h
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
#include <cstdint>
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/writer.h"
namespace art {
namespace dwarf {
@@ -252,4 +252,4 @@ class DebugLineOpCodeWriter FINAL : private Writer<Vector> {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
+#endif // ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/debug/dwarf/dwarf_constants.h
index 0d7951b73a..96f805e85f 100644
--- a/compiler/dwarf/dwarf_constants.h
+++ b/compiler/debug/dwarf/dwarf_constants.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_DWARF_CONSTANTS_H_
-#define ART_COMPILER_DWARF_DWARF_CONSTANTS_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DWARF_CONSTANTS_H_
+#define ART_COMPILER_DEBUG_DWARF_DWARF_CONSTANTS_H_
namespace art {
namespace dwarf {
@@ -691,4 +691,4 @@ enum CFIFormat : uint8_t {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_DWARF_CONSTANTS_H_
+#endif // ART_COMPILER_DEBUG_DWARF_DWARF_CONSTANTS_H_
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/debug/dwarf/dwarf_test.cc
index 32373119b2..e455d0d617 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/debug/dwarf/dwarf_test.cc
@@ -16,11 +16,11 @@
#include "dwarf_test.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/debug_frame_opcode_writer.h"
-#include "dwarf/debug_info_entry_writer.h"
-#include "dwarf/debug_line_opcode_writer.h"
-#include "dwarf/headers.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/dwarf/debug_line_opcode_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/headers.h"
#include "gtest/gtest.h"
namespace art {
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/debug/dwarf/dwarf_test.h
index c3a3ca9425..41bfe79c21 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/debug/dwarf/dwarf_test.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_DWARF_TEST_H_
-#define ART_COMPILER_DWARF_DWARF_TEST_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
+#define ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
#include <cstring>
#include <dirent.h>
@@ -169,4 +169,4 @@ class DwarfTest : public CommonRuntimeTest {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_DWARF_TEST_H_
+#endif // ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
diff --git a/compiler/dwarf/expression.h b/compiler/debug/dwarf/expression.h
index 1503d03d4f..fafc0462d6 100644
--- a/compiler/dwarf/expression.h
+++ b/compiler/debug/dwarf/expression.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_EXPRESSION_H_
-#define ART_COMPILER_DWARF_EXPRESSION_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_EXPRESSION_H_
+#define ART_COMPILER_DEBUG_DWARF_EXPRESSION_H_
#include <cstddef>
#include <cstdint>
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/writer.h"
namespace art {
namespace dwarf {
@@ -118,4 +118,4 @@ class Expression : private Writer<> {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_EXPRESSION_H_
+#endif // ART_COMPILER_DEBUG_DWARF_EXPRESSION_H_
diff --git a/compiler/dwarf/headers.h b/compiler/debug/dwarf/headers.h
index 137c5668f2..146d9fddf5 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/debug/dwarf/headers.h
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_HEADERS_H_
-#define ART_COMPILER_DWARF_HEADERS_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_HEADERS_H_
+#define ART_COMPILER_DEBUG_DWARF_HEADERS_H_
#include <cstdint>
-#include "dwarf/debug_frame_opcode_writer.h"
-#include "dwarf/debug_info_entry_writer.h"
-#include "dwarf/debug_line_opcode_writer.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/register.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/dwarf/debug_line_opcode_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/register.h"
+#include "debug/dwarf/writer.h"
#include "utils/array_ref.h"
namespace art {
@@ -204,4 +204,4 @@ void WriteDebugLineTable(const std::vector<std::string>& include_directories,
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_HEADERS_H_
+#endif // ART_COMPILER_DEBUG_DWARF_HEADERS_H_
diff --git a/compiler/dwarf/register.h b/compiler/debug/dwarf/register.h
index aa3070a9cd..24bacac292 100644
--- a/compiler/dwarf/register.h
+++ b/compiler/debug/dwarf/register.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_REGISTER_H_
-#define ART_COMPILER_DWARF_REGISTER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_REGISTER_H_
+#define ART_COMPILER_DEBUG_DWARF_REGISTER_H_
namespace art {
namespace dwarf {
@@ -59,4 +59,4 @@ class Reg {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_REGISTER_H_
+#endif // ART_COMPILER_DEBUG_DWARF_REGISTER_H_
diff --git a/compiler/dwarf/writer.h b/compiler/debug/dwarf/writer.h
index 74acf07abe..95912ad6c9 100644
--- a/compiler/dwarf/writer.h
+++ b/compiler/debug/dwarf/writer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_WRITER_H_
-#define ART_COMPILER_DWARF_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_WRITER_H_
#include <type_traits>
#include <vector>
@@ -179,4 +179,4 @@ class Writer {
} // namespace dwarf
} // namespace art
-#endif // ART_COMPILER_DWARF_WRITER_H_
+#endif // ART_COMPILER_DEBUG_DWARF_WRITER_H_
diff --git a/compiler/dwarf/method_debug_info.h b/compiler/debug/elf_compilation_unit.h
index e8ba9148e8..f725f45e15 100644
--- a/compiler/dwarf/method_debug_info.h
+++ b/compiler/debug/elf_compilation_unit.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,28 +14,25 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_
-#define ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_
+#ifndef ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_
+#define ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_
-#include "dex_file.h"
+#include <vector>
+
+#include "debug/method_debug_info.h"
namespace art {
-class CompiledMethod;
-namespace dwarf {
-
-struct MethodDebugInfo {
- const DexFile* dex_file_;
- size_t class_def_index_;
- uint32_t dex_method_index_;
- uint32_t access_flags_;
- const DexFile::CodeItem* code_item_;
- bool deduped_;
- uintptr_t low_pc_;
- uintptr_t high_pc_;
- CompiledMethod* compiled_method_;
+namespace debug {
+
+struct ElfCompilationUnit {
+ std::vector<const MethodDebugInfo*> methods;
+ size_t debug_line_offset = 0;
+ uintptr_t low_pc = std::numeric_limits<uintptr_t>::max();
+ uintptr_t high_pc = 0;
};
-} // namespace dwarf
+} // namespace debug
} // namespace art
-#endif // ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_
+#endif // ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_
+
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
new file mode 100644
index 0000000000..f6d9b169c4
--- /dev/null
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -0,0 +1,290 @@
+/*
+ * 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_DEBUG_FRAME_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_
+
+#include <vector>
+
+#include "arch/instruction_set.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/headers.h"
+#include "debug/method_debug_info.h"
+#include "elf_builder.h"
+
+namespace art {
+namespace debug {
+
+static void WriteCIE(InstructionSet isa,
+ dwarf::CFIFormat format,
+ std::vector<uint8_t>* buffer) {
+ using Reg = dwarf::Reg;
+ // Scratch registers should be marked as undefined. This tells the
+ // debugger that its value in the previous frame is not recoverable.
+ bool is64bit = Is64BitInstructionSet(isa);
+ switch (isa) {
+ case kArm:
+ case kThumb2: {
+ dwarf::DebugFrameOpCodeWriter<> opcodes;
+ opcodes.DefCFA(Reg::ArmCore(13), 0); // R13(SP).
+ // core registers.
+ for (int reg = 0; reg < 13; reg++) {
+ if (reg < 4 || reg == 12) {
+ opcodes.Undefined(Reg::ArmCore(reg));
+ } else {
+ opcodes.SameValue(Reg::ArmCore(reg));
+ }
+ }
+ // fp registers.
+ for (int reg = 0; reg < 32; reg++) {
+ if (reg < 16) {
+ opcodes.Undefined(Reg::ArmFp(reg));
+ } else {
+ opcodes.SameValue(Reg::ArmFp(reg));
+ }
+ }
+ auto return_reg = Reg::ArmCore(14); // R14(LR).
+ WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+ return;
+ }
+ case kArm64: {
+ dwarf::DebugFrameOpCodeWriter<> opcodes;
+ opcodes.DefCFA(Reg::Arm64Core(31), 0); // R31(SP).
+ // core registers.
+ for (int reg = 0; reg < 30; reg++) {
+ if (reg < 8 || reg == 16 || reg == 17) {
+ opcodes.Undefined(Reg::Arm64Core(reg));
+ } else {
+ opcodes.SameValue(Reg::Arm64Core(reg));
+ }
+ }
+ // fp registers.
+ for (int reg = 0; reg < 32; reg++) {
+ if (reg < 8 || reg >= 16) {
+ opcodes.Undefined(Reg::Arm64Fp(reg));
+ } else {
+ opcodes.SameValue(Reg::Arm64Fp(reg));
+ }
+ }
+ auto return_reg = Reg::Arm64Core(30); // R30(LR).
+ WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+ return;
+ }
+ case kMips:
+ case kMips64: {
+ dwarf::DebugFrameOpCodeWriter<> opcodes;
+ opcodes.DefCFA(Reg::MipsCore(29), 0); // R29(SP).
+ // core registers.
+ for (int reg = 1; reg < 26; reg++) {
+ if (reg < 16 || reg == 24 || reg == 25) { // AT, V*, A*, T*.
+ opcodes.Undefined(Reg::MipsCore(reg));
+ } else {
+ opcodes.SameValue(Reg::MipsCore(reg));
+ }
+ }
+ // fp registers.
+ for (int reg = 0; reg < 32; reg++) {
+ if (reg < 24) {
+ opcodes.Undefined(Reg::Mips64Fp(reg));
+ } else {
+ opcodes.SameValue(Reg::Mips64Fp(reg));
+ }
+ }
+ auto return_reg = Reg::MipsCore(31); // R31(RA).
+ WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+ return;
+ }
+ case kX86: {
+ // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296
+ constexpr bool generate_opcodes_for_x86_fp = false;
+ dwarf::DebugFrameOpCodeWriter<> opcodes;
+ opcodes.DefCFA(Reg::X86Core(4), 4); // R4(ESP).
+ opcodes.Offset(Reg::X86Core(8), -4); // R8(EIP).
+ // core registers.
+ for (int reg = 0; reg < 8; reg++) {
+ if (reg <= 3) {
+ opcodes.Undefined(Reg::X86Core(reg));
+ } else if (reg == 4) {
+ // Stack pointer.
+ } else {
+ opcodes.SameValue(Reg::X86Core(reg));
+ }
+ }
+ // fp registers.
+ if (generate_opcodes_for_x86_fp) {
+ for (int reg = 0; reg < 8; reg++) {
+ opcodes.Undefined(Reg::X86Fp(reg));
+ }
+ }
+ auto return_reg = Reg::X86Core(8); // R8(EIP).
+ WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+ return;
+ }
+ case kX86_64: {
+ dwarf::DebugFrameOpCodeWriter<> opcodes;
+ opcodes.DefCFA(Reg::X86_64Core(4), 8); // R4(RSP).
+ opcodes.Offset(Reg::X86_64Core(16), -8); // R16(RIP).
+ // core registers.
+ for (int reg = 0; reg < 16; reg++) {
+ if (reg == 4) {
+ // Stack pointer.
+ } else if (reg < 12 && reg != 3 && reg != 5) { // except EBX and EBP.
+ opcodes.Undefined(Reg::X86_64Core(reg));
+ } else {
+ opcodes.SameValue(Reg::X86_64Core(reg));
+ }
+ }
+ // fp registers.
+ for (int reg = 0; reg < 16; reg++) {
+ if (reg < 12) {
+ opcodes.Undefined(Reg::X86_64Fp(reg));
+ } else {
+ opcodes.SameValue(Reg::X86_64Fp(reg));
+ }
+ }
+ auto return_reg = Reg::X86_64Core(16); // R16(RIP).
+ WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+ return;
+ }
+ case kNone:
+ break;
+ }
+ LOG(FATAL) << "Cannot write CIE frame for ISA " << isa;
+ UNREACHABLE();
+}
+
+template<typename ElfTypes>
+void WriteCFISection(ElfBuilder<ElfTypes>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos,
+ dwarf::CFIFormat format,
+ bool write_oat_patches) {
+ CHECK(format == dwarf::DW_DEBUG_FRAME_FORMAT || format == dwarf::DW_EH_FRAME_FORMAT);
+ typedef typename ElfTypes::Addr Elf_Addr;
+
+ if (method_infos.empty()) {
+ return;
+ }
+
+ std::vector<uint32_t> binary_search_table;
+ std::vector<uintptr_t> patch_locations;
+ if (format == dwarf::DW_EH_FRAME_FORMAT) {
+ binary_search_table.reserve(2 * method_infos.size());
+ } else {
+ patch_locations.reserve(method_infos.size());
+ }
+
+ // The methods can be written in any order.
+ // Let's therefore sort them in the lexicographical order of the opcodes.
+ // This has no effect on its own. However, if the final .debug_frame section is
+ // compressed it reduces the size since similar opcodes sequences are grouped.
+ std::vector<const MethodDebugInfo*> sorted_method_infos;
+ sorted_method_infos.reserve(method_infos.size());
+ for (size_t i = 0; i < method_infos.size(); i++) {
+ sorted_method_infos.push_back(&method_infos[i]);
+ }
+ std::sort(
+ sorted_method_infos.begin(),
+ sorted_method_infos.end(),
+ [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) {
+ ArrayRef<const uint8_t> l = lhs->compiled_method->GetCFIInfo();
+ ArrayRef<const uint8_t> r = rhs->compiled_method->GetCFIInfo();
+ return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
+ });
+
+ // Write .eh_frame/.debug_frame section.
+ auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT
+ ? builder->GetDebugFrame()
+ : builder->GetEhFrame());
+ {
+ cfi_section->Start();
+ const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
+ const Elf_Addr text_address = builder->GetText()->Exists()
+ ? builder->GetText()->GetAddress()
+ : 0;
+ const Elf_Addr cfi_address = cfi_section->GetAddress();
+ const Elf_Addr cie_address = cfi_address;
+ Elf_Addr buffer_address = cfi_address;
+ std::vector<uint8_t> buffer; // Small temporary buffer.
+ WriteCIE(builder->GetIsa(), format, &buffer);
+ cfi_section->WriteFully(buffer.data(), buffer.size());
+ buffer_address += buffer.size();
+ buffer.clear();
+ for (const MethodDebugInfo* mi : sorted_method_infos) {
+ if (!mi->deduped) { // Only one FDE per unique address.
+ ArrayRef<const uint8_t> opcodes = mi->compiled_method->GetCFIInfo();
+ if (!opcodes.empty()) {
+ const Elf_Addr code_address = text_address + mi->low_pc;
+ if (format == dwarf::DW_EH_FRAME_FORMAT) {
+ binary_search_table.push_back(
+ dchecked_integral_cast<uint32_t>(code_address));
+ binary_search_table.push_back(
+ dchecked_integral_cast<uint32_t>(buffer_address));
+ }
+ WriteFDE(is64bit, cfi_address, cie_address,
+ code_address, mi->high_pc - mi->low_pc,
+ opcodes, format, buffer_address, &buffer,
+ &patch_locations);
+ cfi_section->WriteFully(buffer.data(), buffer.size());
+ buffer_address += buffer.size();
+ buffer.clear();
+ }
+ }
+ }
+ cfi_section->End();
+ }
+
+ if (format == dwarf::DW_EH_FRAME_FORMAT) {
+ auto* header_section = builder->GetEhFrameHdr();
+ header_section->Start();
+ uint32_t header_address = dchecked_integral_cast<int32_t>(header_section->GetAddress());
+ // Write .eh_frame_hdr section.
+ std::vector<uint8_t> buffer;
+ dwarf::Writer<> header(&buffer);
+ header.PushUint8(1); // Version.
+ // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
+ // so we have to use pcrel which means relative to the pointer's location.
+ header.PushUint8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4);
+ // Encoding of binary search table size.
+ header.PushUint8(dwarf::DW_EH_PE_udata4);
+ // Encoding of binary search table addresses - libunwind supports only this
+ // specific combination, which means relative to the start of .eh_frame_hdr.
+ header.PushUint8(dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4);
+ // .eh_frame pointer
+ header.PushInt32(cfi_section->GetAddress() - (header_address + 4u));
+ // Binary search table size (number of entries).
+ header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2));
+ header_section->WriteFully(buffer.data(), buffer.size());
+ // Binary search table.
+ for (size_t i = 0; i < binary_search_table.size(); i++) {
+ // Make addresses section-relative since we know the header address now.
+ binary_search_table[i] -= header_address;
+ }
+ header_section->WriteFully(binary_search_table.data(), binary_search_table.size());
+ header_section->End();
+ } else {
+ if (write_oat_patches) {
+ builder->WritePatches(".debug_frame.oat_patches",
+ ArrayRef<const uintptr_t>(patch_locations));
+ }
+ }
+}
+
+} // namespace debug
+} // namespace art
+
+#endif // ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
new file mode 100644
index 0000000000..eed032f88d
--- /dev/null
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -0,0 +1,649 @@
+/*
+ * 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_DEBUG_INFO_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_
+
+#include <map>
+#include <unordered_set>
+#include <vector>
+
+#include "debug/dwarf/debug_abbrev_writer.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/elf_compilation_unit.h"
+#include "debug/elf_debug_loc_writer.h"
+#include "debug/method_debug_info.h"
+#include "dex_file-inl.h"
+#include "dex_file.h"
+#include "elf_builder.h"
+#include "linear_alloc.h"
+#include "mirror/array.h"
+#include "mirror/class-inl.h"
+#include "mirror/class.h"
+
+namespace art {
+namespace debug {
+
+typedef std::vector<DexFile::LocalInfo> LocalInfos;
+
+static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
+ static_cast<LocalInfos*>(ctx)->push_back(entry);
+}
+
+static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
+ std::vector<const char*> names;
+ if (mi->code_item != nullptr) {
+ const uint8_t* stream = mi->dex_file->GetDebugInfoStream(mi->code_item);
+ if (stream != nullptr) {
+ DecodeUnsignedLeb128(&stream); // line.
+ uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+ for (uint32_t i = 0; i < parameters_size; ++i) {
+ uint32_t id = DecodeUnsignedLeb128P1(&stream);
+ names.push_back(mi->dex_file->StringDataByIdx(id));
+ }
+ }
+ }
+ return names;
+}
+
+// Helper class to write .debug_info and its supporting sections.
+template<typename ElfTypes>
+class ElfDebugInfoWriter {
+ using Elf_Addr = typename ElfTypes::Addr;
+
+ public:
+ explicit ElfDebugInfoWriter(ElfBuilder<ElfTypes>* builder)
+ : builder_(builder),
+ debug_abbrev_(&debug_abbrev_buffer_) {
+ }
+
+ void Start() {
+ builder_->GetDebugInfo()->Start();
+ }
+
+ void End(bool write_oat_patches) {
+ builder_->GetDebugInfo()->End();
+ if (write_oat_patches) {
+ builder_->WritePatches(".debug_info.oat_patches",
+ ArrayRef<const uintptr_t>(debug_info_patches_));
+ }
+ builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_);
+ if (!debug_loc_.empty()) {
+ builder_->WriteSection(".debug_loc", &debug_loc_);
+ }
+ if (!debug_ranges_.empty()) {
+ builder_->WriteSection(".debug_ranges", &debug_ranges_);
+ }
+ }
+
+ private:
+ ElfBuilder<ElfTypes>* builder_;
+ std::vector<uintptr_t> debug_info_patches_;
+ std::vector<uint8_t> debug_abbrev_buffer_;
+ dwarf::DebugAbbrevWriter<> debug_abbrev_;
+ std::vector<uint8_t> debug_loc_;
+ std::vector<uint8_t> debug_ranges_;
+
+ std::unordered_set<const char*> defined_dex_classes_; // For CHECKs only.
+
+ template<typename ElfTypes2>
+ friend class ElfCompilationUnitWriter;
+};
+
+// Helper class to write one compilation unit.
+// It holds helper methods and temporary state.
+template<typename ElfTypes>
+class ElfCompilationUnitWriter {
+ using Elf_Addr = typename ElfTypes::Addr;
+
+ public:
+ explicit ElfCompilationUnitWriter(ElfDebugInfoWriter<ElfTypes>* owner)
+ : owner_(owner),
+ info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &owner->debug_abbrev_) {
+ }
+
+ void Write(const ElfCompilationUnit& compilation_unit) {
+ CHECK(!compilation_unit.methods.empty());
+ const Elf_Addr text_address = owner_->builder_->GetText()->Exists()
+ ? owner_->builder_->GetText()->GetAddress()
+ : 0;
+ const uintptr_t cu_size = compilation_unit.high_pc - compilation_unit.low_pc;
+ using namespace dwarf; // NOLINT. For easy access to DWARF constants.
+
+ info_.StartTag(DW_TAG_compile_unit);
+ info_.WriteString(DW_AT_producer, "Android dex2oat");
+ info_.WriteData1(DW_AT_language, DW_LANG_Java);
+ info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT");
+ info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc);
+ info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
+ info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset);
+
+ const char* last_dex_class_desc = nullptr;
+ for (auto mi : compilation_unit.methods) {
+ const DexFile* dex = mi->dex_file;
+ const DexFile::CodeItem* dex_code = mi->code_item;
+ const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
+ const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
+ const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
+ const char* dex_class_desc = dex->GetMethodDeclaringClassDescriptor(dex_method);
+ const bool is_static = (mi->access_flags & kAccStatic) != 0;
+
+ // Enclose the method in correct class definition.
+ if (last_dex_class_desc != dex_class_desc) {
+ if (last_dex_class_desc != nullptr) {
+ EndClassTag();
+ }
+ // Write reference tag for the class we are about to declare.
+ size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type);
+ type_cache_.emplace(std::string(dex_class_desc), reference_tag_offset);
+ size_t type_attrib_offset = info_.size();
+ info_.WriteRef4(DW_AT_type, 0);
+ info_.EndTag();
+ // Declare the class that owns this method.
+ size_t class_offset = StartClassTag(dex_class_desc);
+ info_.UpdateUint32(type_attrib_offset, class_offset);
+ info_.WriteFlagPresent(DW_AT_declaration);
+ // Check that each class is defined only once.
+ bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second;
+ CHECK(unique) << "Redefinition of " << dex_class_desc;
+ last_dex_class_desc = dex_class_desc;
+ }
+
+ int start_depth = info_.Depth();
+ info_.StartTag(DW_TAG_subprogram);
+ WriteName(dex->GetMethodName(dex_method));
+ info_.WriteAddr(DW_AT_low_pc, text_address + mi->low_pc);
+ info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(mi->high_pc-mi->low_pc));
+ std::vector<uint8_t> expr_buffer;
+ Expression expr(&expr_buffer);
+ expr.WriteOpCallFrameCfa();
+ info_.WriteExprLoc(DW_AT_frame_base, expr);
+ WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto));
+
+ // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not
+ // guarantee order or uniqueness so it is safer to iterate over them manually.
+ // DecodeDebugLocalInfo might not also be available if there is no debug info.
+ std::vector<const char*> param_names = GetParamNames(mi);
+ uint32_t arg_reg = 0;
+ if (!is_static) {
+ info_.StartTag(DW_TAG_formal_parameter);
+ WriteName("this");
+ info_.WriteFlagPresent(DW_AT_artificial);
+ WriteLazyType(dex_class_desc);
+ if (dex_code != nullptr) {
+ // Write the stack location of the parameter.
+ const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+ const bool is64bitValue = false;
+ WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc);
+ }
+ arg_reg++;
+ info_.EndTag();
+ }
+ if (dex_params != nullptr) {
+ for (uint32_t i = 0; i < dex_params->Size(); ++i) {
+ info_.StartTag(DW_TAG_formal_parameter);
+ // Parameter names may not be always available.
+ if (i < param_names.size()) {
+ WriteName(param_names[i]);
+ }
+ // Write the type.
+ const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
+ WriteLazyType(type_desc);
+ const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
+ if (dex_code != nullptr) {
+ // Write the stack location of the parameter.
+ const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+ WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc);
+ }
+ arg_reg += is64bitValue ? 2 : 1;
+ info_.EndTag();
+ }
+ if (dex_code != nullptr) {
+ DCHECK_EQ(arg_reg, dex_code->ins_size_);
+ }
+ }
+
+ // Write local variables.
+ LocalInfos local_infos;
+ if (dex->DecodeDebugLocalInfo(dex_code,
+ is_static,
+ mi->dex_method_index,
+ LocalInfoCallback,
+ &local_infos)) {
+ for (const DexFile::LocalInfo& var : local_infos) {
+ if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
+ info_.StartTag(DW_TAG_variable);
+ WriteName(var.name_);
+ WriteLazyType(var.descriptor_);
+ bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J';
+ WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc,
+ var.start_address_, var.end_address_);
+ info_.EndTag();
+ }
+ }
+ }
+
+ info_.EndTag();
+ CHECK_EQ(info_.Depth(), start_depth); // Balanced start/end.
+ }
+ if (last_dex_class_desc != nullptr) {
+ EndClassTag();
+ }
+ FinishLazyTypes();
+ CloseNamespacesAboveDepth(0);
+ info_.EndTag(); // DW_TAG_compile_unit
+ CHECK_EQ(info_.Depth(), 0);
+ std::vector<uint8_t> buffer;
+ buffer.reserve(info_.data()->size() + KB);
+ const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+ // All compilation units share single table which is at the start of .debug_abbrev.
+ const size_t debug_abbrev_offset = 0;
+ WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
+ owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
+ }
+
+ void Write(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) {
+ using namespace dwarf; // NOLINT. For easy access to DWARF constants.
+
+ info_.StartTag(DW_TAG_compile_unit);
+ info_.WriteString(DW_AT_producer, "Android dex2oat");
+ info_.WriteData1(DW_AT_language, DW_LANG_Java);
+
+ // Base class references to be patched at the end.
+ std::map<size_t, mirror::Class*> base_class_references;
+
+ // Already written declarations or definitions.
+ std::map<mirror::Class*, size_t> class_declarations;
+
+ std::vector<uint8_t> expr_buffer;
+ for (mirror::Class* type : types) {
+ if (type->IsPrimitive()) {
+ // For primitive types the definition and the declaration is the same.
+ if (type->GetPrimitiveType() != Primitive::kPrimVoid) {
+ WriteTypeDeclaration(type->GetDescriptor(nullptr));
+ }
+ } else if (type->IsArrayClass()) {
+ mirror::Class* element_type = type->GetComponentType();
+ uint32_t component_size = type->GetComponentSize();
+ uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value();
+ uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
+
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
+ info_.StartTag(DW_TAG_array_type);
+ std::string descriptor_string;
+ WriteLazyType(element_type->GetDescriptor(&descriptor_string));
+ WriteLinkageName(type);
+ info_.WriteUdata(DW_AT_data_member_location, data_offset);
+ info_.StartTag(DW_TAG_subrange_type);
+ Expression count_expr(&expr_buffer);
+ count_expr.WriteOpPushObjectAddress();
+ count_expr.WriteOpPlusUconst(length_offset);
+ count_expr.WriteOpDerefSize(4); // Array length is always 32-bit wide.
+ info_.WriteExprLoc(DW_AT_count, count_expr);
+ info_.EndTag(); // DW_TAG_subrange_type.
+ info_.EndTag(); // DW_TAG_array_type.
+ } else if (type->IsInterface()) {
+ // Skip. Variables cannot have an interface as a dynamic type.
+ // We do not expose the interface information to the debugger in any way.
+ } else {
+ std::string descriptor_string;
+ const char* desc = type->GetDescriptor(&descriptor_string);
+ size_t class_offset = StartClassTag(desc);
+ class_declarations.emplace(type, class_offset);
+
+ if (!type->IsVariableSize()) {
+ info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize());
+ }
+
+ WriteLinkageName(type);
+
+ if (type->IsObjectClass()) {
+ // Generate artificial member which is used to get the dynamic type of variable.
+ // The run-time value of this field will correspond to linkage name of some type.
+ // We need to do it only once in j.l.Object since all other types inherit it.
+ info_.StartTag(DW_TAG_member);
+ WriteName(".dynamic_type");
+ WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I");
+ info_.WriteFlagPresent(DW_AT_artificial);
+ // Create DWARF expression to get the value of the methods_ field.
+ Expression expr(&expr_buffer);
+ // The address of the object has been implicitly pushed on the stack.
+ // Dereference the klass_ field of Object (32-bit; possibly poisoned).
+ DCHECK_EQ(type->ClassOffset().Uint32Value(), 0u);
+ DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Class>), 4u);
+ expr.WriteOpDerefSize(4);
+ if (kPoisonHeapReferences) {
+ expr.WriteOpNeg();
+ // DWARF stack is pointer sized. Ensure that the high bits are clear.
+ expr.WriteOpConstu(0xFFFFFFFF);
+ expr.WriteOpAnd();
+ }
+ // Add offset to the methods_ field.
+ expr.WriteOpPlusUconst(mirror::Class::MethodsOffset().Uint32Value());
+ // Top of stack holds the location of the field now.
+ info_.WriteExprLoc(DW_AT_data_member_location, expr);
+ info_.EndTag(); // DW_TAG_member.
+ }
+
+ // Base class.
+ mirror::Class* base_class = type->GetSuperClass();
+ if (base_class != nullptr) {
+ info_.StartTag(DW_TAG_inheritance);
+ base_class_references.emplace(info_.size(), base_class);
+ info_.WriteRef4(DW_AT_type, 0);
+ info_.WriteUdata(DW_AT_data_member_location, 0);
+ info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
+ info_.EndTag(); // DW_TAG_inheritance.
+ }
+
+ // Member variables.
+ for (uint32_t i = 0, count = type->NumInstanceFields(); i < count; ++i) {
+ ArtField* field = type->GetInstanceField(i);
+ info_.StartTag(DW_TAG_member);
+ WriteName(field->GetName());
+ WriteLazyType(field->GetTypeDescriptor());
+ info_.WriteUdata(DW_AT_data_member_location, field->GetOffset().Uint32Value());
+ uint32_t access_flags = field->GetAccessFlags();
+ if (access_flags & kAccPublic) {
+ info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
+ } else if (access_flags & kAccProtected) {
+ info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_protected);
+ } else if (access_flags & kAccPrivate) {
+ info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
+ }
+ info_.EndTag(); // DW_TAG_member.
+ }
+
+ if (type->IsStringClass()) {
+ // Emit debug info about an artifical class member for java.lang.String which represents
+ // the first element of the data stored in a string instance. Consumers of the debug
+ // info will be able to read the content of java.lang.String based on the count (real
+ // field) and based on the location of this data member.
+ info_.StartTag(DW_TAG_member);
+ WriteName("value");
+ // We don't support fields with C like array types so we just say its type is java char.
+ WriteLazyType("C"); // char.
+ info_.WriteUdata(DW_AT_data_member_location,
+ mirror::String::ValueOffset().Uint32Value());
+ info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
+ info_.EndTag(); // DW_TAG_member.
+ }
+
+ EndClassTag();
+ }
+ }
+
+ // Write base class declarations.
+ for (const auto& base_class_reference : base_class_references) {
+ size_t reference_offset = base_class_reference.first;
+ mirror::Class* base_class = base_class_reference.second;
+ const auto& it = class_declarations.find(base_class);
+ if (it != class_declarations.end()) {
+ info_.UpdateUint32(reference_offset, it->second);
+ } else {
+ // Declare base class. We can not use the standard WriteLazyType
+ // since we want to avoid the DW_TAG_reference_tag wrapping.
+ std::string tmp_storage;
+ const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
+ size_t base_class_declaration_offset = StartClassTag(base_class_desc);
+ info_.WriteFlagPresent(DW_AT_declaration);
+ WriteLinkageName(base_class);
+ EndClassTag();
+ class_declarations.emplace(base_class, base_class_declaration_offset);
+ info_.UpdateUint32(reference_offset, base_class_declaration_offset);
+ }
+ }
+
+ FinishLazyTypes();
+ CloseNamespacesAboveDepth(0);
+ info_.EndTag(); // DW_TAG_compile_unit.
+ CHECK_EQ(info_.Depth(), 0);
+ std::vector<uint8_t> buffer;
+ buffer.reserve(info_.data()->size() + KB);
+ const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+ // All compilation units share single table which is at the start of .debug_abbrev.
+ const size_t debug_abbrev_offset = 0;
+ WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
+ owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
+ }
+
+ // Write table into .debug_loc which describes location of dex register.
+ // The dex register might be valid only at some points and it might
+ // move between machine registers and stack.
+ void WriteRegLocation(const MethodDebugInfo* method_info,
+ uint16_t vreg,
+ bool is64bitValue,
+ uint32_t compilation_unit_low_pc,
+ uint32_t dex_pc_low = 0,
+ uint32_t dex_pc_high = 0xFFFFFFFF) {
+ WriteDebugLocEntry(method_info,
+ vreg,
+ is64bitValue,
+ compilation_unit_low_pc,
+ dex_pc_low,
+ dex_pc_high,
+ owner_->builder_->GetIsa(),
+ &info_,
+ &owner_->debug_loc_,
+ &owner_->debug_ranges_);
+ }
+
+ // Linkage name uniquely identifies type.
+ // It is used to determine the dynamic type of objects.
+ // We use the methods_ field of class since it is unique and it is not moved by the GC.
+ void WriteLinkageName(mirror::Class* type) SHARED_REQUIRES(Locks::mutator_lock_) {
+ auto* methods_ptr = type->GetMethodsPtr();
+ if (methods_ptr == nullptr) {
+ // Some types might have no methods. Allocate empty array instead.
+ LinearAlloc* allocator = Runtime::Current()->GetLinearAlloc();
+ void* storage = allocator->Alloc(Thread::Current(), sizeof(LengthPrefixedArray<ArtMethod>));
+ methods_ptr = new (storage) LengthPrefixedArray<ArtMethod>(0);
+ type->SetMethodsPtr(methods_ptr, 0, 0);
+ DCHECK(type->GetMethodsPtr() != nullptr);
+ }
+ char name[32];
+ snprintf(name, sizeof(name), "0x%" PRIXPTR, reinterpret_cast<uintptr_t>(methods_ptr));
+ info_.WriteString(dwarf::DW_AT_linkage_name, name);
+ }
+
+ // Some types are difficult to define as we go since they need
+ // to be enclosed in the right set of namespaces. Therefore we
+ // just define all types lazily at the end of compilation unit.
+ void WriteLazyType(const char* type_descriptor) {
+ if (type_descriptor != nullptr && type_descriptor[0] != 'V') {
+ lazy_types_.emplace(std::string(type_descriptor), info_.size());
+ info_.WriteRef4(dwarf::DW_AT_type, 0);
+ }
+ }
+
+ void FinishLazyTypes() {
+ for (const auto& lazy_type : lazy_types_) {
+ info_.UpdateUint32(lazy_type.second, WriteTypeDeclaration(lazy_type.first));
+ }
+ lazy_types_.clear();
+ }
+
+ private:
+ void WriteName(const char* name) {
+ if (name != nullptr) {
+ info_.WriteString(dwarf::DW_AT_name, name);
+ }
+ }
+
+ // Convert dex type descriptor to DWARF.
+ // Returns offset in the compilation unit.
+ size_t WriteTypeDeclaration(const std::string& desc) {
+ using namespace dwarf; // NOLINT. For easy access to DWARF constants.
+
+ DCHECK(!desc.empty());
+ const auto& it = type_cache_.find(desc);
+ if (it != type_cache_.end()) {
+ return it->second;
+ }
+
+ size_t offset;
+ if (desc[0] == 'L') {
+ // Class type. For example: Lpackage/name;
+ size_t class_offset = StartClassTag(desc.c_str());
+ info_.WriteFlagPresent(DW_AT_declaration);
+ EndClassTag();
+ // Reference to the class type.
+ offset = info_.StartTag(DW_TAG_reference_type);
+ info_.WriteRef(DW_AT_type, class_offset);
+ info_.EndTag();
+ } else if (desc[0] == '[') {
+ // Array type.
+ size_t element_type = WriteTypeDeclaration(desc.substr(1));
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
+ size_t array_type = info_.StartTag(DW_TAG_array_type);
+ info_.WriteFlagPresent(DW_AT_declaration);
+ info_.WriteRef(DW_AT_type, element_type);
+ info_.EndTag();
+ offset = info_.StartTag(DW_TAG_reference_type);
+ info_.WriteRef4(DW_AT_type, array_type);
+ info_.EndTag();
+ } else {
+ // Primitive types.
+ DCHECK_EQ(desc.size(), 1u);
+
+ const char* name;
+ uint32_t encoding;
+ uint32_t byte_size;
+ switch (desc[0]) {
+ case 'B':
+ name = "byte";
+ encoding = DW_ATE_signed;
+ byte_size = 1;
+ break;
+ case 'C':
+ name = "char";
+ encoding = DW_ATE_UTF;
+ byte_size = 2;
+ break;
+ case 'D':
+ name = "double";
+ encoding = DW_ATE_float;
+ byte_size = 8;
+ break;
+ case 'F':
+ name = "float";
+ encoding = DW_ATE_float;
+ byte_size = 4;
+ break;
+ case 'I':
+ name = "int";
+ encoding = DW_ATE_signed;
+ byte_size = 4;
+ break;
+ case 'J':
+ name = "long";
+ encoding = DW_ATE_signed;
+ byte_size = 8;
+ break;
+ case 'S':
+ name = "short";
+ encoding = DW_ATE_signed;
+ byte_size = 2;
+ break;
+ case 'Z':
+ name = "boolean";
+ encoding = DW_ATE_boolean;
+ byte_size = 1;
+ break;
+ case 'V':
+ LOG(FATAL) << "Void type should not be encoded";
+ UNREACHABLE();
+ default:
+ LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\"";
+ UNREACHABLE();
+ }
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
+ offset = info_.StartTag(DW_TAG_base_type);
+ WriteName(name);
+ info_.WriteData1(DW_AT_encoding, encoding);
+ info_.WriteData1(DW_AT_byte_size, byte_size);
+ info_.EndTag();
+ }
+
+ type_cache_.emplace(desc, offset);
+ return offset;
+ }
+
+ // Start DW_TAG_class_type tag nested in DW_TAG_namespace tags.
+ // Returns offset of the class tag in the compilation unit.
+ size_t StartClassTag(const char* desc) {
+ std::string name = SetNamespaceForClass(desc);
+ size_t offset = info_.StartTag(dwarf::DW_TAG_class_type);
+ WriteName(name.c_str());
+ return offset;
+ }
+
+ void EndClassTag() {
+ info_.EndTag();
+ }
+
+ // Set the current namespace nesting to one required by the given class.
+ // Returns the class name with namespaces, 'L', and ';' stripped.
+ std::string SetNamespaceForClass(const char* desc) {
+ DCHECK(desc != nullptr && desc[0] == 'L');
+ desc++; // Skip the initial 'L'.
+ size_t depth = 0;
+ for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) {
+ // Check whether the name at this depth is already what we need.
+ if (depth < current_namespace_.size()) {
+ const std::string& name = current_namespace_[depth];
+ if (name.compare(0, name.size(), desc, end - desc) == 0) {
+ continue;
+ }
+ }
+ // Otherwise we need to open a new namespace tag at this depth.
+ CloseNamespacesAboveDepth(depth);
+ info_.StartTag(dwarf::DW_TAG_namespace);
+ std::string name(desc, end - desc);
+ WriteName(name.c_str());
+ current_namespace_.push_back(std::move(name));
+ }
+ CloseNamespacesAboveDepth(depth);
+ return std::string(desc, strchr(desc, ';') - desc);
+ }
+
+ // Close namespace tags to reach the given nesting depth.
+ void CloseNamespacesAboveDepth(size_t depth) {
+ DCHECK_LE(depth, current_namespace_.size());
+ while (current_namespace_.size() > depth) {
+ info_.EndTag();
+ current_namespace_.pop_back();
+ }
+ }
+
+ // For access to the ELF sections.
+ ElfDebugInfoWriter<ElfTypes>* owner_;
+ // Temporary buffer to create and store the entries.
+ dwarf::DebugInfoEntryWriter<> info_;
+ // Cache of already translated type descriptors.
+ std::map<std::string, size_t> type_cache_; // type_desc -> definition_offset.
+ // 32-bit references which need to be resolved to a type later.
+ // Given type may be used multiple times. Therefore we need a multimap.
+ std::multimap<std::string, size_t> lazy_types_; // type_desc -> patch_offset.
+ // The current set of open namespace tags which are active and not closed yet.
+ std::vector<std::string> current_namespace_;
+};
+
+} // namespace debug
+} // namespace art
+
+#endif // ART_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
new file mode 100644
index 0000000000..ac0f4ca21d
--- /dev/null
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -0,0 +1,247 @@
+/*
+ * 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_DEBUG_LINE_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_
+
+#include <vector>
+
+#include "compiled_method.h"
+#include "debug/dwarf/debug_line_opcode_writer.h"
+#include "debug/dwarf/headers.h"
+#include "debug/elf_compilation_unit.h"
+#include "dex_file-inl.h"
+#include "dex_file.h"
+#include "elf_builder.h"
+#include "stack_map.h"
+
+namespace art {
+namespace debug {
+
+typedef std::vector<DexFile::PositionInfo> PositionInfos;
+
+static bool PositionInfoCallback(void* ctx, const DexFile::PositionInfo& entry) {
+ static_cast<PositionInfos*>(ctx)->push_back(entry);
+ return false;
+}
+
+template<typename ElfTypes>
+class ElfDebugLineWriter {
+ using Elf_Addr = typename ElfTypes::Addr;
+
+ public:
+ explicit ElfDebugLineWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) {
+ }
+
+ void Start() {
+ builder_->GetDebugLine()->Start();
+ }
+
+ // Write line table for given set of methods.
+ // Returns the number of bytes written.
+ size_t WriteCompilationUnit(ElfCompilationUnit& compilation_unit) {
+ const bool is64bit = Is64BitInstructionSet(builder_->GetIsa());
+ const Elf_Addr text_address = builder_->GetText()->Exists()
+ ? builder_->GetText()->GetAddress()
+ : 0;
+
+ compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetSize();
+
+ 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;
+ int code_factor_bits_ = 0;
+ int dwarf_isa = -1;
+ switch (builder_->GetIsa()) {
+ case kArm: // arm actually means thumb2.
+ case kThumb2:
+ code_factor_bits_ = 1; // 16-bit instuctions
+ dwarf_isa = 1; // DW_ISA_ARM_thumb.
+ break;
+ case kArm64:
+ case kMips:
+ case kMips64:
+ code_factor_bits_ = 2; // 32-bit instructions
+ break;
+ case kNone:
+ case kX86:
+ case kX86_64:
+ break;
+ }
+ dwarf::DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_);
+ for (const MethodDebugInfo* mi : compilation_unit.methods) {
+ // Ignore function if we have already generated line table for the same address.
+ // It would confuse the debugger and the DWARF specification forbids it.
+ if (mi->deduped) {
+ continue;
+ }
+
+ ArrayRef<const SrcMapElem> src_mapping_table;
+ std::vector<SrcMapElem> src_mapping_table_from_stack_maps;
+ if (mi->IsFromOptimizingCompiler()) {
+ // Use stack maps to create mapping table from pc to dex.
+ const CodeInfo code_info(mi->compiled_method->GetVmapTable().data());
+ const StackMapEncoding encoding = code_info.ExtractEncoding();
+ for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
+ StackMap stack_map = code_info.GetStackMapAt(s, encoding);
+ DCHECK(stack_map.IsValid());
+ // Emit only locations where we have local-variable information.
+ // In particular, skip mappings inside the prologue.
+ if (stack_map.HasDexRegisterMap(encoding)) {
+ const uint32_t pc = stack_map.GetNativePcOffset(encoding);
+ const int32_t dex = stack_map.GetDexPc(encoding);
+ src_mapping_table_from_stack_maps.push_back({pc, dex});
+ }
+ }
+ std::sort(src_mapping_table_from_stack_maps.begin(),
+ src_mapping_table_from_stack_maps.end());
+ src_mapping_table = ArrayRef<const SrcMapElem>(src_mapping_table_from_stack_maps);
+ } else {
+ // Use the mapping table provided by the quick compiler.
+ src_mapping_table = mi->compiled_method->GetSrcMappingTable();
+ }
+
+ if (src_mapping_table.empty()) {
+ continue;
+ }
+
+ Elf_Addr method_address = text_address + mi->low_pc;
+
+ PositionInfos position_infos;
+ const DexFile* dex = mi->dex_file;
+ if (!dex->DecodeDebugPositionInfo(mi->code_item, PositionInfoCallback, &position_infos)) {
+ continue;
+ }
+
+ if (position_infos.empty()) {
+ continue;
+ }
+
+ opcodes.SetAddress(method_address);
+ if (dwarf_isa != -1) {
+ opcodes.SetISA(dwarf_isa);
+ }
+
+ // Get and deduplicate directory and filename.
+ int file_index = 0; // 0 - primary source file of the compilation.
+ auto& dex_class_def = dex->GetClassDef(mi->class_def_index);
+ const char* source_file = dex->GetSourceFile(dex_class_def);
+ if (source_file != nullptr) {
+ std::string file_name(source_file);
+ size_t file_name_slash = file_name.find_last_of('/');
+ std::string class_name(dex->GetClassDescriptor(dex_class_def));
+ size_t class_name_slash = class_name.find_last_of('/');
+ std::string full_path(file_name);
+
+ // Guess directory from package name.
+ int directory_index = 0; // 0 - current directory of the compilation.
+ if (file_name_slash == std::string::npos && // Just filename.
+ class_name.front() == 'L' && // Type descriptor for a class.
+ class_name_slash != std::string::npos) { // Has package name.
+ std::string package_name = class_name.substr(1, class_name_slash - 1);
+ auto it = directories_map.find(package_name);
+ if (it == directories_map.end()) {
+ directory_index = 1 + directories.size();
+ directories_map.emplace(package_name, directory_index);
+ directories.push_back(package_name);
+ } else {
+ directory_index = it->second;
+ }
+ full_path = package_name + "/" + file_name;
+ }
+
+ // Add file entry.
+ auto it2 = files_map.find(full_path);
+ if (it2 == files_map.end()) {
+ file_index = 1 + files.size();
+ files_map.emplace(full_path, file_index);
+ files.push_back(dwarf::FileEntry {
+ file_name,
+ directory_index,
+ 0, // Modification time - NA.
+ 0, // File size - NA.
+ });
+ } else {
+ file_index = it2->second;
+ }
+ }
+ opcodes.SetFile(file_index);
+
+ // Generate mapping opcodes from PC to Java lines.
+ if (file_index != 0) {
+ bool first = true;
+ for (SrcMapElem pc2dex : src_mapping_table) {
+ uint32_t pc = pc2dex.from_;
+ int dex_pc = pc2dex.to_;
+ // Find mapping with address with is greater than our dex pc; then go back one step.
+ auto ub = std::upper_bound(position_infos.begin(), position_infos.end(), dex_pc,
+ [](uint32_t address, const DexFile::PositionInfo& entry) {
+ return address < entry.address_;
+ });
+ if (ub != position_infos.begin()) {
+ int line = (--ub)->line_;
+ if (first) {
+ first = false;
+ if (pc > 0) {
+ // Assume that any preceding code is prologue.
+ int first_line = position_infos.front().line_;
+ // Prologue is not a sensible place for a breakpoint.
+ opcodes.NegateStmt();
+ opcodes.AddRow(method_address, first_line);
+ opcodes.NegateStmt();
+ opcodes.SetPrologueEnd();
+ }
+ opcodes.AddRow(method_address + pc, line);
+ } else if (line != opcodes.CurrentLine()) {
+ opcodes.AddRow(method_address + pc, line);
+ }
+ }
+ }
+ } else {
+ // line 0 - instruction cannot be attributed to any source line.
+ opcodes.AddRow(method_address, 0);
+ }
+
+ opcodes.AdvancePC(text_address + mi->high_pc);
+ opcodes.EndSequence();
+ }
+ std::vector<uint8_t> buffer;
+ buffer.reserve(opcodes.data()->size() + KB);
+ size_t offset = builder_->GetDebugLine()->GetSize();
+ WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_);
+ builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
+ return buffer.size();
+ }
+
+ void End(bool write_oat_patches) {
+ builder_->GetDebugLine()->End();
+ if (write_oat_patches) {
+ builder_->WritePatches(".debug_line.oat_patches",
+ ArrayRef<const uintptr_t>(debug_line_patches_));
+ }
+ }
+
+ private:
+ ElfBuilder<ElfTypes>* builder_;
+ std::vector<uintptr_t> debug_line_patches_;
+};
+
+} // namespace debug
+} // namespace art
+
+#endif // ART_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
new file mode 100644
index 0000000000..fd7f949c5d
--- /dev/null
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -0,0 +1,298 @@
+/*
+ * 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_DEBUG_LOC_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+
+#include <map>
+
+#include "arch/instruction_set.h"
+#include "compiled_method.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/dwarf/register.h"
+#include "debug/method_debug_info.h"
+#include "stack_map.h"
+
+namespace art {
+namespace debug {
+using Reg = dwarf::Reg;
+
+static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) {
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ return Reg::ArmCore(machine_reg);
+ case kArm64:
+ return Reg::Arm64Core(machine_reg);
+ case kX86:
+ return Reg::X86Core(machine_reg);
+ case kX86_64:
+ return Reg::X86_64Core(machine_reg);
+ case kMips:
+ return Reg::MipsCore(machine_reg);
+ case kMips64:
+ return Reg::Mips64Core(machine_reg);
+ case kNone:
+ LOG(FATAL) << "No instruction set";
+ }
+ UNREACHABLE();
+}
+
+static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) {
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ return Reg::ArmFp(machine_reg);
+ case kArm64:
+ return Reg::Arm64Fp(machine_reg);
+ case kX86:
+ return Reg::X86Fp(machine_reg);
+ case kX86_64:
+ return Reg::X86_64Fp(machine_reg);
+ case kMips:
+ return Reg::MipsFp(machine_reg);
+ case kMips64:
+ return Reg::Mips64Fp(machine_reg);
+ case kNone:
+ LOG(FATAL) << "No instruction set";
+ }
+ UNREACHABLE();
+}
+
+struct VariableLocation {
+ uint32_t low_pc;
+ uint32_t high_pc;
+ DexRegisterLocation reg_lo; // May be None if the location is unknown.
+ DexRegisterLocation reg_hi; // Most significant bits of 64-bit value.
+};
+
+// Get the location of given dex register (e.g. stack or machine register).
+// Note that the location might be different based on the current pc.
+// The result will cover all ranges where the variable is in scope.
+std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info,
+ uint16_t vreg,
+ bool is64bitValue,
+ uint32_t dex_pc_low,
+ uint32_t dex_pc_high) {
+ std::vector<VariableLocation> variable_locations;
+
+ // Get stack maps sorted by pc (they might not be sorted internally).
+ const CodeInfo code_info(method_info->compiled_method->GetVmapTable().data());
+ const StackMapEncoding encoding = code_info.ExtractEncoding();
+ std::map<uint32_t, StackMap> stack_maps;
+ for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
+ StackMap stack_map = code_info.GetStackMapAt(s, encoding);
+ DCHECK(stack_map.IsValid());
+ const uint32_t low_pc = method_info->low_pc + stack_map.GetNativePcOffset(encoding);
+ DCHECK_LE(low_pc, method_info->high_pc);
+ stack_maps.emplace(low_pc, stack_map);
+ }
+
+ // Create entries for the requested register based on stack map data.
+ for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) {
+ const StackMap& stack_map = it->second;
+ const uint32_t low_pc = it->first;
+ auto next_it = it;
+ next_it++;
+ const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first
+ : method_info->high_pc;
+ DCHECK_LE(low_pc, high_pc);
+ if (low_pc == high_pc) {
+ continue; // Ignore if the address range is empty.
+ }
+
+ // Check that the stack map is in the requested range.
+ uint32_t dex_pc = stack_map.GetDexPc(encoding);
+ if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) {
+ continue;
+ }
+
+ // Find the location of the dex register.
+ DexRegisterLocation reg_lo = DexRegisterLocation::None();
+ DexRegisterLocation reg_hi = DexRegisterLocation::None();
+ if (stack_map.HasDexRegisterMap(encoding)) {
+ DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
+ stack_map, encoding, method_info->code_item->registers_size_);
+ reg_lo = dex_register_map.GetDexRegisterLocation(
+ vreg, method_info->code_item->registers_size_, code_info, encoding);
+ if (is64bitValue) {
+ reg_hi = dex_register_map.GetDexRegisterLocation(
+ vreg + 1, method_info->code_item->registers_size_, code_info, encoding);
+ }
+ }
+
+ // Add location entry for this address range.
+ if (!variable_locations.empty() &&
+ variable_locations.back().reg_lo == reg_lo &&
+ variable_locations.back().reg_hi == reg_hi &&
+ variable_locations.back().high_pc == low_pc) {
+ // Merge with the previous entry (extend its range).
+ variable_locations.back().high_pc = high_pc;
+ } else {
+ variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi});
+ }
+ }
+
+ return variable_locations;
+}
+
+// Write table into .debug_loc which describes location of dex register.
+// The dex register might be valid only at some points and it might
+// move between machine registers and stack.
+static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
+ uint16_t vreg,
+ bool is64bitValue,
+ uint32_t compilation_unit_low_pc,
+ uint32_t dex_pc_low,
+ uint32_t dex_pc_high,
+ InstructionSet isa,
+ dwarf::DebugInfoEntryWriter<>* debug_info,
+ std::vector<uint8_t>* debug_loc_buffer,
+ std::vector<uint8_t>* debug_ranges_buffer) {
+ using Kind = DexRegisterLocation::Kind;
+ if (!method_info->IsFromOptimizingCompiler()) {
+ return;
+ }
+
+ dwarf::Writer<> debug_loc(debug_loc_buffer);
+ dwarf::Writer<> debug_ranges(debug_ranges_buffer);
+ debug_info->WriteSecOffset(dwarf::DW_AT_location, debug_loc.size());
+ debug_info->WriteSecOffset(dwarf::DW_AT_start_scope, debug_ranges.size());
+
+ std::vector<VariableLocation> variable_locations = GetVariableLocations(
+ method_info,
+ vreg,
+ is64bitValue,
+ dex_pc_low,
+ dex_pc_high);
+
+ // Write .debug_loc entries.
+ const bool is64bit = Is64BitInstructionSet(isa);
+ std::vector<uint8_t> expr_buffer;
+ for (const VariableLocation& variable_location : variable_locations) {
+ // Translate dex register location to DWARF expression.
+ // Note that 64-bit value might be split to two distinct locations.
+ // (for example, two 32-bit machine registers, or even stack and register)
+ dwarf::Expression expr(&expr_buffer);
+ DexRegisterLocation reg_lo = variable_location.reg_lo;
+ DexRegisterLocation reg_hi = variable_location.reg_hi;
+ for (int piece = 0; piece < (is64bitValue ? 2 : 1); piece++) {
+ DexRegisterLocation reg_loc = (piece == 0 ? reg_lo : reg_hi);
+ const Kind kind = reg_loc.GetKind();
+ const int32_t value = reg_loc.GetValue();
+ if (kind == Kind::kInStack) {
+ const size_t frame_size = method_info->compiled_method->GetFrameSizeInBytes();
+ // The stack offset is relative to SP. Make it relative to CFA.
+ expr.WriteOpFbreg(value - frame_size);
+ if (piece == 0 && reg_hi.GetKind() == Kind::kInStack &&
+ reg_hi.GetValue() == value + 4) {
+ break; // the high word is correctly implied by the low word.
+ }
+ } else if (kind == Kind::kInRegister) {
+ expr.WriteOpReg(GetDwarfCoreReg(isa, value).num());
+ if (piece == 0 && reg_hi.GetKind() == Kind::kInRegisterHigh &&
+ reg_hi.GetValue() == value) {
+ break; // the high word is correctly implied by the low word.
+ }
+ } else if (kind == Kind::kInFpuRegister) {
+ if ((isa == kArm || isa == kThumb2) &&
+ piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister &&
+ reg_hi.GetValue() == value + 1 && value % 2 == 0) {
+ // Translate S register pair to D register (e.g. S4+S5 to D2).
+ expr.WriteOpReg(Reg::ArmDp(value / 2).num());
+ break;
+ }
+ expr.WriteOpReg(GetDwarfFpReg(isa, value).num());
+ if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh &&
+ reg_hi.GetValue() == reg_lo.GetValue()) {
+ break; // the high word is correctly implied by the low word.
+ }
+ } else if (kind == Kind::kConstant) {
+ expr.WriteOpConsts(value);
+ expr.WriteOpStackValue();
+ } else if (kind == Kind::kNone) {
+ break;
+ } else {
+ // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
+ // kInRegisterHigh and kInFpuRegisterHigh should be handled by
+ // the special cases above and they should not occur alone.
+ LOG(ERROR) << "Unexpected register location kind: "
+ << DexRegisterLocation::PrettyDescriptor(kind);
+ break;
+ }
+ if (is64bitValue) {
+ // Write the marker which is needed by split 64-bit values.
+ // This code is skipped by the special cases.
+ expr.WriteOpPiece(4);
+ }
+ }
+
+ if (expr.size() > 0) {
+ if (is64bit) {
+ debug_loc.PushUint64(variable_location.low_pc - compilation_unit_low_pc);
+ debug_loc.PushUint64(variable_location.high_pc - compilation_unit_low_pc);
+ } else {
+ debug_loc.PushUint32(variable_location.low_pc - compilation_unit_low_pc);
+ debug_loc.PushUint32(variable_location.high_pc - compilation_unit_low_pc);
+ }
+ // Write the expression.
+ debug_loc.PushUint16(expr.size());
+ debug_loc.PushData(expr.data());
+ } else {
+ // Do not generate .debug_loc if the location is not known.
+ }
+ }
+ // Write end-of-list entry.
+ if (is64bit) {
+ debug_loc.PushUint64(0);
+ debug_loc.PushUint64(0);
+ } else {
+ debug_loc.PushUint32(0);
+ debug_loc.PushUint32(0);
+ }
+
+ // Write .debug_ranges entries.
+ // This includes ranges where the variable is in scope but the location is not known.
+ for (size_t i = 0; i < variable_locations.size(); i++) {
+ uint32_t low_pc = variable_locations[i].low_pc;
+ uint32_t high_pc = variable_locations[i].high_pc;
+ while (i + 1 < variable_locations.size() && variable_locations[i+1].low_pc == high_pc) {
+ // Merge address range with the next entry.
+ high_pc = variable_locations[++i].high_pc;
+ }
+ if (is64bit) {
+ debug_ranges.PushUint64(low_pc - compilation_unit_low_pc);
+ debug_ranges.PushUint64(high_pc - compilation_unit_low_pc);
+ } else {
+ debug_ranges.PushUint32(low_pc - compilation_unit_low_pc);
+ debug_ranges.PushUint32(high_pc - compilation_unit_low_pc);
+ }
+ }
+ // Write end-of-list entry.
+ if (is64bit) {
+ debug_ranges.PushUint64(0);
+ debug_ranges.PushUint64(0);
+ } else {
+ debug_ranges.PushUint32(0);
+ debug_ranges.PushUint32(0);
+ }
+}
+
+} // namespace debug
+} // namespace art
+
+#endif // ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
new file mode 100644
index 0000000000..01bd6797c9
--- /dev/null
+++ b/compiler/debug/elf_debug_writer.cc
@@ -0,0 +1,183 @@
+/*
+ * 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 "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 "utils/array_ref.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) {
+ // Add methods to .symtab.
+ WriteDebugSymbols(builder, method_infos, true /* with_signature */);
+ // Generate CFI (stack unwinding information).
+ WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
+ // Write DWARF .debug_* sections.
+ WriteDebugSections(builder, method_infos, write_oat_patches);
+}
+
+template<typename ElfTypes>
+static void WriteDebugSections(ElfBuilder<ElfTypes>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos,
+ bool 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) {
+ 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);
+ cu.low_pc = std::min(cu.low_pc, mi.low_pc);
+ cu.high_pc = std::max(cu.high_pc, mi.high_pc);
+ 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,
+ size_t rodata_size,
+ size_t text_size,
+ const ArrayRef<const MethodDebugInfo>& method_infos) {
+ if (Is64BitInstructionSet(isa)) {
+ return MakeMiniDebugInfoInternal<ElfTypes64>(isa, rodata_size, text_size, method_infos);
+ } else {
+ return MakeMiniDebugInfoInternal<ElfTypes32>(isa, rodata_size, text_size, method_infos);
+ }
+}
+
+template <typename ElfTypes>
+static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal(
+ const MethodDebugInfo& method_info) {
+ const InstructionSet isa = method_info.compiled_method->GetInstructionSet();
+ std::vector<uint8_t> buffer;
+ buffer.reserve(KB);
+ VectorOutputStream out("Debug ELF file", &buffer);
+ std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &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(),
+ ArrayRef<const MethodDebugInfo>(&method_info, 1),
+ dwarf::DW_DEBUG_FRAME_FORMAT,
+ false /* write_oat_patches */);
+ builder->End();
+ CHECK(builder->Good());
+ // Make a copy of the buffer. We want to shrink it anyway.
+ uint8_t* result = new uint8_t[buffer.size()];
+ CHECK(result != nullptr);
+ memcpy(result, buffer.data(), buffer.size());
+ return ArrayRef<const uint8_t>(result, buffer.size());
+}
+
+ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const MethodDebugInfo& method_info) {
+ const InstructionSet isa = method_info.compiled_method->GetInstructionSet();
+ if (Is64BitInstructionSet(isa)) {
+ return WriteDebugElfFileForMethodInternal<ElfTypes64>(method_info);
+ } else {
+ return WriteDebugElfFileForMethodInternal<ElfTypes32>(method_info);
+ }
+}
+
+template <typename ElfTypes>
+static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal(
+ const InstructionSet isa, const ArrayRef<mirror::Class*>& types)
+ SHARED_REQUIRES(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, &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());
+ // Make a copy of the buffer. We want to shrink it anyway.
+ uint8_t* result = new uint8_t[buffer.size()];
+ CHECK(result != nullptr);
+ memcpy(result, buffer.data(), buffer.size());
+ return ArrayRef<const uint8_t>(result, buffer.size());
+}
+
+ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
+ const ArrayRef<mirror::Class*>& types) {
+ if (Is64BitInstructionSet(isa)) {
+ return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, types);
+ } else {
+ return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, types);
+ }
+}
+
+// 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
diff --git a/compiler/elf_writer_debug.h b/compiler/debug/elf_debug_writer.h
index e289197971..103b501489 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_ELF_WRITER_DEBUG_H_
-#define ART_COMPILER_ELF_WRITER_DEBUG_H_
+#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
#include "base/macros.h"
#include "base/mutex.h"
-#include "dwarf/dwarf_constants.h"
+#include "debug/dwarf/dwarf_constants.h"
#include "elf_builder.h"
#include "utils/array_ref.h"
@@ -27,13 +27,13 @@ namespace art {
namespace mirror {
class Class;
}
-namespace dwarf {
+namespace debug {
struct MethodDebugInfo;
template <typename ElfTypes>
void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
const ArrayRef<const MethodDebugInfo>& method_infos,
- CFIFormat cfi_format,
+ dwarf::CFIFormat cfi_format,
bool write_oat_patches);
std::vector<uint8_t> MakeMiniDebugInfo(InstructionSet isa,
@@ -41,13 +41,13 @@ std::vector<uint8_t> MakeMiniDebugInfo(InstructionSet isa,
size_t text_section_size,
const ArrayRef<const MethodDebugInfo>& method_infos);
-ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info);
+ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const MethodDebugInfo& method_info);
ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
const ArrayRef<mirror::Class*>& types)
SHARED_REQUIRES(Locks::mutator_lock_);
-} // namespace dwarf
+} // namespace debug
} // namespace art
-#endif // ART_COMPILER_ELF_WRITER_DEBUG_H_
+#endif // ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
new file mode 100644
index 0000000000..5c7d1c72a4
--- /dev/null
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -0,0 +1,111 @@
+/*
+ * 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,
+ 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, &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_
+
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
new file mode 100644
index 0000000000..41508f44b4
--- /dev/null
+++ b/compiler/debug/elf_symtab_writer.h
@@ -0,0 +1,115 @@
+/*
+ * 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_SYMTAB_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
+
+#include <unordered_set>
+
+#include "debug/method_debug_info.h"
+#include "elf_builder.h"
+#include "utils.h"
+
+namespace art {
+namespace debug {
+
+// The ARM specification defines three special mapping symbols
+// $a, $t and $d which mark ARM, Thumb and data ranges respectively.
+// These symbols can be used by tools, for example, to pretty
+// print instructions correctly. Objdump will use them if they
+// exist, but it will still work well without them.
+// However, these extra symbols take space, so let's just generate
+// one symbol which marks the whole .text section as code.
+constexpr bool kGenerateSingleArmMappingSymbol = true;
+
+template <typename ElfTypes>
+static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos,
+ bool with_signature) {
+ bool generated_mapping_symbol = false;
+ auto* strtab = builder->GetStrTab();
+ auto* symtab = builder->GetSymTab();
+
+ if (method_infos.empty()) {
+ return;
+ }
+
+ // Find all addresses (low_pc) which contain deduped methods.
+ // The first instance of method is not marked deduped_, but the rest is.
+ std::unordered_set<uint32_t> deduped_addresses;
+ for (const MethodDebugInfo& info : method_infos) {
+ if (info.deduped) {
+ deduped_addresses.insert(info.low_pc);
+ }
+ }
+
+ strtab->Start();
+ strtab->Write(""); // strtab should start with empty string.
+ std::string last_name;
+ size_t last_name_offset = 0;
+ for (const MethodDebugInfo& info : method_infos) {
+ if (info.deduped) {
+ continue; // Add symbol only for the first instance.
+ }
+ std::string name = PrettyMethod(info.dex_method_index, *info.dex_file, with_signature);
+ if (deduped_addresses.find(info.low_pc) != deduped_addresses.end()) {
+ name += " [DEDUPED]";
+ }
+ // If we write method names without signature, we might see the same name multiple times.
+ size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
+
+ const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr;
+ const bool is_relative = (text != nullptr);
+ uint32_t low_pc = info.low_pc;
+ // Add in code delta, e.g., thumb bit 0 for Thumb2 code.
+ low_pc += info.compiled_method->CodeDelta();
+ symtab->Add(name_offset,
+ text,
+ low_pc,
+ is_relative,
+ info.high_pc - info.low_pc,
+ STB_GLOBAL,
+ STT_FUNC);
+
+ // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
+ // instructions, so that disassembler tools can correctly disassemble.
+ // Note that even if we generate just a single mapping symbol, ARM's Streamline
+ // requires it to match function symbol. Just address 0 does not work.
+ if (info.compiled_method->GetInstructionSet() == kThumb2) {
+ if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) {
+ symtab->Add(strtab->Write("$t"), text, info.low_pc & ~1,
+ is_relative, 0, STB_LOCAL, STT_NOTYPE);
+ generated_mapping_symbol = true;
+ }
+ }
+
+ last_name = std::move(name);
+ last_name_offset = name_offset;
+ }
+ strtab->End();
+
+ // Symbols are buffered and written after names (because they are smaller).
+ // We could also do two passes in this function to avoid the buffering.
+ symtab->Start();
+ symtab->Write();
+ symtab->End();
+}
+
+} // namespace debug
+} // namespace art
+
+#endif // ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
+
diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h
new file mode 100644
index 0000000000..6b3dd8c528
--- /dev/null
+++ b/compiler/debug/method_debug_info.h
@@ -0,0 +1,48 @@
+/*
+ * 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_DEBUG_METHOD_DEBUG_INFO_H_
+#define ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_
+
+#include "compiled_method.h"
+#include "dex_file.h"
+
+namespace art {
+namespace debug {
+
+struct MethodDebugInfo {
+ const DexFile* dex_file;
+ size_t class_def_index;
+ uint32_t dex_method_index;
+ uint32_t access_flags;
+ const DexFile::CodeItem* code_item;
+ bool deduped;
+ uintptr_t low_pc;
+ uintptr_t high_pc;
+ CompiledMethod* compiled_method;
+
+ bool IsFromOptimizingCompiler() const {
+ return compiled_method->GetQuickCode().size() > 0 &&
+ compiled_method->GetVmapTable().size() > 0 &&
+ compiled_method->GetGcMap().size() == 0 &&
+ code_item != nullptr;
+ }
+};
+
+} // namespace debug
+} // namespace art
+
+#endif // ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_
diff --git a/compiler/dex/quick/lazy_debug_frame_opcode_writer.h b/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
index c425fc852d..85050f4f13 100644
--- a/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
+++ b/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
@@ -19,7 +19,7 @@
#include "base/arena_allocator.h"
#include "base/arena_containers.h"
-#include "dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
namespace art {
struct LIR;
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 5dbf7360f8..d50a08cb20 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -32,9 +32,9 @@ namespace art {
class ElfFile;
class OutputStream;
-namespace dwarf {
+namespace debug {
struct MethodDebugInfo;
-} // namespace dwarf
+} // namespace debug
class ElfWriter {
public:
@@ -54,14 +54,14 @@ class ElfWriter {
virtual void Start() = 0;
virtual void PrepareDebugInfo(size_t rodata_section_size,
size_t text_section_size,
- const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) = 0;
+ const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
virtual OutputStream* StartRoData() = 0;
virtual void EndRoData(OutputStream* rodata) = 0;
virtual OutputStream* StartText() = 0;
virtual void EndText(OutputStream* text) = 0;
virtual void SetBssSize(size_t bss_size) = 0;
virtual void WriteDynamicSection() = 0;
- virtual void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) = 0;
+ virtual void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
virtual void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) = 0;
virtual bool End() = 0;
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
deleted file mode 100644
index e2481b061c..0000000000
--- a/compiler/elf_writer_debug.cc
+++ /dev/null
@@ -1,1666 +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.
- */
-
-#include "elf_writer_debug.h"
-
-#include <algorithm>
-#include <unordered_set>
-#include <vector>
-#include <cstdio>
-
-#include "base/casts.h"
-#include "base/stl_util.h"
-#include "linear_alloc.h"
-#include "compiled_method.h"
-#include "dex_file-inl.h"
-#include "driver/compiler_driver.h"
-#include "dwarf/expression.h"
-#include "dwarf/headers.h"
-#include "dwarf/method_debug_info.h"
-#include "dwarf/register.h"
-#include "elf_builder.h"
-#include "linker/vector_output_stream.h"
-#include "mirror/array.h"
-#include "mirror/class-inl.h"
-#include "mirror/class.h"
-#include "oat_writer.h"
-#include "stack_map.h"
-#include "utils.h"
-
-// liblzma.
-#include "XzEnc.h"
-#include "7zCrc.h"
-#include "XzCrc64.h"
-
-namespace art {
-namespace dwarf {
-
-// The ARM specification defines three special mapping symbols
-// $a, $t and $d which mark ARM, Thumb and data ranges respectively.
-// These symbols can be used by tools, for example, to pretty
-// print instructions correctly. Objdump will use them if they
-// exist, but it will still work well without them.
-// However, these extra symbols take space, so let's just generate
-// one symbol which marks the whole .text section as code.
-constexpr bool kGenerateSingleArmMappingSymbol = true;
-
-static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) {
- switch (isa) {
- case kArm:
- case kThumb2:
- return Reg::ArmCore(machine_reg);
- case kArm64:
- return Reg::Arm64Core(machine_reg);
- case kX86:
- return Reg::X86Core(machine_reg);
- case kX86_64:
- return Reg::X86_64Core(machine_reg);
- case kMips:
- return Reg::MipsCore(machine_reg);
- case kMips64:
- return Reg::Mips64Core(machine_reg);
- default:
- LOG(FATAL) << "Unknown instruction set: " << isa;
- UNREACHABLE();
- }
-}
-
-static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) {
- switch (isa) {
- case kArm:
- case kThumb2:
- return Reg::ArmFp(machine_reg);
- case kArm64:
- return Reg::Arm64Fp(machine_reg);
- case kX86:
- return Reg::X86Fp(machine_reg);
- case kX86_64:
- return Reg::X86_64Fp(machine_reg);
- case kMips:
- return Reg::MipsFp(machine_reg);
- case kMips64:
- return Reg::Mips64Fp(machine_reg);
- default:
- LOG(FATAL) << "Unknown instruction set: " << isa;
- UNREACHABLE();
- }
-}
-
-static void WriteCIE(InstructionSet isa,
- CFIFormat format,
- std::vector<uint8_t>* buffer) {
- // Scratch registers should be marked as undefined. This tells the
- // debugger that its value in the previous frame is not recoverable.
- bool is64bit = Is64BitInstructionSet(isa);
- switch (isa) {
- case kArm:
- case kThumb2: {
- DebugFrameOpCodeWriter<> opcodes;
- opcodes.DefCFA(Reg::ArmCore(13), 0); // R13(SP).
- // core registers.
- for (int reg = 0; reg < 13; reg++) {
- if (reg < 4 || reg == 12) {
- opcodes.Undefined(Reg::ArmCore(reg));
- } else {
- opcodes.SameValue(Reg::ArmCore(reg));
- }
- }
- // fp registers.
- for (int reg = 0; reg < 32; reg++) {
- if (reg < 16) {
- opcodes.Undefined(Reg::ArmFp(reg));
- } else {
- opcodes.SameValue(Reg::ArmFp(reg));
- }
- }
- auto return_reg = Reg::ArmCore(14); // R14(LR).
- WriteCIE(is64bit, return_reg, opcodes, format, buffer);
- return;
- }
- case kArm64: {
- DebugFrameOpCodeWriter<> opcodes;
- opcodes.DefCFA(Reg::Arm64Core(31), 0); // R31(SP).
- // core registers.
- for (int reg = 0; reg < 30; reg++) {
- if (reg < 8 || reg == 16 || reg == 17) {
- opcodes.Undefined(Reg::Arm64Core(reg));
- } else {
- opcodes.SameValue(Reg::Arm64Core(reg));
- }
- }
- // fp registers.
- for (int reg = 0; reg < 32; reg++) {
- if (reg < 8 || reg >= 16) {
- opcodes.Undefined(Reg::Arm64Fp(reg));
- } else {
- opcodes.SameValue(Reg::Arm64Fp(reg));
- }
- }
- auto return_reg = Reg::Arm64Core(30); // R30(LR).
- WriteCIE(is64bit, return_reg, opcodes, format, buffer);
- return;
- }
- case kMips:
- case kMips64: {
- DebugFrameOpCodeWriter<> opcodes;
- opcodes.DefCFA(Reg::MipsCore(29), 0); // R29(SP).
- // core registers.
- for (int reg = 1; reg < 26; reg++) {
- if (reg < 16 || reg == 24 || reg == 25) { // AT, V*, A*, T*.
- opcodes.Undefined(Reg::MipsCore(reg));
- } else {
- opcodes.SameValue(Reg::MipsCore(reg));
- }
- }
- // fp registers.
- for (int reg = 0; reg < 32; reg++) {
- if (reg < 24) {
- opcodes.Undefined(Reg::Mips64Fp(reg));
- } else {
- opcodes.SameValue(Reg::Mips64Fp(reg));
- }
- }
- auto return_reg = Reg::MipsCore(31); // R31(RA).
- WriteCIE(is64bit, return_reg, opcodes, format, buffer);
- return;
- }
- case kX86: {
- // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296
- constexpr bool generate_opcodes_for_x86_fp = false;
- DebugFrameOpCodeWriter<> opcodes;
- opcodes.DefCFA(Reg::X86Core(4), 4); // R4(ESP).
- opcodes.Offset(Reg::X86Core(8), -4); // R8(EIP).
- // core registers.
- for (int reg = 0; reg < 8; reg++) {
- if (reg <= 3) {
- opcodes.Undefined(Reg::X86Core(reg));
- } else if (reg == 4) {
- // Stack pointer.
- } else {
- opcodes.SameValue(Reg::X86Core(reg));
- }
- }
- // fp registers.
- if (generate_opcodes_for_x86_fp) {
- for (int reg = 0; reg < 8; reg++) {
- opcodes.Undefined(Reg::X86Fp(reg));
- }
- }
- auto return_reg = Reg::X86Core(8); // R8(EIP).
- WriteCIE(is64bit, return_reg, opcodes, format, buffer);
- return;
- }
- case kX86_64: {
- DebugFrameOpCodeWriter<> opcodes;
- opcodes.DefCFA(Reg::X86_64Core(4), 8); // R4(RSP).
- opcodes.Offset(Reg::X86_64Core(16), -8); // R16(RIP).
- // core registers.
- for (int reg = 0; reg < 16; reg++) {
- if (reg == 4) {
- // Stack pointer.
- } else if (reg < 12 && reg != 3 && reg != 5) { // except EBX and EBP.
- opcodes.Undefined(Reg::X86_64Core(reg));
- } else {
- opcodes.SameValue(Reg::X86_64Core(reg));
- }
- }
- // fp registers.
- for (int reg = 0; reg < 16; reg++) {
- if (reg < 12) {
- opcodes.Undefined(Reg::X86_64Fp(reg));
- } else {
- opcodes.SameValue(Reg::X86_64Fp(reg));
- }
- }
- auto return_reg = Reg::X86_64Core(16); // R16(RIP).
- WriteCIE(is64bit, return_reg, opcodes, format, buffer);
- return;
- }
- case kNone:
- break;
- }
- LOG(FATAL) << "Cannot write CIE frame for ISA " << isa;
- UNREACHABLE();
-}
-
-template<typename ElfTypes>
-void WriteCFISection(ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- CFIFormat format,
- bool write_oat_patches) {
- CHECK(format == DW_DEBUG_FRAME_FORMAT || format == DW_EH_FRAME_FORMAT);
- typedef typename ElfTypes::Addr Elf_Addr;
-
- if (method_infos.empty()) {
- return;
- }
-
- std::vector<uint32_t> binary_search_table;
- std::vector<uintptr_t> patch_locations;
- if (format == DW_EH_FRAME_FORMAT) {
- binary_search_table.reserve(2 * method_infos.size());
- } else {
- patch_locations.reserve(method_infos.size());
- }
-
- // The methods can be written any order.
- // Let's therefore sort them in the lexicographical order of the opcodes.
- // This has no effect on its own. However, if the final .debug_frame section is
- // compressed it reduces the size since similar opcodes sequences are grouped.
- std::vector<const MethodDebugInfo*> sorted_method_infos;
- sorted_method_infos.reserve(method_infos.size());
- for (size_t i = 0; i < method_infos.size(); i++) {
- sorted_method_infos.push_back(&method_infos[i]);
- }
- std::sort(
- sorted_method_infos.begin(),
- sorted_method_infos.end(),
- [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) {
- ArrayRef<const uint8_t> l = lhs->compiled_method_->GetCFIInfo();
- ArrayRef<const uint8_t> r = rhs->compiled_method_->GetCFIInfo();
- return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
- });
-
- // Write .eh_frame/.debug_frame section.
- auto* cfi_section = (format == DW_DEBUG_FRAME_FORMAT
- ? builder->GetDebugFrame()
- : builder->GetEhFrame());
- {
- cfi_section->Start();
- const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
- const Elf_Addr text_address = builder->GetText()->Exists()
- ? builder->GetText()->GetAddress()
- : 0;
- const Elf_Addr cfi_address = cfi_section->GetAddress();
- const Elf_Addr cie_address = cfi_address;
- Elf_Addr buffer_address = cfi_address;
- std::vector<uint8_t> buffer; // Small temporary buffer.
- WriteCIE(builder->GetIsa(), format, &buffer);
- cfi_section->WriteFully(buffer.data(), buffer.size());
- buffer_address += buffer.size();
- buffer.clear();
- for (const MethodDebugInfo* mi : sorted_method_infos) {
- if (!mi->deduped_) { // Only one FDE per unique address.
- ArrayRef<const uint8_t> opcodes = mi->compiled_method_->GetCFIInfo();
- if (!opcodes.empty()) {
- const Elf_Addr code_address = text_address + mi->low_pc_;
- if (format == DW_EH_FRAME_FORMAT) {
- binary_search_table.push_back(
- dchecked_integral_cast<uint32_t>(code_address));
- binary_search_table.push_back(
- dchecked_integral_cast<uint32_t>(buffer_address));
- }
- WriteFDE(is64bit, cfi_address, cie_address,
- code_address, mi->high_pc_ - mi->low_pc_,
- opcodes, format, buffer_address, &buffer,
- &patch_locations);
- cfi_section->WriteFully(buffer.data(), buffer.size());
- buffer_address += buffer.size();
- buffer.clear();
- }
- }
- }
- cfi_section->End();
- }
-
- if (format == DW_EH_FRAME_FORMAT) {
- auto* header_section = builder->GetEhFrameHdr();
- header_section->Start();
- uint32_t header_address = dchecked_integral_cast<int32_t>(header_section->GetAddress());
- // Write .eh_frame_hdr section.
- std::vector<uint8_t> buffer;
- Writer<> header(&buffer);
- header.PushUint8(1); // Version.
- // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
- // so we have to use pcrel which means relative to the pointer's location.
- header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
- // Encoding of binary search table size.
- header.PushUint8(DW_EH_PE_udata4);
- // Encoding of binary search table addresses - libunwind supports only this
- // specific combination, which means relative to the start of .eh_frame_hdr.
- header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4);
- // .eh_frame pointer
- header.PushInt32(cfi_section->GetAddress() - (header_address + 4u));
- // Binary search table size (number of entries).
- header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2));
- header_section->WriteFully(buffer.data(), buffer.size());
- // Binary search table.
- for (size_t i = 0; i < binary_search_table.size(); i++) {
- // Make addresses section-relative since we know the header address now.
- binary_search_table[i] -= header_address;
- }
- header_section->WriteFully(binary_search_table.data(), binary_search_table.size());
- header_section->End();
- } else {
- if (write_oat_patches) {
- builder->WritePatches(".debug_frame.oat_patches",
- ArrayRef<const uintptr_t>(patch_locations));
- }
- }
-}
-
-namespace {
- struct CompilationUnit {
- std::vector<const MethodDebugInfo*> methods_;
- size_t debug_line_offset_ = 0;
- uintptr_t low_pc_ = std::numeric_limits<uintptr_t>::max();
- uintptr_t high_pc_ = 0;
- };
-
- typedef std::vector<DexFile::LocalInfo> LocalInfos;
-
- void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
- static_cast<LocalInfos*>(ctx)->push_back(entry);
- }
-
- typedef std::vector<DexFile::PositionInfo> PositionInfos;
-
- bool PositionInfoCallback(void* ctx, const DexFile::PositionInfo& entry) {
- static_cast<PositionInfos*>(ctx)->push_back(entry);
- return false;
- }
-
- std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
- std::vector<const char*> names;
- if (mi->code_item_ != nullptr) {
- const uint8_t* stream = mi->dex_file_->GetDebugInfoStream(mi->code_item_);
- if (stream != nullptr) {
- DecodeUnsignedLeb128(&stream); // line.
- uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
- for (uint32_t i = 0; i < parameters_size; ++i) {
- uint32_t id = DecodeUnsignedLeb128P1(&stream);
- names.push_back(mi->dex_file_->StringDataByIdx(id));
- }
- }
- }
- return names;
- }
-
- struct VariableLocation {
- uint32_t low_pc;
- uint32_t high_pc;
- DexRegisterLocation reg_lo; // May be None if the location is unknown.
- DexRegisterLocation reg_hi; // Most significant bits of 64-bit value.
- };
-
- // Get the location of given dex register (e.g. stack or machine register).
- // Note that the location might be different based on the current pc.
- // The result will cover all ranges where the variable is in scope.
- std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info,
- uint16_t vreg,
- bool is64bitValue,
- uint32_t dex_pc_low,
- uint32_t dex_pc_high) {
- std::vector<VariableLocation> variable_locations;
-
- // Get stack maps sorted by pc (they might not be sorted internally).
- const CodeInfo code_info(method_info->compiled_method_->GetVmapTable().data());
- const StackMapEncoding encoding = code_info.ExtractEncoding();
- std::map<uint32_t, StackMap> stack_maps;
- for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
- StackMap stack_map = code_info.GetStackMapAt(s, encoding);
- DCHECK(stack_map.IsValid());
- const uint32_t low_pc = method_info->low_pc_ + stack_map.GetNativePcOffset(encoding);
- DCHECK_LE(low_pc, method_info->high_pc_);
- stack_maps.emplace(low_pc, stack_map);
- }
-
- // Create entries for the requested register based on stack map data.
- for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) {
- const StackMap& stack_map = it->second;
- const uint32_t low_pc = it->first;
- auto next_it = it;
- next_it++;
- const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first
- : method_info->high_pc_;
- DCHECK_LE(low_pc, high_pc);
- if (low_pc == high_pc) {
- continue; // Ignore if the address range is empty.
- }
-
- // Check that the stack map is in the requested range.
- uint32_t dex_pc = stack_map.GetDexPc(encoding);
- if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) {
- continue;
- }
-
- // Find the location of the dex register.
- DexRegisterLocation reg_lo = DexRegisterLocation::None();
- DexRegisterLocation reg_hi = DexRegisterLocation::None();
- if (stack_map.HasDexRegisterMap(encoding)) {
- DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
- stack_map, encoding, method_info->code_item_->registers_size_);
- reg_lo = dex_register_map.GetDexRegisterLocation(
- vreg, method_info->code_item_->registers_size_, code_info, encoding);
- if (is64bitValue) {
- reg_hi = dex_register_map.GetDexRegisterLocation(
- vreg + 1, method_info->code_item_->registers_size_, code_info, encoding);
- }
- }
-
- // Add location entry for this address range.
- if (!variable_locations.empty() &&
- variable_locations.back().reg_lo == reg_lo &&
- variable_locations.back().reg_hi == reg_hi &&
- variable_locations.back().high_pc == low_pc) {
- // Merge with the previous entry (extend its range).
- variable_locations.back().high_pc = high_pc;
- } else {
- variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi});
- }
- }
-
- return variable_locations;
- }
-
- bool IsFromOptimizingCompiler(const MethodDebugInfo* method_info) {
- return method_info->compiled_method_->GetQuickCode().size() > 0 &&
- method_info->compiled_method_->GetVmapTable().size() > 0 &&
- method_info->compiled_method_->GetGcMap().size() == 0 &&
- method_info->code_item_ != nullptr;
- }
-} // namespace
-
-// Helper class to write .debug_info and its supporting sections.
-template<typename ElfTypes>
-class DebugInfoWriter {
- typedef typename ElfTypes::Addr Elf_Addr;
-
- // Helper class to write one compilation unit.
- // It holds helper methods and temporary state.
- class CompilationUnitWriter {
- public:
- explicit CompilationUnitWriter(DebugInfoWriter* owner)
- : owner_(owner),
- info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &owner->debug_abbrev_) {
- }
-
- void Write(const CompilationUnit& compilation_unit) {
- CHECK(!compilation_unit.methods_.empty());
- const Elf_Addr text_address = owner_->builder_->GetText()->Exists()
- ? owner_->builder_->GetText()->GetAddress()
- : 0;
- const uintptr_t cu_size = compilation_unit.high_pc_ - compilation_unit.low_pc_;
-
- info_.StartTag(DW_TAG_compile_unit);
- info_.WriteString(DW_AT_producer, "Android dex2oat");
- info_.WriteData1(DW_AT_language, DW_LANG_Java);
- info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT");
- info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc_);
- info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
- info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset_);
-
- const char* last_dex_class_desc = nullptr;
- for (auto mi : compilation_unit.methods_) {
- const DexFile* dex = mi->dex_file_;
- const DexFile::CodeItem* dex_code = mi->code_item_;
- const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index_);
- const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
- const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
- const char* dex_class_desc = dex->GetMethodDeclaringClassDescriptor(dex_method);
- const bool is_static = (mi->access_flags_ & kAccStatic) != 0;
-
- // Enclose the method in correct class definition.
- if (last_dex_class_desc != dex_class_desc) {
- if (last_dex_class_desc != nullptr) {
- EndClassTag();
- }
- // Write reference tag for the class we are about to declare.
- size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type);
- type_cache_.emplace(std::string(dex_class_desc), reference_tag_offset);
- size_t type_attrib_offset = info_.size();
- info_.WriteRef4(DW_AT_type, 0);
- info_.EndTag();
- // Declare the class that owns this method.
- size_t class_offset = StartClassTag(dex_class_desc);
- info_.UpdateUint32(type_attrib_offset, class_offset);
- info_.WriteFlagPresent(DW_AT_declaration);
- // Check that each class is defined only once.
- bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second;
- CHECK(unique) << "Redefinition of " << dex_class_desc;
- last_dex_class_desc = dex_class_desc;
- }
-
- int start_depth = info_.Depth();
- info_.StartTag(DW_TAG_subprogram);
- WriteName(dex->GetMethodName(dex_method));
- info_.WriteAddr(DW_AT_low_pc, text_address + mi->low_pc_);
- info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(mi->high_pc_-mi->low_pc_));
- std::vector<uint8_t> expr_buffer;
- Expression expr(&expr_buffer);
- expr.WriteOpCallFrameCfa();
- info_.WriteExprLoc(DW_AT_frame_base, expr);
- WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto));
-
- // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not
- // guarantee order or uniqueness so it is safer to iterate over them manually.
- // DecodeDebugLocalInfo might not also be available if there is no debug info.
- std::vector<const char*> param_names = GetParamNames(mi);
- uint32_t arg_reg = 0;
- if (!is_static) {
- info_.StartTag(DW_TAG_formal_parameter);
- WriteName("this");
- info_.WriteFlagPresent(DW_AT_artificial);
- WriteLazyType(dex_class_desc);
- if (dex_code != nullptr) {
- // Write the stack location of the parameter.
- const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
- const bool is64bitValue = false;
- WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_);
- }
- arg_reg++;
- info_.EndTag();
- }
- if (dex_params != nullptr) {
- for (uint32_t i = 0; i < dex_params->Size(); ++i) {
- info_.StartTag(DW_TAG_formal_parameter);
- // Parameter names may not be always available.
- if (i < param_names.size()) {
- WriteName(param_names[i]);
- }
- // Write the type.
- const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
- WriteLazyType(type_desc);
- const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
- if (dex_code != nullptr) {
- // Write the stack location of the parameter.
- const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
- WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_);
- }
- arg_reg += is64bitValue ? 2 : 1;
- info_.EndTag();
- }
- if (dex_code != nullptr) {
- DCHECK_EQ(arg_reg, dex_code->ins_size_);
- }
- }
-
- // Write local variables.
- LocalInfos local_infos;
- if (dex->DecodeDebugLocalInfo(dex_code,
- is_static,
- mi->dex_method_index_,
- LocalInfoCallback,
- &local_infos)) {
- for (const DexFile::LocalInfo& var : local_infos) {
- if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
- info_.StartTag(DW_TAG_variable);
- WriteName(var.name_);
- WriteLazyType(var.descriptor_);
- bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J';
- WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc_,
- var.start_address_, var.end_address_);
- info_.EndTag();
- }
- }
- }
-
- info_.EndTag();
- CHECK_EQ(info_.Depth(), start_depth); // Balanced start/end.
- }
- if (last_dex_class_desc != nullptr) {
- EndClassTag();
- }
- FinishLazyTypes();
- CloseNamespacesAboveDepth(0);
- info_.EndTag(); // DW_TAG_compile_unit
- CHECK_EQ(info_.Depth(), 0);
- std::vector<uint8_t> buffer;
- buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
- // All compilation units share single table which is at the start of .debug_abbrev.
- const size_t debug_abbrev_offset = 0;
- WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
- owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
- }
-
- void Write(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) {
- info_.StartTag(DW_TAG_compile_unit);
- info_.WriteString(DW_AT_producer, "Android dex2oat");
- info_.WriteData1(DW_AT_language, DW_LANG_Java);
-
- // Base class references to be patched at the end.
- std::map<size_t, mirror::Class*> base_class_references;
-
- // Already written declarations or definitions.
- std::map<mirror::Class*, size_t> class_declarations;
-
- std::vector<uint8_t> expr_buffer;
- for (mirror::Class* type : types) {
- if (type->IsPrimitive()) {
- // For primitive types the definition and the declaration is the same.
- if (type->GetPrimitiveType() != Primitive::kPrimVoid) {
- WriteTypeDeclaration(type->GetDescriptor(nullptr));
- }
- } else if (type->IsArrayClass()) {
- mirror::Class* element_type = type->GetComponentType();
- uint32_t component_size = type->GetComponentSize();
- uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value();
- uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
-
- CloseNamespacesAboveDepth(0); // Declare in root namespace.
- info_.StartTag(DW_TAG_array_type);
- std::string descriptor_string;
- WriteLazyType(element_type->GetDescriptor(&descriptor_string));
- WriteLinkageName(type);
- info_.WriteUdata(DW_AT_data_member_location, data_offset);
- info_.StartTag(DW_TAG_subrange_type);
- Expression count_expr(&expr_buffer);
- count_expr.WriteOpPushObjectAddress();
- count_expr.WriteOpPlusUconst(length_offset);
- count_expr.WriteOpDerefSize(4); // Array length is always 32-bit wide.
- info_.WriteExprLoc(DW_AT_count, count_expr);
- info_.EndTag(); // DW_TAG_subrange_type.
- info_.EndTag(); // DW_TAG_array_type.
- } else if (type->IsInterface()) {
- // Skip. Variables cannot have an interface as a dynamic type.
- // We do not expose the interface information to the debugger in any way.
- } else {
- std::string descriptor_string;
- const char* desc = type->GetDescriptor(&descriptor_string);
- size_t class_offset = StartClassTag(desc);
- class_declarations.emplace(type, class_offset);
-
- if (!type->IsVariableSize()) {
- info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize());
- }
-
- WriteLinkageName(type);
-
- if (type->IsObjectClass()) {
- // Generate artificial member which is used to get the dynamic type of variable.
- // The run-time value of this field will correspond to linkage name of some type.
- // We need to do it only once in j.l.Object since all other types inherit it.
- info_.StartTag(DW_TAG_member);
- WriteName(".dynamic_type");
- WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I");
- info_.WriteFlagPresent(DW_AT_artificial);
- // Create DWARF expression to get the value of the methods_ field.
- Expression expr(&expr_buffer);
- // The address of the object has been implicitly pushed on the stack.
- // Dereference the klass_ field of Object (32-bit; possibly poisoned).
- DCHECK_EQ(type->ClassOffset().Uint32Value(), 0u);
- DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Class>), 4u);
- expr.WriteOpDerefSize(4);
- if (kPoisonHeapReferences) {
- expr.WriteOpNeg();
- // DWARF stack is pointer sized. Ensure that the high bits are clear.
- expr.WriteOpConstu(0xFFFFFFFF);
- expr.WriteOpAnd();
- }
- // Add offset to the methods_ field.
- expr.WriteOpPlusUconst(mirror::Class::MethodsOffset().Uint32Value());
- // Top of stack holds the location of the field now.
- info_.WriteExprLoc(DW_AT_data_member_location, expr);
- info_.EndTag(); // DW_TAG_member.
- }
-
- // Base class.
- mirror::Class* base_class = type->GetSuperClass();
- if (base_class != nullptr) {
- info_.StartTag(DW_TAG_inheritance);
- base_class_references.emplace(info_.size(), base_class);
- info_.WriteRef4(DW_AT_type, 0);
- info_.WriteUdata(DW_AT_data_member_location, 0);
- info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
- info_.EndTag(); // DW_TAG_inheritance.
- }
-
- // Member variables.
- for (uint32_t i = 0, count = type->NumInstanceFields(); i < count; ++i) {
- ArtField* field = type->GetInstanceField(i);
- info_.StartTag(DW_TAG_member);
- WriteName(field->GetName());
- WriteLazyType(field->GetTypeDescriptor());
- info_.WriteUdata(DW_AT_data_member_location, field->GetOffset().Uint32Value());
- uint32_t access_flags = field->GetAccessFlags();
- if (access_flags & kAccPublic) {
- info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
- } else if (access_flags & kAccProtected) {
- info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_protected);
- } else if (access_flags & kAccPrivate) {
- info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
- }
- info_.EndTag(); // DW_TAG_member.
- }
-
- if (type->IsStringClass()) {
- // Emit debug info about an artifical class member for java.lang.String which represents
- // the first element of the data stored in a string instance. Consumers of the debug
- // info will be able to read the content of java.lang.String based on the count (real
- // field) and based on the location of this data member.
- info_.StartTag(DW_TAG_member);
- WriteName("value");
- // We don't support fields with C like array types so we just say its type is java char.
- WriteLazyType("C"); // char.
- info_.WriteUdata(DW_AT_data_member_location,
- mirror::String::ValueOffset().Uint32Value());
- info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
- info_.EndTag(); // DW_TAG_member.
- }
-
- EndClassTag();
- }
- }
-
- // Write base class declarations.
- for (const auto& base_class_reference : base_class_references) {
- size_t reference_offset = base_class_reference.first;
- mirror::Class* base_class = base_class_reference.second;
- const auto& it = class_declarations.find(base_class);
- if (it != class_declarations.end()) {
- info_.UpdateUint32(reference_offset, it->second);
- } else {
- // Declare base class. We can not use the standard WriteLazyType
- // since we want to avoid the DW_TAG_reference_tag wrapping.
- std::string tmp_storage;
- const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
- size_t base_class_declaration_offset = StartClassTag(base_class_desc);
- info_.WriteFlagPresent(DW_AT_declaration);
- WriteLinkageName(base_class);
- EndClassTag();
- class_declarations.emplace(base_class, base_class_declaration_offset);
- info_.UpdateUint32(reference_offset, base_class_declaration_offset);
- }
- }
-
- FinishLazyTypes();
- CloseNamespacesAboveDepth(0);
- info_.EndTag(); // DW_TAG_compile_unit.
- CHECK_EQ(info_.Depth(), 0);
- std::vector<uint8_t> buffer;
- buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
- // All compilation units share single table which is at the start of .debug_abbrev.
- const size_t debug_abbrev_offset = 0;
- WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
- owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
- }
-
- // Linkage name uniquely identifies type.
- // It is used to determine the dynamic type of objects.
- // We use the methods_ field of class since it is unique and it is not moved by the GC.
- void WriteLinkageName(mirror::Class* type) SHARED_REQUIRES(Locks::mutator_lock_) {
- auto* methods_ptr = type->GetMethodsPtr();
- if (methods_ptr == nullptr) {
- // Some types might have no methods. Allocate empty array instead.
- LinearAlloc* allocator = Runtime::Current()->GetLinearAlloc();
- void* storage = allocator->Alloc(Thread::Current(), sizeof(LengthPrefixedArray<ArtMethod>));
- methods_ptr = new (storage) LengthPrefixedArray<ArtMethod>(0);
- type->SetMethodsPtr(methods_ptr, 0, 0);
- DCHECK(type->GetMethodsPtr() != nullptr);
- }
- char name[32];
- snprintf(name, sizeof(name), "0x%" PRIXPTR, reinterpret_cast<uintptr_t>(methods_ptr));
- info_.WriteString(DW_AT_linkage_name, name);
- }
-
- // Write table into .debug_loc which describes location of dex register.
- // The dex register might be valid only at some points and it might
- // move between machine registers and stack.
- void WriteRegLocation(const MethodDebugInfo* method_info,
- uint16_t vreg,
- bool is64bitValue,
- uint32_t compilation_unit_low_pc,
- uint32_t dex_pc_low = 0,
- uint32_t dex_pc_high = 0xFFFFFFFF) {
- using Kind = DexRegisterLocation::Kind;
- if (!IsFromOptimizingCompiler(method_info)) {
- return;
- }
-
- Writer<> debug_loc(&owner_->debug_loc_);
- Writer<> debug_ranges(&owner_->debug_ranges_);
- info_.WriteSecOffset(DW_AT_location, debug_loc.size());
- info_.WriteSecOffset(DW_AT_start_scope, debug_ranges.size());
-
- std::vector<VariableLocation> variable_locations = GetVariableLocations(
- method_info,
- vreg,
- is64bitValue,
- dex_pc_low,
- dex_pc_high);
-
- // Write .debug_loc entries.
- const InstructionSet isa = owner_->builder_->GetIsa();
- const bool is64bit = Is64BitInstructionSet(isa);
- std::vector<uint8_t> expr_buffer;
- for (const VariableLocation& variable_location : variable_locations) {
- // Translate dex register location to DWARF expression.
- // Note that 64-bit value might be split to two distinct locations.
- // (for example, two 32-bit machine registers, or even stack and register)
- Expression expr(&expr_buffer);
- DexRegisterLocation reg_lo = variable_location.reg_lo;
- DexRegisterLocation reg_hi = variable_location.reg_hi;
- for (int piece = 0; piece < (is64bitValue ? 2 : 1); piece++) {
- DexRegisterLocation reg_loc = (piece == 0 ? reg_lo : reg_hi);
- const Kind kind = reg_loc.GetKind();
- const int32_t value = reg_loc.GetValue();
- if (kind == Kind::kInStack) {
- const size_t frame_size = method_info->compiled_method_->GetFrameSizeInBytes();
- // The stack offset is relative to SP. Make it relative to CFA.
- expr.WriteOpFbreg(value - frame_size);
- if (piece == 0 && reg_hi.GetKind() == Kind::kInStack &&
- reg_hi.GetValue() == value + 4) {
- break; // the high word is correctly implied by the low word.
- }
- } else if (kind == Kind::kInRegister) {
- expr.WriteOpReg(GetDwarfCoreReg(isa, value).num());
- if (piece == 0 && reg_hi.GetKind() == Kind::kInRegisterHigh &&
- reg_hi.GetValue() == value) {
- break; // the high word is correctly implied by the low word.
- }
- } else if (kind == Kind::kInFpuRegister) {
- if ((isa == kArm || isa == kThumb2) &&
- piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister &&
- reg_hi.GetValue() == value + 1 && value % 2 == 0) {
- // Translate S register pair to D register (e.g. S4+S5 to D2).
- expr.WriteOpReg(Reg::ArmDp(value / 2).num());
- break;
- }
- expr.WriteOpReg(GetDwarfFpReg(isa, value).num());
- if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh &&
- reg_hi.GetValue() == reg_lo.GetValue()) {
- break; // the high word is correctly implied by the low word.
- }
- } else if (kind == Kind::kConstant) {
- expr.WriteOpConsts(value);
- expr.WriteOpStackValue();
- } else if (kind == Kind::kNone) {
- break;
- } else {
- // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
- // kInRegisterHigh and kInFpuRegisterHigh should be handled by
- // the special cases above and they should not occur alone.
- LOG(ERROR) << "Unexpected register location kind: "
- << DexRegisterLocation::PrettyDescriptor(kind);
- break;
- }
- if (is64bitValue) {
- // Write the marker which is needed by split 64-bit values.
- // This code is skipped by the special cases.
- expr.WriteOpPiece(4);
- }
- }
-
- if (expr.size() > 0) {
- if (is64bit) {
- debug_loc.PushUint64(variable_location.low_pc - compilation_unit_low_pc);
- debug_loc.PushUint64(variable_location.high_pc - compilation_unit_low_pc);
- } else {
- debug_loc.PushUint32(variable_location.low_pc - compilation_unit_low_pc);
- debug_loc.PushUint32(variable_location.high_pc - compilation_unit_low_pc);
- }
- // Write the expression.
- debug_loc.PushUint16(expr.size());
- debug_loc.PushData(expr.data());
- } else {
- // Do not generate .debug_loc if the location is not known.
- }
- }
- // Write end-of-list entry.
- if (is64bit) {
- debug_loc.PushUint64(0);
- debug_loc.PushUint64(0);
- } else {
- debug_loc.PushUint32(0);
- debug_loc.PushUint32(0);
- }
-
- // Write .debug_ranges entries.
- // This includes ranges where the variable is in scope but the location is not known.
- for (size_t i = 0; i < variable_locations.size(); i++) {
- uint32_t low_pc = variable_locations[i].low_pc;
- uint32_t high_pc = variable_locations[i].high_pc;
- while (i + 1 < variable_locations.size() && variable_locations[i+1].low_pc == high_pc) {
- // Merge address range with the next entry.
- high_pc = variable_locations[++i].high_pc;
- }
- if (is64bit) {
- debug_ranges.PushUint64(low_pc - compilation_unit_low_pc);
- debug_ranges.PushUint64(high_pc - compilation_unit_low_pc);
- } else {
- debug_ranges.PushUint32(low_pc - compilation_unit_low_pc);
- debug_ranges.PushUint32(high_pc - compilation_unit_low_pc);
- }
- }
- // Write end-of-list entry.
- if (is64bit) {
- debug_ranges.PushUint64(0);
- debug_ranges.PushUint64(0);
- } else {
- debug_ranges.PushUint32(0);
- debug_ranges.PushUint32(0);
- }
- }
-
- // Some types are difficult to define as we go since they need
- // to be enclosed in the right set of namespaces. Therefore we
- // just define all types lazily at the end of compilation unit.
- void WriteLazyType(const char* type_descriptor) {
- if (type_descriptor != nullptr && type_descriptor[0] != 'V') {
- lazy_types_.emplace(std::string(type_descriptor), info_.size());
- info_.WriteRef4(DW_AT_type, 0);
- }
- }
-
- void FinishLazyTypes() {
- for (const auto& lazy_type : lazy_types_) {
- info_.UpdateUint32(lazy_type.second, WriteTypeDeclaration(lazy_type.first));
- }
- lazy_types_.clear();
- }
-
- private:
- void WriteName(const char* name) {
- if (name != nullptr) {
- info_.WriteString(DW_AT_name, name);
- }
- }
-
- // Convert dex type descriptor to DWARF.
- // Returns offset in the compilation unit.
- size_t WriteTypeDeclaration(const std::string& desc) {
- DCHECK(!desc.empty());
- const auto& it = type_cache_.find(desc);
- if (it != type_cache_.end()) {
- return it->second;
- }
-
- size_t offset;
- if (desc[0] == 'L') {
- // Class type. For example: Lpackage/name;
- size_t class_offset = StartClassTag(desc.c_str());
- info_.WriteFlagPresent(DW_AT_declaration);
- EndClassTag();
- // Reference to the class type.
- offset = info_.StartTag(DW_TAG_reference_type);
- info_.WriteRef(DW_AT_type, class_offset);
- info_.EndTag();
- } else if (desc[0] == '[') {
- // Array type.
- size_t element_type = WriteTypeDeclaration(desc.substr(1));
- CloseNamespacesAboveDepth(0); // Declare in root namespace.
- size_t array_type = info_.StartTag(DW_TAG_array_type);
- info_.WriteFlagPresent(DW_AT_declaration);
- info_.WriteRef(DW_AT_type, element_type);
- info_.EndTag();
- offset = info_.StartTag(DW_TAG_reference_type);
- info_.WriteRef4(DW_AT_type, array_type);
- info_.EndTag();
- } else {
- // Primitive types.
- DCHECK_EQ(desc.size(), 1u);
-
- const char* name;
- uint32_t encoding;
- uint32_t byte_size;
- switch (desc[0]) {
- case 'B':
- name = "byte";
- encoding = DW_ATE_signed;
- byte_size = 1;
- break;
- case 'C':
- name = "char";
- encoding = DW_ATE_UTF;
- byte_size = 2;
- break;
- case 'D':
- name = "double";
- encoding = DW_ATE_float;
- byte_size = 8;
- break;
- case 'F':
- name = "float";
- encoding = DW_ATE_float;
- byte_size = 4;
- break;
- case 'I':
- name = "int";
- encoding = DW_ATE_signed;
- byte_size = 4;
- break;
- case 'J':
- name = "long";
- encoding = DW_ATE_signed;
- byte_size = 8;
- break;
- case 'S':
- name = "short";
- encoding = DW_ATE_signed;
- byte_size = 2;
- break;
- case 'Z':
- name = "boolean";
- encoding = DW_ATE_boolean;
- byte_size = 1;
- break;
- case 'V':
- LOG(FATAL) << "Void type should not be encoded";
- UNREACHABLE();
- default:
- LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\"";
- UNREACHABLE();
- }
- CloseNamespacesAboveDepth(0); // Declare in root namespace.
- offset = info_.StartTag(DW_TAG_base_type);
- WriteName(name);
- info_.WriteData1(DW_AT_encoding, encoding);
- info_.WriteData1(DW_AT_byte_size, byte_size);
- info_.EndTag();
- }
-
- type_cache_.emplace(desc, offset);
- return offset;
- }
-
- // Start DW_TAG_class_type tag nested in DW_TAG_namespace tags.
- // Returns offset of the class tag in the compilation unit.
- size_t StartClassTag(const char* desc) {
- std::string name = SetNamespaceForClass(desc);
- size_t offset = info_.StartTag(DW_TAG_class_type);
- WriteName(name.c_str());
- return offset;
- }
-
- void EndClassTag() {
- info_.EndTag();
- }
-
- // Set the current namespace nesting to one required by the given class.
- // Returns the class name with namespaces, 'L', and ';' stripped.
- std::string SetNamespaceForClass(const char* desc) {
- DCHECK(desc != nullptr && desc[0] == 'L');
- desc++; // Skip the initial 'L'.
- size_t depth = 0;
- for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) {
- // Check whether the name at this depth is already what we need.
- if (depth < current_namespace_.size()) {
- const std::string& name = current_namespace_[depth];
- if (name.compare(0, name.size(), desc, end - desc) == 0) {
- continue;
- }
- }
- // Otherwise we need to open a new namespace tag at this depth.
- CloseNamespacesAboveDepth(depth);
- info_.StartTag(DW_TAG_namespace);
- std::string name(desc, end - desc);
- WriteName(name.c_str());
- current_namespace_.push_back(std::move(name));
- }
- CloseNamespacesAboveDepth(depth);
- return std::string(desc, strchr(desc, ';') - desc);
- }
-
- // Close namespace tags to reach the given nesting depth.
- void CloseNamespacesAboveDepth(size_t depth) {
- DCHECK_LE(depth, current_namespace_.size());
- while (current_namespace_.size() > depth) {
- info_.EndTag();
- current_namespace_.pop_back();
- }
- }
-
- // For access to the ELF sections.
- DebugInfoWriter<ElfTypes>* owner_;
- // Temporary buffer to create and store the entries.
- DebugInfoEntryWriter<> info_;
- // Cache of already translated type descriptors.
- std::map<std::string, size_t> type_cache_; // type_desc -> definition_offset.
- // 32-bit references which need to be resolved to a type later.
- // Given type may be used multiple times. Therefore we need a multimap.
- std::multimap<std::string, size_t> lazy_types_; // type_desc -> patch_offset.
- // The current set of open namespace tags which are active and not closed yet.
- std::vector<std::string> current_namespace_;
- };
-
- public:
- explicit DebugInfoWriter(ElfBuilder<ElfTypes>* builder)
- : builder_(builder),
- debug_abbrev_(&debug_abbrev_buffer_) {
- }
-
- void Start() {
- builder_->GetDebugInfo()->Start();
- }
-
- void WriteCompilationUnit(const CompilationUnit& compilation_unit) {
- CompilationUnitWriter writer(this);
- writer.Write(compilation_unit);
- }
-
- void WriteTypes(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) {
- CompilationUnitWriter writer(this);
- writer.Write(types);
- }
-
- void End(bool write_oat_patches) {
- builder_->GetDebugInfo()->End();
- if (write_oat_patches) {
- builder_->WritePatches(".debug_info.oat_patches",
- ArrayRef<const uintptr_t>(debug_info_patches_));
- }
- builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_);
- if (!debug_loc_.empty()) {
- builder_->WriteSection(".debug_loc", &debug_loc_);
- }
- if (!debug_ranges_.empty()) {
- builder_->WriteSection(".debug_ranges", &debug_ranges_);
- }
- }
-
- private:
- ElfBuilder<ElfTypes>* builder_;
- std::vector<uintptr_t> debug_info_patches_;
- std::vector<uint8_t> debug_abbrev_buffer_;
- DebugAbbrevWriter<> debug_abbrev_;
- std::vector<uint8_t> debug_loc_;
- std::vector<uint8_t> debug_ranges_;
-
- std::unordered_set<const char*> defined_dex_classes_; // For CHECKs only.
-};
-
-template<typename ElfTypes>
-class DebugLineWriter {
- typedef typename ElfTypes::Addr Elf_Addr;
-
- public:
- explicit DebugLineWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) {
- }
-
- void Start() {
- builder_->GetDebugLine()->Start();
- }
-
- // Write line table for given set of methods.
- // Returns the number of bytes written.
- size_t WriteCompilationUnit(CompilationUnit& compilation_unit) {
- const bool is64bit = Is64BitInstructionSet(builder_->GetIsa());
- const Elf_Addr text_address = builder_->GetText()->Exists()
- ? builder_->GetText()->GetAddress()
- : 0;
-
- compilation_unit.debug_line_offset_ = builder_->GetDebugLine()->GetSize();
-
- std::vector<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;
- int code_factor_bits_ = 0;
- int dwarf_isa = -1;
- switch (builder_->GetIsa()) {
- case kArm: // arm actually means thumb2.
- case kThumb2:
- code_factor_bits_ = 1; // 16-bit instuctions
- dwarf_isa = 1; // DW_ISA_ARM_thumb.
- break;
- case kArm64:
- case kMips:
- case kMips64:
- code_factor_bits_ = 2; // 32-bit instructions
- break;
- case kNone:
- case kX86:
- case kX86_64:
- break;
- }
- DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_);
- for (const MethodDebugInfo* mi : compilation_unit.methods_) {
- // Ignore function if we have already generated line table for the same address.
- // It would confuse the debugger and the DWARF specification forbids it.
- if (mi->deduped_) {
- continue;
- }
-
- ArrayRef<const SrcMapElem> src_mapping_table;
- std::vector<SrcMapElem> src_mapping_table_from_stack_maps;
- if (IsFromOptimizingCompiler(mi)) {
- // Use stack maps to create mapping table from pc to dex.
- const CodeInfo code_info(mi->compiled_method_->GetVmapTable().data());
- const StackMapEncoding encoding = code_info.ExtractEncoding();
- for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
- StackMap stack_map = code_info.GetStackMapAt(s, encoding);
- DCHECK(stack_map.IsValid());
- // Emit only locations where we have local-variable information.
- // In particular, skip mappings inside the prologue.
- if (stack_map.HasDexRegisterMap(encoding)) {
- const uint32_t pc = stack_map.GetNativePcOffset(encoding);
- const int32_t dex = stack_map.GetDexPc(encoding);
- src_mapping_table_from_stack_maps.push_back({pc, dex});
- }
- }
- std::sort(src_mapping_table_from_stack_maps.begin(),
- src_mapping_table_from_stack_maps.end());
- src_mapping_table = ArrayRef<const SrcMapElem>(src_mapping_table_from_stack_maps);
- } else {
- // Use the mapping table provided by the quick compiler.
- src_mapping_table = mi->compiled_method_->GetSrcMappingTable();
- }
-
- if (src_mapping_table.empty()) {
- continue;
- }
-
- Elf_Addr method_address = text_address + mi->low_pc_;
-
- PositionInfos position_infos;
- const DexFile* dex = mi->dex_file_;
- if (!dex->DecodeDebugPositionInfo(mi->code_item_, PositionInfoCallback, &position_infos)) {
- continue;
- }
-
- if (position_infos.empty()) {
- continue;
- }
-
- opcodes.SetAddress(method_address);
- if (dwarf_isa != -1) {
- opcodes.SetISA(dwarf_isa);
- }
-
- // Get and deduplicate directory and filename.
- int file_index = 0; // 0 - primary source file of the compilation.
- auto& dex_class_def = dex->GetClassDef(mi->class_def_index_);
- const char* source_file = dex->GetSourceFile(dex_class_def);
- if (source_file != nullptr) {
- std::string file_name(source_file);
- size_t file_name_slash = file_name.find_last_of('/');
- std::string class_name(dex->GetClassDescriptor(dex_class_def));
- size_t class_name_slash = class_name.find_last_of('/');
- std::string full_path(file_name);
-
- // Guess directory from package name.
- int directory_index = 0; // 0 - current directory of the compilation.
- if (file_name_slash == std::string::npos && // Just filename.
- class_name.front() == 'L' && // Type descriptor for a class.
- class_name_slash != std::string::npos) { // Has package name.
- std::string package_name = class_name.substr(1, class_name_slash - 1);
- auto it = directories_map.find(package_name);
- if (it == directories_map.end()) {
- directory_index = 1 + directories.size();
- directories_map.emplace(package_name, directory_index);
- directories.push_back(package_name);
- } else {
- directory_index = it->second;
- }
- full_path = package_name + "/" + file_name;
- }
-
- // Add file entry.
- auto it2 = files_map.find(full_path);
- if (it2 == files_map.end()) {
- file_index = 1 + files.size();
- files_map.emplace(full_path, file_index);
- files.push_back(FileEntry {
- file_name,
- directory_index,
- 0, // Modification time - NA.
- 0, // File size - NA.
- });
- } else {
- file_index = it2->second;
- }
- }
- opcodes.SetFile(file_index);
-
- // Generate mapping opcodes from PC to Java lines.
- if (file_index != 0) {
- bool first = true;
- for (SrcMapElem pc2dex : src_mapping_table) {
- uint32_t pc = pc2dex.from_;
- int dex_pc = pc2dex.to_;
- // Find mapping with address with is greater than our dex pc; then go back one step.
- auto ub = std::upper_bound(position_infos.begin(), position_infos.end(), dex_pc,
- [](uint32_t address, const DexFile::PositionInfo& entry) {
- return address < entry.address_;
- });
- if (ub != position_infos.begin()) {
- int line = (--ub)->line_;
- if (first) {
- first = false;
- if (pc > 0) {
- // Assume that any preceding code is prologue.
- int first_line = position_infos.front().line_;
- // Prologue is not a sensible place for a breakpoint.
- opcodes.NegateStmt();
- opcodes.AddRow(method_address, first_line);
- opcodes.NegateStmt();
- opcodes.SetPrologueEnd();
- }
- opcodes.AddRow(method_address + pc, line);
- } else if (line != opcodes.CurrentLine()) {
- opcodes.AddRow(method_address + pc, line);
- }
- }
- }
- } else {
- // line 0 - instruction cannot be attributed to any source line.
- opcodes.AddRow(method_address, 0);
- }
-
- opcodes.AdvancePC(text_address + mi->high_pc_);
- opcodes.EndSequence();
- }
- std::vector<uint8_t> buffer;
- buffer.reserve(opcodes.data()->size() + KB);
- size_t offset = builder_->GetDebugLine()->GetSize();
- WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches);
- builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
- return buffer.size();
- }
-
- void End(bool write_oat_patches) {
- builder_->GetDebugLine()->End();
- if (write_oat_patches) {
- builder_->WritePatches(".debug_line.oat_patches",
- ArrayRef<const uintptr_t>(debug_line_patches));
- }
- }
-
- private:
- ElfBuilder<ElfTypes>* builder_;
- std::vector<uintptr_t> debug_line_patches;
-};
-
-template<typename ElfTypes>
-static void WriteDebugSections(ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- bool write_oat_patches) {
- // Group the methods into compilation units based on source file.
- std::vector<CompilationUnit> compilation_units;
- const char* last_source_file = nullptr;
- for (const MethodDebugInfo& mi : method_infos) {
- 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(CompilationUnit());
- }
- CompilationUnit& cu = compilation_units.back();
- cu.methods_.push_back(&mi);
- cu.low_pc_ = std::min(cu.low_pc_, mi.low_pc_);
- cu.high_pc_ = std::max(cu.high_pc_, mi.high_pc_);
- last_source_file = source_file;
- }
-
- // Write .debug_line section.
- if (!compilation_units.empty()) {
- DebugLineWriter<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()) {
- DebugInfoWriter<ElfTypes> info_writer(builder);
- info_writer.Start();
- for (const auto& compilation_unit : compilation_units) {
- info_writer.WriteCompilationUnit(compilation_unit);
- }
- info_writer.End(write_oat_patches);
- }
-}
-
-template <typename ElfTypes>
-static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- bool with_signature) {
- bool generated_mapping_symbol = false;
- auto* strtab = builder->GetStrTab();
- auto* symtab = builder->GetSymTab();
-
- if (method_infos.empty()) {
- return;
- }
-
- // Find all addresses (low_pc) which contain deduped methods.
- // The first instance of method is not marked deduped_, but the rest is.
- std::unordered_set<uint32_t> deduped_addresses;
- for (const MethodDebugInfo& info : method_infos) {
- if (info.deduped_) {
- deduped_addresses.insert(info.low_pc_);
- }
- }
-
- strtab->Start();
- strtab->Write(""); // strtab should start with empty string.
- std::string last_name;
- size_t last_name_offset = 0;
- for (const MethodDebugInfo& info : method_infos) {
- if (info.deduped_) {
- continue; // Add symbol only for the first instance.
- }
- std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, with_signature);
- if (deduped_addresses.find(info.low_pc_) != deduped_addresses.end()) {
- name += " [DEDUPED]";
- }
- // If we write method names without signature, we might see the same name multiple times.
- size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
-
- const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr;
- const bool is_relative = (text != nullptr);
- uint32_t low_pc = info.low_pc_;
- // Add in code delta, e.g., thumb bit 0 for Thumb2 code.
- low_pc += info.compiled_method_->CodeDelta();
- symtab->Add(name_offset,
- text,
- low_pc,
- is_relative,
- info.high_pc_ - info.low_pc_,
- STB_GLOBAL,
- STT_FUNC);
-
- // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
- // instructions, so that disassembler tools can correctly disassemble.
- // Note that even if we generate just a single mapping symbol, ARM's Streamline
- // requires it to match function symbol. Just address 0 does not work.
- if (info.compiled_method_->GetInstructionSet() == kThumb2) {
- if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) {
- symtab->Add(strtab->Write("$t"), text, info.low_pc_ & ~1,
- is_relative, 0, STB_LOCAL, STT_NOTYPE);
- generated_mapping_symbol = true;
- }
- }
-
- last_name = std::move(name);
- last_name_offset = name_offset;
- }
- strtab->End();
-
- // Symbols are buffered and written after names (because they are smaller).
- // We could also do two passes in this function to avoid the buffering.
- symtab->Start();
- symtab->Write();
- symtab->End();
-}
-
-template <typename ElfTypes>
-void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- CFIFormat cfi_format,
- bool write_oat_patches) {
- // Add methods to .symtab.
- WriteDebugSymbols(builder, method_infos, true /* with_signature */);
- // Generate CFI (stack unwinding information).
- WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
- // Write DWARF .debug_* sections.
- WriteDebugSections(builder, method_infos, write_oat_patches);
-}
-
-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>
-std::vector<uint8_t> MakeMiniDebugInfoInternal(
- InstructionSet isa,
- 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, &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, 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;
-}
-
-std::vector<uint8_t> MakeMiniDebugInfo(
- InstructionSet isa,
- size_t rodata_size,
- size_t text_size,
- const ArrayRef<const MethodDebugInfo>& method_infos) {
- if (Is64BitInstructionSet(isa)) {
- return MakeMiniDebugInfoInternal<ElfTypes64>(isa, rodata_size, text_size, method_infos);
- } else {
- return MakeMiniDebugInfoInternal<ElfTypes32>(isa, rodata_size, text_size, method_infos);
- }
-}
-
-template <typename ElfTypes>
-static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal(
- const dwarf::MethodDebugInfo& method_info) {
- const InstructionSet isa = method_info.compiled_method_->GetInstructionSet();
- std::vector<uint8_t> buffer;
- buffer.reserve(KB);
- VectorOutputStream out("Debug ELF file", &buffer);
- std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &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(),
- ArrayRef<const MethodDebugInfo>(&method_info, 1),
- DW_DEBUG_FRAME_FORMAT,
- false /* write_oat_patches */);
- builder->End();
- CHECK(builder->Good());
- // Make a copy of the buffer. We want to shrink it anyway.
- uint8_t* result = new uint8_t[buffer.size()];
- CHECK(result != nullptr);
- memcpy(result, buffer.data(), buffer.size());
- return ArrayRef<const uint8_t>(result, buffer.size());
-}
-
-ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info) {
- const InstructionSet isa = method_info.compiled_method_->GetInstructionSet();
- if (Is64BitInstructionSet(isa)) {
- return WriteDebugElfFileForMethodInternal<ElfTypes64>(method_info);
- } else {
- return WriteDebugElfFileForMethodInternal<ElfTypes32>(method_info);
- }
-}
-
-template <typename ElfTypes>
-static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal(
- const InstructionSet isa, const ArrayRef<mirror::Class*>& types)
- SHARED_REQUIRES(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, &out));
- // No program headers since the ELF file is not linked and has no allocated sections.
- builder->Start(false /* write_program_headers */);
- DebugInfoWriter<ElfTypes> info_writer(builder.get());
- info_writer.Start();
- info_writer.WriteTypes(types);
- info_writer.End(false /* write_oat_patches */);
-
- builder->End();
- CHECK(builder->Good());
- // Make a copy of the buffer. We want to shrink it anyway.
- uint8_t* result = new uint8_t[buffer.size()];
- CHECK(result != nullptr);
- memcpy(result, buffer.data(), buffer.size());
- return ArrayRef<const uint8_t>(result, buffer.size());
-}
-
-ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
- const ArrayRef<mirror::Class*>& types) {
- if (Is64BitInstructionSet(isa)) {
- return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, types);
- } else {
- return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, types);
- }
-}
-
-// Explicit instantiations
-template void WriteDebugInfo<ElfTypes32>(
- ElfBuilder<ElfTypes32>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- CFIFormat cfi_format,
- bool write_oat_patches);
-template void WriteDebugInfo<ElfTypes64>(
- ElfBuilder<ElfTypes64>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- CFIFormat cfi_format,
- bool write_oat_patches);
-
-} // namespace dwarf
-} // namespace art
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 864e1b1bed..1d71e572d7 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -23,12 +23,12 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "compiled_method.h"
+#include "debug/elf_debug_writer.h"
+#include "debug/method_debug_info.h"
#include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
#include "elf.h"
#include "elf_builder.h"
#include "elf_utils.h"
-#include "elf_writer_debug.h"
#include "globals.h"
#include "leb128.h"
#include "linker/buffered_output_stream.h"
@@ -53,7 +53,7 @@ class DebugInfoTask : public Task {
DebugInfoTask(InstructionSet isa,
size_t rodata_section_size,
size_t text_section_size,
- const ArrayRef<const dwarf::MethodDebugInfo>& method_infos)
+ const ArrayRef<const debug::MethodDebugInfo>& method_infos)
: isa_(isa),
rodata_section_size_(rodata_section_size),
text_section_size_(text_section_size),
@@ -61,7 +61,7 @@ class DebugInfoTask : public Task {
}
void Run(Thread*) {
- result_ = dwarf::MakeMiniDebugInfo(isa_,
+ result_ = debug::MakeMiniDebugInfo(isa_,
rodata_section_size_,
text_section_size_,
method_infos_);
@@ -75,7 +75,7 @@ class DebugInfoTask : public Task {
InstructionSet isa_;
size_t rodata_section_size_;
size_t text_section_size_;
- const ArrayRef<const dwarf::MethodDebugInfo>& method_infos_;
+ const ArrayRef<const debug::MethodDebugInfo>& method_infos_;
std::vector<uint8_t> result_;
};
@@ -90,14 +90,14 @@ class ElfWriterQuick FINAL : public ElfWriter {
void Start() OVERRIDE;
void PrepareDebugInfo(size_t rodata_section_size,
size_t text_section_size,
- const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) OVERRIDE;
+ const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
OutputStream* StartRoData() OVERRIDE;
void EndRoData(OutputStream* rodata) OVERRIDE;
OutputStream* StartText() OVERRIDE;
void EndText(OutputStream* text) OVERRIDE;
void SetBssSize(size_t bss_size) OVERRIDE;
void WriteDynamicSection() OVERRIDE;
- void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) OVERRIDE;
+ void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) OVERRIDE;
bool End() OVERRIDE;
@@ -188,7 +188,7 @@ template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(
size_t rodata_section_size,
size_t text_section_size,
- const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) {
+ const ArrayRef<const debug::MethodDebugInfo>& method_infos) {
if (!method_infos.empty() && compiler_options_->GetGenerateMiniDebugInfo()) {
// Prepare the mini-debug-info in background while we do other I/O.
Thread* self = Thread::Current();
@@ -206,11 +206,11 @@ void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(
template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::WriteDebugInfo(
- const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) {
+ const ArrayRef<const debug::MethodDebugInfo>& method_infos) {
if (!method_infos.empty()) {
if (compiler_options_->GetGenerateDebugInfo()) {
// Generate all the debug information we can.
- dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */);
+ debug::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */);
}
if (compiler_options_->GetGenerateMiniDebugInfo()) {
// Wait for the mini-debug-info generation to finish and write it to disk.
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index a5a7796614..4920f9baa5 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -23,7 +23,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker-inl.h"
#include "common_compiler_test.h"
-#include "dwarf/method_debug_info.h"
+#include "debug/method_debug_info.h"
#include "elf_writer.h"
#include "elf_writer_quick.h"
#include "gc/space/image_space.h"
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 68f4783741..d2bf6c07c8 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -16,19 +16,19 @@
#include "jit_compiler.h"
-#include "art_method-inl.h"
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
+#include "art_method-inl.h"
#include "base/stringpiece.h"
#include "base/time_utils.h"
#include "base/timing_logger.h"
#include "base/unix_file/fd_file.h"
#include "compiler_callbacks.h"
+#include "debug/elf_debug_writer.h"
#include "dex/pass_manager.h"
#include "dex/quick_compiler_callbacks.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
-#include "elf_writer_debug.h"
#include "jit/debugger_interface.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
@@ -74,7 +74,7 @@ extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t cou
DCHECK(jit_compiler != nullptr);
if (jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo()) {
const ArrayRef<mirror::Class*> types_array(types, count);
- ArrayRef<const uint8_t> elf_file = dwarf::WriteDebugElfFileForClasses(kRuntimeISA, types_array);
+ ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForClasses(kRuntimeISA, types_array);
CreateJITCodeEntry(std::unique_ptr<const uint8_t[]>(elf_file.data()), elf_file.size());
}
}
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index cff2f471bf..894d29ee99 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -21,20 +21,20 @@
#include "common_compiler_test.h"
#include "compiled_method.h"
#include "compiler.h"
+#include "debug/method_debug_info.h"
#include "dex/pass_manager.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex/quick_compiler_callbacks.h"
#include "dex/verification_results.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
#include "elf_writer.h"
#include "elf_writer_quick.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "linker/vector_output_stream.h"
#include "mirror/class-inl.h"
-#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
#include "oat_file-inl.h"
#include "oat_writer.h"
#include "scoped_thread_state_change.h"
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 90ac499ba2..47dcfd56f8 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -29,11 +29,11 @@
#include "class_linker.h"
#include "compiled_class.h"
#include "compiled_method.h"
-#include "dex_file-inl.h"
+#include "debug/method_debug_info.h"
#include "dex/verification_results.h"
+#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
#include "gc/space/image_space.h"
#include "gc/space/space.h"
#include "handle_scope-inl.h"
@@ -811,7 +811,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
// 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;
- writer_->method_info_.push_back(dwarf::MethodDebugInfo {
+ writer_->method_info_.push_back(debug::MethodDebugInfo {
dex_file_,
class_def_index_,
it.GetMemberIndex(),
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 14c6d5054a..5a55fc6c95 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -43,9 +43,9 @@ class TimingLogger;
class TypeLookupTable;
class ZipEntry;
-namespace dwarf {
+namespace debug {
struct MethodDebugInfo;
-} // namespace dwarf
+} // namespace debug
// OatHeader variable length with count of D OatDexFiles
//
@@ -193,8 +193,8 @@ class OatWriter {
~OatWriter();
- ArrayRef<const dwarf::MethodDebugInfo> GetMethodDebugInfo() const {
- return ArrayRef<const dwarf::MethodDebugInfo>(method_info_);
+ ArrayRef<const debug::MethodDebugInfo> GetMethodDebugInfo() const {
+ return ArrayRef<const debug::MethodDebugInfo>(method_info_);
}
const CompilerDriver* GetCompilerDriver() {
@@ -289,7 +289,7 @@ class OatWriter {
// We need this because we keep plain pointers to the strings' c_str().
std::list<std::string> zipped_dex_file_locations_;
- dchecked_vector<dwarf::MethodDebugInfo> method_info_;
+ dchecked_vector<debug::MethodDebugInfo> method_info_;
const CompilerDriver* compiler_driver_;
ImageWriter* image_writer_;
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 96a3c3c2f1..00a158b10a 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1580,6 +1580,251 @@ void IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) {
__ Bind(slow_path->GetExitLabel());
}
+static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ // If the graph is debuggable, all callee-saved floating-point registers are blocked by
+ // the code generator. Furthermore, the register allocator creates fixed live intervals
+ // for all caller-saved registers because we are doing a function call. As a result, if
+ // the input and output locations are unallocated, the register allocator runs out of
+ // registers and fails; however, a debuggable graph is not the common case.
+ if (invoke->GetBlock()->GetGraph()->IsDebuggable()) {
+ return;
+ }
+
+ DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
+ DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
+ DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
+
+ LocationSummary* const locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ const InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ // Native code uses the soft float ABI.
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+}
+
+static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ // If the graph is debuggable, all callee-saved floating-point registers are blocked by
+ // the code generator. Furthermore, the register allocator creates fixed live intervals
+ // for all caller-saved registers because we are doing a function call. As a result, if
+ // the input and output locations are unallocated, the register allocator runs out of
+ // registers and fails; however, a debuggable graph is not the common case.
+ if (invoke->GetBlock()->GetGraph()->IsDebuggable()) {
+ return;
+ }
+
+ DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
+ DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
+ DCHECK_EQ(invoke->InputAt(1)->GetType(), Primitive::kPrimDouble);
+ DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
+
+ LocationSummary* const locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ const InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ // Native code uses the soft float ABI.
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+ locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
+}
+
+static void GenFPToFPCall(HInvoke* invoke,
+ ArmAssembler* assembler,
+ CodeGeneratorARM* codegen,
+ QuickEntrypointEnum entry) {
+ LocationSummary* const locations = invoke->GetLocations();
+ const InvokeRuntimeCallingConvention calling_convention;
+
+ DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
+ DCHECK(locations->WillCall() && locations->Intrinsified());
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0)));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1)));
+
+ __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value());
+ // Native code uses the soft float ABI.
+ __ vmovrrd(calling_convention.GetRegisterAt(0),
+ calling_convention.GetRegisterAt(1),
+ FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
+ __ blx(LR);
+ codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+ __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
+ calling_convention.GetRegisterAt(0),
+ calling_convention.GetRegisterAt(1));
+}
+
+static void GenFPFPToFPCall(HInvoke* invoke,
+ ArmAssembler* assembler,
+ CodeGeneratorARM* codegen,
+ QuickEntrypointEnum entry) {
+ LocationSummary* const locations = invoke->GetLocations();
+ const InvokeRuntimeCallingConvention calling_convention;
+
+ DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
+ DCHECK(locations->WillCall() && locations->Intrinsified());
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0)));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1)));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(2)));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(3)));
+
+ __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value());
+ // Native code uses the soft float ABI.
+ __ vmovrrd(calling_convention.GetRegisterAt(0),
+ calling_convention.GetRegisterAt(1),
+ FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
+ __ vmovrrd(calling_convention.GetRegisterAt(2),
+ calling_convention.GetRegisterAt(3),
+ FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>()));
+ __ blx(LR);
+ codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+ __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
+ calling_convention.GetRegisterAt(0),
+ calling_convention.GetRegisterAt(1));
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathCos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathCos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCos);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathSin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathSin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSin);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAcos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAcos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAcos);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAsin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAsin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAsin);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAtan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAtan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathCbrt(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathCbrt(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCbrt);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathCosh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathCosh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCosh);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathExp(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathExp(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExp);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathExpm1(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathExpm1(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExpm1);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathLog(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathLog(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathLog10(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathLog10(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog10);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathSinh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathSinh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSinh);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathTan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathTan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTan);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathTanh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathTanh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTanh);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAtan2(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAtan2(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan2);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathHypot(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathHypot(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickHypot);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathNextAfter(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathNextAfter(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickNextAfter);
+}
+
// Unimplemented intrinsics.
#define UNIMPLEMENTED_INTRINSIC(Name) \
@@ -1610,23 +1855,6 @@ UNIMPLEMENTED_INTRINSIC(UnsafeCASLong) // High register pressure.
UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
-UNIMPLEMENTED_INTRINSIC(MathCos)
-UNIMPLEMENTED_INTRINSIC(MathSin)
-UNIMPLEMENTED_INTRINSIC(MathAcos)
-UNIMPLEMENTED_INTRINSIC(MathAsin)
-UNIMPLEMENTED_INTRINSIC(MathAtan)
-UNIMPLEMENTED_INTRINSIC(MathAtan2)
-UNIMPLEMENTED_INTRINSIC(MathCbrt)
-UNIMPLEMENTED_INTRINSIC(MathCosh)
-UNIMPLEMENTED_INTRINSIC(MathExp)
-UNIMPLEMENTED_INTRINSIC(MathExpm1)
-UNIMPLEMENTED_INTRINSIC(MathHypot)
-UNIMPLEMENTED_INTRINSIC(MathLog)
-UNIMPLEMENTED_INTRINSIC(MathLog10)
-UNIMPLEMENTED_INTRINSIC(MathNextAfter)
-UNIMPLEMENTED_INTRINSIC(MathSinh)
-UNIMPLEMENTED_INTRINSIC(MathTan)
-UNIMPLEMENTED_INTRINSIC(MathTanh)
UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 736ac32011..dcd8e7d216 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -45,15 +45,14 @@
#include "compiler.h"
#include "constant_folding.h"
#include "dead_code_elimination.h"
+#include "debug/elf_debug_writer.h"
+#include "debug/method_debug_info.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
-#include "dex/verified_method.h"
#include "dex/verification_results.h"
-#include "driver/compiler_driver.h"
+#include "dex/verified_method.h"
#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
-#include "dwarf/method_debug_info.h"
-#include "elf_writer_debug.h"
#include "elf_writer_quick.h"
#include "graph_checker.h"
#include "graph_visualizer.h"
@@ -64,20 +63,20 @@
#include "intrinsics.h"
#include "jit/debugger_interface.h"
#include "jit/jit_code_cache.h"
-#include "licm.h"
#include "jni/quick/jni_compiler.h"
+#include "licm.h"
#include "load_store_elimination.h"
#include "nodes.h"
+#include "oat_quick_method_header.h"
#include "prepare_for_register_allocation.h"
#include "reference_type_propagation.h"
#include "register_allocator.h"
-#include "oat_quick_method_header.h"
#include "select_generator.h"
#include "sharpening.h"
#include "side_effects_analysis.h"
#include "ssa_builder.h"
-#include "ssa_phi_elimination.h"
#include "ssa_liveness_analysis.h"
+#include "ssa_phi_elimination.h"
#include "utils/assembler.h"
#include "verifier/method_verifier.h"
@@ -933,7 +932,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,
ArrayRef<const uint8_t>(), // native_gc_map.
ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
ArrayRef<const LinkerPatch>());
- dwarf::MethodDebugInfo method_debug_info {
+ debug::MethodDebugInfo method_debug_info {
dex_file,
class_def_idx,
method_idx,
@@ -944,7 +943,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,
code_address + code_allocator.GetSize(),
&compiled_method
};
- ArrayRef<const uint8_t> elf_file = dwarf::WriteDebugElfFileForMethod(method_debug_info);
+ ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForMethod(method_debug_info);
CreateJITCodeEntryForAddress(code_address,
std::unique_ptr<const uint8_t[]>(elf_file.data()),
elf_file.size());
diff --git a/compiler/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h
index 5fde9e8856..5b84058f7f 100644
--- a/compiler/utils/arm/managed_register_arm.h
+++ b/compiler/utils/arm/managed_register_arm.h
@@ -19,7 +19,7 @@
#include "base/logging.h"
#include "constants_arm.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h
index dbcd8c56f7..46be1c528c 100644
--- a/compiler/utils/arm64/managed_register_arm64.h
+++ b/compiler/utils/arm64/managed_register_arm64.h
@@ -19,7 +19,7 @@
#include "base/logging.h"
#include "constants_arm64.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 1dbc142391..414ea7e660 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -21,9 +21,10 @@
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
+#include "arm/constants_arm.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "arm/constants_arm.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
#include "label.h"
#include "managed_register.h"
#include "memory_region.h"
@@ -31,7 +32,6 @@
#include "offsets.h"
#include "x86/constants_x86.h"
#include "x86_64/constants_x86_64.h"
-#include "dwarf/debug_frame_opcode_writer.h"
namespace art {
diff --git a/compiler/utils/mips/managed_register_mips.h b/compiler/utils/mips/managed_register_mips.h
index 40d39e3386..5e7ed11f51 100644
--- a/compiler/utils/mips/managed_register_mips.h
+++ b/compiler/utils/mips/managed_register_mips.h
@@ -18,7 +18,7 @@
#define ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_
#include "constants_mips.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/mips64/managed_register_mips64.h b/compiler/utils/mips64/managed_register_mips64.h
index 4c4705bbfb..1d36128a09 100644
--- a/compiler/utils/mips64/managed_register_mips64.h
+++ b/compiler/utils/mips64/managed_register_mips64.h
@@ -18,7 +18,7 @@
#define ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_
#include "constants_mips64.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h
index 4e8c41e217..fc20d7e208 100644
--- a/compiler/utils/x86/managed_register_x86.h
+++ b/compiler/utils/x86/managed_register_x86.h
@@ -18,7 +18,7 @@
#define ART_COMPILER_UTILS_X86_MANAGED_REGISTER_X86_H_
#include "constants_x86.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/x86_64/managed_register_x86_64.h b/compiler/utils/x86_64/managed_register_x86_64.h
index 47bbb44fc8..c4228c1139 100644
--- a/compiler/utils/x86_64/managed_register_x86_64.h
+++ b/compiler/utils/x86_64/managed_register_x86_64.h
@@ -18,7 +18,7 @@
#define ART_COMPILER_UTILS_X86_64_MANAGED_REGISTER_X86_64_H_
#include "constants_x86_64.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index b1f71cee3d..541fb5a423 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -35,9 +35,9 @@
#define ATRACE_TAG ATRACE_TAG_DALVIK
#include <cutils/trace.h>
-#include "art_method-inl.h"
#include "arch/instruction_set_features.h"
#include "arch/mips/instruction_set_features_mips.h"
+#include "art_method-inl.h"
#include "base/dumpable.h"
#include "base/macros.h"
#include "base/stl_util.h"
@@ -48,14 +48,14 @@
#include "class_linker.h"
#include "compiler.h"
#include "compiler_callbacks.h"
-#include "dex_file-inl.h"
+#include "debug/method_debug_info.h"
#include "dex/pass_manager.h"
-#include "dex/verification_results.h"
-#include "dex/quick_compiler_callbacks.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "dex/quick_compiler_callbacks.h"
+#include "dex/verification_results.h"
+#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
#include "elf_file.h"
#include "elf_writer.h"
#include "elf_writer_quick.h"
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 71411817af..e358ff879c 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -130,6 +130,25 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
qpoints->pL2f = art_quick_l2f;
}
+ // More math.
+ qpoints->pCos = cos;
+ qpoints->pSin = sin;
+ qpoints->pAcos = acos;
+ qpoints->pAsin = asin;
+ qpoints->pAtan = atan;
+ qpoints->pAtan2 = atan2;
+ qpoints->pCbrt = cbrt;
+ qpoints->pCosh = cosh;
+ qpoints->pExp = exp;
+ qpoints->pExpm1 = expm1;
+ qpoints->pHypot = hypot;
+ qpoints->pLog = log;
+ qpoints->pLog10 = log10;
+ qpoints->pNextAfter = nextafter;
+ qpoints->pSinh = sinh;
+ qpoints->pTan = tan;
+ qpoints->pTanh = tanh;
+
// Intrinsics
qpoints->pIndexOf = art_quick_indexof;
qpoints->pStringCompareTo = art_quick_string_compareto;
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 7a852e216e..ddf27496d9 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -478,7 +478,7 @@ bool DexFileVerifier::CheckClassDataItemField(uint32_t idx,
// Check field access flags.
std::string error_msg;
- if (!CheckFieldAccessFlags(access_flags, class_access_flags, &error_msg)) {
+ if (!CheckFieldAccessFlags(idx, access_flags, class_access_flags, &error_msg)) {
ErrorStringPrintf("%s", error_msg.c_str());
return false;
}
@@ -2312,12 +2312,88 @@ static bool CheckAtMostOneOfPublicProtectedPrivate(uint32_t flags) {
return count <= 1;
}
-bool DexFileVerifier::CheckFieldAccessFlags(uint32_t field_access_flags,
+// Helper functions to retrieve names from the dex file. We do not want to rely on DexFile
+// functionality, as we're still verifying the dex file. begin and header correspond to the
+// underscored variants in the DexFileVerifier.
+
+static std::string GetStringOrError(const uint8_t* const begin,
+ const DexFile::Header* const header,
+ uint32_t string_idx) {
+ if (header->string_ids_size_ < string_idx) {
+ return "(error)";
+ }
+
+ const DexFile::StringId* string_id =
+ reinterpret_cast<const DexFile::StringId*>(begin + header->string_ids_off_) + string_idx;
+
+ // Assume that the data is OK at this point. String data has been checked at this point.
+
+ const uint8_t* ptr = begin + string_id->string_data_off_;
+ DecodeUnsignedLeb128(&ptr);
+ return reinterpret_cast<const char*>(ptr);
+}
+
+static std::string GetClassOrError(const uint8_t* const begin,
+ const DexFile::Header* const header,
+ uint32_t class_idx) {
+ if (header->type_ids_size_ < class_idx) {
+ return "(error)";
+ }
+
+ const DexFile::TypeId* type_id =
+ reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx;
+
+ // Assume that the data is OK at this point. Type id offsets have been checked at this point.
+
+ return GetStringOrError(begin, header, type_id->descriptor_idx_);
+}
+
+static std::string GetFieldDescriptionOrError(const uint8_t* const begin,
+ const DexFile::Header* const header,
+ uint32_t idx) {
+ if (header->field_ids_size_ < idx) {
+ return "(error)";
+ }
+
+ const DexFile::FieldId* field_id =
+ reinterpret_cast<const DexFile::FieldId*>(begin + header->field_ids_off_) + idx;
+
+ // Assume that the data is OK at this point. Field id offsets have been checked at this point.
+
+ std::string class_name = GetClassOrError(begin, header, field_id->class_idx_);
+ std::string field_name = GetStringOrError(begin, header, field_id->name_idx_);
+
+ return class_name + "." + field_name;
+}
+
+static std::string GetMethodDescriptionOrError(const uint8_t* const begin,
+ const DexFile::Header* const header,
+ uint32_t idx) {
+ if (header->method_ids_size_ < idx) {
+ return "(error)";
+ }
+
+ const DexFile::MethodId* method_id =
+ reinterpret_cast<const DexFile::MethodId*>(begin + header->method_ids_off_) + idx;
+
+ // Assume that the data is OK at this point. Method id offsets have been checked at this point.
+
+ std::string class_name = GetClassOrError(begin, header, method_id->class_idx_);
+ std::string method_name = GetStringOrError(begin, header, method_id->name_idx_);
+
+ return class_name + "." + method_name;
+}
+
+bool DexFileVerifier::CheckFieldAccessFlags(uint32_t idx,
+ uint32_t field_access_flags,
uint32_t class_access_flags,
std::string* error_msg) {
// Generally sort out >16-bit flags.
if ((field_access_flags & ~kAccJavaFlagsMask) != 0) {
- *error_msg = StringPrintf("Bad class_data_item field access_flags %x", field_access_flags);
+ *error_msg = StringPrintf("Bad field access_flags for %s: %x(%s)",
+ GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+ field_access_flags,
+ PrettyJavaAccessFlags(field_access_flags).c_str());
return false;
}
@@ -2334,8 +2410,10 @@ bool DexFileVerifier::CheckFieldAccessFlags(uint32_t field_access_flags,
// Fields may have only one of public/protected/final.
if (!CheckAtMostOneOfPublicProtectedPrivate(field_access_flags)) {
- *error_msg = StringPrintf("Field may have only one of public/protected/private, %x",
- field_access_flags);
+ *error_msg = StringPrintf("Field may have only one of public/protected/private, %s: %x(%s)",
+ GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+ field_access_flags,
+ PrettyJavaAccessFlags(field_access_flags).c_str());
return false;
}
@@ -2344,14 +2422,19 @@ bool DexFileVerifier::CheckFieldAccessFlags(uint32_t field_access_flags,
// Interface fields must be public final static.
constexpr uint32_t kPublicFinalStatic = kAccPublic | kAccFinal | kAccStatic;
if ((field_access_flags & kPublicFinalStatic) != kPublicFinalStatic) {
- *error_msg = StringPrintf("Interface field is not public final static: %x",
- field_access_flags);
+ *error_msg = StringPrintf("Interface field is not public final static, %s: %x(%s)",
+ GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+ field_access_flags,
+ PrettyJavaAccessFlags(field_access_flags).c_str());
return false;
}
// Interface fields may be synthetic, but may not have other flags.
constexpr uint32_t kDisallowed = ~(kPublicFinalStatic | kAccSynthetic);
if ((field_access_flags & kFieldAccessFlags & kDisallowed) != 0) {
- *error_msg = StringPrintf("Interface field has disallowed flag: %x", field_access_flags);
+ *error_msg = StringPrintf("Interface field has disallowed flag, %s: %x(%s)",
+ GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+ field_access_flags,
+ PrettyJavaAccessFlags(field_access_flags).c_str());
return false;
}
return true;
@@ -2360,7 +2443,8 @@ bool DexFileVerifier::CheckFieldAccessFlags(uint32_t field_access_flags,
// Volatile fields may not be final.
constexpr uint32_t kVolatileFinal = kAccVolatile | kAccFinal;
if ((field_access_flags & kVolatileFinal) == kVolatileFinal) {
- *error_msg = "Fields may not be volatile and final";
+ *error_msg = StringPrintf("Fields may not be volatile and final: %s",
+ GetFieldDescriptionOrError(begin_, header_, idx).c_str());
return false;
}
@@ -2410,7 +2494,9 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
constexpr uint32_t kAllMethodFlags =
kAccJavaFlagsMask | kAccConstructor | kAccDeclaredSynchronized;
if ((method_access_flags & ~kAllMethodFlags) != 0) {
- *error_msg = StringPrintf("Bad class_data_item method access_flags %x", method_access_flags);
+ *error_msg = StringPrintf("Bad method access_flags for %s: %x",
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
+ method_access_flags);
return false;
}
@@ -2430,7 +2516,8 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
// Methods may have only one of public/protected/final.
if (!CheckAtMostOneOfPublicProtectedPrivate(method_access_flags)) {
- *error_msg = StringPrintf("Method may have only one of public/protected/private, %x",
+ *error_msg = StringPrintf("Method may have only one of public/protected/private, %s: %x",
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
method_access_flags);
return false;
}
@@ -2456,8 +2543,10 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
// Only methods named "<clinit>" or "<init>" may be marked constructor. Note: we cannot enforce
// the reverse for backwards compatibility reasons.
if (((method_access_flags & kAccConstructor) != 0) && !is_constructor) {
- *error_msg = StringPrintf("Method %" PRIu32 " is marked constructor, but doesn't match name",
- method_index);
+ *error_msg =
+ StringPrintf("Method %" PRIu32 "(%s) is marked constructor, but doesn't match name",
+ method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
return false;
}
// Check that the static constructor (= static initializer) is named "<clinit>" and that the
@@ -2465,8 +2554,9 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
if (is_constructor) {
bool is_static = (method_access_flags & kAccStatic) != 0;
if (is_static ^ is_clinit_by_name) {
- *error_msg = StringPrintf("Constructor %" PRIu32 " is not flagged correctly wrt/ static.",
- method_index);
+ *error_msg = StringPrintf("Constructor %" PRIu32 "(%s) is not flagged correctly wrt/ static.",
+ method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
return false;
}
}
@@ -2474,8 +2564,9 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
// and other methods in the virtual methods list.
bool is_direct = (method_access_flags & (kAccStatic | kAccPrivate)) != 0 || is_constructor;
if (is_direct != expect_direct) {
- *error_msg = StringPrintf("Direct/virtual method %" PRIu32 " not in expected list %d",
+ *error_msg = StringPrintf("Direct/virtual method %" PRIu32 "(%s) not in expected list %d",
method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
expect_direct);
return false;
}
@@ -2488,14 +2579,17 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
if (!has_code) {
// Only native or abstract methods may not have code.
if ((method_access_flags & (kAccNative | kAccAbstract)) == 0) {
- *error_msg = StringPrintf("Method %" PRIu32 " has no code, but is not marked native or "
+ *error_msg = StringPrintf("Method %" PRIu32 "(%s) has no code, but is not marked native or "
"abstract",
- method_index);
+ method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
return false;
}
// Constructors must always have code.
if (is_constructor) {
- *error_msg = StringPrintf("Constructor %u must not be abstract or native", method_index);
+ *error_msg = StringPrintf("Constructor %u(%s) must not be abstract or native",
+ method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
return false;
}
if ((method_access_flags & kAccAbstract) != 0) {
@@ -2503,14 +2597,15 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
constexpr uint32_t kForbidden =
kAccPrivate | kAccStatic | kAccFinal | kAccNative | kAccStrict | kAccSynchronized;
if ((method_access_flags & kForbidden) != 0) {
- *error_msg = StringPrintf("Abstract method %" PRIu32 " has disallowed access flags %x",
- method_index,
- method_access_flags);
+ *error_msg = StringPrintf("Abstract method %" PRIu32 "(%s) has disallowed access flags %x",
+ method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
+ method_access_flags);
return false;
}
// Abstract methods should be in an abstract class or interface.
if ((class_access_flags & (kAccInterface | kAccAbstract)) == 0) {
- LOG(WARNING) << "Method " << PrettyMethod(method_index, *dex_file_)
+ LOG(WARNING) << "Method " << GetMethodDescriptionOrError(begin_, header_, method_index)
<< " is abstract, but the declaring class is neither abstract nor an "
<< "interface in dex file "
<< dex_file_->GetLocation();
@@ -2520,8 +2615,9 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
if ((class_access_flags & kAccInterface) != 0) {
// Interface methods must be public and abstract.
if ((method_access_flags & (kAccPublic | kAccAbstract)) != (kAccPublic | kAccAbstract)) {
- *error_msg = StringPrintf("Interface method %" PRIu32 " is not public and abstract",
- method_index);
+ *error_msg = StringPrintf("Interface method %" PRIu32 "(%s) is not public and abstract",
+ method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
return false;
}
// At this point, we know the method is public and abstract. This means that all the checks
@@ -2533,8 +2629,9 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
// When there's code, the method must not be native or abstract.
if ((method_access_flags & (kAccNative | kAccAbstract)) != 0) {
- *error_msg = StringPrintf("Method %" PRIu32 " has code, but is marked native or abstract",
- method_index);
+ *error_msg = StringPrintf("Method %" PRIu32 "(%s) has code, but is marked native or abstract",
+ method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
return false;
}
@@ -2543,8 +2640,9 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
static constexpr uint32_t kInitAllowed =
kAccPrivate | kAccProtected | kAccPublic | kAccStrict | kAccVarargs | kAccSynthetic;
if ((method_access_flags & ~kInitAllowed) != 0) {
- *error_msg = StringPrintf("Constructor %" PRIu32 " flagged inappropriately %x",
+ *error_msg = StringPrintf("Constructor %" PRIu32 "(%s) flagged inappropriately %x",
method_index,
+ GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
method_access_flags);
return false;
}
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 6c63749f04..ddfeea2305 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -157,9 +157,10 @@ class DexFileVerifier {
// Check validity of the given access flags, interpreted for a field in the context of a class
// with the given second access flags.
- static bool CheckFieldAccessFlags(uint32_t field_access_flags,
- uint32_t class_access_flags,
- std::string* error_msg);
+ bool CheckFieldAccessFlags(uint32_t idx,
+ uint32_t field_access_flags,
+ uint32_t class_access_flags,
+ std::string* error_msg);
// Check validity of the given method and access flags, in the context of a class with the given
// second access flags.
bool CheckMethodAccessFlags(uint32_t method_index,
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index b67af53458..558a6ed5bf 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -527,7 +527,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsConstructors) {
ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
OrMaskToMethodFlags(dex_file, "<init>", kAccStatic);
},
- "Constructor 1 is not flagged correctly wrt/ static");
+ "Constructor 1(LMethodFlags;.<init>) is not flagged correctly wrt/ static");
static constexpr uint32_t kInitNotAllowed[] = {
kAccFinal,
kAccSynchronized,
@@ -544,7 +544,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsConstructors) {
ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
OrMaskToMethodFlags(dex_file, "<init>", kInitNotAllowed[i]);
},
- "Constructor 1 flagged inappropriately");
+ "Constructor 1(LMethodFlags;.<init>) flagged inappropriately");
}
}
@@ -742,7 +742,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
},
- "Interface method 1 is not public and abstract");
+ "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract");
VerifyModification(
kMethodFlagsInterface,
"method_flags_interface_non_abstract",
@@ -751,7 +751,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
ApplyMaskToMethodFlags(dex_file, "foo", ~kAccAbstract);
},
- "Method 1 has no code, but is not marked native or abstract");
+ "Method 1(LInterfaceMethodFlags;.foo) has no code, but is not marked native or abstract");
VerifyModification(
kMethodFlagsInterface,
@@ -761,7 +761,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
OrMaskToMethodFlags(dex_file, "foo", kAccStatic);
},
- "Direct/virtual method 1 not in expected list 0");
+ "Direct/virtual method 1(LInterfaceMethodFlags;.foo) not in expected list 0");
VerifyModification(
kMethodFlagsInterface,
"method_flags_interface_private",
@@ -771,7 +771,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
OrMaskToMethodFlags(dex_file, "foo", kAccPrivate);
},
- "Direct/virtual method 1 not in expected list 0");
+ "Direct/virtual method 1(LInterfaceMethodFlags;.foo) not in expected list 0");
VerifyModification(
kMethodFlagsInterface,
@@ -781,7 +781,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
},
- "Interface method 1 is not public and abstract");
+ "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract");
VerifyModification(
kMethodFlagsInterface,
"method_flags_interface_protected",
@@ -791,7 +791,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
OrMaskToMethodFlags(dex_file, "foo", kAccProtected);
},
- "Interface method 1 is not public and abstract");
+ "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract");
constexpr uint32_t kAllMethodFlags =
kAccPublic |
@@ -831,7 +831,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
}
OrMaskToMethodFlags(dex_file, "foo", mask);
},
- "Abstract method 1 has disallowed access flags");
+ "Abstract method 1(LInterfaceMethodFlags;.foo) has disallowed access flags");
}
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 8269f7662f..3c9312f256 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2622,6 +2622,10 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type,
}
if (collector != mark_compact_collector_ && collector != concurrent_copying_collector_) {
temp_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
+ if (kIsDebugBuild) {
+ // Try to read each page of the memory map in case mprotect didn't work properly b/19894268.
+ temp_space_->GetMemMap()->TryReadable();
+ }
CHECK(temp_space_->IsEmpty());
}
gc_type = collector::kGcTypeFull; // TODO: Not hard code this in.
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 18c52e47b6..c908b3920a 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -877,4 +877,22 @@ std::ostream& operator<<(std::ostream& os, const MemMap& mem_map) {
return os;
}
+void MemMap::TryReadable() {
+ if (base_begin_ == nullptr && base_size_ == 0) {
+ return;
+ }
+ CHECK_NE(prot_ & PROT_READ, 0);
+ volatile uint8_t* begin = reinterpret_cast<volatile uint8_t*>(base_begin_);
+ volatile uint8_t* end = begin + base_size_;
+ DCHECK(IsAligned<kPageSize>(begin));
+ DCHECK(IsAligned<kPageSize>(end));
+ // Read the first byte of each page. Use volatile to prevent the compiler from optimizing away the
+ // reads.
+ for (volatile uint8_t* ptr = begin; ptr < end; ptr += kPageSize) {
+ // This read could fault if protection wasn't set correctly.
+ uint8_t value = *ptr;
+ UNUSED(value);
+ }
+}
+
} // namespace art
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index ebd550a552..3eaf576845 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -184,6 +184,11 @@ class MemMap {
static void Init() REQUIRES(!Locks::mem_maps_lock_);
static void Shutdown() REQUIRES(!Locks::mem_maps_lock_);
+ // If the map is PROT_READ, try to read each page of the map to check it is in fact readable (not
+ // faulting). This is used to diagnose a bug b/19894268 where mprotect doesn't seem to be working
+ // intermittently.
+ void TryReadable();
+
private:
MemMap(const std::string& name,
uint8_t* begin,
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index a80585abca..b5d859b6b8 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -388,7 +388,7 @@ static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis,
auto h_args = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
Handle<mirror::Class> h_klass = hs.NewHandle(DecodeClass(soa, javaThis));
ArtMethod* result = nullptr;
- for (auto& m : h_klass->GetVirtualMethods(sizeof(void*))) {
+ for (auto& m : h_klass->GetDeclaredVirtualMethods(sizeof(void*))) {
auto* np_method = m.GetInterfaceMethodIfProxy(sizeof(void*));
// May cause thread suspension.
mirror::String* np_name = np_method->GetNameAsString(soa.Self());
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index ab0d93431a..725067a351 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -66,17 +66,13 @@ extern "C" void android_update_LD_LIBRARY_PATH(const char* ld_library_path);
#undef LOG_TAG
#define LOG_TAG "artopenjdk"
-using art::DEBUG;
using art::WARNING;
-using art::VERBOSE;
using art::INFO;
using art::ERROR;
using art::FATAL;
/* posix open() with extensions; used by e.g. ZipFile */
JNIEXPORT jint JVM_Open(const char* fname, jint flags, jint mode) {
- LOG(DEBUG) << "JVM_Open fname='" << fname << "', flags=" << flags << ", mode=" << mode;
-
/*
* The call is expected to handle JVM_O_DELETE, which causes the file
* to be removed after it is opened. Also, some code seems to
@@ -86,7 +82,6 @@ JNIEXPORT jint JVM_Open(const char* fname, jint flags, jint mode) {
int fd = TEMP_FAILURE_RETRY(open(fname, flags & ~JVM_O_DELETE, mode));
if (fd < 0) {
int err = errno;
- LOG(DEBUG) << "open(" << fname << ") failed: " << strerror(errno);
if (err == EEXIST) {
return JVM_EEXIST;
} else {
@@ -95,39 +90,32 @@ JNIEXPORT jint JVM_Open(const char* fname, jint flags, jint mode) {
}
if (flags & JVM_O_DELETE) {
- LOG(DEBUG) << "Deleting '" << fname << "' after open\n";
if (unlink(fname) != 0) {
LOG(WARNING) << "Post-open deletion of '" << fname << "' failed: " << strerror(errno);
}
- /* ignore */
}
- LOG(VERBOSE) << "open(" << fname << ") --> " << fd;
return fd;
}
/* posix close() */
JNIEXPORT jint JVM_Close(jint fd) {
- LOG(DEBUG) << "JVM_Close fd=" << fd;
// don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR
return close(fd);
}
/* posix read() */
JNIEXPORT jint JVM_Read(jint fd, char* buf, jint nbytes) {
- LOG(DEBUG) << "JVM_Read fd=" << fd << ", buf='" << buf << "', nbytes=" << nbytes;
return TEMP_FAILURE_RETRY(read(fd, buf, nbytes));
}
/* posix write(); is used to write messages to stderr */
JNIEXPORT jint JVM_Write(jint fd, char* buf, jint nbytes) {
- LOG(DEBUG) << "JVM_Write fd=" << fd << ", buf='" << buf << "', nbytes=" << nbytes;
return TEMP_FAILURE_RETRY(write(fd, buf, nbytes));
}
/* posix lseek() */
JNIEXPORT jlong JVM_Lseek(jint fd, jlong offset, jint whence) {
- LOG(DEBUG) << "JVM_Lseek fd=" << fd << ", offset=" << offset << ", whence=" << whence;
return TEMP_FAILURE_RETRY(lseek(fd, offset, whence));
}
@@ -136,42 +124,41 @@ JNIEXPORT jlong JVM_Lseek(jint fd, jlong offset, jint whence) {
* mutexes. They're used by ZipFile.
*/
JNIEXPORT void* JVM_RawMonitorCreate(void) {
- LOG(DEBUG) << "JVM_RawMonitorCreate";
- pthread_mutex_t* newMutex =
+ pthread_mutex_t* mutex =
reinterpret_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t)));
- pthread_mutex_init(newMutex, NULL);
- return newMutex;
+ CHECK(mutex != nullptr);
+ CHECK_PTHREAD_CALL(pthread_mutex_init, (mutex, nullptr), "JVM_RawMonitorCreate");
+ return mutex;
}
JNIEXPORT void JVM_RawMonitorDestroy(void* mon) {
- LOG(DEBUG) << "JVM_RawMonitorDestroy mon=" << mon;
- pthread_mutex_destroy(reinterpret_cast<pthread_mutex_t*>(mon));
+ CHECK_PTHREAD_CALL(pthread_mutex_destroy,
+ (reinterpret_cast<pthread_mutex_t*>(mon)),
+ "JVM_RawMonitorDestroy");
+ free(mon);
}
JNIEXPORT jint JVM_RawMonitorEnter(void* mon) {
- LOG(DEBUG) << "JVM_RawMonitorEnter mon=" << mon;
return pthread_mutex_lock(reinterpret_cast<pthread_mutex_t*>(mon));
}
JNIEXPORT void JVM_RawMonitorExit(void* mon) {
- LOG(DEBUG) << "JVM_RawMonitorExit mon=" << mon;
- pthread_mutex_unlock(reinterpret_cast<pthread_mutex_t*>(mon));
+ CHECK_PTHREAD_CALL(pthread_mutex_unlock,
+ (reinterpret_cast<pthread_mutex_t*>(mon)),
+ "JVM_RawMonitorExit");
}
JNIEXPORT char* JVM_NativePath(char* path) {
- LOG(DEBUG) << "JVM_NativePath path='" << path << "'";
return path;
}
JNIEXPORT jint JVM_GetLastErrorString(char* buf, int len) {
#if defined(__GLIBC__) || defined(__BIONIC__)
- int err = errno; // grab before JVM_TRACE can trash it
- LOG(DEBUG) << "JVM_GetLastErrorString buf=" << buf << ", len=" << len;
-
if (len == 0) {
return 0;
}
+ const int err = errno;
char* result = strerror_r(err, buf, len);
if (result != buf) {
strncpy(buf, result, len);
@@ -203,27 +190,22 @@ JNIEXPORT int jio_vfprintf(FILE* fp, const char* fmt, va_list args) {
/* posix fsync() */
JNIEXPORT jint JVM_Sync(jint fd) {
- LOG(DEBUG) << "JVM_Sync fd=" << fd;
return TEMP_FAILURE_RETRY(fsync(fd));
}
JNIEXPORT void* JVM_FindLibraryEntry(void* handle, const char* name) {
- LOG(DEBUG) << "JVM_FindLibraryEntry handle=" << handle << " name=" << name;
return dlsym(handle, name);
}
-JNIEXPORT jlong JVM_CurrentTimeMillis(JNIEnv* env, jclass clazz ATTRIBUTE_UNUSED) {
- LOG(DEBUG) << "JVM_CurrentTimeMillis env=" << env;
+JNIEXPORT jlong JVM_CurrentTimeMillis(JNIEnv* env ATTRIBUTE_UNUSED,
+ jclass clazz ATTRIBUTE_UNUSED) {
struct timeval tv;
-
gettimeofday(&tv, (struct timezone *) NULL);
jlong when = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
return when;
}
JNIEXPORT jint JVM_Socket(jint domain, jint type, jint protocol) {
- LOG(DEBUG) << "JVM_Socket domain=" << domain << ", type=" << type << ", protocol=" << protocol;
-
return TEMP_FAILURE_RETRY(socket(domain, type, protocol));
}
@@ -247,21 +229,15 @@ int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
JNIEXPORT jint JVM_SetSockOpt(jint fd, int level, int optname,
const char* optval, int optlen) {
- LOG(DEBUG) << "JVM_SetSockOpt fd=" << fd << ", level=" << level << ", optname=" << optname
- << ", optval=" << optval << ", optlen=" << optlen;
return TEMP_FAILURE_RETRY(setsockopt(fd, level, optname, optval, optlen));
}
JNIEXPORT jint JVM_SocketShutdown(jint fd, jint howto) {
- LOG(DEBUG) << "JVM_SocketShutdown fd=" << fd << ", howto=" << howto;
return TEMP_FAILURE_RETRY(shutdown(fd, howto));
}
JNIEXPORT jint JVM_GetSockOpt(jint fd, int level, int optname, char* optval,
int* optlen) {
- LOG(DEBUG) << "JVM_GetSockOpt fd=" << fd << ", level=" << level << ", optname=" << optname
- << ", optval=" << optval << ", optlen=" << optlen;
-
socklen_t len = *optlen;
int cc = TEMP_FAILURE_RETRY(getsockopt(fd, level, optname, optval, &len));
*optlen = len;
@@ -269,8 +245,6 @@ JNIEXPORT jint JVM_GetSockOpt(jint fd, int level, int optname, char* optval,
}
JNIEXPORT jint JVM_GetSockName(jint fd, struct sockaddr* addr, int* addrlen) {
- LOG(DEBUG) << "JVM_GetSockName fd=" << fd << ", addr=" << addr << ", addrlen=" << addrlen;
-
socklen_t len = *addrlen;
int cc = TEMP_FAILURE_RETRY(getsockname(fd, addr, &len));
*addrlen = len;
@@ -278,10 +252,7 @@ JNIEXPORT jint JVM_GetSockName(jint fd, struct sockaddr* addr, int* addrlen) {
}
JNIEXPORT jint JVM_SocketAvailable(jint fd, jint* result) {
- LOG(DEBUG) << "JVM_SocketAvailable fd=" << fd << ", result=" << result;
-
if (TEMP_FAILURE_RETRY(ioctl(fd, FIONREAD, result)) < 0) {
- LOG(DEBUG) << "ioctl(" << fd << ", FIONREAD) failed: " << strerror(errno);
return JNI_FALSE;
}
@@ -289,39 +260,27 @@ JNIEXPORT jint JVM_SocketAvailable(jint fd, jint* result) {
}
JNIEXPORT jint JVM_Send(jint fd, char* buf, jint nBytes, jint flags) {
- LOG(DEBUG) << "JVM_Send fd=" << fd << ", buf=" << buf << ", nBytes="
- << nBytes << ", flags=" << flags;
-
return TEMP_FAILURE_RETRY(send(fd, buf, nBytes, flags));
}
JNIEXPORT jint JVM_SocketClose(jint fd) {
- LOG(DEBUG) << "JVM_SocketClose fd=" << fd;
-
- // don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR
+ // Don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR.
return close(fd);
}
JNIEXPORT jint JVM_Listen(jint fd, jint count) {
- LOG(DEBUG) << "JVM_Listen fd=" << fd << ", count=" << count;
-
return TEMP_FAILURE_RETRY(listen(fd, count));
}
JNIEXPORT jint JVM_Connect(jint fd, struct sockaddr* addr, jint addrlen) {
- LOG(DEBUG) << "JVM_Connect fd=" << fd << ", addr=" << addr << ", addrlen=" << addrlen;
-
return TEMP_FAILURE_RETRY(connect(fd, addr, addrlen));
}
JNIEXPORT int JVM_GetHostName(char* name, int namelen) {
- LOG(DEBUG) << "JVM_GetHostName name=" << name << ", namelen=" << namelen;
-
return TEMP_FAILURE_RETRY(gethostname(name, namelen));
}
JNIEXPORT jstring JVM_InternString(JNIEnv* env, jstring jstr) {
- LOG(DEBUG) << "JVM_InternString env=" << env << ", jstr=" << jstr;
art::ScopedFastNativeObjectAccess soa(env);
art::mirror::String* s = soa.Decode<art::mirror::String*>(jstr);
art::mirror::String* result = s->Intern();
diff --git a/test/048-reflect-v8/expected.txt b/test/048-reflect-v8/expected.txt
index 3109eccda6..54aede9a79 100644
--- a/test/048-reflect-v8/expected.txt
+++ b/test/048-reflect-v8/expected.txt
@@ -6,6 +6,15 @@ IsDefaultTest$RegularInterface is default = no
IsDefaultTest$ImplementsWithDefault is default = yes
IsDefaultTest$ImplementsWithRegular is default = no
==============================
+Are These Methods found by getDeclaredMethod:
+==============================
+No error thrown for class interface DefaultDeclared$DefaultInterface
+No error thrown for class interface DefaultDeclared$RegularInterface
+NoSuchMethodException thrown for class class DefaultDeclared$ImplementsWithDefault
+No error thrown for class class DefaultDeclared$ImplementsWithDeclared
+No error thrown for class class DefaultDeclared$ImplementsWithRegular
+NoSuchMethodException thrown for class class DefaultDeclared$UnimplementedWithRegular
+==============================
Class annotations by type:
==============================
Annotations by type, defined by class SingleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23)
diff --git a/test/048-reflect-v8/src/DefaultDeclared.java b/test/048-reflect-v8/src/DefaultDeclared.java
new file mode 100644
index 0000000000..16e8a24c00
--- /dev/null
+++ b/test/048-reflect-v8/src/DefaultDeclared.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class DefaultDeclared {
+ interface DefaultInterface {
+ default void sayHi() {
+ System.out.println("hi default");
+ }
+ }
+
+ interface RegularInterface {
+ void sayHi();
+ }
+
+ class ImplementsWithDefault implements DefaultInterface {}
+
+ class ImplementsWithDeclared implements DefaultInterface {
+ public void sayHi() {
+ System.out.println("hello specific from default");
+ }
+ }
+
+ abstract class UnimplementedWithRegular implements RegularInterface { }
+
+ class ImplementsWithRegular implements RegularInterface {
+ public void sayHi() {
+ System.out.println("hello specific");
+ }
+ }
+
+ private static void printGetMethod(Class<?> klass) {
+ Method m;
+ try {
+ m = klass.getDeclaredMethod("sayHi");
+ System.out.println("No error thrown for class " + klass.toString());
+ } catch (NoSuchMethodException e) {
+ System.out.println("NoSuchMethodException thrown for class " + klass.toString());
+ } catch (Throwable t) {
+ System.out.println("Unknown error thrown for class " + klass.toString());
+ t.printStackTrace();
+ }
+ }
+
+ public static void test() {
+ System.out.println("==============================");
+ System.out.println("Are These Methods found by getDeclaredMethod:");
+ System.out.println("==============================");
+
+ printGetMethod(DefaultInterface.class);
+ printGetMethod(RegularInterface.class);
+ printGetMethod(ImplementsWithDefault.class);
+ printGetMethod(ImplementsWithDeclared.class);
+ printGetMethod(ImplementsWithRegular.class);
+ printGetMethod(UnimplementedWithRegular.class);
+ }
+}
diff --git a/test/048-reflect-v8/src/Main.java b/test/048-reflect-v8/src/Main.java
index f2b8287d18..b270e68284 100644
--- a/test/048-reflect-v8/src/Main.java
+++ b/test/048-reflect-v8/src/Main.java
@@ -17,6 +17,7 @@
public class Main {
public static void main(String[] args) {
IsDefaultTest.test();
+ DefaultDeclared.test();
AnnotationTest.testAnnotationsByType();
AnnotationTest.testDeclaredAnnotation();
AnnotationTest.testDeclaredAnnotationsByType();