blob: bcf7c5d140ae8660d6f51946674ab3f0172b69ca [file] [log] [blame]
jeffhao725a9572012-11-13 18:20:12 -08001/*
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 "instrumentation.h"
18
19#include <sys/uio.h>
20
Elliott Hughes76160052012-12-12 16:31:20 -080021#include "base/unix_file/fd_file.h"
jeffhao725a9572012-11-13 18:20:12 -080022#include "class_linker.h"
23#include "debugger.h"
24#include "dex_cache.h"
25#if !defined(ART_USE_LLVM_COMPILER)
26#include "oat/runtime/oat_support_entrypoints.h"
27#endif
28#include "object_utils.h"
29#include "os.h"
30#include "scoped_thread_state_change.h"
31#include "thread.h"
32#include "thread_list.h"
33#include "trace.h"
34
35namespace art {
36
37static bool InstallStubsClassVisitor(Class* klass, void*)
38 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
39 Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
40 for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
41 AbstractMethod* method = klass->GetDirectMethod(i);
42 if (instrumentation->GetSavedCodeFromMap(method) == NULL) {
43 instrumentation->SaveAndUpdateCode(method);
44 }
45 }
46
47 for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
48 AbstractMethod* method = klass->GetVirtualMethod(i);
49 if (instrumentation->GetSavedCodeFromMap(method) == NULL) {
50 instrumentation->SaveAndUpdateCode(method);
51 }
52 }
53 return true;
54}
55
56static bool UninstallStubsClassVisitor(Class* klass, void*)
57 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
58 Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
59 for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
60 AbstractMethod* method = klass->GetDirectMethod(i);
61 if (instrumentation->GetSavedCodeFromMap(method) != NULL) {
62 instrumentation->ResetSavedCode(method);
63 }
64 }
65
66 for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
67 AbstractMethod* method = klass->GetVirtualMethod(i);
68 if (instrumentation->GetSavedCodeFromMap(method) != NULL) {
69 instrumentation->ResetSavedCode(method);
70 }
71 }
72 return true;
73}
74
Ian Rogers306057f2012-11-26 12:45:53 -080075void InstrumentationInstallStack(Thread* self, void* arg)
76 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
77 struct InstallStackVisitor : public StackVisitor {
78 InstallStackVisitor(Thread* self, uintptr_t instrumentation_exit_pc)
79 : StackVisitor(self->GetManagedStack(), self->GetInstrumentationStack(), NULL),
80 self_(self), instrumentation_exit_pc_(instrumentation_exit_pc) {}
jeffhao725a9572012-11-13 18:20:12 -080081
Ian Rogers306057f2012-11-26 12:45:53 -080082 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
83 if (GetCurrentQuickFrame() == NULL) {
84 return true; // Ignore shadow frames.
85 }
86 AbstractMethod* m = GetMethod();
87 if (m == NULL) {
88 return true; // Ignore upcalls.
89 }
90 if (m->GetDexMethodIndex() == DexFile::kDexNoIndex16) {
91 return true; // Ignore unresolved methods since they will be instrumented after resolution.
92 }
93 uintptr_t pc = GetReturnPc();
94 InstrumentationStackFrame instrumentation_frame(m, pc, GetFrameId());
95 self_->PushBackInstrumentationStackFrame(instrumentation_frame);
96 SetReturnPc(instrumentation_exit_pc_);
97 return true; // Continue.
98 }
99 Thread* const self_;
100 const uintptr_t instrumentation_exit_pc_;
101 };
102 uintptr_t instrumentation_exit_pc = GetInstrumentationExitPc();
103 InstallStackVisitor visitor(self, instrumentation_exit_pc);
104 visitor.WalkStack(true);
105 Trace* trace = reinterpret_cast<Trace*>(arg);
106 if (trace != NULL) {
107 std::deque<InstrumentationStackFrame>::const_reverse_iterator it =
108 self->GetInstrumentationStack()->rbegin();
109 std::deque<InstrumentationStackFrame>::const_reverse_iterator end =
110 self->GetInstrumentationStack()->rend();
111 for (; it != end; ++it) {
112 trace->LogMethodTraceEvent(self, (*it).method_, Trace::kMethodTraceEnter);
113 }
114 }
115}
116
117static void InstrumentationRestoreStack(Thread* self, void*)
118 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
119 struct RestoreStackVisitor : public StackVisitor {
120 RestoreStackVisitor(Thread* self, uintptr_t instrumentation_exit_pc)
121 : StackVisitor(self->GetManagedStack(), self->GetInstrumentationStack(), NULL),
122 self_(self), instrumentation_exit_pc_(instrumentation_exit_pc) {}
123
124 virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
jeffhao725a9572012-11-13 18:20:12 -0800125 if (self_->IsInstrumentationStackEmpty()) {
126 return false; // Stop.
127 }
Ian Rogers306057f2012-11-26 12:45:53 -0800128 AbstractMethod* m = GetMethod();
129 if (m == NULL) {
130 return true; // Ignore upcalls.
131 }
jeffhao725a9572012-11-13 18:20:12 -0800132 uintptr_t pc = GetReturnPc();
Ian Rogers306057f2012-11-26 12:45:53 -0800133 if (pc == instrumentation_exit_pc_) {
jeffhao725a9572012-11-13 18:20:12 -0800134 InstrumentationStackFrame instrumentation_frame = self_->PopInstrumentationStackFrame();
135 SetReturnPc(instrumentation_frame.return_pc_);
Ian Rogers306057f2012-11-26 12:45:53 -0800136 CHECK(m == instrumentation_frame.method_);
137 CHECK_EQ(GetFrameId(), instrumentation_frame.frame_id_);
138 Runtime* runtime = Runtime::Current();
139 if (runtime->IsMethodTracingActive()) {
140 Trace* trace = runtime->GetInstrumentation()->GetTrace();
141 trace->LogMethodTraceEvent(self_, m, Trace::kMethodTraceExit);
142 }
jeffhao725a9572012-11-13 18:20:12 -0800143 }
144 return true; // Continue.
145 }
Ian Rogers306057f2012-11-26 12:45:53 -0800146 Thread* const self_;
147 const uintptr_t instrumentation_exit_pc_;
jeffhao725a9572012-11-13 18:20:12 -0800148 };
Ian Rogers306057f2012-11-26 12:45:53 -0800149 uintptr_t instrumentation_exit_pc = GetInstrumentationExitPc();
150 RestoreStackVisitor visitor(self, instrumentation_exit_pc);
151 visitor.WalkStack(true);
jeffhao725a9572012-11-13 18:20:12 -0800152}
153
154Instrumentation::~Instrumentation() {
155 delete trace_;
156}
157
158void Instrumentation::InstallStubs() {
Ian Rogers306057f2012-11-26 12:45:53 -0800159 Thread* self = Thread::Current();
160 Locks::thread_list_lock_->AssertNotHeld(self);
jeffhao725a9572012-11-13 18:20:12 -0800161 Runtime::Current()->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, NULL);
Ian Rogers306057f2012-11-26 12:45:53 -0800162 MutexLock mu(self, *Locks::thread_list_lock_);
163 Runtime::Current()->GetThreadList()->ForEach(InstrumentationInstallStack, GetTrace());
jeffhao725a9572012-11-13 18:20:12 -0800164}
165
166void Instrumentation::UninstallStubs() {
167 Thread* self = Thread::Current();
168 Locks::thread_list_lock_->AssertNotHeld(self);
169 Runtime::Current()->GetClassLinker()->VisitClasses(UninstallStubsClassVisitor, NULL);
170 MutexLock mu(self, *Locks::thread_list_lock_);
171 Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, NULL);
172}
173
174void Instrumentation::AddSavedCodeToMap(const AbstractMethod* method, const void* code) {
175 saved_code_map_.Put(method, code);
176}
177
178void Instrumentation::RemoveSavedCodeFromMap(const AbstractMethod* method) {
179 saved_code_map_.erase(method);
180}
181
182const void* Instrumentation::GetSavedCodeFromMap(const AbstractMethod* method) {
183 typedef SafeMap<const AbstractMethod*, const void*>::const_iterator It; // TODO: C++0x auto
184 It it = saved_code_map_.find(method);
185 if (it == saved_code_map_.end()) {
186 return NULL;
187 } else {
188 return it->second;
189 }
190}
191
192void Instrumentation::SaveAndUpdateCode(AbstractMethod* method) {
193#if defined(ART_USE_LLVM_COMPILER)
194 UNUSED(method);
195 UNIMPLEMENTED(FATAL);
196#else
197 void* instrumentation_stub = GetInstrumentationEntryPoint();
198 CHECK(GetSavedCodeFromMap(method) == NULL);
199 AddSavedCodeToMap(method, method->GetCode());
200 method->SetCode(instrumentation_stub);
201#endif
202}
203
204void Instrumentation::ResetSavedCode(AbstractMethod* method) {
205 CHECK(GetSavedCodeFromMap(method) != NULL);
206 method->SetCode(GetSavedCodeFromMap(method));
207 RemoveSavedCodeFromMap(method);
208}
209
210Trace* Instrumentation::GetTrace() const {
211 return trace_;
212}
213
214void Instrumentation::SetTrace(Trace* trace) {
215 trace_ = trace;
216}
217
218void Instrumentation::RemoveTrace() {
219 delete trace_;
220 trace_ = NULL;
221}
222
223uint32_t InstrumentationMethodUnwindFromCode(Thread* self) {
224 Trace* trace = Runtime::Current()->GetInstrumentation()->GetTrace();
225 InstrumentationStackFrame instrumentation_frame = self->PopInstrumentationStackFrame();
226 AbstractMethod* method = instrumentation_frame.method_;
227 uint32_t lr = instrumentation_frame.return_pc_;
228
229 trace->LogMethodTraceEvent(self, method, Trace::kMethodTraceUnwind);
230
231 return lr;
232}
233
234} // namespace art