Added more functionality to dex file tracking

Additional functions were added for (un)poisoning only certain sections
of a dex file. All functions related to tracking are now in a class
(DexFileTrackingRegistrar) since unpoisoning subsections of an already
poisoned section cause poison reads. Static variables were added
representing specific configurations that were used for testing.

GetCodeItem from art/dex/layout/dex_ir.cc was moved to
art/runtime/dex_file.cc because dex_file_tracking_registrar calls
GetCodeItem and GetCodeItem returns a property of a DexFile.

Bug: 37754950
Test: export ART_DEX_FILE_ACCESS_TRACKING=true && m -j && m -j
SANITIZE_TARGET=address SANITIZE_LITE=true test-art-host

Change-Id: Ie4e5aefb6f80b18fdaae5b5e8aa3bc99d77cbeac
diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex_file_tracking_registrar.cc
index cfbca3d..f41a50b 100644
--- a/runtime/dex_file_tracking_registrar.cc
+++ b/runtime/dex_file_tracking_registrar.cc
@@ -16,6 +16,9 @@
 
 #include "dex_file_tracking_registrar.h"
 
+#include <deque>
+#include <tuple>
+
 // For dex tracking through poisoning. Note: Requires forcing sanitization. This is the reason for
 // the ifdefs and early include.
 #ifdef ART_DEX_FILE_ACCESS_TRACKING
@@ -26,6 +29,7 @@
 #include "base/memory_tool.h"
 
 #include "base/logging.h"
+#include "dex_file-inl.h"
 
 namespace art {
 namespace dex {
@@ -39,11 +43,161 @@
     false;
 #endif
 
-void RegisterDexFile(const DexFile* const dex_file) {
-  if (kDexFileAccessTracking && dex_file != nullptr) {
-    LOG(ERROR) << dex_file->GetLocation() + " @ " << std::hex
-               << reinterpret_cast<uintptr_t>(dex_file->Begin());
-    MEMORY_TOOL_MAKE_NOACCESS(dex_file->Begin(), dex_file->Size());
+// The following are configurations of poisoning certain sections of a Dex File.
+// More will be added
+enum DexTrackingType {
+  // Poisons all of a Dex File when set.
+  kWholeDexTracking,
+  // Poisons all Code Items of a Dex File when set.
+  kCodeItemTracking,
+  // Poisons all subsections of a Code Item, except the Insns bytecode array
+  // section, when set for all Code Items in a Dex File.
+  kCodeItemNonInsnsTracking,
+  // Poisons all subsections of a Code Item, except the Insns bytecode array
+  // section, when set for all Code Items in a Dex File.
+  // Additionally unpoisons the entire Code Item when method is a class
+  // initializer.
+  kCodeItemNonInsnsNoClinitTracking,
+  // Poisons based on a custom tracking system which can be specified in
+  // SetDexSections
+  kCustomTracking,
+};
+
+// Intended for local changes only.
+// Represents the current configuration being run.
+static constexpr DexTrackingType kCurrentTrackingSystem = kWholeDexTracking;
+
+// Intended for local changes only.
+void DexFileTrackingRegistrar::SetDexSections() {
+  if (kDexFileAccessTracking || dex_file_ != nullptr) {
+    switch (kCurrentTrackingSystem) {
+      case kWholeDexTracking:
+        SetDexFileRegistration(true);
+        break;
+      case kCodeItemTracking:
+        SetAllCodeItemRegistration(true);
+        break;
+      case kCodeItemNonInsnsTracking:
+        SetAllCodeItemRegistration(true);
+        SetAllInsnsRegistration(false);
+        break;
+      case kCodeItemNonInsnsNoClinitTracking:
+        SetAllCodeItemRegistration(true);
+        SetAllInsnsRegistration(false);
+        SetCodeItemRegistration("<clinit>", false);
+        break;
+      case kCustomTracking:
+        // TODO: Add/remove additional calls here to (un)poison sections of
+        // dex_file_
+        break;
+    }
+  }
+}
+
+void RegisterDexFile(const DexFile* dex_file) {
+  DexFileTrackingRegistrar dex_tracking_registrar(dex_file);
+  dex_tracking_registrar.SetDexSections();
+  dex_tracking_registrar.SetCurrentRanges();
+}
+
+inline void SetRegistrationRange(const void* begin, size_t size, bool should_poison) {
+  if (should_poison) {
+    MEMORY_TOOL_MAKE_NOACCESS(begin, size);
+  } else {
+    // Note: MEMORY_TOOL_MAKE_UNDEFINED has the same functionality with Address
+    // Sanitizer. The difference has not been tested with Valgrind
+    MEMORY_TOOL_MAKE_DEFINED(begin, size);
+  }
+}
+
+void DexFileTrackingRegistrar::SetCurrentRanges() {
+  // This also empties range_values_ to avoid redundant (un)poisoning upon
+  // subsequent calls.
+  while (!range_values_.empty()) {
+    const std::tuple<const void*, size_t, bool>& current_range = range_values_.front();
+    SetRegistrationRange(std::get<0>(current_range),
+                         std::get<1>(current_range),
+                         std::get<2>(current_range));
+    range_values_.pop_front();
+  }
+}
+
+void DexFileTrackingRegistrar::SetDexFileRegistration(bool should_poison) {
+  const void* dex_file_begin = reinterpret_cast<const void*>(dex_file_->Begin());
+  size_t dex_file_size = dex_file_->Size();
+  range_values_.push_back(std::make_tuple(dex_file_begin, dex_file_size, should_poison));
+}
+
+void DexFileTrackingRegistrar::SetAllCodeItemRegistration(bool should_poison) {
+  for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
+    const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
+    const uint8_t* class_data = dex_file_->GetClassData(cd);
+    if (class_data != nullptr) {
+      ClassDataItemIterator cdit(*dex_file_, class_data);
+      // Skipping Fields
+      while (cdit.HasNextStaticField() || cdit.HasNextInstanceField()) {
+        cdit.Next();
+      }
+      while (cdit.HasNextDirectMethod()) {
+        const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
+        if (code_item != nullptr) {
+          const void* code_item_begin = reinterpret_cast<const void*>(code_item);
+          size_t code_item_size = DexFile::GetCodeItemSize(*code_item);
+          range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison));
+        }
+        cdit.Next();
+      }
+    }
+  }
+}
+
+void DexFileTrackingRegistrar::SetAllInsnsRegistration(bool should_poison) {
+  for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
+    const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
+    const uint8_t* class_data = dex_file_->GetClassData(cd);
+    if (class_data != nullptr) {
+      ClassDataItemIterator cdit(*dex_file_, class_data);
+      // Skipping Fields
+      while (cdit.HasNextStaticField() || cdit.HasNextInstanceField()) {
+        cdit.Next();
+      }
+      while (cdit.HasNextDirectMethod()) {
+        const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
+        if (code_item != nullptr) {
+          const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_);
+          // Member insns_size_in_code_units_ is in 2-byte units
+          size_t insns_size = code_item->insns_size_in_code_units_ * 2;
+          range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison));
+        }
+        cdit.Next();
+      }
+    }
+  }
+}
+
+void DexFileTrackingRegistrar::SetCodeItemRegistration(const char* class_name, bool should_poison) {
+  for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
+    const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
+    const uint8_t* class_data = dex_file_->GetClassData(cd);
+    if (class_data != nullptr) {
+      ClassDataItemIterator cdit(*dex_file_, class_data);
+      // Skipping Fields
+      while (cdit.HasNextStaticField() || cdit.HasNextInstanceField()) {
+        cdit.Next();
+      }
+      while (cdit.HasNextDirectMethod()) {
+        const DexFile::MethodId& methodid_item = dex_file_->GetMethodId(cdit.GetMemberIndex());
+        const char * methodid_name = dex_file_->GetMethodName(methodid_item);
+        const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
+        if (code_item != nullptr && strcmp(methodid_name, class_name) == 0) {
+          const void* code_item_begin = reinterpret_cast<const void*>(code_item);
+          size_t code_item_size = DexFile::GetCodeItemSize(*code_item);
+          range_values_.push_back(
+              std::make_tuple(code_item_begin, code_item_size, should_poison));
+        }
+        cdit.Next();
+      }
+    }
   }
 }