1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
18*288bf522SAndroid Build Coastguard Worker #include <getopt.h>
19*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
20*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
21*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
22*288bf522SAndroid Build Coastguard Worker
23*288bf522SAndroid Build Coastguard Worker #include <string>
24*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
25*288bf522SAndroid Build Coastguard Worker #include <utility>
26*288bf522SAndroid Build Coastguard Worker
27*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
28*288bf522SAndroid Build Coastguard Worker
29*288bf522SAndroid Build Coastguard Worker #include <memory_trace/MemoryTrace.h>
30*288bf522SAndroid Build Coastguard Worker
31*288bf522SAndroid Build Coastguard Worker #include "File.h"
32*288bf522SAndroid Build Coastguard Worker
Usage()33*288bf522SAndroid Build Coastguard Worker static void Usage() {
34*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Usage: %s [--attempt_repair] TRACE_FILE1 TRACE_FILE2 ...\n",
35*288bf522SAndroid Build Coastguard Worker android::base::Basename(android::base::GetExecutablePath()).c_str());
36*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " --attempt_repair\n");
37*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " If a trace file has some errors, try to fix them. The new\n");
38*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " file will be named TRACE_FILE.repair\n");
39*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " TRACE_FILE1 TRACE_FILE2 ...\n");
40*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " The trace files to verify\n");
41*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "\n Verify trace are valid.\n");
42*288bf522SAndroid Build Coastguard Worker exit(1);
43*288bf522SAndroid Build Coastguard Worker }
44*288bf522SAndroid Build Coastguard Worker
WriteRepairEntries(const std::string & repair_file,memory_trace::Entry * entries,size_t num_entries)45*288bf522SAndroid Build Coastguard Worker static bool WriteRepairEntries(const std::string& repair_file, memory_trace::Entry* entries,
46*288bf522SAndroid Build Coastguard Worker size_t num_entries) {
47*288bf522SAndroid Build Coastguard Worker int fd = open(repair_file.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0644);
48*288bf522SAndroid Build Coastguard Worker if (fd == -1) {
49*288bf522SAndroid Build Coastguard Worker printf(" Failed to create repair file %s: %s\n", repair_file.c_str(), strerror(errno));
50*288bf522SAndroid Build Coastguard Worker return false;
51*288bf522SAndroid Build Coastguard Worker }
52*288bf522SAndroid Build Coastguard Worker bool valid = true;
53*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < num_entries; i++) {
54*288bf522SAndroid Build Coastguard Worker if (!memory_trace::WriteEntryToFd(fd, entries[i])) {
55*288bf522SAndroid Build Coastguard Worker printf(" Failed to write entry to file:\n");
56*288bf522SAndroid Build Coastguard Worker valid = false;
57*288bf522SAndroid Build Coastguard Worker break;
58*288bf522SAndroid Build Coastguard Worker }
59*288bf522SAndroid Build Coastguard Worker }
60*288bf522SAndroid Build Coastguard Worker close(fd);
61*288bf522SAndroid Build Coastguard Worker if (!valid) {
62*288bf522SAndroid Build Coastguard Worker unlink(repair_file.c_str());
63*288bf522SAndroid Build Coastguard Worker }
64*288bf522SAndroid Build Coastguard Worker return valid;
65*288bf522SAndroid Build Coastguard Worker }
66*288bf522SAndroid Build Coastguard Worker
VerifyTrace(const char * trace_file,bool attempt_repair)67*288bf522SAndroid Build Coastguard Worker static void VerifyTrace(const char* trace_file, bool attempt_repair) {
68*288bf522SAndroid Build Coastguard Worker printf("Checking %s\n", trace_file);
69*288bf522SAndroid Build Coastguard Worker
70*288bf522SAndroid Build Coastguard Worker memory_trace::Entry* entries;
71*288bf522SAndroid Build Coastguard Worker size_t num_entries;
72*288bf522SAndroid Build Coastguard Worker GetUnwindInfo(trace_file, &entries, &num_entries);
73*288bf522SAndroid Build Coastguard Worker
74*288bf522SAndroid Build Coastguard Worker size_t errors_found = 0;
75*288bf522SAndroid Build Coastguard Worker size_t errors_repaired = 0;
76*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint64_t, std::pair<memory_trace::Entry*, size_t>> live_ptrs;
77*288bf522SAndroid Build Coastguard Worker std::pair<memory_trace::Entry*, size_t> erased(nullptr, 0);
78*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < num_entries; i++) {
79*288bf522SAndroid Build Coastguard Worker memory_trace::Entry* entry = &entries[i];
80*288bf522SAndroid Build Coastguard Worker
81*288bf522SAndroid Build Coastguard Worker uint64_t ptr = 0;
82*288bf522SAndroid Build Coastguard Worker switch (entry->type) {
83*288bf522SAndroid Build Coastguard Worker case memory_trace::MALLOC:
84*288bf522SAndroid Build Coastguard Worker case memory_trace::MEMALIGN:
85*288bf522SAndroid Build Coastguard Worker ptr = entry->ptr;
86*288bf522SAndroid Build Coastguard Worker break;
87*288bf522SAndroid Build Coastguard Worker case memory_trace::CALLOC:
88*288bf522SAndroid Build Coastguard Worker ptr = entry->ptr;
89*288bf522SAndroid Build Coastguard Worker break;
90*288bf522SAndroid Build Coastguard Worker case memory_trace::REALLOC:
91*288bf522SAndroid Build Coastguard Worker if (entry->ptr != 0) {
92*288bf522SAndroid Build Coastguard Worker ptr = entry->ptr;
93*288bf522SAndroid Build Coastguard Worker }
94*288bf522SAndroid Build Coastguard Worker if (entry->u.old_ptr != 0) {
95*288bf522SAndroid Build Coastguard Worker // Verify old pointer
96*288bf522SAndroid Build Coastguard Worker auto entry_iter = live_ptrs.find(entry->u.old_ptr);
97*288bf522SAndroid Build Coastguard Worker if (entry_iter == live_ptrs.end()) {
98*288bf522SAndroid Build Coastguard Worker // Verify the pointer didn't get realloc'd to itself.
99*288bf522SAndroid Build Coastguard Worker if (entry->u.old_ptr != entry->ptr) {
100*288bf522SAndroid Build Coastguard Worker printf(" Line %zu: freeing of unknown ptr 0x%" PRIx64 "\n", i + 1, entry->u.old_ptr);
101*288bf522SAndroid Build Coastguard Worker printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
102*288bf522SAndroid Build Coastguard Worker errors_found++;
103*288bf522SAndroid Build Coastguard Worker if (attempt_repair) {
104*288bf522SAndroid Build Coastguard Worker printf(" Unable to repair this failure.\n");
105*288bf522SAndroid Build Coastguard Worker }
106*288bf522SAndroid Build Coastguard Worker }
107*288bf522SAndroid Build Coastguard Worker } else {
108*288bf522SAndroid Build Coastguard Worker if (attempt_repair) {
109*288bf522SAndroid Build Coastguard Worker erased = entry_iter->second;
110*288bf522SAndroid Build Coastguard Worker }
111*288bf522SAndroid Build Coastguard Worker live_ptrs.erase(entry_iter);
112*288bf522SAndroid Build Coastguard Worker }
113*288bf522SAndroid Build Coastguard Worker }
114*288bf522SAndroid Build Coastguard Worker break;
115*288bf522SAndroid Build Coastguard Worker case memory_trace::FREE:
116*288bf522SAndroid Build Coastguard Worker if (entry->ptr != 0) {
117*288bf522SAndroid Build Coastguard Worker // Verify pointer is present.
118*288bf522SAndroid Build Coastguard Worker auto entry_iter = live_ptrs.find(entry->ptr);
119*288bf522SAndroid Build Coastguard Worker if (entry_iter == live_ptrs.end()) {
120*288bf522SAndroid Build Coastguard Worker printf(" Line %zu: freeing of unknown ptr 0x%" PRIx64 "\n", i + 1, entry->ptr);
121*288bf522SAndroid Build Coastguard Worker printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
122*288bf522SAndroid Build Coastguard Worker errors_found++;
123*288bf522SAndroid Build Coastguard Worker if (attempt_repair) {
124*288bf522SAndroid Build Coastguard Worker printf(" Unable to repair this failure.\n");
125*288bf522SAndroid Build Coastguard Worker }
126*288bf522SAndroid Build Coastguard Worker } else {
127*288bf522SAndroid Build Coastguard Worker live_ptrs.erase(entry_iter);
128*288bf522SAndroid Build Coastguard Worker }
129*288bf522SAndroid Build Coastguard Worker }
130*288bf522SAndroid Build Coastguard Worker break;
131*288bf522SAndroid Build Coastguard Worker case memory_trace::THREAD_DONE:
132*288bf522SAndroid Build Coastguard Worker break;
133*288bf522SAndroid Build Coastguard Worker }
134*288bf522SAndroid Build Coastguard Worker
135*288bf522SAndroid Build Coastguard Worker if (ptr != 0) {
136*288bf522SAndroid Build Coastguard Worker auto old_entry = live_ptrs.find(ptr);
137*288bf522SAndroid Build Coastguard Worker if (old_entry != live_ptrs.end()) {
138*288bf522SAndroid Build Coastguard Worker printf(" Line %zu: duplicate ptr 0x%" PRIx64 "\n", i + 1, ptr);
139*288bf522SAndroid Build Coastguard Worker printf(" Original entry at line %zu:\n", old_entry->second.second);
140*288bf522SAndroid Build Coastguard Worker printf(" %s\n", memory_trace::CreateStringFromEntry(*old_entry->second.first).c_str());
141*288bf522SAndroid Build Coastguard Worker printf(" Duplicate entry at line %zu:\n", i + 1);
142*288bf522SAndroid Build Coastguard Worker printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
143*288bf522SAndroid Build Coastguard Worker errors_found++;
144*288bf522SAndroid Build Coastguard Worker if (attempt_repair) {
145*288bf522SAndroid Build Coastguard Worker // There is a small chance of a race where the same pointer is returned
146*288bf522SAndroid Build Coastguard Worker // in two different threads before the free is recorded. If this occurs,
147*288bf522SAndroid Build Coastguard Worker // the way to repair is to search forward for the free of the pointer and
148*288bf522SAndroid Build Coastguard Worker // swap the two entries.
149*288bf522SAndroid Build Coastguard Worker bool fixed = false;
150*288bf522SAndroid Build Coastguard Worker for (size_t j = i + 1; j < num_entries; j++) {
151*288bf522SAndroid Build Coastguard Worker if ((entries[j].type == memory_trace::FREE && entries[j].ptr == ptr) ||
152*288bf522SAndroid Build Coastguard Worker (entries[j].type == memory_trace::REALLOC && entries[j].u.old_ptr == ptr)) {
153*288bf522SAndroid Build Coastguard Worker memory_trace::Entry tmp_entry = *entry;
154*288bf522SAndroid Build Coastguard Worker *entry = entries[j];
155*288bf522SAndroid Build Coastguard Worker entries[j] = tmp_entry;
156*288bf522SAndroid Build Coastguard Worker errors_repaired++;
157*288bf522SAndroid Build Coastguard Worker
158*288bf522SAndroid Build Coastguard Worker live_ptrs.erase(old_entry);
159*288bf522SAndroid Build Coastguard Worker if (entry->type == memory_trace::REALLOC) {
160*288bf522SAndroid Build Coastguard Worker if (entry->ptr != 0) {
161*288bf522SAndroid Build Coastguard Worker // Need to add the newly allocated pointer.
162*288bf522SAndroid Build Coastguard Worker live_ptrs[entry->ptr] = std::make_pair(entry, i + 1);
163*288bf522SAndroid Build Coastguard Worker }
164*288bf522SAndroid Build Coastguard Worker if (erased.first != nullptr) {
165*288bf522SAndroid Build Coastguard Worker // Need to put the erased old ptr back.
166*288bf522SAndroid Build Coastguard Worker live_ptrs[tmp_entry.u.old_ptr] = erased;
167*288bf522SAndroid Build Coastguard Worker }
168*288bf522SAndroid Build Coastguard Worker }
169*288bf522SAndroid Build Coastguard Worker fixed = true;
170*288bf522SAndroid Build Coastguard Worker break;
171*288bf522SAndroid Build Coastguard Worker }
172*288bf522SAndroid Build Coastguard Worker }
173*288bf522SAndroid Build Coastguard Worker if (!fixed) {
174*288bf522SAndroid Build Coastguard Worker printf(" Unable to fix error.\n");
175*288bf522SAndroid Build Coastguard Worker }
176*288bf522SAndroid Build Coastguard Worker }
177*288bf522SAndroid Build Coastguard Worker } else {
178*288bf522SAndroid Build Coastguard Worker live_ptrs[ptr] = std::make_pair(entry, i + 1);
179*288bf522SAndroid Build Coastguard Worker }
180*288bf522SAndroid Build Coastguard Worker }
181*288bf522SAndroid Build Coastguard Worker }
182*288bf522SAndroid Build Coastguard Worker
183*288bf522SAndroid Build Coastguard Worker if (errors_found != 0) {
184*288bf522SAndroid Build Coastguard Worker printf("Trace %s is not valid.\n", trace_file);
185*288bf522SAndroid Build Coastguard Worker if (attempt_repair) {
186*288bf522SAndroid Build Coastguard Worker // Save the repaired data out to a file.
187*288bf522SAndroid Build Coastguard Worker std::string repair_file(std::string(trace_file) + ".repair");
188*288bf522SAndroid Build Coastguard Worker printf("Creating repaired trace file %s...\n", repair_file.c_str());
189*288bf522SAndroid Build Coastguard Worker if (!WriteRepairEntries(repair_file, entries, num_entries)) {
190*288bf522SAndroid Build Coastguard Worker printf("Failed trying to write repaired entries to file.\n");
191*288bf522SAndroid Build Coastguard Worker } else if (errors_repaired == errors_found) {
192*288bf522SAndroid Build Coastguard Worker printf("Repaired file is complete, no more errors.\n");
193*288bf522SAndroid Build Coastguard Worker } else {
194*288bf522SAndroid Build Coastguard Worker printf("Repaired file is still not valid.\n");
195*288bf522SAndroid Build Coastguard Worker }
196*288bf522SAndroid Build Coastguard Worker }
197*288bf522SAndroid Build Coastguard Worker } else if (attempt_repair) {
198*288bf522SAndroid Build Coastguard Worker printf("Trace %s is valid, no repair needed.\n", trace_file);
199*288bf522SAndroid Build Coastguard Worker } else {
200*288bf522SAndroid Build Coastguard Worker printf("Trace %s is valid.\n", trace_file);
201*288bf522SAndroid Build Coastguard Worker }
202*288bf522SAndroid Build Coastguard Worker
203*288bf522SAndroid Build Coastguard Worker FreeEntries(entries, num_entries);
204*288bf522SAndroid Build Coastguard Worker }
205*288bf522SAndroid Build Coastguard Worker
main(int argc,char ** argv)206*288bf522SAndroid Build Coastguard Worker int main(int argc, char** argv) {
207*288bf522SAndroid Build Coastguard Worker option options[] = {
208*288bf522SAndroid Build Coastguard Worker {"attempt_repair", no_argument, nullptr, 'a'},
209*288bf522SAndroid Build Coastguard Worker {nullptr, 0, nullptr, 0},
210*288bf522SAndroid Build Coastguard Worker };
211*288bf522SAndroid Build Coastguard Worker int option_index = 0;
212*288bf522SAndroid Build Coastguard Worker int opt = getopt_long(argc, argv, "", options, &option_index);
213*288bf522SAndroid Build Coastguard Worker if (argc == 1 || (argc == 2 && opt != -1)) {
214*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Requires at least one TRACE_FILE\n");
215*288bf522SAndroid Build Coastguard Worker Usage();
216*288bf522SAndroid Build Coastguard Worker }
217*288bf522SAndroid Build Coastguard Worker
218*288bf522SAndroid Build Coastguard Worker bool attempt_repair = false;
219*288bf522SAndroid Build Coastguard Worker if (opt == 'a') {
220*288bf522SAndroid Build Coastguard Worker attempt_repair = true;
221*288bf522SAndroid Build Coastguard Worker } else if (opt != -1) {
222*288bf522SAndroid Build Coastguard Worker Usage();
223*288bf522SAndroid Build Coastguard Worker }
224*288bf522SAndroid Build Coastguard Worker
225*288bf522SAndroid Build Coastguard Worker for (int i = 1; i < argc; i++) {
226*288bf522SAndroid Build Coastguard Worker if (i + 1 == optind) {
227*288bf522SAndroid Build Coastguard Worker continue;
228*288bf522SAndroid Build Coastguard Worker }
229*288bf522SAndroid Build Coastguard Worker VerifyTrace(argv[i], attempt_repair);
230*288bf522SAndroid Build Coastguard Worker }
231*288bf522SAndroid Build Coastguard Worker
232*288bf522SAndroid Build Coastguard Worker return 0;
233*288bf522SAndroid Build Coastguard Worker }
234