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