xref: /aosp_15_r20/system/extras/memory_replay/MemoryTrace.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2022 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 <inttypes.h>
18*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
19*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
20*288bf522SAndroid Build Coastguard Worker 
21*288bf522SAndroid Build Coastguard Worker #include <string>
22*288bf522SAndroid Build Coastguard Worker 
23*288bf522SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
24*288bf522SAndroid Build Coastguard Worker 
25*288bf522SAndroid Build Coastguard Worker #include <memory_trace/MemoryTrace.h>
26*288bf522SAndroid Build Coastguard Worker 
27*288bf522SAndroid Build Coastguard Worker namespace memory_trace {
28*288bf522SAndroid Build Coastguard Worker 
29*288bf522SAndroid Build Coastguard Worker // This is larger than the maximum length of a possible line.
30*288bf522SAndroid Build Coastguard Worker constexpr size_t kBufferLen = 256;
31*288bf522SAndroid Build Coastguard Worker 
FillInEntryFromString(const std::string & line,Entry & entry,std::string & error)32*288bf522SAndroid Build Coastguard Worker bool FillInEntryFromString(const std::string& line, Entry& entry, std::string& error) {
33*288bf522SAndroid Build Coastguard Worker   // All lines have this format:
34*288bf522SAndroid Build Coastguard Worker   //   TID: ALLOCATION_TYPE POINTER [START_TIME_NS END_TIME_NS]
35*288bf522SAndroid Build Coastguard Worker   // where
36*288bf522SAndroid Build Coastguard Worker   //   TID is the thread id of the thread doing the operation.
37*288bf522SAndroid Build Coastguard Worker   //   ALLOCATION_TYPE is one of malloc, calloc, memalign, realloc, free, thread_done
38*288bf522SAndroid Build Coastguard Worker   //   POINTER is the hex value of the actual pointer
39*288bf522SAndroid Build Coastguard Worker   //   START_TIME_NS is the start time of the operation in nanoseconds.
40*288bf522SAndroid Build Coastguard Worker   //   END_TIME_NS is the end time of the operation in nanoseconds.
41*288bf522SAndroid Build Coastguard Worker   // The START_TIME_NS and END_TIME_NS are optional parameters, either both
42*288bf522SAndroid Build Coastguard Worker   // are present are neither are present.
43*288bf522SAndroid Build Coastguard Worker   int op_prefix_pos = 0;
44*288bf522SAndroid Build Coastguard Worker   char name[128];
45*288bf522SAndroid Build Coastguard Worker   if (sscanf(line.c_str(), "%d: %127s %" SCNx64 " %n", &entry.tid, name, &entry.ptr,
46*288bf522SAndroid Build Coastguard Worker              &op_prefix_pos) != 3) {
47*288bf522SAndroid Build Coastguard Worker     error = "Failed to process line: " + line;
48*288bf522SAndroid Build Coastguard Worker     return false;
49*288bf522SAndroid Build Coastguard Worker   }
50*288bf522SAndroid Build Coastguard Worker 
51*288bf522SAndroid Build Coastguard Worker   // Handle each individual type of entry type.
52*288bf522SAndroid Build Coastguard Worker   std::string type(name);
53*288bf522SAndroid Build Coastguard Worker   if (type == "thread_done") {
54*288bf522SAndroid Build Coastguard Worker     //   TID: thread_done 0x0 [END_TIME_NS]
55*288bf522SAndroid Build Coastguard Worker     // Where END_TIME_NS is optional.
56*288bf522SAndroid Build Coastguard Worker     entry.type = THREAD_DONE;
57*288bf522SAndroid Build Coastguard Worker     entry.start_ns = 0;
58*288bf522SAndroid Build Coastguard Worker     // Thread done has an optional time which is when the thread ended.
59*288bf522SAndroid Build Coastguard Worker     // This is the only entry type that has a single timestamp.
60*288bf522SAndroid Build Coastguard Worker     int n_match = sscanf(&line[op_prefix_pos], " %" SCNd64, &entry.end_ns);
61*288bf522SAndroid Build Coastguard Worker     entry.start_ns = 0;
62*288bf522SAndroid Build Coastguard Worker     if (n_match == EOF) {
63*288bf522SAndroid Build Coastguard Worker       entry.end_ns = 0;
64*288bf522SAndroid Build Coastguard Worker     } else if (n_match != 1) {
65*288bf522SAndroid Build Coastguard Worker       error = "Failed to read thread_done end time: " + line;
66*288bf522SAndroid Build Coastguard Worker       return false;
67*288bf522SAndroid Build Coastguard Worker     }
68*288bf522SAndroid Build Coastguard Worker     return true;
69*288bf522SAndroid Build Coastguard Worker   }
70*288bf522SAndroid Build Coastguard Worker 
71*288bf522SAndroid Build Coastguard Worker   int args_offset = 0;
72*288bf522SAndroid Build Coastguard Worker   const char* args_beg = &line[op_prefix_pos];
73*288bf522SAndroid Build Coastguard Worker   if (type == "malloc") {
74*288bf522SAndroid Build Coastguard Worker     // Format:
75*288bf522SAndroid Build Coastguard Worker     //   TID: malloc POINTER SIZE_OF_ALLOCATION [START_TIME_NS END_TIME_NS]
76*288bf522SAndroid Build Coastguard Worker     if (sscanf(args_beg, "%zu%n", &entry.size, &args_offset) != 1) {
77*288bf522SAndroid Build Coastguard Worker       error = "Failed to read malloc data: " + line;
78*288bf522SAndroid Build Coastguard Worker       return false;
79*288bf522SAndroid Build Coastguard Worker     }
80*288bf522SAndroid Build Coastguard Worker     entry.type = MALLOC;
81*288bf522SAndroid Build Coastguard Worker   } else if (type == "free") {
82*288bf522SAndroid Build Coastguard Worker     // Format:
83*288bf522SAndroid Build Coastguard Worker     //   TID: free POINTER [START_TIME_NS END_TIME_NS]
84*288bf522SAndroid Build Coastguard Worker     entry.type = FREE;
85*288bf522SAndroid Build Coastguard Worker   } else if (type == "calloc") {
86*288bf522SAndroid Build Coastguard Worker     // Format:
87*288bf522SAndroid Build Coastguard Worker     //   TID: calloc POINTER ITEM_COUNT ITEM_SIZE [START_TIME_NS END_TIME_NS]
88*288bf522SAndroid Build Coastguard Worker     if (sscanf(args_beg, "%" SCNd64 " %zu%n", &entry.u.n_elements, &entry.size, &args_offset) !=
89*288bf522SAndroid Build Coastguard Worker         2) {
90*288bf522SAndroid Build Coastguard Worker       error = "Failed to read calloc data: " + line;
91*288bf522SAndroid Build Coastguard Worker       return false;
92*288bf522SAndroid Build Coastguard Worker     }
93*288bf522SAndroid Build Coastguard Worker     entry.type = CALLOC;
94*288bf522SAndroid Build Coastguard Worker   } else if (type == "realloc") {
95*288bf522SAndroid Build Coastguard Worker     // Format:
96*288bf522SAndroid Build Coastguard Worker     //   TID: realloc POINTER OLD_POINTER NEW_SIZE [START_TIME_NS END_TIME_NS]
97*288bf522SAndroid Build Coastguard Worker     if (sscanf(args_beg, "%" SCNx64 " %zu%n", &entry.u.old_ptr, &entry.size, &args_offset) != 2) {
98*288bf522SAndroid Build Coastguard Worker       error = "Failed to read realloc data: " + line;
99*288bf522SAndroid Build Coastguard Worker       return false;
100*288bf522SAndroid Build Coastguard Worker     }
101*288bf522SAndroid Build Coastguard Worker     entry.type = REALLOC;
102*288bf522SAndroid Build Coastguard Worker   } else if (type == "memalign") {
103*288bf522SAndroid Build Coastguard Worker     // Format:
104*288bf522SAndroid Build Coastguard Worker     //   TID: memalign POINTER ALIGNMENT SIZE [START_TIME_NS END_TIME_NS]
105*288bf522SAndroid Build Coastguard Worker     if (sscanf(args_beg, "%" SCNd64 " %zu%n", &entry.u.align, &entry.size, &args_offset) != 2) {
106*288bf522SAndroid Build Coastguard Worker       error = "Failed to read memalign data: " + line;
107*288bf522SAndroid Build Coastguard Worker       return false;
108*288bf522SAndroid Build Coastguard Worker     }
109*288bf522SAndroid Build Coastguard Worker     entry.type = MEMALIGN;
110*288bf522SAndroid Build Coastguard Worker   } else {
111*288bf522SAndroid Build Coastguard Worker     printf("Unknown type %s: %s\n", type.c_str(), line.c_str());
112*288bf522SAndroid Build Coastguard Worker     error = "Unknown type " + type + ": " + line;
113*288bf522SAndroid Build Coastguard Worker     return false;
114*288bf522SAndroid Build Coastguard Worker   }
115*288bf522SAndroid Build Coastguard Worker 
116*288bf522SAndroid Build Coastguard Worker   const char* timestamps_beg = &args_beg[args_offset];
117*288bf522SAndroid Build Coastguard Worker 
118*288bf522SAndroid Build Coastguard Worker   // Get the optional timestamps if they exist.
119*288bf522SAndroid Build Coastguard Worker   int n_match = sscanf(timestamps_beg, "%" SCNd64 " %" SCNd64, &entry.start_ns, &entry.end_ns);
120*288bf522SAndroid Build Coastguard Worker   if (n_match == EOF) {
121*288bf522SAndroid Build Coastguard Worker     entry.start_ns = 0;
122*288bf522SAndroid Build Coastguard Worker     entry.end_ns = 0;
123*288bf522SAndroid Build Coastguard Worker   } else if (n_match != 2) {
124*288bf522SAndroid Build Coastguard Worker     error = "Failed to read timestamps: " + line;
125*288bf522SAndroid Build Coastguard Worker     return false;
126*288bf522SAndroid Build Coastguard Worker   }
127*288bf522SAndroid Build Coastguard Worker   return true;
128*288bf522SAndroid Build Coastguard Worker }
129*288bf522SAndroid Build Coastguard Worker 
TypeToName(const TypeEnum type)130*288bf522SAndroid Build Coastguard Worker static const char* TypeToName(const TypeEnum type) {
131*288bf522SAndroid Build Coastguard Worker   switch (type) {
132*288bf522SAndroid Build Coastguard Worker     case CALLOC:
133*288bf522SAndroid Build Coastguard Worker       return "calloc";
134*288bf522SAndroid Build Coastguard Worker     case FREE:
135*288bf522SAndroid Build Coastguard Worker       return "free";
136*288bf522SAndroid Build Coastguard Worker     case MALLOC:
137*288bf522SAndroid Build Coastguard Worker       return "malloc";
138*288bf522SAndroid Build Coastguard Worker     case MEMALIGN:
139*288bf522SAndroid Build Coastguard Worker       return "memalign";
140*288bf522SAndroid Build Coastguard Worker     case REALLOC:
141*288bf522SAndroid Build Coastguard Worker       return "realloc";
142*288bf522SAndroid Build Coastguard Worker     case THREAD_DONE:
143*288bf522SAndroid Build Coastguard Worker       return "thread_done";
144*288bf522SAndroid Build Coastguard Worker   }
145*288bf522SAndroid Build Coastguard Worker   return "unknown";
146*288bf522SAndroid Build Coastguard Worker }
147*288bf522SAndroid Build Coastguard Worker 
FormatEntry(const Entry & entry,char * buffer,size_t buffer_len)148*288bf522SAndroid Build Coastguard Worker static size_t FormatEntry(const Entry& entry, char* buffer, size_t buffer_len) {
149*288bf522SAndroid Build Coastguard Worker   int len = snprintf(buffer, buffer_len, "%d: %s 0x%" PRIx64, entry.tid, TypeToName(entry.type),
150*288bf522SAndroid Build Coastguard Worker                      entry.ptr);
151*288bf522SAndroid Build Coastguard Worker   if (len < 0) {
152*288bf522SAndroid Build Coastguard Worker     return 0;
153*288bf522SAndroid Build Coastguard Worker   }
154*288bf522SAndroid Build Coastguard Worker   size_t cur_len = len;
155*288bf522SAndroid Build Coastguard Worker   switch (entry.type) {
156*288bf522SAndroid Build Coastguard Worker     case FREE:
157*288bf522SAndroid Build Coastguard Worker       len = 0;
158*288bf522SAndroid Build Coastguard Worker       break;
159*288bf522SAndroid Build Coastguard Worker     case CALLOC:
160*288bf522SAndroid Build Coastguard Worker       len = snprintf(&buffer[cur_len], buffer_len - cur_len, " %" PRIu64 " %zu", entry.u.n_elements,
161*288bf522SAndroid Build Coastguard Worker                      entry.size);
162*288bf522SAndroid Build Coastguard Worker       break;
163*288bf522SAndroid Build Coastguard Worker     case MALLOC:
164*288bf522SAndroid Build Coastguard Worker       len = snprintf(&buffer[cur_len], buffer_len - cur_len, " %zu", entry.size);
165*288bf522SAndroid Build Coastguard Worker       break;
166*288bf522SAndroid Build Coastguard Worker     case MEMALIGN:
167*288bf522SAndroid Build Coastguard Worker       len = snprintf(&buffer[cur_len], buffer_len - cur_len, " %" PRIu64 " %zu", entry.u.align,
168*288bf522SAndroid Build Coastguard Worker                      entry.size);
169*288bf522SAndroid Build Coastguard Worker       break;
170*288bf522SAndroid Build Coastguard Worker     case REALLOC:
171*288bf522SAndroid Build Coastguard Worker       len = snprintf(&buffer[cur_len], buffer_len - cur_len, " 0x%" PRIx64 " %zu", entry.u.old_ptr,
172*288bf522SAndroid Build Coastguard Worker                      entry.size);
173*288bf522SAndroid Build Coastguard Worker       break;
174*288bf522SAndroid Build Coastguard Worker     case THREAD_DONE:
175*288bf522SAndroid Build Coastguard Worker       // Thread done only has a single optional timestamp, end_ns.
176*288bf522SAndroid Build Coastguard Worker       if (entry.end_ns != 0) {
177*288bf522SAndroid Build Coastguard Worker         len = snprintf(&buffer[cur_len], buffer_len - cur_len, " %" PRId64, entry.end_ns);
178*288bf522SAndroid Build Coastguard Worker         if (len < 0) {
179*288bf522SAndroid Build Coastguard Worker           return 0;
180*288bf522SAndroid Build Coastguard Worker         }
181*288bf522SAndroid Build Coastguard Worker         return cur_len + len;
182*288bf522SAndroid Build Coastguard Worker       }
183*288bf522SAndroid Build Coastguard Worker       return cur_len;
184*288bf522SAndroid Build Coastguard Worker     default:
185*288bf522SAndroid Build Coastguard Worker       return 0;
186*288bf522SAndroid Build Coastguard Worker   }
187*288bf522SAndroid Build Coastguard Worker   if (len < 0) {
188*288bf522SAndroid Build Coastguard Worker     return 0;
189*288bf522SAndroid Build Coastguard Worker   }
190*288bf522SAndroid Build Coastguard Worker 
191*288bf522SAndroid Build Coastguard Worker   cur_len += len;
192*288bf522SAndroid Build Coastguard Worker   if (entry.start_ns == 0) {
193*288bf522SAndroid Build Coastguard Worker     return cur_len;
194*288bf522SAndroid Build Coastguard Worker   }
195*288bf522SAndroid Build Coastguard Worker 
196*288bf522SAndroid Build Coastguard Worker   len = snprintf(&buffer[cur_len], buffer_len - cur_len, " %" PRIu64 " %" PRIu64, entry.start_ns,
197*288bf522SAndroid Build Coastguard Worker                  entry.end_ns);
198*288bf522SAndroid Build Coastguard Worker   if (len < 0) {
199*288bf522SAndroid Build Coastguard Worker     return 0;
200*288bf522SAndroid Build Coastguard Worker   }
201*288bf522SAndroid Build Coastguard Worker   return cur_len + len;
202*288bf522SAndroid Build Coastguard Worker }
203*288bf522SAndroid Build Coastguard Worker 
CreateStringFromEntry(const Entry & entry)204*288bf522SAndroid Build Coastguard Worker std::string CreateStringFromEntry(const Entry& entry) {
205*288bf522SAndroid Build Coastguard Worker   std::string line(kBufferLen, '\0');
206*288bf522SAndroid Build Coastguard Worker 
207*288bf522SAndroid Build Coastguard Worker   size_t size = FormatEntry(entry, line.data(), line.size());
208*288bf522SAndroid Build Coastguard Worker   if (size == 0) {
209*288bf522SAndroid Build Coastguard Worker     return "";
210*288bf522SAndroid Build Coastguard Worker   }
211*288bf522SAndroid Build Coastguard Worker   line.resize(size);
212*288bf522SAndroid Build Coastguard Worker   return line;
213*288bf522SAndroid Build Coastguard Worker }
214*288bf522SAndroid Build Coastguard Worker 
WriteEntryToFd(int fd,const Entry & entry)215*288bf522SAndroid Build Coastguard Worker bool WriteEntryToFd(int fd, const Entry& entry) {
216*288bf522SAndroid Build Coastguard Worker   char buffer[kBufferLen];
217*288bf522SAndroid Build Coastguard Worker   size_t size = FormatEntry(entry, buffer, sizeof(buffer));
218*288bf522SAndroid Build Coastguard Worker   if (size == 0 || size == sizeof(buffer)) {
219*288bf522SAndroid Build Coastguard Worker     return false;
220*288bf522SAndroid Build Coastguard Worker   }
221*288bf522SAndroid Build Coastguard Worker   buffer[size++] = '\n';
222*288bf522SAndroid Build Coastguard Worker   buffer[size] = '\0';
223*288bf522SAndroid Build Coastguard Worker   ssize_t bytes = TEMP_FAILURE_RETRY(write(fd, buffer, size));
224*288bf522SAndroid Build Coastguard Worker   if (bytes < 0 || static_cast<size_t>(bytes) != size) {
225*288bf522SAndroid Build Coastguard Worker     return false;
226*288bf522SAndroid Build Coastguard Worker   }
227*288bf522SAndroid Build Coastguard Worker   return true;
228*288bf522SAndroid Build Coastguard Worker }
229*288bf522SAndroid Build Coastguard Worker 
230*288bf522SAndroid Build Coastguard Worker }  // namespace memory_trace
231