blob: 8ed278086aae134f41b675ad545732458d6210f3 [file] [log] [blame]
Florian Mayerb64d6b12018-08-30 10:46:30 -07001/*
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
Florian Mayera2fae262018-08-31 12:10:01 -070017#include <unwindstack/MachineArm.h>
18#include <unwindstack/MachineArm64.h>
19#include <unwindstack/MachineMips.h>
20#include <unwindstack/MachineMips64.h>
21#include <unwindstack/MachineX86.h>
22#include <unwindstack/MachineX86_64.h>
Florian Mayerb64d6b12018-08-30 10:46:30 -070023#include <unwindstack/Maps.h>
24#include <unwindstack/Memory.h>
Florian Mayera2fae262018-08-31 12:10:01 -070025#include <unwindstack/Regs.h>
26#include <unwindstack/RegsArm.h>
27#include <unwindstack/RegsArm64.h>
28#include <unwindstack/RegsMips.h>
29#include <unwindstack/RegsMips64.h>
30#include <unwindstack/RegsX86.h>
31#include <unwindstack/RegsX86_64.h>
32#include <unwindstack/Unwinder.h>
33#include <unwindstack/UserArm.h>
34#include <unwindstack/UserArm64.h>
35#include <unwindstack/UserMips.h>
36#include <unwindstack/UserMips64.h>
37#include <unwindstack/UserX86.h>
38#include <unwindstack/UserX86_64.h>
Florian Mayerb64d6b12018-08-30 10:46:30 -070039
40#include <procinfo/process_map.h>
41
42#include "perfetto/base/file_utils.h"
43#include "perfetto/base/logging.h"
44#include "perfetto/base/scoped_file.h"
Florian Mayerb64d6b12018-08-30 10:46:30 -070045#include "src/profiling/memory/unwinding.h"
Florian Mayerb85a9382018-09-27 13:59:01 +010046#include "src/profiling/memory/wire_protocol.h"
Florian Mayerb64d6b12018-08-30 10:46:30 -070047
48namespace perfetto {
49
Florian Mayera2fae262018-08-31 12:10:01 -070050namespace {
51
52size_t kMaxFrames = 1000;
53
54std::unique_ptr<unwindstack::Regs> CreateFromRawData(unwindstack::ArchEnum arch,
55 void* raw_data) {
56 std::unique_ptr<unwindstack::Regs> ret;
57 // unwindstack::RegsX::Read returns a raw ptr which we are expected to free.
58 switch (arch) {
59 case unwindstack::ARCH_X86:
60 ret.reset(unwindstack::RegsX86::Read(raw_data));
61 break;
62 case unwindstack::ARCH_X86_64:
63 ret.reset(unwindstack::RegsX86_64::Read(raw_data));
64 break;
65 case unwindstack::ARCH_ARM:
66 ret.reset(unwindstack::RegsArm::Read(raw_data));
67 break;
68 case unwindstack::ARCH_ARM64:
69 ret.reset(unwindstack::RegsArm64::Read(raw_data));
70 break;
71 case unwindstack::ARCH_MIPS:
72 ret.reset(unwindstack::RegsMips::Read(raw_data));
73 break;
74 case unwindstack::ARCH_MIPS64:
75 ret.reset(unwindstack::RegsMips64::Read(raw_data));
76 break;
77 case unwindstack::ARCH_UNKNOWN:
78 ret.reset(nullptr);
79 break;
80 }
81 return ret;
82}
83
84} // namespace
85
86size_t RegSize(unwindstack::ArchEnum arch) {
87 switch (arch) {
88 case unwindstack::ARCH_X86:
89 return unwindstack::X86_REG_LAST * sizeof(uint32_t);
90 case unwindstack::ARCH_X86_64:
91 return unwindstack::X86_64_REG_LAST * sizeof(uint64_t);
92 case unwindstack::ARCH_ARM:
93 return unwindstack::ARM_REG_LAST * sizeof(uint32_t);
94 case unwindstack::ARCH_ARM64:
95 return unwindstack::ARM64_REG_LAST * sizeof(uint64_t);
96 case unwindstack::ARCH_MIPS:
97 return unwindstack::MIPS_REG_LAST * sizeof(uint32_t);
98 case unwindstack::ARCH_MIPS64:
99 return unwindstack::MIPS64_REG_LAST * sizeof(uint64_t);
100 case unwindstack::ARCH_UNKNOWN:
101 PERFETTO_DCHECK(false);
102 return 0;
103 }
104}
105
Florian Mayerb64d6b12018-08-30 10:46:30 -0700106StackMemory::StackMemory(int mem_fd, uint64_t sp, uint8_t* stack, size_t size)
107 : mem_fd_(mem_fd), sp_(sp), stack_end_(sp + size), stack_(stack) {}
108
109size_t StackMemory::Read(uint64_t addr, void* dst, size_t size) {
110 if (addr >= sp_ && addr + size <= stack_end_ && addr + size > sp_) {
111 size_t offset = static_cast<size_t>(addr - sp_);
112 memcpy(dst, stack_ + offset, size);
113 return size;
114 }
115
116 if (lseek(mem_fd_, static_cast<off_t>(addr), SEEK_SET) == -1)
117 return 0;
118
119 ssize_t rd = read(mem_fd_, dst, size);
120 if (rd == -1) {
121 PERFETTO_DPLOG("read");
122 return 0;
123 }
124 return static_cast<size_t>(rd);
125}
126
127FileDescriptorMaps::FileDescriptorMaps(base::ScopedFile fd)
128 : fd_(std::move(fd)) {}
129
130bool FileDescriptorMaps::Parse() {
131 // If the process has already exited, lseek or ReadFileDescriptor will
132 // return false.
133 if (lseek(*fd_, 0, SEEK_SET) == -1)
134 return false;
135
136 std::string content;
137 if (!base::ReadFileDescriptor(*fd_, &content))
138 return false;
Florian Mayerb64d6b12018-08-30 10:46:30 -0700139 return android::procinfo::ReadMapFileContent(
140 &content[0], [&](uint64_t start, uint64_t end, uint16_t flags,
141 uint64_t pgoff, const char* name) {
142 // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
143 if (strncmp(name, "/dev/", 5) == 0 &&
144 strncmp(name + 5, "ashmem/", 7) != 0) {
145 flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
146 }
147 maps_.push_back(
148 new unwindstack::MapInfo(start, end, pgoff, flags, name));
149 });
150}
151
152void FileDescriptorMaps::Reset() {
153 for (unwindstack::MapInfo* info : maps_)
154 delete info;
155 maps_.clear();
156}
157
Florian Mayerb85a9382018-09-27 13:59:01 +0100158bool DoUnwind(WireMessage* msg, ProcessMetadata* metadata, AllocRecord* out) {
159 AllocMetadata* alloc_metadata = msg->alloc_header;
Florian Mayera2fae262018-08-31 12:10:01 -0700160 std::unique_ptr<unwindstack::Regs> regs(
Florian Mayerb85a9382018-09-27 13:59:01 +0100161 CreateFromRawData(alloc_metadata->arch, alloc_metadata->register_data));
Florian Mayera2fae262018-08-31 12:10:01 -0700162 if (regs == nullptr) {
163 PERFETTO_ELOG("regs");
164 return false;
165 }
Florian Mayerb85a9382018-09-27 13:59:01 +0100166 out->alloc_metadata = *alloc_metadata;
167 uint8_t* stack = reinterpret_cast<uint8_t*>(msg->payload);
Florian Mayera2fae262018-08-31 12:10:01 -0700168 std::shared_ptr<unwindstack::Memory> mems = std::make_shared<StackMemory>(
169 *metadata->mem_fd, alloc_metadata->stack_pointer, stack,
Florian Mayerb85a9382018-09-27 13:59:01 +0100170 msg->payload_size);
Florian Mayera2fae262018-08-31 12:10:01 -0700171 unwindstack::Unwinder unwinder(kMaxFrames, &metadata->maps, regs.get(), mems);
172 // Surpress incorrect "variable may be uninitialized" error for if condition
173 // after this loop. error_code = LastErrorCode gets run at least once.
174 uint8_t error_code = 0;
175 for (int attempt = 0; attempt < 2; ++attempt) {
176 if (attempt > 0) {
177 metadata->maps.Reset();
178 metadata->maps.Parse();
179 }
180 unwinder.Unwind();
181 error_code = unwinder.LastErrorCode();
182 if (error_code != unwindstack::ERROR_INVALID_MAP)
183 break;
184 }
185 if (error_code == 0)
Florian Mayerb85a9382018-09-27 13:59:01 +0100186 out->frames = unwinder.frames();
Florian Mayera2fae262018-08-31 12:10:01 -0700187 else
188 PERFETTO_DLOG("unwinding failed %" PRIu8, error_code);
189 return error_code == 0;
190}
191
Florian Mayerb85a9382018-09-27 13:59:01 +0100192bool HandleUnwindingRecord(UnwindingRecord* rec, BookkeepingRecord* out) {
193 WireMessage msg;
194 if (!ReceiveWireMessage(reinterpret_cast<char*>(rec->data.get()), rec->size,
195 &msg))
196 return false;
197 switch (msg.record_type) {
198 case RecordType::Malloc: {
199 std::shared_ptr<ProcessMetadata> metadata = rec->metadata.lock();
200 if (!metadata)
201 // Process has already gone away.
202 return false;
203
204 out->metadata = std::move(rec->metadata);
205 out->free_record = {};
206 return DoUnwind(&msg, metadata.get(), &out->alloc_record);
207 }
208 case RecordType::Free: {
209 // We need to keep this alive, because msg.free_header is a pointer into
210 // this.
211 out->metadata = std::move(rec->metadata);
212 out->free_record.free_data = std::move(rec->data);
213 out->free_record.metadata = msg.free_header;
214 out->alloc_record = {};
215 return true;
216 }
217 }
218}
219
220__attribute__((noreturn)) void UnwindingMainLoop(
221 BoundedQueue<UnwindingRecord>* input_queue,
222 BoundedQueue<BookkeepingRecord>* output_queue) {
223 for (;;) {
224 UnwindingRecord rec = input_queue->Get();
225 BookkeepingRecord out;
226 if (HandleUnwindingRecord(&rec, &out))
227 output_queue->Add(std::move(out));
228 }
229}
230
231void HandleBookkeepingRecord(BookkeepingRecord* rec) {
232 std::shared_ptr<ProcessMetadata> metadata = rec->metadata.lock();
233 if (!metadata)
234 // Process has already gone away.
235 return;
236
237 if (rec->free_record.free_data) {
238 FreeRecord& free_rec = rec->free_record;
239 FreePageEntry* entries = free_rec.metadata->entries;
240 uint64_t num_entries = free_rec.metadata->num_entries;
Florian Mayer7ad12752018-10-02 16:48:44 +0100241 if (num_entries > kFreePageSize)
242 return;
Florian Mayerb85a9382018-09-27 13:59:01 +0100243 for (size_t i = 0; i < num_entries; ++i) {
244 const FreePageEntry& entry = entries[i];
245 metadata->heap_dump.RecordFree(entry.addr, entry.sequence_number);
246 }
247 } else {
248 AllocRecord& alloc_rec = rec->alloc_record;
249 std::vector<CodeLocation> code_locations;
250 for (unwindstack::FrameData& frame : alloc_rec.frames)
251 code_locations.emplace_back(frame.map_name, frame.function_name);
252 metadata->heap_dump.RecordMalloc(code_locations,
253 alloc_rec.alloc_metadata.alloc_address,
254 alloc_rec.alloc_metadata.alloc_size,
255 alloc_rec.alloc_metadata.sequence_number);
256 }
257}
258
259__attribute__((noreturn)) void BookkeepingMainLoop(
260 BoundedQueue<BookkeepingRecord>* input_queue) {
261 for (;;) {
262 BookkeepingRecord rec = input_queue->Get();
263 HandleBookkeepingRecord(&rec);
264 }
265}
266
Florian Mayerb64d6b12018-08-30 10:46:30 -0700267} // namespace perfetto