• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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