exception_test.cc revision f8bbb8448c733e9e3ad43aad69774c37888329b1
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <sys/mman.h> 18 19#include "UniquePtr.h" 20#include "assembler.h" 21#include "class_linker.h" 22#include "common_test.h" 23#include "dex_file.h" 24#include "gtest/gtest.h" 25#include "runtime.h" 26#include "thread.h" 27 28namespace art { 29 30class ExceptionTest : public CommonTest { 31 protected: 32 virtual void SetUp() { 33 CommonTest::SetUp(); 34 35 SirtRef<ClassLoader> class_loader(LoadDex("ExceptionHandle")); 36 my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader.get()); 37 ASSERT_TRUE(my_klass_ != NULL); 38 39 dex_ = &Runtime::Current()->GetClassLinker()->FindDexFile(my_klass_->GetDexCache()); 40 41 uint32_t code_size = 12; 42 fake_code_.push_back((code_size >> 24) & 0xFF); 43 fake_code_.push_back((code_size >> 16) & 0xFF); 44 fake_code_.push_back((code_size >> 8) & 0xFF); 45 fake_code_.push_back((code_size >> 0) & 0xFF); 46 for (size_t i = 0 ; i < code_size; i++) { 47 fake_code_.push_back(0x70 | i); 48 } 49 50 fake_mapping_data_.push_back(2); // first element is count of remaining elements 51 fake_mapping_data_.push_back(3); // offset 3 52 fake_mapping_data_.push_back(3); // maps to dex offset 3 53 54 method_f_ = my_klass_->FindVirtualMethod("f", "()I"); 55 ASSERT_TRUE(method_f_ != NULL); 56 method_f_->SetFrameSizeInBytes(kStackAlignment); 57 method_f_->SetCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); 58 method_f_->SetMappingTable(&fake_mapping_data_[0]); 59 60 method_g_ = my_klass_->FindVirtualMethod("g", "(I)V"); 61 ASSERT_TRUE(method_g_ != NULL); 62 method_g_->SetFrameSizeInBytes(kStackAlignment); 63 method_g_->SetCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); 64 method_g_->SetMappingTable(&fake_mapping_data_[0]); 65 } 66 67 const DexFile* dex_; 68 69 std::vector<uint8_t> fake_code_; 70 std::vector<uint32_t> fake_mapping_data_; 71 72 Method* method_f_; 73 Method* method_g_; 74 75 private: 76 Class* my_klass_; 77}; 78 79TEST_F(ExceptionTest, FindCatchHandler) { 80 const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset()); 81 82 ASSERT_TRUE(code_item != NULL); 83 84 ASSERT_EQ(2u, code_item->tries_size_); 85 ASSERT_NE(0u, code_item->insns_size_in_code_units_); 86 87 const struct DexFile::TryItem *t0, *t1; 88 t0 = dex_->GetTryItems(*code_item, 0); 89 t1 = dex_->GetTryItems(*code_item, 1); 90 EXPECT_LE(t0->start_addr_, t1->start_addr_); 91 { 92 CatchHandlerIterator iter(*code_item, 4 /* Dex PC in the first try block */); 93 EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); 94 ASSERT_TRUE(iter.HasNext()); 95 iter.Next(); 96 EXPECT_STREQ("Ljava/lang/Exception;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); 97 ASSERT_TRUE(iter.HasNext()); 98 iter.Next(); 99 EXPECT_FALSE(iter.HasNext()); 100 } 101 { 102 CatchHandlerIterator iter(*code_item, 8 /* Dex PC in the second try block */); 103 EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); 104 ASSERT_TRUE(iter.HasNext()); 105 iter.Next(); 106 EXPECT_FALSE(iter.HasNext()); 107 } 108 { 109 CatchHandlerIterator iter(*code_item, 11 /* Dex PC not in any try block */); 110 EXPECT_FALSE(iter.HasNext()); 111 } 112} 113 114TEST_F(ExceptionTest, StackTraceElement) { 115 runtime_->Start(); 116 117 std::vector<uintptr_t> fake_stack; 118 ASSERT_EQ(kStackAlignment, 16); 119 ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t)); 120 121 // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code 122 // to dex pc 3, however, we set the return pc to 5 as the stack walker always subtracts two 123 // from a return pc. 124 const uintptr_t pc_offset = 3 + 2; 125 126 // Create/push fake 16byte stack frame for method g 127 fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_)); 128 fake_stack.push_back(0); 129 fake_stack.push_back(0); 130 fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_->GetCode()) + pc_offset); // return pc 131 132 // Create/push fake 16byte stack frame for method f 133 fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_)); 134 fake_stack.push_back(0); 135 fake_stack.push_back(0); 136 fake_stack.push_back(0xEBAD6070); // return pc 137 138 // Pull Method* of NULL to terminate the trace 139 fake_stack.push_back(0); 140 141 // Set up thread to appear as if we called out of method_g_ at pc 3 142 Thread* thread = Thread::Current(); 143 thread->SetTopOfStack(&fake_stack[0], reinterpret_cast<uintptr_t>(method_g_->GetCode()) + pc_offset); // return pc 144 145 JNIEnv* env = thread->GetJniEnv(); 146 jobject internal = thread->CreateInternalStackTrace(env); 147 ASSERT_TRUE(internal != NULL); 148 jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(env, internal); 149 ASSERT_TRUE(ste_array != NULL); 150 ObjectArray<StackTraceElement>* trace_array = 151 Decode<ObjectArray<StackTraceElement>*>(env, ste_array); 152 153 ASSERT_TRUE(trace_array != NULL); 154 ASSERT_TRUE(trace_array->Get(0) != NULL); 155 EXPECT_STREQ("ExceptionHandle", 156 trace_array->Get(0)->GetDeclaringClass()->ToModifiedUtf8().c_str()); 157 EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(0)->GetFileName()->ToModifiedUtf8().c_str()); 158 EXPECT_STREQ("g", trace_array->Get(0)->GetMethodName()->ToModifiedUtf8().c_str()); 159 EXPECT_EQ(37, trace_array->Get(0)->GetLineNumber()); 160 161 ASSERT_TRUE(trace_array->Get(1) != NULL); 162 EXPECT_STREQ("ExceptionHandle", 163 trace_array->Get(1)->GetDeclaringClass()->ToModifiedUtf8().c_str()); 164 EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(1)->GetFileName()->ToModifiedUtf8().c_str()); 165 EXPECT_STREQ("f", trace_array->Get(1)->GetMethodName()->ToModifiedUtf8().c_str()); 166 EXPECT_EQ(22, trace_array->Get(1)->GetLineNumber()); 167} 168 169} // namespace art 170