exception_test.cc revision 0571d357843c53e042f370f5f2c2e9aa3fe803a9
1// Copyright 2011 Google Inc. All Rights Reserved. 2 3#include <sys/mman.h> 4 5#include "UniquePtr.h" 6#include "assembler.h" 7#include "class_linker.h" 8#include "common_test.h" 9#include "dex_file.h" 10#include "gtest/gtest.h" 11#include "jni_compiler.h" 12#include "runtime.h" 13#include "thread.h" 14 15namespace art { 16 17class ExceptionTest : public CommonTest { 18 protected: 19 virtual void SetUp() { 20 CommonTest::SetUp(); 21 22 SirtRef<ClassLoader> class_loader(LoadDex("ExceptionHandle")); 23 my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader.get()); 24 ASSERT_TRUE(my_klass_ != NULL); 25 26 dex_ = &Runtime::Current()->GetClassLinker()->FindDexFile(my_klass_->GetDexCache()); 27 28 for (size_t i = 0 ; i < 12; i++) { 29 fake_code_.push_back(0x70000000 | i); 30 } 31 32 fake_mapping_data_.push_back(2); // first element is count of remaining elements 33 fake_mapping_data_.push_back(3); // offset 3 34 fake_mapping_data_.push_back(3); // maps to dex offset 3 35 36 method_f_ = my_klass_->FindVirtualMethod("f", "()I"); 37 ASSERT_TRUE(method_f_ != NULL); 38 method_f_->SetFrameSizeInBytes(kStackAlignment); 39 method_f_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2)); 40 method_f_->SetMappingTable(&fake_mapping_data_[0]); 41 42 method_g_ = my_klass_->FindVirtualMethod("g", "(I)V"); 43 ASSERT_TRUE(method_g_ != NULL); 44 method_g_->SetFrameSizeInBytes(kStackAlignment); 45 method_g_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2)); 46 method_g_->SetMappingTable(&fake_mapping_data_[0]); 47 } 48 49 const DexFile* dex_; 50 51 std::vector<uint8_t> fake_code_; 52 std::vector<uint32_t> fake_mapping_data_; 53 54 Method* method_f_; 55 Method* method_g_; 56 57 private: 58 Class* my_klass_; 59}; 60 61TEST_F(ExceptionTest, FindCatchHandler) { 62 const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset()); 63 64 ASSERT_TRUE(code_item != NULL); 65 66 ASSERT_EQ(2u, code_item->tries_size_); 67 ASSERT_NE(0u, code_item->insns_size_in_code_units_); 68 69 const struct DexFile::TryItem *t0, *t1; 70 t0 = dex_->GetTryItems(*code_item, 0); 71 t1 = dex_->GetTryItems(*code_item, 1); 72 EXPECT_LE(t0->start_addr_, t1->start_addr_); 73 { 74 CatchHandlerIterator iter(*code_item, 4 /* Dex PC in the first try block */); 75 EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); 76 ASSERT_TRUE(iter.HasNext()); 77 iter.Next(); 78 EXPECT_STREQ("Ljava/lang/Exception;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); 79 ASSERT_TRUE(iter.HasNext()); 80 iter.Next(); 81 EXPECT_FALSE(iter.HasNext()); 82 } 83 { 84 CatchHandlerIterator iter(*code_item, 8 /* Dex PC in the second try block */); 85 EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); 86 ASSERT_TRUE(iter.HasNext()); 87 iter.Next(); 88 EXPECT_FALSE(iter.HasNext()); 89 } 90 { 91 CatchHandlerIterator iter(*code_item, 11 /* Dex PC not in any try block */); 92 EXPECT_FALSE(iter.HasNext()); 93 } 94} 95 96TEST_F(ExceptionTest, StackTraceElement) { 97 runtime_->Start(); 98 99 std::vector<uintptr_t> fake_stack; 100 ASSERT_EQ(kStackAlignment, 16); 101 ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t)); 102 103 // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code 104 // to dex pc 3, however, we set the return pc to 5 as the stack walker always subtracts two 105 // from a return pc. 106 const uintptr_t pc_offset = 3 + 2; 107 108 // Create/push fake 16byte stack frame for method g 109 fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_)); 110 fake_stack.push_back(0); 111 fake_stack.push_back(0); 112 fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_->GetCode()) + pc_offset); // return pc 113 114 // Create/push fake 16byte stack frame for method f 115 fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_)); 116 fake_stack.push_back(0); 117 fake_stack.push_back(0); 118 fake_stack.push_back(0xEBAD6070); // return pc 119 120 // Pull Method* of NULL to terminate the trace 121 fake_stack.push_back(NULL); 122 123 // Set up thread to appear as if we called out of method_g_ at pc 3 124 Thread* thread = Thread::Current(); 125 thread->SetTopOfStack(&fake_stack[0], reinterpret_cast<uintptr_t>(method_g_->GetCode()) + pc_offset); // return pc 126 127 JNIEnv* env = thread->GetJniEnv(); 128 jobject internal = thread->CreateInternalStackTrace(env); 129 jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(env, internal); 130 ObjectArray<StackTraceElement>* trace_array = 131 Decode<ObjectArray<StackTraceElement>*>(env, ste_array); 132 133 ASSERT_TRUE(trace_array->Get(0) != NULL); 134 EXPECT_STREQ("ExceptionHandle", 135 trace_array->Get(0)->GetDeclaringClass()->ToModifiedUtf8().c_str()); 136 EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(0)->GetFileName()->ToModifiedUtf8().c_str()); 137 EXPECT_STREQ("g", trace_array->Get(0)->GetMethodName()->ToModifiedUtf8().c_str()); 138 EXPECT_EQ(22, trace_array->Get(0)->GetLineNumber()); 139 140 ASSERT_TRUE(trace_array->Get(1) != NULL); 141 EXPECT_STREQ("ExceptionHandle", 142 trace_array->Get(1)->GetDeclaringClass()->ToModifiedUtf8().c_str()); 143 EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(1)->GetFileName()->ToModifiedUtf8().c_str()); 144 EXPECT_STREQ("f", trace_array->Get(1)->GetMethodName()->ToModifiedUtf8().c_str()); 145 EXPECT_EQ(7, trace_array->Get(1)->GetLineNumber()); 146} 147 148} // namespace art 149