1 /*
2 * Copyright (C) 2014 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
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include <functional>
21 #include <map>
22 #include <optional>
23 #include <ostream>
24 #include <set>
25 #include <string>
26 #include <unordered_set>
27 #include <vector>
28
29 #include <android-base/parseint.h>
30 #include "android-base/stringprintf.h"
31
32 #include "art_field-inl.h"
33 #include "art_method-inl.h"
34 #include "base/array_ref.h"
35 #include "base/os.h"
36 #include "base/string_view_cpp20.h"
37 #include "base/unix_file/fd_file.h"
38 #include "class_linker.h"
39 #include "gc/heap.h"
40 #include "gc/space/image_space.h"
41 #include "image-inl.h"
42 #include "mirror/class-inl.h"
43 #include "mirror/object-inl.h"
44 #include "oat.h"
45 #include "oat_file.h"
46 #include "oat_file_manager.h"
47 #include "scoped_thread_state_change-inl.h"
48
49 #include "procinfo/process_map.h"
50 #include "cmdline.h"
51
52 #include <signal.h>
53 #include <sys/stat.h>
54 #include <sys/types.h>
55
56 namespace art {
57
58 using android::base::StringPrintf;
59
60 namespace {
61
62 constexpr size_t kMaxAddressPrint = 5;
63
64 enum class ProcessType {
65 kZygote,
66 kRemote
67 };
68
69 enum class RemoteProcesses {
70 kImageOnly,
71 kZygoteOnly,
72 kImageAndZygote
73 };
74
operator <<(std::ostream & os,RemoteProcesses remotes)75 std::ostream& operator<<(std::ostream& os, RemoteProcesses remotes) {
76 switch (remotes) {
77 case RemoteProcesses::kImageOnly: os << "ImageOnly"; break;
78 case RemoteProcesses::kZygoteOnly: os << "ZygoteOnly"; break;
79 case RemoteProcesses::kImageAndZygote: os << "ImageAndZygote"; break;
80 default: UNREACHABLE();
81 }
82 return os;
83 }
84
85 struct MappingData {
86 // The count of pages that are considered dirty by the OS.
87 size_t dirty_pages = 0;
88 // The count of pages that differ by at least one byte.
89 size_t different_pages = 0;
90 // The count of differing bytes.
91 size_t different_bytes = 0;
92 // The count of differing four-byte units.
93 size_t different_int32s = 0;
94 // The count of pages that have mapping count == 1.
95 size_t private_pages = 0;
96 // The count of private pages that are also dirty.
97 size_t private_dirty_pages = 0;
98 // The count of pages that are marked dirty but do not differ.
99 size_t false_dirty_pages = 0;
100 // Set of the local virtual page indices that are dirty.
101 std::set<size_t> dirty_page_set;
102 // Private dirty page counts for each section of the image
103 std::array<size_t, ImageHeader::kSectionCount> private_dirty_pages_for_section = {};
104 };
105
GetClassDescriptor(mirror::Class * klass)106 static std::string GetClassDescriptor(mirror::Class* klass)
107 REQUIRES_SHARED(Locks::mutator_lock_) {
108 CHECK(klass != nullptr);
109
110 std::string descriptor;
111 const char* descriptor_str = klass->GetDescriptor(&descriptor /*out*/);
112
113 return std::string(descriptor_str);
114 }
115
PrettyFieldValue(ArtField * field,mirror::Object * object)116 static std::string PrettyFieldValue(ArtField* field, mirror::Object* object)
117 REQUIRES_SHARED(Locks::mutator_lock_) {
118 std::ostringstream oss;
119 switch (field->GetTypeAsPrimitiveType()) {
120 case Primitive::kPrimNot: {
121 oss << object->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(
122 field->GetOffset());
123 break;
124 }
125 case Primitive::kPrimBoolean: {
126 oss << static_cast<bool>(object->GetFieldBoolean<kVerifyNone>(field->GetOffset()));
127 break;
128 }
129 case Primitive::kPrimByte: {
130 oss << static_cast<int32_t>(object->GetFieldByte<kVerifyNone>(field->GetOffset()));
131 break;
132 }
133 case Primitive::kPrimChar: {
134 oss << object->GetFieldChar<kVerifyNone>(field->GetOffset());
135 break;
136 }
137 case Primitive::kPrimShort: {
138 oss << object->GetFieldShort<kVerifyNone>(field->GetOffset());
139 break;
140 }
141 case Primitive::kPrimInt: {
142 oss << object->GetField32<kVerifyNone>(field->GetOffset());
143 break;
144 }
145 case Primitive::kPrimLong: {
146 oss << object->GetField64<kVerifyNone>(field->GetOffset());
147 break;
148 }
149 case Primitive::kPrimFloat: {
150 oss << object->GetField32<kVerifyNone>(field->GetOffset());
151 break;
152 }
153 case Primitive::kPrimDouble: {
154 oss << object->GetField64<kVerifyNone>(field->GetOffset());
155 break;
156 }
157 case Primitive::kPrimVoid: {
158 oss << "void";
159 break;
160 }
161 }
162 return oss.str();
163 }
164
165 template <typename K, typename V, typename D>
SortByValueDesc(const std::map<K,D> map,std::function<V (const D &)> value_mapper=[](const D & d){})166 static std::vector<std::pair<V, K>> SortByValueDesc(
167 const std::map<K, D> map,
168 std::function<V(const D&)> value_mapper = [](const D& d) { return static_cast<V>(d); }) {
169 // Store value->key so that we can use the default sort from pair which
170 // sorts by value first and then key
171 std::vector<std::pair<V, K>> value_key_vector;
172 value_key_vector.reserve(map.size());
173 for (const auto& kv_pair : map) {
174 value_key_vector.push_back(std::make_pair(value_mapper(kv_pair.second), kv_pair.first));
175 }
176
177 // Sort in reverse (descending order)
178 std::sort(value_key_vector.rbegin(), value_key_vector.rend());
179 return value_key_vector;
180 }
181
182 // Fixup a remote pointer that we read from a foreign boot.art to point to our own memory.
183 // Returned pointer will point to inside of remote_contents.
184 template <typename T>
FixUpRemotePointer(ObjPtr<T> remote_ptr,ArrayRef<uint8_t> remote_contents,const android::procinfo::MapInfo & boot_map)185 static ObjPtr<T> FixUpRemotePointer(ObjPtr<T> remote_ptr,
186 ArrayRef<uint8_t> remote_contents,
187 const android::procinfo::MapInfo& boot_map)
188 REQUIRES_SHARED(Locks::mutator_lock_) {
189 if (remote_ptr == nullptr) {
190 return nullptr;
191 }
192
193 uintptr_t remote = reinterpret_cast<uintptr_t>(remote_ptr.Ptr());
194
195 // In the case the remote pointer is out of range, it probably belongs to another image.
196 // Just return null for this case.
197 if (remote < boot_map.start || remote >= boot_map.end) {
198 return nullptr;
199 }
200
201 off_t boot_offset = remote - boot_map.start;
202
203 return reinterpret_cast<T*>(&remote_contents[boot_offset]);
204 }
205
206 template <typename T>
RemoteContentsPointerToLocal(ObjPtr<T> remote_ptr,ArrayRef<uint8_t> remote_contents,const ImageHeader & image_header)207 static ObjPtr<T> RemoteContentsPointerToLocal(ObjPtr<T> remote_ptr,
208 ArrayRef<uint8_t> remote_contents,
209 const ImageHeader& image_header)
210 REQUIRES_SHARED(Locks::mutator_lock_) {
211 if (remote_ptr == nullptr) {
212 return nullptr;
213 }
214
215 uint8_t* remote = reinterpret_cast<uint8_t*>(remote_ptr.Ptr());
216 ptrdiff_t boot_offset = remote - &remote_contents[0];
217
218 const uint8_t* local_ptr = reinterpret_cast<const uint8_t*>(&image_header) + boot_offset;
219
220 return reinterpret_cast<T*>(const_cast<uint8_t*>(local_ptr));
221 }
222
EntrySize(mirror::Object * object)223 size_t EntrySize(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
224 return object->SizeOf();
225 }
EntrySize(ArtMethod * art_method)226 size_t EntrySize(ArtMethod* art_method) REQUIRES_SHARED(Locks::mutator_lock_) {
227 return sizeof(*art_method);
228 }
229
230 // Print all pages the entry belongs to
PrintEntryPages(uintptr_t entry_address,size_t entry_size,std::ostream & os)231 void PrintEntryPages(uintptr_t entry_address, size_t entry_size, std::ostream& os) {
232 const char* tabs = " ";
233 const uintptr_t first_page_idx = entry_address / kPageSize;
234 const uintptr_t last_page_idx = RoundUp(entry_address + entry_size,
235 kObjectAlignment) / kPageSize;
236 for (uintptr_t page_idx = first_page_idx; page_idx <= last_page_idx; ++page_idx) {
237 os << tabs << "page_idx=" << page_idx << "\n";
238 }
239 }
240
241 // entry1 and entry2 might be relocated, this means we must use the runtime image's entry
242 // (image_entry) to avoid crashes.
243 template <typename T>
EntriesDiffer(T * image_entry,T * entry1,T * entry2)244 static bool EntriesDiffer(T* image_entry,
245 T* entry1,
246 T* entry2) REQUIRES_SHARED(Locks::mutator_lock_) {
247 // Use the image entry since entry1 and entry2 might both be remote and relocated.
248 return memcmp(entry1, entry2, EntrySize(image_entry)) != 0;
249 }
250
251 template <typename T>
252 struct RegionCommon {
253 public:
RegionCommonart::__anon3c13ab810111::RegionCommon254 RegionCommon(std::ostream* os,
255 ArrayRef<uint8_t> remote_contents,
256 ArrayRef<uint8_t> zygote_contents,
257 const android::procinfo::MapInfo& boot_map,
258 const ImageHeader& image_header) :
259 os_(*os),
260 remote_contents_(remote_contents),
261 zygote_contents_(zygote_contents),
262 boot_map_(boot_map),
263 image_header_(image_header),
264 different_entries_(0),
265 dirty_entry_bytes_(0),
266 false_dirty_entry_bytes_(0) {
267 CHECK(!remote_contents.empty());
268 }
269
DumpSamplesAndOffsetCountart::__anon3c13ab810111::RegionCommon270 void DumpSamplesAndOffsetCount() {
271 os_ << " sample object addresses: ";
272 for (size_t i = 0; i < dirty_entries_.size() && i < kMaxAddressPrint; ++i) {
273 T* entry = dirty_entries_[i];
274 os_ << reinterpret_cast<void*>(entry) << ", ";
275 }
276 os_ << "\n";
277 os_ << " dirty byte +offset:count list = ";
278 std::vector<std::pair<size_t, off_t>> field_dirty_count_sorted =
279 SortByValueDesc<off_t, size_t, size_t>(field_dirty_count_);
280 for (const std::pair<size_t, off_t>& pair : field_dirty_count_sorted) {
281 off_t offset = pair.second;
282 size_t count = pair.first;
283 os_ << "+" << offset << ":" << count << ", ";
284 }
285 os_ << "\n";
286 }
287
GetDifferentEntryCountart::__anon3c13ab810111::RegionCommon288 size_t GetDifferentEntryCount() const { return different_entries_; }
GetDirtyEntryBytesart::__anon3c13ab810111::RegionCommon289 size_t GetDirtyEntryBytes() const { return dirty_entry_bytes_; }
GetFalseDirtyEntryCountart::__anon3c13ab810111::RegionCommon290 size_t GetFalseDirtyEntryCount() const { return false_dirty_entries_.size(); }
GetFalseDirtyEntryBytesart::__anon3c13ab810111::RegionCommon291 size_t GetFalseDirtyEntryBytes() const { return false_dirty_entry_bytes_; }
292
293 protected:
IsEntryOnDirtyPageart::__anon3c13ab810111::RegionCommon294 bool IsEntryOnDirtyPage(T* entry, const std::set<size_t>& dirty_pages) const
295 REQUIRES_SHARED(Locks::mutator_lock_) {
296 size_t size = EntrySize(entry);
297 size_t page_off = 0;
298 size_t current_page_idx;
299 uintptr_t entry_address = reinterpret_cast<uintptr_t>(entry);
300 // Iterate every page this entry belongs to
301 do {
302 current_page_idx = entry_address / kPageSize + page_off;
303 if (dirty_pages.find(current_page_idx) != dirty_pages.end()) {
304 // This entry is on a dirty page
305 return true;
306 }
307 page_off++;
308 } while ((current_page_idx * kPageSize) < RoundUp(entry_address + size, kObjectAlignment));
309 return false;
310 }
311
AddImageDirtyEntryart::__anon3c13ab810111::RegionCommon312 void AddImageDirtyEntry(T* entry) REQUIRES_SHARED(Locks::mutator_lock_) {
313 image_dirty_entries_.insert(entry);
314 }
315
AddFalseDirtyEntryart::__anon3c13ab810111::RegionCommon316 void AddFalseDirtyEntry(T* entry) REQUIRES_SHARED(Locks::mutator_lock_) {
317 false_dirty_entries_.push_back(entry);
318 false_dirty_entry_bytes_ += EntrySize(entry);
319 }
320
321 // The output stream to write to.
322 std::ostream& os_;
323 // The byte contents of the remote (image) process' image.
324 ArrayRef<uint8_t> remote_contents_;
325 // The byte contents of the zygote process' image.
326 ArrayRef<uint8_t> zygote_contents_;
327 const android::procinfo::MapInfo& boot_map_;
328 const ImageHeader& image_header_;
329
330 // Count of entries that are different.
331 size_t different_entries_;
332
333 // Local entries that are dirty (differ in at least one byte).
334 size_t dirty_entry_bytes_;
335 std::vector<T*> dirty_entries_;
336
337 // Local entries that are clean, but located on dirty pages.
338 size_t false_dirty_entry_bytes_;
339 std::vector<T*> false_dirty_entries_;
340
341 // Image dirty entries
342 // If zygote_pid_only_ == true, these are shared dirty entries in the zygote.
343 // If zygote_pid_only_ == false, these are private dirty entries in the application.
344 std::set<T*> image_dirty_entries_;
345
346 std::map<off_t /* field offset */, size_t /* count */> field_dirty_count_;
347
348 private:
349 DISALLOW_COPY_AND_ASSIGN(RegionCommon);
350 };
351
352 template <typename T>
353 class RegionSpecializedBase : public RegionCommon<T> {
354 };
355
356 // Region analysis for mirror::Objects
357 class ImgObjectVisitor : public ObjectVisitor {
358 public:
359 using ComputeDirtyFunc = std::function<void(mirror::Object* object,
360 const uint8_t* begin_image_ptr,
361 const std::set<size_t>& dirty_pages)>;
ImgObjectVisitor(ComputeDirtyFunc dirty_func,const uint8_t * begin_image_ptr,const std::set<size_t> & dirty_pages)362 ImgObjectVisitor(ComputeDirtyFunc dirty_func,
363 const uint8_t* begin_image_ptr,
364 const std::set<size_t>& dirty_pages) :
365 dirty_func_(std::move(dirty_func)),
366 begin_image_ptr_(begin_image_ptr),
367 dirty_pages_(dirty_pages) { }
368
~ImgObjectVisitor()369 ~ImgObjectVisitor() override { }
370
Visit(mirror::Object * object)371 void Visit(mirror::Object* object) override REQUIRES_SHARED(Locks::mutator_lock_) {
372 // Check that we are reading a real mirror::Object
373 CHECK(object->GetClass() != nullptr) << "Image object at address "
374 << object
375 << " has null class";
376 if (kUseBakerReadBarrier) {
377 object->AssertReadBarrierState();
378 }
379 dirty_func_(object, begin_image_ptr_, dirty_pages_);
380 }
381
382 private:
383 const ComputeDirtyFunc dirty_func_;
384 const uint8_t* begin_image_ptr_;
385 const std::set<size_t>& dirty_pages_;
386 };
387
388 template<>
389 class RegionSpecializedBase<mirror::Object> : public RegionCommon<mirror::Object> {
390 public:
RegionSpecializedBase(std::ostream * os,ArrayRef<uint8_t> remote_contents,ArrayRef<uint8_t> zygote_contents,const android::procinfo::MapInfo & boot_map,const ImageHeader & image_header,bool dump_dirty_objects)391 RegionSpecializedBase(std::ostream* os,
392 ArrayRef<uint8_t> remote_contents,
393 ArrayRef<uint8_t> zygote_contents,
394 const android::procinfo::MapInfo& boot_map,
395 const ImageHeader& image_header,
396 bool dump_dirty_objects)
397 : RegionCommon<mirror::Object>(os, remote_contents, zygote_contents, boot_map, image_header),
398 os_(*os),
399 dump_dirty_objects_(dump_dirty_objects) { }
400
401 // Define a common public type name for use by RegionData.
402 using VisitorClass = ImgObjectVisitor;
403
VisitEntries(VisitorClass * visitor,uint8_t * base,PointerSize pointer_size)404 void VisitEntries(VisitorClass* visitor,
405 uint8_t* base,
406 PointerSize pointer_size)
407 REQUIRES_SHARED(Locks::mutator_lock_) {
408 RegionCommon<mirror::Object>::image_header_.VisitObjects(visitor, base, pointer_size);
409 }
410
VisitEntry(mirror::Object * entry)411 void VisitEntry(mirror::Object* entry)
412 REQUIRES_SHARED(Locks::mutator_lock_) {
413 // Unconditionally store the class descriptor in case we need it later
414 mirror::Class* klass = entry->GetClass();
415 class_data_[klass].descriptor = GetClassDescriptor(klass);
416 }
417
AddCleanEntry(mirror::Object * entry)418 void AddCleanEntry(mirror::Object* entry)
419 REQUIRES_SHARED(Locks::mutator_lock_) {
420 class_data_[entry->GetClass()].AddCleanObject();
421 }
422
AddFalseDirtyEntry(mirror::Object * entry)423 void AddFalseDirtyEntry(mirror::Object* entry)
424 REQUIRES_SHARED(Locks::mutator_lock_) {
425 RegionCommon<mirror::Object>::AddFalseDirtyEntry(entry);
426 class_data_[entry->GetClass()].AddFalseDirtyObject(entry);
427 }
428
AddDirtyEntry(mirror::Object * entry,mirror::Object * entry_remote)429 void AddDirtyEntry(mirror::Object* entry, mirror::Object* entry_remote)
430 REQUIRES_SHARED(Locks::mutator_lock_) {
431 size_t entry_size = EntrySize(entry);
432 ++different_entries_;
433 dirty_entry_bytes_ += entry_size;
434 // Log dirty count and objects for class objects only.
435 mirror::Class* klass = entry->GetClass();
436 if (klass->IsClassClass()) {
437 // Increment counts for the fields that are dirty
438 const uint8_t* current = reinterpret_cast<const uint8_t*>(entry);
439 const uint8_t* current_remote = reinterpret_cast<const uint8_t*>(entry_remote);
440 for (size_t i = 0; i < entry_size; ++i) {
441 if (current[i] != current_remote[i]) {
442 field_dirty_count_[i]++;
443 }
444 }
445 dirty_entries_.push_back(entry);
446 }
447 class_data_[klass].AddDirtyObject(entry, entry_remote);
448 }
449
DiffEntryContents(mirror::Object * entry,uint8_t * remote_bytes,const uint8_t * base_ptr,bool log_dirty_objects,size_t entry_offset)450 void DiffEntryContents(mirror::Object* entry,
451 uint8_t* remote_bytes,
452 const uint8_t* base_ptr,
453 bool log_dirty_objects,
454 size_t entry_offset) REQUIRES_SHARED(Locks::mutator_lock_) {
455 const char* tabs = " ";
456 // Attempt to find fields for all dirty bytes.
457 mirror::Class* klass = entry->GetClass();
458 std::string temp;
459 if (entry->IsClass()) {
460 os_ << tabs
461 << "Class " << mirror::Class::PrettyClass(entry->AsClass()) << " " << entry << "\n";
462 os_ << tabs << "dirty_obj: " << entry_offset << " class "
463 << entry->AsClass()->DescriptorHash() << "\n";
464 } else {
465 os_ << tabs
466 << "Instance of " << mirror::Class::PrettyClass(klass) << " " << entry << "\n";
467 os_ << tabs << "dirty_obj: " << entry_offset << " instance " << klass->DescriptorHash()
468 << "\n";
469 }
470 PrintEntryPages(reinterpret_cast<uintptr_t>(entry), EntrySize(entry), os_);
471
472 std::unordered_set<ArtField*> dirty_instance_fields;
473 std::unordered_set<ArtField*> dirty_static_fields;
474 // Examine the bytes comprising the Object, computing which fields are dirty
475 // and recording them for later display. If the Object is an array object,
476 // compute the dirty entries.
477 mirror::Object* remote_entry = reinterpret_cast<mirror::Object*>(remote_bytes);
478 for (size_t i = 0, count = entry->SizeOf(); i < count; ++i) {
479 if (base_ptr[i] != remote_bytes[i]) {
480 ArtField* field = ArtField::FindInstanceFieldWithOffset</*exact*/false>(klass, i);
481 if (field != nullptr) {
482 dirty_instance_fields.insert(field);
483 } else if (entry->IsClass()) {
484 field = ArtField::FindStaticFieldWithOffset</*exact*/false>(entry->AsClass(), i);
485 if (field != nullptr) {
486 dirty_static_fields.insert(field);
487 }
488 }
489 if (field == nullptr) {
490 if (klass->IsArrayClass()) {
491 ObjPtr<mirror::Class> component_type = klass->GetComponentType();
492 Primitive::Type primitive_type = component_type->GetPrimitiveType();
493 size_t component_size = Primitive::ComponentSize(primitive_type);
494 size_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value();
495 DCHECK_ALIGNED_PARAM(data_offset, component_size);
496 if (i >= data_offset) {
497 os_ << tabs << "Dirty array element " << (i - data_offset) / component_size << "\n";
498 // Skip the remaining bytes of this element to prevent spam.
499 DCHECK(IsPowerOfTwo(component_size));
500 i |= component_size - 1;
501 continue;
502 }
503 }
504 os_ << tabs << "No field for byte offset " << i << "\n";
505 }
506 }
507 }
508 // Dump different fields.
509 if (!dirty_instance_fields.empty()) {
510 os_ << tabs << "Dirty instance fields " << dirty_instance_fields.size() << "\n";
511 for (ArtField* field : dirty_instance_fields) {
512 os_ << tabs << ArtField::PrettyField(field)
513 << " original=" << PrettyFieldValue(field, entry)
514 << " remote=" << PrettyFieldValue(field, remote_entry) << "\n";
515 }
516 }
517 if (!dirty_static_fields.empty()) {
518 if (dump_dirty_objects_ && log_dirty_objects) {
519 dirty_objects_.insert(entry);
520 }
521 os_ << tabs << "Dirty static fields " << dirty_static_fields.size() << "\n";
522 for (ArtField* field : dirty_static_fields) {
523 os_ << tabs << ArtField::PrettyField(field)
524 << " original=" << PrettyFieldValue(field, entry)
525 << " remote=" << PrettyFieldValue(field, remote_entry) << "\n";
526 }
527 }
528 os_ << "\n";
529 }
530
DumpDirtyObjects()531 void DumpDirtyObjects() REQUIRES_SHARED(Locks::mutator_lock_) {
532 for (mirror::Object* obj : dirty_objects_) {
533 if (obj->IsClass()) {
534 std::string temp;
535 os_ << "Private dirty object: " << obj->AsClass()->GetDescriptor(&temp) << "\n";
536 }
537 }
538 }
539
DumpDirtyEntries()540 void DumpDirtyEntries() REQUIRES_SHARED(Locks::mutator_lock_) {
541 // vector of pairs (size_t count, Class*)
542 auto dirty_object_class_values =
543 SortByValueDesc<mirror::Class*, size_t, ClassData>(
544 class_data_,
545 [](const ClassData& d) { return d.dirty_object_count; });
546 os_ << "\n" << " Dirty object count by class:\n";
547 for (const auto& vk_pair : dirty_object_class_values) {
548 size_t dirty_object_count = vk_pair.first;
549 mirror::Class* klass = vk_pair.second;
550 ClassData& class_data = class_data_[klass];
551 size_t object_sizes = class_data.dirty_object_size_in_bytes;
552 float avg_dirty_bytes_per_class =
553 class_data.dirty_object_byte_count * 1.0f / object_sizes;
554 float avg_object_size = object_sizes * 1.0f / dirty_object_count;
555 const std::string& descriptor = class_data.descriptor;
556 os_ << " " << mirror::Class::PrettyClass(klass) << " ("
557 << "objects: " << dirty_object_count << ", "
558 << "avg dirty bytes: " << avg_dirty_bytes_per_class << ", "
559 << "avg object size: " << avg_object_size << ", "
560 << "class descriptor: '" << descriptor << "'"
561 << ")\n";
562 if (strcmp(descriptor.c_str(), "Ljava/lang/Class;") == 0) {
563 DumpSamplesAndOffsetCount();
564 os_ << " field contents:\n";
565 for (mirror::Object* object : class_data.dirty_objects) {
566 // remote class object
567 ObjPtr<mirror::Class> remote_klass =
568 ObjPtr<mirror::Class>::DownCast<mirror::Object>(object);
569 // local class object
570 ObjPtr<mirror::Class> local_klass =
571 RemoteContentsPointerToLocal(remote_klass,
572 RegionCommon<mirror::Object>::remote_contents_,
573 RegionCommon<mirror::Object>::image_header_);
574 os_ << " " << reinterpret_cast<const void*>(object) << " ";
575 os_ << " class_status (remote): " << remote_klass->GetStatus() << ", ";
576 os_ << " class_status (local): " << local_klass->GetStatus();
577 os_ << "\n";
578 }
579 }
580 }
581 }
582
DumpFalseDirtyEntries()583 void DumpFalseDirtyEntries() REQUIRES_SHARED(Locks::mutator_lock_) {
584 // vector of pairs (size_t count, Class*)
585 auto false_dirty_object_class_values =
586 SortByValueDesc<mirror::Class*, size_t, ClassData>(
587 class_data_,
588 [](const ClassData& d) { return d.false_dirty_object_count; });
589 os_ << "\n" << " False-dirty object count by class:\n";
590 for (const auto& vk_pair : false_dirty_object_class_values) {
591 size_t object_count = vk_pair.first;
592 mirror::Class* klass = vk_pair.second;
593 ClassData& class_data = class_data_[klass];
594 size_t object_sizes = class_data.false_dirty_byte_count;
595 float avg_object_size = object_sizes * 1.0f / object_count;
596 const std::string& descriptor = class_data.descriptor;
597 os_ << " " << mirror::Class::PrettyClass(klass) << " ("
598 << "objects: " << object_count << ", "
599 << "avg object size: " << avg_object_size << ", "
600 << "total bytes: " << object_sizes << ", "
601 << "class descriptor: '" << descriptor << "'"
602 << ")\n";
603 }
604 }
605
DumpCleanEntries()606 void DumpCleanEntries() REQUIRES_SHARED(Locks::mutator_lock_) {
607 // vector of pairs (size_t count, Class*)
608 auto clean_object_class_values =
609 SortByValueDesc<mirror::Class*, size_t, ClassData>(
610 class_data_,
611 [](const ClassData& d) { return d.clean_object_count; });
612 os_ << "\n" << " Clean object count by class:\n";
613 for (const auto& vk_pair : clean_object_class_values) {
614 os_ << " " << mirror::Class::PrettyClass(vk_pair.second) << " (" << vk_pair.first << ")\n";
615 }
616 }
617
618 private:
619 // Aggregate and detail class data from an image diff.
620 struct ClassData {
621 size_t dirty_object_count = 0;
622 // Track only the byte-per-byte dirtiness (in bytes)
623 size_t dirty_object_byte_count = 0;
624 // Track the object-by-object dirtiness (in bytes)
625 size_t dirty_object_size_in_bytes = 0;
626 size_t clean_object_count = 0;
627 std::string descriptor;
628 size_t false_dirty_byte_count = 0;
629 size_t false_dirty_object_count = 0;
630 std::vector<mirror::Object*> false_dirty_objects;
631 // Remote pointers to dirty objects
632 std::vector<mirror::Object*> dirty_objects;
633
AddCleanObjectart::__anon3c13ab810111::RegionSpecializedBase::ClassData634 void AddCleanObject() REQUIRES_SHARED(Locks::mutator_lock_) {
635 ++clean_object_count;
636 }
637
AddDirtyObjectart::__anon3c13ab810111::RegionSpecializedBase::ClassData638 void AddDirtyObject(mirror::Object* object, mirror::Object* object_remote)
639 REQUIRES_SHARED(Locks::mutator_lock_) {
640 ++dirty_object_count;
641 dirty_object_byte_count += CountDirtyBytes(object, object_remote);
642 dirty_object_size_in_bytes += EntrySize(object);
643 dirty_objects.push_back(object_remote);
644 }
645
AddFalseDirtyObjectart::__anon3c13ab810111::RegionSpecializedBase::ClassData646 void AddFalseDirtyObject(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
647 ++false_dirty_object_count;
648 false_dirty_objects.push_back(object);
649 false_dirty_byte_count += EntrySize(object);
650 }
651
652 private:
653 // Go byte-by-byte and figure out what exactly got dirtied
CountDirtyBytesart::__anon3c13ab810111::RegionSpecializedBase::ClassData654 static size_t CountDirtyBytes(mirror::Object* object1, mirror::Object* object2)
655 REQUIRES_SHARED(Locks::mutator_lock_) {
656 const uint8_t* cur1 = reinterpret_cast<const uint8_t*>(object1);
657 const uint8_t* cur2 = reinterpret_cast<const uint8_t*>(object2);
658 size_t dirty_bytes = 0;
659 size_t object_size = EntrySize(object1);
660 for (size_t i = 0; i < object_size; ++i) {
661 if (cur1[i] != cur2[i]) {
662 dirty_bytes++;
663 }
664 }
665 return dirty_bytes;
666 }
667 };
668
669 std::ostream& os_;
670 bool dump_dirty_objects_;
671 std::unordered_set<mirror::Object*> dirty_objects_;
672 std::map<mirror::Class*, ClassData> class_data_;
673
674 DISALLOW_COPY_AND_ASSIGN(RegionSpecializedBase);
675 };
676
677 // Region analysis for ArtMethods.
678 class ImgArtMethodVisitor {
679 public:
680 using ComputeDirtyFunc = std::function<void(ArtMethod*,
681 const uint8_t*,
682 const std::set<size_t>&)>;
ImgArtMethodVisitor(ComputeDirtyFunc dirty_func,const uint8_t * begin_image_ptr,const std::set<size_t> & dirty_pages)683 ImgArtMethodVisitor(ComputeDirtyFunc dirty_func,
684 const uint8_t* begin_image_ptr,
685 const std::set<size_t>& dirty_pages) :
686 dirty_func_(std::move(dirty_func)),
687 begin_image_ptr_(begin_image_ptr),
688 dirty_pages_(dirty_pages) { }
operator ()(ArtMethod & method) const689 void operator()(ArtMethod& method) const {
690 dirty_func_(&method, begin_image_ptr_, dirty_pages_);
691 }
692
693 private:
694 const ComputeDirtyFunc dirty_func_;
695 const uint8_t* begin_image_ptr_;
696 const std::set<size_t>& dirty_pages_;
697 };
698
699 // Struct and functor for computing offsets of members of ArtMethods.
700 // template <typename RegionType>
701 struct MemberInfo {
702 template <typename T>
operator ()art::__anon3c13ab810111::MemberInfo703 void operator() (const ArtMethod* method, const T* member_address, const std::string& name) {
704 // Check that member_address is a pointer inside *method.
705 DCHECK(reinterpret_cast<uintptr_t>(method) <= reinterpret_cast<uintptr_t>(member_address));
706 DCHECK(reinterpret_cast<uintptr_t>(member_address) + sizeof(T) <=
707 reinterpret_cast<uintptr_t>(method) + sizeof(ArtMethod));
708 size_t offset =
709 reinterpret_cast<uintptr_t>(member_address) - reinterpret_cast<uintptr_t>(method);
710 offset_to_name_size_.insert({offset, NameAndSize(sizeof(T), name)});
711 }
712
713 struct NameAndSize {
714 size_t size_;
715 std::string name_;
NameAndSizeart::__anon3c13ab810111::MemberInfo::NameAndSize716 NameAndSize(size_t size, const std::string& name) : size_(size), name_(name) { }
NameAndSizeart::__anon3c13ab810111::MemberInfo::NameAndSize717 NameAndSize() : size_(0), name_("INVALID") { }
718 };
719
720 std::map<size_t, NameAndSize> offset_to_name_size_;
721 };
722
723 template<>
724 class RegionSpecializedBase<ArtMethod> : public RegionCommon<ArtMethod> {
725 public:
RegionSpecializedBase(std::ostream * os,ArrayRef<uint8_t> remote_contents,ArrayRef<uint8_t> zygote_contents,const android::procinfo::MapInfo & boot_map,const ImageHeader & image_header,bool dump_dirty_objects ATTRIBUTE_UNUSED)726 RegionSpecializedBase(std::ostream* os,
727 ArrayRef<uint8_t> remote_contents,
728 ArrayRef<uint8_t> zygote_contents,
729 const android::procinfo::MapInfo& boot_map,
730 const ImageHeader& image_header,
731 bool dump_dirty_objects ATTRIBUTE_UNUSED)
732 : RegionCommon<ArtMethod>(os, remote_contents, zygote_contents, boot_map, image_header),
733 os_(*os) {
734 // Prepare the table for offset to member lookups.
735 ArtMethod* art_method = reinterpret_cast<ArtMethod*>(&remote_contents[0]);
736 art_method->VisitMembers(member_info_);
737 // Prepare the table for address to symbolic entry point names.
738 BuildEntryPointNames();
739 class_linker_ = Runtime::Current()->GetClassLinker();
740 }
741
742 // Define a common public type name for use by RegionData.
743 using VisitorClass = ImgArtMethodVisitor;
744
VisitEntries(VisitorClass * visitor,uint8_t * base,PointerSize pointer_size)745 void VisitEntries(VisitorClass* visitor,
746 uint8_t* base,
747 PointerSize pointer_size)
748 REQUIRES_SHARED(Locks::mutator_lock_) {
749 RegionCommon<ArtMethod>::image_header_.VisitPackedArtMethods(*visitor, base, pointer_size);
750 }
751
VisitEntry(ArtMethod * method ATTRIBUTE_UNUSED)752 void VisitEntry(ArtMethod* method ATTRIBUTE_UNUSED)
753 REQUIRES_SHARED(Locks::mutator_lock_) {
754 }
755
AddCleanEntry(ArtMethod * method ATTRIBUTE_UNUSED)756 void AddCleanEntry(ArtMethod* method ATTRIBUTE_UNUSED) {
757 }
758
AddFalseDirtyEntry(ArtMethod * method)759 void AddFalseDirtyEntry(ArtMethod* method)
760 REQUIRES_SHARED(Locks::mutator_lock_) {
761 RegionCommon<ArtMethod>::AddFalseDirtyEntry(method);
762 }
763
AddDirtyEntry(ArtMethod * method,ArtMethod * method_remote)764 void AddDirtyEntry(ArtMethod* method, ArtMethod* method_remote)
765 REQUIRES_SHARED(Locks::mutator_lock_) {
766 size_t entry_size = EntrySize(method);
767 ++different_entries_;
768 dirty_entry_bytes_ += entry_size;
769 // Increment counts for the fields that are dirty
770 const uint8_t* current = reinterpret_cast<const uint8_t*>(method);
771 const uint8_t* current_remote = reinterpret_cast<const uint8_t*>(method_remote);
772 // ArtMethods always log their dirty count and entries.
773 for (size_t i = 0; i < entry_size; ++i) {
774 if (current[i] != current_remote[i]) {
775 field_dirty_count_[i]++;
776 }
777 }
778 dirty_entries_.push_back(method);
779 }
780
DiffEntryContents(ArtMethod * method,uint8_t * remote_bytes,const uint8_t * base_ptr,bool log_dirty_objects ATTRIBUTE_UNUSED,size_t entry_offset ATTRIBUTE_UNUSED)781 void DiffEntryContents(ArtMethod* method,
782 uint8_t* remote_bytes,
783 const uint8_t* base_ptr,
784 bool log_dirty_objects ATTRIBUTE_UNUSED,
785 size_t entry_offset ATTRIBUTE_UNUSED)
786 REQUIRES_SHARED(Locks::mutator_lock_) {
787 const char* tabs = " ";
788 os_ << tabs << "ArtMethod " << ArtMethod::PrettyMethod(method) << "\n";
789 PrintEntryPages(reinterpret_cast<uintptr_t>(method), EntrySize(method), os_);
790
791 std::unordered_set<size_t> dirty_members;
792 // Examine the members comprising the ArtMethod, computing which members are dirty.
793 for (const std::pair<const size_t,
794 MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) {
795 const size_t offset = p.first;
796 if (memcmp(base_ptr + offset, remote_bytes + offset, p.second.size_) != 0) {
797 dirty_members.insert(p.first);
798 }
799 }
800 // Dump different fields.
801 if (!dirty_members.empty()) {
802 os_ << tabs << "Dirty members " << dirty_members.size() << "\n";
803 for (size_t offset : dirty_members) {
804 const MemberInfo::NameAndSize& member_info = member_info_.offset_to_name_size_[offset];
805 os_ << tabs << member_info.name_
806 << " original=" << StringFromBytes(base_ptr + offset, member_info.size_)
807 << " remote=" << StringFromBytes(remote_bytes + offset, member_info.size_)
808 << "\n";
809 }
810 }
811 os_ << "\n";
812 }
813
DumpDirtyObjects()814 void DumpDirtyObjects() REQUIRES_SHARED(Locks::mutator_lock_) {
815 }
816
DumpDirtyEntries()817 void DumpDirtyEntries() REQUIRES_SHARED(Locks::mutator_lock_) {
818 DumpSamplesAndOffsetCount();
819 os_ << " offset to field map:\n";
820 for (const std::pair<const size_t,
821 MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) {
822 const size_t offset = p.first;
823 const size_t size = p.second.size_;
824 os_ << StringPrintf(" %zu-%zu: ", offset, offset + size - 1)
825 << p.second.name_
826 << std::endl;
827 }
828
829 os_ << " field contents:\n";
830 for (ArtMethod* method : dirty_entries_) {
831 // remote method
832 auto art_method = reinterpret_cast<ArtMethod*>(method);
833 // remote class
834 ObjPtr<mirror::Class> remote_declaring_class =
835 FixUpRemotePointer(art_method->GetDeclaringClass(),
836 RegionCommon<ArtMethod>::remote_contents_,
837 RegionCommon<ArtMethod>::boot_map_);
838 // local class
839 ObjPtr<mirror::Class> declaring_class =
840 RemoteContentsPointerToLocal(remote_declaring_class,
841 RegionCommon<ArtMethod>::remote_contents_,
842 RegionCommon<ArtMethod>::image_header_);
843 DumpOneArtMethod(art_method, declaring_class, remote_declaring_class);
844 }
845 }
846
DumpFalseDirtyEntries()847 void DumpFalseDirtyEntries() REQUIRES_SHARED(Locks::mutator_lock_) {
848 os_ << "\n" << " False-dirty ArtMethods\n";
849 os_ << " field contents:\n";
850 for (ArtMethod* method : false_dirty_entries_) {
851 // local class
852 ObjPtr<mirror::Class> declaring_class = method->GetDeclaringClass();
853 DumpOneArtMethod(method, declaring_class, nullptr);
854 }
855 }
856
DumpCleanEntries()857 void DumpCleanEntries() REQUIRES_SHARED(Locks::mutator_lock_) {
858 }
859
860 private:
861 std::ostream& os_;
862 MemberInfo member_info_;
863 std::map<const void*, std::string> entry_point_names_;
864 ClassLinker* class_linker_;
865
866 // Compute a map of addresses to names in the boot OAT file(s).
BuildEntryPointNames()867 void BuildEntryPointNames() {
868 OatFileManager& oat_file_manager = Runtime::Current()->GetOatFileManager();
869 std::vector<const OatFile*> boot_oat_files = oat_file_manager.GetBootOatFiles();
870 for (const OatFile* oat_file : boot_oat_files) {
871 const OatHeader& oat_header = oat_file->GetOatHeader();
872 const void* jdl = oat_header.GetJniDlsymLookupTrampoline();
873 if (jdl != nullptr) {
874 entry_point_names_[jdl] = "JniDlsymLookupTrampoline (from boot oat file)";
875 }
876 const void* jdlc = oat_header.GetJniDlsymLookupCriticalTrampoline();
877 if (jdlc != nullptr) {
878 entry_point_names_[jdlc] = "JniDlsymLookupCriticalTrampoline (from boot oat file)";
879 }
880 const void* qgjt = oat_header.GetQuickGenericJniTrampoline();
881 if (qgjt != nullptr) {
882 entry_point_names_[qgjt] = "QuickGenericJniTrampoline (from boot oat file)";
883 }
884 const void* qrt = oat_header.GetQuickResolutionTrampoline();
885 if (qrt != nullptr) {
886 entry_point_names_[qrt] = "QuickResolutionTrampoline (from boot oat file)";
887 }
888 const void* qict = oat_header.GetQuickImtConflictTrampoline();
889 if (qict != nullptr) {
890 entry_point_names_[qict] = "QuickImtConflictTrampoline (from boot oat file)";
891 }
892 const void* q2ib = oat_header.GetQuickToInterpreterBridge();
893 if (q2ib != nullptr) {
894 entry_point_names_[q2ib] = "QuickToInterpreterBridge (from boot oat file)";
895 }
896 }
897 }
898
StringFromBytes(const uint8_t * bytes,size_t size)899 std::string StringFromBytes(const uint8_t* bytes, size_t size) {
900 switch (size) {
901 case 1:
902 return StringPrintf("%" PRIx8, *bytes);
903 case 2:
904 return StringPrintf("%" PRIx16, *reinterpret_cast<const uint16_t*>(bytes));
905 case 4:
906 case 8: {
907 // Compute an address if the bytes might contain one.
908 uint64_t intval;
909 if (size == 4) {
910 intval = *reinterpret_cast<const uint32_t*>(bytes);
911 } else {
912 intval = *reinterpret_cast<const uint64_t*>(bytes);
913 }
914 const void* addr = reinterpret_cast<const void*>(intval);
915 // Match the address against those that have Is* methods in the ClassLinker.
916 if (class_linker_->IsQuickToInterpreterBridge(addr)) {
917 return "QuickToInterpreterBridge";
918 } else if (class_linker_->IsQuickGenericJniStub(addr)) {
919 return "QuickGenericJniStub";
920 } else if (class_linker_->IsQuickResolutionStub(addr)) {
921 return "QuickResolutionStub";
922 } else if (class_linker_->IsJniDlsymLookupStub(addr)) {
923 return "JniDlsymLookupStub";
924 } else if (class_linker_->IsJniDlsymLookupCriticalStub(addr)) {
925 return "JniDlsymLookupCriticalStub";
926 }
927 // Match the address against those that we saved from the boot OAT files.
928 if (entry_point_names_.find(addr) != entry_point_names_.end()) {
929 return entry_point_names_[addr];
930 }
931 return StringPrintf("%" PRIx64, intval);
932 }
933 default:
934 LOG(WARNING) << "Don't know how to convert " << size << " bytes to integer";
935 return "<UNKNOWN>";
936 }
937 }
938
DumpOneArtMethod(ArtMethod * art_method,ObjPtr<mirror::Class> declaring_class,ObjPtr<mirror::Class> remote_declaring_class)939 void DumpOneArtMethod(ArtMethod* art_method,
940 ObjPtr<mirror::Class> declaring_class,
941 ObjPtr<mirror::Class> remote_declaring_class)
942 REQUIRES_SHARED(Locks::mutator_lock_) {
943 PointerSize pointer_size = InstructionSetPointerSize(Runtime::Current()->GetInstructionSet());
944 os_ << " " << reinterpret_cast<const void*>(art_method) << " ";
945 os_ << " entryPointFromJni: "
946 << reinterpret_cast<const void*>(art_method->GetDataPtrSize(pointer_size)) << ", ";
947 os_ << " entryPointFromQuickCompiledCode: "
948 << reinterpret_cast<const void*>(
949 art_method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size))
950 << ", ";
951 os_ << " isNative? " << (art_method->IsNative() ? "yes" : "no") << ", ";
952 // Null for runtime metionds.
953 if (declaring_class != nullptr) {
954 os_ << " class_status (local): " << declaring_class->GetStatus();
955 }
956 if (remote_declaring_class != nullptr) {
957 os_ << ", class_status (remote): " << remote_declaring_class->GetStatus();
958 }
959 os_ << "\n";
960 }
961
962 DISALLOW_COPY_AND_ASSIGN(RegionSpecializedBase);
963 };
964
965 template <typename T>
966 class RegionData : public RegionSpecializedBase<T> {
967 public:
RegionData(std::ostream * os,ArrayRef<uint8_t> remote_contents,ArrayRef<uint8_t> zygote_contents,const android::procinfo::MapInfo & boot_map,const ImageHeader & image_header,bool dump_dirty_objects)968 RegionData(std::ostream* os,
969 ArrayRef<uint8_t> remote_contents,
970 ArrayRef<uint8_t> zygote_contents,
971 const android::procinfo::MapInfo& boot_map,
972 const ImageHeader& image_header,
973 bool dump_dirty_objects)
974 : RegionSpecializedBase<T>(os,
975 remote_contents,
976 zygote_contents,
977 boot_map,
978 image_header,
979 dump_dirty_objects),
980 os_(*os) {
981 CHECK(!remote_contents.empty());
982 }
983
984 // Walk over the type T entries in theregion between begin_image_ptr and end_image_ptr,
985 // collecting and reporting data regarding dirty, difference, etc.
ProcessRegion(const MappingData & mapping_data,RemoteProcesses remotes,const uint8_t * begin_image_ptr)986 void ProcessRegion(const MappingData& mapping_data,
987 RemoteProcesses remotes,
988 const uint8_t* begin_image_ptr)
989 REQUIRES_SHARED(Locks::mutator_lock_) {
990 typename RegionSpecializedBase<T>::VisitorClass visitor(
991 [this](T* entry,
992 const uint8_t* begin_image_ptr,
993 const std::set<size_t>& dirty_page_set) REQUIRES_SHARED(Locks::mutator_lock_) {
994 this->ComputeEntryDirty(entry, begin_image_ptr, dirty_page_set);
995 },
996 begin_image_ptr,
997 mapping_data.dirty_page_set);
998 PointerSize pointer_size = InstructionSetPointerSize(Runtime::Current()->GetInstructionSet());
999 RegionSpecializedBase<T>::VisitEntries(&visitor,
1000 const_cast<uint8_t*>(begin_image_ptr),
1001 pointer_size);
1002
1003 // Looking at only dirty pages, figure out how many of those bytes belong to dirty entries.
1004 // TODO: fix this now that there are multiple regions in a mapping.
1005 float true_dirtied_percent =
1006 RegionCommon<T>::GetDirtyEntryBytes() * 1.0f / (mapping_data.dirty_pages * kPageSize);
1007
1008 // Entry specific statistics.
1009 os_ << RegionCommon<T>::GetDifferentEntryCount() << " different entries, \n "
1010 << RegionCommon<T>::GetDirtyEntryBytes() << " different entry [bytes], \n "
1011 << RegionCommon<T>::GetFalseDirtyEntryCount() << " false dirty entries,\n "
1012 << RegionCommon<T>::GetFalseDirtyEntryBytes() << " false dirty entry [bytes], \n "
1013 << true_dirtied_percent << " different entries-vs-total in a dirty page;\n "
1014 << "\n";
1015
1016 const uint8_t* base_ptr = begin_image_ptr;
1017 switch (remotes) {
1018 case RemoteProcesses::kZygoteOnly:
1019 os_ << " Zygote shared dirty entries: ";
1020 break;
1021 case RemoteProcesses::kImageAndZygote:
1022 os_ << " Application dirty entries (private dirty): ";
1023 // If we are dumping private dirty, diff against the zygote map to make it clearer what
1024 // fields caused the page to be private dirty.
1025 base_ptr = RegionCommon<T>::zygote_contents_.data();
1026 break;
1027 case RemoteProcesses::kImageOnly:
1028 os_ << " Application dirty entries (unknown whether private or shared dirty): ";
1029 break;
1030 }
1031 DiffDirtyEntries(RegionCommon<T>::image_dirty_entries_,
1032 begin_image_ptr,
1033 RegionCommon<T>::remote_contents_,
1034 base_ptr,
1035 /*log_dirty_objects=*/true);
1036 RegionSpecializedBase<T>::DumpDirtyObjects();
1037 RegionSpecializedBase<T>::DumpDirtyEntries();
1038 RegionSpecializedBase<T>::DumpFalseDirtyEntries();
1039 RegionSpecializedBase<T>::DumpCleanEntries();
1040 }
1041
1042 private:
1043 std::ostream& os_;
1044
DiffDirtyEntries(const std::set<T * > & entries,const uint8_t * begin_image_ptr,ArrayRef<uint8_t> contents,const uint8_t * base_ptr,bool log_dirty_objects)1045 void DiffDirtyEntries(const std::set<T*>& entries,
1046 const uint8_t* begin_image_ptr,
1047 ArrayRef<uint8_t> contents,
1048 const uint8_t* base_ptr,
1049 bool log_dirty_objects)
1050 REQUIRES_SHARED(Locks::mutator_lock_) {
1051 os_ << RegionCommon<T>::dirty_entries_.size() << "\n";
1052 for (T* entry : entries) {
1053 uint8_t* entry_bytes = reinterpret_cast<uint8_t*>(entry);
1054 ptrdiff_t offset = entry_bytes - begin_image_ptr;
1055 uint8_t* remote_bytes = &contents[offset];
1056 RegionSpecializedBase<T>::DiffEntryContents(
1057 entry, remote_bytes, &base_ptr[offset], log_dirty_objects, static_cast<size_t>(offset));
1058 }
1059 }
1060
ComputeEntryDirty(T * entry,const uint8_t * begin_image_ptr,const std::set<size_t> & dirty_pages)1061 void ComputeEntryDirty(T* entry,
1062 const uint8_t* begin_image_ptr,
1063 const std::set<size_t>& dirty_pages)
1064 REQUIRES_SHARED(Locks::mutator_lock_) {
1065 // Set up pointers in the remote and the zygote for comparison.
1066 uint8_t* current = reinterpret_cast<uint8_t*>(entry);
1067 ptrdiff_t offset = current - begin_image_ptr;
1068 T* entry_remote =
1069 reinterpret_cast<T*>(const_cast<uint8_t*>(&RegionCommon<T>::remote_contents_[offset]));
1070 const bool have_zygote = !RegionCommon<T>::zygote_contents_.empty();
1071 const uint8_t* current_zygote =
1072 have_zygote ? &RegionCommon<T>::zygote_contents_[offset] : nullptr;
1073 T* entry_zygote = reinterpret_cast<T*>(const_cast<uint8_t*>(current_zygote));
1074 // Visit and classify entries at the current location.
1075 RegionSpecializedBase<T>::VisitEntry(entry);
1076
1077 // Test private dirty first.
1078 bool is_dirty = false;
1079 if (have_zygote) {
1080 if (EntriesDiffer(entry, entry_zygote, entry_remote)) {
1081 // Private dirty, app vs zygote.
1082 is_dirty = true;
1083 RegionCommon<T>::AddImageDirtyEntry(entry);
1084 }
1085 } else if (EntriesDiffer(entry, entry_remote, entry)) {
1086 // Shared or private dirty, app vs image.
1087 is_dirty = true;
1088 RegionCommon<T>::AddImageDirtyEntry(entry);
1089 }
1090 if (is_dirty) {
1091 // TODO: Add support dirty entries in zygote and image.
1092 RegionSpecializedBase<T>::AddDirtyEntry(entry, entry_remote);
1093 } else {
1094 RegionSpecializedBase<T>::AddCleanEntry(entry);
1095 if (RegionCommon<T>::IsEntryOnDirtyPage(entry, dirty_pages)) {
1096 // This entry was either never mutated or got mutated back to the same value.
1097 // TODO: Do I want to distinguish a "different" vs a "dirty" page here?
1098 RegionSpecializedBase<T>::AddFalseDirtyEntry(entry);
1099 }
1100 }
1101 }
1102
1103 DISALLOW_COPY_AND_ASSIGN(RegionData);
1104 };
1105
1106 } // namespace
1107
1108
1109 class ImgDiagDumper {
1110 public:
ImgDiagDumper(std::ostream * os,pid_t image_diff_pid,pid_t zygote_diff_pid,bool dump_dirty_objects)1111 explicit ImgDiagDumper(std::ostream* os,
1112 pid_t image_diff_pid,
1113 pid_t zygote_diff_pid,
1114 bool dump_dirty_objects)
1115 : os_(os),
1116 image_diff_pid_(image_diff_pid),
1117 zygote_diff_pid_(zygote_diff_pid),
1118 dump_dirty_objects_(dump_dirty_objects),
1119 zygote_pid_only_(false) {}
1120
Init()1121 bool Init() {
1122 std::ostream& os = *os_;
1123
1124 if (image_diff_pid_ < 0 || zygote_diff_pid_ < 0) {
1125 // TODO: ComputeDirtyBytes must be modified
1126 // to support single app/zygote to bootimage comparison
1127 os << "Both --image-diff-pid and --zygote-diff-pid must be specified.\n";
1128 return false;
1129 }
1130
1131 // To avoid the combinations of command-line argument use cases:
1132 // If the user invoked with only --zygote-diff-pid, shuffle that to
1133 // image_diff_pid_, invalidate zygote_diff_pid_, and remember that
1134 // image_diff_pid_ is now special.
1135 if (image_diff_pid_ < 0) {
1136 image_diff_pid_ = zygote_diff_pid_;
1137 zygote_diff_pid_ = -1;
1138 zygote_pid_only_ = true;
1139 }
1140
1141 {
1142 struct stat sts;
1143 std::string proc_pid_str =
1144 StringPrintf("/proc/%ld", static_cast<long>(image_diff_pid_)); // NOLINT [runtime/int]
1145 if (stat(proc_pid_str.c_str(), &sts) == -1) {
1146 os << "Process does not exist";
1147 return false;
1148 }
1149 }
1150
1151 auto open_proc_maps = [&os](pid_t pid,
1152 /*out*/ std::vector<android::procinfo::MapInfo>* proc_maps) {
1153 if (!android::procinfo::ReadProcessMaps(pid, proc_maps)) {
1154 os << "Could not read process maps for " << pid;
1155 return false;
1156 }
1157 return true;
1158 };
1159 auto open_file = [&os] (const char* file_name, /*out*/ std::unique_ptr<File>* file) {
1160 file->reset(OS::OpenFileForReading(file_name));
1161 if (*file == nullptr) {
1162 os << "Failed to open " << file_name << " for reading";
1163 return false;
1164 }
1165 return true;
1166 };
1167 auto open_mem_file = [&open_file](pid_t pid, /*out*/ std::unique_ptr<File>* mem_file) {
1168 // Open /proc/<pid>/mem and for reading remote contents.
1169 std::string mem_file_name =
1170 StringPrintf("/proc/%ld/mem", static_cast<long>(pid)); // NOLINT [runtime/int]
1171 return open_file(mem_file_name.c_str(), mem_file);
1172 };
1173 auto open_pagemap_file = [&open_file](pid_t pid, /*out*/ std::unique_ptr<File>* pagemap_file) {
1174 // Open /proc/<pid>/pagemap.
1175 std::string pagemap_file_name = StringPrintf(
1176 "/proc/%ld/pagemap", static_cast<long>(pid)); // NOLINT [runtime/int]
1177 return open_file(pagemap_file_name.c_str(), pagemap_file);
1178 };
1179
1180 // Open files for inspecting image memory.
1181 std::vector<android::procinfo::MapInfo> image_proc_maps;
1182 std::unique_ptr<File> image_mem_file;
1183 std::unique_ptr<File> image_pagemap_file;
1184 if (!open_proc_maps(image_diff_pid_, &image_proc_maps) ||
1185 !open_mem_file(image_diff_pid_, &image_mem_file) ||
1186 !open_pagemap_file(image_diff_pid_, &image_pagemap_file)) {
1187 return false;
1188 }
1189
1190 // If zygote_diff_pid_ != -1, open files for inspecting zygote memory.
1191 std::vector<android::procinfo::MapInfo> zygote_proc_maps;
1192 std::unique_ptr<File> zygote_mem_file;
1193 std::unique_ptr<File> zygote_pagemap_file;
1194 if (zygote_diff_pid_ != -1) {
1195 if (!open_proc_maps(zygote_diff_pid_, &zygote_proc_maps) ||
1196 !open_mem_file(zygote_diff_pid_, &zygote_mem_file) ||
1197 !open_pagemap_file(zygote_diff_pid_, &zygote_pagemap_file)) {
1198 return false;
1199 }
1200 }
1201
1202 std::unique_ptr<File> kpageflags_file;
1203 std::unique_ptr<File> kpagecount_file;
1204 if (!open_file("/proc/kpageflags", &kpageflags_file) ||
1205 !open_file("/proc/kpagecount", &kpagecount_file)) {
1206 return false;
1207 }
1208
1209 // TODO: Rewrite imgdiag to load boot image without creating a runtime.
1210
1211 // Commit the mappings and files.
1212 image_proc_maps_ = std::move(image_proc_maps);
1213 image_mem_file_ = std::move(*image_mem_file);
1214 image_pagemap_file_ = std::move(*image_pagemap_file);
1215 if (zygote_diff_pid_ != -1) {
1216 zygote_proc_maps_ = std::move(zygote_proc_maps);
1217 zygote_mem_file_ = std::move(*zygote_mem_file);
1218 zygote_pagemap_file_ = std::move(*zygote_pagemap_file);
1219 }
1220 kpageflags_file_ = std::move(*kpageflags_file);
1221 kpagecount_file_ = std::move(*kpagecount_file);
1222
1223 return true;
1224 }
1225
Dump(const ImageHeader & image_header,const std::string & image_location)1226 bool Dump(const ImageHeader& image_header, const std::string& image_location)
1227 REQUIRES_SHARED(Locks::mutator_lock_) {
1228 std::ostream& os = *os_;
1229 os << "IMAGE LOCATION: " << image_location << "\n\n";
1230
1231 os << "MAGIC: " << image_header.GetMagic() << "\n\n";
1232
1233 os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header.GetImageBegin()) << "\n\n";
1234
1235 PrintPidLine("IMAGE", image_diff_pid_);
1236 os << "\n\n";
1237 PrintPidLine("ZYGOTE", zygote_diff_pid_);
1238 bool ret = true;
1239 if (image_diff_pid_ >= 0 || zygote_diff_pid_ >= 0) {
1240 ret = DumpImageDiff(image_header, image_location);
1241 os << "\n\n";
1242 }
1243
1244 os << std::flush;
1245
1246 return ret;
1247 }
1248
1249 private:
DumpImageDiff(const ImageHeader & image_header,const std::string & image_location)1250 bool DumpImageDiff(const ImageHeader& image_header, const std::string& image_location)
1251 REQUIRES_SHARED(Locks::mutator_lock_) {
1252 return DumpImageDiffMap(image_header, image_location);
1253 }
1254
ComputeDirtyBytes(const ImageHeader & image_header,const android::procinfo::MapInfo & boot_map,ArrayRef<uint8_t> remote_contents,ArrayRef<uint8_t> zygote_contents,MappingData * mapping_data,std::string * error_msg)1255 bool ComputeDirtyBytes(const ImageHeader& image_header,
1256 const android::procinfo::MapInfo& boot_map,
1257 ArrayRef<uint8_t> remote_contents,
1258 ArrayRef<uint8_t> zygote_contents,
1259 MappingData* mapping_data /*out*/,
1260 std::string* error_msg /*out*/) {
1261 // Iterate through one page at a time. Boot map begin/end already implicitly aligned.
1262 for (uintptr_t begin = boot_map.start; begin != boot_map.end; begin += kPageSize) {
1263 const ptrdiff_t offset = begin - boot_map.start;
1264
1265 // We treat the image header as part of the memory map for now
1266 // If we wanted to change this, we could pass base=start+sizeof(ImageHeader)
1267 // But it might still be interesting to see if any of the ImageHeader data mutated
1268 const uint8_t* zygote_ptr = &zygote_contents[offset];
1269 const uint8_t* remote_ptr = &remote_contents[offset];
1270
1271 if (memcmp(zygote_ptr, remote_ptr, kPageSize) != 0) {
1272 mapping_data->different_pages++;
1273
1274 // Count the number of 32-bit integers that are different.
1275 for (size_t i = 0; i < kPageSize / sizeof(uint32_t); ++i) {
1276 const uint32_t* remote_ptr_int32 = reinterpret_cast<const uint32_t*>(remote_ptr);
1277 const uint32_t* zygote_ptr_int32 = reinterpret_cast<const uint32_t*>(zygote_ptr);
1278
1279 if (remote_ptr_int32[i] != zygote_ptr_int32[i]) {
1280 mapping_data->different_int32s++;
1281 }
1282 }
1283 // Count the number of bytes that are different.
1284 for (size_t i = 0; i < kPageSize; ++i) {
1285 if (remote_ptr[i] != zygote_ptr[i]) {
1286 mapping_data->different_bytes++;
1287 }
1288 }
1289 }
1290 }
1291
1292 for (uintptr_t begin = boot_map.start; begin != boot_map.end; begin += kPageSize) {
1293 ptrdiff_t offset = begin - boot_map.start;
1294
1295 // Virtual page number (for an absolute memory address)
1296 size_t virtual_page_idx = begin / kPageSize;
1297
1298 uint64_t page_count = 0xC0FFEE;
1299 // TODO: virtual_page_idx needs to be from the same process
1300 int dirtiness = (IsPageDirty(&image_pagemap_file_, // Image-diff-pid procmap
1301 &zygote_pagemap_file_, // Zygote procmap
1302 &kpageflags_file_,
1303 &kpagecount_file_,
1304 virtual_page_idx, // compare same page in image
1305 virtual_page_idx, // and zygote
1306 &page_count,
1307 error_msg));
1308 if (dirtiness < 0) {
1309 return false;
1310 } else if (dirtiness > 0) {
1311 mapping_data->dirty_pages++;
1312 mapping_data->dirty_page_set.insert(mapping_data->dirty_page_set.end(), virtual_page_idx);
1313 }
1314
1315 const bool is_dirty = dirtiness > 0;
1316 const bool is_private = page_count == 1;
1317
1318 if (is_private) {
1319 mapping_data->private_pages++;
1320 }
1321
1322 if (is_dirty && is_private) {
1323 mapping_data->private_dirty_pages++;
1324 for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
1325 const ImageHeader::ImageSections section = static_cast<ImageHeader::ImageSections>(i);
1326 if (image_header.GetImageSection(section).Contains(offset)) {
1327 mapping_data->private_dirty_pages_for_section[i] += 1;
1328 }
1329 }
1330 }
1331 }
1332 mapping_data->false_dirty_pages = mapping_data->dirty_pages - mapping_data->different_pages;
1333
1334 return true;
1335 }
1336
PrintMappingData(const MappingData & mapping_data,const ImageHeader & image_header)1337 void PrintMappingData(const MappingData& mapping_data, const ImageHeader& image_header) {
1338 std::ostream& os = *os_;
1339 // Print low-level (bytes, int32s, pages) statistics.
1340 os << mapping_data.different_bytes << " differing bytes,\n "
1341 << mapping_data.different_int32s << " differing int32s,\n "
1342 << mapping_data.different_pages << " differing pages,\n "
1343 << mapping_data.dirty_pages << " pages are dirty;\n "
1344 << mapping_data.false_dirty_pages << " pages are false dirty;\n "
1345 << mapping_data.private_pages << " pages are private;\n "
1346 << mapping_data.private_dirty_pages << " pages are Private_Dirty\n "
1347 << "\n";
1348
1349 size_t total_private_dirty_pages = std::accumulate(
1350 mapping_data.private_dirty_pages_for_section.begin(),
1351 mapping_data.private_dirty_pages_for_section.end(),
1352 0u);
1353 os << "Image sections (total private dirty pages " << total_private_dirty_pages << ")\n";
1354 for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
1355 const ImageHeader::ImageSections section = static_cast<ImageHeader::ImageSections>(i);
1356 os << section << " " << image_header.GetImageSection(section)
1357 << " private dirty pages=" << mapping_data.private_dirty_pages_for_section[i] << "\n";
1358 }
1359 os << "\n";
1360 }
1361
1362 // Look at /proc/$pid/mem and only diff the things from there
DumpImageDiffMap(const ImageHeader & image_header,const std::string & image_location)1363 bool DumpImageDiffMap(const ImageHeader& image_header, const std::string& image_location)
1364 REQUIRES_SHARED(Locks::mutator_lock_) {
1365 std::ostream& os = *os_;
1366 std::string error_msg;
1367
1368 std::string image_location_base_name = GetImageLocationBaseName(image_location);
1369 auto find_boot_map = [&os, &image_location_base_name](
1370 const std::vector<android::procinfo::MapInfo>& maps,
1371 const char* tag) -> std::optional<android::procinfo::MapInfo> {
1372 // Find the memory map for the current boot image component.
1373 for (const android::procinfo::MapInfo& map_info : maps) {
1374 // The map name ends with ']' if it's an anonymous memmap. We need to special case that
1375 // to find the boot image map in some cases.
1376 if (EndsWith(map_info.name, image_location_base_name) ||
1377 EndsWith(map_info.name, image_location_base_name + "]")) {
1378 if ((map_info.flags & PROT_WRITE) != 0) {
1379 return map_info;
1380 }
1381 // In actuality there's more than 1 map, but the second one is read-only.
1382 // The one we care about is the write-able map.
1383 // The readonly maps are guaranteed to be identical, so its not interesting to compare
1384 // them.
1385 }
1386 }
1387 os << "Could not find map for " << image_location_base_name << " in " << tag;
1388 return std::nullopt;
1389 };
1390
1391 // Find the current boot image mapping.
1392 std::optional<android::procinfo::MapInfo> maybe_boot_map =
1393 find_boot_map(image_proc_maps_, "image");
1394 if (!maybe_boot_map) {
1395 return false;
1396 }
1397 android::procinfo::MapInfo& boot_map = *maybe_boot_map;
1398 // Check the validity of the boot_map_.
1399 CHECK(boot_map.end >= boot_map.start);
1400
1401 // Adjust the `end` of the mapping. Some other mappings may have been
1402 // inserted within the image.
1403 boot_map.end = RoundUp(boot_map.start + image_header.GetImageSize(), kPageSize);
1404 // The size of the boot image mapping.
1405 size_t boot_map_size = boot_map.end - boot_map.start;
1406
1407 // If zygote_diff_pid_ != -1, check that the zygote boot map is the same.
1408 if (zygote_diff_pid_ != -1) {
1409 std::optional<android::procinfo::MapInfo> maybe_zygote_boot_map =
1410 find_boot_map(zygote_proc_maps_, "zygote");
1411 if (!maybe_zygote_boot_map) {
1412 return false;
1413 }
1414 android::procinfo::MapInfo& zygote_boot_map = *maybe_zygote_boot_map;
1415 // Adjust the `end` of the mapping. Some other mappings may have been
1416 // inserted within the image.
1417 zygote_boot_map.end = RoundUp(zygote_boot_map.start + image_header.GetImageSize(), kPageSize);
1418 if (zygote_boot_map.start != boot_map.start) {
1419 os << "Zygote boot map does not match image boot map: "
1420 << "zygote begin " << reinterpret_cast<const void*>(zygote_boot_map.start)
1421 << ", zygote end " << reinterpret_cast<const void*>(zygote_boot_map.end)
1422 << ", image begin " << reinterpret_cast<const void*>(boot_map.start)
1423 << ", image end " << reinterpret_cast<const void*>(boot_map.end);
1424 return false;
1425 }
1426 }
1427
1428 // Walk the bytes and diff against our boot image
1429 os << "\nObserving boot image header at address "
1430 << reinterpret_cast<const void*>(&image_header)
1431 << "\n\n";
1432
1433 const uint8_t* image_begin_unaligned = image_header.GetImageBegin();
1434 const uint8_t* image_end_unaligned = image_begin_unaligned + image_header.GetImageSize();
1435
1436 // Adjust range to nearest page
1437 const uint8_t* image_begin = AlignDown(image_begin_unaligned, kPageSize);
1438 const uint8_t* image_end = AlignUp(image_end_unaligned, kPageSize);
1439
1440 size_t image_size = image_end - image_begin;
1441 if (image_size != boot_map_size) {
1442 os << "Remote boot map size does not match local boot map size: "
1443 << "local size " << image_size
1444 << ", remote size " << boot_map_size;
1445 return false;
1446 }
1447
1448 auto read_contents = [&](File* mem_file,
1449 /*out*/ MemMap* map,
1450 /*out*/ ArrayRef<uint8_t>* contents) {
1451 DCHECK_ALIGNED(boot_map.start, kPageSize);
1452 DCHECK_ALIGNED(boot_map_size, kPageSize);
1453 std::string name = "Contents of " + mem_file->GetPath();
1454 std::string local_error_msg;
1455 // We need to use low 4 GiB memory so that we can walk the objects using standard
1456 // functions that use ObjPtr<> which is checking that it fits into lower 4 GiB.
1457 *map = MemMap::MapAnonymous(name.c_str(),
1458 boot_map_size,
1459 PROT_READ | PROT_WRITE,
1460 /* low_4gb= */ true,
1461 &local_error_msg);
1462 if (!map->IsValid()) {
1463 os << "Failed to allocate anonymous mapping for " << boot_map_size << " bytes.\n";
1464 return false;
1465 }
1466 if (!mem_file->PreadFully(map->Begin(), boot_map_size, boot_map.start)) {
1467 os << "Could not fully read file " << image_mem_file_.GetPath();
1468 return false;
1469 }
1470 *contents = ArrayRef<uint8_t>(map->Begin(), boot_map_size);
1471 return true;
1472 };
1473 // The contents of /proc/<image_diff_pid_>/mem.
1474 MemMap remote_contents_map;
1475 ArrayRef<uint8_t> remote_contents;
1476 if (!read_contents(&image_mem_file_, &remote_contents_map, &remote_contents)) {
1477 return false;
1478 }
1479 // The contents of /proc/<zygote_diff_pid_>/mem.
1480 MemMap zygote_contents_map;
1481 ArrayRef<uint8_t> zygote_contents;
1482 if (zygote_diff_pid_ != -1) {
1483 if (!read_contents(&zygote_mem_file_, &zygote_contents_map, &zygote_contents)) {
1484 return false;
1485 }
1486 }
1487
1488 // TODO: We need to update the entire diff to work with the ASLR. b/77856493
1489 // Since the images may be relocated, just check the sizes.
1490 if (static_cast<uintptr_t>(image_end - image_begin) != boot_map.end - boot_map.start) {
1491 os << "Remote boot map is a different size than local boot map: " <<
1492 "local begin " << reinterpret_cast<const void*>(image_begin) <<
1493 ", local end " << reinterpret_cast<const void*>(image_end) <<
1494 ", remote begin " << reinterpret_cast<const void*>(boot_map.start) <<
1495 ", remote end " << reinterpret_cast<const void*>(boot_map.end);
1496 return false;
1497 // For more validation should also check the ImageHeader from the file
1498 }
1499
1500
1501 RemoteProcesses remotes;
1502 if (zygote_pid_only_) {
1503 remotes = RemoteProcesses::kZygoteOnly;
1504 } else if (zygote_diff_pid_ > 0) {
1505 remotes = RemoteProcesses::kImageAndZygote;
1506 } else {
1507 remotes = RemoteProcesses::kImageOnly;
1508 }
1509
1510 // Only app vs zygote is supported at the moment
1511 CHECK_EQ(remotes, RemoteProcesses::kImageAndZygote);
1512
1513 MappingData mapping_data;
1514 if (!ComputeDirtyBytes(image_header,
1515 boot_map,
1516 remote_contents,
1517 zygote_contents,
1518 &mapping_data,
1519 &error_msg)) {
1520 os << error_msg;
1521 return false;
1522 }
1523 os << "Mapping at [" << reinterpret_cast<void*>(boot_map.start) << ", "
1524 << reinterpret_cast<void*>(boot_map.end) << ") had:\n ";
1525 PrintMappingData(mapping_data, image_header);
1526
1527 // Check all the mirror::Object entries in the image.
1528 RegionData<mirror::Object> object_region_data(os_,
1529 remote_contents,
1530 zygote_contents,
1531 boot_map,
1532 image_header,
1533 dump_dirty_objects_);
1534 object_region_data.ProcessRegion(mapping_data,
1535 remotes,
1536 image_begin_unaligned);
1537
1538 // Check all the ArtMethod entries in the image.
1539 RegionData<ArtMethod> artmethod_region_data(os_,
1540 remote_contents,
1541 zygote_contents,
1542 boot_map,
1543 image_header,
1544 dump_dirty_objects_);
1545 artmethod_region_data.ProcessRegion(mapping_data,
1546 remotes,
1547 image_begin_unaligned);
1548 return true;
1549 }
1550
1551 // Note: On failure, `*page_frame_number` shall be clobbered.
GetPageFrameNumber(File * page_map_file,size_t virtual_page_index,uint64_t * page_frame_number,std::string * error_msg)1552 static bool GetPageFrameNumber(File* page_map_file,
1553 size_t virtual_page_index,
1554 /*out*/ uint64_t* page_frame_number,
1555 /*out*/ std::string* error_msg) {
1556 CHECK(page_frame_number != nullptr);
1557 return GetPageFrameNumbers(page_map_file,
1558 virtual_page_index,
1559 ArrayRef<uint64_t>(page_frame_number, 1u),
1560 error_msg);
1561 }
1562
1563 // Note: On failure, `page_frame_numbers[.]` shall be clobbered.
GetPageFrameNumbers(File * page_map_file,size_t virtual_page_index,ArrayRef<uint64_t> page_frame_numbers,std::string * error_msg)1564 static bool GetPageFrameNumbers(File* page_map_file,
1565 size_t virtual_page_index,
1566 /*out*/ ArrayRef<uint64_t> page_frame_numbers,
1567 /*out*/ std::string* error_msg) {
1568 CHECK(page_map_file != nullptr);
1569 CHECK_NE(page_frame_numbers.size(), 0u);
1570 CHECK(page_frame_numbers.data() != nullptr);
1571 CHECK(error_msg != nullptr);
1572
1573 // Read 64-bit entries from /proc/$pid/pagemap to get the physical page frame numbers.
1574 if (!page_map_file->PreadFully(page_frame_numbers.data(),
1575 page_frame_numbers.size() * kPageMapEntrySize,
1576 virtual_page_index * kPageMapEntrySize)) {
1577 *error_msg = StringPrintf("Failed to read the virtual page index entries from %s, error: %s",
1578 page_map_file->GetPath().c_str(),
1579 strerror(errno));
1580 return false;
1581 }
1582
1583 // Extract page frame numbers from pagemap entries.
1584 for (uint64_t& page_frame_number : page_frame_numbers) {
1585 page_frame_number &= kPageFrameNumberMask;
1586 }
1587
1588 return true;
1589 }
1590
1591 // Note: On failure, `page_flags_or_counts[.]` shall be clobbered.
GetPageFlagsOrCounts(File * kpage_file,ArrayRef<const uint64_t> page_frame_numbers,ArrayRef<uint64_t> page_flags_or_counts,std::string * error_msg)1592 static bool GetPageFlagsOrCounts(File* kpage_file,
1593 ArrayRef<const uint64_t> page_frame_numbers,
1594 /*out*/ ArrayRef<uint64_t> page_flags_or_counts,
1595 /*out*/ std::string* error_msg) {
1596 static_assert(kPageFlagsEntrySize == kPageCountEntrySize, "entry size check");
1597 CHECK_NE(page_frame_numbers.size(), 0u);
1598 CHECK_EQ(page_flags_or_counts.size(), page_frame_numbers.size());
1599 CHECK(kpage_file != nullptr);
1600 CHECK(page_frame_numbers.data() != nullptr);
1601 CHECK(page_flags_or_counts.data() != nullptr);
1602 CHECK(error_msg != nullptr);
1603
1604 size_t size = page_frame_numbers.size();
1605 size_t i = 0;
1606 while (i != size) {
1607 size_t start = i;
1608 ++i;
1609 while (i != size && page_frame_numbers[i] - page_frame_numbers[start] == i - start) {
1610 ++i;
1611 }
1612 // Read 64-bit entries from /proc/kpageflags or /proc/kpagecount.
1613 if (!kpage_file->PreadFully(page_flags_or_counts.data() + start,
1614 (i - start) * kPageMapEntrySize,
1615 page_frame_numbers[start] * kPageFlagsEntrySize)) {
1616 *error_msg = StringPrintf("Failed to read the page flags or counts from %s, error: %s",
1617 kpage_file->GetPath().c_str(),
1618 strerror(errno));
1619 return false;
1620 }
1621 }
1622
1623 return true;
1624 }
1625
IsPageDirty(File * page_map_file,File * clean_pagemap_file,File * kpageflags_file,File * kpagecount_file,size_t virtual_page_idx,size_t clean_virtual_page_idx,uint64_t * page_count,std::string * error_msg)1626 static int IsPageDirty(File* page_map_file,
1627 File* clean_pagemap_file,
1628 File* kpageflags_file,
1629 File* kpagecount_file,
1630 size_t virtual_page_idx,
1631 size_t clean_virtual_page_idx,
1632 // Out parameters:
1633 uint64_t* page_count, std::string* error_msg) {
1634 CHECK(page_map_file != nullptr);
1635 CHECK(clean_pagemap_file != nullptr);
1636 CHECK_NE(page_map_file, clean_pagemap_file);
1637 CHECK(kpageflags_file != nullptr);
1638 CHECK(kpagecount_file != nullptr);
1639 CHECK(page_count != nullptr);
1640 CHECK(error_msg != nullptr);
1641
1642 // Constants are from https://www.kernel.org/doc/Documentation/vm/pagemap.txt
1643
1644 uint64_t page_frame_number = 0;
1645 if (!GetPageFrameNumber(page_map_file, virtual_page_idx, &page_frame_number, error_msg)) {
1646 return -1;
1647 }
1648
1649 uint64_t page_frame_number_clean = 0;
1650 if (!GetPageFrameNumber(clean_pagemap_file, clean_virtual_page_idx, &page_frame_number_clean,
1651 error_msg)) {
1652 return -1;
1653 }
1654
1655 // Read 64-bit entry from /proc/kpageflags to get the dirty bit for a page
1656 uint64_t kpage_flags_entry = 0;
1657 if (!kpageflags_file->PreadFully(&kpage_flags_entry,
1658 kPageFlagsEntrySize,
1659 page_frame_number * kPageFlagsEntrySize)) {
1660 *error_msg = StringPrintf("Failed to read the page flags from %s",
1661 kpageflags_file->GetPath().c_str());
1662 return -1;
1663 }
1664
1665 // Read 64-bit entyry from /proc/kpagecount to get mapping counts for a page
1666 if (!kpagecount_file->PreadFully(page_count /*out*/,
1667 kPageCountEntrySize,
1668 page_frame_number * kPageCountEntrySize)) {
1669 *error_msg = StringPrintf("Failed to read the page count from %s",
1670 kpagecount_file->GetPath().c_str());
1671 return -1;
1672 }
1673
1674 // There must be a page frame at the requested address.
1675 CHECK_EQ(kpage_flags_entry & kPageFlagsNoPageMask, 0u);
1676 // The page frame must be memory mapped
1677 CHECK_NE(kpage_flags_entry & kPageFlagsMmapMask, 0u);
1678
1679 // Page is dirty, i.e. has diverged from file, if the 4th bit is set to 1
1680 bool flags_dirty = (kpage_flags_entry & kPageFlagsDirtyMask) != 0;
1681
1682 // page_frame_number_clean must come from the *same* process
1683 // but a *different* mmap than page_frame_number
1684 if (flags_dirty) {
1685 // FIXME: This check sometimes fails and the reason is not understood. b/123852774
1686 if (page_frame_number != page_frame_number_clean) {
1687 LOG(ERROR) << "Check failed: page_frame_number != page_frame_number_clean "
1688 << "(page_frame_number=" << page_frame_number
1689 << ", page_frame_number_clean=" << page_frame_number_clean << ")"
1690 << " count: " << *page_count << " flags: 0x" << std::hex << kpage_flags_entry;
1691 }
1692 }
1693
1694 return (page_frame_number != page_frame_number_clean) ? 1 : 0;
1695 }
1696
PrintPidLine(const std::string & kind,pid_t pid)1697 void PrintPidLine(const std::string& kind, pid_t pid) {
1698 if (pid < 0) {
1699 *os_ << kind << " DIFF PID: disabled\n\n";
1700 } else {
1701 *os_ << kind << " DIFF PID (" << pid << "): ";
1702 }
1703 }
1704
1705 // Return suffix of the file path after the last /. (e.g. /foo/bar -> bar, bar -> bar)
BaseName(const std::string & str)1706 static std::string BaseName(const std::string& str) {
1707 size_t idx = str.rfind('/');
1708 if (idx == std::string::npos) {
1709 return str;
1710 }
1711
1712 return str.substr(idx + 1);
1713 }
1714
1715 // Return the image location, stripped of any directories, e.g. "boot.art"
GetImageLocationBaseName(const std::string & image_location)1716 static std::string GetImageLocationBaseName(const std::string& image_location) {
1717 return BaseName(std::string(image_location));
1718 }
1719
1720 static constexpr size_t kPageMapEntrySize = sizeof(uint64_t);
1721 // bits 0-54 [in /proc/$pid/pagemap]
1722 static constexpr uint64_t kPageFrameNumberMask = (1ULL << 55) - 1;
1723
1724 static constexpr size_t kPageFlagsEntrySize = sizeof(uint64_t);
1725 static constexpr size_t kPageCountEntrySize = sizeof(uint64_t);
1726 static constexpr uint64_t kPageFlagsDirtyMask = (1ULL << 4); // in /proc/kpageflags
1727 static constexpr uint64_t kPageFlagsNoPageMask = (1ULL << 20); // in /proc/kpageflags
1728 static constexpr uint64_t kPageFlagsMmapMask = (1ULL << 11); // in /proc/kpageflags
1729
1730
1731 std::ostream* os_;
1732 pid_t image_diff_pid_; // Dump image diff against boot.art if pid is non-negative
1733 pid_t zygote_diff_pid_; // Dump image diff against zygote boot.art if pid is non-negative
1734 bool dump_dirty_objects_; // Adds dumping of objects that are dirty.
1735 bool zygote_pid_only_; // The user only specified a pid for the zygote.
1736
1737 // Used for finding the memory mapping of the image file.
1738 std::vector<android::procinfo::MapInfo> image_proc_maps_;
1739 // A File for reading /proc/<image_diff_pid_>/mem.
1740 File image_mem_file_;
1741 // A File for reading /proc/<image_diff_pid_>/pagemap.
1742 File image_pagemap_file_;
1743
1744 // Used for finding the memory mapping of the zygote image file.
1745 std::vector<android::procinfo::MapInfo> zygote_proc_maps_;
1746 // A File for reading /proc/<zygote_diff_pid_>/mem.
1747 File zygote_mem_file_;
1748 // A File for reading /proc/<zygote_diff_pid_>/pagemap.
1749 File zygote_pagemap_file_;
1750
1751 // A File for reading /proc/kpageflags.
1752 File kpageflags_file_;
1753 // A File for reading /proc/kpagecount.
1754 File kpagecount_file_;
1755
1756 DISALLOW_COPY_AND_ASSIGN(ImgDiagDumper);
1757 };
1758
DumpImage(Runtime * runtime,std::ostream * os,pid_t image_diff_pid,pid_t zygote_diff_pid,bool dump_dirty_objects)1759 static int DumpImage(Runtime* runtime,
1760 std::ostream* os,
1761 pid_t image_diff_pid,
1762 pid_t zygote_diff_pid,
1763 bool dump_dirty_objects) {
1764 ScopedObjectAccess soa(Thread::Current());
1765 gc::Heap* heap = runtime->GetHeap();
1766 const std::vector<gc::space::ImageSpace*>& image_spaces = heap->GetBootImageSpaces();
1767 CHECK(!image_spaces.empty());
1768 ImgDiagDumper img_diag_dumper(os,
1769 image_diff_pid,
1770 zygote_diff_pid,
1771 dump_dirty_objects);
1772 if (!img_diag_dumper.Init()) {
1773 return EXIT_FAILURE;
1774 }
1775 for (gc::space::ImageSpace* image_space : image_spaces) {
1776 const ImageHeader& image_header = image_space->GetImageHeader();
1777 if (!image_header.IsValid()) {
1778 fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str());
1779 return EXIT_FAILURE;
1780 }
1781
1782 if (!img_diag_dumper.Dump(image_header, image_space->GetImageLocation())) {
1783 return EXIT_FAILURE;
1784 }
1785 }
1786 return EXIT_SUCCESS;
1787 }
1788
1789 struct ImgDiagArgs : public CmdlineArgs {
1790 protected:
1791 using Base = CmdlineArgs;
1792
ParseCustomart::ImgDiagArgs1793 ParseStatus ParseCustom(const char* raw_option,
1794 size_t raw_option_length,
1795 std::string* error_msg) override {
1796 DCHECK_EQ(strlen(raw_option), raw_option_length);
1797 {
1798 ParseStatus base_parse = Base::ParseCustom(raw_option, raw_option_length, error_msg);
1799 if (base_parse != kParseUnknownArgument) {
1800 return base_parse;
1801 }
1802 }
1803
1804 std::string_view option(raw_option, raw_option_length);
1805 if (StartsWith(option, "--image-diff-pid=")) {
1806 const char* image_diff_pid = raw_option + strlen("--image-diff-pid=");
1807
1808 if (!android::base::ParseInt(image_diff_pid, &image_diff_pid_)) {
1809 *error_msg = "Image diff pid out of range";
1810 return kParseError;
1811 }
1812 } else if (StartsWith(option, "--zygote-diff-pid=")) {
1813 const char* zygote_diff_pid = raw_option + strlen("--zygote-diff-pid=");
1814
1815 if (!android::base::ParseInt(zygote_diff_pid, &zygote_diff_pid_)) {
1816 *error_msg = "Zygote diff pid out of range";
1817 return kParseError;
1818 }
1819 } else if (option == "--dump-dirty-objects") {
1820 dump_dirty_objects_ = true;
1821 } else {
1822 return kParseUnknownArgument;
1823 }
1824
1825 return kParseOk;
1826 }
1827
ParseChecksart::ImgDiagArgs1828 ParseStatus ParseChecks(std::string* error_msg) override {
1829 // Perform the parent checks.
1830 ParseStatus parent_checks = Base::ParseChecks(error_msg);
1831 if (parent_checks != kParseOk) {
1832 return parent_checks;
1833 }
1834
1835 // Perform our own checks.
1836
1837 if (kill(image_diff_pid_,
1838 /*sig*/0) != 0) { // No signal is sent, perform error-checking only.
1839 // Check if the pid exists before proceeding.
1840 if (errno == ESRCH) {
1841 *error_msg = "Process specified does not exist";
1842 } else {
1843 *error_msg = StringPrintf("Failed to check process status: %s", strerror(errno));
1844 }
1845 return kParseError;
1846 } else if (instruction_set_ != InstructionSet::kNone && instruction_set_ != kRuntimeISA) {
1847 // Don't allow different ISAs since the images are ISA-specific.
1848 // Right now the code assumes both the runtime ISA and the remote ISA are identical.
1849 *error_msg = "Must use the default runtime ISA; changing ISA is not supported.";
1850 return kParseError;
1851 }
1852
1853 return kParseOk;
1854 }
1855
GetUsageart::ImgDiagArgs1856 std::string GetUsage() const override {
1857 std::string usage;
1858
1859 usage +=
1860 "Usage: imgdiag [options] ...\n"
1861 " Example: imgdiag --image-diff-pid=$(pidof dex2oat)\n"
1862 " Example: adb shell imgdiag --image-diff-pid=$(pid zygote)\n"
1863 "\n";
1864
1865 usage += Base::GetUsage();
1866
1867 usage += // Optional.
1868 " --image-diff-pid=<pid>: provide the PID of a process whose boot.art you want to diff.\n"
1869 " Example: --image-diff-pid=$(pid zygote)\n"
1870 " --zygote-diff-pid=<pid>: provide the PID of the zygote whose boot.art you want to diff "
1871 "against.\n"
1872 " Example: --zygote-diff-pid=$(pid zygote)\n"
1873 " --dump-dirty-objects: additionally output dirty objects of interest.\n"
1874 "\n";
1875
1876 return usage;
1877 }
1878
1879 public:
1880 pid_t image_diff_pid_ = -1;
1881 pid_t zygote_diff_pid_ = -1;
1882 bool dump_dirty_objects_ = false;
1883 };
1884
1885 struct ImgDiagMain : public CmdlineMain<ImgDiagArgs> {
ExecuteWithRuntimeart::ImgDiagMain1886 bool ExecuteWithRuntime(Runtime* runtime) override {
1887 CHECK(args_ != nullptr);
1888
1889 return DumpImage(runtime,
1890 args_->os_,
1891 args_->image_diff_pid_,
1892 args_->zygote_diff_pid_,
1893 args_->dump_dirty_objects_) == EXIT_SUCCESS;
1894 }
1895 };
1896
1897 } // namespace art
1898
main(int argc,char ** argv)1899 int main(int argc, char** argv) {
1900 art::ImgDiagMain main;
1901 return main.Main(argc, argv);
1902 }
1903