Elliott Hughes | 872d4ec | 2011-10-21 17:07:15 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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 | |
Brian Carlstrom | fc0e321 | 2013-07-17 14:40:12 -0700 | [diff] [blame] | 17 | #ifndef ART_RUNTIME_DEBUGGER_H_ |
| 18 | #define ART_RUNTIME_DEBUGGER_H_ |
Elliott Hughes | 872d4ec | 2011-10-21 17:07:15 -0700 | [diff] [blame] | 19 | |
| 20 | #include <pthread.h> |
| 21 | |
Sebastien Hertz | 61b7f1b | 2013-11-15 15:59:30 +0100 | [diff] [blame] | 22 | #include <set> |
Elliott Hughes | 3bb8156 | 2011-10-21 18:52:59 -0700 | [diff] [blame] | 23 | #include <string> |
Sebastien Hertz | 4d25df3 | 2014-03-21 17:44:46 +0100 | [diff] [blame] | 24 | #include <vector> |
Elliott Hughes | 3bb8156 | 2011-10-21 18:52:59 -0700 | [diff] [blame] | 25 | |
Alex Light | fc58809 | 2020-01-23 15:39:08 -0800 | [diff] [blame] | 26 | #include "art_method.h" |
Alex Light | 8c2b929 | 2017-11-09 13:21:01 -0800 | [diff] [blame] | 27 | #include "base/array_ref.h" |
Alex Light | fc58809 | 2020-01-23 15:39:08 -0800 | [diff] [blame] | 28 | #include "base/locks.h" |
| 29 | #include "base/logging.h" |
Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 30 | #include "jni.h" |
Mythri Alle | ab47488 | 2022-01-17 16:43:04 +0000 | [diff] [blame] | 31 | #include "runtime.h" |
Alex Light | 2161193 | 2017-09-26 13:07:39 -0700 | [diff] [blame] | 32 | #include "runtime_callbacks.h" |
Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 33 | #include "thread.h" |
Jeff Hao | 920af3e | 2013-08-28 15:46:38 -0700 | [diff] [blame] | 34 | #include "thread_state.h" |
Elliott Hughes | 872d4ec | 2011-10-21 17:07:15 -0700 | [diff] [blame] | 35 | |
| 36 | namespace art { |
Sebastien Hertz | 4d25df3 | 2014-03-21 17:44:46 +0100 | [diff] [blame] | 37 | |
Elliott Hughes | 872d4ec | 2011-10-21 17:07:15 -0700 | [diff] [blame] | 38 | class Dbg { |
Elliott Hughes | ff17f1f | 2012-01-24 18:12:29 -0800 | [diff] [blame] | 39 | public: |
Elliott Hughes | 4ffd313 | 2011-10-24 12:06:42 -0700 | [diff] [blame] | 40 | static void SetJdwpAllowed(bool allowed); |
Leonard Mosescu | eb84221 | 2016-10-06 17:26:36 -0700 | [diff] [blame] | 41 | static bool IsJdwpAllowed(); |
Elliott Hughes | 4ffd313 | 2011-10-24 12:06:42 -0700 | [diff] [blame] | 42 | |
Elliott Hughes | 767a147 | 2011-10-26 18:49:02 -0700 | [diff] [blame] | 43 | // Invoked by the GC in case we need to keep DDMS informed. |
Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 44 | static void GcDidFinish() REQUIRES(!Locks::mutator_lock_); |
Elliott Hughes | 767a147 | 2011-10-26 18:49:02 -0700 | [diff] [blame] | 45 | |
Alex Light | fc58809 | 2020-01-23 15:39:08 -0800 | [diff] [blame] | 46 | static uint8_t ToJdwpThreadStatus(ThreadState state); |
Daniel Mihalyi | eb07669 | 2014-08-22 17:33:31 +0200 | [diff] [blame] | 47 | |
| 48 | // Indicates whether we need to force the use of interpreter when returning from the |
| 49 | // interpreter into the runtime. This allows to deoptimize the stack and continue |
| 50 | // execution with interpreter for debugging. |
Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 51 | static bool IsForcedInterpreterNeededForUpcall(Thread* thread, ArtMethod* m) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 52 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Alex Light | fc58809 | 2020-01-23 15:39:08 -0800 | [diff] [blame] | 53 | if (LIKELY(!thread->HasDebuggerShadowFrames())) { |
Daniel Mihalyi | eb07669 | 2014-08-22 17:33:31 +0200 | [diff] [blame] | 54 | return false; |
| 55 | } |
Alex Light | fc58809 | 2020-01-23 15:39:08 -0800 | [diff] [blame] | 56 | // If we have debugger stack frames we always need to go back to interpreter unless we are |
| 57 | // native or a proxy. |
| 58 | return m != nullptr && !m->IsProxyMethod() && !m->IsNative(); |
Daniel Mihalyi | eb07669 | 2014-08-22 17:33:31 +0200 | [diff] [blame] | 59 | } |
| 60 | |
Sebastien Hertz | 520633b | 2015-09-08 17:03:36 +0200 | [diff] [blame] | 61 | // Indicates whether we need to force the use of interpreter when handling an |
| 62 | // exception. This allows to deoptimize the stack and continue execution with |
| 63 | // the interpreter. |
| 64 | // Note: the interpreter will start by handling the exception when executing |
| 65 | // the deoptimized frames. |
| 66 | static bool IsForcedInterpreterNeededForException(Thread* thread) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 67 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Mythri Alle | ab47488 | 2022-01-17 16:43:04 +0000 | [diff] [blame] | 68 | // A quick check to avoid walking the stack. If there are no shadow frames or no method |
| 69 | // that needs to be deoptimized we can safely continue with optimized code. |
| 70 | if (LIKELY(!thread->HasDebuggerShadowFrames() && |
| 71 | Runtime::Current()->GetInstrumentation()->IsDeoptimizedMethodsEmpty())) { |
Sebastien Hertz | 520633b | 2015-09-08 17:03:36 +0200 | [diff] [blame] | 72 | return false; |
| 73 | } |
| 74 | return IsForcedInterpreterNeededForExceptionImpl(thread); |
| 75 | } |
| 76 | |
Sebastien Hertz | cbc5064 | 2015-06-01 17:33:12 +0200 | [diff] [blame] | 77 | |
Elliott Hughes | 872d4ec | 2011-10-21 17:07:15 -0700 | [diff] [blame] | 78 | /* |
| 79 | * DDM support. |
| 80 | */ |
Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 81 | static void DdmSendThreadNotification(Thread* t, uint32_t type) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 82 | REQUIRES_SHARED(Locks::mutator_lock_); |
Sebastien Hertz | 52d131d | 2014-03-13 16:17:40 +0100 | [diff] [blame] | 83 | static void DdmSetThreadNotification(bool enable) |
Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 84 | REQUIRES(!Locks::thread_list_lock_); |
Alex Light | 8c2b929 | 2017-11-09 13:21:01 -0800 | [diff] [blame] | 85 | static bool DdmHandleChunk( |
| 86 | JNIEnv* env, |
| 87 | uint32_t type, |
| 88 | const ArrayRef<const jbyte>& data, |
| 89 | /*out*/uint32_t* out_type, |
| 90 | /*out*/std::vector<uint8_t>* out_data); |
Alex Light | fc58809 | 2020-01-23 15:39:08 -0800 | [diff] [blame] | 91 | |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 92 | static void DdmConnected() REQUIRES_SHARED(Locks::mutator_lock_); |
| 93 | static void DdmDisconnected() REQUIRES_SHARED(Locks::mutator_lock_); |
Elliott Hughes | 767a147 | 2011-10-26 18:49:02 -0700 | [diff] [blame] | 94 | |
Elliott Hughes | 545a064 | 2011-11-08 19:10:03 -0800 | [diff] [blame] | 95 | /* |
Man Cao | 8c2ff64 | 2015-05-27 17:25:30 -0700 | [diff] [blame] | 96 | * Allocation tracking support. |
Elliott Hughes | 545a064 | 2011-11-08 19:10:03 -0800 | [diff] [blame] | 97 | */ |
Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 98 | static void SetAllocTrackingEnabled(bool enabled) REQUIRES(!Locks::alloc_tracker_lock_); |
Sebastien Hertz | 52d131d | 2014-03-13 16:17:40 +0100 | [diff] [blame] | 99 | static jbyteArray GetRecentAllocations() |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 100 | REQUIRES(!Locks::alloc_tracker_lock_) REQUIRES_SHARED(Locks::mutator_lock_); |
Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 101 | static void DumpRecentAllocations() REQUIRES(!Locks::alloc_tracker_lock_); |
Elliott Hughes | 545a064 | 2011-11-08 19:10:03 -0800 | [diff] [blame] | 102 | |
Elliott Hughes | 767a147 | 2011-10-26 18:49:02 -0700 | [diff] [blame] | 103 | enum HpifWhen { |
| 104 | HPIF_WHEN_NEVER = 0, |
| 105 | HPIF_WHEN_NOW = 1, |
| 106 | HPIF_WHEN_NEXT_GC = 2, |
| 107 | HPIF_WHEN_EVERY_GC = 3 |
| 108 | }; |
Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 109 | static int DdmHandleHpifChunk(HpifWhen when) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 110 | REQUIRES_SHARED(Locks::mutator_lock_); |
Elliott Hughes | 767a147 | 2011-10-26 18:49:02 -0700 | [diff] [blame] | 111 | |
| 112 | enum HpsgWhen { |
| 113 | HPSG_WHEN_NEVER = 0, |
| 114 | HPSG_WHEN_EVERY_GC = 1, |
| 115 | }; |
| 116 | enum HpsgWhat { |
| 117 | HPSG_WHAT_MERGED_OBJECTS = 0, |
| 118 | HPSG_WHAT_DISTINCT_OBJECTS = 1, |
| 119 | }; |
| 120 | static bool DdmHandleHpsgNhsgChunk(HpsgWhen when, HpsgWhat what, bool native); |
| 121 | |
Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 122 | static void DdmSendHeapInfo(HpifWhen reason) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 123 | REQUIRES_SHARED(Locks::mutator_lock_); |
Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 124 | static void DdmSendHeapSegments(bool native) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 125 | REQUIRES_SHARED(Locks::mutator_lock_); |
Elliott Hughes | 545a064 | 2011-11-08 19:10:03 -0800 | [diff] [blame] | 126 | |
Andreas Gampe | 04bbb5b | 2017-01-19 17:49:03 +0000 | [diff] [blame] | 127 | static ThreadLifecycleCallback* GetThreadLifecycleCallback() { |
| 128 | return &thread_lifecycle_callback_; |
| 129 | } |
| 130 | |
Elliott Hughes | 545a064 | 2011-11-08 19:10:03 -0800 | [diff] [blame] | 131 | private: |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 132 | static void DdmBroadcast(bool connect) REQUIRES_SHARED(Locks::mutator_lock_); |
Andreas Gampe | 04bbb5b | 2017-01-19 17:49:03 +0000 | [diff] [blame] | 133 | |
| 134 | static void PostThreadStart(Thread* t) |
| 135 | REQUIRES_SHARED(Locks::mutator_lock_); |
| 136 | static void PostThreadDeath(Thread* t) |
| 137 | REQUIRES_SHARED(Locks::mutator_lock_); |
Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 138 | static void PostThreadStartOrStop(Thread*, uint32_t) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 139 | REQUIRES_SHARED(Locks::mutator_lock_); |
Elliott Hughes | a215526 | 2011-11-16 16:26:58 -0800 | [diff] [blame] | 140 | |
Sebastien Hertz | 520633b | 2015-09-08 17:03:36 +0200 | [diff] [blame] | 141 | static bool IsForcedInterpreterNeededForExceptionImpl(Thread* thread) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 142 | REQUIRES_SHARED(Locks::mutator_lock_); |
Sebastien Hertz | 520633b | 2015-09-08 17:03:36 +0200 | [diff] [blame] | 143 | |
Andreas Gampe | 04bbb5b | 2017-01-19 17:49:03 +0000 | [diff] [blame] | 144 | class DbgThreadLifecycleCallback : public ThreadLifecycleCallback { |
| 145 | public: |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 146 | void ThreadStart(Thread* self) override REQUIRES_SHARED(Locks::mutator_lock_); |
| 147 | void ThreadDeath(Thread* self) override REQUIRES_SHARED(Locks::mutator_lock_); |
Andreas Gampe | 04bbb5b | 2017-01-19 17:49:03 +0000 | [diff] [blame] | 148 | }; |
| 149 | |
| 150 | static DbgThreadLifecycleCallback thread_lifecycle_callback_; |
| 151 | |
Ian Rogers | 719d1a3 | 2014-03-06 12:13:39 -0800 | [diff] [blame] | 152 | DISALLOW_COPY_AND_ASSIGN(Dbg); |
Elliott Hughes | 872d4ec | 2011-10-21 17:07:15 -0700 | [diff] [blame] | 153 | }; |
| 154 | |
| 155 | #define CHUNK_TYPE(_name) \ |
Elliott Hughes | 8218847 | 2011-11-07 18:11:48 -0800 | [diff] [blame] | 156 | static_cast<uint32_t>((_name)[0] << 24 | (_name)[1] << 16 | (_name)[2] << 8 | (_name)[3]) |
Elliott Hughes | 872d4ec | 2011-10-21 17:07:15 -0700 | [diff] [blame] | 157 | |
| 158 | } // namespace art |
| 159 | |
Brian Carlstrom | fc0e321 | 2013-07-17 14:40:12 -0700 | [diff] [blame] | 160 | #endif // ART_RUNTIME_DEBUGGER_H_ |