xref: /aosp_15_r20/system/extras/memory_replay/File.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2019 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 <err.h>
18*288bf522SAndroid Build Coastguard Worker #include <errno.h>
19*288bf522SAndroid Build Coastguard Worker #include <stdint.h>
20*288bf522SAndroid Build Coastguard Worker #include <sys/mman.h>
21*288bf522SAndroid Build Coastguard Worker #include <sys/types.h>
22*288bf522SAndroid Build Coastguard Worker #include <sys/wait.h>
23*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
24*288bf522SAndroid Build Coastguard Worker 
25*288bf522SAndroid Build Coastguard Worker #include <string>
26*288bf522SAndroid Build Coastguard Worker 
27*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
28*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
29*288bf522SAndroid Build Coastguard Worker #include <ziparchive/zip_archive.h>
30*288bf522SAndroid Build Coastguard Worker 
31*288bf522SAndroid Build Coastguard Worker #include <memory_trace/MemoryTrace.h>
32*288bf522SAndroid Build Coastguard Worker 
33*288bf522SAndroid Build Coastguard Worker #include "File.h"
34*288bf522SAndroid Build Coastguard Worker 
ZipGetContents(const char * filename)35*288bf522SAndroid Build Coastguard Worker std::string ZipGetContents(const char* filename) {
36*288bf522SAndroid Build Coastguard Worker   ZipArchiveHandle archive;
37*288bf522SAndroid Build Coastguard Worker   if (OpenArchive(filename, &archive) != 0) {
38*288bf522SAndroid Build Coastguard Worker     return "";
39*288bf522SAndroid Build Coastguard Worker   }
40*288bf522SAndroid Build Coastguard Worker 
41*288bf522SAndroid Build Coastguard Worker   // It is assumed that the archive contains only a single entry.
42*288bf522SAndroid Build Coastguard Worker   void* cookie;
43*288bf522SAndroid Build Coastguard Worker   std::string contents;
44*288bf522SAndroid Build Coastguard Worker   if (StartIteration(archive, &cookie) == 0) {
45*288bf522SAndroid Build Coastguard Worker     ZipEntry entry;
46*288bf522SAndroid Build Coastguard Worker     std::string name;
47*288bf522SAndroid Build Coastguard Worker     if (Next(cookie, &entry, &name) == 0) {
48*288bf522SAndroid Build Coastguard Worker       contents.resize(entry.uncompressed_length);
49*288bf522SAndroid Build Coastguard Worker       if (ExtractToMemory(archive, &entry, reinterpret_cast<uint8_t*>(contents.data()),
50*288bf522SAndroid Build Coastguard Worker                           entry.uncompressed_length) != 0) {
51*288bf522SAndroid Build Coastguard Worker         contents = "";
52*288bf522SAndroid Build Coastguard Worker       }
53*288bf522SAndroid Build Coastguard Worker     }
54*288bf522SAndroid Build Coastguard Worker   }
55*288bf522SAndroid Build Coastguard Worker 
56*288bf522SAndroid Build Coastguard Worker   CloseArchive(archive);
57*288bf522SAndroid Build Coastguard Worker   return contents;
58*288bf522SAndroid Build Coastguard Worker }
59*288bf522SAndroid Build Coastguard Worker 
WaitPid(pid_t pid)60*288bf522SAndroid Build Coastguard Worker static void WaitPid(pid_t pid) {
61*288bf522SAndroid Build Coastguard Worker   int wstatus;
62*288bf522SAndroid Build Coastguard Worker   pid_t wait_pid = TEMP_FAILURE_RETRY(waitpid(pid, &wstatus, 0));
63*288bf522SAndroid Build Coastguard Worker   if (wait_pid != pid) {
64*288bf522SAndroid Build Coastguard Worker     if (wait_pid == -1) {
65*288bf522SAndroid Build Coastguard Worker       err(1, "waitpid() failed");
66*288bf522SAndroid Build Coastguard Worker     } else {
67*288bf522SAndroid Build Coastguard Worker       errx(1, "Unexpected pid from waitpid(): expected %d, returned %d", pid, wait_pid);
68*288bf522SAndroid Build Coastguard Worker     }
69*288bf522SAndroid Build Coastguard Worker   }
70*288bf522SAndroid Build Coastguard Worker   if (!WIFEXITED(wstatus)) {
71*288bf522SAndroid Build Coastguard Worker     errx(1, "Forked process did not terminate with exit() call");
72*288bf522SAndroid Build Coastguard Worker   }
73*288bf522SAndroid Build Coastguard Worker   if (WEXITSTATUS(wstatus) != 0) {
74*288bf522SAndroid Build Coastguard Worker     errx(1, "Bad exit value from forked process: returned %d", WEXITSTATUS(wstatus));
75*288bf522SAndroid Build Coastguard Worker   }
76*288bf522SAndroid Build Coastguard Worker }
77*288bf522SAndroid Build Coastguard Worker 
78*288bf522SAndroid Build Coastguard Worker // This function should not do any memory allocations in the main function.
79*288bf522SAndroid Build Coastguard Worker // Any true allocation should happen in fork'd code.
GetUnwindInfo(const char * filename,memory_trace::Entry ** entries,size_t * num_entries)80*288bf522SAndroid Build Coastguard Worker void GetUnwindInfo(const char* filename, memory_trace::Entry** entries, size_t* num_entries) {
81*288bf522SAndroid Build Coastguard Worker   void* mem =
82*288bf522SAndroid Build Coastguard Worker       mmap(nullptr, sizeof(size_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
83*288bf522SAndroid Build Coastguard Worker   if (mem == MAP_FAILED) {
84*288bf522SAndroid Build Coastguard Worker     err(1, "Unable to allocate a shared map of size %zu", sizeof(size_t));
85*288bf522SAndroid Build Coastguard Worker   }
86*288bf522SAndroid Build Coastguard Worker   *reinterpret_cast<size_t*>(mem) = 0;
87*288bf522SAndroid Build Coastguard Worker 
88*288bf522SAndroid Build Coastguard Worker   pid_t pid;
89*288bf522SAndroid Build Coastguard Worker   if ((pid = fork()) == 0) {
90*288bf522SAndroid Build Coastguard Worker     // First get the number of lines in the trace file. It is assumed
91*288bf522SAndroid Build Coastguard Worker     // that there are no blank lines, and every line contains a valid
92*288bf522SAndroid Build Coastguard Worker     // allocation operation.
93*288bf522SAndroid Build Coastguard Worker     std::string contents;
94*288bf522SAndroid Build Coastguard Worker     if (android::base::EndsWith(filename, ".zip")) {
95*288bf522SAndroid Build Coastguard Worker       contents = ZipGetContents(filename);
96*288bf522SAndroid Build Coastguard Worker     } else if (!android::base::ReadFileToString(filename, &contents)) {
97*288bf522SAndroid Build Coastguard Worker       errx(1, "Unable to get contents of %s", filename);
98*288bf522SAndroid Build Coastguard Worker     }
99*288bf522SAndroid Build Coastguard Worker     if (contents.empty()) {
100*288bf522SAndroid Build Coastguard Worker       errx(1, "Unable to get contents of %s", filename);
101*288bf522SAndroid Build Coastguard Worker     }
102*288bf522SAndroid Build Coastguard Worker 
103*288bf522SAndroid Build Coastguard Worker     size_t lines = 0;
104*288bf522SAndroid Build Coastguard Worker     size_t index = 0;
105*288bf522SAndroid Build Coastguard Worker     while (true) {
106*288bf522SAndroid Build Coastguard Worker       index = contents.find('\n', index);
107*288bf522SAndroid Build Coastguard Worker       if (index == std::string::npos) {
108*288bf522SAndroid Build Coastguard Worker         break;
109*288bf522SAndroid Build Coastguard Worker       }
110*288bf522SAndroid Build Coastguard Worker       index++;
111*288bf522SAndroid Build Coastguard Worker       lines++;
112*288bf522SAndroid Build Coastguard Worker     }
113*288bf522SAndroid Build Coastguard Worker     if (contents[contents.size() - 1] != '\n') {
114*288bf522SAndroid Build Coastguard Worker       // Add one since the last line doesn't end in '\n'.
115*288bf522SAndroid Build Coastguard Worker       lines++;
116*288bf522SAndroid Build Coastguard Worker     }
117*288bf522SAndroid Build Coastguard Worker     *reinterpret_cast<size_t*>(mem) = lines;
118*288bf522SAndroid Build Coastguard Worker     _exit(0);
119*288bf522SAndroid Build Coastguard Worker   } else if (pid == -1) {
120*288bf522SAndroid Build Coastguard Worker     err(1, "fork() call failed");
121*288bf522SAndroid Build Coastguard Worker   }
122*288bf522SAndroid Build Coastguard Worker   WaitPid(pid);
123*288bf522SAndroid Build Coastguard Worker   *num_entries = *reinterpret_cast<size_t*>(mem);
124*288bf522SAndroid Build Coastguard Worker   munmap(mem, sizeof(size_t));
125*288bf522SAndroid Build Coastguard Worker 
126*288bf522SAndroid Build Coastguard Worker   mem = mmap(nullptr, *num_entries * sizeof(memory_trace::Entry), PROT_READ | PROT_WRITE,
127*288bf522SAndroid Build Coastguard Worker              MAP_ANONYMOUS | MAP_SHARED, -1, 0);
128*288bf522SAndroid Build Coastguard Worker   if (mem == MAP_FAILED) {
129*288bf522SAndroid Build Coastguard Worker     err(1, "Unable to allocate a shared map of size %zu",
130*288bf522SAndroid Build Coastguard Worker         *num_entries * sizeof(memory_trace::Entry));
131*288bf522SAndroid Build Coastguard Worker   }
132*288bf522SAndroid Build Coastguard Worker   *entries = reinterpret_cast<memory_trace::Entry*>(mem);
133*288bf522SAndroid Build Coastguard Worker 
134*288bf522SAndroid Build Coastguard Worker   if ((pid = fork()) == 0) {
135*288bf522SAndroid Build Coastguard Worker     std::string contents;
136*288bf522SAndroid Build Coastguard Worker     if (android::base::EndsWith(filename, ".zip")) {
137*288bf522SAndroid Build Coastguard Worker       contents = ZipGetContents(filename);
138*288bf522SAndroid Build Coastguard Worker     } else if (!android::base::ReadFileToString(filename, &contents)) {
139*288bf522SAndroid Build Coastguard Worker       errx(1, "Unable to get contents of %s", filename);
140*288bf522SAndroid Build Coastguard Worker     }
141*288bf522SAndroid Build Coastguard Worker     if (contents.empty()) {
142*288bf522SAndroid Build Coastguard Worker       errx(1, "Contents of zip file %s is empty.", filename);
143*288bf522SAndroid Build Coastguard Worker     }
144*288bf522SAndroid Build Coastguard Worker 
145*288bf522SAndroid Build Coastguard Worker     size_t entry_idx = 0;
146*288bf522SAndroid Build Coastguard Worker     size_t start_str = 0;
147*288bf522SAndroid Build Coastguard Worker     size_t end_str = 0;
148*288bf522SAndroid Build Coastguard Worker     while (true) {
149*288bf522SAndroid Build Coastguard Worker       end_str = contents.find('\n', start_str);
150*288bf522SAndroid Build Coastguard Worker       if (end_str == std::string::npos) {
151*288bf522SAndroid Build Coastguard Worker         break;
152*288bf522SAndroid Build Coastguard Worker       }
153*288bf522SAndroid Build Coastguard Worker       if (entry_idx == *num_entries) {
154*288bf522SAndroid Build Coastguard Worker         errx(1, "Too many entries, stopped at entry %zu", entry_idx);
155*288bf522SAndroid Build Coastguard Worker       }
156*288bf522SAndroid Build Coastguard Worker       contents[end_str] = '\0';
157*288bf522SAndroid Build Coastguard Worker       std::string error;
158*288bf522SAndroid Build Coastguard Worker       if (!memory_trace::FillInEntryFromString(&contents[start_str], (*entries)[entry_idx++],
159*288bf522SAndroid Build Coastguard Worker                                                error)) {
160*288bf522SAndroid Build Coastguard Worker         errx(1, "%s", error.c_str());
161*288bf522SAndroid Build Coastguard Worker       }
162*288bf522SAndroid Build Coastguard Worker       start_str = end_str + 1;
163*288bf522SAndroid Build Coastguard Worker     }
164*288bf522SAndroid Build Coastguard Worker     if (entry_idx != *num_entries) {
165*288bf522SAndroid Build Coastguard Worker       errx(1, "Mismatched number of entries found: expected %zu, found %zu", *num_entries,
166*288bf522SAndroid Build Coastguard Worker            entry_idx);
167*288bf522SAndroid Build Coastguard Worker     }
168*288bf522SAndroid Build Coastguard Worker     _exit(0);
169*288bf522SAndroid Build Coastguard Worker   } else if (pid == -1) {
170*288bf522SAndroid Build Coastguard Worker     err(1, "fork() call failed");
171*288bf522SAndroid Build Coastguard Worker   }
172*288bf522SAndroid Build Coastguard Worker   WaitPid(pid);
173*288bf522SAndroid Build Coastguard Worker }
174*288bf522SAndroid Build Coastguard Worker 
FreeEntries(memory_trace::Entry * entries,size_t num_entries)175*288bf522SAndroid Build Coastguard Worker void FreeEntries(memory_trace::Entry* entries, size_t num_entries) {
176*288bf522SAndroid Build Coastguard Worker   munmap(entries, num_entries * sizeof(memory_trace::Entry));
177*288bf522SAndroid Build Coastguard Worker }
178