Snap for 7474514 from 309df156ac2344e041e981af204efac8e87c8a83 to mainline-media-release

Change-Id: I2b46905e59d51ee872db051759ec7ca60ee1196d
diff --git a/OWNERS b/OWNERS
index 96f0a09..7d6099d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,9 +6,12 @@
 
 # Haiku members (fuzzing-on-Android)
 hamzeh@google.com
-ispo@google.com
 kalder@google.com
+mspector@google.com
 
 # ASA
 olorin@google.com
-danielaustin@google.com
+
+# Remote Provisioning
+jbires@google.com
+swillden@google.com
diff --git a/fuzzing/example_fuzzer/Android.bp b/fuzzing/example_fuzzer/Android.bp
index a3e9e8c..a3efd3e 100644
--- a/fuzzing/example_fuzzer/Android.bp
+++ b/fuzzing/example_fuzzer/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_fuzz {
     name: "example_fuzzer",
     srcs: [
diff --git a/fuzzing/example_rust_fuzzer/Android.bp b/fuzzing/example_rust_fuzzer/Android.bp
new file mode 100644
index 0000000..dccc611
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_fuzz {
+    name: "example_rust_fuzzer",
+    srcs: ["fuzzer.rs"],
+    fuzz_config: {
+        fuzz_on_haiku_device: true,
+        fuzz_on_haiku_host: false,
+    },
+    corpus: ["testdata/*"],
+    dictionary: "example_rust_fuzzer.dict",
+}
diff --git a/fuzzing/example_rust_fuzzer/example_rust_fuzzer.dict b/fuzzing/example_rust_fuzzer/example_rust_fuzzer.dict
new file mode 100644
index 0000000..6edf100
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/example_rust_fuzzer.dict
@@ -0,0 +1 @@
+"TEST"
\ No newline at end of file
diff --git a/fuzzing/example_rust_fuzzer/fuzzer.rs b/fuzzing/example_rust_fuzzer/fuzzer.rs
new file mode 100644
index 0000000..e4cebcb
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/fuzzer.rs
@@ -0,0 +1,30 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#![allow(missing_docs)]
+#![no_main]
+#[macro_use] extern crate libfuzzer_sys;
+
+fn heap_oob() {
+    let xs = vec![0, 1, 2, 3];
+    let val = unsafe { *xs.as_ptr().offset(4) };
+    println!("Out-of-bounds heap value: {}", val);
+}
+
+fuzz_target!(|data: &[u8]| {
+    let magic_number = 327;
+    if data.len() == magic_number {
+        heap_oob();
+    }
+});
diff --git a/fuzzing/example_rust_fuzzer/testdata/test.txt b/fuzzing/example_rust_fuzzer/testdata/test.txt
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/fuzzing/example_rust_fuzzer/testdata/test.txt
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/fuzzing/media_fuzzers/OWNERS b/fuzzing/media_fuzzers/OWNERS
deleted file mode 100644
index 241b65a..0000000
--- a/fuzzing/media_fuzzers/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-hamzeh@google.com
-ispo@google.com
-kalder@google.com
-mspector@google.com
-semsmith@google.com
diff --git a/fuzzing/orphans/OWNERS b/fuzzing/orphans/OWNERS
index c7bd45b..1913c00 100644
--- a/fuzzing/orphans/OWNERS
+++ b/fuzzing/orphans/OWNERS
@@ -1,4 +1,4 @@
 hamzeh@google.com
-ispo@google.com
 kalder@google.com
 mitchp@google.com
+mspector@google.com
diff --git a/fuzzing/orphans/gptfdisk/Android.bp b/fuzzing/orphans/gptfdisk/Android.bp
new file mode 100644
index 0000000..e1c5333
--- /dev/null
+++ b/fuzzing/orphans/gptfdisk/Android.bp
@@ -0,0 +1,21 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "sgdisk_fuzz",
+    host_supported: true,
+    srcs: [
+        "sgdisk_fuzz.cc",
+    ],
+    static_libs: [
+        "libgptf",
+    ],
+    shared_libs: ["libext2_uuid"],
+    corpus: ["corpus/*"],
+    target: {
+        android: {
+            cflags: ["-DGPTFDISK_FUZZER_DEVICE"],
+        },
+    },
+}
diff --git a/fuzzing/orphans/gptfdisk/corpus/init.img b/fuzzing/orphans/gptfdisk/corpus/init.img
new file mode 100644
index 0000000..f87f897
--- /dev/null
+++ b/fuzzing/orphans/gptfdisk/corpus/init.img
Binary files differ
diff --git a/fuzzing/orphans/gptfdisk/sgdisk_fuzz.cc b/fuzzing/orphans/gptfdisk/sgdisk_fuzz.cc
new file mode 100644
index 0000000..6a02281
--- /dev/null
+++ b/fuzzing/orphans/gptfdisk/sgdisk_fuzz.cc
@@ -0,0 +1,58 @@
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <errno.h>
+#include "gptcl.h"
+#include <fcntl.h>
+#include <unistd.h>
+
+static int fuzz_gpt(char* partition_file) {
+    BasicMBRData mbrData;
+    GPTData gptData;
+    GPTPart partData;
+    int numParts = 0;
+    stringstream res;
+
+    gptData.JustLooking();
+    gptData.LoadPartitions((string) partition_file);
+    gptData.LoadMainTable();
+    gptData.GetDiskGUID();
+    numParts = gptData.GetNumParts();
+
+    //Extracted from the android_dump function in sgdisk.cc, hits more code
+    for (int i = 0; i < numParts; i++) {
+        partData = gptData[i];
+        if (partData.GetFirstLBA() > 0) {
+            partData.GetType();
+            partData.GetUniqueGUID();
+            partData.GetDescription();;
+        }
+    }
+    return 0;
+}
+
+#ifdef GPTFDISK_FUZZER_DEVICE
+#define TMPFILE_TEMPLATE "/data/local/tmp/gptfuzzXXXXXXXX\x00"
+#else
+#define TMPFILE_TEMPLATE "/dev/shm/gptfuzzXXXXXXXX\x00"
+#endif
+
+size_t TMPFILE_LEN = sizeof(TMPFILE_TEMPLATE);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    char partition_tmp_file[TMPFILE_LEN];
+    int tmpfd;
+
+    memcpy(partition_tmp_file, TMPFILE_TEMPLATE, TMPFILE_LEN);
+    tmpfd = mkstemp(partition_tmp_file);
+    if(tmpfd < 0)
+        return -1;
+    write(tmpfd, data, size);
+    close(tmpfd);
+    fuzz_gpt(partition_tmp_file);
+    remove(partition_tmp_file);
+    return 0;
+}
diff --git a/fuzzing/orphans/libcppbor/Android.bp b/fuzzing/orphans/libcppbor/Android.bp
new file mode 100644
index 0000000..3bb20f9
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/Android.bp
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "cppbor_fuzzer",
+    srcs: [
+        "cppbor_fuzzer.cpp",
+    ],
+    shared_libs: [
+        "libcppbor_external",
+    ],
+    host_supported: true,
+}
+
+cc_fuzz {
+    name: "cppbor_parse_fuzzer",
+    srcs: [
+        "cppbor_parse_fuzzer.cpp",
+    ],
+    shared_libs: [
+        "libcppbor_external",
+    ],
+    corpus: ["corpus/*.cbor"],
+    host_supported: true,
+}
diff --git a/fuzzing/orphans/libcppbor/corpus/array_0.cbor b/fuzzing/orphans/libcppbor/corpus/array_0.cbor
new file mode 100644
index 0000000..5416677
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_0.cbor
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_1.cbor b/fuzzing/orphans/libcppbor/corpus/array_1.cbor
new file mode 100644
index 0000000..4cdf6ce
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_1.cbor
@@ -0,0 +1 @@
+ƒ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_10.cbor b/fuzzing/orphans/libcppbor/corpus/array_10.cbor
new file mode 100644
index 0000000..9b1d08c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_10.cbor
@@ -0,0 +1 @@
+‚aa¡abac
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_11.cbor b/fuzzing/orphans/libcppbor/corpus/array_11.cbor
new file mode 100644
index 0000000..151c13e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_11.cbor
@@ -0,0 +1 @@
+‚aa¿abacÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_2.cbor b/fuzzing/orphans/libcppbor/corpus/array_2.cbor
new file mode 100644
index 0000000..80fd394
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_2.cbor
@@ -0,0 +1 @@
+ƒ‚‚
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_3.cbor b/fuzzing/orphans/libcppbor/corpus/array_3.cbor
new file mode 100644
index 0000000..a0f1ea2
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_3.cbor
@@ -0,0 +1 @@
+ƒ‚Ÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_4.cbor b/fuzzing/orphans/libcppbor/corpus/array_4.cbor
new file mode 100644
index 0000000..dbbf8e5
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_4.cbor
@@ -0,0 +1 @@
+ƒŸÿ‚
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_5.cbor b/fuzzing/orphans/libcppbor/corpus/array_5.cbor
new file mode 100644
index 0000000..ac2e49a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_5.cbor
@@ -0,0 +1,3 @@
+˜
+
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_6.cbor b/fuzzing/orphans/libcppbor/corpus/array_6.cbor
new file mode 100644
index 0000000..422ce24
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_6.cbor
@@ -0,0 +1 @@
+Ÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_7.cbor b/fuzzing/orphans/libcppbor/corpus/array_7.cbor
new file mode 100644
index 0000000..f67cd57
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_7.cbor
@@ -0,0 +1 @@
+Ÿ‚Ÿÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_8.cbor b/fuzzing/orphans/libcppbor/corpus/array_8.cbor
new file mode 100644
index 0000000..78343ed
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_8.cbor
@@ -0,0 +1 @@
+Ÿ‚‚ÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/array_9.cbor b/fuzzing/orphans/libcppbor/corpus/array_9.cbor
new file mode 100644
index 0000000..a9b24c8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/array_9.cbor
@@ -0,0 +1,3 @@
+Ÿ
+
+ÿ
diff --git a/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_1.cbor b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_1.cbor
new file mode 100644
index 0000000..ff6a27b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_2.cbor b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_2.cbor
new file mode 100644
index 0000000..5790402
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/attestation_obj_u2f_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/byte_string_0.cbor b/fuzzing/orphans/libcppbor/corpus/byte_string_0.cbor
new file mode 100644
index 0000000..b516b2c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/byte_string_0.cbor
@@ -0,0 +1 @@
+@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/byte_string_1.cbor b/fuzzing/orphans/libcppbor/corpus/byte_string_1.cbor
new file mode 100644
index 0000000..352e89a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/byte_string_1.cbor
@@ -0,0 +1 @@
+D
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/byte_string_2.cbor b/fuzzing/orphans/libcppbor/corpus/byte_string_2.cbor
new file mode 100644
index 0000000..2681a85
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/byte_string_2.cbor
@@ -0,0 +1 @@
+_BCÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_0.cbor b/fuzzing/orphans/libcppbor/corpus/cose_0.cbor
new file mode 100644
index 0000000..0768c4c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_1.cbor b/fuzzing/orphans/libcppbor/corpus/cose_1.cbor
new file mode 100644
index 0000000..17d89c4
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_10.cbor b/fuzzing/orphans/libcppbor/corpus/cose_10.cbor
new file mode 100644
index 0000000..e8805a1
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_10.cbor
@@ -0,0 +1,2 @@
+ЃC¡
+¡M‰õ/e¡Å€“;Ra§ŒXYtṚ:LÀšeš¢éçÿñaӌç´\ä`ÿµi
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_11.cbor b/fuzzing/orphans/libcppbor/corpus/cose_11.cbor
new file mode 100644
index 0000000..70f90d0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_11.cbor
@@ -0,0 +1,2 @@
+ЃC¡
+¡Ba§X%*‰ÔeÁ%¶vG9pAí	-á9àS½	«Ê
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_12.cbor b/fuzzing/orphans/libcppbor/corpus/cose_12.cbor
new file mode 100644
index 0000000..fc2be35
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_12.cbor
@@ -0,0 +1 @@
+Øa…C¡ TThis is the content.Hž&º¸Hƒ@¢%Jour-secret@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_13.cbor b/fuzzing/orphans/libcppbor/corpus/cose_13.cbor
new file mode 100644
index 0000000..1c368ac
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_13.cbor
@@ -0,0 +1 @@
+Øa…C¡ TThis is the content.X  4H¬ÓÓ7nªû?ä©U¾,¾~Éo,™KÃñjAƒD¡8£"X!peregrin.took@tuckborough.exampleX$meriadoc.brandybuck@buckland.example5X@M…SççO<j:Óï(j•Ëø¢=UŒÏì}4¸$ô-’½½,qð!N·y®(V«õ…¥ƒh°çò©åÎMµ@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_14.cbor b/fuzzing/orphans/libcppbor/corpus/cose_14.cbor
new file mode 100644
index 0000000..03ffb68
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_14.cbor
@@ -0,0 +1 @@
+Øa…C¡ TThis is the content.H6õ¯¯«]Cƒ@¢$X$018c0ae5-4d9b-471b-bfd6-eef314bc7037Xq°Ü/ÄX]Î'ïúgÈ	>ºo"{n°
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_15.cbor b/fuzzing/orphans/libcppbor/corpus/cose_15.cbor
new file mode 100644
index 0000000..9b0f078
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_15.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_16.cbor b/fuzzing/orphans/libcppbor/corpus/cose_16.cbor
new file mode 100644
index 0000000..987556b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_16.cbor
@@ -0,0 +1 @@
+фC¡ TThis is the content.Hr`CtP'!O
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_2.cbor b/fuzzing/orphans/libcppbor/corpus/cose_2.cbor
new file mode 100644
index 0000000..46e9790
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_3.cbor b/fuzzing/orphans/libcppbor/corpus/cose_3.cbor
new file mode 100644
index 0000000..110ea03
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_4.cbor b/fuzzing/orphans/libcppbor/corpus/cose_4.cbor
new file mode 100644
index 0000000..33b652f
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_5.cbor b/fuzzing/orphans/libcppbor/corpus/cose_5.cbor
new file mode 100644
index 0000000..b0f63b8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_5.cbor
@@ -0,0 +1 @@
+҄C¡&¡B11TThis is the content.X@Ž³>L£FZ°Z¬4Ìk#Տï\1ÄÒZ‘®ð°~*ù¢‘ª2áJ¸4ÜVí*"4DT~ñ;	å¤ÃEÊË6
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_6.cbor b/fuzzing/orphans/libcppbor/corpus/cose_6.cbor
new file mode 100644
index 0000000..64bbfdd
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_6.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_7.cbor b/fuzzing/orphans/libcppbor/corpus/cose_7.cbor
new file mode 100644
index 0000000..675bc47
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_7.cbor
@@ -0,0 +1,2 @@
+Ø`„C¡
+¡M‰õ/e¡Å€“;Ra§lXu5H¡›L§²i$í•òã±pßé1¶‡¸GƒC¡)¢3PaabbccddeeffgghhJour-secret@
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_8.cbor b/fuzzing/orphans/libcppbor/corpus/cose_8.cbor
new file mode 100644
index 0000000..5f3b4be
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_8.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cose_9.cbor b/fuzzing/orphans/libcppbor/corpus/cose_9.cbor
new file mode 100644
index 0000000..17ae70e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cose_9.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_claims_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_claims_0.cbor
new file mode 100644
index 0000000..5d4c4c6
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_claims_0.cbor
@@ -0,0 +1 @@
+§ucoap://as.example.comeerikwxcoap://light.example.comV®°VÙðVÙðBq
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_cose_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_cose_0.cbor
new file mode 100644
index 0000000..e1d1b46
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_cose_0.cbor
@@ -0,0 +1,2 @@
+¤ P#LMM0QýÂì
+8QÕ³ƒLSymmetric128
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_cose_1.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_cose_1.cbor
new file mode 100644
index 0000000..fba0863
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_cose_1.cbor
@@ -0,0 +1 @@
+¤ X @6—Þ‡¯da2 ]«áü·¨j´5ñì™-yV“ˆLSymmetric256
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_cose_2.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_cose_2.cbor
new file mode 100644
index 0000000..1aebdd0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_cose_2.cbor
@@ -0,0 +1 @@
+§#X l‚vZìSXñs=({Ü9ˆM¤ZlgÈX¼ l"X `÷ñ§€Ø§ƒ¿·¢Ýk'–荻ÎùÓÑhە)—6ç¹!X 3)Ì熎Ai'YœöZ4óÎ/ý¥Z~Êi퉣”Ô/ RAsymmetricECDSA256&
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_encrypted_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_encrypted_0.cbor
new file mode 100644
index 0000000..9787644
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_encrypted_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_maced_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_maced_0.cbor
new file mode 100644
index 0000000..9787644
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_maced_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_maced_1.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_maced_1.cbor
new file mode 100644
index 0000000..a6eeeb2
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_maced_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_nested_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_nested_0.cbor
new file mode 100644
index 0000000..9787644
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_nested_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/cwt_signed_0.cbor b/fuzzing/orphans/libcppbor/corpus/cwt_signed_0.cbor
new file mode 100644
index 0000000..74e0ea7
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/cwt_signed_0.cbor
@@ -0,0 +1 @@
+҄C¡&¡RAsymmetricECDSA256XP§ucoap://as.example.comeerikwxcoap://light.example.comV®°VÙðVÙðBqX@T'Áÿ(Ò?ºÑòœL|jU^`o¢Ÿ‘y¼=t8ºÊÊZÍÈÔÔùa1hBšøYQìît:R¹¶62År	ž0
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_0.cbor b/fuzzing/orphans/libcppbor/corpus/float16_0.cbor
new file mode 100644
index 0000000..e43ae5a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_1.cbor b/fuzzing/orphans/libcppbor/corpus/float16_1.cbor
new file mode 100644
index 0000000..6935671
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_10.cbor b/fuzzing/orphans/libcppbor/corpus/float16_10.cbor
new file mode 100644
index 0000000..7c2eb64
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_10.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_2.cbor b/fuzzing/orphans/libcppbor/corpus/float16_2.cbor
new file mode 100644
index 0000000..ed788bb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_3.cbor b/fuzzing/orphans/libcppbor/corpus/float16_3.cbor
new file mode 100644
index 0000000..5ac3929
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_4.cbor b/fuzzing/orphans/libcppbor/corpus/float16_4.cbor
new file mode 100644
index 0000000..735f467
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_4.cbor
@@ -0,0 +1 @@
+ù{ÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_5.cbor b/fuzzing/orphans/libcppbor/corpus/float16_5.cbor
new file mode 100644
index 0000000..8e144ff
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_5.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_6.cbor b/fuzzing/orphans/libcppbor/corpus/float16_6.cbor
new file mode 100644
index 0000000..16b0d43
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_6.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_7.cbor b/fuzzing/orphans/libcppbor/corpus/float16_7.cbor
new file mode 100644
index 0000000..e5b8b4d
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_7.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_8.cbor b/fuzzing/orphans/libcppbor/corpus/float16_8.cbor
new file mode 100644
index 0000000..2b119eb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_8.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float16_9.cbor b/fuzzing/orphans/libcppbor/corpus/float16_9.cbor
new file mode 100644
index 0000000..d73f58e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float16_9.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_0.cbor b/fuzzing/orphans/libcppbor/corpus/float32_0.cbor
new file mode 100644
index 0000000..f36a086
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_1.cbor b/fuzzing/orphans/libcppbor/corpus/float32_1.cbor
new file mode 100644
index 0000000..16f3345
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_1.cbor
@@ -0,0 +1 @@
+úÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_2.cbor b/fuzzing/orphans/libcppbor/corpus/float32_2.cbor
new file mode 100644
index 0000000..82965f3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_3.cbor b/fuzzing/orphans/libcppbor/corpus/float32_3.cbor
new file mode 100644
index 0000000..2a9ccae
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float32_4.cbor b/fuzzing/orphans/libcppbor/corpus/float32_4.cbor
new file mode 100644
index 0000000..a9e0eeb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float32_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_0.cbor b/fuzzing/orphans/libcppbor/corpus/float64_0.cbor
new file mode 100644
index 0000000..fc9ea00
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_0.cbor
@@ -0,0 +1 @@
+û?ñ™™™™™š
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_1.cbor b/fuzzing/orphans/libcppbor/corpus/float64_1.cbor
new file mode 100644
index 0000000..8e79bf5
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_1.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_2.cbor b/fuzzing/orphans/libcppbor/corpus/float64_2.cbor
new file mode 100644
index 0000000..815adc3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_2.cbor
@@ -0,0 +1 @@
+ûÀffffff
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_3.cbor b/fuzzing/orphans/libcppbor/corpus/float64_3.cbor
new file mode 100644
index 0000000..c90d682
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_4.cbor b/fuzzing/orphans/libcppbor/corpus/float64_4.cbor
new file mode 100644
index 0000000..802efe1
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/float64_5.cbor b/fuzzing/orphans/libcppbor/corpus/float64_5.cbor
new file mode 100644
index 0000000..7a1f61c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/float64_5.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/map_0.cbor b/fuzzing/orphans/libcppbor/corpus/map_0.cbor
new file mode 100644
index 0000000..eea1bf0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_0.cbor
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_1.cbor b/fuzzing/orphans/libcppbor/corpus/map_1.cbor
new file mode 100644
index 0000000..abc169a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_1.cbor
@@ -0,0 +1 @@
+¢
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_2.cbor b/fuzzing/orphans/libcppbor/corpus/map_2.cbor
new file mode 100644
index 0000000..81e3847
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_2.cbor
@@ -0,0 +1 @@
+¢aaab‚
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_3.cbor b/fuzzing/orphans/libcppbor/corpus/map_3.cbor
new file mode 100644
index 0000000..05bb07f
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_3.cbor
@@ -0,0 +1 @@
+¥aaaAabaBacaCadaDaeaE
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_4.cbor b/fuzzing/orphans/libcppbor/corpus/map_4.cbor
new file mode 100644
index 0000000..018602c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_4.cbor
@@ -0,0 +1 @@
+¿aaabŸÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/map_5.cbor b/fuzzing/orphans/libcppbor/corpus/map_5.cbor
new file mode 100644
index 0000000..c0f4fd5
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/map_5.cbor
@@ -0,0 +1 @@
+¿cFunõcAmt!ÿ
\ No newline at end of file
diff --git a/sanitizer-status/MODULE_LICENSE_APACHE2 b/fuzzing/orphans/libcppbor/corpus/negative_integer_0.cbor
similarity index 100%
rename from sanitizer-status/MODULE_LICENSE_APACHE2
rename to fuzzing/orphans/libcppbor/corpus/negative_integer_0.cbor
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_1.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_1.cbor
new file mode 100644
index 0000000..e8a0f87
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_1.cbor
@@ -0,0 +1 @@
+)
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_2.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_2.cbor
new file mode 100644
index 0000000..bfefdad
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_2.cbor
@@ -0,0 +1 @@
+8c
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_3.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_3.cbor
new file mode 100644
index 0000000..5de2555
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_3.cbor
@@ -0,0 +1 @@
+9ç
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/negative_integer_4.cbor b/fuzzing/orphans/libcppbor/corpus/negative_integer_4.cbor
new file mode 100644
index 0000000..077457a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/negative_integer_4.cbor
@@ -0,0 +1 @@
+;ÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_0.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_0.cbor
new file mode 100644
index 0000000..f76dd23
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_0.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_1.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_1.cbor
new file mode 100644
index 0000000..6b2aaa7
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_1.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_10.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_10.cbor
new file mode 100644
index 0000000..fed1e13
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_10.cbor
@@ -0,0 +1 @@
+ÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_2.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_2.cbor
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_2.cbor
@@ -0,0 +1 @@
+
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_3.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_3.cbor
new file mode 100644
index 0000000..c96ab3c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_3.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_4.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_4.cbor
new file mode 100644
index 0000000..a1910b3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_4.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_5.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_5.cbor
new file mode 100644
index 0000000..d4e634a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_5.cbor
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_6.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_6.cbor
new file mode 100644
index 0000000..3b5c907
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_6.cbor
@@ -0,0 +1 @@
+d
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_7.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_7.cbor
new file mode 100644
index 0000000..fda74fd
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_7.cbor
@@ -0,0 +1 @@
+è
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_8.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_8.cbor
new file mode 100644
index 0000000..9162819
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_8.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/positive_integer_9.cbor b/fuzzing/orphans/libcppbor/corpus/positive_integer_9.cbor
new file mode 100644
index 0000000..4cdcd7c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/positive_integer_9.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_0.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_0.cbor
new file mode 100644
index 0000000..3a6e607
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_0.cbor
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_1.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_1.cbor
new file mode 100644
index 0000000..bb7d13c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_1.cbor
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_2.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_2.cbor
new file mode 100644
index 0000000..f7a8cad
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_2.cbor
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_3.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_3.cbor
new file mode 100644
index 0000000..04f7b5b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_3.cbor
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_5.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_5.cbor
new file mode 100644
index 0000000..a61a462
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_5.cbor
@@ -0,0 +1 @@
+øÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/primitives_6.cbor b/fuzzing/orphans/libcppbor/corpus/primitives_6.cbor
new file mode 100644
index 0000000..009080e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/primitives_6.cbor
@@ -0,0 +1 @@

\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/struct_0.cbor b/fuzzing/orphans/libcppbor/corpus/struct_0.cbor
new file mode 100644
index 0000000..5f34271
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/struct_0.cbor
@@ -0,0 +1,5 @@
+¨aTõbUiÿÿÿÿÿÿÿÿaI9çaFûÀffffffaBX
+
+aSx+The quick brown fox jumps over the lazy dogdSlci˜
+
+cMss­acaCaeaEafaFagaGahaHanaNamaMaaaAabaBadaDaiaIajaJalaL
diff --git a/fuzzing/orphans/libcppbor/corpus/struct_keyasint_0.cbor b/fuzzing/orphans/libcppbor/corpus/struct_keyasint_0.cbor
new file mode 100644
index 0000000..4511f9e
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/struct_keyasint_0.cbor
@@ -0,0 +1,5 @@
+¨õÿÿÿÿÿÿÿÿ9çûÀffffffX
+
+x+The quick brown fox jumps over the lazy dog˜
+
+­adaDafaFagaGahaHamaManaNaaaAabaBacaCaeaEaiaIajaJalaL
diff --git a/fuzzing/orphans/libcppbor/corpus/struct_toarray_0.cbor b/fuzzing/orphans/libcppbor/corpus/struct_toarray_0.cbor
new file mode 100644
index 0000000..d8faa45
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/struct_toarray_0.cbor
@@ -0,0 +1,5 @@
+ˆõÿÿÿÿÿÿÿÿ9çûÀffffffX
+
+x+The quick brown fox jumps over the lazy dog˜
+
+­abaBacaCadaDaeaEafaFaiaIanaNaaaAagaGahaHajaJalaLamaM
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_0.cbor b/fuzzing/orphans/libcppbor/corpus/tag_0.cbor
new file mode 100644
index 0000000..d2fbff8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_0.cbor
@@ -0,0 +1 @@
+Àt2013-03-21T20:04:00Z
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_1.cbor b/fuzzing/orphans/libcppbor/corpus/tag_1.cbor
new file mode 100644
index 0000000..4ecf946
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_1.cbor
@@ -0,0 +1 @@
+ÁQKg°
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_2.cbor b/fuzzing/orphans/libcppbor/corpus/tag_2.cbor
new file mode 100644
index 0000000..00a3f0c
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_2.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_3.cbor b/fuzzing/orphans/libcppbor/corpus/tag_3.cbor
new file mode 100644
index 0000000..b4818a3
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_3.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_4.cbor b/fuzzing/orphans/libcppbor/corpus/tag_4.cbor
new file mode 100644
index 0000000..c5c79cf
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_4.cbor
Binary files differ
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_5.cbor b/fuzzing/orphans/libcppbor/corpus/tag_5.cbor
new file mode 100644
index 0000000..7d0120d
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_5.cbor
@@ -0,0 +1 @@
+×D
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_6.cbor b/fuzzing/orphans/libcppbor/corpus/tag_6.cbor
new file mode 100644
index 0000000..2784fd8
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_6.cbor
@@ -0,0 +1 @@
+ØEdIETF
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/tag_7.cbor b/fuzzing/orphans/libcppbor/corpus/tag_7.cbor
new file mode 100644
index 0000000..b7d2601
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/tag_7.cbor
@@ -0,0 +1 @@
+Ø vhttp://www.example.com
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_0.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_0.cbor
new file mode 100644
index 0000000..64845fb
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_0.cbor
@@ -0,0 +1 @@
+`
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_1.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_1.cbor
new file mode 100644
index 0000000..7ec9a4b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_1.cbor
@@ -0,0 +1 @@
+aa
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_2.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_2.cbor
new file mode 100644
index 0000000..743669b
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_2.cbor
@@ -0,0 +1 @@
+dIETF
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_3.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_3.cbor
new file mode 100644
index 0000000..cce6615
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_3.cbor
@@ -0,0 +1 @@
+b"\
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_4.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_4.cbor
new file mode 100644
index 0000000..9055a92
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_4.cbor
@@ -0,0 +1 @@
+bü
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_5.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_5.cbor
new file mode 100644
index 0000000..0868c9a
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_5.cbor
@@ -0,0 +1 @@
+c水
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_6.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_6.cbor
new file mode 100644
index 0000000..8ea48a0
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_6.cbor
@@ -0,0 +1 @@
+d𐅑
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/corpus/text_string_7.cbor b/fuzzing/orphans/libcppbor/corpus/text_string_7.cbor
new file mode 100644
index 0000000..d0daf28
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/corpus/text_string_7.cbor
@@ -0,0 +1 @@
+estreadmingÿ
\ No newline at end of file
diff --git a/fuzzing/orphans/libcppbor/cppbor_fuzzer.cpp b/fuzzing/orphans/libcppbor/cppbor_fuzzer.cpp
new file mode 100644
index 0000000..6ee80a6
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/cppbor_fuzzer.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+void FuzzStringParsing(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    std::string contents = dataProvider.ConsumeRemainingBytesAsString();
+    cppbor::Tstr val(contents);
+    cppbor::parse(val.encode());
+}
+
+void FuzzVectorParsing(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    size_t keySize = dataProvider.remaining_bytes() / 4;
+    std::string key1 = dataProvider.ConsumeBytesAsString(keySize);
+    std::string key2 = dataProvider.ConsumeBytesAsString(keySize);
+    std::vector<uint8_t> contentsBytes = dataProvider.ConsumeRemainingBytes<uint8_t>();
+    cppbor::Map map;
+    map.add(key1, cppbor::Array().add(cppbor::Map().add(key2, contentsBytes)));
+    cppbor::parse(map.encode());
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzStringParsing(data, size);
+    FuzzVectorParsing(data, size);
+    return 0;
+}
diff --git a/fuzzing/orphans/libcppbor/cppbor_parse_fuzzer.cpp b/fuzzing/orphans/libcppbor/cppbor_parse_fuzzer.cpp
new file mode 100644
index 0000000..52ed8ad
--- /dev/null
+++ b/fuzzing/orphans/libcppbor/cppbor_parse_fuzzer.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cppbor_parse.h>
+
+using namespace cppbor;
+
+class FuzzParseClient : public ParseClient {
+  public:
+    virtual ParseClient* item(std::unique_ptr<Item>&, const uint8_t*, const uint8_t*,
+                              const uint8_t*) override {
+        return this;
+    }
+    virtual ParseClient* itemEnd(std::unique_ptr<Item>&, const uint8_t*, const uint8_t*,
+                                 const uint8_t*) override {
+        return this;
+    }
+    virtual void error(const uint8_t*, const std::string&) override {}
+};
+
+void FuzzParse(const uint8_t* data, size_t size) {
+    const uint8_t* cursor = data;
+    const uint8_t* end = data + size;
+    while (cursor < end) {
+        auto [item, newPos, errMsg] = parse(cursor, end);
+        if (!item || !errMsg.empty()) {
+            return;
+        }
+        cursor = newPos;
+    }
+}
+
+void FuzzParseWithViews(const uint8_t* data, size_t size) {
+    const uint8_t* cursor = data;
+    const uint8_t* end = data + size;
+    while (cursor < end) {
+        auto [item, newPos, errMsg] = parseWithViews(cursor, end);
+        if (!item || !errMsg.empty()) {
+            return;
+        }
+        cursor = newPos;
+    }
+}
+
+void FuzzParseWithClient(const uint8_t* data, size_t size) {
+    const uint8_t* end = data + size;
+    FuzzParseClient parseClient;
+    parse(data, end, &parseClient);
+}
+
+void FuzzParseWithClientAndViews(const uint8_t* data, size_t size) {
+    const uint8_t* end = data + size;
+    FuzzParseClient parseClient;
+    parseWithViews(data, end, &parseClient);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzParse(data, size);
+    FuzzParseWithViews(data, size);
+    FuzzParseWithClient(data, size);
+    FuzzParseWithClientAndViews(data, size);
+    return 0;
+}
diff --git a/fuzzing/orphans/libexif/Android.bp b/fuzzing/orphans/libexif/Android.bp
index e68788d..d7ee450 100644
--- a/fuzzing/orphans/libexif/Android.bp
+++ b/fuzzing/orphans/libexif/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_fuzz {
     name: "libexif_fuzzer",
     srcs: [
@@ -7,4 +11,5 @@
         "libexif",
     ],
     host_supported: false,
+    corpus: ["corpus/*"],
 }
diff --git a/fuzzing/orphans/libffi/Android.bp b/fuzzing/orphans/libffi/Android.bp
new file mode 100644
index 0000000..9e49f93
--- /dev/null
+++ b/fuzzing/orphans/libffi/Android.bp
@@ -0,0 +1,22 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "libffi_fuzz",
+    host_supported: true,
+    srcs: [
+        "fuzz_ffi.cc",
+    ],
+    include_dirs: [
+        "external/libffi",
+    ],
+    cflags: [
+        "-Wno-macro-redefined",
+        "-Wno-unused-parameter",
+        "-Wno-deprecated-declarations",
+    ],
+    static_libs: [
+        "libffi",
+    ],
+}
diff --git a/fuzzing/orphans/libffi/fuzz_ffi.cc b/fuzzing/orphans/libffi/fuzz_ffi.cc
new file mode 100644
index 0000000..525f58a
--- /dev/null
+++ b/fuzzing/orphans/libffi/fuzz_ffi.cc
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Don't lint the next line, as cpplint will suggest adding
+// /tools/security as an include_dir
+// NOLINTNEXTLINE
+#include "fuzz_ffi.h"
+
+#include <vector>
+#include "include/ffi_common.h"
+
+// Empty functions we can use for our function targets
+void fn(int num_args, ...) {}
+void closure_fn(ffi_cif* cif __UNUSED__,
+        void* resp, void** args, void* userdata) {}
+void raw_closure_fn(ffi_cif* cif __UNUSED__,
+        void* resp, ffi_raw* args, void* userdata) {}
+void java_raw_closure_fn(ffi_cif* cif __UNUSED__,
+        void* resp, ffi_java_raw* args, void* userdata) {}
+
+ffi_type* generateCustomType(FuzzedDataProvider* dataProvider) {
+    // Set our flag so we don't call a java-related function (triggers an abort)
+    args_contain_struct = true;
+
+    ffi_type* new_type = reinterpret_cast<ffi_type*>(malloc(sizeof(ffi_type)));
+    ffi_alloc_vector.push_back(new_type);
+
+    new_type->size = 0;
+    new_type->alignment = 0;
+    new_type->type = FFI_TYPE_STRUCT;
+
+    // Generate our subobjects
+    size_t num_elements = dataProvider->ConsumeIntegralInRange<size_t>(0,
+            MAX_NUM_ELEMENTS);
+    new_type->elements = reinterpret_cast<ffi_type**>(
+            malloc(sizeof(ffi_type*)*(num_elements+1)));
+
+    // Nested custom structs will cause an assert, so disable them
+    // TODO(michael.ensing@leviathansecurity.com):
+    //     change the 'false' here to true once libffi supports nested structs.
+    //     It'll just throw an assert currently.
+    for (size_t i=0; i < num_elements; i++) {
+        new_type->elements[i] = getRandomType(dataProvider, false);
+    }
+
+    // The final element must be a nullptr
+    new_type->elements[num_elements] = NULL;
+
+    // Get our size/alignment
+    ffi_get_struct_offsets(abi, new_type, NULL);
+
+    return new_type;
+}
+
+size_t getTotalSize(ffi_type* type) {
+    if (type == NULL) {
+        return 0;
+    }
+
+    // Start the total as the size of the object itself
+    size_t total_size = type->size > WORDSIZE_BYTES ?
+            type->size : WORDSIZE_BYTES;
+
+    // Recursively add the size of the subelements
+    if (type->elements != NULL) {
+        for (size_t i=0; type->elements[i] != NULL; i++) {
+            total_size += getTotalSize(type->elements[i]);
+        }
+    }
+
+    return total_size;
+}
+
+ffi_type* getRandomType(FuzzedDataProvider* dataProvider,
+        bool allowCustomTypes) {
+    // Which type? Let type==NUM_TYPES be our custom struct case
+    size_t type_index = dataProvider->ConsumeIntegralInRange<size_t>(0,
+            NUM_TYPES);
+    ffi_type* type;
+    if (type_index == NUM_TYPES) {
+        if (allowCustomTypes) {
+            type = generateCustomType(dataProvider);
+        } else {
+            return NULL;
+        }
+    } else {
+        type = ffi_types[type_index];
+    }
+
+    return type;
+}
+
+void* genArg(ffi_type* type, FuzzedDataProvider* dataProvider) {
+    // Allocate the space for our arg
+    // TODO(michael.ensing@leviathansecurity.com):
+    //    Properly allocate the correct amount of aligned-space,
+    //    don't just double (which should contain any alignment)
+    size_t type_size = getTotalSize(type)*2;
+
+    if (type_size == 0) {
+        return NULL;
+    }
+
+    void* ret = malloc(type_size);
+
+    std::vector<uint8_t> bytes = dataProvider->ConsumeBytes<uint8_t>(type_size);
+    memcpy(ret, bytes.data(), bytes.size());
+
+    return ret;
+}
+
+bool buildArgArrays(ffi_type* arg_types[], void* arg_array[], size_t num_args,
+        FuzzedDataProvider* dataProvider) {
+    // The first value in our array should be the number of arguments
+    arg_types[0] = &ffi_type_sint;
+    size_t* size_ptr = reinterpret_cast<size_t*>(malloc(sizeof(size_t)));
+    *size_ptr = num_args;
+    arg_array[0] = size_ptr;
+
+    // Grab our arguments
+    for (size_t i = 1; i <= num_args; i++) {
+        // Determine what type we're using
+        ffi_type* type = getRandomType(dataProvider, true);
+        if (type == NULL) {
+            return false;
+        }
+        arg_types[i] = type;
+
+        // Generate a value for it and add to our arguments array
+        arg_array[i] = genArg(type, dataProvider);
+    }
+
+    // Our arrays of pointers need to be nullptr-terminated
+    arg_types[num_args+1] = NULL;
+    arg_array[num_args+1] = NULL;
+
+    return true;
+}
+
+void runMainFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
+        FuzzedDataProvider* dataProvider) {
+    // Call function
+    ffi_call(cif, FFI_FN(fn), resp_buf, arg_array);
+
+    // Prep Closure
+    ffi_closure* pcl = NULL;
+    void* code;
+    ffi_status ret;
+
+    pcl = reinterpret_cast<ffi_closure*>(
+            ffi_closure_alloc(sizeof(ffi_closure), &code));
+    if (pcl == NULL) {
+        return;
+    }
+
+    size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
+            MAX_RESP_SIZE);
+    std::vector<uint8_t> data_vector =
+            dataProvider->ConsumeBytes<uint8_t>(buf_size);
+    ret = ffi_prep_closure_loc(
+            pcl,
+            cif,
+            closure_fn,
+            data_vector.data(),
+            code);
+    if (ret != FFI_OK) {
+        ffi_closure_free(pcl);
+    }
+}
+
+void runRawFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
+        FuzzedDataProvider* dataProvider) {
+    #if !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
+    // Allocate our ffi_raw and put our args there
+    size_t rsize = ffi_raw_size(cif);
+    ffi_raw* raw_args = reinterpret_cast<ffi_raw*>(malloc(rsize));
+    raw_alloc_vector.push_back(raw_args);
+    ffi_ptrarray_to_raw(cif, arg_array, raw_args);
+
+    // Call
+    ffi_raw_call(cif, FFI_FN(fn), resp_buf, raw_args);
+
+    // Prep Closure
+    #if FFI_CLOSURES
+    ffi_raw_closure* pcl = NULL;
+    void* code;
+    ffi_status ret;
+
+    pcl = static_cast<ffi_raw_closure*>(
+            ffi_closure_alloc(sizeof(ffi_raw_closure), &code));
+    if (pcl == NULL) {
+        return;
+    }
+    size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
+            MAX_RESP_SIZE);
+    std::vector<uint8_t> data_vector =
+            dataProvider->ConsumeBytes<uint8_t>(buf_size);
+    ret = ffi_prep_raw_closure_loc(
+            pcl,
+            cif,
+            raw_closure_fn,
+            data_vector.data(),
+            code);
+    if (ret != FFI_OK) {
+        ffi_closure_free(pcl);
+    }
+
+    #endif  // FFI_CLOSURES
+    #endif  // !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
+}
+
+void runJavaFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
+        FuzzedDataProvider* dataProvider) {
+    #if !defined(NO_JAVA_RAW_API)
+    #if  !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
+
+    // Allocate our ffi_java_raw and put our args there
+    size_t rsize = ffi_java_raw_size(cif);
+    // NOTE: a buffer overread will occasionally happen if we don't
+    //       increase rsize.
+    ffi_java_raw* raw_args = reinterpret_cast<ffi_raw*>(malloc(rsize*2));
+    raw_alloc_vector.push_back(raw_args);
+    ffi_ptrarray_to_raw(cif, arg_array, raw_args);
+
+    // Call
+    ffi_java_raw_call(cif, FFI_FN(fn), resp_buf, raw_args);
+
+    // Prep Closure
+    #if FFI_CLOSURES
+    ffi_java_raw_closure* pcl = NULL;
+    void* code;
+    ffi_status ret;
+
+    pcl = static_cast<ffi_java_raw_closure*>(
+            ffi_closure_alloc(sizeof(ffi_java_raw_closure), &code));
+    if (pcl == NULL) {
+        return;
+    }
+    size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
+            MAX_RESP_SIZE);
+    std::vector<uint8_t> data_vector =
+            dataProvider->ConsumeBytes<uint8_t>(buf_size);
+    ret = ffi_prep_java_raw_closure_loc(
+            pcl,
+            cif,
+            raw_closure_fn,
+            data_vector.data(),
+            code);
+    if (ret != FFI_OK) {
+        ffi_closure_free(pcl);
+    }
+
+    #endif  // FFI_CLOSURES
+    #endif  // !FFI_NATIVE_RAW_API
+    #endif  // !NO_JAVA_RAW_API
+}
+
+void freeFFI(ffi_type* ffi_type) {
+    // Make sure it's one of our structs
+    if (ffi_type == NULL || ffi_type->type != FFI_TYPE_STRUCT) {
+        return;
+    }
+
+    if (ffi_type->elements != NULL) {
+        free(ffi_type->elements);
+    }
+
+    // Finally, free our object
+    free(ffi_type);
+}
+
+void freeAll(void* arg_array[], size_t num_args, void* resp_buf) {
+    // Free our custom struct objects
+    for (const auto& ffi : ffi_alloc_vector) {
+        freeFFI(ffi);
+    }
+    ffi_alloc_vector.clear();
+    for (const auto& raw : raw_alloc_vector) {
+        free(raw);
+    }
+    raw_alloc_vector.clear();
+
+    for (size_t i=0; i <= num_args; i++) {
+        free(arg_array[i]);
+    }
+
+    if (resp_buf) {
+        free(resp_buf);
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    // Init our wrapper
+    FuzzedDataProvider dataProvider(Data, Size);
+    ffi_cif cif;
+    ffi_status ret;
+    void* resp_buf = NULL;
+    args_contain_struct = false;
+    ffi_type* rtype;
+
+    // How many args are we sending?
+    size_t num_args = dataProvider.ConsumeIntegralInRange<size_t>(0,
+            MAX_NUM_ARGS);
+
+    // Build our array of args (+2 for leading arg_count and trailing nullptr)
+    ffi_type* arg_types[num_args+2];
+    void* arg_array[num_args+2];
+    bool success = buildArgArrays(arg_types, arg_array, num_args,
+            &dataProvider);
+    if (!success) {
+        goto free;
+    }
+
+    // Get return type
+    rtype = dataProvider.PickValueInArray<ffi_type*, NUM_TYPES>(ffi_types);
+
+    // Create a buffer for our return value
+    resp_buf = malloc(MAX_RESP_SIZE);
+    if (resp_buf == NULL) {
+        goto free;
+    }
+
+    // Set up our ABI
+    // NOTE: fuzzing abi triggers an abort on linux-x86_64,
+    //       so only fuzz it on ARM
+    #if MAX_ABI > 0 && defined(ARM)
+    abi = static_cast<ffi_abi>(
+           dataProvider.ConsumeIntegralInRange<uint32_t>(0, MAX_ABI));
+    #endif
+    #if HAVE_LONG_DOUBLE_VARIANT
+    ffi_prep_types(abi);
+    #endif
+
+    // ============= Call Functions =============
+    ret = ffi_prep_cif_var(&cif, abi, 1, num_args, rtype,
+            arg_types);
+    if (ret != FFI_OK) {
+        goto free;
+    }
+
+    runMainFunctions(&cif, resp_buf, arg_array, &dataProvider);
+    runRawFunctions(&cif, resp_buf, arg_array, &dataProvider);
+    if (!args_contain_struct) {
+        runJavaFunctions(&cif, resp_buf, arg_array, &dataProvider);
+    }
+
+free:
+    freeAll(arg_array, num_args, resp_buf);
+    return 0;
+}
diff --git a/fuzzing/orphans/libffi/fuzz_ffi.h b/fuzzing/orphans/libffi/fuzz_ffi.h
new file mode 100644
index 0000000..db4a66f
--- /dev/null
+++ b/fuzzing/orphans/libffi/fuzz_ffi.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FUZZING_ORPHANS_LIBFFI_FUZZ_FFI_H_
+#define FUZZING_ORPHANS_LIBFFI_FUZZ_FFI_H_
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <ffi.h>
+#include <cstdarg>
+#include <vector>
+
+#if defined(__GNUC__)
+#define __UNUSED__ __attribute__((__unused__))
+#endif
+
+#define MAX_NUM_ARGS 128
+#define MAX_NUM_ELEMENTS 16
+#define MAX_RESP_SIZE 4096
+#define WORDSIZE_BYTES (__WORDSIZE / 8)
+
+// TODO(michael.ensing@leviathansecurity.com):
+//     Ideally, we should add/remove supported types based on
+//     arch-specific #defines (listed in ffi_gen.h)
+#define NUM_TYPES 21
+ffi_type* ffi_types[] = {
+    &ffi_type_uchar,
+    &ffi_type_schar,
+    &ffi_type_ushort,
+    &ffi_type_sshort,
+    &ffi_type_uint,
+    &ffi_type_sint,
+    &ffi_type_ulong,
+    &ffi_type_slong,
+    &ffi_type_void,
+    &ffi_type_uint8,
+    &ffi_type_sint8,
+    &ffi_type_uint16,
+    &ffi_type_sint16,
+    &ffi_type_uint32,
+    &ffi_type_sint32,
+    &ffi_type_uint64,
+    &ffi_type_sint64,
+    &ffi_type_float,
+    &ffi_type_double,
+    &ffi_type_pointer,
+    &ffi_type_longdouble,
+    // The following types are not available on some architectures
+    // &ffi_type_complex_float,
+    // &ffi_type_complex_double,
+    // &ffi_type_complex_longdouble,
+    // // nullptrs are used to terminate the array. Handle them manually.
+    // nullptr
+};
+
+// Store vectors of allocated objects
+std::vector<ffi_type*> ffi_alloc_vector;
+std::vector<void*> raw_alloc_vector;
+
+
+// Keep a boolean to track if the args have a struct,
+// which will trigger an abort on java calls
+bool args_contain_struct = false;
+
+// Store the current ABI as a global
+ffi_abi abi = FFI_DEFAULT_ABI;
+
+// Define the number of possible ffi_abi values
+// NOTE: Only supported architectures are arm/arm64, x86_64
+// arm
+#if defined(ARM)
+#define MAX_ABI 4
+// x86_64
+#elif defined(X86_64) || (defined(__x86_64__) && defined(X86_DARWIN))
+#define MAX_ABI 7
+#else
+#define MAX_ABI 0  // If we hit this case, do NOT fuzz the abi value.
+#endif
+
+// Retrieve the total size (in bytes) of a ffi_type.
+// Useful for custom structs
+size_t getTotalSize(ffi_type*);
+
+// Retrieve a random type from the ffi_types array
+ffi_type* getRandomType(FuzzedDataProvider*, bool);
+
+// Generates a custom struct, in ffi_type format
+ffi_type* generateCustomType(FuzzedDataProvider*);
+
+// Copies buffer data into a buffer described by the provided ffi_type
+// (may be a struct or have subobjects)
+size_t copyArg(ffi_type*, void*, FuzzedDataProvider*);
+
+// Builds out the arrays of ffi_types and arguments to define a function's
+// parameters. Returns true on success, false on failure.
+bool buildArgArrays(ffi_type*[], void*[], size_t, FuzzedDataProvider*);
+
+// Allocates the necessary space for a new argument buffer for given ffi_type
+// After allocation, calls copyArg() to fill buffer with data
+void* genArg(ffi_type*, FuzzedDataProvider*);
+
+// Functions to perform our library calls
+void runMainFunctions(ffi_cif&, void*, void**, FuzzedDataProvider*);
+void runRawFunctions(ffi_cif&, void*, void**, FuzzedDataProvider*);
+void runJavaFunctions(ffi_cif&, void*, void**, FuzzedDataProvider*);
+
+// Free any custom struct ffi_type objects
+// Safe to call on default types.
+void freeFFI(ffi_type*);
+
+// Frees all elements that the fuzzer has allocated
+void freeAll();
+
+#endif  // FUZZING_ORPHANS_LIBFFI_FUZZ_FFI_H_
diff --git a/fuzzing/orphans/libskia/Android.bp b/fuzzing/orphans/libskia/Android.bp
new file mode 100644
index 0000000..a1c353f
--- /dev/null
+++ b/fuzzing/orphans/libskia/Android.bp
@@ -0,0 +1,54 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+  name: "libskia_image_processor_fuzzer",
+
+  srcs: [
+    "libskia_image_processor_fuzzer.cpp",
+  ],
+
+  shared_libs: [
+      "libdng_sdk",
+      "libft2",
+      "libjpeg",
+      "liblog",
+      "libpiex",
+      "libpng",
+  ],
+  static_libs: [
+      "libskia",
+      "libarect",
+      "libsfntly",
+      "libwebp-decode",
+      "libwebp-encode",
+  ],
+
+  target: {
+    android: {
+      shared_libs: [
+          "libz",
+          "libexpat",
+          "libandroidicu",
+          "libcutils",
+          "libEGL",
+          "libGLESv2",
+          "libheif",
+          "libvulkan",
+          "libnativewindow",
+      ],
+      export_shared_lib_headers: [
+          "libvulkan",
+      ],
+    },
+    host: {
+      static_libs: [
+        "libcutils",
+      ],
+    },
+  },
+
+  corpus: ["corpus/*"],
+  host_supported: true,
+}
diff --git a/fuzzing/orphans/libskia/corpus/test1.bmp b/fuzzing/orphans/libskia/corpus/test1.bmp
new file mode 100644
index 0000000..abe9c91
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test1.bmp
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test2.gif b/fuzzing/orphans/libskia/corpus/test2.gif
new file mode 100644
index 0000000..6da1431
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test2.gif
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test3.heic b/fuzzing/orphans/libskia/corpus/test3.heic
new file mode 100644
index 0000000..1f6c29d
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test3.heic
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test4.tif b/fuzzing/orphans/libskia/corpus/test4.tif
new file mode 100644
index 0000000..ca33b52
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test4.tif
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test5.jpg b/fuzzing/orphans/libskia/corpus/test5.jpg
new file mode 100644
index 0000000..cc116e3
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test5.jpg
Binary files differ
diff --git a/fuzzing/orphans/libskia/corpus/test6.png b/fuzzing/orphans/libskia/corpus/test6.png
new file mode 100644
index 0000000..eb5492a
--- /dev/null
+++ b/fuzzing/orphans/libskia/corpus/test6.png
Binary files differ
diff --git a/fuzzing/orphans/libskia/libskia_image_processor_fuzzer.cpp b/fuzzing/orphans/libskia/libskia_image_processor_fuzzer.cpp
new file mode 100644
index 0000000..6f3f2f2
--- /dev/null
+++ b/fuzzing/orphans/libskia/libskia_image_processor_fuzzer.cpp
@@ -0,0 +1,83 @@
+/////////////////////////////////////////////////////////////////////////
+//
+// Author: Mateusz Jurczyk (mjurczyk@google.com)
+//
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <cstdio>
+#include <string>
+
+#include "SkAndroidCodec.h"
+#include "SkBitmap.h"
+#include "SkCodec.h"
+#include "SkString.h"
+
+#include "fuzzer/FuzzedDataProvider.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+static int getAndroidPixels(std::string& contents, bool requestPremul) {
+  // Generate stream contents
+  std::unique_ptr<SkMemoryStream> stream = SkMemoryStream::MakeDirect(contents.data(), contents.size());
+  if (!stream) {
+    return 0;
+  }
+
+  std::unique_ptr<SkCodec> c = SkCodec::MakeFromStream(std::move(stream),
+                                                       nullptr);
+  if (!c) {
+    return 0;
+  }
+
+  std::unique_ptr<SkAndroidCodec> codec;
+  codec = SkAndroidCodec::MakeFromCodec(std::move(c));
+  if (!codec) {
+    return 0;
+  }
+
+  SkImageInfo info = codec->getInfo();
+  const int width = info.width();
+  const int height = info.height();
+
+  SkColorType decodeColorType = kN32_SkColorType;
+  SkAlphaType alphaType =
+      codec->computeOutputAlphaType(requestPremul);
+  const SkImageInfo decodeInfo =
+      SkImageInfo::Make(width, height, decodeColorType, alphaType);
+
+  SkImageInfo bitmapInfo = decodeInfo;
+  SkBitmap decodingBitmap;
+  if (!decodingBitmap.tryAllocPixels(bitmapInfo)) {
+    return 0;
+  }
+
+  codec->getAndroidPixels(
+      decodeInfo, decodingBitmap.getPixels(), decodingBitmap.rowBytes());
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(char *data, size_t size) {
+  if (size == 0) {
+    return 0;
+  }
+
+  std::string sdata1(data, size);
+  getAndroidPixels(sdata1, true);
+  std::string sdata2(data, size);
+  getAndroidPixels(sdata2, false);
+  return 0;
+}
diff --git a/fuzzing/orphans/pppd/Android.bp b/fuzzing/orphans/pppd/Android.bp
new file mode 100644
index 0000000..e2b4dc0
--- /dev/null
+++ b/fuzzing/orphans/pppd/Android.bp
@@ -0,0 +1,35 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "eap_pppd_fuzz",
+
+    srcs: [
+        "eap_fuzz.proto",
+        "eap_fuzz.cc",
+        "eap_fuzz_Cproxy.c",
+    ],
+
+    static_libs: [
+        "libprotobuf-mutator",
+        "libpppd",
+    ],
+    shared_libs: [
+        "libprotobuf-cpp-full",
+        "libdl",
+        "liblog",
+        "libcutils",
+        "libcrypto",
+    ],
+
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+
+    ldflags: ["-rdynamic"],
+    required: [
+        "pppol2tp-android",
+        "pppopptp-android",
+    ],
+}
diff --git a/fuzzing/orphans/pppd/eap_fuzz.cc b/fuzzing/orphans/pppd/eap_fuzz.cc
new file mode 100644
index 0000000..5372e15
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz.cc
@@ -0,0 +1,215 @@
+#include <stdint.h>
+extern "C" {
+#include "eap_fuzz_Cproxy.h"
+}
+
+#include <src/libfuzzer/libfuzzer_macro.h>
+#include "eap_fuzz.pb.h"
+
+#define S_MALLOC(var, size) \
+do { \
+ if ((var = (uint8_t *)malloc(size)) == NULL) { \
+     return; \
+ } \
+} while(0)
+
+void write_header(uint8_t *packet, uint16_t data_size, uint8_t type)
+{
+    data_size += EAP_HEADERLEN;
+    //the packet type
+    *(packet)++ = type&0xff;
+    //id
+    *(packet)++ = 0x0;
+    //the length as big endian short
+    *(packet)++ = ((data_size >> 8)&0xff);
+    *(packet)++ = data_size&0xff;
+}
+
+DEFINE_BINARY_PROTO_FUZZER(const eap_fuzz::proto::PacketSet &packets){
+    init();
+
+    for(const eap_fuzz::proto::Packet& packet: packets.packets()){
+       uint8_t *fuzz_packet = NULL;
+       size_t packet_len = 0;
+       std::string data = "";
+       uint8_t packet_type = -1;
+       switch(packet.PacketType_case()){
+           case eap_fuzz::proto::Packet::kEapRequest: {
+                packet_type = EAP_REQUEST;
+                uint8_t eap_request_type = -1;
+                auto eap_request = packet.eap_request();
+                switch(eap_request.EapRequestType_case()){
+                    case eap_fuzz::proto::EapRequest::kIdentity: {
+                        eap_request_type = EAPT_IDENTITY;
+                        data = eap_request.identity().data();
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+                        break;
+                    }
+                    case eap_fuzz::proto::EapRequest::kNotification: {
+                        eap_request_type = EAPT_NOTIFICATION;
+                        data = eap_request.notification().data();
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+                        break;
+                    }
+                    case eap_fuzz::proto::EapRequest::kMd5Chap: {
+                        eap_request_type = EAPT_MD5CHAP;
+                        data = eap_request.md5chap().data();
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+                        break;
+                    }
+                    case eap_fuzz::proto::EapRequest::kSrp: {
+                        auto request_srp = eap_request.srp();
+                        eap_request_type = EAPT_SRP;
+                        uint8_t srp_type = -1;
+                        switch(request_srp.EspMessage_case()){
+                            case eap_fuzz::proto::EaptRequestSRP::kSrpChallenge:{
+                                data = request_srp.srp_challenge().data();
+                                srp_type = EAPSRP_CHALLENGE;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptRequestSRP::kSrpValidator:{
+                                data = request_srp.srp_validator().data();
+                                srp_type = EAPSRP_SVALIDATOR;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptRequestSRP::kSrpKey:{
+                                data = request_srp.srp_key().data();
+                                srp_type = EAPSRP_SKEY;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptRequestSRP::kSrpLwreChallenge:{
+                                data = request_srp.srp_lwre_challenge().data();
+                                srp_type = EAPSRP_LWRECHALLENGE;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptRequestSRP::ESPMESSAGE_NOT_SET:{
+                                return;
+                            }
+
+                        }
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+2);
+                        *(fuzz_packet+EAP_HEADERLEN+1) = srp_type;
+                        packet_len++;
+                        break;
+                    }
+                    case eap_fuzz::proto::EapRequest::EAPREQUESTTYPE_NOT_SET: {
+                        return;
+                    }
+                }
+                *(fuzz_packet+EAP_HEADERLEN) = eap_request_type;
+                ++packet_len;
+                break;
+           }
+
+           case eap_fuzz::proto::Packet::kEapResponse: {
+                packet_type = EAP_RESPONSE;
+                auto eap_response = packet.eap_response();
+                uint8_t eap_response_type = -1;
+                switch(eap_response.EapResponseType_case()){
+                    case eap_fuzz::proto::EapResponse::kIdentity: {
+                        eap_response_type = EAPT_IDENTITY;
+                        data = eap_response.identity().data();
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+                        break;
+                    }
+                    case eap_fuzz::proto::EapResponse::kNotification: {
+                        eap_response_type = EAPT_NOTIFICATION;
+                        data = eap_response.notification().data();
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+                        break;
+                    }
+                    case eap_fuzz::proto::EapResponse::kMd5Chap: {
+                        eap_response_type = EAPT_MD5CHAP;
+                        data = eap_response.md5chap().data();
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+1);
+                        break;
+                    }
+                    case eap_fuzz::proto::EapResponse::kNak: {
+                        eap_response_type = EAPT_NAK;
+                        auto response_nak = eap_response.nak();
+                        uint8_t nak_type = -1;
+                        switch(response_nak.EaptResponseNAKType_case()){
+                            case eap_fuzz::proto::EaptResponseNAK::kSrp:{
+                                nak_type = EAPT_SRP;
+                                break;
+
+                            }
+                            case eap_fuzz::proto::EaptResponseNAK::kMd5Chap:{
+                                nak_type = EAPT_MD5CHAP;
+                                break;
+
+                            }
+                            case eap_fuzz::proto::EaptResponseNAK::EAPTRESPONSENAKTYPE_NOT_SET:{
+                                return;
+                            }
+                        }
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+2);
+                        *(fuzz_packet+EAP_HEADERLEN+1) = nak_type;
+                        packet_len++;
+                        break;
+                    }
+                    case eap_fuzz::proto::EapResponse::kSrp: {
+                        auto response_srp = eap_response.srp();
+                        eap_response_type = EAPT_SRP;
+                        uint8_t srp_type = -1;
+                        switch(response_srp.EspMessage_case()){
+                            case eap_fuzz::proto::EaptResponseSRP::kSrpChallenge:{
+                                data = response_srp.srp_challenge().data();
+                                srp_type = EAPSRP_LWRECHALLENGE;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptResponseSRP::kSrpCvalidator:{
+                                data = response_srp.srp_cvalidator().data();
+                                srp_type = EAPSRP_CVALIDATOR;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptResponseSRP::kSrpCkey:{
+                                data = response_srp.srp_ckey().data();
+                                srp_type = EAPSRP_CKEY;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptResponseSRP::kSrpAck:{
+                                data = response_srp.srp_ack().data();
+                                srp_type = EAPSRP_ACK;
+                                break;
+                            }
+                            case eap_fuzz::proto::EaptResponseSRP::ESPMESSAGE_NOT_SET:{
+                                return;
+                            }
+
+                        }
+                        S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN+2);
+                        *(fuzz_packet+EAP_HEADERLEN+1) = srp_type;
+                        packet_len++;
+                        break;
+                    }
+                    case eap_fuzz::proto::EapResponse::EAPRESPONSETYPE_NOT_SET: {
+                        return;
+                    }
+                }
+                *(fuzz_packet+EAP_HEADERLEN) = eap_response_type;
+                ++packet_len;
+                break;
+           }
+           case eap_fuzz::proto::Packet::kEapSuccess: {
+                packet_type = EAP_SUCCESS;
+                data = packet.eap_success().data();
+                S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN);
+                break;
+           }
+           case eap_fuzz::proto::Packet::kEapFailure: {
+                packet_type = EAP_FAILURE;
+                data = packet.eap_failure().data();
+                S_MALLOC(fuzz_packet, data.size()+EAP_HEADERLEN);
+                break;
+           }
+           case eap_fuzz::proto::Packet::PACKETTYPE_NOT_SET: {
+                return;
+         }
+       }
+       write_header(fuzz_packet, data.size()+packet_len, packet_type);
+       memcpy(fuzz_packet+EAP_HEADERLEN+packet_len, data.data(), data.size());
+       proxy_packet(fuzz_packet, data.size()+EAP_HEADERLEN+packet_len);
+       free(fuzz_packet);
+    }
+}
diff --git a/fuzzing/orphans/pppd/eap_fuzz.proto b/fuzzing/orphans/pppd/eap_fuzz.proto
new file mode 100644
index 0000000..6d41214
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz.proto
@@ -0,0 +1,133 @@
+syntax = "proto2";
+package eap_fuzz.proto;
+
+message PacketSet{
+    repeated Packet packets = 1;
+}
+
+message Packet{
+    oneof PacketType {
+        EapRequest eap_request = 1;
+        EapResponse eap_response = 2;
+        EapSuccess eap_success = 3;
+        EapFailure eap_failure = 4;
+    }
+}
+
+message EapRequest{
+    oneof EapRequestType{
+        EaptRequestIdentity identity = 1;
+        EsptRequestNotification notification = 2;
+        EaptRequestMD5Chap md5chap = 3;
+        EaptRequestSRP srp = 4;
+    }
+
+}
+
+message EaptRequestIdentity{
+    required bytes data = 1;
+}
+
+message EsptRequestNotification{
+    required bytes data = 1;
+}
+
+message EaptRequestMD5Chap{
+    required bytes data = 2;
+}
+message EaptRequestSRP{
+    oneof EspMessage {
+        EapRequestSRPChallenge srp_challenge = 1;
+        EapRequestSRPKey srp_key = 2;
+        EapRequestSRPValidator srp_validator = 3;
+        EapRequestSRPLWREChallenge srp_lwre_challenge = 4;
+    }
+}
+
+message EapRequestSRPChallenge{
+    required bytes data = 1;
+}
+
+message EapRequestSRPKey{
+    required bytes data = 1;
+}
+
+message EapRequestSRPValidator {
+    required bytes data = 1;
+}
+
+message EapRequestSRPLWREChallenge{
+   required bytes data = 1;
+}
+
+message EapResponse{
+    oneof EapResponseType{
+        EaptResponseIdentity identity = 1;
+        EsptResponseNotification notification = 2;
+        EaptResponseNAK nak = 3;
+        EaptResponseMD5Chap md5chap = 4;
+        EaptResponseSRP srp = 5;
+    }
+}
+
+message EaptResponseIdentity{
+    required bytes data = 1;
+}
+
+message EsptResponseNotification{
+    required bytes data = 1;
+}
+
+message EaptResponseNAK{
+    oneof EaptResponseNAKType{
+        EaptResponseNAKSRP srp = 1;
+        EaptResponseNAKMD5Chap md5_chap = 2;
+    }
+}
+
+
+message EaptResponseNAKSRP{
+    required bytes data = 1;
+}
+
+message EaptResponseNAKMD5Chap {
+    required bytes data = 1;
+}
+
+message EaptResponseMD5Chap {
+    required bytes data = 1;
+}
+
+message EaptResponseSRP{
+    oneof EspMessage {
+        EapResponseSRPCKey srp_ckey = 1;
+        EapResponseSRPCValidator srp_cvalidator = 2;
+        EapResponseSRPACK srp_ack = 3;
+        EapResponseSRPLWEChallenge srp_challenge = 4;
+    }
+}
+
+message EapResponseSRPCKey {
+    required bytes data = 1;
+}
+
+message EapResponseSRPCValidator{
+    required bytes data = 1;
+}
+
+message EapResponseSRPACK{
+    required bytes data = 1;
+}
+
+message EapResponseSRPLWEChallenge{
+    required bytes data = 1;
+}
+
+message EapSuccess{
+    required bytes data = 1;
+}
+
+message EapFailure{
+    required bytes data = 1;
+}
+
diff --git a/fuzzing/orphans/pppd/eap_fuzz_Cproxy.c b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.c
new file mode 100644
index 0000000..e2b7d98
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "pppd.h"
+#include "pathnames.h"
+#include "md5.h"
+#include "eap.h"
+#include "magic.h"
+
+void init()
+{
+    eap_protent.init(0);
+}
+
+
+void proxy_packet(uint8_t *data, int len)
+{
+    eap_protent.input(0, data, len);
+}
diff --git a/fuzzing/orphans/pppd/eap_fuzz_Cproxy.h b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.h
new file mode 100644
index 0000000..6846f5e
--- /dev/null
+++ b/fuzzing/orphans/pppd/eap_fuzz_Cproxy.h
@@ -0,0 +1,56 @@
+//from pppd.h, can't include it directly in the fuzzer because C -> C++ issues
+#define	EAP_HEADERLEN	4
+
+/* EAP message codes. */
+#define	EAP_REQUEST	1
+#define	EAP_RESPONSE	2
+#define	EAP_SUCCESS	3
+#define	EAP_FAILURE	4
+
+/* EAP types */
+#define	EAPT_IDENTITY		1
+#define	EAPT_NOTIFICATION	2
+#define	EAPT_NAK		3	/* (response only) */
+#define	EAPT_MD5CHAP		4
+#define	EAPT_OTP		5	/* One-Time Password; RFC 1938 */
+#define	EAPT_TOKEN		6	/* Generic Token Card */
+/* 7 and 8 are unassigned. */
+#define	EAPT_RSA		9	/* RSA Public Key Authentication */
+#define	EAPT_DSS		10	/* DSS Unilateral */
+#define	EAPT_KEA		11	/* KEA */
+#define	EAPT_KEA_VALIDATE	12	/* KEA-VALIDATE	*/
+#define	EAPT_TLS		13	/* EAP-TLS */
+#define	EAPT_DEFENDER		14	/* Defender Token (AXENT) */
+#define	EAPT_W2K		15	/* Windows 2000 EAP */
+#define	EAPT_ARCOT		16	/* Arcot Systems */
+#define	EAPT_CISCOWIRELESS	17	/* Cisco Wireless */
+#define	EAPT_NOKIACARD		18	/* Nokia IP smart card */
+#define	EAPT_SRP		19	/* Secure Remote Password */
+/* 20 is deprecated */
+
+/* EAP SRP-SHA1 Subtypes */
+#define	EAPSRP_CHALLENGE	1	/* Request 1 - Challenge */
+#define	EAPSRP_CKEY		1	/* Response 1 - Client Key */
+#define	EAPSRP_SKEY		2	/* Request 2 - Server Key */
+#define	EAPSRP_CVALIDATOR	2	/* Response 2 - Client Validator */
+#define	EAPSRP_SVALIDATOR	3	/* Request 3 - Server Validator */
+#define	EAPSRP_ACK		3	/* Response 3 - final ack */
+#define	EAPSRP_LWRECHALLENGE	4	/* Req/resp 4 - Lightweight rechal */
+
+#define	SRPVAL_EBIT	0x00000001	/* Use shared key for ECP */
+
+#define	SRP_PSEUDO_ID	"pseudo_"
+#define	SRP_PSEUDO_LEN	7
+
+#define MD5_SIGNATURE_SIZE	16
+#define MIN_CHALLENGE_LENGTH	16
+#define MAX_CHALLENGE_LENGTH	24
+
+void init();
+void proxy_packet(uint8_t *data, int len);
+
+//override output so we don't write to a broken fd
+void output (int unit, unsigned char *p, int len)
+{
+
+}
diff --git a/fuzzing/orphans/widevine/trusty/Android.bp b/fuzzing/orphans/widevine/trusty/Android.bp
new file mode 100644
index 0000000..c1f1165
--- /dev/null
+++ b/fuzzing/orphans/widevine/trusty/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "trusty_widevine_tipc_fuzzer",
+    defaults: ["trusty_fuzzer_defaults"],
+    srcs: [":trusty_tipc_fuzzer"],
+    cflags: [
+        "-DTRUSTY_APP_PORT=\"com.android.trusty.widevine\"",
+        "-DTRUSTY_APP_UUID=\"08d3ed40-bde2-448c-a91d-75f1989c57ef\"",
+        "-DTRUSTY_APP_FILENAME=\"widevine.syms.elf\"",
+    ],
+}
+
+// Fuzzer for ODK_DispatchMessage() that's inside Trusty.
+cc_fuzz {
+    name: "trusty_widevine_dispatch_fuzzer",
+    defaults: ["trusty_fuzzer_defaults"],
+    srcs: ["dispatch_fuzzer.cpp"],
+    shared_libs: [
+        "libdmabufheap",
+    ],
+}
diff --git a/fuzzing/orphans/widevine/trusty/OWNERS b/fuzzing/orphans/widevine/trusty/OWNERS
new file mode 100644
index 0000000..5f8199f
--- /dev/null
+++ b/fuzzing/orphans/widevine/trusty/OWNERS
@@ -0,0 +1 @@
+trong@google.com
diff --git a/fuzzing/orphans/widevine/trusty/dispatch_fuzzer.cpp b/fuzzing/orphans/widevine/trusty/dispatch_fuzzer.cpp
new file mode 100644
index 0000000..072b661
--- /dev/null
+++ b/fuzzing/orphans/widevine/trusty/dispatch_fuzzer.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BufferAllocator/BufferAllocator.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <trusty/coverage/coverage.h>
+#include <trusty/fuzz/counters.h>
+#include <trusty/fuzz/utils.h>
+#include <trusty/tipc.h>
+#include <unistd.h>
+#include <iostream>
+
+using android::trusty::coverage::CoverageRecord;
+using android::trusty::fuzz::ExtraCounters;
+using android::trusty::fuzz::TrustyApp;
+
+#define countof(arr) (sizeof(arr) / sizeof(arr[0]))
+
+#define TIPC_DEV "/dev/trusty-ipc-dev0"
+#define WIDEVINE_PORT "com.android.trusty.widevine"
+#define WIDEVINE_MODULE_NAME "widevine.syms.elf"
+
+#define WV_IPC_BUFFER_SIZE (32)
+#define WV_MESSAGE_BUFFER_SIZE (32 * 1024)
+#define WV_SHARED_BUFFER_SIZE (16 * 1024 * 1024)
+
+struct wv_ipc_header {
+    uint16_t tag;
+};
+
+enum wv_tag : uint16_t {
+    WV_TAG_ACK = 0u,
+    WV_TAG_BIND = 1u,
+    WV_TAG_WIDEVINE = 2u,
+};
+
+struct bind_message {
+    uint32_t protocol_version;
+    uint32_t message_buffer_size;
+    uint32_t shared_buffer_size;
+};
+
+struct widevine_message {
+    uint32_t message_size;
+};
+
+/* Widevine TA's UUID is 08d3ed40-bde2-448c-a91d-75f1989c57ef */
+static struct uuid widevine_uuid = {
+        0x08d3ed40,
+        0xbde2,
+        0x448c,
+        {0xa9, 0x1d, 0x75, 0xf1, 0x98, 0x9c, 0x57, 0xef},
+};
+
+static android::base::unique_fd wv_msg_buf_fd;
+static void* wv_msg_buf_base;
+
+static android::base::unique_fd wv_shared_buf_fd;
+static void* wv_shared_buf_base;
+
+static TrustyApp trusty_app(TIPC_DEV, WIDEVINE_PORT);
+static CoverageRecord record(TIPC_DEV, &widevine_uuid, WIDEVINE_MODULE_NAME);
+
+extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
+    auto ret = trusty_app.Connect();
+    if (!ret.ok()) {
+        std::cerr << ret.error() << std::endl;
+        exit(-1);
+    }
+
+    ret = record.Open();
+    if (!ret.ok()) {
+        std::cerr << ret.error() << std::endl;
+        exit(-1);
+    }
+
+    BufferAllocator allocator;
+
+    wv_msg_buf_fd.reset(allocator.Alloc(kDmabufSystemHeapName, WV_MESSAGE_BUFFER_SIZE));
+    if (wv_msg_buf_fd < 0) {
+        std::cerr << "Failed to allocate message buffer." << std::endl;
+        exit(-1);
+    }
+
+    wv_msg_buf_base = mmap(0, WV_MESSAGE_BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+                           wv_msg_buf_fd, 0);
+    if (wv_msg_buf_base == MAP_FAILED) {
+        std::cerr << "Failed to mmap() message buffer." << std::endl;
+        exit(-1);
+    }
+
+    wv_shared_buf_fd.reset(allocator.Alloc(kDmabufSystemHeapName, WV_SHARED_BUFFER_SIZE));
+    if (wv_shared_buf_fd < 0) {
+        std::cerr << "Failed to allocate shared buffer." << std::endl;
+        exit(-1);
+    }
+
+    wv_shared_buf_base = mmap(0, WV_SHARED_BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+                              wv_shared_buf_fd, 0);
+    if (wv_shared_buf_base == MAP_FAILED) {
+        std::cerr << "Failed to mmap() shared buffer." << std::endl;
+        exit(-1);
+    }
+
+    return 0;
+}
+
+static bool Bind() {
+    wv_ipc_header hdr = {
+        .tag = WV_TAG_BIND,
+    };
+    bind_message args = {
+        .protocol_version = 0,
+        .message_buffer_size = WV_MESSAGE_BUFFER_SIZE,
+        .shared_buffer_size = WV_SHARED_BUFFER_SIZE,
+    };
+    iovec iov[] = {
+        {
+            .iov_base = &hdr,
+            .iov_len = sizeof(hdr),
+        },
+        {
+            .iov_base = &args,
+            .iov_len = sizeof(args),
+        },
+    };
+    trusty_shm handles[] = {
+        {
+            .fd = wv_msg_buf_fd,
+            .transfer = TRUSTY_SHARE,
+        },
+        {
+            .fd = wv_shared_buf_fd,
+            .transfer = TRUSTY_SHARE,
+        },
+    };
+    int chan = *trusty_app.GetRawFd();
+
+    int rc = tipc_send(chan, iov, countof(iov), handles, countof(handles));
+    if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
+        return false;
+    }
+
+    rc = read(chan, &hdr, sizeof(hdr));
+    if (rc != static_cast<int>(sizeof(hdr))) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool Msg(const uint8_t* data, size_t size) {
+    size = std::min((size_t)WV_MESSAGE_BUFFER_SIZE, size);
+    wv_ipc_header hdr = {
+        .tag = WV_TAG_WIDEVINE,
+    };
+    widevine_message args = {
+        .message_size = static_cast<uint32_t>(size),
+    };
+    iovec iov[] = {
+        {
+            .iov_base = &hdr,
+            .iov_len = sizeof(hdr),
+        },
+        {
+            .iov_base = &args,
+            .iov_len = sizeof(args),
+        },
+    };
+    int chan = *trusty_app.GetRawFd();
+
+    memset(wv_msg_buf_base, 0, WV_MESSAGE_BUFFER_SIZE);
+    memcpy(wv_msg_buf_base, data, size);
+
+    int rc = tipc_send(chan, iov, countof(iov), NULL, 0);
+    if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
+        return false;
+    }
+
+    rc = readv(chan, iov, countof(iov));
+    if (rc != static_cast<int>(sizeof(hdr) + sizeof(args))) {
+        return false;
+    }
+
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    ExtraCounters counters(&record);
+    counters.Reset();
+
+    bool success = Bind();
+    if (!success) {
+        android::trusty::fuzz::Abort();
+    }
+
+    success = Msg(data, size);
+    if (!success) {
+        android::trusty::fuzz::Abort();
+    }
+
+    // Reconnect to ensure that the service is still up.
+    trusty_app.Disconnect();
+    auto ret = trusty_app.Connect();
+    if (!ret.ok()) {
+        std::cerr << ret.error() << std::endl;
+        android::trusty::fuzz::Abort();
+    }
+
+    return 0;
+}
diff --git a/fuzzing/system_fuzzers/libcrypto_utils/Android.bp b/fuzzing/system_fuzzers/libcrypto_utils/Android.bp
index 4214b35..c9f4820 100644
--- a/fuzzing/system_fuzzers/libcrypto_utils/Android.bp
+++ b/fuzzing/system_fuzzers/libcrypto_utils/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_fuzz {
     host_supported: true,
     name : "libcrypto_utils_fuzzer",
@@ -14,4 +18,3 @@
         "libcrypto",
     ],
 }
-
diff --git a/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp b/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp
index b14086d..cc40a3b 100644
--- a/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp
+++ b/fuzzing/system_fuzzers/libcrypto_utils/libcrypto_utils_fuzzer.cpp
@@ -21,6 +21,7 @@
 #include <openssl/obj_mac.h>
 #include <openssl/rsa.h>
 #include <cstdio>
+#include <limits>
 
 #define ANDROID_PUBKEY_MODULUS_SIZE_WORDS (ANDROID_PUBKEY_MODULUS_SIZE / 4)
 
@@ -35,7 +36,7 @@
     uint32_t modulus_size_words = ANDROID_PUBKEY_MODULUS_SIZE_WORDS;
     memcpy(buffer, &modulus_size_words, sizeof(uint32_t));
 
-    uint32_t n0inv = fdp.ConsumeIntegralInRange<uint32_t>(0,2^32);
+    uint32_t n0inv = fdp.ConsumeIntegralInRange<uint32_t>(0,std::numeric_limits<uint32_t>::max());
     memcpy(buffer+sizeof(uint32_t), &n0inv, sizeof(uint32_t));
 
     std::string s = fdp.ConsumeBytesAsString(ANDROID_PUBKEY_MODULUS_SIZE);
diff --git a/fuzzing/system_fuzzers/libwatchdog_perf_service/Android.bp b/fuzzing/system_fuzzers/libwatchdog_perf_service/Android.bp
new file mode 100644
index 0000000..1193d18
--- /dev/null
+++ b/fuzzing/system_fuzzers/libwatchdog_perf_service/Android.bp
@@ -0,0 +1,27 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name : "libwatchdog_perf_service_fuzzer",
+    srcs: [
+        "libwatchdog_perf_service_fuzzer.cpp",
+    ],
+    defaults: [
+        "carwatchdogd_defaults",
+        "libwatchdog_perf_service_defaults",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter"
+    ],
+    static_libs: [
+        "libgtest",
+        "libwatchdog_perf_service",
+    ],
+    shared_libs: [
+        "libbase",
+    ],
+}
diff --git a/fuzzing/system_fuzzers/libwatchdog_perf_service/libwatchdog_perf_service_fuzzer.cpp b/fuzzing/system_fuzzers/libwatchdog_perf_service/libwatchdog_perf_service_fuzzer.cpp
new file mode 100644
index 0000000..4de3b0e
--- /dev/null
+++ b/fuzzing/system_fuzzers/libwatchdog_perf_service/libwatchdog_perf_service_fuzzer.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "IoPerfCollection.h"
+#include "UidIoStats.h"
+
+#include <android-base/file.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <iostream>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::base::WriteStringToFile;
+
+struct statsInfo {
+    std::string instr[13];
+    int len[13];
+};
+
+statsInfo info = {{"cpu", "procs_running", "procs_blocked", "cpu0", "cpu1", "cpu2", "cpu3", "intr",
+                   "ctxt", "btime", "process", "procs_sleeping", "softirq"},
+                  {10, 1, 1, 10, 10, 10, 10, 31, 1, 1, 1, 1, 11}};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    std::string uidIoStatsSnapshot;
+    std::string procStatsSnapshot;
+
+    // Prepare for UidIOStats data
+    int count = 0;
+    while (fdp.remaining_bytes() > (size / 2)) {
+        uint64_t val = fdp.ConsumeIntegral<uint64_t>();
+        uidIoStatsSnapshot += (((count % 11) == 0 ? "" : " ") + std::to_string(val));
+        if (count > 0 && count % 11 == 10) {
+            uidIoStatsSnapshot += "\n";
+        }
+        count++;
+    }
+
+    // Prepare for ProcStats data
+    while (fdp.remaining_bytes() > 5) {
+        uint32_t choose = fdp.ConsumeIntegralInRange<uint32_t>(0, 3);
+        uint32_t idx = choose;
+        switch (choose) {
+            case 0:
+            case 1:
+            case 2:
+                break;
+            case 3:
+                idx = fdp.ConsumeIntegralInRange<uint32_t>(3, 12);
+                break;
+            default:
+                break;
+        }
+        procStatsSnapshot += info.instr[idx];
+        for (int i = 0; i < info.len[idx]; i++) {
+            uint64_t val = fdp.ConsumeIntegral<uint64_t>();
+            procStatsSnapshot += " " + std::to_string(val);
+        }
+        procStatsSnapshot += "\n";
+    }
+
+    if (uidIoStatsSnapshot.size() > 0 && procStatsSnapshot.size() > 0) {
+        // Test UidIoStats
+        TemporaryFile tf1;
+        WriteStringToFile(uidIoStatsSnapshot, tf1.path);
+        UidIoStats uidIoStats(tf1.path);
+        assert(uidIoStats.enabled() == true);
+        uidIoStats.collect();
+        // Test ProcStats
+        TemporaryFile tf2;
+        WriteStringToFile(procStatsSnapshot, tf2.path);
+        ProcStat procStat(tf2.path);
+        assert(procStat.enabled() == true);
+        procStat.collect();
+    }
+    return 0;
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/fuzzing/vrp_fuzzers/OWNERS b/fuzzing/vrp_fuzzers/OWNERS
deleted file mode 100644
index 241b65a..0000000
--- a/fuzzing/vrp_fuzzers/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-hamzeh@google.com
-ispo@google.com
-kalder@google.com
-mspector@google.com
-semsmith@google.com
diff --git a/gdb/gdb_json_printer/README.md b/gdb/gdb_json_printer/README.md
new file mode 100644
index 0000000..8e4636f
--- /dev/null
+++ b/gdb/gdb_json_printer/README.md
@@ -0,0 +1,77 @@
+# gdb-json-pretty-printer
+This is a printer that prints variables in json format.
+## Install in GDB
+Copy the content in gdbinit into your ~/.gdbinit, replace the path <path_to_gdb_json_printer> by the actual path of gdb_json_printer directory.
+## Run tests
+First, in the gdb_json_printer directory, compile each example program with O0 optimization
+```
+g++ test_examples/basic_types.cpp -O0 -g -o test_examples/basic_types
+g++ test_examples/objects1.cpp -O0 -g -o test_examples/objects1
+g++ test_examples/objects2.cpp -O0 -g -o test_examples/objects2
+g++ test_examples/objects.cpp -O0 -g -o test_examples/objects
+g++ test_examples/array.cpp -O0 -g -o test_examples/array
+g++ test_examples/reference.cpp -O0 -g -o test_examples/reference
+```
+second, run gdb in the gdb_json_printer directory:
+```
+gdb
+```
+finally, source the test script:
+```
+source test/gdb_json_printer_test.py
+```
+## printing format
+```
+Pointer := {
+  type: 'pointer',
+  ctype: ctype for pointer,
+  address: Address,
+  reference: Struct
+}
+
+Struct := {
+  type: 'struct',
+  ctype: ctype for struct,
+  address: Address,
+  fields: StructField[]
+}
+
+StructField := {
+  field: name of field,
+  field_type: 'base_class' or 'argument'
+  value: Value
+}
+
+Int := {
+  type: 'int',
+  ctype: ctype for int,
+  address: Address,
+  value: number
+}
+
+Float := {
+  type: 'float',
+  ctype: 'float' or 'double',
+  address: Address,
+  value: number
+}
+
+Enum := {
+  type: 'enum',
+  ctype: ctype for enum,
+  address: Address,
+  value: number
+}
+
+Visit variable := {
+  type: 'visited',
+  ctype: ctype for struct,
+  address: Address,
+}
+
+```
+
+## problem to solve
+* support for print parent/child class members.
+* the printer treats all arrays as pointers now. We expected it to have ability to extract array/buffer length.
+* the printer prints smart pointers into a super complex json block. Maybe we need some specific printer for these common objects.
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/gdb_json_printer/printers.py b/gdb/gdb_json_printer/gdb_json_printer/printers.py
new file mode 100644
index 0000000..167f503
--- /dev/null
+++ b/gdb/gdb_json_printer/gdb_json_printer/printers.py
@@ -0,0 +1,404 @@
+#   Copyright 2020 - The Android Open Source Project
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+import gdb
+import gdb.printing
+import re
+from abc import ABC, abstractmethod
+import json
+
+# our code now only support Python3. In python2 we need to use intptr=long. Use this typedef
+# for easier support of Python2 later.
+intptr = int
+
+
+def check_optimized_out(to_json):
+    """ A decorator for to_json method of JsonPrinters. Check if the value in the printer
+    is already optimized out.
+    If the value is already optimized out, return {'type': 'optimized_out'}.
+
+    Args:
+        to_json: A to_json method of a JsonPrinter.
+
+    Returns:
+        decorated to_json method
+    """
+
+    def decorator(self, *args, **kwargs):
+        if self.value is None or self.value.is_optimized_out:
+            return {'type': 'optimized_out'}
+
+        return to_json(self, *args, **kwargs)
+    return decorator
+
+
+def check_visited(to_json):
+    """ A decorator for to_json method of JsonPrinters. Check if the value in the printer
+    has appeared in visited_addresses_and_types.
+    If the value has appeared in visited_addresses_and_types, return {'type': 'visited',
+    'ctype': str(self.value.type), 'address': self.address}
+
+    Args:
+        to_json: A to_json method of a JsonPrinter.
+
+    Returns:
+        decorated to_json method
+    """
+
+    def decorator(self):
+        addresstype = self.get_address_type()
+        if addresstype != None and addresstype in self.visited_addresses_and_types:
+            return {
+                'type': 'visited',
+                'ctype': str(self.value.type),
+                'address': self.address
+            }
+        self.visited_addresses_and_types.add(self.get_address_type())
+        return to_json(self)
+    return decorator
+
+
+class JsonPrinter(ABC):
+    """Base class for all json printers.
+
+    Attributes:
+        value:
+            The value to print, note that the lifetime of printer is limited to single print command.
+        visited_addresses_and_types:
+            A set of all `address`_`type` string that already visited during printing.
+            If the address and type is in the set and the value is a struct or pointer,
+            the printer will mark 'type' as visited and no longer expand the value. Can be None.
+    """
+
+    def __init__(self, value, visited_addresses_and_types=None):
+        """ Constructor. A JsonPrinter will be created for each time a variable is printed.
+
+        Args:
+            value:
+                A gdb.Value object, the value to print.
+            visited_addresses_and_types:
+                A set of all `address`_`type` string that already visited during printing.
+                If the address and type is in the set and the value is a struct or pointer,
+                the printer will mark 'type' as visited and no longer expand the value. Can be None.
+        """
+        self.value = value
+        self.visited_addresses_and_types = visited_addresses_and_types
+        if self.visited_addresses_and_types == None:
+            self.visited_addresses_and_types = set()
+
+        # value may not have address attribute if it's in register
+        if hasattr(self.value, 'address') and self.value.address is not None:
+            self.address = hex(intptr(self.value.address))
+        else:
+            self.address = None
+
+    def to_string(self):
+        """ Gdb Python interface to print a gdb.Value.
+
+        Returns:
+            A string representing the json format of a gdb.Value.
+        """
+        return json.dumps(self.to_json(), indent=4)
+
+    @abstractmethod
+    def to_json(self):
+        """ The method to be implemented. Convert a gdb.Value object into a Python json object.
+
+        Returns:
+            A Python json object.
+        """
+        pass
+
+    # we use address and type to identify a printed value and avoid circular references
+    def get_address_type(self):
+        address_str = self.address if self.address is not None else ""
+        return address_str + "_" + str(self.value.type.strip_typedefs())
+
+
+class BasicTypePrinter(JsonPrinter):
+    """ Printer for basic types, now supports Enum, Int, Float, and Void.
+
+    All integer variables in C++ will be considered as Int, e.g. char, short, long. Similarly,
+    float and double are all considered as Float. For enum variables, they are actually int in
+    C++, gdb knows they are enum variables, but can only print them as integer.
+    """
+
+    """
+    BasicTypePrinter uses this dict to print basic_types.
+    """
+    basic_type_json_info = {
+        gdb.TYPE_CODE_ENUM: {'type': 'enum', 'value_func': lambda value: str(int(value))},
+        gdb.TYPE_CODE_INT: {'type': 'int', 'value_func': lambda value: str(int(value))},
+        gdb.TYPE_CODE_FLT: {'type': 'float', 'value_func': lambda value: str(float(value))},
+        gdb.TYPE_CODE_VOID: {'type': 'void', 'value_func': lambda value: None},
+    }
+
+    @check_optimized_out
+    @check_visited
+    def to_json(self):
+        """ Output format is:
+        {
+            'type': 'int'/'float'/'enum'/'void',
+            'ctype': string format type in C++,
+            'address': string format address,
+            'value': string format value
+        }.
+        """
+        type_code = self.value.type.strip_typedefs().code
+        json_type = BasicTypePrinter.basic_type_json_info[type_code]["type"]
+        value_func = BasicTypePrinter.basic_type_json_info[type_code]["value_func"]
+        value_json = {
+            'type': json_type,
+            'ctype': str(self.value.type),
+            'address': self.address,
+            'value': value_func(self.value)
+        }
+        return value_json
+
+
+class ObjectPrinter(JsonPrinter):
+    """ A Printer for objects in C++.
+
+    The current version won't extract the dynamic/actual type of objects, and the member variable
+    of a parent/child class won't be printed. We expect to support this function later.
+    """
+
+    @check_visited
+    def to_json_without_expanding_base_class(self):
+        """ A helper function for the to_json method.
+
+        It tries to extract all member variables of an object without casting it into base classes.
+        """
+        value_json = {
+            'type': 'struct',
+            'ctype': str(self.value.type),
+            'address': self.address,
+            'fields': []
+        }
+
+        for field in self.value.type.fields():
+            if not field.is_base_class:
+                field_json = {
+                    'field': field.name,
+                    'value': None
+                }
+
+                field_printer = general_lookup_function(
+                    self.value[field.name], self.visited_addresses_and_types)
+                try:
+                    field_json['value'] = field_printer.to_json()
+                except:
+                    field_json['value'] = "extract failed"
+
+                value_json['fields'].append(field_json)
+
+        return value_json
+
+    @check_optimized_out
+    def to_json(self, cast_to_dynamic_type=True):
+        """Output format:
+        {
+            'type': 'struct',
+            'ctype': string format type in C++,
+            'address': string format address,
+            'base_classes': [] # a list of value casted into each base class
+            'fields': [] # a list of struct fields
+        }.
+        For each field in fields, its format is:
+        {
+            'field': string format of field name,
+            'field_type': 'base_class'/'member', if it is a base class. the value will be the
+            object which is casted into that base_class. Otherwise, the value is the json of
+            the member variable.
+            'value': json of the field
+        }.
+        """
+        if cast_to_dynamic_type and \
+                self.value.type.strip_typedefs() != self.value.dynamic_type.strip_typedefs():
+            self.value = self.value.cast(self.value.dynamic_type)
+
+        # address/type pair is set to visited after casted to dynamic type to avoid base class
+        # being filtered by the visited check
+        value_json = self.to_json_without_expanding_base_class()
+
+        # if the type is visited, it's not necessary to explore its ancestors.
+        if value_json["type"] != "visited":
+            base_classes_list = []
+            for field in self.value.type.fields():
+                if field.is_base_class:
+                    field_json = {
+                        'base_class': field.name,
+                        'value': None
+                    }
+
+                    base_class_printer = ObjectPrinter(
+                        self.value.cast(field.type),
+                        self.visited_addresses_and_types)
+                    field_json["value"] = base_class_printer.to_json(
+                        cast_to_dynamic_type=False)
+                    base_classes_list.append(field_json)
+            value_json['base_classes'] = base_classes_list
+
+        return value_json
+
+
+class RefAndPtrPrinter(JsonPrinter):
+    """ Printer for reference and raw pointer in C++.
+    """
+
+    def __init__(self, value, visited_addresses_and_types=None):
+        super().__init__(value, visited_addresses_and_types)
+        self.void_ptr_re = re.compile(r"^.*void\s?\*$")
+
+    @check_optimized_out
+    @check_visited
+    def to_json(self):
+        """Output format:
+        {
+            'type': 'pointer'/"reference,
+            'ctype': string format type in C++,
+            'address': string format address,
+            'reference': Json for a C++ object
+        }.
+        If the pointer is a void* pointer, reference would be "cannot extract void ptr",
+        because gdb cannot extract content from a void* pointer. If the pointer is nullptr,
+        reference would be "nullptr".
+        """
+        value_type = 'pointer' if self.value.type.code == gdb.TYPE_CODE_PTR else 'reference'
+        value_json = {
+            'type': value_type,
+            'ctype': str(self.value.type),
+            'address': self.address,
+            'reference': None
+        }
+
+        # handle void pointer, dereference a void pointer will cause exception
+        if self.void_ptr_re.match(str(self.value.type.strip_typedefs())) is not None:
+            value_json['reference'] = "cannot extract void ptr"
+            return value_json
+
+        # handle nullptr
+        if value_type == 'pointer' and int(self.value) == 0:
+            value_json['reference'] = "nullptr"
+            return value_json
+
+        deref_value = self.value.referenced_value()
+        deref_value_printer = general_lookup_function(
+            deref_value, self.visited_addresses_and_types)
+        value_json['reference'] = deref_value_printer.to_json()
+        return value_json
+
+
+class ExtractFailedPrinter(JsonPrinter):
+    """ Printer for the case that cannot be extracted by current printer.
+    """
+
+    def to_json(self):
+        """ output format: {'type': 'extract failed'}
+        """
+        return {'type': 'extract failed'}
+
+
+class OptimizedOutPrinter(JsonPrinter):
+    """ Printer for the case that a variable is already optimized out.
+    """
+
+    def to_json(self):
+        """ Output format: {'type': 'optimized out'}.
+        """
+        return {'type': 'optimized out'}
+
+
+class StackArrayPrinter(JsonPrinter):
+    """ Printer for the arrays in C++.
+
+    Note that this printer works only for C++ arrays(with type= T[]). It cannot
+    print out buffers on heap.
+    Output format:
+    {
+        'type': 'array',
+        'element_type': string format type of array elements in C++,
+        'values': A list of Value json indiciating each element in array
+    }.
+    """
+    @check_optimized_out
+    @check_visited
+    def to_json(self):
+        total_size = self.value.type.sizeof
+        element_size = self.value.type.target().sizeof
+        element_count = total_size // element_size
+        stack_array_json = {
+            'type': 'array',
+            'element_type': str(self.value.type.target()),
+            'values': []
+        }
+        for idx in range(element_count):
+            element_json = general_lookup_function(
+                self.value[idx], self.visited_addresses_and_types).to_json()
+            stack_array_json['values'].append(element_json)
+        return stack_array_json
+
+
+""" The table indiciating which printer should be called given a gdb value.
+"""
+gdb_type_printer_map = {
+    gdb.TYPE_CODE_PTR: RefAndPtrPrinter,
+    gdb.TYPE_CODE_ARRAY: StackArrayPrinter,
+    gdb.TYPE_CODE_STRUCT: ObjectPrinter,
+    gdb.TYPE_CODE_UNION: ObjectPrinter,
+    gdb.TYPE_CODE_ENUM: BasicTypePrinter,
+    gdb.TYPE_CODE_FLAGS: None,
+    gdb.TYPE_CODE_FUNC: None,
+    gdb.TYPE_CODE_INT: BasicTypePrinter,
+    gdb.TYPE_CODE_FLT: BasicTypePrinter,
+    gdb.TYPE_CODE_VOID: BasicTypePrinter,
+    gdb.TYPE_CODE_SET: None,    # not exist in C++
+    gdb.TYPE_CODE_RANGE: None,    # not exist in C++?
+    # not exist in C++, in C++, string is not a built-in type
+    gdb.TYPE_CODE_STRING: None,
+    gdb.TYPE_CODE_BITSTRING: None,  # deprecated
+    gdb.TYPE_CODE_ERROR: None,
+    gdb.TYPE_CODE_METHOD: None,
+    gdb.TYPE_CODE_METHODPTR: None,
+    gdb.TYPE_CODE_MEMBERPTR: None,
+    gdb.TYPE_CODE_REF: RefAndPtrPrinter,
+    gdb.TYPE_CODE_RVALUE_REF: None,
+    gdb.TYPE_CODE_CHAR: None,   # char is an integer in C++
+    gdb.TYPE_CODE_BOOL: None,   # bool is actually char in C++
+    gdb.TYPE_CODE_COMPLEX: None,    # not exist in C++
+    gdb.TYPE_CODE_TYPEDEF: None,
+    gdb.TYPE_CODE_NAMESPACE: None,
+    gdb.TYPE_CODE_DECFLOAT: None,    # not exist in C++
+    gdb.TYPE_CODE_INTERNAL_FUNCTION: None
+}
+
+
+def general_lookup_function(value, visited_addresses_and_types=None):
+    """ The actual printer installed, it will select JsonPrinter based on the gdb value given.
+    """
+    if value.is_optimized_out:
+        return OptimizedOutPrinter(value)
+    type_code = value.type.strip_typedefs().code
+    if type_code not in gdb_type_printer_map or gdb_type_printer_map[type_code] is None:
+        return ExtractFailedPrinter(value)
+
+    # TODO: add regex match and specific printer for some type here? such as shared_ptr
+
+    return gdb_type_printer_map[type_code](value, visited_addresses_and_types)
+
+
+def register_printers():
+    """ Call this function in your ~/.gdbinit to register the printer into gdb.
+    """
+    gdb.pretty_printers.append(general_lookup_function)
diff --git a/gdb/gdb_json_printer/gdbinit b/gdb/gdb_json_printer/gdbinit
new file mode 100644
index 0000000..1410988
--- /dev/null
+++ b/gdb/gdb_json_printer/gdbinit
@@ -0,0 +1,7 @@
+set auto-load python-scripts off
+python
+import sys
+sys.path.insert(0, '<path_to_gdb_json_printer>')
+from gdb_json_printer.printers import register_printers
+register_printers()
+end
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_a.json b/gdb/gdb_json_printer/test/array_42_a.json
new file mode 100644
index 0000000..7518900
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_a.json
@@ -0,0 +1,36 @@
+{
+    "type": "array",
+    "element_type": "int16_t",
+    "values": [
+        {
+            "type": "int",
+            "ctype": "int16_t",
+            "address": "0x7fffffffd766",
+            "value": "1"
+        },
+        {
+            "type": "int",
+            "ctype": "int16_t",
+            "address": "0x7fffffffd768",
+            "value": "2"
+        },
+        {
+            "type": "int",
+            "ctype": "int16_t",
+            "address": "0x7fffffffd76a",
+            "value": "3"
+        },
+        {
+            "type": "int",
+            "ctype": "int16_t",
+            "address": "0x7fffffffd76c",
+            "value": "4"
+        },
+        {
+            "type": "int",
+            "ctype": "int16_t",
+            "address": "0x7fffffffd76e",
+            "value": "5"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_b.json b/gdb/gdb_json_printer/test/array_42_b.json
new file mode 100644
index 0000000..8edf0b4
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_b.json
@@ -0,0 +1,11 @@
+{
+    "type": "pointer",
+    "ctype": "int16_t *",
+    "address": "0x7fffffffd778",
+    "reference": {
+        "type": "int",
+        "ctype": "int16_t",
+        "address": "0x7fffffffd76a",
+        "value": "3"
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_bar.json b/gdb/gdb_json_printer/test/array_42_bar.json
new file mode 100644
index 0000000..ed2f5be
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_bar.json
@@ -0,0 +1,57 @@
+{
+    "type": "array",
+    "element_type": "Bar",
+    "values": [
+        {
+            "type": "struct",
+            "ctype": "Bar",
+            "address": "0x7fffffffd72a",
+            "fields": [
+                {
+                    "field": "b",
+                    "value": {
+                        "type": "int",
+                        "ctype": "uint16_t",
+                        "address": "0x7fffffffd72a",
+                        "value": "2"
+                    }
+                }
+            ],
+            "base_classes": []
+        },
+        {
+            "type": "struct",
+            "ctype": "Bar",
+            "address": "0x7fffffffd72c",
+            "fields": [
+                {
+                    "field": "b",
+                    "value": {
+                        "type": "int",
+                        "ctype": "uint16_t",
+                        "address": "0x7fffffffd72c",
+                        "value": "2"
+                    }
+                }
+            ],
+            "base_classes": []
+        },
+        {
+            "type": "struct",
+            "ctype": "Bar",
+            "address": "0x7fffffffd72e",
+            "fields": [
+                {
+                    "field": "b",
+                    "value": {
+                        "type": "int",
+                        "ctype": "uint16_t",
+                        "address": "0x7fffffffd72e",
+                        "value": "2"
+                    }
+                }
+            ],
+            "base_classes": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/array_42_foo.json b/gdb/gdb_json_printer/test/array_42_foo.json
new file mode 100644
index 0000000..fafd644
--- /dev/null
+++ b/gdb/gdb_json_printer/test/array_42_foo.json
@@ -0,0 +1,132 @@
+{
+    "type": "array",
+    "element_type": "Foo",
+    "values": [
+        {
+            "type": "struct",
+            "ctype": "Foo",
+            "address": "0x7fffffffd730",
+            "fields": [
+                {
+                    "field": "a",
+                    "value": {
+                        "type": "int",
+                        "ctype": "uint8_t",
+                        "address": "0x7fffffffd730",
+                        "value": "1"
+                    }
+                },
+                {
+                    "field": "bar",
+                    "value": {
+                        "type": "pointer",
+                        "ctype": "Bar *",
+                        "address": "0x7fffffffd738",
+                        "reference": {
+                            "type": "struct",
+                            "ctype": "Bar",
+                            "address": "0x7fffffffd72a",
+                            "fields": [
+                                {
+                                    "field": "b",
+                                    "value": {
+                                        "type": "int",
+                                        "ctype": "uint16_t",
+                                        "address": "0x7fffffffd72a",
+                                        "value": "2"
+                                    }
+                                }
+                            ],
+                            "base_classes": []
+                        }
+                    }
+                }
+            ],
+            "base_classes": []
+        },
+        {
+            "type": "struct",
+            "ctype": "Foo",
+            "address": "0x7fffffffd740",
+            "fields": [
+                {
+                    "field": "a",
+                    "value": {
+                        "type": "int",
+                        "ctype": "uint8_t",
+                        "address": "0x7fffffffd740",
+                        "value": "1"
+                    }
+                },
+                {
+                    "field": "bar",
+                    "value": {
+                        "type": "pointer",
+                        "ctype": "Bar *",
+                        "address": "0x7fffffffd748",
+                        "reference": {
+                            "type": "struct",
+                            "ctype": "Bar",
+                            "address": "0x7fffffffd72c",
+                            "fields": [
+                                {
+                                    "field": "b",
+                                    "value": {
+                                        "type": "int",
+                                        "ctype": "uint16_t",
+                                        "address": "0x7fffffffd72c",
+                                        "value": "2"
+                                    }
+                                }
+                            ],
+                            "base_classes": []
+                        }
+                    }
+                }
+            ],
+            "base_classes": []
+        },
+        {
+            "type": "struct",
+            "ctype": "Foo",
+            "address": "0x7fffffffd750",
+            "fields": [
+                {
+                    "field": "a",
+                    "value": {
+                        "type": "int",
+                        "ctype": "uint8_t",
+                        "address": "0x7fffffffd750",
+                        "value": "1"
+                    }
+                },
+                {
+                    "field": "bar",
+                    "value": {
+                        "type": "pointer",
+                        "ctype": "Bar *",
+                        "address": "0x7fffffffd758",
+                        "reference": {
+                            "type": "struct",
+                            "ctype": "Bar",
+                            "address": "0x7fffffffd72e",
+                            "fields": [
+                                {
+                                    "field": "b",
+                                    "value": {
+                                        "type": "int",
+                                        "ctype": "uint16_t",
+                                        "address": "0x7fffffffd72e",
+                                        "value": "2"
+                                    }
+                                }
+                            ],
+                            "base_classes": []
+                        }
+                    }
+                }
+            ],
+            "base_classes": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/gdb_json_printer_test.py b/gdb/gdb_json_printer/test/gdb_json_printer_test.py
new file mode 100644
index 0000000..dd6b40e
--- /dev/null
+++ b/gdb/gdb_json_printer/test/gdb_json_printer_test.py
@@ -0,0 +1,236 @@
+#   Copyright 2020 - The Android Open Source Project
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+import unittest
+import gdb
+import json
+
+
+def remove_gdb_output_prefix(str):
+    """ gdb output contains a "$%d =" prefix, the function remove the prefix
+    """
+    idx = str.find("=")
+    return str[idx + 1:]
+
+
+def check_type_and_ctype(input_json, input_type, ctype):
+    assert(input_json["type"] == input_type)
+    assert(input_json["ctype"] == ctype)
+
+
+def check_basic_value(input_json, input_type, ctype, value):
+    check_type_and_ctype(input_json, input_type, ctype)
+    assert(input_json["value"] == value)
+
+
+def gdb_extract_variable_to_json(variable_name):
+    """ extract a variable from gdb
+
+    Args:
+        variable_name:
+            a string, the name of the variable to extract
+    Returns:
+        A json Object in Python
+    """
+    variable = gdb.execute("p {}".format(variable_name), to_string=True)
+    variable = remove_gdb_output_prefix(variable)
+    variable_json = json.loads(variable)
+    return variable_json
+
+
+def json_equal_except_address(testcase, json0, json1):
+    """ check if all content of two json are same except the address fields
+
+    The function will check the two json objects recursively to set address fields to None,
+    then convert two json objects into strings with sorted keys, and check if the two strings
+    are same.
+    """
+    def replace_address_by_None(input_json):
+        if isinstance(input_json, dict):
+            for (k, v) in input_json.items():
+                if k == "address":
+                    input_json[k] = None
+                else:
+                    replace_address_by_None(v)
+        elif isinstance(input_json, list):
+            for item in input_json:
+                replace_address_by_None(item)
+
+    replace_address_by_None(json0)
+    replace_address_by_None(json1)
+    json0 = json.dumps(json0, sort_keys=True)
+    json1 = json.dumps(json1, sort_keys=True)
+    testcase.assertEqual(json0, json1)
+
+
+def test_json_variable(testcase, testname, line, variable_name_list):
+    for variable_name in variable_name_list:
+        variable_json = gdb_extract_variable_to_json(variable_name)
+        with open("test/{}_{}_{}.json".format(testname, str(line), variable_name), "r") as f:
+            expect_variable = json.load(f)
+        json_equal_except_address(testcase, variable_json, expect_variable)
+
+
+class TestGdbJsonPrinter(unittest.TestCase):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.maxDiff = None
+
+    def test_basic_types(self):
+        gdb.execute("file test_examples/basic_types")
+        gdb.execute("b 42")
+        gdb.execute("r")
+
+        variable_json = gdb_extract_variable_to_json("a")
+        check_basic_value(variable_json, "int", "uint8_t", "1")
+
+        variable_json = gdb_extract_variable_to_json("a")
+        check_basic_value(variable_json, "int", "uint8_t", "1")
+
+        variable_json = gdb_extract_variable_to_json("b")
+        check_basic_value(variable_json, "int", "int8_t", "-2")
+
+        variable_json = gdb_extract_variable_to_json("c")
+        check_basic_value(variable_json, "int", "uint16_t", "3")
+
+        variable_json = gdb_extract_variable_to_json("d")
+        check_basic_value(variable_json, "int", "int16_t", "-4")
+
+        variable_json = gdb_extract_variable_to_json("e")
+        check_basic_value(variable_json, "int", "uint32_t", "5")
+
+        variable_json = gdb_extract_variable_to_json("f")
+        check_basic_value(variable_json, "int", "int32_t", "-6")
+
+        variable_json = gdb_extract_variable_to_json("g")
+        check_basic_value(variable_json, "int", "uint64_t", "7")
+
+        variable_json = gdb_extract_variable_to_json("h")
+        check_basic_value(variable_json, "int", "int64_t", "-8")
+
+        variable_json = gdb_extract_variable_to_json("i")
+        check_basic_value(variable_json, "float", "float", "9.0")
+
+        variable_json = gdb_extract_variable_to_json("j")
+        check_basic_value(variable_json, "float", "double", "-10.0")
+
+        variable_json = gdb_extract_variable_to_json("k")
+        check_type_and_ctype(variable_json, "pointer", "const char *")
+        check_basic_value(
+            variable_json["reference"], "int", "const char", "72")
+
+        variable_json = gdb_extract_variable_to_json("l")
+        check_type_and_ctype(variable_json, "pointer", "void *")
+        assert(variable_json["reference"] == "cannot extract void ptr")
+
+        variable_json = gdb_extract_variable_to_json("m")
+        check_type_and_ctype(variable_json, "pointer", "char *")
+        assert(variable_json["reference"] == "nullptr")
+
+        variable_json = gdb_extract_variable_to_json("o")
+        check_basic_value(variable_json, "enum", "Animal", "0")
+
+        gdb.execute("b 61")
+        gdb.execute("c")
+
+        variable_json = gdb_extract_variable_to_json("a")
+        check_basic_value(variable_json, "int", "const uint8_t", "1")
+
+        variable_json = gdb_extract_variable_to_json("a")
+        check_basic_value(variable_json, "int", "const uint8_t", "1")
+
+        variable_json = gdb_extract_variable_to_json("b")
+        check_basic_value(variable_json, "int", "const int8_t", "-2")
+
+        variable_json = gdb_extract_variable_to_json("c")
+        check_basic_value(variable_json, "int", "const uint16_t", "3")
+
+        variable_json = gdb_extract_variable_to_json("d")
+        check_basic_value(variable_json, "int", "const int16_t", "-4")
+
+        variable_json = gdb_extract_variable_to_json("e")
+        check_basic_value(variable_json, "int", "const uint32_t", "5")
+
+        variable_json = gdb_extract_variable_to_json("f")
+        check_basic_value(variable_json, "int", "const int32_t", "-6")
+
+        variable_json = gdb_extract_variable_to_json("g")
+        check_basic_value(variable_json, "int", "const uint64_t", "7")
+
+        variable_json = gdb_extract_variable_to_json("h")
+        check_basic_value(variable_json, "int", "const int64_t", "-8")
+
+        variable_json = gdb_extract_variable_to_json("i")
+        check_basic_value(variable_json, "float", "const float", "9.0")
+
+        variable_json = gdb_extract_variable_to_json("j")
+        check_basic_value(variable_json, "float", "const double", "-10.0")
+
+        variable_json = gdb_extract_variable_to_json("k")
+        check_type_and_ctype(variable_json, "pointer", "const char *")
+        check_basic_value(
+            variable_json["reference"], "int", "const char", "72")
+
+        variable_json = gdb_extract_variable_to_json("l")
+        check_type_and_ctype(variable_json, "pointer", "const void *")
+        assert(variable_json["reference"] == "cannot extract void ptr")
+
+        variable_json = gdb_extract_variable_to_json("m")
+        check_type_and_ctype(variable_json, "pointer", "const char *")
+        assert(variable_json["reference"] == "nullptr")
+
+        variable_json = gdb_extract_variable_to_json("o")
+        check_basic_value(variable_json, "enum", "const Animal", "1")
+
+    def test_objects(self):
+        gdb.execute("file test_examples/objects")
+        gdb.execute("b 37")
+        gdb.execute("r")
+        test_json_variable(self, "objects", 37, ["bar", "foo"])
+
+    def test_objects1(self):
+        gdb.execute("file test_examples/objects1")
+        gdb.execute("b 41")
+        gdb.execute("r")
+        test_json_variable(self, "objects1", 41, ["bar", "foo"])
+
+    def test_objects2(self):
+        gdb.execute("file test_examples/objects2")
+        gdb.execute("b 85")
+        gdb.execute("r")
+        test_json_variable(
+            self,
+            "objects2",
+            85,
+            ["a", "b", "c", "d", "e", "f", "w", "x", "y", "z"])
+
+    def test_array(self):
+        gdb.execute("file test_examples/array")
+        gdb.execute("b 42")
+        gdb.execute("r")
+        test_json_variable(self, "array", 42, ["a", "b", "bar", "foo"])
+
+    def test_reference(self):
+        gdb.execute("file test_examples/reference")
+        gdb.execute("b 41")
+        gdb.execute("r")
+        test_json_variable(
+            self,
+            "reference",
+            41,
+            ["bar", "foo", "bar_ref", "foo_ref", "bar_ptr", "foo_ptr"])
+
+
+unittest.main()
diff --git a/gdb/gdb_json_printer/test/objects1_41_bar.json b/gdb/gdb_json_printer/test/objects1_41_bar.json
new file mode 100644
index 0000000..2f0cdac
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects1_41_bar.json
@@ -0,0 +1,60 @@
+{
+    "type": "pointer",
+    "ctype": "Bar *",
+    "address": "0x7fffffffd760",
+    "reference": {
+        "type": "struct",
+        "ctype": "Bar",
+        "address": "0x55555556aed0",
+        "fields": [
+            {
+                "field": "b",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint16_t",
+                    "address": "0x55555556aed0",
+                    "value": "2"
+                }
+            },
+            {
+                "field": "foo",
+                "value": {
+                    "type": "pointer",
+                    "ctype": "Foo *",
+                    "address": "0x55555556aed8",
+                    "reference": {
+                        "type": "struct",
+                        "ctype": "Foo",
+                        "address": "0x55555556aeb0",
+                        "fields": [
+                            {
+                                "field": "a",
+                                "value": {
+                                    "type": "int",
+                                    "ctype": "uint8_t",
+                                    "address": "0x55555556aeb0",
+                                    "value": "1"
+                                }
+                            },
+                            {
+                                "field": "bar",
+                                "value": {
+                                    "type": "pointer",
+                                    "ctype": "Bar *",
+                                    "address": "0x55555556aeb8",
+                                    "reference": {
+                                        "type": "visited",
+                                        "ctype": "Bar",
+                                        "address": "0x55555556aed0"
+                                    }
+                                }
+                            }
+                        ],
+                        "base_classes": []
+                    }
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects1_41_foo.json b/gdb/gdb_json_printer/test/objects1_41_foo.json
new file mode 100644
index 0000000..6ce8164
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects1_41_foo.json
@@ -0,0 +1,60 @@
+{
+    "type": "pointer",
+    "ctype": "Foo *",
+    "address": "0x7fffffffd768",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo",
+        "address": "0x55555556aeb0",
+        "fields": [
+            {
+                "field": "a",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint8_t",
+                    "address": "0x55555556aeb0",
+                    "value": "1"
+                }
+            },
+            {
+                "field": "bar",
+                "value": {
+                    "type": "pointer",
+                    "ctype": "Bar *",
+                    "address": "0x55555556aeb8",
+                    "reference": {
+                        "type": "struct",
+                        "ctype": "Bar",
+                        "address": "0x55555556aed0",
+                        "fields": [
+                            {
+                                "field": "b",
+                                "value": {
+                                    "type": "int",
+                                    "ctype": "uint16_t",
+                                    "address": "0x55555556aed0",
+                                    "value": "2"
+                                }
+                            },
+                            {
+                                "field": "foo",
+                                "value": {
+                                    "type": "pointer",
+                                    "ctype": "Foo *",
+                                    "address": "0x55555556aed8",
+                                    "reference": {
+                                        "type": "visited",
+                                        "ctype": "Foo",
+                                        "address": "0x55555556aeb0"
+                                    }
+                                }
+                            }
+                        ],
+                        "base_classes": []
+                    }
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_a.json b/gdb/gdb_json_printer/test/objects2_85_a.json
new file mode 100644
index 0000000..f6ae441
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_a.json
@@ -0,0 +1,22 @@
+{
+    "type": "pointer",
+    "ctype": "Bar *",
+    "address": "0x7fffffffd748",
+    "reference": {
+        "type": "struct",
+        "ctype": "Bar",
+        "address": "0x55555556af29",
+        "fields": [
+            {
+                "field": "e",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint8_t",
+                    "address": "0x55555556af29",
+                    "value": "5"
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_b.json b/gdb/gdb_json_printer/test/objects2_85_b.json
new file mode 100644
index 0000000..2a78825
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_b.json
@@ -0,0 +1,63 @@
+{
+    "type": "struct",
+    "ctype": "Foo2",
+    "address": "0x7fffffffd710",
+    "fields": [
+        {
+            "field": "c",
+            "value": {
+                "type": "int",
+                "ctype": "uint32_t",
+                "address": "0x7fffffffd71c",
+                "value": "4"
+            }
+        },
+        {
+            "field": "cc",
+            "value": {
+                "type": "int",
+                "ctype": "uint32_t",
+                "address": "0x7fffffffd720",
+                "value": "4"
+            }
+        }
+    ],
+    "base_classes": [
+        {
+            "base_class": "Foo",
+            "value": {
+                "type": "struct",
+                "ctype": "Foo",
+                "address": "0x7fffffffd710",
+                "fields": [
+                    {
+                        "field": "_vptr.Foo",
+                        "value": {
+                            "type": "pointer",
+                            "ctype": "int (**)(void)",
+                            "address": "0x7fffffffd710",
+                            "reference": {
+                                "type": "pointer",
+                                "ctype": "int (*)(void)",
+                                "address": "0x555555557c70",
+                                "reference": {
+                                    "type": "extract failed"
+                                }
+                            }
+                        }
+                    },
+                    {
+                        "field": "a",
+                        "value": {
+                            "type": "int",
+                            "ctype": "uint8_t",
+                            "address": "0x7fffffffd718",
+                            "value": "1"
+                        }
+                    }
+                ],
+                "base_classes": []
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_c.json b/gdb/gdb_json_printer/test/objects2_85_c.json
new file mode 100644
index 0000000..41fed32
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_c.json
@@ -0,0 +1,146 @@
+{
+    "type": "reference",
+    "ctype": "Foo &",
+    "address": "0x55555556aef0",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo3",
+        "address": "0x55555556aef0",
+        "fields": [
+            {
+                "field": "d",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint32_t",
+                    "address": "0x55555556af14",
+                    "value": "4"
+                }
+            }
+        ],
+        "base_classes": [
+            {
+                "base_class": "Foo1",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo1",
+                    "address": "0x55555556aef0",
+                    "fields": [
+                        {
+                            "field": "b",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint16_t",
+                                "address": "0x55555556aefa",
+                                "value": "2"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556aef0",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556aef0",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557c40",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556aef8",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "base_class": "Foo2",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo2",
+                    "address": "0x55555556af00",
+                    "fields": [
+                        {
+                            "field": "c",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af0c",
+                                "value": "3"
+                            }
+                        },
+                        {
+                            "field": "cc",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af10",
+                                "value": "4"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556af00",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556af00",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557c58",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556af08",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_d.json b/gdb/gdb_json_printer/test/objects2_85_d.json
new file mode 100644
index 0000000..53210de
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_d.json
@@ -0,0 +1,54 @@
+{
+    "type": "struct",
+    "ctype": "Foo1",
+    "address": "0x7fffffffd700",
+    "fields": [
+        {
+            "field": "b",
+            "value": {
+                "type": "int",
+                "ctype": "uint16_t",
+                "address": "0x7fffffffd70a",
+                "value": "2"
+            }
+        }
+    ],
+    "base_classes": [
+        {
+            "base_class": "Foo",
+            "value": {
+                "type": "struct",
+                "ctype": "Foo",
+                "address": "0x7fffffffd700",
+                "fields": [
+                    {
+                        "field": "_vptr.Foo",
+                        "value": {
+                            "type": "pointer",
+                            "ctype": "int (**)(void)",
+                            "address": "0x7fffffffd700",
+                            "reference": {
+                                "type": "pointer",
+                                "ctype": "int (*)(void)",
+                                "address": "0x555555557c88",
+                                "reference": {
+                                    "type": "extract failed"
+                                }
+                            }
+                        }
+                    },
+                    {
+                        "field": "a",
+                        "value": {
+                            "type": "int",
+                            "ctype": "uint8_t",
+                            "address": "0x7fffffffd708",
+                            "value": "1"
+                        }
+                    }
+                ],
+                "base_classes": []
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_e.json b/gdb/gdb_json_printer/test/objects2_85_e.json
new file mode 100644
index 0000000..2617f5a
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_e.json
@@ -0,0 +1,150 @@
+{
+    "type": "pointer",
+    "ctype": "Foo *",
+    "address": "0x7fffffffd738",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo6",
+        "address": "0x55555556af68",
+        "fields": [
+            {
+                "field": "d",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint32_t",
+                    "address": "0x55555556af60",
+                    "value": "4"
+                }
+            }
+        ],
+        "base_classes": [
+            {
+                "base_class": "Foo4",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo4",
+                    "address": "0x55555556af40",
+                    "fields": [
+                        {
+                            "field": "_vptr.Foo4",
+                            "value": {
+                                "type": "pointer",
+                                "ctype": "int (**)(void)",
+                                "address": "0x55555556af40",
+                                "reference": {
+                                    "type": "pointer",
+                                    "ctype": "int (*)(void)",
+                                    "address": "0x555555557b30",
+                                    "reference": {
+                                        "type": "extract failed"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "field": "b",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint16_t",
+                                "address": "0x55555556af48",
+                                "value": "2"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556af68",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556af68",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557b70",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556af70",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "base_class": "Foo5",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo5",
+                    "address": "0x55555556af50",
+                    "fields": [
+                        {
+                            "field": "_vptr.Foo5",
+                            "value": {
+                                "type": "pointer",
+                                "ctype": "int (**)(void)",
+                                "address": "0x55555556af50",
+                                "reference": {
+                                    "type": "pointer",
+                                    "ctype": "int (*)(void)",
+                                    "address": "0x555555557b50",
+                                    "reference": {
+                                        "type": "extract failed"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "field": "c",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af58",
+                                "value": "3"
+                            }
+                        },
+                        {
+                            "field": "cc",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af5c",
+                                "value": "4"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "visited",
+                                "ctype": "Foo",
+                                "address": "0x55555556af68"
+                            }
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_f.json b/gdb/gdb_json_printer/test/objects2_85_f.json
new file mode 100644
index 0000000..8ef76cd
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_f.json
@@ -0,0 +1,150 @@
+{
+    "type": "pointer",
+    "ctype": "Foo4 *",
+    "address": "0x7fffffffd730",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo6",
+        "address": "0x55555556af40",
+        "fields": [
+            {
+                "field": "d",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint32_t",
+                    "address": "0x55555556af60",
+                    "value": "4"
+                }
+            }
+        ],
+        "base_classes": [
+            {
+                "base_class": "Foo4",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo4",
+                    "address": "0x55555556af40",
+                    "fields": [
+                        {
+                            "field": "_vptr.Foo4",
+                            "value": {
+                                "type": "pointer",
+                                "ctype": "int (**)(void)",
+                                "address": "0x55555556af40",
+                                "reference": {
+                                    "type": "pointer",
+                                    "ctype": "int (*)(void)",
+                                    "address": "0x555555557b30",
+                                    "reference": {
+                                        "type": "extract failed"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "field": "b",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint16_t",
+                                "address": "0x55555556af48",
+                                "value": "2"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556af68",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556af68",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557b70",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556af70",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "base_class": "Foo5",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo5",
+                    "address": "0x55555556af50",
+                    "fields": [
+                        {
+                            "field": "_vptr.Foo5",
+                            "value": {
+                                "type": "pointer",
+                                "ctype": "int (**)(void)",
+                                "address": "0x55555556af50",
+                                "reference": {
+                                    "type": "pointer",
+                                    "ctype": "int (*)(void)",
+                                    "address": "0x555555557b50",
+                                    "reference": {
+                                        "type": "extract failed"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "field": "c",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af58",
+                                "value": "3"
+                            }
+                        },
+                        {
+                            "field": "cc",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af5c",
+                                "value": "4"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "visited",
+                                "ctype": "Foo",
+                                "address": "0x55555556af68"
+                            }
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_w.json b/gdb/gdb_json_printer/test/objects2_85_w.json
new file mode 100644
index 0000000..cf9037b
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_w.json
@@ -0,0 +1,146 @@
+{
+    "type": "pointer",
+    "ctype": "Foo *",
+    "address": "0x7fffffffd750",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo3",
+        "address": "0x55555556aef0",
+        "fields": [
+            {
+                "field": "d",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint32_t",
+                    "address": "0x55555556af14",
+                    "value": "4"
+                }
+            }
+        ],
+        "base_classes": [
+            {
+                "base_class": "Foo1",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo1",
+                    "address": "0x55555556aef0",
+                    "fields": [
+                        {
+                            "field": "b",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint16_t",
+                                "address": "0x55555556aefa",
+                                "value": "2"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556aef0",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556aef0",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557c40",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556aef8",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "base_class": "Foo2",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo2",
+                    "address": "0x55555556af00",
+                    "fields": [
+                        {
+                            "field": "c",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af0c",
+                                "value": "3"
+                            }
+                        },
+                        {
+                            "field": "cc",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af10",
+                                "value": "4"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556af00",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556af00",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557c58",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556af08",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_x.json b/gdb/gdb_json_printer/test/objects2_85_x.json
new file mode 100644
index 0000000..a2b8fad
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_x.json
@@ -0,0 +1,59 @@
+{
+    "type": "pointer",
+    "ctype": "Foo *",
+    "address": "0x7fffffffd768",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo1",
+        "address": "0x55555556aeb0",
+        "fields": [
+            {
+                "field": "b",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint16_t",
+                    "address": "0x55555556aeba",
+                    "value": "2"
+                }
+            }
+        ],
+        "base_classes": [
+            {
+                "base_class": "Foo",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo",
+                    "address": "0x55555556aeb0",
+                    "fields": [
+                        {
+                            "field": "_vptr.Foo",
+                            "value": {
+                                "type": "pointer",
+                                "ctype": "int (**)(void)",
+                                "address": "0x55555556aeb0",
+                                "reference": {
+                                    "type": "pointer",
+                                    "ctype": "int (*)(void)",
+                                    "address": "0x555555557c88",
+                                    "reference": {
+                                        "type": "extract failed"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "field": "a",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint8_t",
+                                "address": "0x55555556aeb8",
+                                "value": "1"
+                            }
+                        }
+                    ],
+                    "base_classes": []
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_y.json b/gdb/gdb_json_printer/test/objects2_85_y.json
new file mode 100644
index 0000000..4f12cef
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_y.json
@@ -0,0 +1,68 @@
+{
+    "type": "pointer",
+    "ctype": "Foo *",
+    "address": "0x7fffffffd760",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo2",
+        "address": "0x55555556aed0",
+        "fields": [
+            {
+                "field": "c",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint32_t",
+                    "address": "0x55555556aedc",
+                    "value": "3"
+                }
+            },
+            {
+                "field": "cc",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint32_t",
+                    "address": "0x55555556aee0",
+                    "value": "4"
+                }
+            }
+        ],
+        "base_classes": [
+            {
+                "base_class": "Foo",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo",
+                    "address": "0x55555556aed0",
+                    "fields": [
+                        {
+                            "field": "_vptr.Foo",
+                            "value": {
+                                "type": "pointer",
+                                "ctype": "int (**)(void)",
+                                "address": "0x55555556aed0",
+                                "reference": {
+                                    "type": "pointer",
+                                    "ctype": "int (*)(void)",
+                                    "address": "0x555555557c70",
+                                    "reference": {
+                                        "type": "extract failed"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "field": "a",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint8_t",
+                                "address": "0x55555556aed8",
+                                "value": "1"
+                            }
+                        }
+                    ],
+                    "base_classes": []
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects2_85_z.json b/gdb/gdb_json_printer/test/objects2_85_z.json
new file mode 100644
index 0000000..c77c9b5
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects2_85_z.json
@@ -0,0 +1,146 @@
+{
+    "type": "pointer",
+    "ctype": "Foo1 *",
+    "address": "0x7fffffffd758",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo3",
+        "address": "0x55555556aef0",
+        "fields": [
+            {
+                "field": "d",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint32_t",
+                    "address": "0x55555556af14",
+                    "value": "4"
+                }
+            }
+        ],
+        "base_classes": [
+            {
+                "base_class": "Foo1",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo1",
+                    "address": "0x55555556aef0",
+                    "fields": [
+                        {
+                            "field": "b",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint16_t",
+                                "address": "0x55555556aefa",
+                                "value": "2"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556aef0",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556aef0",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557c40",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556aef8",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            },
+            {
+                "base_class": "Foo2",
+                "value": {
+                    "type": "struct",
+                    "ctype": "Foo2",
+                    "address": "0x55555556af00",
+                    "fields": [
+                        {
+                            "field": "c",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af0c",
+                                "value": "3"
+                            }
+                        },
+                        {
+                            "field": "cc",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint32_t",
+                                "address": "0x55555556af10",
+                                "value": "4"
+                            }
+                        }
+                    ],
+                    "base_classes": [
+                        {
+                            "base_class": "Foo",
+                            "value": {
+                                "type": "struct",
+                                "ctype": "Foo",
+                                "address": "0x55555556af00",
+                                "fields": [
+                                    {
+                                        "field": "_vptr.Foo",
+                                        "value": {
+                                            "type": "pointer",
+                                            "ctype": "int (**)(void)",
+                                            "address": "0x55555556af00",
+                                            "reference": {
+                                                "type": "pointer",
+                                                "ctype": "int (*)(void)",
+                                                "address": "0x555555557c58",
+                                                "reference": {
+                                                    "type": "extract failed"
+                                                }
+                                            }
+                                        }
+                                    },
+                                    {
+                                        "field": "a",
+                                        "value": {
+                                            "type": "int",
+                                            "ctype": "uint8_t",
+                                            "address": "0x55555556af08",
+                                            "value": "1"
+                                        }
+                                    }
+                                ],
+                                "base_classes": []
+                            }
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects_37_bar.json b/gdb/gdb_json_printer/test/objects_37_bar.json
new file mode 100644
index 0000000..38cb376
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects_37_bar.json
@@ -0,0 +1,22 @@
+{
+    "type": "pointer",
+    "ctype": "Bar *",
+    "address": "0x7fffffffd760",
+    "reference": {
+        "type": "struct",
+        "ctype": "Bar",
+        "address": "0x55555556ded0",
+        "fields": [
+            {
+                "field": "b",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint16_t",
+                    "address": "0x55555556ded0",
+                    "value": "2"
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/objects_37_foo.json b/gdb/gdb_json_printer/test/objects_37_foo.json
new file mode 100644
index 0000000..58202f7
--- /dev/null
+++ b/gdb/gdb_json_printer/test/objects_37_foo.json
@@ -0,0 +1,47 @@
+{
+    "type": "pointer",
+    "ctype": "Foo *",
+    "address": "0x7fffffffd768",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo",
+        "address": "0x55555556deb0",
+        "fields": [
+            {
+                "field": "a",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint8_t",
+                    "address": "0x55555556deb0",
+                    "value": "1"
+                }
+            },
+            {
+                "field": "bar",
+                "value": {
+                    "type": "pointer",
+                    "ctype": "Bar *",
+                    "address": "0x55555556deb8",
+                    "reference": {
+                        "type": "struct",
+                        "ctype": "Bar",
+                        "address": "0x55555556ded0",
+                        "fields": [
+                            {
+                                "field": "b",
+                                "value": {
+                                    "type": "int",
+                                    "ctype": "uint16_t",
+                                    "address": "0x55555556ded0",
+                                    "value": "2"
+                                }
+                            }
+                        ],
+                        "base_classes": []
+                    }
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_bar.json b/gdb/gdb_json_printer/test/reference_41_bar.json
new file mode 100644
index 0000000..22d33f7
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_bar.json
@@ -0,0 +1,17 @@
+{
+    "type": "struct",
+    "ctype": "Bar",
+    "address": "0x7fffffffd74e",
+    "fields": [
+        {
+            "field": "b",
+            "value": {
+                "type": "int",
+                "ctype": "uint16_t",
+                "address": "0x7fffffffd74e",
+                "value": "2"
+            }
+        }
+    ],
+    "base_classes": []
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_bar_ptr.json b/gdb/gdb_json_printer/test/reference_41_bar_ptr.json
new file mode 100644
index 0000000..3fd919d
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_bar_ptr.json
@@ -0,0 +1,22 @@
+{
+    "type": "pointer",
+    "ctype": "Bar *",
+    "address": "0x7fffffffd760",
+    "reference": {
+        "type": "struct",
+        "ctype": "Bar",
+        "address": "0x7fffffffd74e",
+        "fields": [
+            {
+                "field": "b",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint16_t",
+                    "address": "0x7fffffffd74e",
+                    "value": "2"
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_bar_ref.json b/gdb/gdb_json_printer/test/reference_41_bar_ref.json
new file mode 100644
index 0000000..d5515f3
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_bar_ref.json
@@ -0,0 +1,22 @@
+{
+    "type": "reference",
+    "ctype": "Bar &",
+    "address": "0x7fffffffd74e",
+    "reference": {
+        "type": "struct",
+        "ctype": "Bar",
+        "address": "0x7fffffffd74e",
+        "fields": [
+            {
+                "field": "b",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint16_t",
+                    "address": "0x7fffffffd74e",
+                    "value": "2"
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_foo.json b/gdb/gdb_json_printer/test/reference_41_foo.json
new file mode 100644
index 0000000..9fec7d5
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_foo.json
@@ -0,0 +1,42 @@
+{
+    "type": "struct",
+    "ctype": "Foo",
+    "address": "0x7fffffffd750",
+    "fields": [
+        {
+            "field": "a",
+            "value": {
+                "type": "int",
+                "ctype": "uint8_t",
+                "address": "0x7fffffffd750",
+                "value": "1"
+            }
+        },
+        {
+            "field": "bar",
+            "value": {
+                "type": "pointer",
+                "ctype": "Bar *",
+                "address": "0x7fffffffd758",
+                "reference": {
+                    "type": "struct",
+                    "ctype": "Bar",
+                    "address": "0x7fffffffd74e",
+                    "fields": [
+                        {
+                            "field": "b",
+                            "value": {
+                                "type": "int",
+                                "ctype": "uint16_t",
+                                "address": "0x7fffffffd74e",
+                                "value": "2"
+                            }
+                        }
+                    ],
+                    "base_classes": []
+                }
+            }
+        }
+    ],
+    "base_classes": []
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_foo_ptr.json b/gdb/gdb_json_printer/test/reference_41_foo_ptr.json
new file mode 100644
index 0000000..9d965e8
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_foo_ptr.json
@@ -0,0 +1,47 @@
+{
+    "type": "pointer",
+    "ctype": "Foo *",
+    "address": "0x7fffffffd768",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo",
+        "address": "0x7fffffffd750",
+        "fields": [
+            {
+                "field": "a",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint8_t",
+                    "address": "0x7fffffffd750",
+                    "value": "1"
+                }
+            },
+            {
+                "field": "bar",
+                "value": {
+                    "type": "pointer",
+                    "ctype": "Bar *",
+                    "address": "0x7fffffffd758",
+                    "reference": {
+                        "type": "struct",
+                        "ctype": "Bar",
+                        "address": "0x7fffffffd74e",
+                        "fields": [
+                            {
+                                "field": "b",
+                                "value": {
+                                    "type": "int",
+                                    "ctype": "uint16_t",
+                                    "address": "0x7fffffffd74e",
+                                    "value": "2"
+                                }
+                            }
+                        ],
+                        "base_classes": []
+                    }
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test/reference_41_foo_ref.json b/gdb/gdb_json_printer/test/reference_41_foo_ref.json
new file mode 100644
index 0000000..76975dc
--- /dev/null
+++ b/gdb/gdb_json_printer/test/reference_41_foo_ref.json
@@ -0,0 +1,47 @@
+{
+    "type": "reference",
+    "ctype": "Foo &",
+    "address": "0x7fffffffd750",
+    "reference": {
+        "type": "struct",
+        "ctype": "Foo",
+        "address": "0x7fffffffd750",
+        "fields": [
+            {
+                "field": "a",
+                "value": {
+                    "type": "int",
+                    "ctype": "uint8_t",
+                    "address": "0x7fffffffd750",
+                    "value": "1"
+                }
+            },
+            {
+                "field": "bar",
+                "value": {
+                    "type": "pointer",
+                    "ctype": "Bar *",
+                    "address": "0x7fffffffd758",
+                    "reference": {
+                        "type": "struct",
+                        "ctype": "Bar",
+                        "address": "0x7fffffffd74e",
+                        "fields": [
+                            {
+                                "field": "b",
+                                "value": {
+                                    "type": "int",
+                                    "ctype": "uint16_t",
+                                    "address": "0x7fffffffd74e",
+                                    "value": "2"
+                                }
+                            }
+                        ],
+                        "base_classes": []
+                    }
+                }
+            }
+        ],
+        "base_classes": []
+    }
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/array.cpp b/gdb/gdb_json_printer/test_examples/array.cpp
new file mode 100644
index 0000000..d2a9b85
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/array.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Bar {
+public:
+  uint16_t b = 2;
+};
+
+class Foo {
+public:
+  uint8_t a = 1;
+  Bar *bar = nullptr;
+};
+
+int main() {
+  int16_t a[5] = {1, 2, 3, 4, 5};
+  int16_t* b = &a[2];
+  Foo foo[3];
+  Bar bar[3];
+  foo[0].bar = &bar[0];
+  foo[1].bar = &bar[1];
+  foo[2].bar = &bar[2];
+  Foo& foo1 = foo[0];
+  
+  return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/basic_types.cpp b/gdb/gdb_json_printer/test_examples/basic_types.cpp
new file mode 100644
index 0000000..dd13c02
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/basic_types.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+
+enum Animal { CAT, DOG, TIGER };
+
+int main() {
+  {
+    uint8_t a = 1;
+    int8_t b = -2;
+    uint16_t c = 3;
+    int16_t d = -4;
+    uint32_t e = 5;
+    int32_t f = -6;
+    uint64_t g = 7;
+    int64_t h = -8;
+    float i = 9.0;
+    double j = -10.0;
+    const char *k = "Hello";
+    void *l = nullptr;
+    char *m = nullptr;
+    bool n = rand() % 2 == 0;
+    Animal o = CAT;
+    if (n) {
+      a += b;
+    }
+    std::cout << a + b + c + d + e + f + g + h + i + j << std::endl;
+  }
+  {
+    {
+      const uint8_t a = 1;
+      const int8_t b = -2;
+      const uint16_t c = 3;
+      const int16_t d = -4;
+      const uint32_t e = 5;
+      const int32_t f = -6;
+      const uint64_t g = 7;
+      const int64_t h = -8;
+      const float i = 9.0;
+      const double j = -10.0;
+      const char *k = "Hello";
+      const void *l = nullptr;
+      const char *m = nullptr;
+      const bool n = rand() % 2 == 0;
+      const Animal o = DOG;
+      if (n) {
+        std::cout << a + b + c + d + e + f + g + h + i + j << std::endl;
+      }
+    }
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/objects.cpp b/gdb/gdb_json_printer/test_examples/objects.cpp
new file mode 100644
index 0000000..9f3bb92
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/objects.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Bar {
+public:
+  uint16_t b = 2;
+};
+
+class Foo {
+public:
+  uint8_t a = 1;
+  Bar *bar = nullptr;
+};
+
+int main() {
+  {
+    Foo *foo = new Foo();
+    Bar *bar = new Bar();
+    foo->bar = bar;
+    delete foo;
+    delete bar;
+  }
+  {
+    std::unique_ptr<Foo> foo = std::make_unique<Foo>();
+    std::unique_ptr<Bar> bar = std::make_unique<Bar>();
+    foo->bar = bar.get();
+    foo->bar->b++;
+  }
+  {
+    std::shared_ptr<Foo> foo = std::make_shared<Foo>();
+    std::shared_ptr<Bar> bar = std::make_shared<Bar>();
+    foo->bar = bar.get();
+    foo->bar->b++;
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/objects1.cpp b/gdb/gdb_json_printer/test_examples/objects1.cpp
new file mode 100644
index 0000000..dc4e4d4
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/objects1.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Foo;
+
+class Bar {
+public:
+  uint16_t b = 2;
+  Foo *foo = nullptr;
+};
+
+class Foo {
+public:
+  uint8_t a = 1;
+  Bar *bar = nullptr;
+};
+
+int main() {
+  {
+    Foo *foo = new Foo();
+    Bar *bar = new Bar();
+    foo->bar = bar;
+    bar->foo = foo;
+    delete foo;
+    delete bar;
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/objects2.cpp b/gdb/gdb_json_printer/test_examples/objects2.cpp
new file mode 100644
index 0000000..7985cff
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/objects2.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Foo {
+public:
+  uint8_t a = 1;
+  virtual int get() = 0;
+};
+
+class Foo1 : public Foo {
+  uint16_t b = 2;
+  virtual int get() override { return b; }
+};
+
+class Foo2 : public Foo {
+public:
+  uint32_t c = 3;
+  uint32_t cc = 4;
+  virtual int get() override { return c; }
+};
+
+class Foo3 : public Foo1, public Foo2 {
+  uint32_t d = 4;
+  virtual int get() override { return d; }
+};
+
+class Foo4 : virtual public Foo {
+  uint16_t b = 2;
+  virtual int get() override { return b; }
+};
+
+class Foo5 : virtual public Foo {
+public:
+  uint32_t c = 3;
+  uint32_t cc = 4;
+  virtual int get() override { return c; }
+};
+
+class Foo6 : public Foo4, public Foo5 {
+  uint32_t d = 4;
+  virtual int get() override { return d; }
+};
+
+class Bar {
+public:
+  uint8_t e = 5;
+};
+
+class Bar1 : virtual public Bar {
+public:
+  uint8_t f = 6;
+};
+
+int main() {
+  {
+    Foo *x = new Foo1();
+    Foo *y = new Foo2();
+    Foo1 *z = new Foo3();
+    Foo *w = z;
+    Bar *a = new Bar1();
+    Foo2 b;
+    Foo &c = *w;
+    Foo1 d = *z;
+    b.c += 1;
+    Foo *e = new Foo6();
+    Foo4 *f = dynamic_cast<Foo6 *>(e);
+
+    delete a;
+    delete x;
+    delete y;
+    delete z;
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/gdb/gdb_json_printer/test_examples/reference.cpp b/gdb/gdb_json_printer/test_examples/reference.cpp
new file mode 100644
index 0000000..e86b7b4
--- /dev/null
+++ b/gdb/gdb_json_printer/test_examples/reference.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+class Bar {
+public:
+  uint16_t b = 2;
+};
+
+class Foo {
+public:
+  uint8_t a = 1;
+  Bar *bar = nullptr;
+};
+
+int main() {
+  Foo foo;
+  Bar bar;
+  foo.bar = &bar;
+  Foo &foo_ref = foo;
+  Bar &bar_ref = bar;
+  Foo *foo_ptr = &foo;
+  Bar *bar_ptr = &bar;
+
+  return 0;
+}
\ No newline at end of file
diff --git a/gdb/heap_print/README.md b/gdb/heap_print/README.md
new file mode 100644
index 0000000..63a767c
--- /dev/null
+++ b/gdb/heap_print/README.md
@@ -0,0 +1,44 @@
+Script supports 2 custom commands:
+
+1) watch_heap : sets break point at dynamic memory allocation and keeps track of it
+2) print_ptr : prints the memory pointed by raw pointer in hex format.
+
+                eg:
+                (gdb) print_ptr malloc_ptr
+                Type : int *
+                Starting Address: 0x55555556aeb0
+                Length : 40
+                0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x03 0x00 0x00 0x00
+                0x04 0x00 0x00 0x00 0x05 0x00 0x00 0x00 0x06 0x00 0x00 0x00
+                0x07 0x00 0x00 0x00 0x08 0x00 0x00 0x00 0x09 0x00 0x00 0x00
+                0x0a 0x00 0x00 0x00
+
+    If print_ptr is used after free/delete[], then it would print "No address mapping found!"
+
+
+Tests:
+
+To run the test
+
+In the heap_print dir,
+
+Compile :
+
+g++ -O0 -g test/sample_heap_test.cc -o test/sample_heap_test.o
+
+And then Run:
+
+$ gdb
+$ source test/test_heap_print_script.py
+
+
+Future Goals:
+
+To handle pointer offset, for eg, (gdb) print_ptr malloc_ptr + 3
+
+To handle custom allacator, may be watch_heap command could take in arguements
+and sets additional break points.
+
+
+
+
diff --git a/gdb/heap_print/heap_print_script.py b/gdb/heap_print/heap_print_script.py
new file mode 100644
index 0000000..f65d56b
--- /dev/null
+++ b/gdb/heap_print/heap_print_script.py
@@ -0,0 +1,239 @@
+import gdb
+
+
+def parse_address_to_int(address):
+    int_address_string = gdb.execute(
+        'p/d {}'.format(address), to_string=True)
+    int_address = int(int_address_string.split('=')[1].strip())
+    return int_address
+
+
+def parse_gdb_equals(str):
+    """
+    str is $1 = value. so it returns value
+    """
+    return str.split("=")[1].strip()
+
+
+class HeapMapping:
+    """
+    Wrapper class for dictionary to have customization for the dictionary
+    and one entry point
+    """
+
+    address_length_mapping = {}
+    address_set = set()
+
+    @staticmethod
+    def put(address, length):
+        HeapMapping.address_length_mapping[address] = length
+        HeapMapping.address_set.add(address)
+
+    @staticmethod
+    def get(address):
+        """
+        Gets the length of the dynamic array corresponding to address. Suppose dynamic
+        array is {1,2,3,4,5} and starting address is 400 which is passed as address to this
+        method, then method would return 20(i.e. 5 * sizeof(int)). When this address
+        is offsetted for eg 408 is passed to this method, then it will return remainder
+        number of bytes allocated, here it would be 12 (i.e. 420 - 408)
+        Algorithm tries to find address in address_length_apping, if it doesn't find it
+        then it tries to find the range that can fit the address. if it fails to find such
+        mapping then it would return None.
+        """
+
+        length_found = HeapMapping.address_length_mapping.get(address)
+        if length_found:
+            return length_found
+        else:
+            address_list = list(HeapMapping.address_set)
+            address_list.sort()
+            left = 0
+            right = len(address_list) - 1
+            while left <= right:
+                mid = int((left + right) / 2)
+                if address > address_list[mid]:
+                    left = mid + 1
+                # only < case would be accounted in else.
+                # As == would be handled in the if-check above (outside while)
+                else:
+                    right = mid - 1
+
+            index = left - 1
+            if index == -1:
+                return None
+            base_address = address_list[index]
+            base_len = HeapMapping.address_length_mapping.get(base_address)
+            if base_address + base_len > address:
+                return base_address + base_len - address
+            else:
+                return None
+
+    @staticmethod
+    def remove(address):
+        HeapMapping.address_length_mapping.pop(address, None)
+        HeapMapping.address_set.discard(address)
+
+
+class AllocationFinishedBreakpoint(gdb.FinishBreakpoint):
+    """
+    Sets temporary breakpoints on returns (specifically returns of memory allocations)
+    to record address allocated.
+    It get instantiated from AllocationBreakpoint and ReallocationBreakpoint. When it is
+    instantiated from ReallocationBreakPoint, it carries prev_address.
+    """
+
+    def __init__(self, length, prev_address=None):
+        super().__init__(internal=True)
+        self.length = length
+        self.prev_address = prev_address
+
+    def stop(self):
+        """
+        Called when the return address in the current frame is hit. It parses hex address
+        into int address. If return address is not null then it stores address and length
+        into the address_length_mapping dictionary.
+        """
+
+        return_address = self.return_value
+        if return_address is not None or return_address == 0x0:
+            if self.prev_address != None:
+                HeapMapping.remove(self.prev_address)
+
+            # Converting hex address to int address
+            int_address = parse_address_to_int(return_address)
+            HeapMapping.put(int_address, self.length)
+        return False
+
+
+class AllocationBreakpoint(gdb.Breakpoint):
+    """
+    Handler class when malloc and operator new[] gets hit
+    """
+
+    def __init__(self, spec):
+        super().__init__(spec, internal=True)
+
+    def stop(self):
+        # handle malloc and new
+        func_args_string = gdb.execute('info args', to_string=True)
+        if func_args_string.find("=") != -1:
+            # There will be just 1 argument to malloc. So no need to handle multiline
+            length = int(parse_gdb_equals(func_args_string))
+            AllocationFinishedBreakpoint(length)
+            return False
+
+
+class ReallocationBreakpoint(gdb.Breakpoint):
+    """
+    Handler class when realloc gets hit
+    """
+
+    def __init__(self, spec):
+        super().__init__(spec, internal=True)
+
+    def stop(self):
+        # handle realloc
+        func_args_string = gdb.execute('info args', to_string=True)
+        if func_args_string.find("=") != -1:
+            args = func_args_string.split("\n")
+            address = parse_gdb_equals(args[0])
+            int_address = parse_address_to_int(address)
+            length = int(parse_gdb_equals(args[1]))
+            AllocationFinishedBreakpoint(length, int_address)
+            return False
+
+
+class DeallocationBreakpoint(gdb.Breakpoint):
+    """
+    Handler class when free and operator delete[] gets hit
+    """
+
+    def __init__(self, spec):
+        super().__init__(spec, internal=True)
+
+    def stop(self):
+        func_args_string = gdb.execute('info args', to_string=True)
+        if func_args_string.find("=") != -1:
+            address = parse_gdb_equals(func_args_string)
+            int_address = parse_address_to_int(address)
+            HeapMapping.remove(int_address)
+        return False
+
+
+class WatchHeap(gdb.Command):
+    """
+    Custom Command to keep track of Heap Memory Allocation.
+    Currently keeps tracks of memory allocated/deallocated using
+    malloc, realloc, free, operator new[] and operator delete[]
+    """
+
+    def __init__(self):
+        super(WatchHeap, self).__init__("watch_heap", gdb.COMMAND_USER)
+
+    def complete(self, text, word):
+        return gdb.COMPLETE_COMMAND
+
+    def invoke(self, args, from_tty):
+        # TODO : Check whether break location methods are defined
+        AllocationBreakpoint("malloc")
+        AllocationBreakpoint("operator new[]")
+        ReallocationBreakpoint("realloc")
+        DeallocationBreakpoint("free")
+        DeallocationBreakpoint("operator delete[]")
+
+
+class PrintHeapPointer(gdb.Command):
+    """
+    Custom command to print memory allocated at dynamic time
+    """
+
+    def __init__(self):
+        super(PrintHeapPointer, self).__init__("print_ptr", gdb.COMMAND_USER)
+
+    def complete(self, text, word):
+        return gdb.COMPLETE_COMMAND
+
+    def invoke(self, args, from_tty=True):
+        try:
+            value = gdb.parse_and_eval(args)
+            if value.type.code == gdb.TYPE_CODE_PTR:
+                print("Type : ", value.type)
+                starting_address_string = gdb.execute(
+                    'p/x {}'.format(value), to_string=True)
+                print("Address: ",
+                      parse_gdb_equals(starting_address_string))
+                int_address = parse_address_to_int(value)
+                # print memory
+                self.print_heap(int_address)
+        except Exception:
+            print('No symbol found!')
+
+    def print_heap(self, address):
+        """
+        Prints the memory that is being pointed by address in hex format
+
+        Parameters
+        ---------
+        address : raw pointer
+        """
+
+        memory_size = HeapMapping.get(address)
+        if memory_size:
+            print('Length :', memory_size)
+            result = ''
+            i = 0
+            while i < memory_size:
+                byte_string = gdb.execute(
+                    'x/1bx {}'.format(address), to_string=True)
+                result += byte_string.split(':')[1].strip() + " "
+                address += 1
+                i += 1
+            print(result)
+        else:
+            print("No address mapping found!")
+
+
+if __name__ == '__main__':
+    WatchHeap()
+    PrintHeapPointer()
diff --git a/gdb/heap_print/test/sample_heap_test.cc b/gdb/heap_print/test/sample_heap_test.cc
new file mode 100644
index 0000000..783c471
--- /dev/null
+++ b/gdb/heap_print/test/sample_heap_test.cc
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <new>
+
+int main()
+{
+    int n = 10;
+
+    // Dynamically allocate memory using malloc()
+    int *malloc_ptr = (int *)malloc(n * sizeof(int));
+
+    if (malloc_ptr != NULL)
+    {
+        //Just Feeding data
+        for (int i = 0; i < n; ++i)
+        {
+            malloc_ptr[i] = i + 1;
+        }
+        //For checking realloc
+        int new_n = 20;
+        malloc_ptr = (int *)realloc(malloc_ptr, new_n * sizeof(int));
+        for (int i = 0; i < new_n; ++i)
+        {
+            malloc_ptr[i] = i + 1;
+        }
+        //For checking free
+        free(malloc_ptr);
+    }
+
+    // Dynamically allocating memory using operator new[]
+    int *new_ptr = new int[n];
+    if (new_ptr != NULL)
+    {
+        //Just feeding data
+        for (int i = 0; i < n; ++i)
+        {
+            new_ptr[i] = i + 1;
+        }
+
+        //For checking operator delete[]
+        delete[] new_ptr;
+    }
+    printf("Done");
+    return 0;
+}
\ No newline at end of file
diff --git a/gdb/heap_print/test/test_heap_print_script.py b/gdb/heap_print/test/test_heap_print_script.py
new file mode 100644
index 0000000..5518527
--- /dev/null
+++ b/gdb/heap_print/test/test_heap_print_script.py
@@ -0,0 +1,113 @@
+import unittest
+import gdb
+
+
+def get_n(n_str):
+    return int(n_str.split("=")[1].strip())
+
+
+class HeapMemoryTest(unittest.TestCase):
+
+    def setUp(self):
+        gdb.execute('set pagination on')
+        gdb.execute("file test/sample_heap_test.o")
+        gdb.execute("source heap_print_script.py")
+        gdb.execute("delete")
+        gdb.execute("watch_heap")
+
+    def check_memory(self, n, array_ptr_str, offset=1):
+        """
+        It is used to test what we got from 'print_ptr' is what we expect.
+        Sample test program allocates array of n int's using malloc and then
+        assigns 1 to n values to that array. So checking that malloc_ptr_str
+        is 1 to n, following big endian size and size of int as 32 bits
+
+        Parameters
+        ----------
+        n : int
+            array length
+        array_ptr_str : str
+            whole output from print_ptr command including memory content
+        offset : int
+            checking memory content starts from offset value. By default it is 1
+        """
+
+        data = array_ptr_str.split("\n")[3]
+        bytes_from_heap = data.split(" ")
+        actual_start = offset
+        for i in range(0, n * 4, 4):
+            hex_str = bytes_from_heap[i+3][2:]
+            hex_str += bytes_from_heap[i+2][2:]
+            hex_str += bytes_from_heap[i+1][2:]
+            hex_str += bytes_from_heap[i][2:]
+            int_of_hex = int(hex_str, 16)
+            self.assertEqual(actual_start, int_of_hex)
+            actual_start += 1
+
+    def test_malloc(self):
+        print("malloc test")
+        gdb.execute("b 20")
+        gdb.execute("r")
+        n_str = gdb.execute("print n", to_string=True)
+        n = get_n(n_str)
+        malloc_ptr_array_str = gdb.execute(
+            "print_ptr malloc_ptr", to_string=True)
+        print(malloc_ptr_array_str)
+        self.check_memory(n, malloc_ptr_array_str)
+        self.assertTrue(True)
+
+    def test_realloc(self):
+        print("realloc test")
+        gdb.execute("b 27")
+        gdb.execute("r")
+        new_n = gdb.execute("print new_n", to_string=True)
+        n = get_n(new_n)
+        malloc_ptr_str = gdb.execute("print_ptr malloc_ptr", to_string=True)
+        print(malloc_ptr_str)
+        self.check_memory(n, malloc_ptr_str)
+
+    def test_offset(self):
+        """
+        Testcase to test raw_pointers that are offset
+        """
+
+        print("offset test. we have array of 20 (80 bytes) and \
+                we offset it by 3, so new length should be 68")
+        offset = 3
+        gdb.execute("b 27")
+        gdb.execute("r")
+        new_n = gdb.execute("print new_n", to_string=True)
+        n = get_n(new_n)
+        malloc_ptr_str = gdb.execute(
+            "print_ptr malloc_ptr + {}".format(offset), to_string=True)
+        print(malloc_ptr_str)
+        self.check_memory(n - offset, malloc_ptr_str, offset+1)
+
+    def test_free(self):
+        print("free test")
+        gdb.execute("b 28")
+        gdb.execute("r")
+        malloc_ptr_str = gdb.execute("print_ptr malloc_ptr", to_string=True)
+        data = malloc_ptr_str.split("\n")[2].strip()
+        self.assertEqual(data, "No address mapping found!")
+
+    def test_new(self):
+        print("operator new[] test")
+        gdb.execute("b 41")
+        gdb.execute("r")
+        n_str = gdb.execute("print n", to_string=True)
+        n = get_n(n_str)
+        new_ptr_array_str = gdb.execute("print_ptr new_ptr", to_string=True)
+        self.check_memory(n, new_ptr_array_str)
+
+    def test_delete(self):
+        print("operator delete[]")
+        gdb.execute("b 42")
+        gdb.execute("r")
+        new_ptr_array_str = gdb.execute("print_ptr new_ptr", to_string=True)
+        data = new_ptr_array_str.split("\n")[2].strip()
+        self.assertEqual(data, "No address mapping found!")
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/gdb/parameters_extract.py b/gdb/parameters_extract.py
new file mode 100644
index 0000000..b1af70c
--- /dev/null
+++ b/gdb/parameters_extract.py
@@ -0,0 +1,288 @@
+import os
+import re
+
+# If doing it on device with gdbserver
+DEVICE = os.environ.get('GDBSCRIPT_ON_DEVICE', False)
+# Path of the file on device
+DEVICE_FILEPATH = os.environ.get('GDBSCRIPT_FILENAME', None)
+# GDBServer's port
+DEVICE_PORT = os.environ.get('GDBSCRIPT_DEVICE_PORT', 4444)
+# Serial number of device for adb
+DEVICE_SERIAL = os.environ.get('GDBSCRIPT_DEVICE_SERIAL', None)
+
+def check_device_args():
+    """
+    Checks if FILEPATH is provided if the execution is on device
+    """
+    if not DEVICE:
+        return
+
+    if not DEVICE_FILEPATH:
+        raise ValueError("Filename (GDBSCRIPT_FILEPATH) not provided")
+
+class RecordPoint(gdb.Breakpoint):
+    """
+    A custom breakpoint that records the arguments when the breakpoint is hit and continues
+    Also enables the next breakpoint and disables all the ones after it
+    """
+    def stop(self):
+        """
+        The function that's called when a breakpoint is hit. If we return true,
+        it halts otherwise it continues
+        We always return false because we just need to record the value and we
+        can do it without halting the program
+        """
+        self.args[self.times_hit % self.count] = get_function_args()
+        self.times_hit += 1
+
+        if self.next_bp != None:
+            self.next_bp.previous_hit()
+
+        return False
+
+    def previous_hit(self):
+        """
+        This function is called if the previous breakpoint is hit so it can enable
+        itself and disable the next ones
+        """
+        self.enabled = True
+
+        if self.next_bp != None:
+            self.next_bp.propagate_disable()
+
+    def propagate_disable(self):
+        """
+        Disabled all the breakpoints after itself
+        """
+        self.enabled = False
+        if self.next_bp != None:
+            self.next_bp.propagate_disable()
+
+    def process_arguments(self):
+        """
+        Orders the recorded arguments into the right order (oldest to newest)
+        """
+        current_hit_point = self.times_hit % self.count
+        # Split at the point of current_hit_point because all the entries after it
+        # are older than the ones before it
+        self.processed_args = self.args[current_hit_point:] + self.args[:current_hit_point]
+        self.current_arg_idx = 0
+
+    def get_arguments(self):
+        """
+        Gets the current argument value.
+        Should be called the same amount of times as the function was called
+        in the stacktrace
+        First call returns the arguments recorded for the first call in the stacktrace
+        and so on.
+        """
+        if self.current_arg_idx >= len(self.processed_args):
+            raise ValueError("Cannot get arguments more times than the function \
+                    was present in stacktrace")
+
+        cur = self.processed_args[self.current_arg_idx]
+        self.current_arg_idx += 1
+        return cur
+
+def init_gdb():
+    """
+    Initialized the GDB specific stuff
+    """
+    gdb.execute('set pagination off')
+    gdb.execute('set print frame-arguments all')
+    if DEVICE:
+        gdb.execute('target extended-remote :{}'.format(DEVICE_PORT))
+        gdb.execute('set remote exec-file /data/local/tmp/{}'.format(DEVICE_FILEPATH))
+
+def initial_run():
+    """
+    The initial run of the program which captures the stacktrace in init.log file
+    """
+    gdb.execute('r > init.log 2>&1',from_tty=True, to_string=True)
+    if DEVICE:
+        if DEVICE_SERIAL:
+            os.system('adb -s "{}" pull /data/local/tmp/init.log'.format(DEVICE_SERIAL))
+        else:
+            os.system("adb pull /data/local/tmp/init.log")
+    with open("init.log", "rb") as f:
+        out = f.read().decode()
+    return out
+
+def gdb_exit():
+    """
+    Exits the GDB instance
+    """
+    gdb.execute('q')
+
+def get_stacktrace_functions(stacktrace):
+    """
+    Gets the functions from ASAN/HWASAN's stacktrace
+    Args:
+        stacktrace: (string) ASAN/HWASAN's stacktrace output
+    Returns:
+        functions: (list) functions in the stacktrace
+    """
+    stacktrace_start = stacktrace[stacktrace.index('==ERROR: '):].split("\n")
+    functions = []
+
+    # skip the first two lines of stacktrace
+    for line in stacktrace_start[2:]:
+        if line == "":
+            break
+
+        # Extracts the function name from a line like this
+        # "#0 0xaddress in function_name() file/path.cc:xx:yy"
+        func_name = line.strip().split(" ")[3]
+        if '(' in func_name:
+            func_name = func_name[:func_name.index('(')]
+
+        functions.append(func_name)
+
+    #remove last function from stacktrace because it would be _start
+    return functions
+
+def parse_function_arguments(func_info):
+    """
+    Parses the output of 'whatis' command into a list of arguments
+    "void (teststruct)" --> ["teststruct"]
+    "int (int (*)(int, char **, char **), int, char **, int (*)(int, char **, char **),
+    void (*)(void), void (*)(void), void *)" --> ['int (*)(int, char **, char **)',
+    'int', 'char **', 'int (*)(int, char **, char **)', 'void (*)(void)',
+    'void (*)(void)', ' void *']
+
+    Args:
+        func_info: (string) output of gdb's 'whatis' command for a function
+    Returns:
+        parsed_params: (list) parsed parameters of the function
+    """
+    if '(' not in func_info:
+        return []
+    func_params = func_info[func_info.index('(')+1:-1]
+    parentheses_count = 0
+    current_param = ""
+    parsed_params = []
+
+    for token in func_params:
+        # Essentially trying to get the data types from a function declaration
+        if token == '(':
+            parentheses_count += 1
+        elif token == ')':
+            parentheses_count -= 1
+
+        # If we are not inside any paren and see a ',' it signals the start of
+        #the next parameter
+        if token == ',' and parentheses_count == 0:
+            parsed_params.append(current_param.strip())
+            current_param = ""
+        else:
+            current_param += token
+
+    parsed_params.append(current_param)
+    return parsed_params
+
+def parse_stacktrace(stacktrace):
+    """
+    Parses the ASAN/HWASAN's stacktrace to a list of functions, their addresses
+    and argument types
+    Args:
+        stacktrace: (string) ASAN/HWASAN's stacktrace output
+    Returns:
+        functions_info: (list) parsed function information as a dictionary
+    """
+    stacktrace_functions = get_stacktrace_functions(stacktrace)[:-1]
+    functions_info = []
+    for function in stacktrace_functions:
+        # Gets the value right hand side of gdb's whatis command.
+        # "type = {function info}" -> "{function info}"
+        func_info = gdb.execute('whatis {}'.format(function),
+                to_string=True).split(' = ')[1].strip()
+        # Uses gdb's x/i to print its address and parse it from hex to int
+        address = int(gdb.execute("x/i {}".format(function),
+            to_string=True).strip().split(" ")[0], 16)
+        functions_info.append({'name': function, 'address':address,
+            'arguments' : parse_function_arguments(func_info)})
+    #In the order they are called in the execution
+    return functions_info[::-1]
+
+def get_function_args():
+    """
+    Gets the current function arguments
+    """
+    args = gdb.execute('info args -q', to_string=True).strip()
+    return args
+
+def functions_to_breakpoint(parsed_functions):
+    """
+    Sets the breakpoint at every function and returns a dictionary mapping the
+    function to it's breakpoint
+    Args:
+        parsed_functions: (list) functions in the stacktrace (in the same order) as
+        dictionary with "name" referring to the function name
+        ({"name" : function_name})
+    Returns:
+        function_breakpoints: (dictionary) maps the function name to its
+        breakpoint object
+    """
+    function_breakpoints = {}
+    last_bp = None
+
+    for function in reversed(parsed_functions):
+        function_name = function['name']
+        if function_name in function_breakpoints:
+            function_breakpoints[function_name].count += 1
+            function_breakpoints[function_name].args.append(None)
+            continue
+
+        cur_bp = RecordPoint("{}".format(function_name))
+        cur_bp.count = 1
+        cur_bp.times_hit = 0
+        cur_bp.args = []
+        cur_bp.args.append(None)
+        cur_bp.next_bp = last_bp
+
+        function_breakpoints[function['name']] = cur_bp
+        last_bp = cur_bp
+
+    return function_breakpoints
+
+def run(parsed_functions):
+    """
+    Runs the whole thing by setting up breakpoints and printing them after
+    excecution is done
+    Args:
+        parsed_functions: A list of functions in the stacktrace (in the same order)
+        as dictionary with "name" referring to the function name
+        ({"name" : function_name})
+    """
+    names = [function['name'] for function in parsed_functions]
+    breakpoints = functions_to_breakpoint(parsed_functions)
+
+    #Disable all breakpoints at start
+    for bp in breakpoints:
+        breakpoints[bp].enabled = False
+
+    breakpoints[names[0]].enabled = True
+
+    gdb.execute('r')
+    for breakpoint in breakpoints:
+        breakpoints[breakpoint].process_arguments()
+
+    function_args = []
+    for name in names:
+        print("-----------")
+        print("Function -> {}".format(name))
+
+        function_args.append({'function':name,
+            'arguments' : breakpoints[name].get_arguments()})
+        print(function_args[-1]['arguments'])
+
+    return function_args
+
+
+if __name__ == '__main__':
+    check_device_args()
+    init_gdb()
+    initial_out = initial_run()
+    function_data = parse_stacktrace(initial_out)
+    run(function_data)
+    gdb_exit()
diff --git a/remote_provisioning/OWNERS b/remote_provisioning/OWNERS
new file mode 100644
index 0000000..78a6711
--- /dev/null
+++ b/remote_provisioning/OWNERS
@@ -0,0 +1,3 @@
+jbires@google.com
+swillden@google.com
+wedsonaf@google.com
diff --git a/remote_provisioning/attestation_testing/Android.bp b/remote_provisioning/attestation_testing/Android.bp
new file mode 100644
index 0000000..341f7c0
--- /dev/null
+++ b/remote_provisioning/attestation_testing/Android.bp
@@ -0,0 +1,16 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "AttestationTestTool",
+    srcs: [
+        "java/**/*.java",
+    ],
+    manifest: "AndroidManifest.xml",
+    resource_dirs: ["res"],
+    static_libs: ["androidx.appcompat_appcompat",
+                  "bouncycastle-unbundled",
+                  "guava"],
+    platform_apis: true,
+}
diff --git a/remote_provisioning/attestation_testing/AndroidManifest.xml b/remote_provisioning/attestation_testing/AndroidManifest.xml
new file mode 100644
index 0000000..9af01e5
--- /dev/null
+++ b/remote_provisioning/attestation_testing/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.attestationexample">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher">
+        <activity
+            android:name=".AttestationActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/remote_provisioning/attestation_testing/README b/remote_provisioning/attestation_testing/README
new file mode 100644
index 0000000..fc92654
--- /dev/null
+++ b/remote_provisioning/attestation_testing/README
@@ -0,0 +1,8 @@
+Run the following commands to run this attestation test on device. From the root of the tree:
+> . build/envsetup.sh
+> lunch <<your_device_target>>
+> m AttestationTestTool
+> python tools/security/remote_provisioning/attestation_testing/attestation_test_host.py
+
+Any failures found during execution will be printed to the terminal in the format of:
+> AttestationFail: <<Description of failure>>
diff --git a/remote_provisioning/attestation_testing/attestation_test_host.py b/remote_provisioning/attestation_testing/attestation_test_host.py
new file mode 100644
index 0000000..417842a
--- /dev/null
+++ b/remote_provisioning/attestation_testing/attestation_test_host.py
@@ -0,0 +1,38 @@
+from sys import argv
+import os
+import subprocess
+import time
+
+APK_DIR = '${ANDROID_PRODUCT_OUT}/system/app/AttestationTestTool/AttestationTestTool.apk'
+FAILURE_TAG = 'AttestationFail'
+FAILURE_PREFIX = 'Failure: '
+FINISHED_TAG = 'AttestationFinished'
+INFO_TAG = 'AttestationFailInfo'
+INFO_PREFIX = ' ' * len(FAILURE_PREFIX)
+devnull = open(os.devnull, 'wb')
+
+# Clear logcat
+subprocess.call('adb logcat -c', shell=True, stdout=devnull)
+subprocess.call('adb install -r ' + APK_DIR, shell=True, stdout=devnull)
+subprocess.call('adb shell am start -a android.intent.action.MAIN -n com.google.attestationexample/.AttestationActivity',
+                shell=True, stdout=devnull)
+finished = False
+read_retry = 0
+failures = 0
+while not finished and read_retry < 5:
+    time.sleep(1)
+    logcat = subprocess.check_output(['adb', 'logcat', '-d'], stderr=subprocess.STDOUT)
+    for line in logcat.split('\n'):
+        if INFO_TAG in line:
+            print INFO_PREFIX + line[line.index('AttestationFailInfo') + len('AttestationFailInfo:'):]
+        elif FAILURE_TAG in line:
+            failures += 1
+            print FAILURE_PREFIX + line[line.index('AttestationFail') + len('AttestationFail:'):]
+        elif FINISHED_TAG in line and not finished:
+            print 'Finished. Failures: ' + str(failures)
+            finished = True
+            break
+    read_retry += 1
+    if read_retry is 5:
+        print 'Attestation test did not complete, check logcat to determine the source of the error'
+subprocess.call('adb uninstall com.google.attestationexample', shell=True, stdout=devnull)
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/Asn1Utils.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Asn1Utils.java
new file mode 100644
index 0000000..c3dc62b
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Asn1Utils.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.attestationexample;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.bouncycastle.asn1.ASN1Boolean;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DEROctetString;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.String;
+import java.math.BigInteger;
+import java.security.cert.CertificateParsingException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Set;
+
+public class Asn1Utils {
+
+    public static int getIntegerFromAsn1(ASN1Encodable asn1Value)
+            throws CertificateParsingException {
+        if (asn1Value instanceof ASN1Integer) {
+            return bigIntegerToInt(((ASN1Integer) asn1Value).getValue());
+        } else if (asn1Value instanceof ASN1Enumerated) {
+            return bigIntegerToInt(((ASN1Enumerated) asn1Value).getValue());
+        } else {
+            throw new CertificateParsingException(
+                    "Integer value expected, " + asn1Value.getClass().getName() + " found.");
+        }
+    }
+
+    public static Long getLongFromAsn1(ASN1Encodable asn1Value) throws CertificateParsingException {
+        if (asn1Value instanceof ASN1Integer) {
+            return bigIntegerToLong(((ASN1Integer) asn1Value).getValue());
+        } else {
+            throw new CertificateParsingException(
+                    "Integer value expected, " + asn1Value.getClass().getName() + " found.");
+        }
+    }
+
+    public static byte[] getByteArrayFromAsn1(ASN1Encodable asn1Encodable)
+            throws CertificateParsingException {
+        if (asn1Encodable == null || !(asn1Encodable instanceof DEROctetString)) {
+            throw new CertificateParsingException("Expected DEROctetString");
+        }
+        ASN1OctetString derOctectString = (ASN1OctetString) asn1Encodable;
+        return derOctectString.getOctets();
+    }
+
+    public static ASN1Encodable getAsn1EncodableFromBytes(byte[] bytes)
+            throws CertificateParsingException {
+        try (ASN1InputStream asn1InputStream = new ASN1InputStream(bytes)) {
+            return asn1InputStream.readObject();
+        } catch (IOException e) {
+            throw new CertificateParsingException("Failed to parse Encodable", e);
+        }
+    }
+
+    public static ASN1Sequence getAsn1SequenceFromBytes(byte[] bytes)
+            throws CertificateParsingException {
+        try (ASN1InputStream asn1InputStream = new ASN1InputStream(bytes)) {
+            return getAsn1SequenceFromStream(asn1InputStream);
+        } catch (IOException e) {
+            throw new CertificateParsingException("Failed to parse SEQUENCE", e);
+        }
+    }
+
+    public static ASN1Sequence getAsn1SequenceFromStream(final ASN1InputStream asn1InputStream)
+            throws IOException, CertificateParsingException {
+        ASN1Primitive asn1Primitive = asn1InputStream.readObject();
+        if (!(asn1Primitive instanceof ASN1OctetString)) {
+            throw new CertificateParsingException(
+                    "Expected octet stream, found " + asn1Primitive.getClass().getName());
+        }
+        try (ASN1InputStream seqInputStream = new ASN1InputStream(
+                ((ASN1OctetString) asn1Primitive).getOctets())) {
+            asn1Primitive = seqInputStream.readObject();
+            if (!(asn1Primitive instanceof ASN1Sequence)) {
+                throw new CertificateParsingException(
+                        "Expected sequence, found " + asn1Primitive.getClass().getName());
+            }
+            return (ASN1Sequence) asn1Primitive;
+        }
+    }
+
+    public static Set<Integer> getIntegersFromAsn1Set(ASN1Encodable set)
+            throws CertificateParsingException {
+        if (!(set instanceof ASN1Set)) {
+            throw new CertificateParsingException(
+                    "Expected set, found " + set.getClass().getName());
+        }
+
+        ImmutableSet.Builder<Integer> builder = ImmutableSet.builder();
+        for (Enumeration<?> e = ((ASN1Set) set).getObjects(); e.hasMoreElements();) {
+            builder.add(getIntegerFromAsn1((ASN1Integer) e.nextElement()));
+        }
+        return builder.build();
+    }
+
+    public static String getStringFromAsn1OctetStreamAssumingUTF8(ASN1Encodable encodable)
+            throws CertificateParsingException, UnsupportedEncodingException {
+        if (!(encodable instanceof ASN1OctetString)) {
+            throw new CertificateParsingException(
+                    "Expected octet string, found " + encodable.getClass().getName());
+        }
+
+        ASN1OctetString octetString = (ASN1OctetString) encodable;
+        return new String(octetString.getOctets(), "UTF-8");
+    }
+
+    public static Date getDateFromAsn1(ASN1Primitive value) throws CertificateParsingException {
+        return new Date(getLongFromAsn1(value));
+    }
+
+    public static boolean getBooleanFromAsn1(ASN1Encodable value)
+            throws CertificateParsingException {
+        if (!(value instanceof ASN1Boolean)) {
+            throw new CertificateParsingException(
+                    "Expected boolean, found " + value.getClass().getName());
+        }
+        return ((ASN1Boolean) value).isTrue();
+    }
+
+    private static int bigIntegerToInt(BigInteger bigInt) throws CertificateParsingException {
+        if (bigInt.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0
+                || bigInt.compareTo(BigInteger.ZERO) < 0) {
+            throw new CertificateParsingException("INTEGER out of bounds");
+        }
+        return bigInt.intValue();
+    }
+
+    private static long bigIntegerToLong(BigInteger bigInt) throws CertificateParsingException {
+        if (bigInt.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0
+                || bigInt.compareTo(BigInteger.ZERO) < 0) {
+            throw new CertificateParsingException("INTEGER out of bounds");
+        }
+        return bigInt.longValue();
+    }
+}
\ No newline at end of file
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/Attestation.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Attestation.java
new file mode 100644
index 0000000..c94ff3f
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Attestation.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.attestationexample;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.io.BaseEncoding;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Parses an attestation certificate and provides an easy-to-use interface for examining the
+ * contents.
+ */
+public class Attestation {
+    static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";
+    static final int ATTESTATION_VERSION_INDEX = 0;
+    static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
+    static final int KEYMASTER_VERSION_INDEX = 2;
+    static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
+    static final int ATTESTATION_CHALLENGE_INDEX = 4;
+    static final int UNIQUE_ID_INDEX = 5;
+    static final int SW_ENFORCED_INDEX = 6;
+    static final int TEE_ENFORCED_INDEX = 7;
+
+    public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
+    public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
+    public static final int KM_SECURITY_LEVEL_STRONGBOX = 2;
+
+    private final boolean haveAttestation;
+    private final int attestationVersion;
+    private final int attestationSecurityLevel;
+    private final int keymasterVersion;
+    private final int keymasterSecurityLevel;
+    private final byte[] attestationChallenge;
+    private final byte[] uniqueId;
+    private final AuthorizationList softwareEnforced;
+    private final AuthorizationList teeEnforced;
+
+
+    /**
+     * Constructs an {@code Attestation} object from the provided {@link X509Certificate},
+     * extracting the attestation data from the attestation extension.
+     *
+     * @throws CertificateParsingException if the certificate does not contain a properly-formatted
+     *                                     attestation extension.
+     */
+    public Attestation(X509Certificate x509Cert) throws CertificateParsingException {
+        ASN1Sequence seq = getAttestationSequence(x509Cert);
+        if (seq == null) {
+            haveAttestation = false;
+            attestationVersion = 0;
+            attestationSecurityLevel = 0;
+            keymasterVersion = 0;
+            keymasterSecurityLevel = 0;
+            attestationChallenge = null;
+            uniqueId = null;
+            softwareEnforced = null;
+            teeEnforced = null;
+            return;
+        }
+
+        haveAttestation = true;
+        attestationVersion =
+                Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_VERSION_INDEX));
+        attestationSecurityLevel =
+                Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX));
+        keymasterVersion = Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_VERSION_INDEX));
+        keymasterSecurityLevel =
+                Asn1Utils.getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX));
+
+        attestationChallenge =
+                Asn1Utils.getByteArrayFromAsn1(
+                        seq.getObjectAt(Attestation.ATTESTATION_CHALLENGE_INDEX));
+
+        uniqueId = Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(Attestation.UNIQUE_ID_INDEX));
+
+        softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX));
+        teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX));
+    }
+
+    public static String securityLevelToString(int attestationSecurityLevel) {
+        switch (attestationSecurityLevel) {
+            case KM_SECURITY_LEVEL_SOFTWARE:
+                return "Software";
+            case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+                return "TEE";
+            case KM_SECURITY_LEVEL_STRONGBOX:
+                return "StrongBox";
+            default:
+                return "Unknown";
+        }
+    }
+
+    public int getAttestationVersion() {
+        return attestationVersion;
+    }
+
+    public int getAttestationSecurityLevel() {
+        return attestationSecurityLevel;
+    }
+
+    public int getKeymasterVersion() {
+        return keymasterVersion;
+    }
+
+    public int getKeymasterSecurityLevel() {
+        return keymasterSecurityLevel;
+    }
+
+    public byte[] getAttestationChallenge() {
+        return attestationChallenge;
+    }
+
+    public byte[] getUniqueId() {
+        return uniqueId;
+    }
+
+    public AuthorizationList getSoftwareEnforced() {
+        return softwareEnforced;
+    }
+
+    public AuthorizationList getTeeEnforced() {
+        return teeEnforced;
+    }
+
+    @Override
+    public String toString() {
+        if (!haveAttestation) {
+            return "No attestation";
+        }
+
+        StringBuilder s = new StringBuilder();
+        s.append("Attestation version: " + attestationVersion);
+        s.append("\nAttestation security: " + securityLevelToString(attestationSecurityLevel));
+        s.append("\nKM version: " + keymasterVersion);
+        s.append("\nKM security: " + securityLevelToString(keymasterSecurityLevel));
+
+        s.append("\nChallenge");
+        String stringChallenge = new String(attestationChallenge);
+        if (CharMatcher.ascii().matchesAllOf(stringChallenge)) {
+            s.append(": [" + stringChallenge + "]");
+        } else {
+            s.append(" (base64): [" + BaseEncoding.base64().encode(attestationChallenge) + "]");
+        }
+        if (uniqueId != null) {
+            s.append("\nUnique ID (base64): [" + BaseEncoding.base64().encode(uniqueId) + "]");
+        }
+
+        s.append("\n\n-- SW enforced --");
+        s.append(softwareEnforced);
+        s.append("\n\n-- TEE enforced --");
+        s.append(teeEnforced);
+        s.append("\n");
+
+        return s.toString();
+    }
+
+    private ASN1Sequence getAttestationSequence(X509Certificate x509Cert)
+            throws CertificateParsingException {
+        byte[] attestationExtensionBytes = x509Cert.getExtensionValue(KEY_DESCRIPTION_OID);
+        if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
+            return null;
+        }
+        return Asn1Utils.getAsn1SequenceFromBytes(attestationExtensionBytes);
+    }
+
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationActivity.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationActivity.java
new file mode 100644
index 0000000..0fb8cf4
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationActivity.java
@@ -0,0 +1,21 @@
+package com.google.attestationexample;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class AttestationActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        runTests();
+    }
+
+    private void runTests() {
+        try {
+            new AttestationTest().execute();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationApplicationId.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationApplicationId.java
new file mode 100644
index 0000000..b0bd257
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationApplicationId.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.attestationexample;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+
+import java.security.cert.CertificateParsingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
+
+public class AttestationApplicationId implements java.lang.Comparable<AttestationApplicationId> {
+    private static final int PACKAGE_INFOS_INDEX = 0;
+    private static final int SIGNATURE_DIGESTS_INDEX = 1;
+
+    private final List<AttestationPackageInfo> packageInfos;
+    private final List<byte[]> signatureDigests;
+
+    public AttestationApplicationId(Context context)
+            throws NoSuchAlgorithmException, NameNotFoundException {
+        PackageManager pm = context.getPackageManager();
+        int uid = context.getApplicationInfo().uid;
+        String[] packageNames = pm.getPackagesForUid(uid);
+        if (packageNames == null || packageNames.length == 0) {
+            throw new NameNotFoundException("No names found for uid");
+        }
+        packageInfos = new ArrayList<AttestationPackageInfo>();
+        for (String packageName : packageNames) {
+            // get the package info for the given package name including
+            // the signatures
+            PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+            packageInfos.add(new AttestationPackageInfo(packageName, packageInfo.versionCode));
+        }
+        // The infos must be sorted, the implementation of Comparable relies on it.
+        packageInfos.sort(null);
+
+        // compute the sha256 digests of the signature blobs
+        signatureDigests = new ArrayList<byte[]>();
+        PackageInfo packageInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
+        for (Signature signature : packageInfo.signatures) {
+            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+            signatureDigests.add(sha256.digest(signature.toByteArray()));
+        }
+        // The digests must be sorted. the implementation of Comparable relies on it
+        signatureDigests.sort(new ByteArrayComparator());
+    }
+
+    public AttestationApplicationId(ASN1Encodable asn1Encodable)
+            throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Sequence)) {
+            throw new CertificateParsingException(
+                    "Expected sequence for AttestationApplicationId, found "
+                            + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+        packageInfos = parseAttestationPackageInfos(sequence.getObjectAt(PACKAGE_INFOS_INDEX));
+        // The infos must be sorted, the implementation of Comparable relies on it.
+        packageInfos.sort(null);
+        signatureDigests = parseSignatures(sequence.getObjectAt(SIGNATURE_DIGESTS_INDEX));
+        // The digests must be sorted. the implementation of Comparable relies on it
+        signatureDigests.sort(new ByteArrayComparator());
+    }
+
+    public List<AttestationPackageInfo> getAttestationPackageInfos() {
+        return packageInfos;
+    }
+
+    public List<byte[]> getSignatureDigests() {
+        return signatureDigests;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        int noOfInfos = packageInfos.size();
+        int i = 1;
+        for (AttestationPackageInfo info : packageInfos) {
+            sb.append("\n### Package info " + i + "/" + noOfInfos + " ###\n");
+            sb.append(info);
+        }
+        i = 1;
+        int noOfSigs = signatureDigests.size();
+        for (byte[] sig : signatureDigests) {
+            sb.append("\nSignature digest " + i++ + "/" + noOfSigs + ":");
+            for (byte b : sig) {
+                sb.append(String.format(" %02X", b));
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public int compareTo(AttestationApplicationId other) {
+        int res = Integer.compare(packageInfos.size(), other.packageInfos.size());
+        if (res != 0) return res;
+        for (int i = 0; i < packageInfos.size(); ++i) {
+            res = packageInfos.get(i).compareTo(other.packageInfos.get(i));
+            if (res != 0) return res;
+        }
+        res = Integer.compare(signatureDigests.size(), other.signatureDigests.size());
+        if (res != 0) return res;
+        ByteArrayComparator cmp = new ByteArrayComparator();
+        for (int i = 0; i < signatureDigests.size(); ++i) {
+            res = cmp.compare(signatureDigests.get(i), other.signatureDigests.get(i));
+            if (res != 0) return res;
+        }
+        return res;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof AttestationApplicationId)
+                && (0 == compareTo((AttestationApplicationId) o));
+    }
+
+    private List<AttestationPackageInfo> parseAttestationPackageInfos(ASN1Encodable asn1Encodable)
+            throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Set)) {
+            throw new CertificateParsingException(
+                    "Expected set for AttestationApplicationsInfos, found "
+                            + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Set set = (ASN1Set) asn1Encodable;
+        List<AttestationPackageInfo> result = new ArrayList<AttestationPackageInfo>();
+        for (ASN1Encodable e : set) {
+            result.add(new AttestationPackageInfo(e));
+        }
+        return result;
+    }
+
+    private List<byte[]> parseSignatures(ASN1Encodable asn1Encodable)
+            throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Set)) {
+            throw new CertificateParsingException("Expected set for Signature digests, found "
+                    + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Set set = (ASN1Set) asn1Encodable;
+        List<byte[]> result = new ArrayList<byte[]>();
+
+        for (ASN1Encodable e : set) {
+            result.add(Asn1Utils.getByteArrayFromAsn1(e));
+        }
+        return result;
+    }
+
+    private class ByteArrayComparator implements java.util.Comparator<byte[]> {
+        @Override
+        public int compare(byte[] a, byte[] b) {
+            int res = Integer.compare(a.length, b.length);
+            if (res != 0) return res;
+            for (int i = 0; i < a.length; ++i) {
+                res = Byte.compare(a[i], b[i]);
+                if (res != 0) return res;
+            }
+            return res;
+        }
+    }
+}
\ No newline at end of file
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationPackageInfo.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationPackageInfo.java
new file mode 100644
index 0000000..3ccaf7a
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationPackageInfo.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.attestationexample;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+
+import java.io.UnsupportedEncodingException;
+
+public class AttestationPackageInfo implements java.lang.Comparable<AttestationPackageInfo> {
+    private static final int PACKAGE_NAME_INDEX = 0;
+    private static final int VERSION_INDEX = 1;
+
+    private final String packageName;
+    private final int version;
+
+    public AttestationPackageInfo(String packageName, int version) {
+        this.packageName = packageName;
+        this.version = version;
+    }
+
+    public AttestationPackageInfo(ASN1Encodable asn1Encodable) throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Sequence)) {
+            throw new CertificateParsingException(
+                    "Expected sequence for AttestationPackageInfo, found "
+                            + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+        try {
+            packageName = Asn1Utils.getStringFromAsn1OctetStreamAssumingUTF8(
+                    sequence.getObjectAt(PACKAGE_NAME_INDEX));
+        } catch (UnsupportedEncodingException e) {
+            throw new CertificateParsingException(
+                    "Converting octet stream to String triggered an UnsupportedEncodingException",
+                    e);
+        }
+        version = Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERSION_INDEX));
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder().append("Package name: ").append(getPackageName())
+                .append("\nVersion: " + getVersion()).toString();
+    }
+
+    @Override
+    public int compareTo(AttestationPackageInfo other) {
+        int res = packageName.compareTo(other.packageName);
+        if (res != 0) return res;
+        res = Integer.compare(version, other.version);
+        if (res != 0) return res;
+        return res;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof AttestationPackageInfo)
+                && (0 == compareTo((AttestationPackageInfo) o));
+    }
+}
\ No newline at end of file
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationTest.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationTest.java
new file mode 100644
index 0000000..287d065
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AttestationTest.java
@@ -0,0 +1,317 @@
+package com.google.attestationexample;
+
+import android.os.AsyncTask;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Base64;
+import android.util.Log;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.io.ByteArrayInputStream;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static android.security.keystore.KeyProperties.DIGEST_SHA256;
+import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC;
+import static com.google.attestationexample.RootOfTrust.KM_VERIFIED_BOOT_VERIFIED;
+
+/**
+ * AttestationTest generates an EC Key pair, with attestation, and displays the result in the
+ * TextView provided to its constructor.
+ */
+public class AttestationTest extends AsyncTask<Void, String, Void> {
+    private static final int ORIGINATION_TIME_OFFSET = 1000000;
+    private static final int CONSUMPTION_TIME_OFFSET = 2000000;
+
+    private static final int KEY_USAGE_BITSTRING_LENGTH = 9;
+    private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0;
+    private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2;
+    private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3;
+
+    private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1;
+    private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2;
+    private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3;
+    private static final Pattern OS_VERSION_STRING_PATTERN = Pattern
+            .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?");
+
+    private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1;
+    private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2;
+    private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern
+            .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
+
+    private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
+
+    private static final String FINISHED = "AttestationFinished";
+    private static final String FAIL = "AttestationFail";
+    private static final String INFO = "AttestationInfo";
+    private static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";
+    private static final String KEY_USAGE_OID = "2.5.29.15";  // Standard key usage extension.
+
+    private static final String GOOGLE_ROOT_CERTIFICATE =
+            "-----BEGIN CERTIFICATE-----\n"
+                    + "MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV"
+                    + "BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy"
+                    + "ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B"
+                    + "AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS"
+                    + "Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7"
+                    + "tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj"
+                    + "nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq"
+                    + "C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ"
+                    + "oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O"
+                    + "JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg"
+                    + "sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi"
+                    + "igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M"
+                    + "RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E"
+                    + "aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um"
+                    + "AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD"
+                    + "VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO"
+                    + "BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk"
+                    + "Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD"
+                    + "ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB"
+                    + "Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m"
+                    + "qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY"
+                    + "DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm"
+                    + "QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u"
+                    + "JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD"
+                    + "CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy"
+                    + "ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD"
+                    + "qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic"
+                    + "MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1"
+                    + "wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk\n"
+                    + "-----END CERTIFICATE-----";
+
+    @Override
+    protected Void doInBackground(Void... params) {
+        try {
+            testEcAttestation();
+        } catch (Exception e) {
+            Log.e(FAIL, "Something is wrong, check detailed logcat logs:\n", e);
+        }
+        return null;
+    }
+
+    private void testEcAttestation() throws Exception {
+        String ecCurve = "secp256r1";
+        int keySize = 256;
+        byte[] challenge = "challenge".getBytes();
+        String keystoreAlias = "test_key";
+
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+
+        keyStore.deleteEntry(keystoreAlias);
+
+        Log.d(INFO,"Generating key pair...");
+        Date startTime = new Date(new Date().getTime() - 1000);
+        Log.d("****", "Start Time is: " + startTime.toString());
+        Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET);
+        Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET);
+        KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias,
+                KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+                .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve))
+                .setDigests(DIGEST_SHA256)
+                .setAttestationChallenge(challenge);
+
+        builder.setKeyValidityStart(startTime)
+                .setKeyValidityForOriginationEnd(originationEnd)
+                .setKeyValidityForConsumptionEnd(consumptionEnd);
+
+        generateKeyPair(KEY_ALGORITHM_EC, builder.build());
+        Log.d(INFO, "Key pair generated\n\n");
+
+        Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
+        Log.d(INFO, "Retrieved certificate chain of length " + certificates.length + "\n");
+        try {
+            verifyCertificateSignatures(certificates);
+        } catch (GeneralSecurityException e) {
+            Log.e(FAIL, "Certificate chain does not verify.", e);
+        }
+
+        X509Certificate attestationCert = (X509Certificate) certificates[0];
+        X509Certificate secureRoot = (X509Certificate) CertificateFactory
+                .getInstance("X.509").generateCertificate(
+                        new ByteArrayInputStream(
+                                GOOGLE_ROOT_CERTIFICATE.getBytes()));
+        X509Certificate rootCert = (X509Certificate) certificates[certificates.length - 1];
+        if (!Arrays.equals(secureRoot.getPublicKey().getEncoded(),
+                rootCert.getPublicKey().getEncoded())) {
+            Log.e(FAIL, "root certificate public key does not match Google public key");
+        }
+        printKeyUsage(attestationCert);
+
+        ImmutableSet<String> unexpectedExtensionOids =
+                (ImmutableSet) retrieveUnexpectedExtensionOids(attestationCert);
+        if (!unexpectedExtensionOids.isEmpty()) {
+            Log.e(FAIL, "attestation certificate contains unexpected OIDs");
+            for (String oid : unexpectedExtensionOids.toArray(new String[unexpectedExtensionOids.size()])) {
+                Log.e(FAIL, "Unexpected OID: " + oid);
+            }
+        }
+
+        Attestation attestation = new Attestation(attestationCert);
+        if (!Arrays.equals(attestation.getAttestationChallenge(), challenge)) {
+            Utils.logError("challenge mismatch\nExpected:",
+                    challenge, attestation.getAttestationChallenge());
+        }
+
+        if (attestation.getAttestationSecurityLevel() != 1) {
+            Utils.logError("Attestation cert reporting non-TEE security level",
+                    1, attestation.getAttestationSecurityLevel());
+        }
+        if (attestation.getKeymasterSecurityLevel() != 1) {
+            Utils.logError("Keymaster reporting non-TEE security level",
+                    1, attestation.getKeymasterSecurityLevel());
+        }
+
+        checkRootOfTrust(attestation);
+
+        Signature signer = Signature.getInstance("SHA256WithECDSA");
+        KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
+        keystore.load(null);
+
+        PrivateKey key = (PrivateKey) keystore.getKey(keystoreAlias, null);
+        try {
+            signer.initSign(key);
+            signer.update("Hello".getBytes());
+            signer.sign();
+        } catch(Exception e) {
+            Log.e(FAIL,"Failed to sign with generated key", e);
+        }
+        Log.d(FINISHED, "Signing completed");
+    }
+
+    private void generateKeyPair(String algorithm, KeyGenParameterSpec spec)
+            throws NoSuchAlgorithmException, NoSuchProviderException,
+            InvalidAlgorithmParameterException {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm,
+                "AndroidKeyStore");
+        keyPairGenerator.initialize(spec);
+        keyPairGenerator.generateKeyPair();
+    }
+
+    private void verifyCertificateSignatures(Certificate[] certChain)
+            throws GeneralSecurityException {
+
+        for (Certificate cert : certChain) {
+            final byte[] derCert = cert.getEncoded();
+            final String pemCertPre = Base64.encodeToString(derCert, Base64.NO_WRAP);
+            Log.e("****", pemCertPre);
+        }
+
+        for (int i = 1; i < certChain.length; ++i) {
+            PublicKey pubKey = certChain[i].getPublicKey();
+            try {
+                certChain[i - 1].verify(pubKey);
+            } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException
+                    | NoSuchProviderException | SignatureException e) {
+                throw new GeneralSecurityException("Failed to verify certificate "
+                        + certChain[i - 1] + " with public key " + certChain[i].getPublicKey(), e);
+            }
+            if (i == certChain.length - 1) {
+                // Last cert is self-signed.
+                try {
+                    certChain[i].verify(pubKey);
+                } catch (CertificateException e) {
+                    throw new GeneralSecurityException(
+                            "Root cert " + certChain[i] + " is not correctly self-signed", e);
+                }
+            }
+        }
+    }
+
+    private void printKeyUsage(X509Certificate attestationCert) {
+        Log.d(INFO, "Key usage:");
+        if (attestationCert.getKeyUsage() == null) {
+            Log.d(INFO, " NONE\n");
+            return;
+        }
+        if (attestationCert.getKeyUsage()[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET]) {
+            Log.d(INFO, " sign");
+        }
+        if (attestationCert.getKeyUsage()[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET]) {
+            Log.d(INFO, " encrypt_data");
+        }
+        if (attestationCert.getKeyUsage()[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET]) {
+            Log.d(INFO, " encrypt_keys");
+        }
+        Log.d(INFO, "\n");
+    }
+
+    private Set<String> retrieveUnexpectedExtensionOids(X509Certificate x509Cert) {
+        return new ImmutableSet.Builder<String>()
+                .addAll(x509Cert.getCriticalExtensionOIDs()
+                        .stream()
+                        .filter(s -> !KEY_USAGE_OID.equals(s))
+                        .iterator())
+                .addAll(x509Cert.getNonCriticalExtensionOIDs()
+                        .stream()
+                        .filter(s -> !KEY_DESCRIPTION_OID.equals(s))
+                        .iterator())
+                .build();
+    }
+
+
+    private void checkRootOfTrust(Attestation attestation) {
+        RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
+        if (rootOfTrust == null) {
+            Log.e(FAIL, "Root of trust is null");
+            return;
+        }
+        if (rootOfTrust.getVerifiedBootKey() == null) {
+            Log.e(FAIL, "Verified boot key is null");
+            return;
+        }
+        if (rootOfTrust.getVerifiedBootKey().length < 32) {
+            Log.e(FAIL, "Verified boot key is less than 32 bytes");
+        }
+        if (isAllZeroes(rootOfTrust.getVerifiedBootKey())) {
+            Log.e(FAIL, "Verified boot key is all zeros.");
+        }
+        if (!rootOfTrust.isDeviceLocked()) {
+            Log.e(FAIL, "Device isn't locked");
+        }
+        if (KM_VERIFIED_BOOT_VERIFIED != rootOfTrust.getVerifiedBootState()) {
+            Utils.logError("Root of trust isn't reporting boot verified.",
+                    KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
+        }
+        if (rootOfTrust.getVerifiedBootHash() == null) {
+            Log.e(FAIL, "Verified boot hash is null");
+            return;
+        }
+        if (rootOfTrust.getVerifiedBootHash().length != 32) {
+            Log.e(FAIL, "Verified boot hash isn't 32 bytes");
+        }
+        if (isAllZeroes(rootOfTrust.getVerifiedBootHash())) {
+            Log.e(FAIL, "Verified boot hash is all zeros.");
+        }
+    }
+
+    private boolean isAllZeroes(byte[] checkArray) {
+        for (byte b : checkArray) {
+            if (b != 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/AuthorizationList.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AuthorizationList.java
new file mode 100644
index 0000000..29b317e
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/AuthorizationList.java
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.attestationexample;
+
+import android.security.keystore.KeyProperties;
+import android.util.Log;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1SequenceParser;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+
+import java.io.IOException;
+import java.security.cert.CertificateParsingException;
+import java.text.DateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.base.Functions.forMap;
+import static com.google.common.collect.Collections2.transform;
+
+public class AuthorizationList {
+    // Algorithm values.
+    public static final int KM_ALGORITHM_RSA = 1;
+    public static final int KM_ALGORITHM_EC = 3;
+
+    // EC Curves
+    public static final int KM_EC_CURVE_P224 = 0;
+    public static final int KM_EC_CURVE_P256 = 1;
+    public static final int KM_EC_CURVE_P384 = 2;
+    public static final int KM_EC_CURVE_P521 = 3;
+
+    // Padding modes.
+    public static final int KM_PAD_NONE = 1;
+    public static final int KM_PAD_RSA_OAEP = 2;
+    public static final int KM_PAD_RSA_PSS = 3;
+    public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
+    public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
+
+    // Digest modes.
+    public static final int KM_DIGEST_NONE = 0;
+    public static final int KM_DIGEST_MD5 = 1;
+    public static final int KM_DIGEST_SHA1 = 2;
+    public static final int KM_DIGEST_SHA_2_224 = 3;
+    public static final int KM_DIGEST_SHA_2_256 = 4;
+    public static final int KM_DIGEST_SHA_2_384 = 5;
+    public static final int KM_DIGEST_SHA_2_512 = 6;
+
+    // Key origins.
+    public static final int KM_ORIGIN_GENERATED = 0;
+    public static final int KM_ORIGIN_IMPORTED = 2;
+    public static final int KM_ORIGIN_UNKNOWN = 3;
+
+    // Operation Purposes.
+    public static final int KM_PURPOSE_ENCRYPT = 0;
+    public static final int KM_PURPOSE_DECRYPT = 1;
+    public static final int KM_PURPOSE_SIGN = 2;
+    public static final int KM_PURPOSE_VERIFY = 3;
+    public static final int KM_PURPOSE_DERIVE_KEY = 4;
+    public static final int KM_PURPOSE_WRAP_KEY = 5;
+
+    // User authenticators.
+    public static final int HW_AUTH_PASSWORD = 1 << 0;
+    public static final int HW_AUTH_FINGERPRINT = 1 << 1;
+
+    // Keymaster tag classes
+    private static final int KM_ENUM = 1 << 28;
+    private static final int KM_ENUM_REP = 2 << 28;
+    private static final int KM_UINT = 3 << 28;
+    private static final int KM_ULONG = 5 << 28;
+    private static final int KM_DATE = 6 << 28;
+    private static final int KM_BOOL = 7 << 28;
+    private static final int KM_BYTES = 9 << 28;
+
+    // Tag class removal mask
+    private static final int KEYMASTER_TAG_TYPE_MASK = 0x0FFFFFFF;
+
+    // Keymaster tags
+    private static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
+    private static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
+    private static final int KM_TAG_KEY_SIZE = KM_UINT | 3;
+    private static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
+    private static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
+    private static final int KM_TAG_EC_CURVE = KM_ENUM | 10;
+    private static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200;
+    private static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
+    private static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
+    private static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
+    private static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
+    private static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
+    private static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
+    private static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
+    private static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
+    private static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
+    private static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
+    private static final int KM_TAG_ORIGIN = KM_ENUM | 702;
+    private static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
+    private static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
+    private static final int KM_TAG_OS_VERSION = KM_UINT | 705;
+    private static final int KM_TAG_OS_PATCHLEVEL = KM_UINT | 706;
+    private static final int KM_TAG_ATTESTATION_APPLICATION_ID = KM_BYTES | 709;
+    private static final int KM_TAG_VENDOR_PATCHLEVEL = KM_UINT | 718;
+    private static final int KM_TAG_BOOT_PATCHLEVEL = KM_UINT | 719;
+
+    // Map for converting padding values to strings
+    private static final ImmutableMap<Integer, String> paddingMap = ImmutableMap
+            .<Integer, String> builder()
+            .put(KM_PAD_NONE, "NONE")
+            .put(KM_PAD_RSA_OAEP, "OAEP")
+            .put(KM_PAD_RSA_PSS, "PSS")
+            .put(KM_PAD_RSA_PKCS1_1_5_ENCRYPT, "PKCS1 ENCRYPT")
+            .put(KM_PAD_RSA_PKCS1_1_5_SIGN, "PKCS1 SIGN")
+            .build();
+
+    // Map for converting digest values to strings
+    private static final ImmutableMap<Integer, String> digestMap = ImmutableMap
+            .<Integer, String> builder()
+            .put(KM_DIGEST_NONE, "NONE")
+            .put(KM_DIGEST_MD5, "MD5")
+            .put(KM_DIGEST_SHA1, "SHA1")
+            .put(KM_DIGEST_SHA_2_224, "SHA224")
+            .put(KM_DIGEST_SHA_2_256, "SHA256")
+            .put(KM_DIGEST_SHA_2_384, "SHA384")
+            .put(KM_DIGEST_SHA_2_512, "SHA512")
+            .build();
+
+    // Map for converting purpose values to strings
+    private static final ImmutableMap<Integer, String> purposeMap = ImmutableMap
+            .<Integer, String> builder()
+            .put(KM_PURPOSE_DECRYPT, "DECRYPT")
+            .put(KM_PURPOSE_ENCRYPT, "ENCRYPT")
+            .put(KM_PURPOSE_SIGN, "SIGN")
+            .put(KM_PURPOSE_VERIFY, "VERIFY")
+            .build();
+
+    private Set<Integer> purposes;
+    private Integer algorithm;
+    private Integer keySize;
+    private Set<Integer> digests;
+    private Set<Integer> paddingModes;
+    private Integer ecCurve;
+    private Long rsaPublicExponent;
+    private Date activeDateTime;
+    private Date originationExpireDateTime;
+    private Date usageExpireDateTime;
+    private boolean noAuthRequired;
+    private Integer userAuthType;
+    private Integer authTimeout;
+    private boolean allowWhileOnBody;
+    private boolean allApplications;
+    private byte[] applicationId;
+    private Date creationDateTime;
+    private Integer origin;
+    private boolean rollbackResistant;
+    private RootOfTrust rootOfTrust;
+    private Integer osVersion;
+    private Integer osPatchLevel;
+    private Integer vendorPatchLevel;
+    private Integer bootPatchLevel;
+    private AttestationApplicationId attestationApplicationId;
+
+    public AuthorizationList(ASN1Encodable sequence) throws CertificateParsingException {
+        if (!(sequence instanceof ASN1Sequence)) {
+            throw new CertificateParsingException("Expected sequence for authorization list, found "
+                    + sequence.getClass().getName());
+        }
+
+        ASN1SequenceParser parser = ((ASN1Sequence) sequence).parser();
+        ASN1TaggedObject entry = parseAsn1TaggedObject(parser);
+        for (; entry != null; entry = parseAsn1TaggedObject(parser)) {
+            int tag = entry.getTagNo();
+            ASN1Primitive value = entry.getObject();
+            Log.i("Attestation", "Parsing tag: [" + tag + "], value: [" + value + "]");
+            switch (tag) {
+                default:
+                    throw new CertificateParsingException("Unknown tag " + tag + " found");
+
+                case KM_TAG_PURPOSE & KEYMASTER_TAG_TYPE_MASK:
+                    purposes = Asn1Utils.getIntegersFromAsn1Set(value);
+                    break;
+                case KM_TAG_ALGORITHM & KEYMASTER_TAG_TYPE_MASK:
+                    algorithm = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_KEY_SIZE & KEYMASTER_TAG_TYPE_MASK:
+                    keySize = Asn1Utils.getIntegerFromAsn1(value);
+                    Log.i("Attestation", "Found KEY SIZE, value: " + keySize);
+                    break;
+                case KM_TAG_DIGEST & KEYMASTER_TAG_TYPE_MASK:
+                    digests = Asn1Utils.getIntegersFromAsn1Set(value);
+                    break;
+                case KM_TAG_PADDING & KEYMASTER_TAG_TYPE_MASK:
+                    paddingModes = Asn1Utils.getIntegersFromAsn1Set(value);
+                    break;
+                case KM_TAG_RSA_PUBLIC_EXPONENT & KEYMASTER_TAG_TYPE_MASK:
+                    rsaPublicExponent = Asn1Utils.getLongFromAsn1(value);
+                    break;
+                case KM_TAG_NO_AUTH_REQUIRED & KEYMASTER_TAG_TYPE_MASK:
+                    noAuthRequired = true;
+                    break;
+                case KM_TAG_CREATION_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+                    creationDateTime = Asn1Utils.getDateFromAsn1(value);
+                    break;
+                case KM_TAG_ORIGIN & KEYMASTER_TAG_TYPE_MASK:
+                    origin = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_OS_VERSION & KEYMASTER_TAG_TYPE_MASK:
+                    osVersion = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_OS_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
+                    osPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_VENDOR_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
+                    vendorPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_BOOT_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
+                    bootPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_ACTIVE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+                    activeDateTime = Asn1Utils.getDateFromAsn1(value);
+                    break;
+                case KM_TAG_ORIGINATION_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+                    originationExpireDateTime = Asn1Utils.getDateFromAsn1(value);
+                    break;
+                case KM_TAG_USAGE_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
+                    usageExpireDateTime = Asn1Utils.getDateFromAsn1(value);
+                    break;
+                case KM_TAG_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK:
+                    applicationId = Asn1Utils.getByteArrayFromAsn1(value);
+                    break;
+                case KM_TAG_ROLLBACK_RESISTANT & KEYMASTER_TAG_TYPE_MASK:
+                    rollbackResistant = true;
+                    break;
+                case KM_TAG_AUTH_TIMEOUT & KEYMASTER_TAG_TYPE_MASK:
+                    authTimeout = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_ALLOW_WHILE_ON_BODY & KEYMASTER_TAG_TYPE_MASK:
+                    allowWhileOnBody = true;
+                    break;
+                case KM_TAG_EC_CURVE & KEYMASTER_TAG_TYPE_MASK:
+                    ecCurve = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_USER_AUTH_TYPE & KEYMASTER_TAG_TYPE_MASK:
+                    userAuthType = Asn1Utils.getIntegerFromAsn1(value);
+                    break;
+                case KM_TAG_ROOT_OF_TRUST & KEYMASTER_TAG_TYPE_MASK:
+                    try {
+                        rootOfTrust = new RootOfTrust(value);
+                    } catch (CertificateParsingException e) {
+                        Log.e("AttestationFail", "Root of trust parsing failure" + e);
+                        rootOfTrust = null;
+                    }
+                    break;
+                case KM_TAG_ATTESTATION_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK:
+                    attestationApplicationId = new AttestationApplicationId(Asn1Utils
+                            .getAsn1EncodableFromBytes(Asn1Utils.getByteArrayFromAsn1(value)));
+                    break;
+                case KM_TAG_ALL_APPLICATIONS & KEYMASTER_TAG_TYPE_MASK:
+                    allApplications = true;
+                    break;
+            }
+        }
+
+    }
+
+    public static String algorithmToString(int algorithm) {
+        switch (algorithm) {
+            case KM_ALGORITHM_RSA:
+                return "RSA";
+            case KM_ALGORITHM_EC:
+                return "ECDSA";
+            default:
+                return "Unknown";
+        }
+    }
+
+    public static String paddingModesToString(final Set<Integer> paddingModes) {
+        return joinStrings(transform(paddingModes, forMap(paddingMap, "Unknown")));
+    }
+
+    public static String paddingModeToString(int paddingMode) {
+        return forMap(paddingMap, "Unknown").apply(paddingMode);
+    }
+
+    public static String digestsToString(Set<Integer> digests) {
+        return joinStrings(transform(digests, forMap(digestMap, "Unknown")));
+    }
+
+    public static String digestToString(int digest) {
+        return forMap(digestMap, "Unknown").apply(digest);
+    }
+
+    public static String purposesToString(Set<Integer> purposes) {
+        return joinStrings(transform(purposes, forMap(purposeMap, "Unknown")));
+    }
+
+    public static String userAuthTypeToString(int userAuthType) {
+        List<String> types = Lists.newArrayList();
+        if ((userAuthType & HW_AUTH_FINGERPRINT) != 0)
+            types.add("Fingerprint");
+        if ((userAuthType & HW_AUTH_PASSWORD) != 0)
+            types.add("Password");
+        return joinStrings(types);
+    }
+
+    public static String originToString(int origin) {
+        switch (origin) {
+            case KM_ORIGIN_GENERATED:
+                return "Generated";
+            case KM_ORIGIN_IMPORTED:
+                return "Imported";
+            case KM_ORIGIN_UNKNOWN:
+                return "Unknown (KM0)";
+            default:
+                return "Unknown";
+        }
+    }
+
+    private static String joinStrings(Collection<String> collection) {
+        return new StringBuilder()
+                .append("[")
+                .append(Joiner.on(", ").join(collection))
+                .append("]")
+                .toString();
+    }
+
+    private static String formatDate(Date date) {
+        return DateFormat.getDateTimeInstance().format(date);
+    }
+
+    private static ASN1TaggedObject parseAsn1TaggedObject(ASN1SequenceParser parser)
+            throws CertificateParsingException {
+        ASN1Encodable asn1Encodable = parseAsn1Encodable(parser);
+        if (asn1Encodable == null || asn1Encodable instanceof ASN1TaggedObject) {
+            return (ASN1TaggedObject) asn1Encodable;
+        }
+        throw new CertificateParsingException(
+                "Expected tagged object, found " + asn1Encodable.getClass().getName());
+    }
+
+    private static ASN1Encodable parseAsn1Encodable(ASN1SequenceParser parser)
+            throws CertificateParsingException {
+        try {
+            return parser.readObject();
+        } catch (IOException e) {
+            throw new CertificateParsingException("Failed to parse ASN1 sequence", e);
+        }
+    }
+
+    public Set<Integer> getPurposes() {
+        return purposes;
+    }
+
+    public Integer getAlgorithm() {
+        return algorithm;
+    }
+
+    public Integer getKeySize() {
+        return keySize;
+    }
+
+    public Set<Integer> getDigests() {
+        return digests;
+    }
+
+    public Set<Integer> getPaddingModes() {
+        return paddingModes;
+    }
+
+    public Set<String> getPaddingModesAsStrings() throws CertificateParsingException {
+        if (paddingModes == null) {
+            return ImmutableSet.of();
+        }
+
+        ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+        for (int paddingMode : paddingModes) {
+            switch (paddingMode) {
+                case KM_PAD_NONE:
+                    builder.add(KeyProperties.ENCRYPTION_PADDING_NONE);
+                    break;
+                case KM_PAD_RSA_OAEP:
+                    builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
+                    break;
+                case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+                    builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+                    break;
+                case KM_PAD_RSA_PKCS1_1_5_SIGN:
+                    builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+                    break;
+                case KM_PAD_RSA_PSS:
+                    builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+                    break;
+                default:
+                    throw new CertificateParsingException("Invalid padding mode " + paddingMode);
+            }
+        }
+        return builder.build();
+    }
+
+    public Integer getEcCurve() {
+        return ecCurve;
+    }
+
+    public String ecCurveAsString() {
+        if (ecCurve == null)
+            return "NULL";
+
+        switch (ecCurve) {
+            case KM_EC_CURVE_P224:
+                return "secp224r1";
+            case KM_EC_CURVE_P256:
+                return "secp256r1";
+            case KM_EC_CURVE_P384:
+                return "secp384r1";
+            case KM_EC_CURVE_P521:
+                return "secp521r1";
+            default:
+                return "unknown";
+        }
+    }
+
+    public Long getRsaPublicExponent() {
+        return rsaPublicExponent;
+    }
+
+    public Date getActiveDateTime() {
+        return activeDateTime;
+    }
+
+    public Date getOriginationExpireDateTime() {
+        return originationExpireDateTime;
+    }
+
+    public Date getUsageExpireDateTime() {
+        return usageExpireDateTime;
+    }
+
+    public boolean isNoAuthRequired() {
+        return noAuthRequired;
+    }
+
+    public Integer getUserAuthType() {
+        return userAuthType;
+    }
+
+    public Integer getAuthTimeout() {
+        return authTimeout;
+    }
+
+    public boolean isAllowWhileOnBody() {
+        return allowWhileOnBody;
+    }
+
+    public boolean isAllApplications() {
+        return allApplications;
+    }
+
+    public byte[] getApplicationId() {
+        return applicationId;
+    }
+
+    public Date getCreationDateTime() {
+        return creationDateTime;
+    }
+
+    public Integer getOrigin() {
+        return origin;
+    }
+
+    public boolean isRollbackResistant() {
+        return rollbackResistant;
+    }
+
+    public RootOfTrust getRootOfTrust() {
+        return rootOfTrust;
+    }
+
+    public Integer getOsVersion() {
+        return osVersion;
+    }
+
+    public Integer getOsPatchLevel() {
+        return osPatchLevel;
+    }
+
+    public Integer getVendorPatchLevel() { return vendorPatchLevel; }
+
+    public Integer getBootPatchLevel() { return bootPatchLevel; }
+
+    public AttestationApplicationId getAttestationApplicationId() {
+        return attestationApplicationId;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+
+        if (algorithm != null) {
+            s.append("\nAlgorithm: ").append(algorithmToString(algorithm));
+        }
+
+        if (keySize != null) {
+            s.append("\nKeySize: ").append(keySize);
+        }
+
+        if (purposes != null && !purposes.isEmpty()) {
+            s.append("\nPurposes: ").append(purposesToString(purposes));
+        }
+
+        if (digests != null && !digests.isEmpty()) {
+            s.append("\nDigests: ").append(digestsToString(digests));
+        }
+
+        if (paddingModes != null && !paddingModes.isEmpty()) {
+            s.append("\nPadding modes: ").append(paddingModesToString(paddingModes));
+        }
+
+        if (ecCurve != null) {
+            s.append("\nEC Curve: ").append(ecCurveAsString());
+        }
+
+        String label = "\nRSA exponent: ";
+        if (rsaPublicExponent != null) {
+            s.append(label).append(rsaPublicExponent);
+        }
+
+        if (activeDateTime != null) {
+            s.append("\nActive: ").append(formatDate(activeDateTime));
+        }
+
+        if (originationExpireDateTime != null) {
+            s.append("\nOrigination expire: ").append(formatDate(originationExpireDateTime));
+        }
+
+        if (usageExpireDateTime != null) {
+            s.append("\nUsage expire: ").append(formatDate(usageExpireDateTime));
+        }
+
+        if (!noAuthRequired && userAuthType != null) {
+            s.append("\nAuth types: ").append(userAuthTypeToString(userAuthType));
+            if (authTimeout != null) {
+                s.append("\nAuth timeout: ").append(authTimeout);
+            }
+        }
+
+        if (applicationId != null) {
+            s.append("\nApplication ID: ").append(new String(applicationId));
+        }
+
+        if (creationDateTime != null) {
+            s.append("\nCreated: ").append(formatDate(creationDateTime));
+        }
+
+        if (origin != null) {
+            s.append("\nOrigin: ").append(originToString(origin));
+        }
+
+        if (rollbackResistant) {
+            s.append("\nRollback resistant: true");
+        }
+
+        if (rootOfTrust != null) {
+            s.append("\nRoot of Trust:\n");
+            s.append(rootOfTrust);
+        }
+
+        if (osVersion != null) {
+            s.append("\nOS Version: ").append(osVersion);
+        }
+
+        if (osPatchLevel != null) {
+            s.append("\nOS Patchlevel: ").append(osPatchLevel);
+        }
+
+        if (vendorPatchLevel != null) {
+            s.append("\nVendor Patchlevel: ").append(vendorPatchLevel);
+        }
+
+        if (bootPatchLevel != null) {
+            s.append("\nBoot Patchlevel: ").append(bootPatchLevel);
+        }
+
+        if (attestationApplicationId != null) {
+            s.append("\nApplication ID:").append(attestationApplicationId.toString());
+        }
+
+        return s.toString();
+    }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/RootOfTrust.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/RootOfTrust.java
new file mode 100644
index 0000000..7821a94
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/RootOfTrust.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.attestationexample;
+
+import com.google.common.io.BaseEncoding;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+
+public class RootOfTrust {
+    private static final int VERIFIED_BOOT_KEY_INDEX = 0;
+    private static final int DEVICE_LOCKED_INDEX = 1;
+    private static final int VERIFIED_BOOT_STATE_INDEX = 2;
+    private static final int VERIFIED_BOOT_HASH_INDEX = 3;
+
+    public static final int KM_VERIFIED_BOOT_VERIFIED = 0;
+    public static final int KM_VERIFIED_BOOT_SELF_SIGNED = 1;
+    public static final int KM_VERIFIED_BOOT_UNVERIFIED = 2;
+    public static final int KM_VERIFIED_BOOT_FAILED = 3;
+
+    private final byte[] verifiedBootKey;
+    private final byte[] verifiedBootHash;
+    private final boolean deviceLocked;
+    private final int verifiedBootState;
+
+    public RootOfTrust(ASN1Encodable asn1Encodable) throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Sequence)) {
+            throw new CertificateParsingException("Expected sequence for root of trust, found "
+                    + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+        if (sequence.size() != 4) {
+            throw new CertificateParsingException(
+                "Incorrect size, actual size is:" + sequence.size());
+        }
+        verifiedBootKey =
+                Asn1Utils.getByteArrayFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_KEY_INDEX));
+        deviceLocked = Asn1Utils.getBooleanFromAsn1(sequence.getObjectAt(DEVICE_LOCKED_INDEX));
+        verifiedBootState =
+                Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_STATE_INDEX));
+        verifiedBootHash =
+                Asn1Utils.getByteArrayFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_HASH_INDEX));
+    }
+
+    public static String verifiedBootStateToString(int verifiedBootState) {
+        switch (verifiedBootState) {
+            case KM_VERIFIED_BOOT_VERIFIED:
+                return "Verified";
+            case KM_VERIFIED_BOOT_SELF_SIGNED:
+                return "Self-signed";
+            case KM_VERIFIED_BOOT_UNVERIFIED:
+                return "Unverified";
+            case KM_VERIFIED_BOOT_FAILED:
+                return "Failed";
+            default:
+                return "Unknown";
+        }
+    }
+
+    public byte[] getVerifiedBootKey() {
+        return verifiedBootKey;
+    }
+
+    public boolean isDeviceLocked() {
+        return deviceLocked;
+    }
+
+    public int getVerifiedBootState() {
+        return verifiedBootState;
+    }
+
+    public byte[] getVerifiedBootHash() { return verifiedBootHash; }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("Verified boot Key: ")
+                .append(BaseEncoding.base64().encode(verifiedBootKey))
+                .append("\nDevice locked: ")
+                .append(deviceLocked)
+                .append("\nVerified boot state: ")
+                .append(verifiedBootStateToString(verifiedBootState))
+                .append("\nVerified boot hash: ")
+                .append(BaseEncoding.base64().encode(verifiedBootHash))
+                .toString();
+    }
+}
diff --git a/remote_provisioning/attestation_testing/java/com/google/attestationexample/Utils.java b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Utils.java
new file mode 100644
index 0000000..e13d8a8
--- /dev/null
+++ b/remote_provisioning/attestation_testing/java/com/google/attestationexample/Utils.java
@@ -0,0 +1,22 @@
+package com.google.attestationexample;
+
+import android.util.Log;
+
+import java.util.Arrays;
+
+public class Utils {
+    public static final String FAIL = "AttestationFail";
+    public static final String FAIL_INFO = "AttestationFailInfo";
+
+    public static void logError(String message, int expected, int actual) {
+        Log.e(FAIL, message);
+        Log.e(FAIL_INFO, "Expected: " + expected);
+        Log.e(FAIL_INFO, "Actual: " + actual);
+    }
+
+    public static void logError(String message, byte[] expected, byte[] actual) {
+        Log.e(FAIL, message);
+        Log.e(FAIL_INFO, "Expected: " + Arrays.toString(expected));
+        Log.e(FAIL_INFO, "Actual: " + Arrays.toString(actual));
+    }
+}
diff --git a/remote_provisioning/attestation_testing/res/layout/activity_attestation.xml b/remote_provisioning/attestation_testing/res/layout/activity_attestation.xml
new file mode 100644
index 0000000..4aaffed
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/layout/activity_attestation.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
+    tools:context="com.google.attestationexample.AttestationActivity">
+
+    <android.support.design.widget.AppBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:theme="@style/AppTheme.AppBarOverlay">
+
+        <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize"
+            android:background="?attr/colorPrimary"
+            app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+    </android.support.design.widget.AppBarLayout>
+
+    <include layout="@layout/content_attestation" />
+
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/fab"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|end"
+        android:layout_margin="@dimen/fab_margin"
+        app:srcCompat="@android:drawable/btn_star_big_on" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/remote_provisioning/attestation_testing/res/layout/content_attestation.xml b/remote_provisioning/attestation_testing/res/layout/content_attestation.xml
new file mode 100644
index 0000000..9759ef2
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/layout/content_attestation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/content_attestation"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context="com.google.attestationexample.AttestationActivity"
+    tools:showIn="@layout/activity_attestation">
+
+    <TextView
+        android:id="@+id/textview"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:maxLines="10000"
+        android:scrollbars="vertical"
+        android:text=""
+        android:scrollbarAlwaysDrawVerticalTrack="false"
+        android:scrollbarAlwaysDrawHorizontalTrack="false"
+        android:scrollHorizontally="false" />
+</RelativeLayout>
diff --git a/remote_provisioning/attestation_testing/res/menu/menu_attestation.xml b/remote_provisioning/attestation_testing/res/menu/menu_attestation.xml
new file mode 100644
index 0000000..9a34152
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/menu/menu_attestation.xml
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context="com.google.attestationexample.AttestationActivity">
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:title="@string/action_settings"
+        app:showAsAction="never" />
+</menu>
diff --git a/remote_provisioning/attestation_testing/res/mipmap-hdpi/ic_launcher.png b/remote_provisioning/attestation_testing/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/remote_provisioning/attestation_testing/res/values-v21/styles.xml b/remote_provisioning/attestation_testing/res/values-v21/styles.xml
new file mode 100644
index 0000000..dbbdd40
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values-v21/styles.xml
@@ -0,0 +1,9 @@
+<resources>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+    </style>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values-w820dp/dimens.xml b/remote_provisioning/attestation_testing/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+         (such as screen margins) for screens with more than 820dp of available width. This
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/colors.xml b/remote_provisioning/attestation_testing/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/dimens.xml b/remote_provisioning/attestation_testing/res/values/dimens.xml
new file mode 100644
index 0000000..812cb7b
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/strings.xml b/remote_provisioning/attestation_testing/res/values/strings.xml
new file mode 100644
index 0000000..e6cb24b
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+    <string name="app_name">AttestationExample</string>
+    <string name="action_settings">Settings</string>
+</resources>
diff --git a/remote_provisioning/attestation_testing/res/values/styles.xml b/remote_provisioning/attestation_testing/res/values/styles.xml
new file mode 100644
index 0000000..545b9c6
--- /dev/null
+++ b/remote_provisioning/attestation_testing/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/sanitizer-status/Android.bp b/sanitizer-status/Android.bp
index 86501df..74f863c 100644
--- a/sanitizer-status/Android.bp
+++ b/sanitizer-status/Android.bp
@@ -1,37 +1,31 @@
-cc_defaults {
-    name: "sanitizer-status_defaults",
+package {
+    default_applicable_licenses: ["tools_security_sanitizer-status_license"],
+}
 
-    c_std: "c11",
+// Added automatically by a large-scale-change
+// http://go/android-license-faq
+license {
+    name: "tools_security_sanitizer-status_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
+cc_binary {
+    name: "sanitizer-status",
+
+    srcs: ["sanitizer-status.cpp"],
     cflags: [
         "-Wall",
         "-Werror",
         "-O0",
     ],
-}
 
-sanitizer_status_library_shared {
-    name: "libsanitizer-status",
-    defaults: ["sanitizer-status_defaults"],
-
-    srcs: ["sanitizer-status.c"],
-}
-
-cc_binary {
-    name: "sanitizer-status",
-    defaults: ["sanitizer-status_defaults"],
-
-    srcs: ["main.c"],
-    shared_libs: ["libsanitizer-status"],
-}
-
-bootstrap_go_package {
-    name: "soong-sanitizer_status",
-    pkgPath: "android/soong/security/santizers_status",
-    deps: [
-        "blueprint",
-        "soong-android",
-        "soong-cc",
+    header_libs: [
+        "bionic_libc_platform_headers",
     ],
-    srcs: ["sanitizer-status.go"],
-    pluginFor: ["soong_build"],
 }
diff --git a/sanitizer-status/main.c b/sanitizer-status/main.c
deleted file mode 100644
index 2186ccd..0000000
--- a/sanitizer-status/main.c
+++ /dev/null
@@ -1,5 +0,0 @@
-int sanitizer_status(int argc, char** argv);
-
-int main(int argc, char** argv) {
-    return sanitizer_status(argc, argv);
-}
diff --git a/sanitizer-status/sanitizer-status.c b/sanitizer-status/sanitizer-status.cpp
similarity index 73%
rename from sanitizer-status/sanitizer-status.c
rename to sanitizer-status/sanitizer-status.cpp
index 14730f1..9e07e61 100644
--- a/sanitizer-status/sanitizer-status.c
+++ b/sanitizer-status/sanitizer-status.cpp
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <limits.h>
+#include <malloc.h>
 #include <paths.h>
 #include <pthread.h>
 #include <pwd.h>
@@ -27,14 +28,25 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
-// crashes if built with -fsanitize=address
-void test_crash_malloc() {
-  volatile char* heap = malloc(32);
+#include <bionic/mte.h>
+
+// crashes if built with -fsanitize={address,hwaddress}
+void test_crash_malloc_overflow() {
+  volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
   heap[32] = heap[32];
-  printf("(HW)ASAN: Heap Test Failed\n");
+  printf("Heap Overflow Test Failed\n");
+}
+
+// crashes if built with -fsanitize={address,hwaddresss}
+void test_crash_malloc_uaf() {
+  volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
+  free((void *)heap);
+  heap[0] = heap[0];
+  printf("Heap UAF Test Failed\n");
 }
 
 // crashes if built with -fsanitize=address
@@ -46,8 +58,8 @@
 }
 
 void test_crash_pthread_mutex_unlock() {
-  volatile char* heap = malloc(32);
-  pthread_mutex_unlock((void*)&heap[32]);
+  volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
+  pthread_mutex_unlock((pthread_mutex_t*)&heap[32]);
   printf("HWASAN: Libc Test Failed\n");
 }
 
@@ -65,7 +77,7 @@
 void test_msan_crash_stack() {
   volatile int stack[10];
   stack[5] = 0;
-  if (stack[0]) {
+  if (stack[0]) { // NOLINT
     stack[0] = 1;
   }
   printf("MSAN: Stack Test Failed\n");
@@ -110,7 +122,7 @@
 // crashes with GWP-ASan
 void test_crash_gwp_asan() {
   for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i ) {
-    volatile char *x = malloc(1);
+    volatile char* x = reinterpret_cast<volatile char *>(malloc(1));
     free((void*) x);
     *x = 0;
   }
@@ -157,7 +169,7 @@
   return 0;
 }
 
-int sanitizer_status(int argc, const char** argv) {
+int main(int argc, const char** argv) {
   int test_everything = 0;
   int failures = 0;
 
@@ -167,12 +179,13 @@
   if (test_everything || have_option("asan", argv, argc)) {
     int asan_failures = 0;
 
-#if !defined(ANDROID_SANITIZE_ADDRESS)
+#if !__has_feature(address_sanitizer)
     asan_failures += 1;
     printf("ASAN: Compiler flags failed!\n");
 #endif
 
-    asan_failures += test(test_crash_malloc);
+    asan_failures += test(test_crash_malloc_overflow);
+    asan_failures += test(test_crash_malloc_uaf);
     asan_failures += test(test_crash_stack);
     asan_failures += data_asan_exists();
 
@@ -185,12 +198,13 @@
   if (test_everything || have_option("hwasan", argv, argc)) {
     int hwasan_failures = 0;
 
-#if !defined(ANDROID_SANITIZE_HWADDRESS)
+#if !__has_feature(hwaddress_sanitizer)
     hwasan_failures += 1;
     printf("HWASAN: Compiler flags failed!\n");
 #endif
 
-    hwasan_failures += test(test_crash_malloc);
+    hwasan_failures += test(test_crash_malloc_overflow);
+    hwasan_failures += test(test_crash_malloc_uaf);
     hwasan_failures += test(test_crash_stack);
     hwasan_failures += test(test_crash_pthread_mutex_unlock);
 
@@ -200,20 +214,6 @@
     failures += hwasan_failures;
   }
 
-  if(test_everything || have_option("cov", argv, argc)) {
-    int cov_failures = 0;
-
-#ifndef ANDROID_SANITIZE_COVERAGE
-    printf("COV: Compiler flags failed!\n");
-    cov_failures += 1;
-#endif
-
-    if (!cov_failures)
-      printf("COV: OK\n");
-
-    failures += cov_failures;
-  }
-
   if (test_everything || have_option("msan", argv, argc)) {
     int msan_failures = 0;
 
@@ -269,5 +269,38 @@
     failures += gwp_asan_failures;
   }
 
+  if (test_everything || have_option("mte", argv, argc)) {
+    int mte_failures = 0;
+
+    if (!(mte_supported() && !__has_feature(address_sanitizer) &&
+          !__has_feature(hwaddress_sanitizer))) {
+      mte_failures += 1;
+      printf("MTE: Not supported\n");
+    }
+
+    mte_failures += test(test_crash_malloc_overflow);
+    mte_failures += test(test_crash_malloc_uaf);
+
+    int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+    if (tagged_addr_ctrl < 0) {
+      mte_failures += 1;
+      printf("MTE: PR_GET_TAGGED_ADDR_CTRL failed\n");
+    }
+
+    HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
+    if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level) == 0) {
+      mte_failures += 1;
+      printf("MTE: mallopt failed\n");
+    }
+
+    mte_failures += test(test_crash_malloc_overflow);
+    mte_failures += test(test_crash_malloc_uaf);
+
+    if (!mte_failures)
+      printf("MTE: OK\n");
+
+    failures += mte_failures;
+  }
+
   return failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/sanitizer-status/sanitizer-status.go b/sanitizer-status/sanitizer-status.go
deleted file mode 100644
index 2c75e9f..0000000
--- a/sanitizer-status/sanitizer-status.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package sanitizer_status
-
-import (
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-func init() {
-	android.RegisterModuleType("sanitizer_status_library_shared",
-		libraryFactory)
-}
-
-func libraryFactory() android.Module {
-	module := cc.LibrarySharedFactory()
-	android.AddLoadHook(module, loadHook)
-	return module
-}
-
-func loadHook(ctx android.LoadHookContext) {
-	type props struct {
-		Cflags []string
-	}
-
-	p := &props{}
-
-	sanitizers := ctx.Config().SanitizeDevice()
-
-	if android.InList("address", sanitizers) {
-		p.Cflags = append(p.Cflags, "-DANDROID_SANITIZE_ADDRESS=1")
-	}
-	if android.InList("hwaddress", sanitizers) {
-		p.Cflags = append(p.Cflags, "-DANDROID_SANITIZE_HWADDRESS=1")
-	}
-	if android.InList("coverage", sanitizers) {
-		p.Cflags = append(p.Cflags, "-DANDROID_SANITIZE_COVERAGE=1")
-	}
-
-	ctx.AppendProperties(p)
-}