blob: a829a095217023c305069f066729e89bf97cdc77 [file] [log] [blame]
Christopher Ferris7bd01782016-04-20 12:30:58 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <errno.h>
30#include <fcntl.h>
31#include <pthread.h>
32#include <stdatomic.h>
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <sys/types.h>
37
38#include <mutex>
39
40#include <android-base/stringprintf.h>
41
42#include "Config.h"
Christopher Ferris7bd01782016-04-20 12:30:58 -070043#include "DebugData.h"
44#include "RecordData.h"
Christopher Ferris4da25032018-03-07 13:38:48 -080045#include "debug_disable.h"
46#include "debug_log.h"
Christopher Ferris7bd01782016-04-20 12:30:58 -070047
48RecordEntry::RecordEntry() : tid_(gettid()) {
49}
50
Christopher Ferris06993a62022-09-07 18:19:45 -070051bool ThreadCompleteEntry::Write(int fd) const {
52 return dprintf(fd, "%d: thread_done 0x0\n", tid_) > 0;
Christopher Ferris7bd01782016-04-20 12:30:58 -070053}
54
Christopher Ferris4da25032018-03-07 13:38:48 -080055AllocEntry::AllocEntry(void* pointer) : pointer_(pointer) {}
Christopher Ferris7bd01782016-04-20 12:30:58 -070056
Christopher Ferris4da25032018-03-07 13:38:48 -080057MallocEntry::MallocEntry(void* pointer, size_t size) : AllocEntry(pointer), size_(size) {}
Christopher Ferris7bd01782016-04-20 12:30:58 -070058
Christopher Ferris06993a62022-09-07 18:19:45 -070059bool MallocEntry::Write(int fd) const {
60 return dprintf(fd, "%d: malloc %p %zu\n", tid_, pointer_, size_) > 0;
Christopher Ferris7bd01782016-04-20 12:30:58 -070061}
62
Christopher Ferris4da25032018-03-07 13:38:48 -080063FreeEntry::FreeEntry(void* pointer) : AllocEntry(pointer) {}
Christopher Ferris7bd01782016-04-20 12:30:58 -070064
Christopher Ferris06993a62022-09-07 18:19:45 -070065bool FreeEntry::Write(int fd) const {
66 return dprintf(fd, "%d: free %p\n", tid_, pointer_) > 0;
Christopher Ferris7bd01782016-04-20 12:30:58 -070067}
68
69CallocEntry::CallocEntry(void* pointer, size_t nmemb, size_t size)
Christopher Ferris4da25032018-03-07 13:38:48 -080070 : MallocEntry(pointer, size), nmemb_(nmemb) {}
Christopher Ferris7bd01782016-04-20 12:30:58 -070071
Christopher Ferris06993a62022-09-07 18:19:45 -070072bool CallocEntry::Write(int fd) const {
73 return dprintf(fd, "%d: calloc %p %zu %zu\n", tid_, pointer_, nmemb_, size_) > 0;
Christopher Ferris7bd01782016-04-20 12:30:58 -070074}
75
76ReallocEntry::ReallocEntry(void* pointer, size_t size, void* old_pointer)
Christopher Ferris4da25032018-03-07 13:38:48 -080077 : MallocEntry(pointer, size), old_pointer_(old_pointer) {}
Christopher Ferris7bd01782016-04-20 12:30:58 -070078
Christopher Ferris06993a62022-09-07 18:19:45 -070079bool ReallocEntry::Write(int fd) const {
80 return dprintf(fd, "%d: realloc %p %p %zu\n", tid_, pointer_, old_pointer_, size_) > 0;
Christopher Ferris7bd01782016-04-20 12:30:58 -070081}
82
Christopher Ferriscae21a92018-02-05 18:14:55 -080083// aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
Christopher Ferris7bd01782016-04-20 12:30:58 -070084MemalignEntry::MemalignEntry(void* pointer, size_t size, size_t alignment)
Christopher Ferris4da25032018-03-07 13:38:48 -080085 : MallocEntry(pointer, size), alignment_(alignment) {}
Christopher Ferris7bd01782016-04-20 12:30:58 -070086
Christopher Ferris06993a62022-09-07 18:19:45 -070087bool MemalignEntry::Write(int fd) const {
88 return dprintf(fd, "%d: memalign %p %zu %zu\n", tid_, pointer_, alignment_, size_) > 0;
Christopher Ferris7bd01782016-04-20 12:30:58 -070089}
90
91struct ThreadData {
Christopher Ferris4da25032018-03-07 13:38:48 -080092 ThreadData(RecordData* record_data, ThreadCompleteEntry* entry)
93 : record_data(record_data), entry(entry) {}
Christopher Ferris7bd01782016-04-20 12:30:58 -070094 RecordData* record_data;
95 ThreadCompleteEntry* entry;
96 size_t count = 0;
97};
98
99static void ThreadKeyDelete(void* data) {
100 ThreadData* thread_data = reinterpret_cast<ThreadData*>(data);
101
102 thread_data->count++;
103
104 // This should be the last time we are called.
105 if (thread_data->count == 4) {
106 ScopedDisableDebugCalls disable;
107
108 thread_data->record_data->AddEntryOnly(thread_data->entry);
109 delete thread_data;
110 } else {
111 pthread_setspecific(thread_data->record_data->key(), data);
112 }
113}
114
Christopher Ferris06993a62022-09-07 18:19:45 -0700115RecordData* RecordData::record_obj_ = nullptr;
116
117void RecordData::WriteData(int, siginfo_t*, void*) {
118 // Dump from here, the function must not allocate so this is safe.
119 record_obj_->WriteEntries();
Christopher Ferris7bd01782016-04-20 12:30:58 -0700120}
121
Christopher Ferris06993a62022-09-07 18:19:45 -0700122void RecordData::WriteEntries() {
123 std::lock_guard<std::mutex> entries_lock(entries_lock_);
124 if (cur_index_ == 0) {
125 info_log("No alloc entries to write.");
Christopher Ferris7bd01782016-04-20 12:30:58 -0700126 return;
127 }
128
Christopher Ferris4da25032018-03-07 13:38:48 -0800129 int dump_fd =
130 open(dump_file_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
Christopher Ferris06993a62022-09-07 18:19:45 -0700131 if (dump_fd == -1) {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700132 error_log("Cannot create record alloc file %s: %s", dump_file_.c_str(), strerror(errno));
Christopher Ferris06993a62022-09-07 18:19:45 -0700133 return;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700134 }
135
Christopher Ferris06993a62022-09-07 18:19:45 -0700136 for (size_t i = 0; i < cur_index_; i++) {
137 if (!entries_[i]->Write(dump_fd)) {
138 error_log("Failed to write record alloc information: %s", strerror(errno));
139 break;
140 }
141 }
142 close(dump_fd);
143
144 // Mark the entries dumped.
145 cur_index_ = 0U;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700146}
147
148RecordData::RecordData() {
149 pthread_key_create(&key_, ThreadKeyDelete);
150}
151
152bool RecordData::Initialize(const Config& config) {
Christopher Ferris06993a62022-09-07 18:19:45 -0700153 record_obj_ = this;
Elliott Hughes3e235912018-02-01 14:21:51 -0800154 struct sigaction64 dump_act = {};
Christopher Ferris06993a62022-09-07 18:19:45 -0700155 dump_act.sa_sigaction = RecordData::WriteData;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700156 dump_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
Elliott Hughes3e235912018-02-01 14:21:51 -0800157 if (sigaction64(config.record_allocs_signal(), &dump_act, nullptr) != 0) {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700158 error_log("Unable to set up record dump signal function: %s", strerror(errno));
159 return false;
160 }
161 pthread_setspecific(key_, nullptr);
162
Christopher Ferrisc328e442019-04-01 19:31:26 -0700163 if (config.options() & VERBOSE) {
164 info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
165 config.record_allocs_signal(), getpid());
166 }
Christopher Ferris7bd01782016-04-20 12:30:58 -0700167
Christopher Ferris06993a62022-09-07 18:19:45 -0700168 entries_.resize(config.record_allocs_num_entries());
169 cur_index_ = 0U;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700170 dump_file_ = config.record_allocs_file();
Christopher Ferris7bd01782016-04-20 12:30:58 -0700171
172 return true;
173}
174
175RecordData::~RecordData() {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700176 pthread_key_delete(key_);
177}
178
179void RecordData::AddEntryOnly(const RecordEntry* entry) {
Christopher Ferris06993a62022-09-07 18:19:45 -0700180 std::lock_guard<std::mutex> entries_lock(entries_lock_);
181 if (cur_index_ == entries_.size()) {
182 // Maxed out, throw the entry away.
183 return;
184 }
185
186 entries_[cur_index_++].reset(entry);
187 if (cur_index_ == entries_.size()) {
188 info_log("Maximum number of records added, all new operations will be dropped.");
Christopher Ferris7bd01782016-04-20 12:30:58 -0700189 }
190}
191
192void RecordData::AddEntry(const RecordEntry* entry) {
193 void* data = pthread_getspecific(key_);
194 if (data == nullptr) {
195 ThreadData* thread_data = new ThreadData(this, new ThreadCompleteEntry());
196 pthread_setspecific(key_, thread_data);
197 }
198
199 AddEntryOnly(entry);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700200}