blob: 0fa39cfb673480204ce431b517e03722cce64393 [file] [log] [blame]
Alex Light543d8452018-07-13 16:25:58 +00001/*
2 * Copyright (C) 2018 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 "backtrace_helper.h"
18
19#if defined(__linux__)
20
Alex Light543d8452018-07-13 16:25:58 +000021#include <sys/types.h>
David Srbeckyf1603942019-04-05 12:06:36 +010022#include <unistd.h>
23
24#include "unwindstack/Unwinder.h"
25#include "unwindstack/RegsGetLocal.h"
Alex Light543d8452018-07-13 16:25:58 +000026
27#include "thread-inl.h"
28
29#else
30
31// For UNUSED
32#include "base/macros.h"
33
34#endif
35
36namespace art {
37
38// We only really support libbacktrace on linux which is unfortunate but since this is only for
39// gcstress this isn't a huge deal.
40#if defined(__linux__)
41
David Srbeckyf1603942019-04-05 12:06:36 +010042struct UnwindHelper : public TLSData {
43 static constexpr const char* kTlsKey = "UnwindHelper::kTlsKey";
Alex Light543d8452018-07-13 16:25:58 +000044
David Srbeckyf1603942019-04-05 12:06:36 +010045 explicit UnwindHelper(size_t max_depth)
46 : memory_(new unwindstack::MemoryLocal()),
47 jit_(memory_),
48 dex_(memory_),
49 unwinder_(max_depth, &maps_, memory_) {
50 CHECK(maps_.Parse());
51 unwinder_.SetJitDebug(&jit_, unwindstack::Regs::CurrentArch());
52 unwinder_.SetDexFiles(&dex_, unwindstack::Regs::CurrentArch());
53 unwinder_.SetResolveNames(false);
54 unwindstack::Elf::SetCachingEnabled(true);
55 }
Alex Light543d8452018-07-13 16:25:58 +000056
David Srbeckyf1603942019-04-05 12:06:36 +010057 static UnwindHelper* Get(Thread* self, size_t max_depth) {
58 UnwindHelper* tls = reinterpret_cast<UnwindHelper*>(self->GetCustomTLS(kTlsKey));
59 if (tls == nullptr) {
60 tls = new UnwindHelper(max_depth);
61 self->SetCustomTLS(kTlsKey, tls);
62 }
63 return tls;
64 }
65
66 unwindstack::Unwinder* Unwinder() { return &unwinder_; }
67
68 private:
69 unwindstack::LocalMaps maps_;
70 std::shared_ptr<unwindstack::Memory> memory_;
71 unwindstack::JitDebug jit_;
72 unwindstack::DexFiles dex_;
73 unwindstack::Unwinder unwinder_;
Alex Light543d8452018-07-13 16:25:58 +000074};
75
Alex Light543d8452018-07-13 16:25:58 +000076void BacktraceCollector::Collect() {
David Srbeckyf1603942019-04-05 12:06:36 +010077 unwindstack::Unwinder* unwinder = UnwindHelper::Get(Thread::Current(), max_depth_)->Unwinder();
78 std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
79 RegsGetLocal(regs.get());
80 unwinder->SetRegs(regs.get());
81 unwinder->Unwind();
82 num_frames_ = 0;
83 if (unwinder->NumFrames() > skip_count_) {
84 for (auto it = unwinder->frames().begin() + skip_count_;
85 max_depth_ > num_frames_ && it != unwinder->frames().end();
86 ++it) {
87 out_frames_[num_frames_++] = static_cast<uintptr_t>(it->pc);
88 }
Alex Light543d8452018-07-13 16:25:58 +000089 }
90}
91
92#else
93
94#pragma clang diagnostic push
95#pragma clang diagnostic warning "-W#warnings"
96#warning "Backtrace collector is not implemented. GCStress cannot be used."
97#pragma clang diagnostic pop
98
99// We only have an implementation for linux. On other plaforms just return nothing. This is not
100// really correct but we only use this for hashing and gcstress so it's not too big a deal.
101void BacktraceCollector::Collect() {
102 UNUSED(skip_count_);
103 UNUSED(out_frames_);
104 UNUSED(max_depth_);
105 num_frames_ = 0;
106}
107
108#endif
109
110} // namespace art