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