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 "throwable.h" 18 19 #include "android-base/stringprintf.h" 20 21 #include "art_method-inl.h" 22 #include "base/enums.h" 23 #include "class-inl.h" 24 #include "dex_file-inl.h" 25 #include "gc/accounting/card_table-inl.h" 26 #include "object-inl.h" 27 #include "object_array.h" 28 #include "object_array-inl.h" 29 #include "stack_trace_element.h" 30 #include "utils.h" 31 #include "well_known_classes.h" 32 33 namespace art { 34 namespace mirror { 35 36 using android::base::StringPrintf; 37 38 GcRoot<Class> Throwable::java_lang_Throwable_; 39 40 void Throwable::SetDetailMessage(ObjPtr<String> new_detail_message) { 41 if (Runtime::Current()->IsActiveTransaction()) { 42 SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message); 43 } else { 44 SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), 45 new_detail_message); 46 } 47 } 48 49 void Throwable::SetCause(ObjPtr<Throwable> cause) { 50 CHECK(cause != nullptr); 51 CHECK(cause != this); 52 Throwable* current_cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_)); 53 CHECK(current_cause == nullptr || current_cause == this); 54 if (Runtime::Current()->IsActiveTransaction()) { 55 SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause); 56 } else { 57 SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause); 58 } 59 } 60 61 void Throwable::SetStackState(ObjPtr<Object> state) REQUIRES_SHARED(Locks::mutator_lock_) { 62 CHECK(state != nullptr); 63 if (Runtime::Current()->IsActiveTransaction()) { 64 SetFieldObjectVolatile<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_), state); 65 } else { 66 SetFieldObjectVolatile<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_), state); 67 } 68 } 69 70 bool Throwable::IsCheckedException() { 71 if (InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Error))) { 72 return false; 73 } 74 return !InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_RuntimeException)); 75 } 76 77 int32_t Throwable::GetStackDepth() { 78 ObjPtr<Object> stack_state = GetStackState(); 79 if (stack_state == nullptr || !stack_state->IsObjectArray()) { 80 return -1; 81 } 82 ObjPtr<mirror::ObjectArray<Object>> const trace = stack_state->AsObjectArray<Object>(); 83 const int32_t array_len = trace->GetLength(); 84 DCHECK_GT(array_len, 0); 85 // See method BuildInternalStackTraceVisitor::Init for the format. 86 return array_len - 1; 87 } 88 89 std::string Throwable::Dump() { 90 std::string result(PrettyTypeOf()); 91 result += ": "; 92 ObjPtr<String> msg = GetDetailMessage(); 93 if (msg != nullptr) { 94 result += msg->ToModifiedUtf8(); 95 } 96 result += "\n"; 97 ObjPtr<Object> stack_state = GetStackState(); 98 // check stack state isn't missing or corrupt 99 if (stack_state != nullptr && stack_state->IsObjectArray()) { 100 ObjPtr<ObjectArray<Object>> object_array = stack_state->AsObjectArray<Object>(); 101 // Decode the internal stack trace into the depth and method trace 102 // See method BuildInternalStackTraceVisitor::Init for the format. 103 DCHECK_GT(object_array->GetLength(), 0); 104 ObjPtr<Object> methods_and_dex_pcs = object_array->Get(0); 105 DCHECK(methods_and_dex_pcs->IsIntArray() || methods_and_dex_pcs->IsLongArray()); 106 ObjPtr<PointerArray> method_trace = ObjPtr<PointerArray>::DownCast(methods_and_dex_pcs); 107 const int32_t array_len = method_trace->GetLength(); 108 CHECK_EQ(array_len % 2, 0); 109 const auto depth = array_len / 2; 110 if (depth == 0) { 111 result += "(Throwable with empty stack trace)\n"; 112 } else { 113 const PointerSize ptr_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); 114 for (int32_t i = 0; i < depth; ++i) { 115 ArtMethod* method = method_trace->GetElementPtrSize<ArtMethod*>(i, ptr_size); 116 uintptr_t dex_pc = method_trace->GetElementPtrSize<uintptr_t>(i + depth, ptr_size); 117 int32_t line_number = method->GetLineNumFromDexPC(dex_pc); 118 const char* source_file = method->GetDeclaringClassSourceFile(); 119 result += StringPrintf(" at %s (%s:%d)\n", method->PrettyMethod(true).c_str(), 120 source_file, line_number); 121 } 122 } 123 } else { 124 ObjPtr<Object> stack_trace = GetStackTrace(); 125 if (stack_trace != nullptr && stack_trace->IsObjectArray()) { 126 CHECK_EQ(stack_trace->GetClass()->GetComponentType(), 127 StackTraceElement::GetStackTraceElement()); 128 ObjPtr<ObjectArray<StackTraceElement>> ste_array = 129 ObjPtr<ObjectArray<StackTraceElement>>::DownCast(stack_trace); 130 if (ste_array->GetLength() == 0) { 131 result += "(Throwable with empty stack trace)\n"; 132 } else { 133 for (int32_t i = 0; i < ste_array->GetLength(); ++i) { 134 StackTraceElement* ste = ste_array->Get(i); 135 DCHECK(ste != nullptr); 136 auto* method_name = ste->GetMethodName(); 137 auto* file_name = ste->GetFileName(); 138 result += StringPrintf( 139 " at %s (%s:%d)\n", 140 method_name != nullptr ? method_name->ToModifiedUtf8().c_str() : "<unknown method>", 141 file_name != nullptr ? file_name->ToModifiedUtf8().c_str() : "(Unknown Source)", 142 ste->GetLineNumber()); 143 } 144 } 145 } else { 146 result += "(Throwable with no stack trace)\n"; 147 } 148 } 149 ObjPtr<Throwable> cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_)); 150 if (cause != nullptr && cause != this) { // Constructor makes cause == this by default. 151 result += "Caused by: "; 152 result += cause->Dump(); 153 } 154 return result; 155 } 156 157 void Throwable::SetClass(ObjPtr<Class> java_lang_Throwable) { 158 CHECK(java_lang_Throwable_.IsNull()); 159 CHECK(java_lang_Throwable != nullptr); 160 java_lang_Throwable_ = GcRoot<Class>(java_lang_Throwable); 161 } 162 163 void Throwable::ResetClass() { 164 CHECK(!java_lang_Throwable_.IsNull()); 165 java_lang_Throwable_ = GcRoot<Class>(nullptr); 166 } 167 168 void Throwable::VisitRoots(RootVisitor* visitor) { 169 java_lang_Throwable_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); 170 } 171 172 } // namespace mirror 173 } // namespace art 174