From d133b97b1ccae88f6ee7040e288fd7a239ee4492 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 5 Sep 2013 11:01:30 -0700 Subject: Shard dedupe set locks. We're seeing contention during compilation on the dedupe locks, sharding 4 ways on an occam brings down contention by > 5x. Improve dedupe hash function to have a FNV hash function at its heart. Improve naming of dedupe locks. Tidy portable JNI compiler paramters to be pointers, given that's their primary use. Change-Id: I95d905f2ca5fee4e83a0034926a5f6501b4aeb79 --- compiler/llvm/compiler_llvm.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler/llvm/compiler_llvm.cc') diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index fd440d5bf0..83b0c75e04 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -164,7 +164,7 @@ CompileNativeMethod(DexCompilationUnit* dex_compilation_unit) { UniquePtr cunit(AllocateCompilationUnit()); UniquePtr jni_compiler( - new JniCompiler(cunit.get(), *compiler_driver_, dex_compilation_unit)); + new JniCompiler(cunit.get(), compiler_driver_, dex_compilation_unit)); return jni_compiler->Compile(); } -- cgit v1.2.3-59-g8ed1b From 02ed4c04468ca5f5540c5b704ac3e2f30eb9e8f4 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 6 Sep 2013 13:10:04 -0700 Subject: Move disassembler out of runtime. Bug: 9877500. Change-Id: Ica6d9f5ecfd20c86e5230a2213827bd78cd29a29 --- Android.mk | 1 + compiler/dex/arena_allocator.cc | 1 + compiler/dex/dex_to_dex_compiler.cc | 1 + compiler/dex/portable/mir_to_gbc.cc | 4 +- compiler/dex/quick/mir_to_lir.cc | 1 + compiler/jni/quick/jni_compiler.cc | 6 - compiler/llvm/compiler_llvm.cc | 1 + disassembler/Android.mk | 120 ++++ disassembler/disassembler.cc | 41 ++ disassembler/disassembler.h | 48 ++ disassembler/disassembler_arm.cc | 1359 +++++++++++++++++++++++++++++++++++ disassembler/disassembler_arm.h | 51 ++ disassembler/disassembler_mips.cc | 275 +++++++ disassembler/disassembler_mips.h | 40 ++ disassembler/disassembler_x86.cc | 750 +++++++++++++++++++ disassembler/disassembler_x86.h | 38 + oatdump/Android.mk | 8 +- runtime/Android.mk | 4 - runtime/disassembler.cc | 41 -- runtime/disassembler.h | 48 -- runtime/disassembler_arm.cc | 1359 ----------------------------------- runtime/disassembler_arm.h | 51 -- runtime/disassembler_mips.cc | 275 ------- runtime/disassembler_mips.h | 40 -- runtime/disassembler_x86.cc | 750 ------------------- runtime/disassembler_x86.h | 38 - runtime/thread-inl.h | 13 + runtime/thread.h | 13 +- 28 files changed, 2747 insertions(+), 2630 deletions(-) create mode 100644 disassembler/Android.mk create mode 100644 disassembler/disassembler.cc create mode 100644 disassembler/disassembler.h create mode 100644 disassembler/disassembler_arm.cc create mode 100644 disassembler/disassembler_arm.h create mode 100644 disassembler/disassembler_mips.cc create mode 100644 disassembler/disassembler_mips.h create mode 100644 disassembler/disassembler_x86.cc create mode 100644 disassembler/disassembler_x86.h delete mode 100644 runtime/disassembler.cc delete mode 100644 runtime/disassembler.h delete mode 100644 runtime/disassembler_arm.cc delete mode 100644 runtime/disassembler_arm.h delete mode 100644 runtime/disassembler_mips.cc delete mode 100644 runtime/disassembler_mips.h delete mode 100644 runtime/disassembler_x86.cc delete mode 100644 runtime/disassembler_x86.h (limited to 'compiler/llvm/compiler_llvm.cc') diff --git a/Android.mk b/Android.mk index 46a7c1ec3e..0b4b2316fd 100644 --- a/Android.mk +++ b/Android.mk @@ -85,6 +85,7 @@ ifneq ($(art_dont_bother),true) include $(art_path)/runtime/Android.mk include $(art_path)/compiler/Android.mk include $(art_path)/dex2oat/Android.mk +include $(art_path)/disassembler/Android.mk include $(art_path)/oatdump/Android.mk include $(art_path)/dalvikvm/Android.mk include $(art_path)/jdwpspy/Android.mk diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc index 36393e7387..5a91d27ef5 100644 --- a/compiler/dex/arena_allocator.cc +++ b/compiler/dex/arena_allocator.cc @@ -19,6 +19,7 @@ #include "arena_allocator.h" #include "base/logging.h" #include "base/mutex.h" +#include "thread-inl.h" namespace art { diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 4a724b109a..ffd7905dfe 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -24,6 +24,7 @@ #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" +#include "thread-inl.h" namespace art { namespace optimizer { diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc index 2cf55e7ea5..df10f7eda0 100644 --- a/compiler/dex/portable/mir_to_gbc.cc +++ b/compiler/dex/portable/mir_to_gbc.cc @@ -30,10 +30,10 @@ #include "dex/compiler_internals.h" #include "dex/dataflow_iterator-inl.h" #include "dex/frontend.h" -#include "mir_to_gbc.h" - #include "llvm/llvm_compilation_unit.h" #include "llvm/utils_llvm.h" +#include "mir_to_gbc.h" +#include "thread-inl.h" const char* kLabelFormat = "%c0x%x_%d"; const char kInvalidBlock = 0xff; diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 7c79f59853..22dd6dadb9 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -18,6 +18,7 @@ #include "dex/dataflow_iterator-inl.h" #include "mir_to_lir-inl.h" #include "object_utils.h" +#include "thread-inl.h" namespace art { diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 1417fb9e40..b6b15f94eb 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -24,7 +24,6 @@ #include "compiled_method.h" #include "dex_file-inl.h" #include "driver/compiler_driver.h" -#include "disassembler.h" #include "entrypoints/quick/quick_entrypoints.h" #include "jni_internal.h" #include "utils/assembler.h" @@ -85,7 +84,6 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler, // Assembler that holds generated instructions UniquePtr jni_asm(Assembler::Create(instruction_set)); - bool should_disassemble = false; // Offsets into data structures // TODO: if cross compiling these offsets are for the host not the target @@ -366,10 +364,6 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler, std::vector managed_code(cs); MemoryRegion code(&managed_code[0], managed_code.size()); __ FinalizeInstructions(code); - if (should_disassemble) { - UniquePtr disassembler(Disassembler::Create(instruction_set)); - disassembler->Dump(LOG(INFO), &managed_code[0], &managed_code[managed_code.size()]); - } return new CompiledMethod(compiler, instruction_set, managed_code, diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index 83b0c75e04..0df3c476fc 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -26,6 +26,7 @@ #include "ir_builder.h" #include "jni/portable/jni_compiler.h" #include "llvm_compilation_unit.h" +#include "thread-inl.h" #include "utils_llvm.h" #include "verifier/method_verifier.h" diff --git a/disassembler/Android.mk b/disassembler/Android.mk new file mode 100644 index 0000000000..f8001a4524 --- /dev/null +++ b/disassembler/Android.mk @@ -0,0 +1,120 @@ +# +# Copyright (C) 2012 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. +# + +LOCAL_PATH := $(call my-dir) + +include art/build/Android.common.mk + +LIBART_DISASSEMBLER_SRC_FILES := \ + disassembler.cc \ + disassembler_arm.cc \ + disassembler_mips.cc \ + disassembler_x86.cc + +# $(1): target or host +# $(2): ndebug or debug +define build-libart-disassembler + ifneq ($(1),target) + ifneq ($(1),host) + $$(error expected target or host for argument 1, received $(1)) + endif + endif + ifneq ($(2),ndebug) + ifneq ($(2),debug) + $$(error expected ndebug or debug for argument 2, received $(2)) + endif + endif + + art_target_or_host := $(1) + art_ndebug_or_debug := $(2) + + include $(CLEAR_VARS) + ifeq ($$(art_target_or_host),target) + include external/stlport/libstlport.mk + else + LOCAL_IS_HOST_MODULE := true + endif + LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) + ifeq ($$(art_ndebug_or_debug),ndebug) + LOCAL_MODULE := libart-disassembler + else # debug + LOCAL_MODULE := libartd-disassembler + endif + + LOCAL_MODULE_TAGS := optional + LOCAL_MODULE_CLASS := SHARED_LIBRARIES + + LOCAL_SRC_FILES := $$(LIBART_DISASSEMBLER_SRC_FILES) + + GENERATED_SRC_DIR := $$(call intermediates-dir-for,$$(LOCAL_MODULE_CLASS),$$(LOCAL_MODULE),$$(LOCAL_IS_HOST_MODULE),) + + ifeq ($$(art_target_or_host),target) + LOCAL_CLANG := $(ART_TARGET_CLANG) + LOCAL_CFLAGS += $(ART_TARGET_CFLAGS) + else # host + LOCAL_CLANG := $(ART_HOST_CLANG) + LOCAL_CFLAGS += $(ART_HOST_CFLAGS) + endif + + LOCAL_SHARED_LIBRARIES += liblog + ifeq ($$(art_ndebug_or_debug),debug) + ifeq ($$(art_target_or_host),target) + LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS) + else # host + LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS) + endif + LOCAL_SHARED_LIBRARIES += libartd + else + ifeq ($$(art_target_or_host),target) + LOCAL_CFLAGS += $(ART_TARGET_NON_DEBUG_CFLAGS) + else # host + LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS) + endif + LOCAL_SHARED_LIBRARIES += libart + endif + + LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime + + LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk + LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk + ifeq ($$(art_target_or_host),target) + LOCAL_SHARED_LIBRARIES += libcutils + include $(LLVM_GEN_INTRINSICS_MK) + include $(LLVM_DEVICE_BUILD_MK) + include $(BUILD_SHARED_LIBRARY) + else # host + LOCAL_STATIC_LIBRARIES += libcutils + include $(LLVM_GEN_INTRINSICS_MK) + include $(LLVM_HOST_BUILD_MK) + include $(BUILD_HOST_SHARED_LIBRARY) + endif +endef + +ifeq ($(ART_BUILD_TARGET_NDEBUG),true) + $(eval $(call build-libart-disassembler,target,ndebug)) +endif +ifeq ($(ART_BUILD_TARGET_DEBUG),true) + $(eval $(call build-libart-disassembler,target,debug)) +endif +ifeq ($(WITH_HOST_DALVIK),true) + # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target. + ifeq ($(ART_BUILD_NDEBUG),true) + $(eval $(call build-libart-disassembler,host,ndebug)) + endif + ifeq ($(ART_BUILD_DEBUG),true) + $(eval $(call build-libart-disassembler,host,debug)) + endif +endif diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc new file mode 100644 index 0000000000..067083510b --- /dev/null +++ b/disassembler/disassembler.cc @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 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 "disassembler.h" + +#include + +#include "base/logging.h" +#include "disassembler_arm.h" +#include "disassembler_mips.h" +#include "disassembler_x86.h" + +namespace art { + +Disassembler* Disassembler::Create(InstructionSet instruction_set) { + if (instruction_set == kArm || instruction_set == kThumb2) { + return new arm::DisassemblerArm(); + } else if (instruction_set == kMips) { + return new mips::DisassemblerMips(); + } else if (instruction_set == kX86) { + return new x86::DisassemblerX86(); + } else { + UNIMPLEMENTED(FATAL) << "no disassembler for " << instruction_set; + return NULL; + } +} + +} // namespace art diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h new file mode 100644 index 0000000000..7547ab722b --- /dev/null +++ b/disassembler/disassembler.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 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_DISASSEMBLER_DISASSEMBLER_H_ +#define ART_DISASSEMBLER_DISASSEMBLER_H_ + +#include + +#include + +#include "base/macros.h" +#include "instruction_set.h" + +namespace art { + +class Disassembler { + public: + static Disassembler* Create(InstructionSet instruction_set); + virtual ~Disassembler() {} + + // Dump a single instruction returning the length of that instruction. + virtual size_t Dump(std::ostream& os, const uint8_t* begin) = 0; + // Dump instructions within a range. + virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) = 0; + + protected: + Disassembler() {} + + private: + DISALLOW_COPY_AND_ASSIGN(Disassembler); +}; + +} // namespace art + +#endif // ART_DISASSEMBLER_DISASSEMBLER_H_ diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc new file mode 100644 index 0000000000..879d3ac71c --- /dev/null +++ b/disassembler/disassembler_arm.cc @@ -0,0 +1,1359 @@ +/* + * Copyright (C) 2012 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 "disassembler_arm.h" + +#include + +#include "base/logging.h" +#include "base/stringprintf.h" +#include "thread.h" + +namespace art { +namespace arm { + +DisassemblerArm::DisassemblerArm() { +} + +size_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) { + if ((reinterpret_cast(begin) & 1) == 0) { + DumpArm(os, begin); + return 4; + } else { + // remove thumb specifier bits + begin = reinterpret_cast(reinterpret_cast(begin) & ~1); + return DumpThumb16(os, begin); + } +} + +void DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { + if ((reinterpret_cast(begin) & 1) == 0) { + for (const uint8_t* cur = begin; cur < end; cur += 4) { + DumpArm(os, cur); + } + } else { + // remove thumb specifier bits + begin = reinterpret_cast(reinterpret_cast(begin) & ~1); + end = reinterpret_cast(reinterpret_cast(end) & ~1); + for (const uint8_t* cur = begin; cur < end;) { + cur += DumpThumb16(os, cur); + } + } +} + +static const char* kConditionCodeNames[] = { + "eq", // 0000 - equal + "ne", // 0001 - not-equal + "cs", // 0010 - carry-set, greater than, equal or unordered + "cc", // 0011 - carry-clear, less than + "mi", // 0100 - minus, negative + "pl", // 0101 - plus, positive or zero + "vs", // 0110 - overflow + "vc", // 0111 - no overflow + "hi", // 1000 - unsigned higher + "ls", // 1001 - unsigned lower or same + "ge", // 1010 - signed greater than or equal + "lt", // 1011 - signed less than + "gt", // 1100 - signed greater than + "le", // 1101 - signed less than or equal + "", // 1110 - always + "nv", // 1111 - never (mostly obsolete, but might be a clue that we're mistranslating) +}; + +void DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) { + if (cond < 15) { + os << kConditionCodeNames[cond]; + } else { + os << "Unexpected condition: " << cond; + } +} + +void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) { + os << StringPrintf("%+d (%p)", imm32, instr_ptr + imm32); +} + +static uint32_t ReadU16(const uint8_t* ptr) { + return ptr[0] | (ptr[1] << 8); +} + +static uint32_t ReadU32(const uint8_t* ptr) { + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); +} + +static const char* kDataProcessingOperations[] = { + "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", +}; + +static const char* kThumbDataProcessingOperations[] = { + "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", + "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn", +}; + +struct ArmRegister { + explicit ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); } + ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) { CHECK_LE(r, 15U); } + uint32_t r; +}; +std::ostream& operator<<(std::ostream& os, const ArmRegister& r) { + if (r.r == 13) { + os << "sp"; + } else if (r.r == 14) { + os << "lr"; + } else if (r.r == 15) { + os << "pc"; + } else { + os << "r" << r.r; + } + return os; +} + +struct ThumbRegister : ArmRegister { + ThumbRegister(uint16_t instruction, uint16_t at_bit) : ArmRegister((instruction >> at_bit) & 0x7) {} +}; + +struct Rm { + explicit Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {} + uint32_t shift; + ArmRegister rm; +}; +std::ostream& operator<<(std::ostream& os, const Rm& r) { + os << r.rm; + if (r.shift != 0) { + os << "-shift-" << r.shift; // TODO + } + return os; +} + +struct ShiftedImmediate { + explicit ShiftedImmediate(uint32_t instruction) { + uint32_t rotate = ((instruction >> 8) & 0xf); + uint32_t imm = (instruction & 0xff); + value = (imm >> (2 * rotate)) | (imm << (32 - (2 * rotate))); + } + uint32_t value; +}; +std::ostream& operator<<(std::ostream& os, const ShiftedImmediate& rhs) { + os << "#" << rhs.value; + return os; +} + +struct RegisterList { + explicit RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {} + uint32_t register_list; +}; +std::ostream& operator<<(std::ostream& os, const RegisterList& rhs) { + if (rhs.register_list == 0) { + os << ""; + return os; + } + os << "{"; + bool first = true; + for (size_t i = 0; i < 16; i++) { + if ((rhs.register_list & (1 << i)) != 0) { + if (first) { + first = false; + } else { + os << ", "; + } + os << ArmRegister(i); + } + } + os << "}"; + return os; +} + +void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) { + uint32_t instruction = ReadU32(instr_ptr); + uint32_t cond = (instruction >> 28) & 0xf; + uint32_t op1 = (instruction >> 25) & 0x7; + std::string opcode; + std::string suffixes; + std::ostringstream args; + switch (op1) { + case 0: + case 1: // Data processing instructions. + { + if ((instruction & 0x0ff000f0) == 0x01200070) { // BKPT + opcode = "bkpt"; + uint32_t imm12 = (instruction >> 8) & 0xfff; + uint32_t imm4 = (instruction & 0xf); + args << '#' << ((imm12 << 4) | imm4); + break; + } + if ((instruction & 0x0fffffd0) == 0x012fff10) { // BX and BLX (register) + opcode = (((instruction >> 5) & 1) ? "blx" : "bx"); + args << ArmRegister(instruction & 0xf); + break; + } + bool i = (instruction & (1 << 25)) != 0; + bool s = (instruction & (1 << 20)) != 0; + uint32_t op = (instruction >> 21) & 0xf; + opcode = kDataProcessingOperations[op]; + bool implicit_s = ((op & ~3) == 8); // TST, TEQ, CMP, and CMN. + if (implicit_s) { + // Rd is unused (and not shown), and we don't show the 's' suffix either. + } else { + if (s) { + suffixes += 's'; + } + args << ArmRegister(instruction, 12) << ", "; + } + if (i) { + args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction); + } else { + args << Rm(instruction); + } + } + break; + case 2: // Load/store word and unsigned byte. + { + bool p = (instruction & (1 << 24)) != 0; + bool b = (instruction & (1 << 22)) != 0; + bool w = (instruction & (1 << 21)) != 0; + bool l = (instruction & (1 << 20)) != 0; + opcode = StringPrintf("%s%s", (l ? "ldr" : "str"), (b ? "b" : "")); + args << ArmRegister(instruction, 12) << ", "; + ArmRegister rn(instruction, 16); + if (rn.r == 0xf) { + UNIMPLEMENTED(FATAL) << "literals"; + } else { + bool wback = !p || w; + uint32_t offset = (instruction & 0xfff); + if (p && !wback) { + args << "[" << rn << ", #" << offset << "]"; + } else if (p && wback) { + args << "[" << rn << ", #" << offset << "]!"; + } else if (!p && wback) { + args << "[" << rn << "], #" << offset; + } else { + LOG(FATAL) << p << " " << w; + } + if (rn.r == 9) { + args << " ; "; + Thread::DumpThreadOffset(args, offset, 4); + } + } + } + break; + case 4: // Load/store multiple. + { + bool p = (instruction & (1 << 24)) != 0; + bool u = (instruction & (1 << 23)) != 0; + bool w = (instruction & (1 << 21)) != 0; + bool l = (instruction & (1 << 20)) != 0; + opcode = StringPrintf("%s%c%c", (l ? "ldm" : "stm"), (u ? 'i' : 'd'), (p ? 'b' : 'a')); + args << ArmRegister(instruction, 16) << (w ? "!" : "") << ", " << RegisterList(instruction); + } + break; + case 5: // Branch/branch with link. + { + bool bl = (instruction & (1 << 24)) != 0; + opcode = (bl ? "bl" : "b"); + int32_t imm26 = (instruction & 0xffffff) << 2; + int32_t imm32 = (imm26 << 6) >> 6; // Sign extend. + DumpBranchTarget(args, instr_ptr + 8, imm32); + } + break; + default: + opcode = "???"; + break; + } + opcode += kConditionCodeNames[cond]; + opcode += suffixes; + // TODO: a more complete ARM disassembler could generate wider opcodes. + os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n'; +} + +size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) { + uint32_t instr = (ReadU16(instr_ptr) << 16) | ReadU16(instr_ptr + 2); + // |111|1 1|1000000|0000|1111110000000000| + // |5 3|2 1|0987654|3 0|5 0 5 0| + // |---|---|-------|----|----------------| + // |332|2 2|2222222|1111|1111110000000000| + // |1 9|8 7|6543210|9 6|5 0 5 0| + // |---|---|-------|----|----------------| + // |111|op1| op2 | | | + uint32_t op1 = (instr >> 27) & 3; + if (op1 == 0) { + return DumpThumb16(os, instr_ptr); + } + + uint32_t op2 = (instr >> 20) & 0x7F; + std::ostringstream opcode; + std::ostringstream args; + switch (op1) { + case 0: + break; + case 1: + if ((op2 & 0x64) == 0) { // 00x x0xx + // |111|11|10|00|0|00|0000|1111110000000000| + // |5 3|21|09|87|6|54|3 0|5 0 5 0| + // |---|--|--|--|-|--|----|----------------| + // |332|22|22|22|2|22|1111|1111110000000000| + // |1 9|87|65|43|2|10|9 6|5 0 5 0| + // |---|--|--|--|-|--|----|----------------| + // |111|01|00|op|0|WL| Rn | | + // |111|01| op2 | | | + // STM - 111 01 00-01-0-W0 nnnn rrrrrrrrrrrrrrrr + // LDM - 111 01 00-01-0-W1 nnnn rrrrrrrrrrrrrrrr + // PUSH- 111 01 00-01-0-10 1101 0M0rrrrrrrrrrrrr + // POP - 111 01 00-01-0-11 1101 PM0rrrrrrrrrrrrr + uint32_t op = (instr >> 23) & 3; + uint32_t W = (instr >> 21) & 1; + uint32_t L = (instr >> 20) & 1; + ArmRegister Rn(instr, 16); + if (op == 1 || op == 2) { + if (op == 1) { + if (L == 0) { + opcode << "stm"; + args << Rn << (W == 0 ? "" : "!") << ", "; + } else { + if (Rn.r != 13) { + opcode << "ldm"; + args << Rn << (W == 0 ? "" : "!") << ", "; + } else { + opcode << "pop"; + } + } + } else { + if (L == 0) { + if (Rn.r != 13) { + opcode << "stmdb"; + args << Rn << (W == 0 ? "" : "!") << ", "; + } else { + opcode << "push"; + } + } else { + opcode << "ldmdb"; + args << Rn << (W == 0 ? "" : "!") << ", "; + } + } + args << RegisterList(instr); + } + } else if ((op2 & 0x64) == 4) { // 00x x1xx + uint32_t op3 = (instr >> 23) & 3; + uint32_t op4 = (instr >> 20) & 3; + // uint32_t op5 = (instr >> 4) & 0xF; + ArmRegister Rn(instr, 16); + ArmRegister Rt(instr, 12); + uint32_t imm8 = instr & 0xFF; + if (op3 == 0 && op4 == 0) { // STREX + ArmRegister Rd(instr, 8); + opcode << "strex"; + args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; + } else if (op3 == 0 && op4 == 1) { // LDREX + opcode << "ldrex"; + args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; + } + } else if ((op2 & 0x60) == 0x20) { // 01x xxxx + // Data-processing (shifted register) + // |111|1110|0000|0|0000|1111|1100|00|00|0000| + // |5 3|2109|8765|4|3 0|5 |10 8|7 |5 |3 0| + // |---|----|----|-|----|----|----|--|--|----| + // |332|2222|2222|2|1111|1111|1100|00|00|0000| + // |1 9|8765|4321|0|9 6|5 |10 8|7 |5 |3 0| + // |---|----|----|-|----|----|----|--|--|----| + // |111|0101| op3|S| Rn |imm3| Rd |i2|ty| Rm | + uint32_t op3 = (instr >> 21) & 0xF; + uint32_t S = (instr >> 20) & 1; + uint32_t imm3 = ((instr >> 12) & 0x7); + uint32_t imm2 = ((instr >> 6) & 0x3); + uint32_t imm5 = ((imm3 << 3) | imm2) & 0x1F; + uint32_t shift_type = ((instr >> 4) & 0x2); + ArmRegister Rd(instr, 8); + ArmRegister Rn(instr, 16); + ArmRegister Rm(instr, 0); + switch (op3) { + case 0x0: + if (Rd.r != 0xF) { + opcode << "and"; + } else { + if (S != 1U) { + opcode << "UNKNOWN TST-" << S; + break; + } + opcode << "tst"; + S = 0; // don't print 's' + } + break; + case 0x1: opcode << "bic"; break; + case 0x2: + if (Rn.r != 0xF) { + opcode << "orr"; + } else { + // TODO: use canonical form if there is a shift (lsl, ...). + opcode << "mov"; + } + break; + case 0x3: + if (Rn.r != 0xF) { + opcode << "orn"; + } else { + opcode << "mvn"; + } + break; + case 0x4: + if (Rd.r != 0xF) { + opcode << "eor"; + } else { + if (S != 1U) { + opcode << "UNKNOWN TEQ-" << S; + break; + } + opcode << "teq"; + S = 0; // don't print 's' + } + break; + case 0x6: opcode << "pkh"; break; + case 0x8: + if (Rd.r != 0xF) { + opcode << "add"; + } else { + if (S != 1U) { + opcode << "UNKNOWN CMN-" << S; + break; + } + opcode << "cmn"; + S = 0; // don't print 's' + } + break; + case 0xA: opcode << "adc"; break; + case 0xB: opcode << "sbc"; break; + case 0xD: + if (Rd.r != 0xF) { + opcode << "sub"; + } else { + if (S != 1U) { + opcode << "UNKNOWN CMP-" << S; + break; + } + opcode << "cmp"; + S = 0; // don't print 's' + } + break; + case 0xE: opcode << "rsb"; break; + default: opcode << "UNKNOWN DPSR-" << op3; break; + } + + if (S == 1) { + opcode << "s"; + } + opcode << ".w"; + + if (Rd.r != 0xF) { + args << Rd << ", "; + } + if (Rn.r != 0xF) { + args << Rn << ", "; + } + args << Rm; + + // Shift operand. + bool noShift = (imm5 == 0 && shift_type != 0x3); + if (!noShift) { + args << ", "; + switch (shift_type) { + case 0x0: args << "lsl"; break; + case 0x1: args << "lsr"; break; + case 0x2: args << "asr"; break; + case 0x3: + if (imm5 == 0) { + args << "rrx"; + } else { + args << "ror"; + } + break; + } + if (shift_type != 0x3 /* rrx */) { + args << StringPrintf(" #%d", imm5); + } + } + + } else if ((op2 & 0x40) == 0x40) { // 1xx xxxx + // Co-processor instructions + // |111|1|11|000000|0000|1111|1100|000|0 |0000| + // |5 3|2|10|987654|3 0|54 2|10 8|7 5|4 | 0| + // |---|-|--|------|----|----|----|---|---|----| + // |332|2|22|222222|1111|1111|1100|000|0 |0000| + // |1 9|8|76|543210|9 6|54 2|10 8|7 5|4 | 0| + // |---|-|--|------|----|----|----|---|---|----| + // |111| |11| op3 | Rn | |copr| |op4| | + uint32_t op3 = (instr >> 20) & 0x3F; + uint32_t coproc = (instr >> 8) & 0xF; + uint32_t op4 = (instr >> 4) & 0x1; + if ((op3 == 2 || op3 == 2 || op3 == 6 || op3 == 7) || // 00x1x + (op3 >= 8 && op3 <= 15) || (op3 >= 16 && op3 <= 31)) { // 001xxx, 01xxxx + // Extension register load/store instructions + // |111|1|110|00000|0000|1111|110|000000000| + // |5 3|2|109|87654|3 0|54 2|10 |87 54 0| + // |---|-|---|-----|----|----|---|---------| + // |332|2|222|22222|1111|1111|110|000000000| + // |1 9|8|765|43210|9 6|54 2|10 |87 54 0| + // |---|-|---|-----|----|----|---|---------| + // |111|T|110| op3 | Rn | |101| | + // 111 0 110 01001 0011 0000 101 000000011 - ec930a03 + if (op3 == 9 || op3 == 0xD) { // VLDM + // 1110 110 PUDW1 nnnn dddd 101S iiii iiii + uint32_t P = (instr >> 24) & 1; + uint32_t U = (instr >> 23) & 1; + uint32_t D = (instr >> 22) & 1; + uint32_t W = (instr >> 21) & 1; + uint32_t S = (instr >> 8) & 1; + ArmRegister Rn(instr, 16); + uint32_t Vd = (instr >> 12) & 0xF; + uint32_t imm8 = instr & 0xFF; + uint32_t d = (S == 0 ? ((Vd << 1) | D) : (Vd | (D << 4))); + if (P == 0 && U == 0 && W == 0) { + // TODO: 64bit transfers between ARM core and extension registers. + } else if (P == 0 && U == 1 && Rn.r == 13) { // VPOP + opcode << "vpop" << (S == 0 ? ".f64" : ".f32"); + args << d << " .. " << (d + imm8); + } else if (P == 1 && W == 0) { // VLDR + opcode << "vldr" << (S == 0 ? ".f64" : ".f32"); + args << d << ", [" << Rn << ", #" << imm8 << "]"; + } else { // VLDM + opcode << "vldm" << (S == 0 ? ".f64" : ".f32"); + args << Rn << ", " << d << " .. " << (d + imm8); + } + } + } else if ((op3 & 0x30) == 0x20 && op4 == 0) { // 10 xxxx ... 0 + if ((coproc & 0xE) == 0xA) { + // VFP data-processing instructions + // |111|1|1100|0000|0000|1111|110|0|00 |0|0|0000| + // |5 3|2|1098|7654|3 0|54 2|10 |8|76 |5|4|3 0| + // |---|-|----|----|----|----|---|-|----|-|-|----| + // |332|2|2222|2222|1111|1111|110|0|00 |0|0|0000| + // |1 9|8|7654|3210|9 6|54 2|109|8|76 |5|4|3 0| + // |---|-|----|----|----|----|---|-|----|-|-|----| + // |111|T|1110|opc1|opc2| |101| |opc3| | | | + // 111 0 1110|1111 0100 1110 101 0 01 1 0 1001 - eef4ea69 + uint32_t opc1 = (instr >> 20) & 0xF; + uint32_t opc2 = (instr >> 16) & 0xF; + uint32_t opc3 = (instr >> 6) & 0x3; + if ((opc1 & 0xB) == 0xB) { // 1x11 + // Other VFP data-processing instructions. + uint32_t D = (instr >> 22) & 0x1; + uint32_t Vd = (instr >> 12) & 0xF; + uint32_t sz = (instr >> 8) & 1; + uint32_t M = (instr >> 5) & 1; + uint32_t Vm = instr & 0xF; + bool dp_operation = sz == 1; + switch (opc2) { + case 0x1: // Vneg/Vsqrt + // 1110 11101 D 11 0001 dddd 101s o1M0 mmmm + opcode << (opc3 == 1 ? "vneg" : "vsqrt") << (dp_operation ? ".f64" : ".f32"); + if (dp_operation) { + args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm); + } else { + args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M); + } + break; + case 0x4: case 0x5: { // Vector compare + // 1110 11101 D 11 0100 dddd 101 sE1M0 mmmm + opcode << (opc3 == 1 ? "vcmp" : "vcmpe") << (dp_operation ? ".f64" : ".f32"); + if (dp_operation) { + args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm); + } else { + args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M); + } + break; + } + } + } + } + } else if ((op3 & 0x30) == 0x30) { // 11 xxxx + // Advanced SIMD + if ((instr & 0xFFBF0ED0) == 0xeeb10ac0) { // Vsqrt + // 1110 11101 D 11 0001 dddd 101S 11M0 mmmm + // 1110 11101 0 11 0001 1101 1011 1100 1000 - eeb1dbc8 + uint32_t D = (instr >> 22) & 1; + uint32_t Vd = (instr >> 12) & 0xF; + uint32_t sz = (instr >> 8) & 1; + uint32_t M = (instr >> 5) & 1; + uint32_t Vm = instr & 0xF; + bool dp_operation = sz == 1; + opcode << "vsqrt" << (dp_operation ? ".f64" : ".f32"); + if (dp_operation) { + args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm); + } else { + args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M); + } + } + } + } + break; + case 2: + if ((instr & 0x8000) == 0 && (op2 & 0x20) == 0) { + // Data-processing (modified immediate) + // |111|11|10|0000|0|0000|1|111|1100|00000000| + // |5 3|21|09|8765|4|3 0|5|4 2|10 8|7 5 0| + // |---|--|--|----|-|----|-|---|----|--------| + // |332|22|22|2222|2|1111|1|111|1100|00000000| + // |1 9|87|65|4321|0|9 6|5|4 2|10 8|7 5 0| + // |---|--|--|----|-|----|-|---|----|--------| + // |111|10|i0| op3|S| Rn |0|iii| Rd |iiiiiiii| + // 111 10 x0 xxxx x xxxx opxxx xxxx xxxxxxxx + uint32_t i = (instr >> 26) & 1; + uint32_t op3 = (instr >> 21) & 0xF; + uint32_t S = (instr >> 20) & 1; + ArmRegister Rn(instr, 16); + uint32_t imm3 = (instr >> 12) & 7; + ArmRegister Rd(instr, 8); + uint32_t imm8 = instr & 0xFF; + int32_t imm32 = (i << 11) | (imm3 << 8) | imm8; + if (Rn.r == 0xF && (op3 == 0x2 || op3 == 0x3)) { + if (op3 == 0x2) { + opcode << "mov"; + if (S == 1) { + opcode << "s"; + } + opcode << ".w"; + } else { + opcode << "mvn"; + if (S == 1) { + opcode << "s"; + } + } + args << Rd << ", ThumbExpand(" << imm32 << ")"; + } else if (Rd.r == 0xF && S == 1 && + (op3 == 0x0 || op3 == 0x4 || op3 == 0x8 || op3 == 0xD)) { + if (op3 == 0x0) { + opcode << "tst"; + } else if (op3 == 0x4) { + opcode << "teq"; + } else if (op3 == 0x8) { + opcode << "cmw"; + } else { + opcode << "cmp.w"; + } + args << Rn << ", ThumbExpand(" << imm32 << ")"; + } else { + switch (op3) { + case 0x0: opcode << "and"; break; + case 0x1: opcode << "bic"; break; + case 0x2: opcode << "orr"; break; + case 0x3: opcode << "orn"; break; + case 0x4: opcode << "eor"; break; + case 0x8: opcode << "add"; break; + case 0xA: opcode << "adc"; break; + case 0xB: opcode << "sbc"; break; + case 0xD: opcode << "sub"; break; + case 0xE: opcode << "rsb"; break; + default: opcode << "UNKNOWN DPMI-" << op3; break; + } + if (S == 1) { + opcode << "s"; + } + args << Rd << ", " << Rn << ", ThumbExpand(" << imm32 << ")"; + } + } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) { + // Data-processing (plain binary immediate) + // |111|11|10|00000|0000|1|111110000000000| + // |5 3|21|09|87654|3 0|5|4 0 5 0| + // |---|--|--|-----|----|-|---------------| + // |332|22|22|22222|1111|1|111110000000000| + // |1 9|87|65|43210|9 6|5|4 0 5 0| + // |---|--|--|-----|----|-|---------------| + // |111|10|x1| op3 | Rn |0|xxxxxxxxxxxxxxx| + uint32_t op3 = (instr >> 20) & 0x1F; + switch (op3) { + case 0x00: case 0x0A: { + // ADD/SUB.W Rd, Rn #imm12 - 111 10 i1 0101 0 nnnn 0 iii dddd iiiiiiii + ArmRegister Rd(instr, 8); + ArmRegister Rn(instr, 16); + uint32_t i = (instr >> 26) & 1; + uint32_t imm3 = (instr >> 12) & 0x7; + uint32_t imm8 = instr & 0xFF; + uint32_t imm12 = (i << 11) | (imm3 << 8) | imm8; + if (Rn.r != 0xF) { + opcode << (op3 == 0 ? "addw" : "subw"); + args << Rd << ", " << Rn << ", #" << imm12; + } else { + opcode << "adr"; + args << Rd << ", "; + DumpBranchTarget(args, instr_ptr + 4, (op3 == 0) ? imm12 : -imm12); + } + break; + } + case 0x04: case 0x0C: { + // MOVW/T Rd, #imm16 - 111 10 i0 0010 0 iiii 0 iii dddd iiiiiiii + ArmRegister Rd(instr, 8); + uint32_t i = (instr >> 26) & 1; + uint32_t imm3 = (instr >> 12) & 0x7; + uint32_t imm8 = instr & 0xFF; + uint32_t Rn = (instr >> 16) & 0xF; + uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8; + opcode << (op3 == 0x04 ? "movw" : "movt"); + args << Rd << ", #" << imm16; + break; + } + case 0x16: { + // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii + ArmRegister Rd(instr, 8); + ArmRegister Rn(instr, 16); + uint32_t msb = instr & 0x1F; + uint32_t imm2 = (instr >> 6) & 0x3; + uint32_t imm3 = (instr >> 12) & 0x7; + uint32_t lsb = (imm3 << 2) | imm2; + uint32_t width = msb - lsb + 1; + if (Rn.r != 0xF) { + opcode << "bfi"; + args << Rd << ", " << Rn << ", #" << lsb << ", #" << width; + } else { + opcode << "bfc"; + args << Rd << ", #" << lsb << ", #" << width; + } + break; + } + default: + break; + } + } else { + // Branches and miscellaneous control + // |111|11|1000000|0000|1|111|1100|00000000| + // |5 3|21|0987654|3 0|5|4 2|10 8|7 5 0| + // |---|--|-------|----|-|---|----|--------| + // |332|22|2222222|1111|1|111|1100|00000000| + // |1 9|87|6543210|9 6|5|4 2|10 8|7 5 0| + // |---|--|-------|----|-|---|----|--------| + // |111|10| op2 | |1|op3|op4 | | + + uint32_t op3 = (instr >> 12) & 7; + // uint32_t op4 = (instr >> 8) & 0xF; + switch (op3) { + case 0: + if ((op2 & 0x38) != 0x38) { + // Conditional branch + // |111|11|1|0000|000000|1|1|1 |1|1 |10000000000| + // |5 3|21|0|9876|543 0|5|4|3 |2|1 |0 5 0| + // |---|--|-|----|------|-|-|--|-|--|-----------| + // |332|22|2|2222|221111|1|1|1 |1|1 |10000000000| + // |1 9|87|6|5432|109 6|5|4|3 |2|1 |0 5 0| + // |---|--|-|----|------|-|-|--|-|--|-----------| + // |111|10|S|cond| imm6 |1|0|J1|0|J2| imm11 | + uint32_t S = (instr >> 26) & 1; + uint32_t J2 = (instr >> 11) & 1; + uint32_t J1 = (instr >> 13) & 1; + uint32_t imm6 = (instr >> 16) & 0x3F; + uint32_t imm11 = instr & 0x7FF; + uint32_t cond = (instr >> 22) & 0xF; + int32_t imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); + imm32 = (imm32 << 11) >> 11; // sign extend 21bit immediate + opcode << "b"; + DumpCond(opcode, cond); + opcode << ".w"; + DumpBranchTarget(args, instr_ptr + 4, imm32); + } else if (op2 == 0x3B) { + // Miscellaneous control instructions + uint32_t op5 = (instr >> 4) & 0xF; + switch (op5) { + case 4: opcode << "dsb"; break; + case 5: opcode << "dmb"; break; + case 6: opcode << "isb"; break; + } + } + break; + case 2: + if ((op2 & 0x38) == 0x38) { + if (op2 == 0x7F) { + opcode << "udf"; + } + break; + } + // Else deliberate fall-through to B. + case 1: case 3: { + // B + // |111|11|1|0000|000000|11|1 |1|1 |10000000000| + // |5 3|21|0|9876|543 0|54|3 |2|1 |0 5 0| + // |---|--|-|----|------|--|--|-|--|-----------| + // |332|22|2|2222|221111|11|1 |1|1 |10000000000| + // |1 9|87|6|5 2|10 6|54|3 |2|1 |0 5 0| + // |---|--|-|----|------|--|--|-|--|-----------| + // |111|10|S|cond| imm6 |10|J1|0|J2| imm11 | + // |111|10|S| imm10 |10|J1|1|J2| imm11 | + uint32_t S = (instr >> 26) & 1; + uint32_t cond = (instr >> 22) & 0xF; + uint32_t J2 = (instr >> 11) & 1; + uint32_t form = (instr >> 12) & 1; + uint32_t J1 = (instr >> 13) & 1; + uint32_t imm10 = (instr >> 16) & 0x3FF; + uint32_t imm6 = (instr >> 16) & 0x3F; + uint32_t imm11 = instr & 0x7FF; + opcode << "b"; + int32_t imm32; + if (form == 0) { + DumpCond(opcode, cond); + imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); + imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate. + } else { + uint32_t I1 = ~(J1 ^ S); + uint32_t I2 = ~(J2 ^ S); + imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); + imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate. + } + opcode << ".w"; + DumpBranchTarget(args, instr_ptr + 4, imm32); + break; + } + case 4: case 6: case 5: case 7: { + // BL, BLX (immediate) + // |111|11|1|0000000000|11|1 |1|1 |10000000000| + // |5 3|21|0|9876543 0|54|3 |2|1 |0 5 0| + // |---|--|-|----------|--|--|-|--|-----------| + // |332|22|2|2222221111|11|1 |1|1 |10000000000| + // |1 9|87|6|5 0 6|54|3 |2|1 |0 5 0| + // |---|--|-|----------|--|--|-|--|-----------| + // |111|10|S| imm10 |11|J1|L|J2| imm11 | + uint32_t S = (instr >> 26) & 1; + uint32_t J2 = (instr >> 11) & 1; + uint32_t L = (instr >> 12) & 1; + uint32_t J1 = (instr >> 13) & 1; + uint32_t imm10 = (instr >> 16) & 0x3FF; + uint32_t imm11 = instr & 0x7FF; + if (L == 0) { + opcode << "bx"; + } else { + opcode << "blx"; + } + uint32_t I1 = ~(J1 ^ S); + uint32_t I2 = ~(J2 ^ S); + int32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); + imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate. + DumpBranchTarget(args, instr_ptr + 4, imm32); + break; + } + } + } + break; + case 3: + switch (op2) { + case 0x00: case 0x02: case 0x04: case 0x06: // 000xxx0 + case 0x08: case 0x0A: case 0x0C: case 0x0E: { + // Store single data item + // |111|11|100|000|0|0000|1111|110000|000000| + // |5 3|21|098|765|4|3 0|5 2|10 6|5 0| + // |---|--|---|---|-|----|----|------|------| + // |332|22|222|222|2|1111|1111|110000|000000| + // |1 9|87|654|321|0|9 6|5 2|10 6|5 0| + // |---|--|---|---|-|----|----|------|------| + // |111|11|000|op3|0| | | op4 | | + uint32_t op3 = (instr >> 21) & 7; + // uint32_t op4 = (instr >> 6) & 0x3F; + switch (op3) { + case 0x0: case 0x4: { + // STRB Rt,[Rn,#+/-imm8] - 111 11 00 0 0 00 0 nnnn tttt 1 PUWii ii iiii + // STRB Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 00 0 nnnn tttt 0 00000 ii mmmm + ArmRegister Rn(instr, 16); + ArmRegister Rt(instr, 12); + opcode << "strb"; + if ((instr & 0x800) != 0) { + uint32_t imm8 = instr & 0xFF; + args << Rt << ", [" << Rn << ",#" << imm8 << "]"; + } else { + uint32_t imm2 = (instr >> 4) & 3; + ArmRegister Rm(instr, 0); + args << Rt << ", [" << Rn << ", " << Rm; + if (imm2 != 0) { + args << ", " << "lsl #" << imm2; + } + args << "]"; + } + break; + } + case 0x2: case 0x6: { + ArmRegister Rn(instr, 16); + ArmRegister Rt(instr, 12); + if (op3 == 2) { + if ((instr & 0x800) != 0) { + // STR Rt, [Rn, #imm8] - 111 11 000 010 0 nnnn tttt 1PUWiiiiiiii + uint32_t P = (instr >> 10) & 1; + uint32_t U = (instr >> 9) & 1; + uint32_t W = (instr >> 8) & 1; + uint32_t imm8 = instr & 0xFF; + int32_t imm32 = (imm8 << 24) >> 24; // sign-extend imm8 + if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) { + opcode << "push"; + args << Rt; + } else if (Rn.r == 15 || (P == 0 && W == 0)) { + opcode << "UNDEFINED"; + } else { + if (P == 1 && U == 1 && W == 0) { + opcode << "strt"; + } else { + opcode << "str"; + } + args << Rt << ", [" << Rn; + if (P == 0 && W == 1) { + args << "], #" << imm32; + } else { + args << ", #" << imm32 << "]"; + if (W == 1) { + args << "!"; + } + } + } + } else { + // STR Rt, [Rn, Rm, LSL #imm2] - 111 11 000 010 0 nnnn tttt 000000iimmmm + ArmRegister Rn(instr, 16); + ArmRegister Rt(instr, 12); + ArmRegister Rm(instr, 0); + uint32_t imm2 = (instr >> 4) & 3; + opcode << "str.w"; + args << Rt << ", [" << Rn << ", " << Rm; + if (imm2 != 0) { + args << ", lsl #" << imm2; + } + args << "]"; + } + } else if (op3 == 6) { + // STR.W Rt, [Rn, #imm12] - 111 11 000 110 0 nnnn tttt iiiiiiiiiiii + uint32_t imm12 = instr & 0xFFF; + opcode << "str.w"; + args << Rt << ", [" << Rn << ", #" << imm12 << "]"; + } + break; + } + } + + break; + } + case 0x03: case 0x0B: case 0x13: case 0x1B: { // 00xx011 + // Load halfword + // |111|11|10|0 0|00|0|0000|1111|110000|000000| + // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0| + // |---|--|--|---|--|-|----|----|------|------| + // |332|22|22|2 2|22|2|1111|1111|110000|000000| + // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0| + // |---|--|--|---|--|-|----|----|------|------| + // |111|11|00|op3|01|1| Rn | Rt | op4 | | + // |111|11| op2 | | | imm12 | + uint32_t op3 = (instr >> 23) & 3; + ArmRegister Rn(instr, 16); + ArmRegister Rt(instr, 12); + if (Rt.r != 15) { + if (op3 == 1) { + // LDRH.W Rt, [Rn, #imm12] - 111 11 00 01 011 nnnn tttt iiiiiiiiiiii + uint32_t imm12 = instr & 0xFFF; + opcode << "ldrh.w"; + args << Rt << ", [" << Rn << ", #" << imm12 << "]"; + if (Rn.r == 9) { + args << " ; "; + Thread::DumpThreadOffset(args, imm12, 4); + } else if (Rn.r == 15) { + intptr_t lit_adr = reinterpret_cast(instr_ptr); + lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; + args << " ; " << reinterpret_cast(*reinterpret_cast(lit_adr)); + } + } else if (op3 == 3) { + // LDRSH.W Rt, [Rn, #imm12] - 111 11 00 11 011 nnnn tttt iiiiiiiiiiii + uint32_t imm12 = instr & 0xFFF; + opcode << "ldrsh.w"; + args << Rt << ", [" << Rn << ", #" << imm12 << "]"; + if (Rn.r == 9) { + args << " ; "; + Thread::DumpThreadOffset(args, imm12, 4); + } else if (Rn.r == 15) { + intptr_t lit_adr = reinterpret_cast(instr_ptr); + lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; + args << " ; " << reinterpret_cast(*reinterpret_cast(lit_adr)); + } + } + } + break; + } + case 0x05: case 0x0D: case 0x15: case 0x1D: { // 00xx101 + // Load word + // |111|11|10|0 0|00|0|0000|1111|110000|000000| + // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0| + // |---|--|--|---|--|-|----|----|------|------| + // |332|22|22|2 2|22|2|1111|1111|110000|000000| + // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0| + // |---|--|--|---|--|-|----|----|------|------| + // |111|11|00|op3|10|1| Rn | Rt | op4 | | + // |111|11| op2 | | | imm12 | + uint32_t op3 = (instr >> 23) & 3; + uint32_t op4 = (instr >> 6) & 0x3F; + ArmRegister Rn(instr, 16); + ArmRegister Rt(instr, 12); + if (op3 == 1 || Rn.r == 15) { + // LDR.W Rt, [Rn, #imm12] - 111 11 00 00 101 nnnn tttt iiiiiiiiiiii + // LDR.W Rt, [PC, #imm12] - 111 11 00 0x 101 1111 tttt iiiiiiiiiiii + uint32_t imm12 = instr & 0xFFF; + opcode << "ldr.w"; + args << Rt << ", [" << Rn << ", #" << imm12 << "]"; + if (Rn.r == 9) { + args << " ; "; + Thread::DumpThreadOffset(args, imm12, 4); + } else if (Rn.r == 15) { + intptr_t lit_adr = reinterpret_cast(instr_ptr); + lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; + args << " ; " << reinterpret_cast(*reinterpret_cast(lit_adr)); + } + } else if (op4 == 0) { + // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm + uint32_t imm2 = (instr >> 4) & 0xF; + ArmRegister rm(instr, 0); + opcode << "ldr.w"; + args << Rt << ", [" << Rn << ", " << rm; + if (imm2 != 0) { + args << ", lsl #" << imm2; + } + args << "]"; + } else { + // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii + uint32_t imm8 = instr & 0xFF; + opcode << "ldrt"; + args << Rt << ", [" << Rn << ", #" << imm8 << "]"; + } + break; + } + } + default: + break; + } + + // Apply any IT-block conditions to the opcode if necessary. + if (!it_conditions_.empty()) { + opcode << it_conditions_.back(); + it_conditions_.pop_back(); + } + + os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n'; + return 4; +} // NOLINT(readability/fn_size) + +size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr) { + uint16_t instr = ReadU16(instr_ptr); + bool is_32bit = ((instr & 0xF000) == 0xF000) || ((instr & 0xF800) == 0xE800); + if (is_32bit) { + return DumpThumb32(os, instr_ptr); + } else { + std::ostringstream opcode; + std::ostringstream args; + uint16_t opcode1 = instr >> 10; + if (opcode1 < 0x10) { + // shift (immediate), add, subtract, move, and compare + uint16_t opcode2 = instr >> 9; + switch (opcode2) { + case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xA: case 0xB: { + // Logical shift left - 00 000xx iii mmm ddd + // Logical shift right - 00 001xx iii mmm ddd + // Arithmetic shift right - 00 010xx iii mmm ddd + uint16_t imm5 = (instr >> 6) & 0x1F; + ThumbRegister rm(instr, 3); + ThumbRegister Rd(instr, 0); + if (opcode2 <= 3) { + opcode << "lsls"; + } else if (opcode2 <= 7) { + opcode << "lsrs"; + } else { + opcode << "asrs"; + } + args << Rd << ", " << rm << ", #" << imm5; + break; + } + case 0xC: case 0xD: case 0xE: case 0xF: { + // Add register - 00 01100 mmm nnn ddd + // Sub register - 00 01101 mmm nnn ddd + // Add 3-bit immediate - 00 01110 iii nnn ddd + // Sub 3-bit immediate - 00 01111 iii nnn ddd + uint16_t imm3_or_Rm = (instr >> 6) & 7; + ThumbRegister Rn(instr, 3); + ThumbRegister Rd(instr, 0); + if ((opcode2 & 2) != 0 && imm3_or_Rm == 0) { + opcode << "mov"; + } else { + if ((opcode2 & 1) == 0) { + opcode << "adds"; + } else { + opcode << "subs"; + } + } + args << Rd << ", " << Rn; + if ((opcode2 & 2) == 0) { + ArmRegister Rm(imm3_or_Rm); + args << ", " << Rm; + } else if (imm3_or_Rm != 0) { + args << ", #" << imm3_or_Rm; + } + break; + } + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1A: case 0x1B: + case 0x1C: case 0x1D: case 0x1E: case 0x1F: { + // MOVS Rd, #imm8 - 00100 ddd iiiiiiii + // CMP Rn, #imm8 - 00101 nnn iiiiiiii + // ADDS Rn, #imm8 - 00110 nnn iiiiiiii + // SUBS Rn, #imm8 - 00111 nnn iiiiiiii + ThumbRegister Rn(instr, 8); + uint16_t imm8 = instr & 0xFF; + switch (opcode2 >> 2) { + case 4: opcode << "movs"; break; + case 5: opcode << "cmp"; break; + case 6: opcode << "adds"; break; + case 7: opcode << "subs"; break; + } + args << Rn << ", #" << imm8; + break; + } + default: + break; + } + } else if (opcode1 == 0x10) { + // Data-processing + uint16_t opcode2 = (instr >> 6) & 0xF; + ThumbRegister rm(instr, 3); + ThumbRegister rdn(instr, 0); + opcode << kThumbDataProcessingOperations[opcode2]; + args << rdn << ", " << rm; + } else if (opcode1 == 0x11) { + // Special data instructions and branch and exchange + uint16_t opcode2 = (instr >> 6) & 0x0F; + switch (opcode2) { + case 0x0: case 0x1: case 0x2: case 0x3: { + // Add low registers - 010001 0000 xxxxxx + // Add high registers - 010001 0001/001x xxxxxx + uint16_t DN = (instr >> 7) & 1; + ArmRegister rm(instr, 3); + uint16_t Rdn = instr & 7; + ArmRegister DN_Rdn((DN << 3) | Rdn); + opcode << "add"; + args << DN_Rdn << ", " << rm; + break; + } + case 0x8: case 0x9: case 0xA: case 0xB: { + // Move low registers - 010001 1000 xxxxxx + // Move high registers - 010001 1001/101x xxxxxx + uint16_t DN = (instr >> 7) & 1; + ArmRegister rm(instr, 3); + uint16_t Rdn = instr & 7; + ArmRegister DN_Rdn((DN << 3) | Rdn); + opcode << "mov"; + args << DN_Rdn << ", " << rm; + break; + } + case 0x5: case 0x6: case 0x7: { + // Compare high registers - 010001 0101/011x xxxxxx + uint16_t N = (instr >> 7) & 1; + ArmRegister rm(instr, 3); + uint16_t Rn = instr & 7; + ArmRegister N_Rn((N << 3) | Rn); + opcode << "cmp"; + args << N_Rn << ", " << rm; + break; + } + case 0xC: case 0xD: case 0xE: case 0xF: { + // Branch and exchange - 010001 110x xxxxxx + // Branch with link and exchange - 010001 111x xxxxxx + ArmRegister rm(instr, 3); + opcode << ((opcode2 & 0x2) == 0 ? "bx" : "blx"); + args << rm; + break; + } + default: + break; + } + } else if (opcode1 == 0x12 || opcode1 == 0x13) { // 01001x + ThumbRegister Rt(instr, 8); + uint16_t imm8 = instr & 0xFF; + opcode << "ldr"; + args << Rt << ", [pc, #" << (imm8 << 2) << "]"; + } else if ((opcode1 >= 0x14 && opcode1 <= 0x17) || // 0101xx + (opcode1 >= 0x18 && opcode1 <= 0x1f) || // 011xxx + (opcode1 >= 0x20 && opcode1 <= 0x27)) { // 100xxx + // Load/store single data item + uint16_t opA = (instr >> 12) & 0xF; + if (opA == 0x5) { + uint16_t opB = (instr >> 9) & 0x7; + ThumbRegister Rm(instr, 6); + ThumbRegister Rn(instr, 3); + ThumbRegister Rt(instr, 0); + switch (opB) { + case 0: opcode << "str"; break; + case 1: opcode << "strh"; break; + case 2: opcode << "strb"; break; + case 3: opcode << "ldrsb"; break; + case 4: opcode << "ldr"; break; + case 5: opcode << "ldrh"; break; + case 6: opcode << "ldrb"; break; + case 7: opcode << "ldrsh"; break; + } + args << Rt << ", [" << Rn << ", " << Rm << "]"; + } else if (opA == 9) { + uint16_t opB = (instr >> 11) & 1; + ThumbRegister Rt(instr, 8); + uint16_t imm8 = instr & 0xFF; + opcode << (opB == 0 ? "str" : "ldr"); + args << Rt << ", [sp, #" << (imm8 << 2) << "]"; + } else { + uint16_t imm5 = (instr >> 6) & 0x1F; + uint16_t opB = (instr >> 11) & 1; + ThumbRegister Rn(instr, 3); + ThumbRegister Rt(instr, 0); + switch (opA) { + case 6: + imm5 <<= 2; + opcode << (opB == 0 ? "str" : "ldr"); + break; + case 7: + imm5 <<= 0; + opcode << (opB == 0 ? "strb" : "ldrb"); + break; + case 8: + imm5 <<= 1; + opcode << (opB == 0 ? "strh" : "ldrh"); + break; + } + args << Rt << ", [" << Rn << ", #" << imm5 << "]"; + } + } else if (opcode1 >= 0x34 && opcode1 <= 0x37) { // 1101xx + int8_t imm8 = instr & 0xFF; + uint32_t cond = (instr >> 8) & 0xF; + opcode << "b"; + DumpCond(opcode, cond); + DumpBranchTarget(args, instr_ptr + 4, (imm8 << 1)); + } else if ((instr & 0xF800) == 0xA800) { + // Generate SP-relative address + ThumbRegister rd(instr, 8); + int imm8 = instr & 0xFF; + opcode << "add"; + args << rd << ", sp, #" << (imm8 << 2); + } else if ((instr & 0xF000) == 0xB000) { + // Miscellaneous 16-bit instructions + uint16_t opcode2 = (instr >> 5) & 0x7F; + switch (opcode2) { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: { + // Add immediate to SP - 1011 00000 ii iiiii + // Subtract immediate from SP - 1011 00001 ii iiiii + int imm7 = instr & 0x7F; + opcode << ((opcode2 & 4) == 0 ? "add" : "sub"); + args << "sp, sp, #" << (imm7 << 2); + break; + } + case 0x08: case 0x09: case 0x0A: case 0x0B: // 0001xxx + case 0x0C: case 0x0D: case 0x0E: case 0x0F: + case 0x18: case 0x19: case 0x1A: case 0x1B: // 0011xxx + case 0x1C: case 0x1D: case 0x1E: case 0x1F: + case 0x48: case 0x49: case 0x4A: case 0x4B: // 1001xxx + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + case 0x58: case 0x59: case 0x5A: case 0x5B: // 1011xxx + case 0x5C: case 0x5D: case 0x5E: case 0x5F: { + // CBNZ, CBZ + uint16_t op = (instr >> 11) & 1; + uint16_t i = (instr >> 9) & 1; + uint16_t imm5 = (instr >> 3) & 0x1F; + ThumbRegister Rn(instr, 0); + opcode << (op != 0 ? "cbnz" : "cbz"); + uint32_t imm32 = (i << 6) | (imm5 << 1); + args << Rn << ", "; + DumpBranchTarget(args, instr_ptr + 4, imm32); + break; + } + case 0x78: case 0x79: case 0x7A: case 0x7B: // 1111xxx + case 0x7C: case 0x7D: case 0x7E: case 0x7F: { + // If-Then, and hints + uint16_t opA = (instr >> 4) & 0xF; + uint16_t opB = instr & 0xF; + if (opB == 0) { + switch (opA) { + case 0: opcode << "nop"; break; + case 1: opcode << "yield"; break; + case 2: opcode << "wfe"; break; + case 3: opcode << "sev"; break; + default: break; + } + } else { + uint32_t first_cond = opA; + uint32_t mask = opB; + opcode << "it"; + + // Flesh out the base "it" opcode with the specific collection of 't's and 'e's, + // and store up the actual condition codes we'll want to add to the next few opcodes. + size_t count = 3 - CTZ(mask); + it_conditions_.resize(count + 2); // Plus the implicit 't', plus the "" for the IT itself. + for (size_t i = 0; i < count; ++i) { + bool positive_cond = ((first_cond & 1) != 0); + bool positive_mask = ((mask & (1 << (3 - i))) != 0); + if (positive_mask == positive_cond) { + opcode << 't'; + it_conditions_[i] = kConditionCodeNames[first_cond]; + } else { + opcode << 'e'; + it_conditions_[i] = kConditionCodeNames[first_cond ^ 1]; + } + } + it_conditions_[count] = kConditionCodeNames[first_cond]; // The implicit 't'. + + it_conditions_[count + 1] = ""; // No condition code for the IT itself... + DumpCond(args, first_cond); // ...because it's considered an argument. + } + break; + } + default: + break; + } + } else if (((instr & 0xF000) == 0x5000) || ((instr & 0xE000) == 0x6000) || + ((instr & 0xE000) == 0x8000)) { + // Load/store single data item + uint16_t opA = instr >> 12; + // uint16_t opB = (instr >> 9) & 7; + switch (opA) { + case 0x6: { + // STR Rt, [Rn, #imm] - 01100 iiiii nnn ttt + // LDR Rt, [Rn, #imm] - 01101 iiiii nnn ttt + uint16_t imm5 = (instr >> 6) & 0x1F; + ThumbRegister Rn(instr, 3); + ThumbRegister Rt(instr, 0); + opcode << ((instr & 0x800) == 0 ? "str" : "ldr"); + args << Rt << ", [" << Rn << ", #" << (imm5 << 2) << "]"; + break; + } + case 0x9: { + // STR Rt, [SP, #imm] - 01100 ttt iiiiiiii + // LDR Rt, [SP, #imm] - 01101 ttt iiiiiiii + uint16_t imm8 = instr & 0xFF; + ThumbRegister Rt(instr, 8); + opcode << ((instr & 0x800) == 0 ? "str" : "ldr"); + args << Rt << ", [sp, #" << (imm8 << 2) << "]"; + break; + } + default: + break; + } + } else if (opcode1 == 0x38 || opcode1 == 0x39) { + uint16_t imm11 = instr & 0x7FFF; + int32_t imm32 = imm11 << 1; + imm32 = (imm32 << 20) >> 20; // sign extend 12 bit immediate + opcode << "b"; + DumpBranchTarget(args, instr_ptr + 4, imm32); + } + + // Apply any IT-block conditions to the opcode if necessary. + if (!it_conditions_.empty()) { + opcode << it_conditions_.back(); + it_conditions_.pop_back(); + } + + os << StringPrintf("%p: %04x \t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n'; + } + return 2; +} + +} // namespace arm +} // namespace art diff --git a/disassembler/disassembler_arm.h b/disassembler/disassembler_arm.h new file mode 100644 index 0000000000..2e699ffe88 --- /dev/null +++ b/disassembler/disassembler_arm.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 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_DISASSEMBLER_DISASSEMBLER_ARM_H_ +#define ART_DISASSEMBLER_DISASSEMBLER_ARM_H_ + +#include + +#include "disassembler.h" + +namespace art { +namespace arm { + +class DisassemblerArm : public Disassembler { + public: + DisassemblerArm(); + + virtual size_t Dump(std::ostream& os, const uint8_t* begin); + virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end); + private: + void DumpArm(std::ostream& os, const uint8_t* instr); + + // Returns the size of the instruction just decoded + size_t DumpThumb16(std::ostream& os, const uint8_t* instr); + size_t DumpThumb32(std::ostream& os, const uint8_t* instr_ptr); + + void DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32); + void DumpCond(std::ostream& os, uint32_t cond); + + std::vector it_conditions_; + + DISALLOW_COPY_AND_ASSIGN(DisassemblerArm); +}; + +} // namespace arm +} // namespace art + +#endif // ART_DISASSEMBLER_DISASSEMBLER_ARM_H_ diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc new file mode 100644 index 0000000000..25bbae68ef --- /dev/null +++ b/disassembler/disassembler_mips.cc @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2012 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 "disassembler_mips.h" + +#include + +#include "base/logging.h" +#include "base/stringprintf.h" +#include "thread.h" + +namespace art { +namespace mips { + +struct MipsInstruction { + uint32_t mask; + uint32_t value; + const char* name; + const char* args_fmt; + + bool Matches(uint32_t instruction) const { + return (instruction & mask) == value; + } +}; + +static const uint32_t kOpcodeShift = 26; + +static const uint32_t kCop1 = (17 << kOpcodeShift); + +static const uint32_t kITypeMask = (0x3f << kOpcodeShift); +static const uint32_t kJTypeMask = (0x3f << kOpcodeShift); +static const uint32_t kRTypeMask = ((0x3f << kOpcodeShift) | (0x3f)); +static const uint32_t kSpecial2Mask = (0x3f << kOpcodeShift); +static const uint32_t kFpMask = kRTypeMask; + +static const MipsInstruction gMipsInstructions[] = { + // "sll r0, r0, 0" is the canonical "nop", used in delay slots. + { 0xffffffff, 0, "nop", "" }, + + // R-type instructions. + { kRTypeMask, 0, "sll", "DTA", }, + // 0, 1, movci + { kRTypeMask, 2, "srl", "DTA", }, + { kRTypeMask, 3, "sra", "DTA", }, + { kRTypeMask, 4, "sllv", "DTS", }, + { kRTypeMask, 6, "srlv", "DTS", }, + { kRTypeMask, 7, "srav", "DTS", }, + { kRTypeMask, 8, "jr", "S", }, + { kRTypeMask | (0x1f << 11), 9 | (31 << 11), "jalr", "S", }, // rd = 31 is implicit. + { kRTypeMask, 9, "jalr", "DS", }, // General case. + { kRTypeMask | (0x1f << 6), 10, "movz", "DST", }, + { kRTypeMask | (0x1f << 6), 11, "movn", "DST", }, + { kRTypeMask, 12, "syscall", "", }, // TODO: code + { kRTypeMask, 13, "break", "", }, // TODO: code + { kRTypeMask, 15, "sync", "", }, // TODO: type + { kRTypeMask, 16, "mfhi", "D", }, + { kRTypeMask, 17, "mthi", "S", }, + { kRTypeMask, 18, "mflo", "D", }, + { kRTypeMask, 19, "mtlo", "S", }, + { kRTypeMask, 24, "mult", "ST", }, + { kRTypeMask, 25, "multu", "ST", }, + { kRTypeMask, 26, "div", "ST", }, + { kRTypeMask, 27, "divu", "ST", }, + { kRTypeMask, 32, "add", "DST", }, + { kRTypeMask, 33, "addu", "DST", }, + { kRTypeMask, 34, "sub", "DST", }, + { kRTypeMask, 35, "subu", "DST", }, + { kRTypeMask, 36, "and", "DST", }, + { kRTypeMask, 37, "or", "DST", }, + { kRTypeMask, 38, "xor", "DST", }, + { kRTypeMask, 39, "nor", "DST", }, + { kRTypeMask, 42, "slt", "DST", }, + { kRTypeMask, 43, "sltu", "DST", }, + // 0, 48, tge + // 0, 49, tgeu + // 0, 50, tlt + // 0, 51, tltu + // 0, 52, teq + // 0, 54, tne + + // SPECIAL2 + { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 2, "mul", "DST" }, + { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 32, "clz", "DS" }, + { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 0, "madd", "ST" }, + { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 1, "maddu", "ST" }, + { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 2, "mul", "DST" }, + { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 4, "msub", "ST" }, + { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 5, "msubu", "ST" }, + { kSpecial2Mask | 0x3f, (28 << kOpcodeShift) | 0x3f, "sdbbp", "" }, // TODO: code + + // J-type instructions. + { kJTypeMask, 2 << kOpcodeShift, "j", "L" }, + { kJTypeMask, 3 << kOpcodeShift, "jal", "L" }, + + // I-type instructions. + { kITypeMask, 4 << kOpcodeShift, "beq", "STB" }, + { kITypeMask, 5 << kOpcodeShift, "bne", "STB" }, + { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (1 << 16), "bgez", "SB" }, + { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (0 << 16), "bltz", "SB" }, + { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (2 << 16), "bltzl", "SB" }, + { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (16 << 16), "bltzal", "SB" }, + { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (18 << 16), "bltzall", "SB" }, + { kITypeMask | (0x1f << 16), 6 << kOpcodeShift | (0 << 16), "blez", "SB" }, + { kITypeMask | (0x1f << 16), 7 << kOpcodeShift | (0 << 16), "bgtz", "SB" }, + + { 0xffff0000, (4 << kOpcodeShift), "b", "B" }, + { 0xffff0000, (1 << kOpcodeShift) | (17 << 16), "bal", "B" }, + + { kITypeMask, 8 << kOpcodeShift, "addi", "TSi", }, + { kITypeMask, 9 << kOpcodeShift, "addiu", "TSi", }, + { kITypeMask, 10 << kOpcodeShift, "slti", "TSi", }, + { kITypeMask, 11 << kOpcodeShift, "sltiu", "TSi", }, + { kITypeMask, 12 << kOpcodeShift, "andi", "TSi", }, + { kITypeMask, 13 << kOpcodeShift, "ori", "TSi", }, + { kITypeMask, 14 << kOpcodeShift, "ori", "TSi", }, + { kITypeMask, 15 << kOpcodeShift, "lui", "TI", }, + + { kITypeMask, 32u << kOpcodeShift, "lb", "TO", }, + { kITypeMask, 33u << kOpcodeShift, "lh", "TO", }, + { kITypeMask, 35u << kOpcodeShift, "lw", "TO", }, + { kITypeMask, 36u << kOpcodeShift, "lbu", "TO", }, + { kITypeMask, 37u << kOpcodeShift, "lhu", "TO", }, + { kITypeMask, 40u << kOpcodeShift, "sb", "TO", }, + { kITypeMask, 41u << kOpcodeShift, "sh", "TO", }, + { kITypeMask, 43u << kOpcodeShift, "sw", "TO", }, + { kITypeMask, 49u << kOpcodeShift, "lwc1", "tO", }, + { kITypeMask, 57u << kOpcodeShift, "swc1", "tO", }, + + // Floating point. + { kFpMask, kCop1 | 0, "add", "fdst" }, + { kFpMask, kCop1 | 1, "sub", "fdst" }, + { kFpMask, kCop1 | 2, "mul", "fdst" }, + { kFpMask, kCop1 | 3, "div", "fdst" }, + { kFpMask | (0x1f << 16), kCop1 | 4, "sqrt", "fdst" }, + { kFpMask | (0x1f << 16), kCop1 | 5, "abs", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 6, "mov", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 7, "neg", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 8, "round.l", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 9, "trunc.l", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 10, "ceil.l", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 11, "floor.l", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 12, "round.w", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 13, "trunc.w", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 14, "ceil.w", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 15, "floor.w", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 32, "cvt.s", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 33, "cvt.d", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 36, "cvt.w", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 37, "cvt.l", "fds" }, + { kFpMask | (0x1f << 16), kCop1 | 38, "cvt.ps", "fds" }, +}; + +static uint32_t ReadU32(const uint8_t* ptr) { + // We only support little-endian MIPS. + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); +} + +static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) { + uint32_t instruction = ReadU32(instr_ptr); + + uint32_t rs = (instruction >> 21) & 0x1f; // I-type, R-type. + uint32_t rt = (instruction >> 16) & 0x1f; // I-type, R-type. + uint32_t rd = (instruction >> 11) & 0x1f; // R-type. + uint32_t sa = (instruction >> 6) & 0x1f; // R-type. + + std::string opcode; + std::ostringstream args; + + // TODO: remove this! + uint32_t op = (instruction >> 26) & 0x3f; + uint32_t function = (instruction & 0x3f); // R-type. + opcode = StringPrintf("op=%d fn=%d", op, function); + + for (size_t i = 0; i < arraysize(gMipsInstructions); ++i) { + if (gMipsInstructions[i].Matches(instruction)) { + opcode = gMipsInstructions[i].name; + for (const char* args_fmt = gMipsInstructions[i].args_fmt; *args_fmt; ++args_fmt) { + switch (*args_fmt) { + case 'A': // sa (shift amount). + args << sa; + break; + case 'B': // Branch offset. + { + int32_t offset = static_cast(instruction & 0xffff); + offset <<= 2; + offset += 4; // Delay slot. + args << StringPrintf("%p ; %+d", instr_ptr + offset, offset); + } + break; + case 'D': args << 'r' << rd; break; + case 'd': args << 'f' << rd; break; + case 'f': // Floating point "fmt". + { + size_t fmt = (instruction >> 21) & 0x7; // TODO: other fmts? + switch (fmt) { + case 0: opcode += ".s"; break; + case 1: opcode += ".d"; break; + case 4: opcode += ".w"; break; + case 5: opcode += ".l"; break; + case 6: opcode += ".ps"; break; + default: opcode += ".?"; break; + } + continue; // No ", ". + } + break; + case 'I': // Upper 16-bit immediate. + args << reinterpret_cast((instruction & 0xffff) << 16); + break; + case 'i': // Sign-extended lower 16-bit immediate. + args << static_cast(instruction & 0xffff); + break; + case 'L': // Jump label. + { + // TODO: is this right? + uint32_t instr_index = (instruction & 0x1ffffff); + uint32_t target = (instr_index << 2); + target |= (reinterpret_cast(instr_ptr + 4) & 0xf0000000); + args << reinterpret_cast(target); + } + break; + case 'O': // +x(rs) + { + int32_t offset = static_cast(instruction & 0xffff); + args << StringPrintf("%+d(r%d)", offset, rs); + if (rs == 17) { + args << " ; "; + Thread::DumpThreadOffset(args, offset, 4); + } + } + break; + case 'S': args << 'r' << rs; break; + case 's': args << 'f' << rs; break; + case 'T': args << 'r' << rt; break; + case 't': args << 'f' << rt; break; + } + if (*(args_fmt + 1)) { + args << ", "; + } + } + break; + } + } + + os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n'; +} + +DisassemblerMips::DisassemblerMips() { +} + +size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin) { + DumpMips(os, begin); + return 4; +} + +void DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { + for (const uint8_t* cur = begin; cur < end; cur += 4) { + DumpMips(os, cur); + } +} + +} // namespace mips +} // namespace art diff --git a/disassembler/disassembler_mips.h b/disassembler/disassembler_mips.h new file mode 100644 index 0000000000..d3862676a0 --- /dev/null +++ b/disassembler/disassembler_mips.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 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_DISASSEMBLER_DISASSEMBLER_MIPS_H_ +#define ART_DISASSEMBLER_DISASSEMBLER_MIPS_H_ + +#include + +#include "disassembler.h" + +namespace art { +namespace mips { + +class DisassemblerMips : public Disassembler { + public: + DisassemblerMips(); + virtual size_t Dump(std::ostream& os, const uint8_t* begin); + virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end); + + private: + DISALLOW_COPY_AND_ASSIGN(DisassemblerMips); +}; + +} // namespace mips +} // namespace art + +#endif // ART_DISASSEMBLER_DISASSEMBLER_MIPS_H_ diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc new file mode 100644 index 0000000000..e5cdb7b297 --- /dev/null +++ b/disassembler/disassembler_x86.cc @@ -0,0 +1,750 @@ +/* + * Copyright (C) 2012 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 "disassembler_x86.h" + +#include + +#include "base/logging.h" +#include "base/stringprintf.h" +#include "thread.h" + +namespace art { +namespace x86 { + +DisassemblerX86::DisassemblerX86() {} + +size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) { + return DumpInstruction(os, begin); +} + +void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { + size_t length = 0; + for (const uint8_t* cur = begin; cur < end; cur += length) { + length = DumpInstruction(os, cur); + } +} + +static const char* gReg8Names[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; +static const char* gReg16Names[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; +static const char* gReg32Names[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; + +static void DumpReg0(std::ostream& os, uint8_t /*rex*/, size_t reg, + bool byte_operand, uint8_t size_override) { + DCHECK_LT(reg, 8u); + // TODO: combine rex into size + size_t size = byte_operand ? 1 : (size_override == 0x66 ? 2 : 4); + switch (size) { + case 1: os << gReg8Names[reg]; break; + case 2: os << gReg16Names[reg]; break; + case 4: os << gReg32Names[reg]; break; + default: LOG(FATAL) << "unexpected size " << size; + } +} + +enum RegFile { GPR, MMX, SSE }; + +static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg, + bool byte_operand, uint8_t size_override, RegFile reg_file) { + size_t reg_num = reg; // TODO: combine with REX.R on 64bit + if (reg_file == GPR) { + DumpReg0(os, rex, reg_num, byte_operand, size_override); + } else if (reg_file == SSE) { + os << "xmm" << reg_num; + } else { + os << "mm" << reg_num; + } +} + +static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) { + size_t reg_num = reg; // TODO: combine with REX.B on 64bit + DumpReg0(os, rex, reg_num, false, 0); +} + +static void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) { + int reg_num = reg; // TODO: combine with REX.X on 64bit + DumpReg0(os, rex, reg_num, false, 0); +} + +enum SegmentPrefix { + kCs = 0x2e, + kSs = 0x36, + kDs = 0x3e, + kEs = 0x26, + kFs = 0x64, + kGs = 0x65, +}; + +static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) { + switch (segment_prefix) { + case kCs: os << "cs:"; break; + case kSs: os << "ss:"; break; + case kDs: os << "ds:"; break; + case kEs: os << "es:"; break; + case kFs: os << "fs:"; break; + case kGs: os << "gs:"; break; + default: break; + } +} + +size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) { + const uint8_t* begin_instr = instr; + bool have_prefixes = true; + uint8_t prefix[4] = {0, 0, 0, 0}; + const char** modrm_opcodes = NULL; + do { + switch (*instr) { + // Group 1 - lock and repeat prefixes: + case 0xF0: + case 0xF2: + case 0xF3: + prefix[0] = *instr; + break; + // Group 2 - segment override prefixes: + case kCs: + case kSs: + case kDs: + case kEs: + case kFs: + case kGs: + prefix[1] = *instr; + break; + // Group 3 - operand size override: + case 0x66: + prefix[2] = *instr; + break; + // Group 4 - address size override: + case 0x67: + prefix[3] = *instr; + break; + default: + have_prefixes = false; + break; + } + if (have_prefixes) { + instr++; + } + } while (have_prefixes); + uint8_t rex = (*instr >= 0x40 && *instr <= 0x4F) ? *instr : 0; + bool has_modrm = false; + bool reg_is_opcode = false; + size_t immediate_bytes = 0; + size_t branch_bytes = 0; + std::ostringstream opcode; + bool store = false; // stores to memory (ie rm is on the left) + bool load = false; // loads from memory (ie rm is on the right) + bool byte_operand = false; + bool ax = false; // implicit use of ax + bool cx = false; // implicit use of cx + bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter + bool no_ops = false; + RegFile src_reg_file = GPR; + RegFile dst_reg_file = GPR; + switch (*instr) { +#define DISASSEMBLER_ENTRY(opname, \ + rm8_r8, rm32_r32, \ + r8_rm8, r32_rm32, \ + ax8_i8, ax32_i32) \ + case rm8_r8: opcode << #opname; store = true; has_modrm = true; byte_operand = true; break; \ + case rm32_r32: opcode << #opname; store = true; has_modrm = true; break; \ + case r8_rm8: opcode << #opname; load = true; has_modrm = true; byte_operand = true; break; \ + case r32_rm32: opcode << #opname; load = true; has_modrm = true; break; \ + case ax8_i8: opcode << #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \ + case ax32_i32: opcode << #opname; ax = true; immediate_bytes = 4; break; + +DISASSEMBLER_ENTRY(add, + 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */, + 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */, + 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */) +DISASSEMBLER_ENTRY(or, + 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */, + 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */, + 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */) +DISASSEMBLER_ENTRY(adc, + 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */, + 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */, + 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */) +DISASSEMBLER_ENTRY(sbb, + 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */, + 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */, + 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */) +DISASSEMBLER_ENTRY(and, + 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */, + 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */, + 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */) +DISASSEMBLER_ENTRY(sub, + 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */, + 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */, + 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */) +DISASSEMBLER_ENTRY(xor, + 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */, + 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */, + 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */) +DISASSEMBLER_ENTRY(cmp, + 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem32/Reg32 */, + 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */, + 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */) + +#undef DISASSEMBLER_ENTRY + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + opcode << "push"; + reg_in_opcode = true; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: + opcode << "pop"; + reg_in_opcode = true; + break; + case 0x68: opcode << "push"; immediate_bytes = 4; break; + case 0x6A: opcode << "push"; immediate_bytes = 1; break; + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: + static const char* condition_codes[] = + {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq", "nz/ne", "be/na", "nbe/a", + "s", "ns", "p/pe", "np/po", "l/nge", "nl/ge", "le/ng", "nle/g" + }; + opcode << "j" << condition_codes[*instr & 0xF]; + branch_bytes = 1; + break; + case 0x88: opcode << "mov"; store = true; has_modrm = true; byte_operand = true; break; + case 0x89: opcode << "mov"; store = true; has_modrm = true; break; + case 0x8A: opcode << "mov"; load = true; has_modrm = true; byte_operand = true; break; + case 0x8B: opcode << "mov"; load = true; has_modrm = true; break; + + case 0x0F: // 2 byte extended opcode + instr++; + switch (*instr) { + case 0x10: case 0x11: + if (prefix[0] == 0xF2) { + opcode << "movsd"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF3) { + opcode << "movss"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[2] == 0x66) { + opcode << "movupd"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "movups"; + } + has_modrm = true; + src_reg_file = dst_reg_file = SSE; + load = *instr == 0x10; + store = !load; + break; + case 0x2A: + if (prefix[2] == 0x66) { + opcode << "cvtpi2pd"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF2) { + opcode << "cvtsi2sd"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF3) { + opcode << "cvtsi2ss"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "cvtpi2ps"; + } + load = true; + has_modrm = true; + dst_reg_file = SSE; + break; + case 0x2C: + if (prefix[2] == 0x66) { + opcode << "cvttpd2pi"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF2) { + opcode << "cvttsd2si"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF3) { + opcode << "cvttss2si"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "cvttps2pi"; + } + load = true; + has_modrm = true; + src_reg_file = SSE; + break; + case 0x2D: + if (prefix[2] == 0x66) { + opcode << "cvtpd2pi"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF2) { + opcode << "cvtsd2si"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF3) { + opcode << "cvtss2si"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "cvtps2pi"; + } + load = true; + has_modrm = true; + src_reg_file = SSE; + break; + case 0x2E: + opcode << "u"; + // FALLTHROUGH + case 0x2F: + if (prefix[2] == 0x66) { + opcode << "comisd"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "comiss"; + } + has_modrm = true; + load = true; + src_reg_file = dst_reg_file = SSE; + break; + case 0x38: // 3 byte extended opcode + opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr); + break; + case 0x3A: // 3 byte extended opcode + opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr); + break; + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: { + switch (*instr) { + case 0x50: opcode << "movmsk"; break; + case 0x51: opcode << "sqrt"; break; + case 0x52: opcode << "rsqrt"; break; + case 0x53: opcode << "rcp"; break; + case 0x54: opcode << "and"; break; + case 0x55: opcode << "andn"; break; + case 0x56: opcode << "or"; break; + case 0x57: opcode << "xor"; break; + case 0x58: opcode << "add"; break; + case 0x59: opcode << "mul"; break; + case 0x5C: opcode << "sub"; break; + case 0x5D: opcode << "min"; break; + case 0x5E: opcode << "div"; break; + case 0x5F: opcode << "max"; break; + default: LOG(FATAL) << "Unreachable"; + } + if (prefix[2] == 0x66) { + opcode << "pd"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF2) { + opcode << "sd"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF3) { + opcode << "ss"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "ps"; + } + load = true; + has_modrm = true; + src_reg_file = dst_reg_file = SSE; + break; + } + case 0x5A: + if (prefix[2] == 0x66) { + opcode << "cvtpd2ps"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF2) { + opcode << "cvtsd2ss"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF3) { + opcode << "cvtss2sd"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "cvtps2pd"; + } + load = true; + has_modrm = true; + src_reg_file = dst_reg_file = SSE; + break; + case 0x5B: + if (prefix[2] == 0x66) { + opcode << "cvtps2dq"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF2) { + opcode << "bad opcode F2 0F 5B"; + } else if (prefix[0] == 0xF3) { + opcode << "cvttps2dq"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + opcode << "cvtdq2ps"; + } + load = true; + has_modrm = true; + src_reg_file = dst_reg_file = SSE; + break; + case 0x6E: + if (prefix[2] == 0x66) { + dst_reg_file = SSE; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + dst_reg_file = MMX; + } + opcode << "movd"; + load = true; + has_modrm = true; + break; + case 0x6F: + if (prefix[2] == 0x66) { + dst_reg_file = SSE; + opcode << "movdqa"; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else if (prefix[0] == 0xF3) { + dst_reg_file = SSE; + opcode << "movdqu"; + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + dst_reg_file = MMX; + opcode << "movq"; + } + load = true; + has_modrm = true; + break; + case 0x71: + if (prefix[2] == 0x66) { + dst_reg_file = SSE; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + dst_reg_file = MMX; + } + static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"}; + modrm_opcodes = x71_opcodes; + reg_is_opcode = true; + has_modrm = true; + store = true; + immediate_bytes = 1; + break; + case 0x72: + if (prefix[2] == 0x66) { + dst_reg_file = SSE; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + dst_reg_file = MMX; + } + static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"}; + modrm_opcodes = x72_opcodes; + reg_is_opcode = true; + has_modrm = true; + store = true; + immediate_bytes = 1; + break; + case 0x73: + if (prefix[2] == 0x66) { + dst_reg_file = SSE; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + dst_reg_file = MMX; + } + static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "unknown-73", "unknown-73", "unknown-73", "psllq", "unknown-73"}; + modrm_opcodes = x73_opcodes; + reg_is_opcode = true; + has_modrm = true; + store = true; + immediate_bytes = 1; + break; + case 0x7E: + if (prefix[2] == 0x66) { + src_reg_file = SSE; + prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode + } else { + src_reg_file = MMX; + } + opcode << "movd"; + has_modrm = true; + store = true; + break; + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: + opcode << "j" << condition_codes[*instr & 0xF]; + branch_bytes = 4; + break; + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: + opcode << "set" << condition_codes[*instr & 0xF]; + modrm_opcodes = NULL; + reg_is_opcode = true; + has_modrm = true; + store = true; + break; + case 0xAE: + if (prefix[0] == 0xF3) { + prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode + static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"}; + modrm_opcodes = xAE_opcodes; + reg_is_opcode = true; + has_modrm = true; + uint8_t reg_or_opcode = (instr[1] >> 3) & 7; + switch (reg_or_opcode) { + case 0: + prefix[1] = kFs; + load = true; + break; + case 1: + prefix[1] = kGs; + load = true; + break; + case 2: + prefix[1] = kFs; + store = true; + break; + case 3: + prefix[1] = kGs; + store = true; + break; + default: + load = true; + break; + } + } else { + static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"}; + modrm_opcodes = xAE_opcodes; + reg_is_opcode = true; + has_modrm = true; + load = true; + no_ops = true; + } + break; + case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break; + case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; break; + case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break; + case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break; + case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break; + default: + opcode << StringPrintf("unknown opcode '0F %02X'", *instr); + break; + } + break; + case 0x80: case 0x81: case 0x82: case 0x83: + static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; + modrm_opcodes = x80_opcodes; + has_modrm = true; + reg_is_opcode = true; + store = true; + byte_operand = (*instr & 1) == 0; + immediate_bytes = *instr == 0x81 ? 4 : 1; + break; + case 0x84: case 0x85: + opcode << "test"; + has_modrm = true; + load = true; + byte_operand = (*instr & 1) == 0; + break; + case 0x8D: + opcode << "lea"; + has_modrm = true; + load = true; + break; + case 0x8F: + opcode << "pop"; + has_modrm = true; + reg_is_opcode = true; + store = true; + break; + case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: + opcode << "mov"; + immediate_bytes = 1; + reg_in_opcode = true; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: + opcode << "mov"; + immediate_bytes = 4; + reg_in_opcode = true; + break; + case 0xC0: case 0xC1: + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + static const char* shift_opcodes[] = + {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"}; + modrm_opcodes = shift_opcodes; + has_modrm = true; + reg_is_opcode = true; + store = true; + immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0; + cx = (*instr == 0xD2) || (*instr == 0xD3); + byte_operand = (*instr == 0xC0); + break; + case 0xC3: opcode << "ret"; break; + case 0xC7: + static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"}; + modrm_opcodes = c7_opcodes; + store = true; + immediate_bytes = 4; + has_modrm = true; + reg_is_opcode = true; + break; + case 0xCC: opcode << "int 3"; break; + case 0xE8: opcode << "call"; branch_bytes = 4; break; + case 0xE9: opcode << "jmp"; branch_bytes = 4; break; + case 0xEB: opcode << "jmp"; branch_bytes = 1; break; + case 0xF5: opcode << "cmc"; break; + case 0xF6: case 0xF7: + static const char* f7_opcodes[] = {"test", "unknown-f7", "not", "neg", "mul edx:eax, eax *", "imul edx:eax, eax *", "div edx:eax, edx:eax /", "idiv edx:eax, edx:eax /"}; + modrm_opcodes = f7_opcodes; + has_modrm = true; + reg_is_opcode = true; + store = true; + immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0; + break; + case 0xFF: + static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"}; + modrm_opcodes = ff_opcodes; + has_modrm = true; + reg_is_opcode = true; + load = true; + break; + default: + opcode << StringPrintf("unknown opcode '%02X'", *instr); + break; + } + std::ostringstream args; + if (reg_in_opcode) { + DCHECK(!has_modrm); + DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR); + } + instr++; + uint32_t address_bits = 0; + if (has_modrm) { + uint8_t modrm = *instr; + instr++; + uint8_t mod = modrm >> 6; + uint8_t reg_or_opcode = (modrm >> 3) & 7; + uint8_t rm = modrm & 7; + std::ostringstream address; + if (mod == 0 && rm == 5) { // fixed address + address_bits = *reinterpret_cast(instr); + address << StringPrintf("[0x%x]", address_bits); + instr += 4; + } else if (rm == 4 && mod != 3) { // SIB + uint8_t sib = *instr; + instr++; + uint8_t ss = (sib >> 6) & 3; + uint8_t index = (sib >> 3) & 7; + uint8_t base = sib & 7; + address << "["; + if (base != 5 || mod != 0) { + DumpBaseReg(address, rex, base); + if (index != 4) { + address << " + "; + } + } + if (index != 4) { + DumpIndexReg(address, rex, index); + if (ss != 0) { + address << StringPrintf(" * %d", 1 << ss); + } + } + if (mod == 1) { + address << StringPrintf(" + %d", *reinterpret_cast(instr)); + instr++; + } else if (mod == 2) { + address << StringPrintf(" + %d", *reinterpret_cast(instr)); + instr += 4; + } + address << "]"; + } else { + if (mod == 3) { + if (!no_ops) { + DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file); + } + } else { + address << "["; + DumpBaseReg(address, rex, rm); + if (mod == 1) { + address << StringPrintf(" + %d", *reinterpret_cast(instr)); + instr++; + } else if (mod == 2) { + address << StringPrintf(" + %d", *reinterpret_cast(instr)); + instr += 4; + } + address << "]"; + } + } + + if (reg_is_opcode && modrm_opcodes != NULL) { + opcode << modrm_opcodes[reg_or_opcode]; + } + if (load) { + if (!reg_is_opcode) { + DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file); + args << ", "; + } + DumpSegmentOverride(args, prefix[1]); + args << address.str(); + } else { + DCHECK(store); + DumpSegmentOverride(args, prefix[1]); + args << address.str(); + if (!reg_is_opcode) { + args << ", "; + DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file); + } + } + } + if (ax) { + // If this opcode implicitly uses ax, ax is always the first arg. + DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR); + } + if (cx) { + args << ", "; + DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR); + } + if (immediate_bytes > 0) { + if (has_modrm || reg_in_opcode || ax || cx) { + args << ", "; + } + if (immediate_bytes == 1) { + args << StringPrintf("%d", *reinterpret_cast(instr)); + instr++; + } else { + CHECK_EQ(immediate_bytes, 4u); + args << StringPrintf("%d", *reinterpret_cast(instr)); + instr += 4; + } + } else if (branch_bytes > 0) { + DCHECK(!has_modrm); + int32_t displacement; + if (branch_bytes == 1) { + displacement = *reinterpret_cast(instr); + instr++; + } else { + CHECK_EQ(branch_bytes, 4u); + displacement = *reinterpret_cast(instr); + instr += 4; + } + args << StringPrintf("%+d (%p)", displacement, instr + displacement); + } + if (prefix[1] == kFs) { + args << " ; "; + Thread::DumpThreadOffset(args, address_bits, 4); + } + std::stringstream hex; + for (size_t i = 0; begin_instr + i < instr; ++i) { + hex << StringPrintf("%02X", begin_instr[i]); + } + std::stringstream prefixed_opcode; + switch (prefix[0]) { + case 0xF0: prefixed_opcode << "lock "; break; + case 0xF2: prefixed_opcode << "repne "; break; + case 0xF3: prefixed_opcode << "repe "; break; + case 0: break; + default: LOG(FATAL) << "Unreachable"; + } + prefixed_opcode << opcode.str(); + os << StringPrintf("%p: %22s \t%-7s ", begin_instr, hex.str().c_str(), + prefixed_opcode.str().c_str()) + << args.str() << '\n'; + return instr - begin_instr; +} // NOLINT(readability/fn_size) + +} // namespace x86 +} // namespace art diff --git a/disassembler/disassembler_x86.h b/disassembler/disassembler_x86.h new file mode 100644 index 0000000000..9adaff7048 --- /dev/null +++ b/disassembler/disassembler_x86.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 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_DISASSEMBLER_DISASSEMBLER_X86_H_ +#define ART_DISASSEMBLER_DISASSEMBLER_X86_H_ + +#include "disassembler.h" + +namespace art { +namespace x86 { + +class DisassemblerX86 : public Disassembler { + public: + DisassemblerX86(); + + virtual size_t Dump(std::ostream& os, const uint8_t* begin); + virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end); + private: + size_t DumpInstruction(std::ostream& os, const uint8_t* instr); +}; + +} // namespace x86 +} // namespace art + +#endif // ART_DISASSEMBLER_DISASSEMBLER_X86_H_ diff --git a/oatdump/Android.mk b/oatdump/Android.mk index a63b229846..7cee00e182 100644 --- a/oatdump/Android.mk +++ b/oatdump/Android.mk @@ -22,17 +22,17 @@ OATDUMP_SRC_FILES := \ include art/build/Android.executable.mk ifeq ($(ART_BUILD_TARGET_NDEBUG),true) - $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils,,target,ndebug)) + $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils libart-disassembler,art/disassembler,target,ndebug)) endif ifeq ($(ART_BUILD_TARGET_DEBUG),true) - $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils,,target,debug)) + $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils libartd-disassembler,art/disassembler,target,debug)) endif ifeq ($(WITH_HOST_DALVIK),true) ifeq ($(ART_BUILD_HOST_NDEBUG),true) - $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),,,host,ndebug)) + $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libart-disassembler,art/disassembler,host,ndebug)) endif ifeq ($(ART_BUILD_HOST_DEBUG),true) - $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),,,host,debug)) + $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libartd-disassembler,art/disassembler,host,debug)) endif endif diff --git a/runtime/Android.mk b/runtime/Android.mk index a8d505e1f5..b04cd6ae0b 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -38,10 +38,6 @@ LIBART_COMMON_SRC_FILES := \ dex_file.cc \ dex_file_verifier.cc \ dex_instruction.cc \ - disassembler.cc \ - disassembler_arm.cc \ - disassembler_mips.cc \ - disassembler_x86.cc \ elf_file.cc \ gc/allocator/dlmalloc.cc \ gc/accounting/card_table.cc \ diff --git a/runtime/disassembler.cc b/runtime/disassembler.cc deleted file mode 100644 index 067083510b..0000000000 --- a/runtime/disassembler.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2012 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 "disassembler.h" - -#include - -#include "base/logging.h" -#include "disassembler_arm.h" -#include "disassembler_mips.h" -#include "disassembler_x86.h" - -namespace art { - -Disassembler* Disassembler::Create(InstructionSet instruction_set) { - if (instruction_set == kArm || instruction_set == kThumb2) { - return new arm::DisassemblerArm(); - } else if (instruction_set == kMips) { - return new mips::DisassemblerMips(); - } else if (instruction_set == kX86) { - return new x86::DisassemblerX86(); - } else { - UNIMPLEMENTED(FATAL) << "no disassembler for " << instruction_set; - return NULL; - } -} - -} // namespace art diff --git a/runtime/disassembler.h b/runtime/disassembler.h deleted file mode 100644 index 805ff4d079..0000000000 --- a/runtime/disassembler.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2012 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_RUNTIME_DISASSEMBLER_H_ -#define ART_RUNTIME_DISASSEMBLER_H_ - -#include - -#include - -#include "base/macros.h" -#include "instruction_set.h" - -namespace art { - -class Disassembler { - public: - static Disassembler* Create(InstructionSet instruction_set); - virtual ~Disassembler() {} - - // Dump a single instruction returning the length of that instruction. - virtual size_t Dump(std::ostream& os, const uint8_t* begin) = 0; - // Dump instructions within a range. - virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) = 0; - - protected: - Disassembler() {} - - private: - DISALLOW_COPY_AND_ASSIGN(Disassembler); -}; - -} // namespace art - -#endif // ART_RUNTIME_DISASSEMBLER_H_ diff --git a/runtime/disassembler_arm.cc b/runtime/disassembler_arm.cc deleted file mode 100644 index 879d3ac71c..0000000000 --- a/runtime/disassembler_arm.cc +++ /dev/null @@ -1,1359 +0,0 @@ -/* - * Copyright (C) 2012 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 "disassembler_arm.h" - -#include - -#include "base/logging.h" -#include "base/stringprintf.h" -#include "thread.h" - -namespace art { -namespace arm { - -DisassemblerArm::DisassemblerArm() { -} - -size_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) { - if ((reinterpret_cast(begin) & 1) == 0) { - DumpArm(os, begin); - return 4; - } else { - // remove thumb specifier bits - begin = reinterpret_cast(reinterpret_cast(begin) & ~1); - return DumpThumb16(os, begin); - } -} - -void DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { - if ((reinterpret_cast(begin) & 1) == 0) { - for (const uint8_t* cur = begin; cur < end; cur += 4) { - DumpArm(os, cur); - } - } else { - // remove thumb specifier bits - begin = reinterpret_cast(reinterpret_cast(begin) & ~1); - end = reinterpret_cast(reinterpret_cast(end) & ~1); - for (const uint8_t* cur = begin; cur < end;) { - cur += DumpThumb16(os, cur); - } - } -} - -static const char* kConditionCodeNames[] = { - "eq", // 0000 - equal - "ne", // 0001 - not-equal - "cs", // 0010 - carry-set, greater than, equal or unordered - "cc", // 0011 - carry-clear, less than - "mi", // 0100 - minus, negative - "pl", // 0101 - plus, positive or zero - "vs", // 0110 - overflow - "vc", // 0111 - no overflow - "hi", // 1000 - unsigned higher - "ls", // 1001 - unsigned lower or same - "ge", // 1010 - signed greater than or equal - "lt", // 1011 - signed less than - "gt", // 1100 - signed greater than - "le", // 1101 - signed less than or equal - "", // 1110 - always - "nv", // 1111 - never (mostly obsolete, but might be a clue that we're mistranslating) -}; - -void DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) { - if (cond < 15) { - os << kConditionCodeNames[cond]; - } else { - os << "Unexpected condition: " << cond; - } -} - -void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) { - os << StringPrintf("%+d (%p)", imm32, instr_ptr + imm32); -} - -static uint32_t ReadU16(const uint8_t* ptr) { - return ptr[0] | (ptr[1] << 8); -} - -static uint32_t ReadU32(const uint8_t* ptr) { - return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); -} - -static const char* kDataProcessingOperations[] = { - "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", - "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", -}; - -static const char* kThumbDataProcessingOperations[] = { - "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", - "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn", -}; - -struct ArmRegister { - explicit ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); } - ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) { CHECK_LE(r, 15U); } - uint32_t r; -}; -std::ostream& operator<<(std::ostream& os, const ArmRegister& r) { - if (r.r == 13) { - os << "sp"; - } else if (r.r == 14) { - os << "lr"; - } else if (r.r == 15) { - os << "pc"; - } else { - os << "r" << r.r; - } - return os; -} - -struct ThumbRegister : ArmRegister { - ThumbRegister(uint16_t instruction, uint16_t at_bit) : ArmRegister((instruction >> at_bit) & 0x7) {} -}; - -struct Rm { - explicit Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {} - uint32_t shift; - ArmRegister rm; -}; -std::ostream& operator<<(std::ostream& os, const Rm& r) { - os << r.rm; - if (r.shift != 0) { - os << "-shift-" << r.shift; // TODO - } - return os; -} - -struct ShiftedImmediate { - explicit ShiftedImmediate(uint32_t instruction) { - uint32_t rotate = ((instruction >> 8) & 0xf); - uint32_t imm = (instruction & 0xff); - value = (imm >> (2 * rotate)) | (imm << (32 - (2 * rotate))); - } - uint32_t value; -}; -std::ostream& operator<<(std::ostream& os, const ShiftedImmediate& rhs) { - os << "#" << rhs.value; - return os; -} - -struct RegisterList { - explicit RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {} - uint32_t register_list; -}; -std::ostream& operator<<(std::ostream& os, const RegisterList& rhs) { - if (rhs.register_list == 0) { - os << ""; - return os; - } - os << "{"; - bool first = true; - for (size_t i = 0; i < 16; i++) { - if ((rhs.register_list & (1 << i)) != 0) { - if (first) { - first = false; - } else { - os << ", "; - } - os << ArmRegister(i); - } - } - os << "}"; - return os; -} - -void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) { - uint32_t instruction = ReadU32(instr_ptr); - uint32_t cond = (instruction >> 28) & 0xf; - uint32_t op1 = (instruction >> 25) & 0x7; - std::string opcode; - std::string suffixes; - std::ostringstream args; - switch (op1) { - case 0: - case 1: // Data processing instructions. - { - if ((instruction & 0x0ff000f0) == 0x01200070) { // BKPT - opcode = "bkpt"; - uint32_t imm12 = (instruction >> 8) & 0xfff; - uint32_t imm4 = (instruction & 0xf); - args << '#' << ((imm12 << 4) | imm4); - break; - } - if ((instruction & 0x0fffffd0) == 0x012fff10) { // BX and BLX (register) - opcode = (((instruction >> 5) & 1) ? "blx" : "bx"); - args << ArmRegister(instruction & 0xf); - break; - } - bool i = (instruction & (1 << 25)) != 0; - bool s = (instruction & (1 << 20)) != 0; - uint32_t op = (instruction >> 21) & 0xf; - opcode = kDataProcessingOperations[op]; - bool implicit_s = ((op & ~3) == 8); // TST, TEQ, CMP, and CMN. - if (implicit_s) { - // Rd is unused (and not shown), and we don't show the 's' suffix either. - } else { - if (s) { - suffixes += 's'; - } - args << ArmRegister(instruction, 12) << ", "; - } - if (i) { - args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction); - } else { - args << Rm(instruction); - } - } - break; - case 2: // Load/store word and unsigned byte. - { - bool p = (instruction & (1 << 24)) != 0; - bool b = (instruction & (1 << 22)) != 0; - bool w = (instruction & (1 << 21)) != 0; - bool l = (instruction & (1 << 20)) != 0; - opcode = StringPrintf("%s%s", (l ? "ldr" : "str"), (b ? "b" : "")); - args << ArmRegister(instruction, 12) << ", "; - ArmRegister rn(instruction, 16); - if (rn.r == 0xf) { - UNIMPLEMENTED(FATAL) << "literals"; - } else { - bool wback = !p || w; - uint32_t offset = (instruction & 0xfff); - if (p && !wback) { - args << "[" << rn << ", #" << offset << "]"; - } else if (p && wback) { - args << "[" << rn << ", #" << offset << "]!"; - } else if (!p && wback) { - args << "[" << rn << "], #" << offset; - } else { - LOG(FATAL) << p << " " << w; - } - if (rn.r == 9) { - args << " ; "; - Thread::DumpThreadOffset(args, offset, 4); - } - } - } - break; - case 4: // Load/store multiple. - { - bool p = (instruction & (1 << 24)) != 0; - bool u = (instruction & (1 << 23)) != 0; - bool w = (instruction & (1 << 21)) != 0; - bool l = (instruction & (1 << 20)) != 0; - opcode = StringPrintf("%s%c%c", (l ? "ldm" : "stm"), (u ? 'i' : 'd'), (p ? 'b' : 'a')); - args << ArmRegister(instruction, 16) << (w ? "!" : "") << ", " << RegisterList(instruction); - } - break; - case 5: // Branch/branch with link. - { - bool bl = (instruction & (1 << 24)) != 0; - opcode = (bl ? "bl" : "b"); - int32_t imm26 = (instruction & 0xffffff) << 2; - int32_t imm32 = (imm26 << 6) >> 6; // Sign extend. - DumpBranchTarget(args, instr_ptr + 8, imm32); - } - break; - default: - opcode = "???"; - break; - } - opcode += kConditionCodeNames[cond]; - opcode += suffixes; - // TODO: a more complete ARM disassembler could generate wider opcodes. - os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n'; -} - -size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) { - uint32_t instr = (ReadU16(instr_ptr) << 16) | ReadU16(instr_ptr + 2); - // |111|1 1|1000000|0000|1111110000000000| - // |5 3|2 1|0987654|3 0|5 0 5 0| - // |---|---|-------|----|----------------| - // |332|2 2|2222222|1111|1111110000000000| - // |1 9|8 7|6543210|9 6|5 0 5 0| - // |---|---|-------|----|----------------| - // |111|op1| op2 | | | - uint32_t op1 = (instr >> 27) & 3; - if (op1 == 0) { - return DumpThumb16(os, instr_ptr); - } - - uint32_t op2 = (instr >> 20) & 0x7F; - std::ostringstream opcode; - std::ostringstream args; - switch (op1) { - case 0: - break; - case 1: - if ((op2 & 0x64) == 0) { // 00x x0xx - // |111|11|10|00|0|00|0000|1111110000000000| - // |5 3|21|09|87|6|54|3 0|5 0 5 0| - // |---|--|--|--|-|--|----|----------------| - // |332|22|22|22|2|22|1111|1111110000000000| - // |1 9|87|65|43|2|10|9 6|5 0 5 0| - // |---|--|--|--|-|--|----|----------------| - // |111|01|00|op|0|WL| Rn | | - // |111|01| op2 | | | - // STM - 111 01 00-01-0-W0 nnnn rrrrrrrrrrrrrrrr - // LDM - 111 01 00-01-0-W1 nnnn rrrrrrrrrrrrrrrr - // PUSH- 111 01 00-01-0-10 1101 0M0rrrrrrrrrrrrr - // POP - 111 01 00-01-0-11 1101 PM0rrrrrrrrrrrrr - uint32_t op = (instr >> 23) & 3; - uint32_t W = (instr >> 21) & 1; - uint32_t L = (instr >> 20) & 1; - ArmRegister Rn(instr, 16); - if (op == 1 || op == 2) { - if (op == 1) { - if (L == 0) { - opcode << "stm"; - args << Rn << (W == 0 ? "" : "!") << ", "; - } else { - if (Rn.r != 13) { - opcode << "ldm"; - args << Rn << (W == 0 ? "" : "!") << ", "; - } else { - opcode << "pop"; - } - } - } else { - if (L == 0) { - if (Rn.r != 13) { - opcode << "stmdb"; - args << Rn << (W == 0 ? "" : "!") << ", "; - } else { - opcode << "push"; - } - } else { - opcode << "ldmdb"; - args << Rn << (W == 0 ? "" : "!") << ", "; - } - } - args << RegisterList(instr); - } - } else if ((op2 & 0x64) == 4) { // 00x x1xx - uint32_t op3 = (instr >> 23) & 3; - uint32_t op4 = (instr >> 20) & 3; - // uint32_t op5 = (instr >> 4) & 0xF; - ArmRegister Rn(instr, 16); - ArmRegister Rt(instr, 12); - uint32_t imm8 = instr & 0xFF; - if (op3 == 0 && op4 == 0) { // STREX - ArmRegister Rd(instr, 8); - opcode << "strex"; - args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; - } else if (op3 == 0 && op4 == 1) { // LDREX - opcode << "ldrex"; - args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; - } - } else if ((op2 & 0x60) == 0x20) { // 01x xxxx - // Data-processing (shifted register) - // |111|1110|0000|0|0000|1111|1100|00|00|0000| - // |5 3|2109|8765|4|3 0|5 |10 8|7 |5 |3 0| - // |---|----|----|-|----|----|----|--|--|----| - // |332|2222|2222|2|1111|1111|1100|00|00|0000| - // |1 9|8765|4321|0|9 6|5 |10 8|7 |5 |3 0| - // |---|----|----|-|----|----|----|--|--|----| - // |111|0101| op3|S| Rn |imm3| Rd |i2|ty| Rm | - uint32_t op3 = (instr >> 21) & 0xF; - uint32_t S = (instr >> 20) & 1; - uint32_t imm3 = ((instr >> 12) & 0x7); - uint32_t imm2 = ((instr >> 6) & 0x3); - uint32_t imm5 = ((imm3 << 3) | imm2) & 0x1F; - uint32_t shift_type = ((instr >> 4) & 0x2); - ArmRegister Rd(instr, 8); - ArmRegister Rn(instr, 16); - ArmRegister Rm(instr, 0); - switch (op3) { - case 0x0: - if (Rd.r != 0xF) { - opcode << "and"; - } else { - if (S != 1U) { - opcode << "UNKNOWN TST-" << S; - break; - } - opcode << "tst"; - S = 0; // don't print 's' - } - break; - case 0x1: opcode << "bic"; break; - case 0x2: - if (Rn.r != 0xF) { - opcode << "orr"; - } else { - // TODO: use canonical form if there is a shift (lsl, ...). - opcode << "mov"; - } - break; - case 0x3: - if (Rn.r != 0xF) { - opcode << "orn"; - } else { - opcode << "mvn"; - } - break; - case 0x4: - if (Rd.r != 0xF) { - opcode << "eor"; - } else { - if (S != 1U) { - opcode << "UNKNOWN TEQ-" << S; - break; - } - opcode << "teq"; - S = 0; // don't print 's' - } - break; - case 0x6: opcode << "pkh"; break; - case 0x8: - if (Rd.r != 0xF) { - opcode << "add"; - } else { - if (S != 1U) { - opcode << "UNKNOWN CMN-" << S; - break; - } - opcode << "cmn"; - S = 0; // don't print 's' - } - break; - case 0xA: opcode << "adc"; break; - case 0xB: opcode << "sbc"; break; - case 0xD: - if (Rd.r != 0xF) { - opcode << "sub"; - } else { - if (S != 1U) { - opcode << "UNKNOWN CMP-" << S; - break; - } - opcode << "cmp"; - S = 0; // don't print 's' - } - break; - case 0xE: opcode << "rsb"; break; - default: opcode << "UNKNOWN DPSR-" << op3; break; - } - - if (S == 1) { - opcode << "s"; - } - opcode << ".w"; - - if (Rd.r != 0xF) { - args << Rd << ", "; - } - if (Rn.r != 0xF) { - args << Rn << ", "; - } - args << Rm; - - // Shift operand. - bool noShift = (imm5 == 0 && shift_type != 0x3); - if (!noShift) { - args << ", "; - switch (shift_type) { - case 0x0: args << "lsl"; break; - case 0x1: args << "lsr"; break; - case 0x2: args << "asr"; break; - case 0x3: - if (imm5 == 0) { - args << "rrx"; - } else { - args << "ror"; - } - break; - } - if (shift_type != 0x3 /* rrx */) { - args << StringPrintf(" #%d", imm5); - } - } - - } else if ((op2 & 0x40) == 0x40) { // 1xx xxxx - // Co-processor instructions - // |111|1|11|000000|0000|1111|1100|000|0 |0000| - // |5 3|2|10|987654|3 0|54 2|10 8|7 5|4 | 0| - // |---|-|--|------|----|----|----|---|---|----| - // |332|2|22|222222|1111|1111|1100|000|0 |0000| - // |1 9|8|76|543210|9 6|54 2|10 8|7 5|4 | 0| - // |---|-|--|------|----|----|----|---|---|----| - // |111| |11| op3 | Rn | |copr| |op4| | - uint32_t op3 = (instr >> 20) & 0x3F; - uint32_t coproc = (instr >> 8) & 0xF; - uint32_t op4 = (instr >> 4) & 0x1; - if ((op3 == 2 || op3 == 2 || op3 == 6 || op3 == 7) || // 00x1x - (op3 >= 8 && op3 <= 15) || (op3 >= 16 && op3 <= 31)) { // 001xxx, 01xxxx - // Extension register load/store instructions - // |111|1|110|00000|0000|1111|110|000000000| - // |5 3|2|109|87654|3 0|54 2|10 |87 54 0| - // |---|-|---|-----|----|----|---|---------| - // |332|2|222|22222|1111|1111|110|000000000| - // |1 9|8|765|43210|9 6|54 2|10 |87 54 0| - // |---|-|---|-----|----|----|---|---------| - // |111|T|110| op3 | Rn | |101| | - // 111 0 110 01001 0011 0000 101 000000011 - ec930a03 - if (op3 == 9 || op3 == 0xD) { // VLDM - // 1110 110 PUDW1 nnnn dddd 101S iiii iiii - uint32_t P = (instr >> 24) & 1; - uint32_t U = (instr >> 23) & 1; - uint32_t D = (instr >> 22) & 1; - uint32_t W = (instr >> 21) & 1; - uint32_t S = (instr >> 8) & 1; - ArmRegister Rn(instr, 16); - uint32_t Vd = (instr >> 12) & 0xF; - uint32_t imm8 = instr & 0xFF; - uint32_t d = (S == 0 ? ((Vd << 1) | D) : (Vd | (D << 4))); - if (P == 0 && U == 0 && W == 0) { - // TODO: 64bit transfers between ARM core and extension registers. - } else if (P == 0 && U == 1 && Rn.r == 13) { // VPOP - opcode << "vpop" << (S == 0 ? ".f64" : ".f32"); - args << d << " .. " << (d + imm8); - } else if (P == 1 && W == 0) { // VLDR - opcode << "vldr" << (S == 0 ? ".f64" : ".f32"); - args << d << ", [" << Rn << ", #" << imm8 << "]"; - } else { // VLDM - opcode << "vldm" << (S == 0 ? ".f64" : ".f32"); - args << Rn << ", " << d << " .. " << (d + imm8); - } - } - } else if ((op3 & 0x30) == 0x20 && op4 == 0) { // 10 xxxx ... 0 - if ((coproc & 0xE) == 0xA) { - // VFP data-processing instructions - // |111|1|1100|0000|0000|1111|110|0|00 |0|0|0000| - // |5 3|2|1098|7654|3 0|54 2|10 |8|76 |5|4|3 0| - // |---|-|----|----|----|----|---|-|----|-|-|----| - // |332|2|2222|2222|1111|1111|110|0|00 |0|0|0000| - // |1 9|8|7654|3210|9 6|54 2|109|8|76 |5|4|3 0| - // |---|-|----|----|----|----|---|-|----|-|-|----| - // |111|T|1110|opc1|opc2| |101| |opc3| | | | - // 111 0 1110|1111 0100 1110 101 0 01 1 0 1001 - eef4ea69 - uint32_t opc1 = (instr >> 20) & 0xF; - uint32_t opc2 = (instr >> 16) & 0xF; - uint32_t opc3 = (instr >> 6) & 0x3; - if ((opc1 & 0xB) == 0xB) { // 1x11 - // Other VFP data-processing instructions. - uint32_t D = (instr >> 22) & 0x1; - uint32_t Vd = (instr >> 12) & 0xF; - uint32_t sz = (instr >> 8) & 1; - uint32_t M = (instr >> 5) & 1; - uint32_t Vm = instr & 0xF; - bool dp_operation = sz == 1; - switch (opc2) { - case 0x1: // Vneg/Vsqrt - // 1110 11101 D 11 0001 dddd 101s o1M0 mmmm - opcode << (opc3 == 1 ? "vneg" : "vsqrt") << (dp_operation ? ".f64" : ".f32"); - if (dp_operation) { - args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm); - } else { - args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M); - } - break; - case 0x4: case 0x5: { // Vector compare - // 1110 11101 D 11 0100 dddd 101 sE1M0 mmmm - opcode << (opc3 == 1 ? "vcmp" : "vcmpe") << (dp_operation ? ".f64" : ".f32"); - if (dp_operation) { - args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm); - } else { - args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M); - } - break; - } - } - } - } - } else if ((op3 & 0x30) == 0x30) { // 11 xxxx - // Advanced SIMD - if ((instr & 0xFFBF0ED0) == 0xeeb10ac0) { // Vsqrt - // 1110 11101 D 11 0001 dddd 101S 11M0 mmmm - // 1110 11101 0 11 0001 1101 1011 1100 1000 - eeb1dbc8 - uint32_t D = (instr >> 22) & 1; - uint32_t Vd = (instr >> 12) & 0xF; - uint32_t sz = (instr >> 8) & 1; - uint32_t M = (instr >> 5) & 1; - uint32_t Vm = instr & 0xF; - bool dp_operation = sz == 1; - opcode << "vsqrt" << (dp_operation ? ".f64" : ".f32"); - if (dp_operation) { - args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm); - } else { - args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M); - } - } - } - } - break; - case 2: - if ((instr & 0x8000) == 0 && (op2 & 0x20) == 0) { - // Data-processing (modified immediate) - // |111|11|10|0000|0|0000|1|111|1100|00000000| - // |5 3|21|09|8765|4|3 0|5|4 2|10 8|7 5 0| - // |---|--|--|----|-|----|-|---|----|--------| - // |332|22|22|2222|2|1111|1|111|1100|00000000| - // |1 9|87|65|4321|0|9 6|5|4 2|10 8|7 5 0| - // |---|--|--|----|-|----|-|---|----|--------| - // |111|10|i0| op3|S| Rn |0|iii| Rd |iiiiiiii| - // 111 10 x0 xxxx x xxxx opxxx xxxx xxxxxxxx - uint32_t i = (instr >> 26) & 1; - uint32_t op3 = (instr >> 21) & 0xF; - uint32_t S = (instr >> 20) & 1; - ArmRegister Rn(instr, 16); - uint32_t imm3 = (instr >> 12) & 7; - ArmRegister Rd(instr, 8); - uint32_t imm8 = instr & 0xFF; - int32_t imm32 = (i << 11) | (imm3 << 8) | imm8; - if (Rn.r == 0xF && (op3 == 0x2 || op3 == 0x3)) { - if (op3 == 0x2) { - opcode << "mov"; - if (S == 1) { - opcode << "s"; - } - opcode << ".w"; - } else { - opcode << "mvn"; - if (S == 1) { - opcode << "s"; - } - } - args << Rd << ", ThumbExpand(" << imm32 << ")"; - } else if (Rd.r == 0xF && S == 1 && - (op3 == 0x0 || op3 == 0x4 || op3 == 0x8 || op3 == 0xD)) { - if (op3 == 0x0) { - opcode << "tst"; - } else if (op3 == 0x4) { - opcode << "teq"; - } else if (op3 == 0x8) { - opcode << "cmw"; - } else { - opcode << "cmp.w"; - } - args << Rn << ", ThumbExpand(" << imm32 << ")"; - } else { - switch (op3) { - case 0x0: opcode << "and"; break; - case 0x1: opcode << "bic"; break; - case 0x2: opcode << "orr"; break; - case 0x3: opcode << "orn"; break; - case 0x4: opcode << "eor"; break; - case 0x8: opcode << "add"; break; - case 0xA: opcode << "adc"; break; - case 0xB: opcode << "sbc"; break; - case 0xD: opcode << "sub"; break; - case 0xE: opcode << "rsb"; break; - default: opcode << "UNKNOWN DPMI-" << op3; break; - } - if (S == 1) { - opcode << "s"; - } - args << Rd << ", " << Rn << ", ThumbExpand(" << imm32 << ")"; - } - } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) { - // Data-processing (plain binary immediate) - // |111|11|10|00000|0000|1|111110000000000| - // |5 3|21|09|87654|3 0|5|4 0 5 0| - // |---|--|--|-----|----|-|---------------| - // |332|22|22|22222|1111|1|111110000000000| - // |1 9|87|65|43210|9 6|5|4 0 5 0| - // |---|--|--|-----|----|-|---------------| - // |111|10|x1| op3 | Rn |0|xxxxxxxxxxxxxxx| - uint32_t op3 = (instr >> 20) & 0x1F; - switch (op3) { - case 0x00: case 0x0A: { - // ADD/SUB.W Rd, Rn #imm12 - 111 10 i1 0101 0 nnnn 0 iii dddd iiiiiiii - ArmRegister Rd(instr, 8); - ArmRegister Rn(instr, 16); - uint32_t i = (instr >> 26) & 1; - uint32_t imm3 = (instr >> 12) & 0x7; - uint32_t imm8 = instr & 0xFF; - uint32_t imm12 = (i << 11) | (imm3 << 8) | imm8; - if (Rn.r != 0xF) { - opcode << (op3 == 0 ? "addw" : "subw"); - args << Rd << ", " << Rn << ", #" << imm12; - } else { - opcode << "adr"; - args << Rd << ", "; - DumpBranchTarget(args, instr_ptr + 4, (op3 == 0) ? imm12 : -imm12); - } - break; - } - case 0x04: case 0x0C: { - // MOVW/T Rd, #imm16 - 111 10 i0 0010 0 iiii 0 iii dddd iiiiiiii - ArmRegister Rd(instr, 8); - uint32_t i = (instr >> 26) & 1; - uint32_t imm3 = (instr >> 12) & 0x7; - uint32_t imm8 = instr & 0xFF; - uint32_t Rn = (instr >> 16) & 0xF; - uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8; - opcode << (op3 == 0x04 ? "movw" : "movt"); - args << Rd << ", #" << imm16; - break; - } - case 0x16: { - // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii - ArmRegister Rd(instr, 8); - ArmRegister Rn(instr, 16); - uint32_t msb = instr & 0x1F; - uint32_t imm2 = (instr >> 6) & 0x3; - uint32_t imm3 = (instr >> 12) & 0x7; - uint32_t lsb = (imm3 << 2) | imm2; - uint32_t width = msb - lsb + 1; - if (Rn.r != 0xF) { - opcode << "bfi"; - args << Rd << ", " << Rn << ", #" << lsb << ", #" << width; - } else { - opcode << "bfc"; - args << Rd << ", #" << lsb << ", #" << width; - } - break; - } - default: - break; - } - } else { - // Branches and miscellaneous control - // |111|11|1000000|0000|1|111|1100|00000000| - // |5 3|21|0987654|3 0|5|4 2|10 8|7 5 0| - // |---|--|-------|----|-|---|----|--------| - // |332|22|2222222|1111|1|111|1100|00000000| - // |1 9|87|6543210|9 6|5|4 2|10 8|7 5 0| - // |---|--|-------|----|-|---|----|--------| - // |111|10| op2 | |1|op3|op4 | | - - uint32_t op3 = (instr >> 12) & 7; - // uint32_t op4 = (instr >> 8) & 0xF; - switch (op3) { - case 0: - if ((op2 & 0x38) != 0x38) { - // Conditional branch - // |111|11|1|0000|000000|1|1|1 |1|1 |10000000000| - // |5 3|21|0|9876|543 0|5|4|3 |2|1 |0 5 0| - // |---|--|-|----|------|-|-|--|-|--|-----------| - // |332|22|2|2222|221111|1|1|1 |1|1 |10000000000| - // |1 9|87|6|5432|109 6|5|4|3 |2|1 |0 5 0| - // |---|--|-|----|------|-|-|--|-|--|-----------| - // |111|10|S|cond| imm6 |1|0|J1|0|J2| imm11 | - uint32_t S = (instr >> 26) & 1; - uint32_t J2 = (instr >> 11) & 1; - uint32_t J1 = (instr >> 13) & 1; - uint32_t imm6 = (instr >> 16) & 0x3F; - uint32_t imm11 = instr & 0x7FF; - uint32_t cond = (instr >> 22) & 0xF; - int32_t imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); - imm32 = (imm32 << 11) >> 11; // sign extend 21bit immediate - opcode << "b"; - DumpCond(opcode, cond); - opcode << ".w"; - DumpBranchTarget(args, instr_ptr + 4, imm32); - } else if (op2 == 0x3B) { - // Miscellaneous control instructions - uint32_t op5 = (instr >> 4) & 0xF; - switch (op5) { - case 4: opcode << "dsb"; break; - case 5: opcode << "dmb"; break; - case 6: opcode << "isb"; break; - } - } - break; - case 2: - if ((op2 & 0x38) == 0x38) { - if (op2 == 0x7F) { - opcode << "udf"; - } - break; - } - // Else deliberate fall-through to B. - case 1: case 3: { - // B - // |111|11|1|0000|000000|11|1 |1|1 |10000000000| - // |5 3|21|0|9876|543 0|54|3 |2|1 |0 5 0| - // |---|--|-|----|------|--|--|-|--|-----------| - // |332|22|2|2222|221111|11|1 |1|1 |10000000000| - // |1 9|87|6|5 2|10 6|54|3 |2|1 |0 5 0| - // |---|--|-|----|------|--|--|-|--|-----------| - // |111|10|S|cond| imm6 |10|J1|0|J2| imm11 | - // |111|10|S| imm10 |10|J1|1|J2| imm11 | - uint32_t S = (instr >> 26) & 1; - uint32_t cond = (instr >> 22) & 0xF; - uint32_t J2 = (instr >> 11) & 1; - uint32_t form = (instr >> 12) & 1; - uint32_t J1 = (instr >> 13) & 1; - uint32_t imm10 = (instr >> 16) & 0x3FF; - uint32_t imm6 = (instr >> 16) & 0x3F; - uint32_t imm11 = instr & 0x7FF; - opcode << "b"; - int32_t imm32; - if (form == 0) { - DumpCond(opcode, cond); - imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); - imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate. - } else { - uint32_t I1 = ~(J1 ^ S); - uint32_t I2 = ~(J2 ^ S); - imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); - imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate. - } - opcode << ".w"; - DumpBranchTarget(args, instr_ptr + 4, imm32); - break; - } - case 4: case 6: case 5: case 7: { - // BL, BLX (immediate) - // |111|11|1|0000000000|11|1 |1|1 |10000000000| - // |5 3|21|0|9876543 0|54|3 |2|1 |0 5 0| - // |---|--|-|----------|--|--|-|--|-----------| - // |332|22|2|2222221111|11|1 |1|1 |10000000000| - // |1 9|87|6|5 0 6|54|3 |2|1 |0 5 0| - // |---|--|-|----------|--|--|-|--|-----------| - // |111|10|S| imm10 |11|J1|L|J2| imm11 | - uint32_t S = (instr >> 26) & 1; - uint32_t J2 = (instr >> 11) & 1; - uint32_t L = (instr >> 12) & 1; - uint32_t J1 = (instr >> 13) & 1; - uint32_t imm10 = (instr >> 16) & 0x3FF; - uint32_t imm11 = instr & 0x7FF; - if (L == 0) { - opcode << "bx"; - } else { - opcode << "blx"; - } - uint32_t I1 = ~(J1 ^ S); - uint32_t I2 = ~(J2 ^ S); - int32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); - imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate. - DumpBranchTarget(args, instr_ptr + 4, imm32); - break; - } - } - } - break; - case 3: - switch (op2) { - case 0x00: case 0x02: case 0x04: case 0x06: // 000xxx0 - case 0x08: case 0x0A: case 0x0C: case 0x0E: { - // Store single data item - // |111|11|100|000|0|0000|1111|110000|000000| - // |5 3|21|098|765|4|3 0|5 2|10 6|5 0| - // |---|--|---|---|-|----|----|------|------| - // |332|22|222|222|2|1111|1111|110000|000000| - // |1 9|87|654|321|0|9 6|5 2|10 6|5 0| - // |---|--|---|---|-|----|----|------|------| - // |111|11|000|op3|0| | | op4 | | - uint32_t op3 = (instr >> 21) & 7; - // uint32_t op4 = (instr >> 6) & 0x3F; - switch (op3) { - case 0x0: case 0x4: { - // STRB Rt,[Rn,#+/-imm8] - 111 11 00 0 0 00 0 nnnn tttt 1 PUWii ii iiii - // STRB Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 00 0 nnnn tttt 0 00000 ii mmmm - ArmRegister Rn(instr, 16); - ArmRegister Rt(instr, 12); - opcode << "strb"; - if ((instr & 0x800) != 0) { - uint32_t imm8 = instr & 0xFF; - args << Rt << ", [" << Rn << ",#" << imm8 << "]"; - } else { - uint32_t imm2 = (instr >> 4) & 3; - ArmRegister Rm(instr, 0); - args << Rt << ", [" << Rn << ", " << Rm; - if (imm2 != 0) { - args << ", " << "lsl #" << imm2; - } - args << "]"; - } - break; - } - case 0x2: case 0x6: { - ArmRegister Rn(instr, 16); - ArmRegister Rt(instr, 12); - if (op3 == 2) { - if ((instr & 0x800) != 0) { - // STR Rt, [Rn, #imm8] - 111 11 000 010 0 nnnn tttt 1PUWiiiiiiii - uint32_t P = (instr >> 10) & 1; - uint32_t U = (instr >> 9) & 1; - uint32_t W = (instr >> 8) & 1; - uint32_t imm8 = instr & 0xFF; - int32_t imm32 = (imm8 << 24) >> 24; // sign-extend imm8 - if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) { - opcode << "push"; - args << Rt; - } else if (Rn.r == 15 || (P == 0 && W == 0)) { - opcode << "UNDEFINED"; - } else { - if (P == 1 && U == 1 && W == 0) { - opcode << "strt"; - } else { - opcode << "str"; - } - args << Rt << ", [" << Rn; - if (P == 0 && W == 1) { - args << "], #" << imm32; - } else { - args << ", #" << imm32 << "]"; - if (W == 1) { - args << "!"; - } - } - } - } else { - // STR Rt, [Rn, Rm, LSL #imm2] - 111 11 000 010 0 nnnn tttt 000000iimmmm - ArmRegister Rn(instr, 16); - ArmRegister Rt(instr, 12); - ArmRegister Rm(instr, 0); - uint32_t imm2 = (instr >> 4) & 3; - opcode << "str.w"; - args << Rt << ", [" << Rn << ", " << Rm; - if (imm2 != 0) { - args << ", lsl #" << imm2; - } - args << "]"; - } - } else if (op3 == 6) { - // STR.W Rt, [Rn, #imm12] - 111 11 000 110 0 nnnn tttt iiiiiiiiiiii - uint32_t imm12 = instr & 0xFFF; - opcode << "str.w"; - args << Rt << ", [" << Rn << ", #" << imm12 << "]"; - } - break; - } - } - - break; - } - case 0x03: case 0x0B: case 0x13: case 0x1B: { // 00xx011 - // Load halfword - // |111|11|10|0 0|00|0|0000|1111|110000|000000| - // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0| - // |---|--|--|---|--|-|----|----|------|------| - // |332|22|22|2 2|22|2|1111|1111|110000|000000| - // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0| - // |---|--|--|---|--|-|----|----|------|------| - // |111|11|00|op3|01|1| Rn | Rt | op4 | | - // |111|11| op2 | | | imm12 | - uint32_t op3 = (instr >> 23) & 3; - ArmRegister Rn(instr, 16); - ArmRegister Rt(instr, 12); - if (Rt.r != 15) { - if (op3 == 1) { - // LDRH.W Rt, [Rn, #imm12] - 111 11 00 01 011 nnnn tttt iiiiiiiiiiii - uint32_t imm12 = instr & 0xFFF; - opcode << "ldrh.w"; - args << Rt << ", [" << Rn << ", #" << imm12 << "]"; - if (Rn.r == 9) { - args << " ; "; - Thread::DumpThreadOffset(args, imm12, 4); - } else if (Rn.r == 15) { - intptr_t lit_adr = reinterpret_cast(instr_ptr); - lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; - args << " ; " << reinterpret_cast(*reinterpret_cast(lit_adr)); - } - } else if (op3 == 3) { - // LDRSH.W Rt, [Rn, #imm12] - 111 11 00 11 011 nnnn tttt iiiiiiiiiiii - uint32_t imm12 = instr & 0xFFF; - opcode << "ldrsh.w"; - args << Rt << ", [" << Rn << ", #" << imm12 << "]"; - if (Rn.r == 9) { - args << " ; "; - Thread::DumpThreadOffset(args, imm12, 4); - } else if (Rn.r == 15) { - intptr_t lit_adr = reinterpret_cast(instr_ptr); - lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; - args << " ; " << reinterpret_cast(*reinterpret_cast(lit_adr)); - } - } - } - break; - } - case 0x05: case 0x0D: case 0x15: case 0x1D: { // 00xx101 - // Load word - // |111|11|10|0 0|00|0|0000|1111|110000|000000| - // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0| - // |---|--|--|---|--|-|----|----|------|------| - // |332|22|22|2 2|22|2|1111|1111|110000|000000| - // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0| - // |---|--|--|---|--|-|----|----|------|------| - // |111|11|00|op3|10|1| Rn | Rt | op4 | | - // |111|11| op2 | | | imm12 | - uint32_t op3 = (instr >> 23) & 3; - uint32_t op4 = (instr >> 6) & 0x3F; - ArmRegister Rn(instr, 16); - ArmRegister Rt(instr, 12); - if (op3 == 1 || Rn.r == 15) { - // LDR.W Rt, [Rn, #imm12] - 111 11 00 00 101 nnnn tttt iiiiiiiiiiii - // LDR.W Rt, [PC, #imm12] - 111 11 00 0x 101 1111 tttt iiiiiiiiiiii - uint32_t imm12 = instr & 0xFFF; - opcode << "ldr.w"; - args << Rt << ", [" << Rn << ", #" << imm12 << "]"; - if (Rn.r == 9) { - args << " ; "; - Thread::DumpThreadOffset(args, imm12, 4); - } else if (Rn.r == 15) { - intptr_t lit_adr = reinterpret_cast(instr_ptr); - lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; - args << " ; " << reinterpret_cast(*reinterpret_cast(lit_adr)); - } - } else if (op4 == 0) { - // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm - uint32_t imm2 = (instr >> 4) & 0xF; - ArmRegister rm(instr, 0); - opcode << "ldr.w"; - args << Rt << ", [" << Rn << ", " << rm; - if (imm2 != 0) { - args << ", lsl #" << imm2; - } - args << "]"; - } else { - // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii - uint32_t imm8 = instr & 0xFF; - opcode << "ldrt"; - args << Rt << ", [" << Rn << ", #" << imm8 << "]"; - } - break; - } - } - default: - break; - } - - // Apply any IT-block conditions to the opcode if necessary. - if (!it_conditions_.empty()) { - opcode << it_conditions_.back(); - it_conditions_.pop_back(); - } - - os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n'; - return 4; -} // NOLINT(readability/fn_size) - -size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr) { - uint16_t instr = ReadU16(instr_ptr); - bool is_32bit = ((instr & 0xF000) == 0xF000) || ((instr & 0xF800) == 0xE800); - if (is_32bit) { - return DumpThumb32(os, instr_ptr); - } else { - std::ostringstream opcode; - std::ostringstream args; - uint16_t opcode1 = instr >> 10; - if (opcode1 < 0x10) { - // shift (immediate), add, subtract, move, and compare - uint16_t opcode2 = instr >> 9; - switch (opcode2) { - case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: - case 0x8: case 0x9: case 0xA: case 0xB: { - // Logical shift left - 00 000xx iii mmm ddd - // Logical shift right - 00 001xx iii mmm ddd - // Arithmetic shift right - 00 010xx iii mmm ddd - uint16_t imm5 = (instr >> 6) & 0x1F; - ThumbRegister rm(instr, 3); - ThumbRegister Rd(instr, 0); - if (opcode2 <= 3) { - opcode << "lsls"; - } else if (opcode2 <= 7) { - opcode << "lsrs"; - } else { - opcode << "asrs"; - } - args << Rd << ", " << rm << ", #" << imm5; - break; - } - case 0xC: case 0xD: case 0xE: case 0xF: { - // Add register - 00 01100 mmm nnn ddd - // Sub register - 00 01101 mmm nnn ddd - // Add 3-bit immediate - 00 01110 iii nnn ddd - // Sub 3-bit immediate - 00 01111 iii nnn ddd - uint16_t imm3_or_Rm = (instr >> 6) & 7; - ThumbRegister Rn(instr, 3); - ThumbRegister Rd(instr, 0); - if ((opcode2 & 2) != 0 && imm3_or_Rm == 0) { - opcode << "mov"; - } else { - if ((opcode2 & 1) == 0) { - opcode << "adds"; - } else { - opcode << "subs"; - } - } - args << Rd << ", " << Rn; - if ((opcode2 & 2) == 0) { - ArmRegister Rm(imm3_or_Rm); - args << ", " << Rm; - } else if (imm3_or_Rm != 0) { - args << ", #" << imm3_or_Rm; - } - break; - } - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1A: case 0x1B: - case 0x1C: case 0x1D: case 0x1E: case 0x1F: { - // MOVS Rd, #imm8 - 00100 ddd iiiiiiii - // CMP Rn, #imm8 - 00101 nnn iiiiiiii - // ADDS Rn, #imm8 - 00110 nnn iiiiiiii - // SUBS Rn, #imm8 - 00111 nnn iiiiiiii - ThumbRegister Rn(instr, 8); - uint16_t imm8 = instr & 0xFF; - switch (opcode2 >> 2) { - case 4: opcode << "movs"; break; - case 5: opcode << "cmp"; break; - case 6: opcode << "adds"; break; - case 7: opcode << "subs"; break; - } - args << Rn << ", #" << imm8; - break; - } - default: - break; - } - } else if (opcode1 == 0x10) { - // Data-processing - uint16_t opcode2 = (instr >> 6) & 0xF; - ThumbRegister rm(instr, 3); - ThumbRegister rdn(instr, 0); - opcode << kThumbDataProcessingOperations[opcode2]; - args << rdn << ", " << rm; - } else if (opcode1 == 0x11) { - // Special data instructions and branch and exchange - uint16_t opcode2 = (instr >> 6) & 0x0F; - switch (opcode2) { - case 0x0: case 0x1: case 0x2: case 0x3: { - // Add low registers - 010001 0000 xxxxxx - // Add high registers - 010001 0001/001x xxxxxx - uint16_t DN = (instr >> 7) & 1; - ArmRegister rm(instr, 3); - uint16_t Rdn = instr & 7; - ArmRegister DN_Rdn((DN << 3) | Rdn); - opcode << "add"; - args << DN_Rdn << ", " << rm; - break; - } - case 0x8: case 0x9: case 0xA: case 0xB: { - // Move low registers - 010001 1000 xxxxxx - // Move high registers - 010001 1001/101x xxxxxx - uint16_t DN = (instr >> 7) & 1; - ArmRegister rm(instr, 3); - uint16_t Rdn = instr & 7; - ArmRegister DN_Rdn((DN << 3) | Rdn); - opcode << "mov"; - args << DN_Rdn << ", " << rm; - break; - } - case 0x5: case 0x6: case 0x7: { - // Compare high registers - 010001 0101/011x xxxxxx - uint16_t N = (instr >> 7) & 1; - ArmRegister rm(instr, 3); - uint16_t Rn = instr & 7; - ArmRegister N_Rn((N << 3) | Rn); - opcode << "cmp"; - args << N_Rn << ", " << rm; - break; - } - case 0xC: case 0xD: case 0xE: case 0xF: { - // Branch and exchange - 010001 110x xxxxxx - // Branch with link and exchange - 010001 111x xxxxxx - ArmRegister rm(instr, 3); - opcode << ((opcode2 & 0x2) == 0 ? "bx" : "blx"); - args << rm; - break; - } - default: - break; - } - } else if (opcode1 == 0x12 || opcode1 == 0x13) { // 01001x - ThumbRegister Rt(instr, 8); - uint16_t imm8 = instr & 0xFF; - opcode << "ldr"; - args << Rt << ", [pc, #" << (imm8 << 2) << "]"; - } else if ((opcode1 >= 0x14 && opcode1 <= 0x17) || // 0101xx - (opcode1 >= 0x18 && opcode1 <= 0x1f) || // 011xxx - (opcode1 >= 0x20 && opcode1 <= 0x27)) { // 100xxx - // Load/store single data item - uint16_t opA = (instr >> 12) & 0xF; - if (opA == 0x5) { - uint16_t opB = (instr >> 9) & 0x7; - ThumbRegister Rm(instr, 6); - ThumbRegister Rn(instr, 3); - ThumbRegister Rt(instr, 0); - switch (opB) { - case 0: opcode << "str"; break; - case 1: opcode << "strh"; break; - case 2: opcode << "strb"; break; - case 3: opcode << "ldrsb"; break; - case 4: opcode << "ldr"; break; - case 5: opcode << "ldrh"; break; - case 6: opcode << "ldrb"; break; - case 7: opcode << "ldrsh"; break; - } - args << Rt << ", [" << Rn << ", " << Rm << "]"; - } else if (opA == 9) { - uint16_t opB = (instr >> 11) & 1; - ThumbRegister Rt(instr, 8); - uint16_t imm8 = instr & 0xFF; - opcode << (opB == 0 ? "str" : "ldr"); - args << Rt << ", [sp, #" << (imm8 << 2) << "]"; - } else { - uint16_t imm5 = (instr >> 6) & 0x1F; - uint16_t opB = (instr >> 11) & 1; - ThumbRegister Rn(instr, 3); - ThumbRegister Rt(instr, 0); - switch (opA) { - case 6: - imm5 <<= 2; - opcode << (opB == 0 ? "str" : "ldr"); - break; - case 7: - imm5 <<= 0; - opcode << (opB == 0 ? "strb" : "ldrb"); - break; - case 8: - imm5 <<= 1; - opcode << (opB == 0 ? "strh" : "ldrh"); - break; - } - args << Rt << ", [" << Rn << ", #" << imm5 << "]"; - } - } else if (opcode1 >= 0x34 && opcode1 <= 0x37) { // 1101xx - int8_t imm8 = instr & 0xFF; - uint32_t cond = (instr >> 8) & 0xF; - opcode << "b"; - DumpCond(opcode, cond); - DumpBranchTarget(args, instr_ptr + 4, (imm8 << 1)); - } else if ((instr & 0xF800) == 0xA800) { - // Generate SP-relative address - ThumbRegister rd(instr, 8); - int imm8 = instr & 0xFF; - opcode << "add"; - args << rd << ", sp, #" << (imm8 << 2); - } else if ((instr & 0xF000) == 0xB000) { - // Miscellaneous 16-bit instructions - uint16_t opcode2 = (instr >> 5) & 0x7F; - switch (opcode2) { - case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: { - // Add immediate to SP - 1011 00000 ii iiiii - // Subtract immediate from SP - 1011 00001 ii iiiii - int imm7 = instr & 0x7F; - opcode << ((opcode2 & 4) == 0 ? "add" : "sub"); - args << "sp, sp, #" << (imm7 << 2); - break; - } - case 0x08: case 0x09: case 0x0A: case 0x0B: // 0001xxx - case 0x0C: case 0x0D: case 0x0E: case 0x0F: - case 0x18: case 0x19: case 0x1A: case 0x1B: // 0011xxx - case 0x1C: case 0x1D: case 0x1E: case 0x1F: - case 0x48: case 0x49: case 0x4A: case 0x4B: // 1001xxx - case 0x4C: case 0x4D: case 0x4E: case 0x4F: - case 0x58: case 0x59: case 0x5A: case 0x5B: // 1011xxx - case 0x5C: case 0x5D: case 0x5E: case 0x5F: { - // CBNZ, CBZ - uint16_t op = (instr >> 11) & 1; - uint16_t i = (instr >> 9) & 1; - uint16_t imm5 = (instr >> 3) & 0x1F; - ThumbRegister Rn(instr, 0); - opcode << (op != 0 ? "cbnz" : "cbz"); - uint32_t imm32 = (i << 6) | (imm5 << 1); - args << Rn << ", "; - DumpBranchTarget(args, instr_ptr + 4, imm32); - break; - } - case 0x78: case 0x79: case 0x7A: case 0x7B: // 1111xxx - case 0x7C: case 0x7D: case 0x7E: case 0x7F: { - // If-Then, and hints - uint16_t opA = (instr >> 4) & 0xF; - uint16_t opB = instr & 0xF; - if (opB == 0) { - switch (opA) { - case 0: opcode << "nop"; break; - case 1: opcode << "yield"; break; - case 2: opcode << "wfe"; break; - case 3: opcode << "sev"; break; - default: break; - } - } else { - uint32_t first_cond = opA; - uint32_t mask = opB; - opcode << "it"; - - // Flesh out the base "it" opcode with the specific collection of 't's and 'e's, - // and store up the actual condition codes we'll want to add to the next few opcodes. - size_t count = 3 - CTZ(mask); - it_conditions_.resize(count + 2); // Plus the implicit 't', plus the "" for the IT itself. - for (size_t i = 0; i < count; ++i) { - bool positive_cond = ((first_cond & 1) != 0); - bool positive_mask = ((mask & (1 << (3 - i))) != 0); - if (positive_mask == positive_cond) { - opcode << 't'; - it_conditions_[i] = kConditionCodeNames[first_cond]; - } else { - opcode << 'e'; - it_conditions_[i] = kConditionCodeNames[first_cond ^ 1]; - } - } - it_conditions_[count] = kConditionCodeNames[first_cond]; // The implicit 't'. - - it_conditions_[count + 1] = ""; // No condition code for the IT itself... - DumpCond(args, first_cond); // ...because it's considered an argument. - } - break; - } - default: - break; - } - } else if (((instr & 0xF000) == 0x5000) || ((instr & 0xE000) == 0x6000) || - ((instr & 0xE000) == 0x8000)) { - // Load/store single data item - uint16_t opA = instr >> 12; - // uint16_t opB = (instr >> 9) & 7; - switch (opA) { - case 0x6: { - // STR Rt, [Rn, #imm] - 01100 iiiii nnn ttt - // LDR Rt, [Rn, #imm] - 01101 iiiii nnn ttt - uint16_t imm5 = (instr >> 6) & 0x1F; - ThumbRegister Rn(instr, 3); - ThumbRegister Rt(instr, 0); - opcode << ((instr & 0x800) == 0 ? "str" : "ldr"); - args << Rt << ", [" << Rn << ", #" << (imm5 << 2) << "]"; - break; - } - case 0x9: { - // STR Rt, [SP, #imm] - 01100 ttt iiiiiiii - // LDR Rt, [SP, #imm] - 01101 ttt iiiiiiii - uint16_t imm8 = instr & 0xFF; - ThumbRegister Rt(instr, 8); - opcode << ((instr & 0x800) == 0 ? "str" : "ldr"); - args << Rt << ", [sp, #" << (imm8 << 2) << "]"; - break; - } - default: - break; - } - } else if (opcode1 == 0x38 || opcode1 == 0x39) { - uint16_t imm11 = instr & 0x7FFF; - int32_t imm32 = imm11 << 1; - imm32 = (imm32 << 20) >> 20; // sign extend 12 bit immediate - opcode << "b"; - DumpBranchTarget(args, instr_ptr + 4, imm32); - } - - // Apply any IT-block conditions to the opcode if necessary. - if (!it_conditions_.empty()) { - opcode << it_conditions_.back(); - it_conditions_.pop_back(); - } - - os << StringPrintf("%p: %04x \t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n'; - } - return 2; -} - -} // namespace arm -} // namespace art diff --git a/runtime/disassembler_arm.h b/runtime/disassembler_arm.h deleted file mode 100644 index cab9150108..0000000000 --- a/runtime/disassembler_arm.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2012 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_RUNTIME_DISASSEMBLER_ARM_H_ -#define ART_RUNTIME_DISASSEMBLER_ARM_H_ - -#include - -#include "disassembler.h" - -namespace art { -namespace arm { - -class DisassemblerArm : public Disassembler { - public: - DisassemblerArm(); - - virtual size_t Dump(std::ostream& os, const uint8_t* begin); - virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end); - private: - void DumpArm(std::ostream& os, const uint8_t* instr); - - // Returns the size of the instruction just decoded - size_t DumpThumb16(std::ostream& os, const uint8_t* instr); - size_t DumpThumb32(std::ostream& os, const uint8_t* instr_ptr); - - void DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32); - void DumpCond(std::ostream& os, uint32_t cond); - - std::vector it_conditions_; - - DISALLOW_COPY_AND_ASSIGN(DisassemblerArm); -}; - -} // namespace arm -} // namespace art - -#endif // ART_RUNTIME_DISASSEMBLER_ARM_H_ diff --git a/runtime/disassembler_mips.cc b/runtime/disassembler_mips.cc deleted file mode 100644 index 25bbae68ef..0000000000 --- a/runtime/disassembler_mips.cc +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2012 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 "disassembler_mips.h" - -#include - -#include "base/logging.h" -#include "base/stringprintf.h" -#include "thread.h" - -namespace art { -namespace mips { - -struct MipsInstruction { - uint32_t mask; - uint32_t value; - const char* name; - const char* args_fmt; - - bool Matches(uint32_t instruction) const { - return (instruction & mask) == value; - } -}; - -static const uint32_t kOpcodeShift = 26; - -static const uint32_t kCop1 = (17 << kOpcodeShift); - -static const uint32_t kITypeMask = (0x3f << kOpcodeShift); -static const uint32_t kJTypeMask = (0x3f << kOpcodeShift); -static const uint32_t kRTypeMask = ((0x3f << kOpcodeShift) | (0x3f)); -static const uint32_t kSpecial2Mask = (0x3f << kOpcodeShift); -static const uint32_t kFpMask = kRTypeMask; - -static const MipsInstruction gMipsInstructions[] = { - // "sll r0, r0, 0" is the canonical "nop", used in delay slots. - { 0xffffffff, 0, "nop", "" }, - - // R-type instructions. - { kRTypeMask, 0, "sll", "DTA", }, - // 0, 1, movci - { kRTypeMask, 2, "srl", "DTA", }, - { kRTypeMask, 3, "sra", "DTA", }, - { kRTypeMask, 4, "sllv", "DTS", }, - { kRTypeMask, 6, "srlv", "DTS", }, - { kRTypeMask, 7, "srav", "DTS", }, - { kRTypeMask, 8, "jr", "S", }, - { kRTypeMask | (0x1f << 11), 9 | (31 << 11), "jalr", "S", }, // rd = 31 is implicit. - { kRTypeMask, 9, "jalr", "DS", }, // General case. - { kRTypeMask | (0x1f << 6), 10, "movz", "DST", }, - { kRTypeMask | (0x1f << 6), 11, "movn", "DST", }, - { kRTypeMask, 12, "syscall", "", }, // TODO: code - { kRTypeMask, 13, "break", "", }, // TODO: code - { kRTypeMask, 15, "sync", "", }, // TODO: type - { kRTypeMask, 16, "mfhi", "D", }, - { kRTypeMask, 17, "mthi", "S", }, - { kRTypeMask, 18, "mflo", "D", }, - { kRTypeMask, 19, "mtlo", "S", }, - { kRTypeMask, 24, "mult", "ST", }, - { kRTypeMask, 25, "multu", "ST", }, - { kRTypeMask, 26, "div", "ST", }, - { kRTypeMask, 27, "divu", "ST", }, - { kRTypeMask, 32, "add", "DST", }, - { kRTypeMask, 33, "addu", "DST", }, - { kRTypeMask, 34, "sub", "DST", }, - { kRTypeMask, 35, "subu", "DST", }, - { kRTypeMask, 36, "and", "DST", }, - { kRTypeMask, 37, "or", "DST", }, - { kRTypeMask, 38, "xor", "DST", }, - { kRTypeMask, 39, "nor", "DST", }, - { kRTypeMask, 42, "slt", "DST", }, - { kRTypeMask, 43, "sltu", "DST", }, - // 0, 48, tge - // 0, 49, tgeu - // 0, 50, tlt - // 0, 51, tltu - // 0, 52, teq - // 0, 54, tne - - // SPECIAL2 - { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 2, "mul", "DST" }, - { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 32, "clz", "DS" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 0, "madd", "ST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 1, "maddu", "ST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 2, "mul", "DST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 4, "msub", "ST" }, - { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 5, "msubu", "ST" }, - { kSpecial2Mask | 0x3f, (28 << kOpcodeShift) | 0x3f, "sdbbp", "" }, // TODO: code - - // J-type instructions. - { kJTypeMask, 2 << kOpcodeShift, "j", "L" }, - { kJTypeMask, 3 << kOpcodeShift, "jal", "L" }, - - // I-type instructions. - { kITypeMask, 4 << kOpcodeShift, "beq", "STB" }, - { kITypeMask, 5 << kOpcodeShift, "bne", "STB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (1 << 16), "bgez", "SB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (0 << 16), "bltz", "SB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (2 << 16), "bltzl", "SB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (16 << 16), "bltzal", "SB" }, - { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (18 << 16), "bltzall", "SB" }, - { kITypeMask | (0x1f << 16), 6 << kOpcodeShift | (0 << 16), "blez", "SB" }, - { kITypeMask | (0x1f << 16), 7 << kOpcodeShift | (0 << 16), "bgtz", "SB" }, - - { 0xffff0000, (4 << kOpcodeShift), "b", "B" }, - { 0xffff0000, (1 << kOpcodeShift) | (17 << 16), "bal", "B" }, - - { kITypeMask, 8 << kOpcodeShift, "addi", "TSi", }, - { kITypeMask, 9 << kOpcodeShift, "addiu", "TSi", }, - { kITypeMask, 10 << kOpcodeShift, "slti", "TSi", }, - { kITypeMask, 11 << kOpcodeShift, "sltiu", "TSi", }, - { kITypeMask, 12 << kOpcodeShift, "andi", "TSi", }, - { kITypeMask, 13 << kOpcodeShift, "ori", "TSi", }, - { kITypeMask, 14 << kOpcodeShift, "ori", "TSi", }, - { kITypeMask, 15 << kOpcodeShift, "lui", "TI", }, - - { kITypeMask, 32u << kOpcodeShift, "lb", "TO", }, - { kITypeMask, 33u << kOpcodeShift, "lh", "TO", }, - { kITypeMask, 35u << kOpcodeShift, "lw", "TO", }, - { kITypeMask, 36u << kOpcodeShift, "lbu", "TO", }, - { kITypeMask, 37u << kOpcodeShift, "lhu", "TO", }, - { kITypeMask, 40u << kOpcodeShift, "sb", "TO", }, - { kITypeMask, 41u << kOpcodeShift, "sh", "TO", }, - { kITypeMask, 43u << kOpcodeShift, "sw", "TO", }, - { kITypeMask, 49u << kOpcodeShift, "lwc1", "tO", }, - { kITypeMask, 57u << kOpcodeShift, "swc1", "tO", }, - - // Floating point. - { kFpMask, kCop1 | 0, "add", "fdst" }, - { kFpMask, kCop1 | 1, "sub", "fdst" }, - { kFpMask, kCop1 | 2, "mul", "fdst" }, - { kFpMask, kCop1 | 3, "div", "fdst" }, - { kFpMask | (0x1f << 16), kCop1 | 4, "sqrt", "fdst" }, - { kFpMask | (0x1f << 16), kCop1 | 5, "abs", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 6, "mov", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 7, "neg", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 8, "round.l", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 9, "trunc.l", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 10, "ceil.l", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 11, "floor.l", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 12, "round.w", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 13, "trunc.w", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 14, "ceil.w", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 15, "floor.w", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 32, "cvt.s", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 33, "cvt.d", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 36, "cvt.w", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 37, "cvt.l", "fds" }, - { kFpMask | (0x1f << 16), kCop1 | 38, "cvt.ps", "fds" }, -}; - -static uint32_t ReadU32(const uint8_t* ptr) { - // We only support little-endian MIPS. - return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); -} - -static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) { - uint32_t instruction = ReadU32(instr_ptr); - - uint32_t rs = (instruction >> 21) & 0x1f; // I-type, R-type. - uint32_t rt = (instruction >> 16) & 0x1f; // I-type, R-type. - uint32_t rd = (instruction >> 11) & 0x1f; // R-type. - uint32_t sa = (instruction >> 6) & 0x1f; // R-type. - - std::string opcode; - std::ostringstream args; - - // TODO: remove this! - uint32_t op = (instruction >> 26) & 0x3f; - uint32_t function = (instruction & 0x3f); // R-type. - opcode = StringPrintf("op=%d fn=%d", op, function); - - for (size_t i = 0; i < arraysize(gMipsInstructions); ++i) { - if (gMipsInstructions[i].Matches(instruction)) { - opcode = gMipsInstructions[i].name; - for (const char* args_fmt = gMipsInstructions[i].args_fmt; *args_fmt; ++args_fmt) { - switch (*args_fmt) { - case 'A': // sa (shift amount). - args << sa; - break; - case 'B': // Branch offset. - { - int32_t offset = static_cast(instruction & 0xffff); - offset <<= 2; - offset += 4; // Delay slot. - args << StringPrintf("%p ; %+d", instr_ptr + offset, offset); - } - break; - case 'D': args << 'r' << rd; break; - case 'd': args << 'f' << rd; break; - case 'f': // Floating point "fmt". - { - size_t fmt = (instruction >> 21) & 0x7; // TODO: other fmts? - switch (fmt) { - case 0: opcode += ".s"; break; - case 1: opcode += ".d"; break; - case 4: opcode += ".w"; break; - case 5: opcode += ".l"; break; - case 6: opcode += ".ps"; break; - default: opcode += ".?"; break; - } - continue; // No ", ". - } - break; - case 'I': // Upper 16-bit immediate. - args << reinterpret_cast((instruction & 0xffff) << 16); - break; - case 'i': // Sign-extended lower 16-bit immediate. - args << static_cast(instruction & 0xffff); - break; - case 'L': // Jump label. - { - // TODO: is this right? - uint32_t instr_index = (instruction & 0x1ffffff); - uint32_t target = (instr_index << 2); - target |= (reinterpret_cast(instr_ptr + 4) & 0xf0000000); - args << reinterpret_cast(target); - } - break; - case 'O': // +x(rs) - { - int32_t offset = static_cast(instruction & 0xffff); - args << StringPrintf("%+d(r%d)", offset, rs); - if (rs == 17) { - args << " ; "; - Thread::DumpThreadOffset(args, offset, 4); - } - } - break; - case 'S': args << 'r' << rs; break; - case 's': args << 'f' << rs; break; - case 'T': args << 'r' << rt; break; - case 't': args << 'f' << rt; break; - } - if (*(args_fmt + 1)) { - args << ", "; - } - } - break; - } - } - - os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n'; -} - -DisassemblerMips::DisassemblerMips() { -} - -size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin) { - DumpMips(os, begin); - return 4; -} - -void DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { - for (const uint8_t* cur = begin; cur < end; cur += 4) { - DumpMips(os, cur); - } -} - -} // namespace mips -} // namespace art diff --git a/runtime/disassembler_mips.h b/runtime/disassembler_mips.h deleted file mode 100644 index e248503963..0000000000 --- a/runtime/disassembler_mips.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2012 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_RUNTIME_DISASSEMBLER_MIPS_H_ -#define ART_RUNTIME_DISASSEMBLER_MIPS_H_ - -#include - -#include "disassembler.h" - -namespace art { -namespace mips { - -class DisassemblerMips : public Disassembler { - public: - DisassemblerMips(); - virtual size_t Dump(std::ostream& os, const uint8_t* begin); - virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end); - - private: - DISALLOW_COPY_AND_ASSIGN(DisassemblerMips); -}; - -} // namespace mips -} // namespace art - -#endif // ART_RUNTIME_DISASSEMBLER_MIPS_H_ diff --git a/runtime/disassembler_x86.cc b/runtime/disassembler_x86.cc deleted file mode 100644 index e5cdb7b297..0000000000 --- a/runtime/disassembler_x86.cc +++ /dev/null @@ -1,750 +0,0 @@ -/* - * Copyright (C) 2012 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 "disassembler_x86.h" - -#include - -#include "base/logging.h" -#include "base/stringprintf.h" -#include "thread.h" - -namespace art { -namespace x86 { - -DisassemblerX86::DisassemblerX86() {} - -size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) { - return DumpInstruction(os, begin); -} - -void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { - size_t length = 0; - for (const uint8_t* cur = begin; cur < end; cur += length) { - length = DumpInstruction(os, cur); - } -} - -static const char* gReg8Names[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; -static const char* gReg16Names[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; -static const char* gReg32Names[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; - -static void DumpReg0(std::ostream& os, uint8_t /*rex*/, size_t reg, - bool byte_operand, uint8_t size_override) { - DCHECK_LT(reg, 8u); - // TODO: combine rex into size - size_t size = byte_operand ? 1 : (size_override == 0x66 ? 2 : 4); - switch (size) { - case 1: os << gReg8Names[reg]; break; - case 2: os << gReg16Names[reg]; break; - case 4: os << gReg32Names[reg]; break; - default: LOG(FATAL) << "unexpected size " << size; - } -} - -enum RegFile { GPR, MMX, SSE }; - -static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg, - bool byte_operand, uint8_t size_override, RegFile reg_file) { - size_t reg_num = reg; // TODO: combine with REX.R on 64bit - if (reg_file == GPR) { - DumpReg0(os, rex, reg_num, byte_operand, size_override); - } else if (reg_file == SSE) { - os << "xmm" << reg_num; - } else { - os << "mm" << reg_num; - } -} - -static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) { - size_t reg_num = reg; // TODO: combine with REX.B on 64bit - DumpReg0(os, rex, reg_num, false, 0); -} - -static void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) { - int reg_num = reg; // TODO: combine with REX.X on 64bit - DumpReg0(os, rex, reg_num, false, 0); -} - -enum SegmentPrefix { - kCs = 0x2e, - kSs = 0x36, - kDs = 0x3e, - kEs = 0x26, - kFs = 0x64, - kGs = 0x65, -}; - -static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) { - switch (segment_prefix) { - case kCs: os << "cs:"; break; - case kSs: os << "ss:"; break; - case kDs: os << "ds:"; break; - case kEs: os << "es:"; break; - case kFs: os << "fs:"; break; - case kGs: os << "gs:"; break; - default: break; - } -} - -size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) { - const uint8_t* begin_instr = instr; - bool have_prefixes = true; - uint8_t prefix[4] = {0, 0, 0, 0}; - const char** modrm_opcodes = NULL; - do { - switch (*instr) { - // Group 1 - lock and repeat prefixes: - case 0xF0: - case 0xF2: - case 0xF3: - prefix[0] = *instr; - break; - // Group 2 - segment override prefixes: - case kCs: - case kSs: - case kDs: - case kEs: - case kFs: - case kGs: - prefix[1] = *instr; - break; - // Group 3 - operand size override: - case 0x66: - prefix[2] = *instr; - break; - // Group 4 - address size override: - case 0x67: - prefix[3] = *instr; - break; - default: - have_prefixes = false; - break; - } - if (have_prefixes) { - instr++; - } - } while (have_prefixes); - uint8_t rex = (*instr >= 0x40 && *instr <= 0x4F) ? *instr : 0; - bool has_modrm = false; - bool reg_is_opcode = false; - size_t immediate_bytes = 0; - size_t branch_bytes = 0; - std::ostringstream opcode; - bool store = false; // stores to memory (ie rm is on the left) - bool load = false; // loads from memory (ie rm is on the right) - bool byte_operand = false; - bool ax = false; // implicit use of ax - bool cx = false; // implicit use of cx - bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter - bool no_ops = false; - RegFile src_reg_file = GPR; - RegFile dst_reg_file = GPR; - switch (*instr) { -#define DISASSEMBLER_ENTRY(opname, \ - rm8_r8, rm32_r32, \ - r8_rm8, r32_rm32, \ - ax8_i8, ax32_i32) \ - case rm8_r8: opcode << #opname; store = true; has_modrm = true; byte_operand = true; break; \ - case rm32_r32: opcode << #opname; store = true; has_modrm = true; break; \ - case r8_rm8: opcode << #opname; load = true; has_modrm = true; byte_operand = true; break; \ - case r32_rm32: opcode << #opname; load = true; has_modrm = true; break; \ - case ax8_i8: opcode << #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \ - case ax32_i32: opcode << #opname; ax = true; immediate_bytes = 4; break; - -DISASSEMBLER_ENTRY(add, - 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */, - 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */, - 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */) -DISASSEMBLER_ENTRY(or, - 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */, - 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */, - 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */) -DISASSEMBLER_ENTRY(adc, - 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */, - 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */, - 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */) -DISASSEMBLER_ENTRY(sbb, - 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */, - 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */, - 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */) -DISASSEMBLER_ENTRY(and, - 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */, - 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */, - 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */) -DISASSEMBLER_ENTRY(sub, - 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */, - 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */, - 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */) -DISASSEMBLER_ENTRY(xor, - 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */, - 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */, - 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */) -DISASSEMBLER_ENTRY(cmp, - 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem32/Reg32 */, - 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */, - 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */) - -#undef DISASSEMBLER_ENTRY - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: - opcode << "push"; - reg_in_opcode = true; - break; - case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: - opcode << "pop"; - reg_in_opcode = true; - break; - case 0x68: opcode << "push"; immediate_bytes = 4; break; - case 0x6A: opcode << "push"; immediate_bytes = 1; break; - case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: - static const char* condition_codes[] = - {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq", "nz/ne", "be/na", "nbe/a", - "s", "ns", "p/pe", "np/po", "l/nge", "nl/ge", "le/ng", "nle/g" - }; - opcode << "j" << condition_codes[*instr & 0xF]; - branch_bytes = 1; - break; - case 0x88: opcode << "mov"; store = true; has_modrm = true; byte_operand = true; break; - case 0x89: opcode << "mov"; store = true; has_modrm = true; break; - case 0x8A: opcode << "mov"; load = true; has_modrm = true; byte_operand = true; break; - case 0x8B: opcode << "mov"; load = true; has_modrm = true; break; - - case 0x0F: // 2 byte extended opcode - instr++; - switch (*instr) { - case 0x10: case 0x11: - if (prefix[0] == 0xF2) { - opcode << "movsd"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF3) { - opcode << "movss"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[2] == 0x66) { - opcode << "movupd"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "movups"; - } - has_modrm = true; - src_reg_file = dst_reg_file = SSE; - load = *instr == 0x10; - store = !load; - break; - case 0x2A: - if (prefix[2] == 0x66) { - opcode << "cvtpi2pd"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF2) { - opcode << "cvtsi2sd"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF3) { - opcode << "cvtsi2ss"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "cvtpi2ps"; - } - load = true; - has_modrm = true; - dst_reg_file = SSE; - break; - case 0x2C: - if (prefix[2] == 0x66) { - opcode << "cvttpd2pi"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF2) { - opcode << "cvttsd2si"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF3) { - opcode << "cvttss2si"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "cvttps2pi"; - } - load = true; - has_modrm = true; - src_reg_file = SSE; - break; - case 0x2D: - if (prefix[2] == 0x66) { - opcode << "cvtpd2pi"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF2) { - opcode << "cvtsd2si"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF3) { - opcode << "cvtss2si"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "cvtps2pi"; - } - load = true; - has_modrm = true; - src_reg_file = SSE; - break; - case 0x2E: - opcode << "u"; - // FALLTHROUGH - case 0x2F: - if (prefix[2] == 0x66) { - opcode << "comisd"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "comiss"; - } - has_modrm = true; - load = true; - src_reg_file = dst_reg_file = SSE; - break; - case 0x38: // 3 byte extended opcode - opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr); - break; - case 0x3A: // 3 byte extended opcode - opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr); - break; - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: { - switch (*instr) { - case 0x50: opcode << "movmsk"; break; - case 0x51: opcode << "sqrt"; break; - case 0x52: opcode << "rsqrt"; break; - case 0x53: opcode << "rcp"; break; - case 0x54: opcode << "and"; break; - case 0x55: opcode << "andn"; break; - case 0x56: opcode << "or"; break; - case 0x57: opcode << "xor"; break; - case 0x58: opcode << "add"; break; - case 0x59: opcode << "mul"; break; - case 0x5C: opcode << "sub"; break; - case 0x5D: opcode << "min"; break; - case 0x5E: opcode << "div"; break; - case 0x5F: opcode << "max"; break; - default: LOG(FATAL) << "Unreachable"; - } - if (prefix[2] == 0x66) { - opcode << "pd"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF2) { - opcode << "sd"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF3) { - opcode << "ss"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "ps"; - } - load = true; - has_modrm = true; - src_reg_file = dst_reg_file = SSE; - break; - } - case 0x5A: - if (prefix[2] == 0x66) { - opcode << "cvtpd2ps"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF2) { - opcode << "cvtsd2ss"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF3) { - opcode << "cvtss2sd"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "cvtps2pd"; - } - load = true; - has_modrm = true; - src_reg_file = dst_reg_file = SSE; - break; - case 0x5B: - if (prefix[2] == 0x66) { - opcode << "cvtps2dq"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF2) { - opcode << "bad opcode F2 0F 5B"; - } else if (prefix[0] == 0xF3) { - opcode << "cvttps2dq"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - opcode << "cvtdq2ps"; - } - load = true; - has_modrm = true; - src_reg_file = dst_reg_file = SSE; - break; - case 0x6E: - if (prefix[2] == 0x66) { - dst_reg_file = SSE; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - dst_reg_file = MMX; - } - opcode << "movd"; - load = true; - has_modrm = true; - break; - case 0x6F: - if (prefix[2] == 0x66) { - dst_reg_file = SSE; - opcode << "movdqa"; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else if (prefix[0] == 0xF3) { - dst_reg_file = SSE; - opcode << "movdqu"; - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - dst_reg_file = MMX; - opcode << "movq"; - } - load = true; - has_modrm = true; - break; - case 0x71: - if (prefix[2] == 0x66) { - dst_reg_file = SSE; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - dst_reg_file = MMX; - } - static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"}; - modrm_opcodes = x71_opcodes; - reg_is_opcode = true; - has_modrm = true; - store = true; - immediate_bytes = 1; - break; - case 0x72: - if (prefix[2] == 0x66) { - dst_reg_file = SSE; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - dst_reg_file = MMX; - } - static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"}; - modrm_opcodes = x72_opcodes; - reg_is_opcode = true; - has_modrm = true; - store = true; - immediate_bytes = 1; - break; - case 0x73: - if (prefix[2] == 0x66) { - dst_reg_file = SSE; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - dst_reg_file = MMX; - } - static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "unknown-73", "unknown-73", "unknown-73", "psllq", "unknown-73"}; - modrm_opcodes = x73_opcodes; - reg_is_opcode = true; - has_modrm = true; - store = true; - immediate_bytes = 1; - break; - case 0x7E: - if (prefix[2] == 0x66) { - src_reg_file = SSE; - prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode - } else { - src_reg_file = MMX; - } - opcode << "movd"; - has_modrm = true; - store = true; - break; - case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: - opcode << "j" << condition_codes[*instr & 0xF]; - branch_bytes = 4; - break; - case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: - case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: - opcode << "set" << condition_codes[*instr & 0xF]; - modrm_opcodes = NULL; - reg_is_opcode = true; - has_modrm = true; - store = true; - break; - case 0xAE: - if (prefix[0] == 0xF3) { - prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode - static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"}; - modrm_opcodes = xAE_opcodes; - reg_is_opcode = true; - has_modrm = true; - uint8_t reg_or_opcode = (instr[1] >> 3) & 7; - switch (reg_or_opcode) { - case 0: - prefix[1] = kFs; - load = true; - break; - case 1: - prefix[1] = kGs; - load = true; - break; - case 2: - prefix[1] = kFs; - store = true; - break; - case 3: - prefix[1] = kGs; - store = true; - break; - default: - load = true; - break; - } - } else { - static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"}; - modrm_opcodes = xAE_opcodes; - reg_is_opcode = true; - has_modrm = true; - load = true; - no_ops = true; - } - break; - case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break; - case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; break; - case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break; - case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break; - case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break; - default: - opcode << StringPrintf("unknown opcode '0F %02X'", *instr); - break; - } - break; - case 0x80: case 0x81: case 0x82: case 0x83: - static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; - modrm_opcodes = x80_opcodes; - has_modrm = true; - reg_is_opcode = true; - store = true; - byte_operand = (*instr & 1) == 0; - immediate_bytes = *instr == 0x81 ? 4 : 1; - break; - case 0x84: case 0x85: - opcode << "test"; - has_modrm = true; - load = true; - byte_operand = (*instr & 1) == 0; - break; - case 0x8D: - opcode << "lea"; - has_modrm = true; - load = true; - break; - case 0x8F: - opcode << "pop"; - has_modrm = true; - reg_is_opcode = true; - store = true; - break; - case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: - opcode << "mov"; - immediate_bytes = 1; - reg_in_opcode = true; - break; - case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: - opcode << "mov"; - immediate_bytes = 4; - reg_in_opcode = true; - break; - case 0xC0: case 0xC1: - case 0xD0: case 0xD1: case 0xD2: case 0xD3: - static const char* shift_opcodes[] = - {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"}; - modrm_opcodes = shift_opcodes; - has_modrm = true; - reg_is_opcode = true; - store = true; - immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0; - cx = (*instr == 0xD2) || (*instr == 0xD3); - byte_operand = (*instr == 0xC0); - break; - case 0xC3: opcode << "ret"; break; - case 0xC7: - static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"}; - modrm_opcodes = c7_opcodes; - store = true; - immediate_bytes = 4; - has_modrm = true; - reg_is_opcode = true; - break; - case 0xCC: opcode << "int 3"; break; - case 0xE8: opcode << "call"; branch_bytes = 4; break; - case 0xE9: opcode << "jmp"; branch_bytes = 4; break; - case 0xEB: opcode << "jmp"; branch_bytes = 1; break; - case 0xF5: opcode << "cmc"; break; - case 0xF6: case 0xF7: - static const char* f7_opcodes[] = {"test", "unknown-f7", "not", "neg", "mul edx:eax, eax *", "imul edx:eax, eax *", "div edx:eax, edx:eax /", "idiv edx:eax, edx:eax /"}; - modrm_opcodes = f7_opcodes; - has_modrm = true; - reg_is_opcode = true; - store = true; - immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0; - break; - case 0xFF: - static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"}; - modrm_opcodes = ff_opcodes; - has_modrm = true; - reg_is_opcode = true; - load = true; - break; - default: - opcode << StringPrintf("unknown opcode '%02X'", *instr); - break; - } - std::ostringstream args; - if (reg_in_opcode) { - DCHECK(!has_modrm); - DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR); - } - instr++; - uint32_t address_bits = 0; - if (has_modrm) { - uint8_t modrm = *instr; - instr++; - uint8_t mod = modrm >> 6; - uint8_t reg_or_opcode = (modrm >> 3) & 7; - uint8_t rm = modrm & 7; - std::ostringstream address; - if (mod == 0 && rm == 5) { // fixed address - address_bits = *reinterpret_cast(instr); - address << StringPrintf("[0x%x]", address_bits); - instr += 4; - } else if (rm == 4 && mod != 3) { // SIB - uint8_t sib = *instr; - instr++; - uint8_t ss = (sib >> 6) & 3; - uint8_t index = (sib >> 3) & 7; - uint8_t base = sib & 7; - address << "["; - if (base != 5 || mod != 0) { - DumpBaseReg(address, rex, base); - if (index != 4) { - address << " + "; - } - } - if (index != 4) { - DumpIndexReg(address, rex, index); - if (ss != 0) { - address << StringPrintf(" * %d", 1 << ss); - } - } - if (mod == 1) { - address << StringPrintf(" + %d", *reinterpret_cast(instr)); - instr++; - } else if (mod == 2) { - address << StringPrintf(" + %d", *reinterpret_cast(instr)); - instr += 4; - } - address << "]"; - } else { - if (mod == 3) { - if (!no_ops) { - DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file); - } - } else { - address << "["; - DumpBaseReg(address, rex, rm); - if (mod == 1) { - address << StringPrintf(" + %d", *reinterpret_cast(instr)); - instr++; - } else if (mod == 2) { - address << StringPrintf(" + %d", *reinterpret_cast(instr)); - instr += 4; - } - address << "]"; - } - } - - if (reg_is_opcode && modrm_opcodes != NULL) { - opcode << modrm_opcodes[reg_or_opcode]; - } - if (load) { - if (!reg_is_opcode) { - DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file); - args << ", "; - } - DumpSegmentOverride(args, prefix[1]); - args << address.str(); - } else { - DCHECK(store); - DumpSegmentOverride(args, prefix[1]); - args << address.str(); - if (!reg_is_opcode) { - args << ", "; - DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file); - } - } - } - if (ax) { - // If this opcode implicitly uses ax, ax is always the first arg. - DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR); - } - if (cx) { - args << ", "; - DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR); - } - if (immediate_bytes > 0) { - if (has_modrm || reg_in_opcode || ax || cx) { - args << ", "; - } - if (immediate_bytes == 1) { - args << StringPrintf("%d", *reinterpret_cast(instr)); - instr++; - } else { - CHECK_EQ(immediate_bytes, 4u); - args << StringPrintf("%d", *reinterpret_cast(instr)); - instr += 4; - } - } else if (branch_bytes > 0) { - DCHECK(!has_modrm); - int32_t displacement; - if (branch_bytes == 1) { - displacement = *reinterpret_cast(instr); - instr++; - } else { - CHECK_EQ(branch_bytes, 4u); - displacement = *reinterpret_cast(instr); - instr += 4; - } - args << StringPrintf("%+d (%p)", displacement, instr + displacement); - } - if (prefix[1] == kFs) { - args << " ; "; - Thread::DumpThreadOffset(args, address_bits, 4); - } - std::stringstream hex; - for (size_t i = 0; begin_instr + i < instr; ++i) { - hex << StringPrintf("%02X", begin_instr[i]); - } - std::stringstream prefixed_opcode; - switch (prefix[0]) { - case 0xF0: prefixed_opcode << "lock "; break; - case 0xF2: prefixed_opcode << "repne "; break; - case 0xF3: prefixed_opcode << "repe "; break; - case 0: break; - default: LOG(FATAL) << "Unreachable"; - } - prefixed_opcode << opcode.str(); - os << StringPrintf("%p: %22s \t%-7s ", begin_instr, hex.str().c_str(), - prefixed_opcode.str().c_str()) - << args.str() << '\n'; - return instr - begin_instr; -} // NOLINT(readability/fn_size) - -} // namespace x86 -} // namespace art diff --git a/runtime/disassembler_x86.h b/runtime/disassembler_x86.h deleted file mode 100644 index ff4322c8b8..0000000000 --- a/runtime/disassembler_x86.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2012 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_RUNTIME_DISASSEMBLER_X86_H_ -#define ART_RUNTIME_DISASSEMBLER_X86_H_ - -#include "disassembler.h" - -namespace art { -namespace x86 { - -class DisassemblerX86 : public Disassembler { - public: - DisassemblerX86(); - - virtual size_t Dump(std::ostream& os, const uint8_t* begin); - virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end); - private: - size_t DumpInstruction(std::ostream& os, const uint8_t* instr); -}; - -} // namespace x86 -} // namespace art - -#endif // ART_RUNTIME_DISASSEMBLER_X86_H_ diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h index c22f2cd921..4552062319 100644 --- a/runtime/thread-inl.h +++ b/runtime/thread-inl.h @@ -19,11 +19,24 @@ #include "thread.h" +#include + #include "base/mutex-inl.h" #include "cutils/atomic-inline.h" namespace art { +inline Thread* Thread::Current() { + // We rely on Thread::Current returning NULL for a detached thread, so it's not obvious + // that we can replace this with a direct %fs access on x86. + if (!is_started_) { + return NULL; + } else { + void* thread = pthread_getspecific(Thread::pthread_key_self_); + return reinterpret_cast(thread); + } +} + inline ThreadState Thread::SetState(ThreadState new_state) { // Cannot use this code to change into Runnable as changing to Runnable should fail if // old_state_and_flags.suspend_request is true. diff --git a/runtime/thread.h b/runtime/thread.h index 40e3f5fbb2..f5f8f563fa 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -17,8 +17,6 @@ #ifndef ART_RUNTIME_THREAD_H_ #define ART_RUNTIME_THREAD_H_ -#include - #include #include #include @@ -104,16 +102,7 @@ class PACKED(4) Thread { // Reset internal state of child thread after fork. void InitAfterFork(); - static Thread* Current() { - // We rely on Thread::Current returning NULL for a detached thread, so it's not obvious - // that we can replace this with a direct %fs access on x86. - if (!is_started_) { - return NULL; - } else { - void* thread = pthread_getspecific(Thread::pthread_key_self_); - return reinterpret_cast(thread); - } - } + static Thread* Current(); static Thread* FromManagedThread(const ScopedObjectAccessUnchecked& ts, mirror::Object* thread_peer) -- cgit v1.2.3-59-g8ed1b From 8b2c0b9abc3f520495f4387ea040132ba85cae69 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 19 Sep 2013 02:56:49 -0700 Subject: Use class def index from java.lang.Class. Bug: 10244719 Depends on: https://googleplex-android-review.git.corp.google.com/362363 This removes the computation of the dex file index, when necessary this is computed by searching the dex file. Its only necessary in dalvik.system.DexFile.defineClassNative and DexFile::FindInClassPath, the latter not showing up significantly in profiling with this change. Change-Id: I20c73a3b17d86286428ab0fd21bc13f51f36c85c --- compiler/dex/compiler_ir.h | 2 +- compiler/dex/dex_to_dex_compiler.cc | 2 +- compiler/dex/frontend.cc | 6 +- compiler/dex/frontend.h | 2 +- compiler/dex/mir_graph.cc | 2 +- compiler/dex/mir_graph.h | 2 +- compiler/dex/quick/codegen_util.cc | 22 ++-- compiler/driver/compiler_driver.cc | 49 +++++---- compiler/driver/compiler_driver.h | 27 +++-- compiler/driver/dex_compilation_unit.cc | 2 +- compiler/driver/dex_compilation_unit.h | 6 +- compiler/image_writer.cc | 1 + compiler/llvm/compiler_llvm.cc | 4 +- compiler/sea_ir/frontend.cc | 6 +- compiler/sea_ir/ir/sea.cc | 4 +- compiler/sea_ir/ir/sea.h | 6 +- oatdump/oatdump.cc | 32 +++--- runtime/Android.mk | 1 + runtime/class_linker.cc | 111 ++++++++++----------- runtime/class_linker.h | 4 +- runtime/class_linker_test.cc | 12 +-- runtime/dex_file.cc | 91 +++++------------ runtime/dex_file.h | 44 +++----- .../entrypoints/quick/quick_invoke_entrypoints.cc | 2 +- runtime/mirror/art_method-inl.h | 2 +- runtime/mirror/class.cc | 23 ++--- runtime/mirror/class.h | 31 ++++-- runtime/mirror/dex_cache.h | 1 + runtime/mirror/proxy.h | 3 + runtime/mirror/string.h | 2 +- runtime/native/dalvik_system_DexFile.cc | 2 +- runtime/native/java_lang_Class.cc | 31 ------ runtime/native/java_lang_DexCache.cc | 56 +++++++++++ runtime/oat_file.cc | 2 +- runtime/oat_file.h | 2 +- runtime/object_utils.h | 87 +++++++--------- runtime/runtime.cc | 5 +- runtime/thread.cc | 2 +- runtime/verifier/method_verifier.cc | 96 +++++++++--------- runtime/verifier/method_verifier.h | 19 ++-- runtime/verifier/method_verifier_test.cc | 3 +- test/100-reflect2/expected.txt | 2 +- 42 files changed, 397 insertions(+), 412 deletions(-) create mode 100644 runtime/native/java_lang_DexCache.cc (limited to 'compiler/llvm/compiler_llvm.cc') diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 26d0923baa..6607562b13 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -77,7 +77,7 @@ struct CompilationUnit { ClassLinker* class_linker; // Linker to resolve fields and methods. const DexFile* dex_file; // DexFile containing the method being compiled. jobject class_loader; // compiling method's class loader. - uint32_t class_def_idx; // compiling method's defining class definition index. + uint16_t class_def_idx; // compiling method's defining class definition index. uint32_t method_idx; // compiling method's index into method_ids of DexFile. const DexFile::CodeItem* code_item; // compiling method's DexFile code_item. uint32_t access_flags; // compiling method's access flags. diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index ffd7905dfe..abafbc5830 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -280,7 +280,7 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, extern "C" void ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file, art::DexToDexCompilationLevel dex_to_dex_compilation_level) { if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) { diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 23036495ce..fefcab9e87 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -110,7 +110,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm::LlvmCompilationUnit* llvm_compilation_unit @@ -273,7 +273,7 @@ CompiledMethod* CompileOneMethod(CompilerDriver& compiler, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, @@ -292,7 +292,7 @@ extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default art::CompilerBackend backend = compiler.GetCompilerBackend(); diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h index bafa46892c..6c33d109e3 100644 --- a/compiler/dex/frontend.h +++ b/compiler/dex/frontend.h @@ -117,7 +117,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_dex_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index c72283e689..c234298a88 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -504,7 +504,7 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ /* Parse a Dex method and insert it into the MIRGraph at the current insert point. */ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file) { current_code_item_ = code_item; method_stack_.push_back(std::make_pair(current_method_, current_offset_)); diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 0244daec9d..9d4ab98f67 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -357,7 +357,7 @@ class MIRGraph { * actually the index of the method in the m_units_ array). */ void InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file); /* Find existing block */ diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index f13ab2db01..4ce752fb39 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -385,11 +385,12 @@ void Mir2Lir::InstallLiteralPools() { while (data_lir != NULL) { uint32_t target = data_lir->operands[0]; cu_->compiler_driver->AddCodePatch(cu_->dex_file, - cu_->method_idx, - cu_->invoke_type, - target, - static_cast(data_lir->operands[1]), - code_buffer_.size()); + cu_->class_def_idx, + cu_->method_idx, + cu_->invoke_type, + target, + static_cast(data_lir->operands[1]), + code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); // unique based on target to ensure code deduplication works uint32_t unique_patch_value = reinterpret_cast(&id); @@ -400,11 +401,12 @@ void Mir2Lir::InstallLiteralPools() { while (data_lir != NULL) { uint32_t target = data_lir->operands[0]; cu_->compiler_driver->AddMethodPatch(cu_->dex_file, - cu_->method_idx, - cu_->invoke_type, - target, - static_cast(data_lir->operands[1]), - code_buffer_.size()); + cu_->class_def_idx, + cu_->method_idx, + cu_->invoke_type, + target, + static_cast(data_lir->operands[1]), + code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); // unique based on target to ensure code deduplication works uint32_t unique_patch_value = reinterpret_cast(&id); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 8d521de72f..658370f1fd 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -293,7 +293,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -301,7 +301,7 @@ extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compi const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -310,7 +310,7 @@ extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -319,7 +319,7 @@ extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -540,7 +540,7 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, base::TimingLog Thread* self = Thread::Current(); jobject jclass_loader; const DexFile* dex_file; - uint32_t class_def_idx; + uint16_t class_def_idx; { ScopedObjectAccessUnchecked soa(self); ScopedLocalRef @@ -1304,13 +1304,15 @@ bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) { void CompilerDriver::AddCodePatch(const DexFile* dex_file, - uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, - size_t literal_offset) { + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); code_to_patch_.push_back(new PatchInformation(dex_file, + referrer_class_def_idx, referrer_method_idx, referrer_invoke_type, target_method_idx, @@ -1318,13 +1320,15 @@ void CompilerDriver::AddCodePatch(const DexFile* dex_file, literal_offset)); } void CompilerDriver::AddMethodPatch(const DexFile* dex_file, - uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, - size_t literal_offset) { + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); methods_to_patch_.push_back(new PatchInformation(dex_file, + referrer_class_def_idx, referrer_method_idx, referrer_invoke_type, target_method_idx, @@ -1625,10 +1629,12 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ */ mirror::DexCache* dex_cache = manager->GetClassLinker()->FindDexCache(*manager->GetDexFile()); std::string error_msg; - if (verifier::MethodVerifier::VerifyClass(manager->GetDexFile(), + const DexFile* dex_file = manager->GetDexFile(); + const DexFile::ClassDef* class_def = &dex_file->GetClassDef(class_def_index); + if (verifier::MethodVerifier::VerifyClass(dex_file, dex_cache, soa.Decode(manager->GetClassLoader()), - class_def_index, error_msg, true) == + class_def, true, &error_msg) == verifier::MethodVerifier::kHardFailure) { const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); LOG(ERROR) << "Verification failed on class " @@ -2137,7 +2143,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } // If successfully initialized place in SSB array. if (klass->IsInitialized()) { - klass->GetDexCache()->GetInitializedStaticStorage()->Set(klass->GetDexTypeIndex(), klass); + int32_t ssb_index = klass->GetDexTypeIndex(); + klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass); } } // Record the final class status if necessary. @@ -2264,7 +2271,7 @@ void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_fil } void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) { @@ -2387,13 +2394,13 @@ void CompilerDriver::SetBitcodeFileName(std::string const& filename) { void CompilerDriver::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - size_t class_def_index) { + uint16_t class_def_index) { WriterMutexLock mu(self, freezing_constructor_lock_); freezing_constructor_classes_.insert(ClassReference(dex_file, class_def_index)); } bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - size_t class_def_index) { + uint16_t class_def_index) { ReaderMutexLock mu(self, freezing_constructor_lock_); return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0; } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index b4ec0c134b..66c9cbf91a 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -145,8 +145,9 @@ class CompilerDriver { CompiledMethod* GetCompiledMethod(MethodReference ref) const LOCKS_EXCLUDED(compiled_methods_lock_); - void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); - bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); + void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, + uint16_t class_def_index); + bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, uint16_t class_def_index); // Callbacks from compiler to see what runtime checks must be generated. @@ -192,6 +193,7 @@ class CompilerDriver { // Record patch information for later fix up. void AddCodePatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, @@ -199,6 +201,7 @@ class CompilerDriver { size_t literal_offset) LOCKS_EXCLUDED(compiled_methods_lock_); void AddMethodPatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, @@ -249,6 +252,9 @@ class CompilerDriver { const DexFile& GetDexFile() const { return *dex_file_; } + uint16_t GetReferrerClassDefIdx() const { + return referrer_class_def_idx_; + } uint32_t GetReferrerMethodIdx() const { return referrer_method_idx_; } @@ -267,12 +273,14 @@ class CompilerDriver { private: PatchInformation(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, InvokeType target_invoke_type, size_t literal_offset) : dex_file_(dex_file), + referrer_class_def_idx_(referrer_class_def_idx), referrer_method_idx_(referrer_method_idx), referrer_invoke_type_(referrer_invoke_type), target_method_idx_(target_method_idx), @@ -281,12 +289,13 @@ class CompilerDriver { CHECK(dex_file_ != NULL); } - const DexFile* dex_file_; - uint32_t referrer_method_idx_; - InvokeType referrer_invoke_type_; - uint32_t target_method_idx_; - InvokeType target_invoke_type_; - size_t literal_offset_; + const DexFile* const dex_file_; + const uint16_t referrer_class_def_idx_; + const uint32_t referrer_method_idx_; + const InvokeType referrer_invoke_type_; + const uint32_t target_method_idx_; + const InvokeType target_invoke_type_; + const size_t literal_offset_; friend class CompilerDriver; DISALLOW_COPY_AND_ASSIGN(PatchInformation); @@ -358,7 +367,7 @@ class CompilerDriver { ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) LOCKS_EXCLUDED(compiled_methods_lock_); diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index eb8941b15f..c441d09ab2 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -39,7 +39,7 @@ DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags) : cu_(cu), diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h index 465139b34f..3df50ffec6 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -36,7 +36,7 @@ class DexCompilationUnit { DexCompilationUnit(CompilationUnit* cu, jobject class_loader, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, - uint32_t class_def_idx, uint32_t method_idx, uint32_t access_flags); + uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags); CompilationUnit* GetCompilationUnit() const { return cu_; @@ -54,7 +54,7 @@ class DexCompilationUnit { return dex_file_; } - uint32_t GetClassDefIndex() const { + uint16_t GetClassDefIndex() const { return class_def_idx_; } @@ -108,7 +108,7 @@ class DexCompilationUnit { const DexFile* const dex_file_; const DexFile::CodeItem* const code_item_; - const uint32_t class_def_idx_; + const uint16_t class_def_idx_; const uint32_t dex_method_idx_; const uint32_t access_flags_; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index d1859e6f98..f82c6fb40f 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -699,6 +699,7 @@ void ImageWriter::PatchOatCodeAndMethods() { void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const void* oat_code = class_linker->GetOatCodeFor(patch->GetDexFile(), + patch->GetReferrerClassDefIdx(), patch->GetReferrerMethodIdx()); OatHeader& oat_header = const_cast(oat_file_->GetOatHeader()); // TODO: make this Thumb2 specific diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index 0df3c476fc..d59afd48b7 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -40,7 +40,7 @@ void CompileOneMethod(CompilerDriver& driver, const CompilerBackend compilerBackend, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, llvm::LlvmCompilationUnit* llvm_info); } @@ -203,7 +203,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc index 93f6f25461..3512911f43 100644 --- a/compiler/sea_ir/frontend.cc +++ b/compiler/sea_ir/frontend.cc @@ -41,7 +41,7 @@ static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, uint32_t method_access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm::LlvmCompilationUnit* llvm_compilation_unit @@ -69,7 +69,7 @@ CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler, const DexFile::CodeItem* code_item, uint32_t method_access_flags, InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, @@ -86,7 +86,7 @@ extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t method_access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { // TODO: Check method fingerprint here to determine appropriate backend type. // Until then, use build default diff --git a/compiler/sea_ir/ir/sea.cc b/compiler/sea_ir/ir/sea.cc index 5ccaba6ad9..0734b21f12 100644 --- a/compiler/sea_ir/ir/sea.cc +++ b/compiler/sea_ir/ir/sea.cc @@ -191,7 +191,7 @@ void SeaGraph::InsertSignatureNodes(const art::DexFile::CodeItem* code_item, Reg } void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, + const art::DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags) { code_item_ = code_item; class_def_idx_ = class_def_idx; @@ -409,7 +409,7 @@ CodeGenData* SeaGraph::GenerateLLVM(const std::string& function_name, CodeGenData* SeaGraph::CompileMethod( const std::string& function_name, - const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + const art::DexFile::CodeItem* code_item, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file) { // Two passes: Builds the intermediate structure (non-SSA) of the sea-ir for the function. BuildMethodSeaGraph(code_item, dex_file, class_def_idx, method_idx, method_access_flags); diff --git a/compiler/sea_ir/ir/sea.h b/compiler/sea_ir/ir/sea.h index 92c2043dbd..26b16be019 100644 --- a/compiler/sea_ir/ir/sea.h +++ b/compiler/sea_ir/ir/sea.h @@ -262,7 +262,7 @@ class SeaGraph: IVisitable { static SeaGraph* GetGraph(const art::DexFile&); CodeGenData* CompileMethod(const std::string& function_name, - const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + const art::DexFile::CodeItem* code_item, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file); // Returns all regions corresponding to this SeaGraph. std::vector* GetRegions() { @@ -288,7 +288,7 @@ class SeaGraph: IVisitable { } TypeInference* ti_; - uint32_t class_def_idx_; + uint16_t class_def_idx_; uint32_t method_idx_; uint32_t method_access_flags_; @@ -311,7 +311,7 @@ class SeaGraph: IVisitable { // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file // with class id @class_def_idx and method id @method_idx. void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, + const art::DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags); // Computes immediate dominators for each region. // Precondition: ComputeMethodSeaGraph() diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index cf1b6af809..fc9e00c2cb 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -176,9 +176,10 @@ class OatDumper { CHECK(oat_dex_file != NULL); UniquePtr dex_file(oat_dex_file->OpenDexFile()); if (dex_file.get() != NULL) { - uint32_t class_def_index; - bool found = dex_file->FindClassDefIndex(mh.GetDeclaringClassDescriptor(), class_def_index); - if (found) { + const DexFile::ClassDef* class_def = + dex_file->FindClassDef(mh.GetDeclaringClassDescriptor()); + if (class_def != NULL) { + uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def); const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); CHECK(oat_class != NULL); size_t method_index = m->GetMethodIndex(); @@ -284,18 +285,17 @@ class OatDumper { } ClassDataItemIterator it(dex_file, class_data); SkipAllFields(it); - uint32_t class_def_idx = dex_file.GetIndexForClassDef(class_def); uint32_t class_method_idx = 0; while (it.HasNextDirectMethod()) { const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def_idx, class_method_idx, oat_method, dex_file, + DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags()); class_method_idx++; it.Next(); } while (it.HasNextVirtualMethod()) { const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def_idx, class_method_idx, oat_method, dex_file, + DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags()); class_method_idx++; it.Next(); @@ -304,7 +304,8 @@ class OatDumper { os << std::flush; } - void DumpOatMethod(std::ostream& os, uint32_t class_def_idx, uint32_t class_method_index, + void DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def, + uint32_t class_method_index, const OatFile::OatMethod& oat_method, const DexFile& dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { @@ -323,7 +324,8 @@ class OatDumper { indent1_os << "VERIFIER TYPE ANALYSIS:\n"; Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); - DumpVerifier(indent2_os, dex_method_idx, &dex_file, class_def_idx, code_item, method_access_flags); + DumpVerifier(indent2_os, dex_method_idx, &dex_file, class_def, code_item, + method_access_flags); } { indent1_os << "OAT DATA:\n"; @@ -363,7 +365,7 @@ class OatDumper { oat_method.GetCode() != NULL ? "..." : ""); Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); - DumpCode(indent2_os, oat_method, dex_method_idx, &dex_file, class_def_idx, code_item, + DumpCode(indent2_os, oat_method, dex_method_idx, &dex_file, class_def, code_item, method_access_flags); } } @@ -554,7 +556,7 @@ class OatDumper { void DumpVRegsAtDexPc(std::ostream& os, const OatFile::OatMethod& oat_method, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags, uint32_t dex_pc) { static UniquePtr verifier; static const DexFile* verified_dex_file = NULL; @@ -563,7 +565,7 @@ class OatDumper { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); mirror::ClassLoader* class_loader = NULL; - verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, class_def_idx, + verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, &class_def, code_item, dex_method_idx, NULL, method_access_flags, true, true)); verifier->Verify(); @@ -615,21 +617,21 @@ class OatDumper { } void DumpVerifier(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { if ((method_access_flags & kAccNative) == 0) { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); mirror::ClassLoader* class_loader = NULL; verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache, - class_loader, class_def_idx, code_item, NULL, + class_loader, &class_def, code_item, NULL, method_access_flags); } } void DumpCode(std::ostream& os, const OatFile::OatMethod& oat_method, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { const void* code = oat_method.GetCode(); size_t code_size = oat_method.GetCodeSize(); @@ -647,7 +649,7 @@ class OatDumper { if (dex_pc != DexFile::kDexNoIndex) { DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset); if (kDumpVRegs) { - DumpVRegsAtDexPc(os, oat_method, dex_method_idx, dex_file, class_def_idx, code_item, + DumpVRegsAtDexPc(os, oat_method, dex_method_idx, dex_file, class_def, code_item, method_access_flags, dex_pc); } } diff --git a/runtime/Android.mk b/runtime/Android.mk index e324060ecb..5edf7592d9 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -91,6 +91,7 @@ LIBART_COMMON_SRC_FILES := \ native/dalvik_system_VMStack.cc \ native/dalvik_system_Zygote.cc \ native/java_lang_Class.cc \ + native/java_lang_DexCache.cc \ native/java_lang_Object.cc \ native/java_lang_Runtime.cc \ native/java_lang_String.cc \ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c19f8724bb..15eab9d165 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -475,40 +475,33 @@ void ClassLinker::FinishInit() { // as the types of the field can't be resolved prior to the runtime being // fully initialized mirror::Class* java_lang_ref_Reference = GetClassRoot(kJavaLangRefReference); - mirror::Class* java_lang_ref_ReferenceQueue = FindSystemClass("Ljava/lang/ref/ReferenceQueue;"); - mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;"); - - const DexFile& java_lang_dex = *java_lang_ref_Reference->GetDexCache()->GetDexFile(); + mirror::Class* java_lang_ref_FinalizerReference = + FindSystemClass("Ljava/lang/ref/FinalizerReference;"); mirror::ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0); FieldHelper fh(pendingNext, this); CHECK_STREQ(fh.GetName(), "pendingNext"); - CHECK_EQ(java_lang_dex.GetFieldId(pendingNext->GetDexFieldIndex()).type_idx_, - java_lang_ref_Reference->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); mirror::ArtField* queue = java_lang_ref_Reference->GetInstanceField(1); fh.ChangeField(queue); CHECK_STREQ(fh.GetName(), "queue"); - CHECK_EQ(java_lang_dex.GetFieldId(queue->GetDexFieldIndex()).type_idx_, - java_lang_ref_ReferenceQueue->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/ReferenceQueue;"); mirror::ArtField* queueNext = java_lang_ref_Reference->GetInstanceField(2); fh.ChangeField(queueNext); CHECK_STREQ(fh.GetName(), "queueNext"); - CHECK_EQ(java_lang_dex.GetFieldId(queueNext->GetDexFieldIndex()).type_idx_, - java_lang_ref_Reference->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); mirror::ArtField* referent = java_lang_ref_Reference->GetInstanceField(3); fh.ChangeField(referent); CHECK_STREQ(fh.GetName(), "referent"); - CHECK_EQ(java_lang_dex.GetFieldId(referent->GetDexFieldIndex()).type_idx_, - GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/Object;"); mirror::ArtField* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2); fh.ChangeField(zombie); CHECK_STREQ(fh.GetName(), "zombie"); - CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_, - GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/Object;"); gc::Heap* heap = Runtime::Current()->GetHeap(); heap->SetReferenceOffsets(referent->GetOffset(), @@ -1234,8 +1227,10 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Cl return NULL; } mirror::Class* klass = k->AsClass(); - klass->SetPrimitiveType(Primitive::kPrimNot); // default to not being primitive + klass->SetPrimitiveType(Primitive::kPrimNot); // Default to not being primitive. klass->SetClassSize(class_size); + klass->SetDexClassDefIndex(DexFile::kDexNoIndex16); // Default to no valid class def index. + klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index. return klass; } @@ -1499,26 +1494,21 @@ size_t ClassLinker::SizeOfClass(const DexFile& dex_file, return size; } -const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) { - DCHECK(descriptor != NULL); +const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) { + DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); - CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor; + CHECK(oat_file != NULL) << dex_file.GetLocation(); const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); - CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor; - uint32_t class_def_index; - bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); - CHECK(found) << dex_file.GetLocation() << " " << descriptor; - const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); - CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << descriptor; + CHECK(oat_dex_file != NULL) << dex_file.GetLocation(); + const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_idx); + CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << class_def_idx; return oat_class; } -static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint32_t method_idx) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - const DexFile::TypeId& type_id = dex_file.GetTypeId(method_id.class_idx_); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(dex_file.GetTypeDescriptor(type_id)); - CHECK(class_def != NULL); - const byte* class_data = dex_file.GetClassData(*class_def); +static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); + const byte* class_data = dex_file.GetClassData(class_def); CHECK(class_data != NULL); ClassDataItemIterator it(dex_file, class_data); // Skip fields @@ -1572,11 +1562,13 @@ const OatFile::OatMethod ClassLinker::GetOatMethodFor(const mirror::ArtMethod* m } CHECK(found) << "Didn't find oat method index for virtual method: " << PrettyMethod(method); } - ClassHelper kh(declaring_class); - UniquePtr oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor())); + UniquePtr + oat_class(GetOatClass(*declaring_class->GetDexCache()->GetDexFile(), + declaring_class->GetDexClassDefIndex())); CHECK(oat_class.get() != NULL); DCHECK_EQ(oat_method_index, GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(), + method->GetDeclaringClass()->GetDexClassDefIndex(), method->GetDexMethodIndex())); return oat_class->GetOatMethod(oat_method_index); @@ -1600,12 +1592,11 @@ const void* ClassLinker::GetOatCodeFor(const mirror::ArtMethod* method) { return result; } -const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint32_t method_idx) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - const char* descriptor = dex_file.GetTypeDescriptor(dex_file.GetTypeId(method_id.class_idx_)); - uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, method_idx); - UniquePtr oat_class(GetOatClass(dex_file, descriptor)); - CHECK(oat_class.get() != NULL); +const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { + UniquePtr oat_class(GetOatClass(dex_file, class_def_idx)); + CHECK(oat_class.get() != nullptr); + uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx); return oat_class->GetOatMethod(oat_method_idx).GetCode(); } @@ -1642,7 +1633,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { // OAT file unavailable return; } - UniquePtr oat_class(GetOatClass(dex_file, kh.GetDescriptor())); + UniquePtr oat_class(GetOatClass(dex_file, klass->GetDexClassDefIndex())); CHECK(oat_class.get() != NULL); ClassDataItemIterator it(dex_file, class_data); // Skip fields @@ -1734,6 +1725,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); klass->SetStatus(mirror::Class::kStatusIdx, NULL); + klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def)); klass->SetDexTypeIndex(dex_class_def.class_idx_); // Load fields fields. @@ -1781,7 +1773,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, UniquePtr oat_class; if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) { - oat_class.reset(GetOatClass(dex_file, descriptor)); + oat_class.reset(GetOatClass(dex_file, klass->GetDexClassDefIndex())); } // Load methods. @@ -1876,7 +1868,8 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged klass->SetFinalizable(); } else { - StringPiece klass_descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); + ClassHelper kh(klass.get()); + StringPiece klass_descriptor(kh.GetDescriptor()); // The Enum class declares a "final" finalize() method to prevent subclasses from // introducing a finalizer. We don't want to set the finalizable flag for Enum or its // subclasses, so we exclude it here. @@ -2342,12 +2335,16 @@ mirror::Class* ClassLinker::LookupClassFromImage(const char* descriptor) { const DexFile* dex_file = dex_cache->GetDexFile(); // First search using the class def map, but don't bother for non-class types. if (descriptor[0] == 'L') { - const DexFile::ClassDef* class_def = dex_file->FindClassDef(descriptor); - if (class_def != NULL) { - mirror::Class* klass = dex_cache->GetResolvedType(class_def->class_idx_); - if (klass != NULL) { - self->EndAssertNoThreadSuspension(old_no_suspend_cause); - return klass; + const DexFile::StringId* descriptor_string_id = dex_file->FindStringId(descriptor); + if (descriptor_string_id != NULL) { + const DexFile::TypeId* type_id = + dex_file->FindTypeId(dex_file->GetIndexForStringId(*descriptor_string_id)); + if (type_id != NULL) { + mirror::Class* klass = dex_cache->GetResolvedType(dex_file->GetIndexForTypeId(*type_id)); + if (klass != NULL) { + self->EndAssertNoThreadSuspension(old_no_suspend_cause); + return klass; + } } } } @@ -2458,8 +2455,9 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; std::string error_msg; if (!preverified) { - verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, - Runtime::Current()->IsCompiler()); + verifier_failure = verifier::MethodVerifier::VerifyClass(klass, + Runtime::Current()->IsCompiler(), + &error_msg); } if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) { @@ -2530,7 +2528,6 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class } } - const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); // Make this work with gtests, which do not set up the image properly. // TODO: we should clean up gtests to set up the image path properly. @@ -2542,9 +2539,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); const char* descriptor = ClassHelper(klass).GetDescriptor(); - uint32_t class_def_index; - bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); - CHECK(found) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + uint16_t class_def_index = klass->GetDexClassDefIndex(); UniquePtr oat_class(oat_dex_file->GetOatClass(class_def_index)); CHECK(oat_class.get() != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; @@ -2657,8 +2652,6 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, klass->SetStatus(mirror::Class::kStatusIdx, self); - klass->SetDexTypeIndex(DexFile::kDexNoIndex16); - // Instance fields are inherited, but we add a couple of static fields... { mirror::ObjectArray* sfields = AllocArtFieldArray(self, 2); @@ -3265,10 +3258,8 @@ bool ClassLinker::LinkClass(SirtRef& klass, bool ClassLinker::LoadSuperAndInterfaces(SirtRef& klass, const DexFile& dex_file) { CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus()); - StringPiece descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(descriptor); - CHECK(class_def != NULL); - uint16_t super_class_idx = class_def->superclass_idx_; + const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex()); + uint16_t super_class_idx = class_def.superclass_idx_; if (super_class_idx != DexFile::kDexNoIndex16) { mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.get()); if (super_class == NULL) { @@ -3284,7 +3275,7 @@ bool ClassLinker::LoadSuperAndInterfaces(SirtRef& klass, const De } klass->SetSuperClass(super_class); } - const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(*class_def); + const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def); if (interfaces != NULL) { for (size_t i = 0; i < interfaces->Size(); i++) { uint16_t idx = interfaces->GetTypeItem(i).type_idx_; diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 20efbb43a9..3ffcf14447 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -329,7 +329,7 @@ class ClassLinker { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get the oat code for a method from a method index. - const void* GetOatCodeFor(const DexFile& dex_file, uint32_t method_idx) + const void* GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); pid_t GetClassesLockOwner(); // For SignalCatcher. @@ -424,7 +424,7 @@ class ClassLinker { void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Finds the associated oat class for a dex_file and descriptor - const OatFile::OatClass* GetOatClass(const DexFile& dex_file, const char* descriptor) + const OatFile::OatClass* GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void RegisterDexFileLocked(const DexFile& dex_file, SirtRef& dex_cache) diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 0fa0ffbc56..bea1139679 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -508,6 +508,7 @@ struct ClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), "numReferenceInstanceFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_), "numReferenceStaticFields")); @@ -570,10 +571,6 @@ struct ProxyOffsets : public CheckOffsets { struct ClassClassOffsets : public CheckOffsets { ClassClassOffsets() : CheckOffsets(true, "Ljava/lang/Class;") { - // padding 32-bit - CHECK_EQ(OFFSETOF_MEMBER(mirror::ClassClass, padding_) + 4, - OFFSETOF_MEMBER(mirror::ClassClass, serialVersionUID_)); - // alphabetical 64-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassClass, serialVersionUID_), "serialVersionUID")); }; @@ -585,11 +582,11 @@ struct StringClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_), "ASCII")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER")); - // padding 32-bit - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); - // alphabetical 64-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); + + // alphabetical 32-bit + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); }; }; @@ -606,6 +603,7 @@ struct ArtMethodClassOffsets : public CheckOffsets { struct DexCacheOffsets : public CheckOffsets { DexCacheOffsets() : CheckOffsets(false, "Ljava/lang/DexCache;") { // alphabetical references + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, initialized_static_storage_), "initializedStaticStorage")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields")); diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 4fd9a608c1..e81c456ccf 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -48,7 +48,7 @@ namespace art { const byte DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' }; const byte DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' }; -DexFile::ClassPathEntry DexFile::FindInClassPath(const StringPiece& descriptor, +DexFile::ClassPathEntry DexFile::FindInClassPath(const char* descriptor, const ClassPath& class_path) { for (size_t i = 0; i != class_path.size(); ++i) { const DexFile* dex_file = class_path[i]; @@ -251,56 +251,11 @@ DexFile::~DexFile() { // the global reference table is otherwise empty! } -class ScopedJniMonitorLock { - public: - ScopedJniMonitorLock(JNIEnv* env, jobject locked) : env_(env), locked_(locked) { - env->MonitorEnter(locked_); - } - ~ScopedJniMonitorLock() { - env_->MonitorExit(locked_); - } - private: - JNIEnv* const env_; - const jobject locked_; -}; - -jobject DexFile::GetDexObject(JNIEnv* env) const { - { - ScopedJniMonitorLock lock(env, WellKnownClasses::com_android_dex_Dex); - if (dex_object_ != NULL) { - return dex_object_; - } - } - void* address = const_cast(reinterpret_cast(begin_)); - jobject byte_buffer = env->NewDirectByteBuffer(address, size_); - if (byte_buffer == NULL) { - return NULL; - } - - ScopedJniMonitorLock lock(env, WellKnownClasses::com_android_dex_Dex); - // Re-test to see if someone beat us to the creation when we had the lock released. - if (dex_object_ != NULL) { - return dex_object_; - } - jvalue args[1]; - args[0].l = byte_buffer; - jobject local = env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex, - WellKnownClasses::com_android_dex_Dex_create, - args); - if (local == NULL) { - return NULL; - } - - dex_object_ = env->NewGlobalRef(local); - return dex_object_; -} - bool DexFile::Init() { InitMembers(); if (!CheckMagicAndVersion()) { return false; } - InitIndex(); return true; } @@ -351,28 +306,36 @@ uint32_t DexFile::GetVersion() const { return atoi(version); } -void DexFile::InitIndex() { - CHECK_EQ(index_.size(), 0U) << GetLocation(); - for (size_t i = 0; i < NumClassDefs(); ++i) { - const ClassDef& class_def = GetClassDef(i); - const char* descriptor = GetClassDescriptor(class_def); - index_.Put(descriptor, i); +const DexFile::ClassDef* DexFile::FindClassDef(const char* descriptor) const { + size_t num_class_defs = NumClassDefs(); + if (num_class_defs == 0) { + return NULL; } -} - -bool DexFile::FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const { - Index::const_iterator it = index_.find(descriptor); - if (it == index_.end()) { - return false; + const StringId* string_id = FindStringId(descriptor); + if (string_id == NULL) { + return NULL; } - idx = it->second; - return true; + const TypeId* type_id = FindTypeId(GetIndexForStringId(*string_id)); + if (type_id == NULL) { + return NULL; + } + uint16_t type_idx = GetIndexForTypeId(*type_id); + for (size_t i = 0; i < num_class_defs; ++i) { + const ClassDef& class_def = GetClassDef(i); + if (class_def.class_idx_ == type_idx) { + return &class_def; + } + } + return NULL; } -const DexFile::ClassDef* DexFile::FindClassDef(const StringPiece& descriptor) const { - uint32_t idx; - if (FindClassDefIndex(descriptor, idx)) { - return &GetClassDef(idx); +const DexFile::ClassDef* DexFile::FindClassDef(uint16_t type_idx) const { + size_t num_class_defs = NumClassDefs(); + for (size_t i = 0; i < num_class_defs; ++i) { + const ClassDef& class_def = GetClassDef(i); + if (class_def.class_idx_ == type_idx) { + return &class_def; + } } return NULL; } diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 26635ae255..7be5cb848f 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -339,7 +339,7 @@ class DexFile { typedef std::vector ClassPath; // Search a collection of DexFiles for a descriptor - static ClassPathEntry FindInClassPath(const StringPiece& descriptor, + static ClassPathEntry FindInClassPath(const char* descriptor, const ClassPath& class_path); // Returns the checksum of a file for comparison with GetLocationChecksum(). @@ -376,10 +376,6 @@ class DexFile { return location_checksum_; } - // Returns a com.android.dex.Dex object corresponding to the mapped-in dex file. - // Used by managed code to implement annotations. - jobject GetDexObject(JNIEnv* env) const; - const Header& GetHeader() const { DCHECK(header_ != NULL) << GetLocation(); return *header_; @@ -584,12 +580,12 @@ class DexFile { } // Returns the ClassDef at the specified index. - const ClassDef& GetClassDef(uint32_t idx) const { + const ClassDef& GetClassDef(uint16_t idx) const { DCHECK_LT(idx, NumClassDefs()) << GetLocation(); return class_defs_[idx]; } - uint32_t GetIndexForClassDef(const ClassDef& class_def) const { + uint16_t GetIndexForClassDef(const ClassDef& class_def) const { CHECK_GE(&class_def, class_defs_) << GetLocation(); CHECK_LT(&class_def, class_defs_ + header_->class_defs_size_) << GetLocation(); return &class_def - class_defs_; @@ -601,10 +597,10 @@ class DexFile { } // Looks up a class definition by its class descriptor. - const ClassDef* FindClassDef(const StringPiece& descriptor) const; + const ClassDef* FindClassDef(const char* descriptor) const; - // Looks up a class definition index by its class descriptor. - bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const; + // Looks up a class definition by its type index. + const ClassDef* FindClassDef(uint16_t type_idx) const; const TypeList* GetInterfacesList(const ClassDef& class_def) const { if (class_def.interfaces_off_ == 0) { @@ -809,6 +805,14 @@ class DexFile { bool DisableWrite() const; + const byte* Begin() const { + return begin_; + } + + size_t Size() const { + return size_; + } + private: // Opens a .dex file static const DexFile* OpenFile(const std::string& filename, @@ -840,7 +844,6 @@ class DexFile { location_(location), location_checksum_(location_checksum), mem_map_(mem_map), - dex_object_(NULL), modification_lock("DEX modification lock"), header_(0), string_ids_(0), @@ -853,23 +856,12 @@ class DexFile { CHECK_GT(size_, 0U) << GetLocation(); } - const byte* Begin() const { - return begin_; - } - - size_t Size() const { - return size_; - } - // Top-level initializer that calls other Init methods. bool Init(); // Caches pointers into to the various file sections. void InitMembers(); - // Builds the index of descriptors to class definitions. - void InitIndex(); - // Returns true if the header magic and version numbers are of the expected values. bool CheckMagicAndVersion() const; @@ -877,10 +869,6 @@ class DexFile { DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, void* context, const byte* stream, LocalInfo* local_in_reg) const; - // The index of descriptors to class definition indexes (as opposed to type id indexes) - typedef SafeMap Index; - Index index_; - // The base address of the memory mapping. const byte* const begin_; @@ -898,10 +886,6 @@ class DexFile { // Manages the underlying memory allocation. UniquePtr mem_map_; - // A cached com.android.dex.Dex instance, possibly NULL. Use GetDexObject. - // TODO: this is mutable as it shouldn't be here. We should move it to the dex cache or similar. - mutable jobject dex_object_; - // The DEX-to-DEX compiler uses this lock to ensure thread safety when // enabling write access to a read-only DEX file. // TODO: move to Locks::dex_file_modification_lock. diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc index 1d8022f803..07c1c015aa 100644 --- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc @@ -32,7 +32,7 @@ extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_me Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtMethod* method; - if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex16)) { + if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) { method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method); if (UNLIKELY(method == NULL)) { FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index 224b2ba0d4..ccf3e59f18 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -178,7 +178,7 @@ inline uint32_t ArtMethod::GetOatNativeGcMapOffset() const { } inline bool ArtMethod::IsRuntimeMethod() const { - return GetDexMethodIndex() == DexFile::kDexNoIndex16; + return GetDexMethodIndex() == DexFile::kDexNoIndex; } inline bool ArtMethod::IsCalleeSaveMethod() const { diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 328c67deb1..c128eded0a 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -119,7 +119,10 @@ void Class::SetDexCache(DexCache* new_dex_cache) { } void Class::SetClassSize(size_t new_class_size) { - DCHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); + if (kIsDebugBuild && (new_class_size < GetClassSize())) { + DumpClass(LOG(ERROR), kDumpClassFullDetail); + CHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); + } SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false); } @@ -291,22 +294,8 @@ bool Class::IsInSamePackage(const Class* that) const { return true; } // Compare the package part of the descriptor string. - if (LIKELY(!klass1->IsProxyClass() && !klass2->IsProxyClass())) { - ClassHelper kh(klass1); - const DexFile* dex_file1 = &kh.GetDexFile(); - const DexFile::TypeId* type_id1 = &dex_file1->GetTypeId(klass1->GetDexTypeIndex()); - const char* descriptor1 = dex_file1->GetTypeDescriptor(*type_id1); - kh.ChangeClass(klass2); - const DexFile* dex_file2 = &kh.GetDexFile(); - const DexFile::TypeId* type_id2 = &dex_file2->GetTypeId(klass2->GetDexTypeIndex()); - const char* descriptor2 = dex_file2->GetTypeDescriptor(*type_id2); - return IsInSamePackage(descriptor1, descriptor2); - } - ClassHelper kh(klass1); - std::string descriptor1(kh.GetDescriptor()); - kh.ChangeClass(klass2); - std::string descriptor2(kh.GetDescriptor()); - return IsInSamePackage(descriptor1, descriptor2); + return IsInSamePackage(ClassHelper(klass1).GetDescriptor(), + ClassHelper(klass2).GetDescriptor()); } bool Class::IsClassClass() const { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 99f3850b9b..d97b603ad8 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -726,6 +726,14 @@ class MANAGED Class : public StaticStorageBase { return GetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false); } + uint16_t GetDexClassDefIndex() const { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), false); + } + + void SetDexClassDefIndex(uint16_t class_def_idx) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false); + } + uint16_t GetDexTypeIndex() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), false); } @@ -807,7 +815,7 @@ class MANAGED Class : public StaticStorageBase { // If class verify fails, we must return same error on subsequent tries. Class* verify_error_class_; - // virtual methods defined in this class; invoked through vtable + // Virtual methods defined in this class; invoked through vtable. ObjectArray* virtual_methods_; // Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass is @@ -816,24 +824,28 @@ class MANAGED Class : public StaticStorageBase { // virtual_ methods_ for miranda methods. ObjectArray* vtable_; - // access flags; low 16 bits are defined by VM spec + // Access flags; low 16 bits are defined by VM spec. uint32_t access_flags_; // Total size of the Class instance; used when allocating storage on gc heap. // See also object_size_. size_t class_size_; - // tid used to check for recursive invocation + // Tid used to check for recursive invocation. pid_t clinit_thread_id_; - // type index from dex file + // ClassDef index in dex file, -1 if no class definition such as an array. + // TODO: really 16bits + int32_t dex_class_def_idx_; + + // Type index in dex file. // TODO: really 16bits - uint32_t dex_type_idx_; + int32_t dex_type_idx_; - // number of instance fields that are object refs + // Number of instance fields that are object refs. size_t num_reference_instance_fields_; - // number of static fields that are object refs + // Number of static fields that are object refs, size_t num_reference_static_fields_; // Total object size; used when allocating storage on gc heap. @@ -841,7 +853,7 @@ class MANAGED Class : public StaticStorageBase { // See also class_size_. size_t object_size_; - // primitive type value, or Primitive::kPrimNot (0); set for generated prim classes + // Primitive type value, or Primitive::kPrimNot (0); set for generated primitive classes. Primitive::Type primitive_type_; // Bitmap of offsets of ifields. @@ -850,7 +862,7 @@ class MANAGED Class : public StaticStorageBase { // Bitmap of offsets of sfields. uint32_t reference_static_offsets_; - // state of class initialization + // State of class initialization. Status status_; // TODO: ? @@ -873,7 +885,6 @@ std::ostream& operator<<(std::ostream& os, const Class::Status& rhs); class MANAGED ClassClass : public Class { private: - int32_t padding_; int64_t serialVersionUID_; friend struct art::ClassClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass); diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 6cfab9e425..0522f134af 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -164,6 +164,7 @@ class MANAGED DexCache : public Object { } private: + Object* dex_; ObjectArray* initialized_static_storage_; String* location_; ObjectArray* resolved_fields_; diff --git a/runtime/mirror/proxy.h b/runtime/mirror/proxy.h index 7c5bc39429..18a84dcbdb 100644 --- a/runtime/mirror/proxy.h +++ b/runtime/mirror/proxy.h @@ -25,6 +25,8 @@ struct ProxyOffsets; namespace mirror { +// All proxy objects have a class which is a synthesized proxy class. The synthesized proxy class +// has the static fields used to implement reflection on proxy objects. class MANAGED SynthesizedProxyClass : public Class { public: ObjectArray* GetInterfaces() { @@ -41,6 +43,7 @@ class MANAGED SynthesizedProxyClass : public Class { DISALLOW_IMPLICIT_CONSTRUCTORS(SynthesizedProxyClass); }; +// C++ mirror of java.lang.reflect.Proxy. class MANAGED Proxy : public Object { private: Object* h_; diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 01d8f318ff..1879f04bef 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -156,8 +156,8 @@ class MANAGED StringClass : public Class { private: CharArray* ASCII_; Object* CASE_INSENSITIVE_ORDER_; - uint32_t REPLACEMENT_CHAR_; int64_t serialVersionUID_; + uint32_t REPLACEMENT_CHAR_; friend struct art::StringClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass); }; diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 2f4e427bb6..d2a6c0edb4 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -150,7 +150,7 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j return NULL; } const std::string descriptor(DotToDescriptor(class_name.c_str())); - const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor); + const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str()); if (dex_class_def == NULL) { VLOG(class_linker) << "Failed to find dex_class_def"; return NULL; diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index a7296996da..d3011cb013 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -78,35 +78,6 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean return soa.AddLocalReference(c); } -static jint Class_getAnnotationDirectoryOffset(JNIEnv* env, jclass javaClass) { - ScopedObjectAccess soa(env); - mirror::Class* c = DecodeClass(soa, javaClass); - if (c->IsPrimitive() || c->IsArrayClass() || c->IsProxyClass()) { - return 0; // primitive, array and proxy classes don't have class definitions - } - const DexFile::ClassDef* class_def = ClassHelper(c).GetClassDef(); - if (class_def == NULL) { - return 0; // not found - } else { - return class_def->annotations_off_; - } -} - -static jobject Class_getDex(JNIEnv* env, jobject javaClass) { - ScopedObjectAccess soa(env); - mirror::Class* c = DecodeClass(soa, javaClass); - - mirror::DexCache* dex_cache = c->GetDexCache(); - if (dex_cache == NULL) { - return NULL; - } - const DexFile* dex_file = dex_cache->GetDexFile(); - if (dex_file == NULL) { - return NULL; - } - return dex_file->GetDexObject(env); -} - static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) { ScopedObjectAccess soa(env); mirror::Class* c = DecodeClass(soa, javaThis); @@ -122,8 +93,6 @@ static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) { static JNINativeMethod gMethods[] = { NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), - NATIVE_METHOD(Class, getAnnotationDirectoryOffset, "()I"), - NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"), NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"), NATIVE_METHOD(Class, getProxyInterfaces, "()[Ljava/lang/Class;"), }; diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc new file mode 100644 index 0000000000..f8eeb2906e --- /dev/null +++ b/runtime/native/java_lang_DexCache.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 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 "dex_file.h" +#include "mirror/dex_cache.h" +#include "mirror/object-inl.h" +#include "scoped_thread_state_change.h" +#include "well_known_classes.h" + +namespace art { + +static jobject DexCache_getDexNative(JNIEnv* env, jobject javaDexCache) { + ScopedObjectAccess soa(env); + mirror::DexCache* dex_cache = soa.Decode(javaDexCache); + // Should only be called while holding the lock on the dex cache. + DCHECK_EQ(dex_cache->GetThinLockId(), soa.Self()->GetThinLockId()); + const DexFile* dex_file = dex_cache->GetDexFile(); + if (dex_file == NULL) { + return NULL; + } + void* address = const_cast(reinterpret_cast(dex_file->Begin())); + jobject byte_buffer = env->NewDirectByteBuffer(address, dex_file->Size()); + if (byte_buffer == NULL) { + DCHECK(soa.Self()->IsExceptionPending()); + return NULL; + } + + jvalue args[1]; + args[0].l = byte_buffer; + return env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex, + WellKnownClasses::com_android_dex_Dex_create, + args); +} + +static JNINativeMethod gMethods[] = { + NATIVE_METHOD(DexCache, getDexNative, "()Lcom/android/dex/Dex;"), +}; + +void register_java_lang_DexCache(JNIEnv* env) { + REGISTER_NATIVE_METHODS("java/lang/DexCache"); +} + +} // namespace art diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index afa823dbd9..4c970172b4 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -365,7 +365,7 @@ const DexFile* OatFile::OatDexFile::OpenDexFile() const { dex_file_location_checksum_); } -const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const { +const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const { uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index]; const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset; diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 325ebb2914..bbd2615b66 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -183,7 +183,7 @@ class OatFile { } // Returns the OatClass for the class specified by the given DexFile class_def_index. - const OatClass* GetOatClass(uint32_t class_def_index) const; + const OatClass* GetOatClass(uint16_t class_def_index) const; ~OatDexFile(); diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 29102437a2..6ee3016179 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -68,8 +68,7 @@ class ClassHelper { public: ClassHelper(const mirror::Class* c = NULL, ClassLinker* l = NULL) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : class_def_(NULL), - class_linker_(l), + : class_linker_(l), dex_cache_(NULL), dex_file_(NULL), interface_type_list_(NULL), @@ -92,7 +91,6 @@ class ClassHelper { } klass_ = new_c; interface_type_list_ = NULL; - class_def_ = NULL; } // The returned const char* is only guaranteed to be valid for the lifetime of the ClassHelper. @@ -108,7 +106,7 @@ class ClassHelper { return descriptor_.c_str(); } else { const DexFile& dex_file = GetDexFile(); - const DexFile::TypeId& type_id = dex_file.GetTypeId(klass_->GetDexTypeIndex()); + const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_); return dex_file.GetTypeDescriptor(type_id); } } @@ -124,14 +122,13 @@ class ClassHelper { return descriptor_.c_str(); } - const DexFile::ClassDef* GetClassDef() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile::ClassDef* result = class_def_; - if (result == NULL) { - result = GetDexFile().FindClassDef(GetDescriptor()); - class_def_ = result; + const DexFile::ClassDef* GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(klass_ != nullptr); + uint16_t class_def_idx = klass_->GetDexClassDefIndex(); + if (class_def_idx == DexFile::kDexNoIndex16) { + return nullptr; } - return result; + return &GetDexFile().GetClassDef(class_def_idx); } uint32_t NumDirectInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -187,7 +184,7 @@ class ClassHelper { const char* GetSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::string descriptor(GetDescriptor()); const DexFile& dex_file = GetDexFile(); - const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor); + const DexFile::ClassDef* dex_class_def = GetClassDef(); CHECK(dex_class_def != NULL); return dex_file.GetSourceFile(*dex_class_def); } @@ -242,7 +239,6 @@ class ClassHelper { return result; } - const DexFile::ClassDef* class_def_; ClassLinker* class_linker_; mirror::DexCache* dex_cache_; const DexFile* dex_file_; @@ -327,12 +323,15 @@ class FieldHelper { // If you need it longer, copy it into a std::string. const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint16_t type_idx = field_->GetDeclaringClass()->GetDexTypeIndex(); - if (type_idx != DexFile::kDexNoIndex16) { + uint32_t field_index = field_->GetDexFieldIndex(); + if (!field_->GetDeclaringClass()->IsProxyClass()) { const DexFile& dex_file = GetDexFile(); - return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + return dex_file.GetFieldDeclaringClassDescriptor(field_id); } else { - // Most likely a proxy class. + DCHECK(field_->IsStatic()); + DCHECK_LT(field_index, 2U); + // 0 == Class[] interfaces; 1 == Class[][] throws; ClassHelper kh(field_->GetDeclaringClass()); declaring_class_descriptor_ = kh.GetDescriptor(); return declaring_class_descriptor_.c_str(); @@ -418,7 +417,7 @@ class MethodHelper { const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex16) { + if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); } else { Runtime* runtime = Runtime::Current(); @@ -464,21 +463,19 @@ class MethodHelper { const std::string GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex16) { + if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx)); } else { return ""; } } - const DexFile::ProtoId& GetPrototype() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::ProtoId& GetPrototype() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); return dex_file.GetMethodPrototype(dex_file.GetMethodId(method_->GetDexMethodIndex())); } - const DexFile::TypeList* GetParameterTypeList() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::TypeList* GetParameterTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile::ProtoId& proto = GetPrototype(); return GetDexFile().GetProtoParameters(proto); } @@ -491,8 +488,7 @@ class MethodHelper { return GetClassFromTypeIdx(return_type_idx); } - const char* GetReturnTypeDescriptor() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const char* GetReturnTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex()); const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(method_id); @@ -500,8 +496,7 @@ class MethodHelper { return dex_file.GetTypeDescriptor(dex_file.GetTypeId(return_type_idx)); } - int32_t GetLineNumFromDexPC(uint32_t dex_pc) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + int32_t GetLineNumFromDexPC(uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (dex_pc == DexFile::kDexNoIndex) { return method_->IsNative() ? -2 : -1; } else { @@ -510,35 +505,29 @@ class MethodHelper { } } - const char* GetDeclaringClassDescriptor() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::Class* klass = method_->GetDeclaringClass(); - DCHECK(!klass->IsProxyClass()); - uint16_t type_idx = klass->GetDexTypeIndex(); + const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); - return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)); + uint32_t dex_method_idx = method_->GetDexMethodIndex(); + if (dex_method_idx != DexFile::kDexNoIndex) { + return dex_file.GetMethodDeclaringClassDescriptor(dex_file.GetMethodId(dex_method_idx)); + } else { + return ""; + } } - const char* GetDeclaringClassSourceFile() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* descriptor = GetDeclaringClassDescriptor(); - const DexFile& dex_file = GetDexFile(); - const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor); - CHECK(dex_class_def != NULL); - return dex_file.GetSourceFile(*dex_class_def); + const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return ClassHelper(method_->GetDeclaringClass()).GetSourceFile(); } - uint32_t GetClassDefIndex() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* descriptor = GetDeclaringClassDescriptor(); - const DexFile& dex_file = GetDexFile(); - uint32_t index; - CHECK(dex_file.FindClassDefIndex(descriptor, index)); - return index; + uint16_t GetClassDefIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return method_->GetDeclaringClass()->GetDexClassDefIndex(); } - mirror::ClassLoader* GetClassLoader() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::ClassDef& GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetDexFile().GetClassDef(GetClassDefIndex()); + } + + mirror::ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return method_->GetDeclaringClass()->GetClassLoader(); } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index c37b7830c8..05f4566d85 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1007,6 +1007,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { REGISTER(register_dalvik_system_VMStack); REGISTER(register_dalvik_system_Zygote); REGISTER(register_java_lang_Class); + REGISTER(register_java_lang_DexCache); REGISTER(register_java_lang_Object); REGISTER(register_java_lang_Runtime); REGISTER(register_java_lang_String); @@ -1175,7 +1176,7 @@ mirror::ArtMethod* Runtime::CreateResolutionMethod() { method(self, down_cast(method_class->AllocObject(self))); method->SetDeclaringClass(method_class); // TODO: use a special method for resolution method saves - method->SetDexMethodIndex(DexFile::kDexNoIndex16); + method->SetDexMethodIndex(DexFile::kDexNoIndex); // When compiling, the code pointer will get set later when the image is loaded. Runtime* r = Runtime::Current(); ClassLinker* cl = r->GetClassLinker(); @@ -1191,7 +1192,7 @@ mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_se method(self, down_cast(method_class->AllocObject(self))); method->SetDeclaringClass(method_class); // TODO: use a special method for callee saves - method->SetDexMethodIndex(DexFile::kDexNoIndex16); + method->SetDexMethodIndex(DexFile::kDexNoIndex); method->SetEntryPointFromCompiledCode(NULL); if ((instruction_set == kThumb2) || (instruction_set == kArm)) { uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6) | (1 << art::arm::R7) | diff --git a/runtime/thread.cc b/runtime/thread.cc index d7d4b1fa97..68370508d3 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1816,7 +1816,7 @@ class CatchBlockStackVisitor : public StackVisitor { uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits(); ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, m, new_dex_pc); verifier::MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), code_item, + &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); verifier.Verify(); std::vector kinds = verifier.DescribeVRegs(dex_pc); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index fa00c61017..9811926b16 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -74,50 +74,51 @@ void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* fl } MethodVerifier::FailureKind MethodVerifier::VerifyClass(const mirror::Class* klass, - std::string& error, - bool allow_soft_failures) { + bool allow_soft_failures, + std::string* error) { if (klass->IsVerified()) { return kNoFailure; } mirror::Class* super = klass->GetSuperClass(); if (super == NULL && StringPiece(ClassHelper(klass).GetDescriptor()) != "Ljava/lang/Object;") { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that has no super class"; + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that has no super class"; return kHardFailure; } if (super != NULL && super->IsFinal()) { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that attempts to sub-class final class "; - error += PrettyDescriptor(super); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that attempts to sub-class final class "; + *error += PrettyDescriptor(super); return kHardFailure; } ClassHelper kh(klass); const DexFile& dex_file = kh.GetDexFile(); - uint32_t class_def_idx; - if (!dex_file.FindClassDefIndex(kh.GetDescriptor(), class_def_idx)) { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that isn't present in dex file "; - error += dex_file.GetLocation(); + const DexFile::ClassDef* class_def = kh.GetClassDef(); + if (class_def == NULL) { + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that isn't present in dex file "; + *error += dex_file.GetLocation(); return kHardFailure; } return VerifyClass(&dex_file, kh.GetDexCache(), klass->GetClassLoader(), - class_def_idx, error, - allow_soft_failures); + class_def, + allow_soft_failures, + error); } MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, - std::string& error, - bool allow_soft_failures) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); - const byte* class_data = dex_file->GetClassData(class_def); + const DexFile::ClassDef* class_def, + bool allow_soft_failures, + std::string* error) { + DCHECK(class_def != nullptr); + const byte* class_data = dex_file->GetClassData(*class_def); if (class_data == NULL) { // empty class, probably a marker interface return kNoFailure; @@ -139,7 +140,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, continue; } previous_direct_method_idx = method_idx; - InvokeType type = it.GetMethodInvokeType(class_def); + InvokeType type = it.GetMethodInvokeType(*class_def); mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type); if (method == NULL) { @@ -151,7 +152,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, dex_file, dex_cache, class_loader, - class_def_idx, + class_def, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), @@ -160,12 +161,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, if (result == kHardFailure) { hard_fail = true; if (error_count > 0) { - error += "\n"; + *error += "\n"; } - error = "Verifier rejected class "; - error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - error += " due to bad method "; - error += PrettyMethod(method_idx, *dex_file); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def)); + *error += " due to bad method "; + *error += PrettyMethod(method_idx, *dex_file); } ++error_count; } @@ -181,7 +182,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, continue; } previous_virtual_method_idx = method_idx; - InvokeType type = it.GetMethodInvokeType(class_def); + InvokeType type = it.GetMethodInvokeType(*class_def); mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type); if (method == NULL) { @@ -193,7 +194,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, dex_file, dex_cache, class_loader, - class_def_idx, + class_def, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), @@ -202,12 +203,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, if (result == kHardFailure) { hard_fail = true; if (error_count > 0) { - error += "\n"; + *error += "\n"; } - error = "Verifier rejected class "; - error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - error += " due to bad method "; - error += PrettyMethod(method_idx, *dex_file); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def)); + *error += " due to bad method "; + *error += PrettyMethod(method_idx, *dex_file); } ++error_count; } @@ -224,7 +225,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, @@ -232,7 +233,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, MethodVerifier::FailureKind result = kNoFailure; uint64_t start_ns = NanoTime(); - MethodVerifier verifier_(dex_file, dex_cache, class_loader, class_def_idx, code_item, method_idx, + MethodVerifier verifier_(dex_file, dex_cache, class_loader, class_def, code_item, method_idx, method, method_access_flags, true, allow_soft_failures); if (verifier_.Verify()) { // Verification completed, however failures may be pending that didn't cause the verification @@ -267,11 +268,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags) { - MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, + MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def, code_item, dex_method_idx, method, method_access_flags, true, true); verifier.Verify(); verifier.DumpFailures(os); @@ -280,7 +282,8 @@ void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_i } MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t dex_method_idx, mirror::ArtMethod* method, uint32_t method_access_flags, bool can_load_classes, @@ -293,7 +296,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca dex_file_(dex_file), dex_cache_(dex_cache), class_loader_(class_loader), - class_def_idx_(class_def_idx), + class_def_(class_def), code_item_(code_item), declaring_class_(NULL), interesting_dex_pc_(-1), @@ -306,13 +309,14 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca allow_soft_failures_(allow_soft_failures), has_check_casts_(false), has_virtual_or_interface_invokes_(false) { + DCHECK(class_def != NULL); } void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc, std::vector& monitor_enter_dex_pcs) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); verifier.interesting_dex_pc_ = dex_pc; verifier.monitor_enter_dex_pcs_ = &monitor_enter_dex_pcs; @@ -334,7 +338,7 @@ mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); return verifier.FindAccessedFieldAtDexPc(dex_pc); } @@ -362,7 +366,7 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m uint32_t dex_pc) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); return verifier.FindInvokedMethodAtDexPc(dex_pc); } @@ -448,7 +452,7 @@ std::ostream& MethodVerifier::Fail(VerifyError error) { // marked as rejected to prevent it from being compiled. case VERIFY_ERROR_BAD_CLASS_HARD: { if (Runtime::Current()->IsCompiler()) { - ClassReference ref(dex_file_, class_def_idx_); + ClassReference ref(dex_file_, dex_file_->GetIndexForClassDef(*class_def_)); AddRejectedClass(ref); } have_pending_hard_failure_ = true; diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 70442fbc04..073a2f76be 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -145,17 +145,19 @@ class MethodVerifier { }; /* Verify a class. Returns "kNoFailure" on success. */ - static FailureKind VerifyClass(const mirror::Class* klass, std::string& error, - bool allow_soft_failures) + static FailureKind VerifyClass(const mirror::Class* klass, bool allow_soft_failures, + std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static FailureKind VerifyClass(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, - std::string& error, bool allow_soft_failures) + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, + bool allow_soft_failures, std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void VerifyMethodAndDump(std::ostream& os, uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef* class_def, + const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -222,7 +224,7 @@ class MethodVerifier { } MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t method_idx, mirror::ArtMethod* method, uint32_t access_flags, bool can_load_classes, bool allow_soft_failures) @@ -262,7 +264,8 @@ class MethodVerifier { */ static FailureKind VerifyMethod(uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def_idx, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, bool allow_soft_failures) @@ -690,7 +693,7 @@ class MethodVerifier { mirror::DexCache* dex_cache_ GUARDED_BY(Locks::mutator_lock_); // The class loader for the declaring class of the method. mirror::ClassLoader* class_loader_ GUARDED_BY(Locks::mutator_lock_); - const uint32_t class_def_idx_; // The class def index of the declaring class of the method. + const DexFile::ClassDef* const class_def_; // The class def of the declaring class of the method. const DexFile::CodeItem* const code_item_; // The code item containing the code for the method. const RegType* declaring_class_; // Lazily computed reg type of the method's declaring class. // Instruction widths and flags, one entry per code unit. diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index 611b7c06eb..a56abba3cf 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -34,7 +34,8 @@ class MethodVerifierTest : public CommonTest { // Verify the class std::string error_msg; - ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg, true) == MethodVerifier::kNoFailure) << error_msg; + ASSERT_TRUE(MethodVerifier::VerifyClass(klass, true, &error_msg) == MethodVerifier::kNoFailure) + << error_msg; } void VerifyDexFile(const DexFile* dex) diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 3d87ebc559..967f167f37 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -35,7 +35,7 @@ z (class java.lang.Character) 62 (class java.lang.Long) 14 (class java.lang.Short) [public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)] -[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID] +[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final long java.lang.String.serialVersionUID, private static final char java.lang.String.REPLACEMENT_CHAR] [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] -- cgit v1.2.3-59-g8ed1b