use gcov to measure the code coverage and return the measured data back
to the host
Change-Id: Ia9393ccb8dd3f3321f545abb9d20a6d37de5765f
diff --git a/sysfuzzer/common/Android.mk b/sysfuzzer/common/Android.mk
index 4f1ddbc..2f5b005 100644
--- a/sysfuzzer/common/Android.mk
+++ b/sysfuzzer/common/Android.mk
@@ -39,6 +39,7 @@
system/extras \
external/protobuf/src \
frameworks/native/include \
+ test/vts/sysfuzzer/libcodecoverage \
system/core/include
LOCAL_SHARED_LIBRARIES := \
@@ -48,6 +49,7 @@
liblog \
libdl \
libandroid_runtime \
+ libvts_codecoverage \
LOCAL_PROTOC_OPTIMIZE_TYPE := full
diff --git a/sysfuzzer/common/component_loader/DllLoader.cpp b/sysfuzzer/common/component_loader/DllLoader.cpp
index a13745e..8dc3966 100644
--- a/sysfuzzer/common/component_loader/DllLoader.cpp
+++ b/sysfuzzer/common/component_loader/DllLoader.cpp
@@ -109,5 +109,50 @@
return func;
}
+bool DllLoader::SancovResetCoverage() {
+ const char* error;
+ void (*func)();
+
+ func = (void (*)()) dlsym(handle_, "__sanitizer_reset_coverage");
+ if ((error = dlerror()) != NULL) {
+ fputs(error, stderr);
+ cerr << __FUNCTION__ << ": Can't find __sanitizer_reset_coverage" << endl;
+ return false;
+ }
+ func();
+ return true;
+}
+
+
+bool DllLoader::GcovInit(writeout_fn wfn, flush_fn ffn) {
+ const char* error;
+ void (*func)(writeout_fn, flush_fn);
+
+ func = (void (*)(writeout_fn, flush_fn)) dlsym(handle_, "llvm_gcov_init");
+ if ((error = dlerror()) != NULL) {
+ fputs(error, stderr);
+ cerr << __FUNCTION__ << ": Can't find llvm_gcov_init" << endl;
+ return false;
+ }
+ func(wfn, ffn);
+ return true;
+}
+
+
+bool DllLoader::GcovFlush() {
+ const char* error;
+ void (*func)();
+
+ func = (void (*)()) dlsym(handle_, "__gcov_flush");
+ if ((error = dlerror()) != NULL) {
+ fputs(error, stderr);
+ cerr << __FUNCTION__ << ": Can't find __gcov_flush" << endl;
+ return false;
+ }
+ func();
+
+ return true;
+}
+
} // namespace vts
} // namespace android
diff --git a/sysfuzzer/common/component_loader/DllLoader.h b/sysfuzzer/common/component_loader/DllLoader.h
index 1db0624..334ce3e 100644
--- a/sysfuzzer/common/component_loader/DllLoader.h
+++ b/sysfuzzer/common/component_loader/DllLoader.h
@@ -28,6 +28,8 @@
// Pointer type for a function in a loaded component.
typedef FuzzerBase* (*loader_function)();
+typedef void (*writeout_fn)();
+typedef void (*flush_fn)();
// Component loader implementation for a DLL file.
@@ -48,6 +50,15 @@
// Returns NULL if not found.
loader_function GetLoaderFunction(const char* function_name);
+ // (for sancov) Reset coverage data.
+ bool SancovResetCoverage();
+
+ // (for gcov) initialize.
+ bool GcovInit(writeout_fn wfn, flush_fn ffn);
+
+ // (for gcov) flush to file(s).
+ bool GcovFlush();
+
private:
// pointer to a handle of the loaded DLL file.
void* handle_;
diff --git a/sysfuzzer/common/fuzz_tester/FuzzerBase.cpp b/sysfuzzer/common/fuzz_tester/FuzzerBase.cpp
index 5a7513f..f1b5915 100644
--- a/sysfuzzer/common/fuzz_tester/FuzzerBase.cpp
+++ b/sysfuzzer/common/fuzz_tester/FuzzerBase.cpp
@@ -16,27 +16,263 @@
#include "fuzz_tester/FuzzerBase.h"
-#include <string>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
#include <iostream>
+#include <string>
+#include <vector>
#include "test/vts/sysfuzzer/common/proto/InterfaceSpecificationMessage.pb.h"
#include "component_loader/DllLoader.h"
#include "utils/InterfaceSpecUtil.h"
+#include "gcda_parser.h"
+
using namespace std;
using namespace android;
+#define USE_GCOV 1
+
+#if SANCOV
+extern "C" {
+typedef unsigned long uptr;
+
+#define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov(uint32_t *guard) {
+ printf("sancov\n");
+ coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
+ guard);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__asan_memset(void *block, int c, uptr size) {
+ ASAN_MEMSET_IMPL(nullptr, block, c, size);
+ return block;
+}
+
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_register_globals() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_unregister_globals() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_handle_no_return() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_load1() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_load2() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_load4() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_load8() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_load16() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_store1() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_store2() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_store4() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_store8() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_report_store16() { }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_set_error_report_callback() { }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_1(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_2(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_3(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_4(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_5(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_6(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_7(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_8(uptr size, uptr real_stack) {
+ return(uptr) malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_9(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_stack_malloc_10(uptr size, uptr real_stack) {
+ return (uptr)malloc(size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_1(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_2(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_3(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_4(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_5(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_6(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_7(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_8(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_9(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_stack_free_10(uptr ptr, uptr size, uptr real_stack) {
+ free((void*)ptr);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_version_mismatch_check_v6() {
+ // Do nothing.
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void
+__sanitizer_cov_module_init(int32_t *guards, uptr npcs, uint8_t *counters,
+ const char *comp_unit_name) {
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_init() {
+ static int inited = 0;
+ if (inited) return;
+ inited = 1;
+#if __WORDSIZE == 64
+ unsigned long start = 0x100000000000;
+ unsigned long size = 0x100000000000;
+#else
+ unsigned long start = 0x20000000;
+ unsigned long size = 0x20000000;
+#endif
+ void *res = mmap((void*)start, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
+ 0, 0);
+ if (res == (void*)start) {
+ fprintf(stderr, "Fake AddressSanitizer run-time initialized ok at %p\n",
+ res);
+ } else {
+ fprintf(stderr, "Fake AddressSanitizer run-time failed to initialize.\n"
+ "You have been warned. Aborting.");
+ abort();
+ }
+}
+
+}
+#endif
+
namespace android {
namespace vts {
+static void RemoveDir(char *path) {
+ struct dirent* entry = NULL;
+ DIR* dir = opendir(path);
+
+ while ((entry = readdir(dir)) != NULL) {
+ DIR* sub_dir = NULL;
+ FILE* file = NULL;
+ char abs_path[4096] = {0};
+
+ if (*(entry->d_name) != '.') {
+ sprintf(abs_path, "%s/%s", path, entry->d_name);
+ if ((sub_dir = opendir(abs_path)) != NULL) {
+ closedir(sub_dir);
+ RemoveDir(abs_path);
+ } else if((file = fopen(abs_path, "r")) != NULL) {
+ fclose(file);
+ remove(abs_path);
+ }
+ }
+ }
+ remove(path);
+}
+
+
FuzzerBase::FuzzerBase(int target_class)
- : target_class_(target_class) {}
+ : target_class_(target_class),
+ component_filename_(NULL),
+ gcov_output_basepath_(NULL) {}
-FuzzerBase::~FuzzerBase() {}
+FuzzerBase::~FuzzerBase() {
+ free(component_filename_);
+}
+void wfn() {
+ cout << "wfn" << endl;
+}
+
+void ffn() {
+ cout << "ffn" << endl;
+}
+
bool FuzzerBase::LoadTargetComponent(
const char* target_dll_path, const char* module_name) {
cout << __FUNCTION__ << ":" << __LINE__ << " " << "LoadTargetCompooent entry" << endl;
@@ -47,6 +283,28 @@
cout << __FUNCTION__ << ": loaded a non-legacy HAL file." << endl;
device_ = target_loader_.GetHWDevice(module_name);
cout << __FUNCTION__ << ": device_ " << device_ << endl;
+#if SANCOV
+ cout << __FUNCTION__ << "sancov reset " << target_loader_.SancovResetCoverage() << endl;;
+#endif
+
+ if (target_dll_path_) {
+ string target_path(target_dll_path_);
+
+ size_t offset = target_path.rfind("/", target_path.length());
+ if (offset != string::npos) {
+ string filename = target_path.substr(offset + 1,
+ target_path.length() - offset);
+ filename = filename.substr(0, filename.length() - 3 /* for .so */);
+ component_filename_ = (char*) malloc(filename.length() + 1);
+ strcpy(component_filename_, filename.c_str());
+ cout << "module file name: " << component_filename_ << endl;
+ }
+ cout << "module_name " << target_dll_path_ << endl;
+ }
+
+#if USE_GCOV
+ cout << __FUNCTION__ << ": gcov init " << target_loader_.GcovInit(wfn, ffn) << endl;
+#endif
return (device_ != NULL);
}
@@ -66,5 +324,156 @@
return true;
}
+
+void FuzzerBase::FunctionCallBegin() {
+ char product_path[4096];
+ char product[128];
+ char module_basepath[4096];
+ char cwd[4096];
+
+ if (getcwd(cwd, 4096)) {
+ cout << cwd << endl;
+ int n = snprintf(product_path, 4096, "%s/out/target/product", cwd);
+ if (n <= 0 || n >= 4096) {
+ cerr << "couln't get product_path" << endl;
+ return;
+ }
+ DIR* srcdir = opendir(product_path);
+ if (!srcdir) {
+ cerr << "couln't open " << product_path << endl;
+ return;
+ }
+
+ int dir_count = 0;
+ struct dirent* dent;
+ while ((dent = readdir(srcdir)) != NULL) {
+ struct stat st;
+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
+ continue;
+ }
+ if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
+ cerr << "error " << dent->d_name << endl;
+ continue;
+ }
+ if (S_ISDIR(st.st_mode)) {
+ cout << dent->d_name << endl;
+ strcpy(product, dent->d_name);
+ dir_count++;
+ }
+ }
+ closedir(srcdir);
+ if (dir_count != 1) {
+ cerr << "more than one product dir found." << endl;
+ return;
+ }
+
+ n = snprintf(module_basepath, 4096, "%s/%s/obj/SHARED_LIBRARIES",
+ product_path, product);
+ if (n <= 0 || n >= 4096) {
+ cerr << "couln't get module_basepath" << endl;
+ return;
+ }
+ srcdir = opendir(module_basepath);
+ if (!srcdir) {
+ cerr << "couln't open " << module_basepath << endl;
+ return;
+ }
+
+ dir_count = 0;
+ string target = string(component_filename_) + "_intermediates";
+ bool hit = false;
+ while ((dent = readdir(srcdir)) != NULL) {
+ struct stat st;
+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
+ continue;
+ }
+ if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
+ cerr << "error " << dent->d_name << endl;
+ continue;
+ }
+ if (S_ISDIR(st.st_mode)) {
+ cout << "module_basepath " << string(dent->d_name) << endl;
+ if (string(dent->d_name) == target) {
+ cout << "hit" << endl;
+ hit = true;
+ }
+ dir_count++;
+ }
+ }
+ if (hit) {
+ if (gcov_output_basepath_) {
+ free(gcov_output_basepath_);
+ }
+ gcov_output_basepath_ = (char*) malloc(strlen(module_basepath) + target.length() + 2);
+ if (!gcov_output_basepath_) {
+ cerr << __FUNCTION__ << ": couldn't alloc memory" << endl;
+ return;
+ }
+ sprintf(gcov_output_basepath_, "%s/%s", module_basepath, target.c_str());
+ RemoveDir(gcov_output_basepath_);
+ }
+ closedir(srcdir);
+ } else {
+ cerr << __FUNCTION__ << ": couldn't get the pwd." << endl;
+ }
+}
+
+
+vector<unsigned>* FuzzerBase::FunctionCallEnd() {
+ cout << __FUNCTION__ << ": gcov flush " << endl;
+ std::vector<unsigned>* result = NULL;
+#if USE_GCOV
+ target_loader_.GcovFlush();
+ // find the file.
+ if (!gcov_output_basepath_) {
+ cerr << __FUNCTION__ << ": no gcov basepath set" << endl;
+ return NULL;
+ }
+ DIR* srcdir = opendir(gcov_output_basepath_);
+ if (!srcdir) {
+ cerr << "couln't open " << gcov_output_basepath_ << endl;
+ return NULL;
+ }
+
+ int dir_count = 0;
+ struct dirent* dent;
+ while ((dent = readdir(srcdir)) != NULL) {
+ struct stat st;
+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
+ continue;
+ }
+ if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
+ cerr << "error " << dent->d_name << endl;
+ continue;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ cout << dent->d_name << endl;
+ if (string(dent->d_name).rfind(".gcda") != string::npos) {
+ char* buffer;
+ buffer = (char*) malloc(strlen(gcov_output_basepath_) + strlen(dent->d_name) + 2);
+ if (!buffer) {
+ cerr << __FUNCTION__ << ": OOM" << endl;
+ closedir(srcdir);
+ return NULL;
+ }
+ sprintf(buffer, "%s/%s", gcov_output_basepath_, dent->d_name);
+ result = android::vts::parse_gcda_file(buffer);
+#if USE_GCOV_DEBUG
+ if (result) {
+ for (unsigned int index = 0; index < result->size(); index++) {
+ cout << result->at(index) << endl;
+ }
+ }
+#endif
+ free(buffer);
+ break;
+ }
+ }
+ }
+ closedir(srcdir);
+#endif
+ return result;
+}
+
} // namespace vts
} // namespace android
diff --git a/sysfuzzer/common/fuzz_tester/FuzzerBase.h b/sysfuzzer/common/fuzz_tester/FuzzerBase.h
index 77a33b1..6e1c8a2 100644
--- a/sysfuzzer/common/fuzz_tester/FuzzerBase.h
+++ b/sysfuzzer/common/fuzz_tester/FuzzerBase.h
@@ -49,6 +49,13 @@
return false;
};
+ // Called before calling a target function.
+ void FunctionCallBegin();
+
+ // Called after calling a target function. Returns a vector which contains
+ // the code coverage info.
+ vector<unsigned>* FunctionCallEnd();
+
protected:
// a pointer to a HAL data structure of the loaded component.
struct hw_device_t* device_;
@@ -65,6 +72,12 @@
// target class
const int target_class_;
+
+ // target component file name (without extension)
+ char* component_filename_;
+
+ // path to store the gcov output files.
+ char* gcov_output_basepath_;
};
} // namespace vts
diff --git a/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto b/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto
index dbe4a26..56417ab 100644
--- a/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto
+++ b/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto
@@ -78,6 +78,12 @@
// a specification of the call flows of the function.
repeated CallFlowSpecificationMessage callflow = 31;
+
+ // profiling data.
+ repeated float profiling_data = 101;
+
+ // coverage measurement data.
+ repeated uint32 coverage_data = 201;
}
diff --git a/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp b/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
index b216115..72ef0c9 100644
--- a/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
+++ b/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
@@ -167,7 +167,8 @@
const string empty_string = string();
-const string& SpecificationBuilder::CallFunction(FunctionSpecificationMessage* func_msg) {
+const string& SpecificationBuilder::CallFunction(
+ FunctionSpecificationMessage* func_msg) {
if (!wrapper_.LoadInterfaceSpecificationLibrary(spec_lib_file_path_)) {
return empty_string;
}
@@ -182,8 +183,19 @@
}
void* result;
+ func_fuzzer->FunctionCallBegin();
cout << "Call Function " << func_msg->name() << endl;
func_fuzzer->Fuzz(*func_msg, &result);
+ cout << __FUNCTION__ << ": called" << endl;
+
+ // set coverage data.
+ vector<unsigned>* coverage = func_fuzzer->FunctionCallEnd();
+ if (coverage && coverage->size() > 0) {
+ for (unsigned int index = 0; index < coverage->size(); index++) {
+ func_msg->mutable_coverage_data()->Add(coverage->at(index));
+ }
+ }
+
if (func_msg->return_type().aggregate_type().size() > 0) {
// TODO: actually handle this case.
if (result != NULL) {
@@ -193,7 +205,10 @@
} else {
cout << __FUNCTION__ << " return value = NULL" << endl;
}
- return *(new string("todo: support aggregate"));
+ cerr << __FUNCTION__ << " todo: support aggregate" << endl;
+ string* output = new string();
+ google::protobuf::TextFormat::PrintToString(*func_msg, output);
+ return *output;
} else if (func_msg->return_type().primitive_type().size() > 0) {
// TODO handle when the size > 1.
if (!strcmp(func_msg->return_type().primitive_type(0).c_str(), "int32_t")) {
@@ -202,8 +217,7 @@
cout << "result " << endl;
// todo handle more types;
string* output = new string();
- google::protobuf::TextFormat::PrintToString(func_msg->return_type(),
- output);
+ google::protobuf::TextFormat::PrintToString(*func_msg, output);
return *output;
}
}
diff --git a/sysfuzzer/framework/VtsFuzzerMain.cpp b/sysfuzzer/framework/VtsFuzzerMain.cpp
index 7bda41b..9eb1cf2 100644
--- a/sysfuzzer/framework/VtsFuzzerMain.cpp
+++ b/sysfuzzer/framework/VtsFuzzerMain.cpp
@@ -19,6 +19,10 @@
* $ fuzzer --class=hal --type=light --version=1.0 /system/lib64/hw/lights.angler.so
* $ fuzzer --class=hal --type=gps --version=1.0 /system/lib64/hw/gps.msm8994.so
*
+ * $ LD_LIBRARY_PATH=/data/local/tmp ./fuzzer --class=hal --type=light \
+ * --version=1.0 --spec_dir=/data/local/tmp/spec \
+ * /data/local/tmp/hw64/lights.bullhead-vts.so
+ *
* Example usage (for GCE virtual devices):
* $ fuzzer --class=hal --type=light --version=1.0 /system/lib/hw/lights.gce_x86.so
* $ fuzzer --class=hal --type=gps --version=1.0 /system/lib/hw/gps.gce_x86.so
diff --git a/sysfuzzer/libcodecoverage/Android.mk b/sysfuzzer/libcodecoverage/Android.mk
new file mode 100644
index 0000000..85b3726
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/Android.mk
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libvts_codecoverage
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ gcda_parser.cpp \
+ gcov_basic_io.cpp \
+
+LOCAL_C_INCLUDES := \
+ bionic \
+ libcore \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/sysfuzzer/libcodecoverage/gcda_parser.cpp b/sysfuzzer/libcodecoverage/gcda_parser.cpp
new file mode 100644
index 0000000..b0b27a5
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/gcda_parser.cpp
@@ -0,0 +1,160 @@
+#include "gcda_parser.h"
+
+#include <vector>
+#include <iostream>
+
+#include "gcov_basic_io.h"
+
+using namespace std;
+
+namespace android {
+namespace vts {
+
+static const tag_format_t tag_table[] = {
+ {0, "NOP", NULL},
+ {0, "UNKNOWN", NULL},
+ {0, "COUNTERS", tag_counters},
+ {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
+ {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
+ {GCOV_TAG_ARCS, "ARCS", tag_arcs},
+ {GCOV_TAG_LINES, "LINES", tag_lines},
+ {0, NULL, NULL}
+};
+
+
+void tag_counters(const char* filename, unsigned tag, unsigned length,
+ vector<unsigned>* result) {
+ unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
+ printf("%s: %d counts\n", __FUNCTION__, n_counts);
+}
+
+
+void tag_function(const char* filename, unsigned tag, unsigned length,
+ vector<unsigned>* result) {
+ unsigned long pos = gcov_position();
+
+ if (length) {
+ gcov_read_unsigned(); // ident %u
+ unsigned lineno_checksum = gcov_read_unsigned();
+ result->push_back(lineno_checksum);
+ gcov_read_unsigned(); // cfg_checksum 0x%08x
+ }
+}
+
+
+void tag_blocks(const char* filename, unsigned tag, unsigned length,
+ vector<unsigned>* result) {
+ unsigned n_blocks = GCOV_TAG_BLOCKS_NUM(length);
+ printf("%s: %u blocks\n", __FUNCTION__, n_blocks);
+}
+
+
+void tag_arcs(const char* filename, unsigned tag, unsigned length,
+ vector<unsigned>* result) {
+ unsigned n_arcs = GCOV_TAG_ARCS_NUM(length);
+ printf("%s: %u arcs\n", __FUNCTION__, n_arcs);
+}
+
+
+void tag_lines(const char* filename, unsigned tag, unsigned length,
+ vector<unsigned>* result) {
+ printf("%s\n", __FUNCTION__);
+}
+
+
+vector<unsigned>* parse_gcda_file(const char* filename) {
+ unsigned tags[4];
+ unsigned depth = 0;
+ vector<unsigned>* result;
+
+ result = new vector<unsigned>();
+ if (!gcov_open(filename, 1)) {
+ fprintf(stderr, "%s:cannot open\n", filename);
+ return result;
+ }
+
+ /* magic */
+ {
+ unsigned magic = gcov_read_unsigned ();
+ unsigned version;
+ const char* type = NULL;
+ int endianness = 0;
+ char m[4], v[4];
+
+ if ((endianness = gcov_magic (magic, GCOV_DATA_MAGIC))) {
+ type = "data";
+ } else {
+ printf ("%s:not a gcov file\n", filename);
+ gcov_close();
+ return result;
+ }
+ version = gcov_read_unsigned();
+ GCOV_UNSIGNED2STRING(v, version);
+ GCOV_UNSIGNED2STRING(m, magic);
+ if (version != GCOV_VERSION) {
+ char e[4];
+ GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
+ }
+ }
+
+ gcov_read_unsigned(); // stamp
+ int cnt = 0;
+ bool found;
+ while (1) {
+ unsigned base, position = gcov_position();
+ unsigned tag, length;
+ tag_format_t const* format;
+ unsigned tag_depth;
+ int error;
+ unsigned mask;
+
+ tag = gcov_read_unsigned();
+ if (!tag)
+ break;
+
+ length = gcov_read_unsigned();
+ base = gcov_position();
+ mask = GCOV_TAG_MASK(tag) >> 1;
+ for (tag_depth = 4; mask; mask >>= 8) {
+ if ((mask & 0xff) != 0xff) {
+ printf ("%s:tag `%08x' is invalid\n", filename, tag);
+ break;
+ }
+ tag_depth--;
+ }
+ found = false;
+ for (format = tag_table; format->name; format++) {
+ if (format->tag == tag) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
+
+ if (tag) {
+ if (depth && depth < tag_depth) {
+ if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
+ printf ("%s:tag `%08x' is incorrectly nested\n",
+ filename, tag);
+ }
+ depth = tag_depth;
+ tags[depth - 1] = tag;
+ }
+ if (format->proc) {
+ (*format->proc) (filename, tag, length, result);
+ }
+ gcov_sync (base, length);
+ if ((error = gcov_is_error ())) {
+ printf(error < 0 ? "%s:counter overflow at %lu\n" :
+ "%s:read error at %lu\n", filename,
+ (long unsigned) gcov_position());
+ break;
+ }
+ }
+ gcov_close();
+ return result;
+}
+
+} // namespace vts
+} // namespace android
+
diff --git a/sysfuzzer/libcodecoverage/gcda_parser.h b/sysfuzzer/libcodecoverage/gcda_parser.h
new file mode 100644
index 0000000..599e03c
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/gcda_parser.h
@@ -0,0 +1,28 @@
+#ifndef __VTS_SYSFUZZER_LIBMEASUREMENT_GCDA_PARSER_H__
+#define __VTS_SYSFUZZER_LIBMEASUREMENT_GCDA_PARSER_H__
+
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace vts {
+
+typedef struct tag_format {
+ unsigned tag;
+ char const* name;
+ void (*proc)(const char*, unsigned, unsigned, vector<unsigned>*);
+} tag_format_t;
+
+void tag_counters(const char* filename, unsigned tag, unsigned length, vector<unsigned>* result);
+void tag_function(const char* filename, unsigned tag, unsigned length, vector<unsigned>* result);
+void tag_blocks(const char* filename, unsigned tag, unsigned length, vector<unsigned>* result);
+void tag_arcs(const char* filename, unsigned tag, unsigned length, vector<unsigned>* result);
+void tag_lines(const char* filename, unsigned tag, unsigned length, vector<unsigned>* result);
+
+vector<unsigned>* parse_gcda_file(const char* filename);
+
+} // namespace vts
+} // namespace android
+
+#endif
diff --git a/sysfuzzer/libcodecoverage/gcda_parser_test.cpp b/sysfuzzer/libcodecoverage/gcda_parser_test.cpp
new file mode 100644
index 0000000..36a191c
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/gcda_parser_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+#include "gcda_parser.h"
+#include "gcda_basic_io.h"
+
+#include <vector>
+#include <iostream>
+
+/*
+ * To test locally:
+ * $ rm a.out; gcc gcda_parser.cpp gcov_basic_io.cpp -lstdc++; ./a.out
+ */
+
+using namespace std;
+
+int main() {
+ std::vector<unsigned>* result = android::vts::parse_gcda_file("testdata/lights.gcda");
+ if (result) {
+ for (unsigned int index = 0; index < result->size(); index++) {
+ cout << result->at(index) << endl;
+ }
+ delete result;
+ }
+ return 0;
+}
diff --git a/sysfuzzer/libcodecoverage/gcov_basic_io.cpp b/sysfuzzer/libcodecoverage/gcov_basic_io.cpp
new file mode 100644
index 0000000..0dc8c7b
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/gcov_basic_io.cpp
@@ -0,0 +1,202 @@
+#include "gcov_basic_io.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+namespace android {
+namespace vts {
+
+struct gcov_var_t gcov_var;
+
+
+unsigned gcov_position (void) {
+ return gcov_var.start + gcov_var.offset;
+}
+
+
+int gcov_is_error() {
+ return gcov_var.file ? gcov_var.error : 1;
+}
+
+
+static inline unsigned from_file(unsigned value) {
+ if (gcov_var.endian) {
+ value = (value >> 16) | (value << 16);
+ value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff);
+ }
+ return value;
+}
+
+
+unsigned gcov_read_string_array(
+ char **string_array, unsigned num_strings) {
+ unsigned i, j, len = 0;
+
+ for (j = 0; j < num_strings; j++) {
+ unsigned string_len = gcov_read_unsigned ();
+ string_array[j] =
+ (char *) malloc (string_len * sizeof (unsigned)); // xmalloc
+ for (i = 0; i < string_len; i++)
+ ((unsigned *) string_array[j])[i] = gcov_read_unsigned ();
+ len += (string_len + 1);
+ }
+ return len;
+}
+
+
+unsigned gcov_read_unsigned() {
+ unsigned value;
+ const unsigned* buffer = gcov_read_words(1);
+
+ if (!buffer) return 0;
+ value = from_file(buffer[0]);
+ return value;
+}
+
+
+void gcov_allocate(unsigned length) {
+ size_t new_size = gcov_var.alloc;
+
+ if (!new_size) new_size = GCOV_BLOCK_SIZE;
+ new_size += length;
+ new_size *= 2;
+ gcov_var.alloc = new_size;
+ gcov_var.buffer = (unsigned*) realloc(gcov_var.buffer, new_size << 2);
+}
+
+
+const unsigned* gcov_read_words(unsigned words) {
+ const unsigned* result;
+ unsigned excess = gcov_var.length - gcov_var.offset;
+
+ assert(gcov_var.mode > 0);
+ if (excess < words) {
+ gcov_var.start += gcov_var.offset;
+ memmove(gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4);
+ gcov_var.offset = 0;
+ gcov_var.length = excess;
+ if (gcov_var.length + words > gcov_var.alloc) {
+ gcov_allocate (gcov_var.length + words);
+ }
+ excess = gcov_var.alloc - gcov_var.length;
+ excess = fread(gcov_var.buffer + gcov_var.length, 1, excess << 2,
+ gcov_var.file) >> 2;
+ gcov_var.length += excess;
+ if (gcov_var.length < words) {
+ gcov_var.overread += words - gcov_var.length;
+ gcov_var.length = 0;
+ return 0;
+ }
+ }
+ result = &gcov_var.buffer[gcov_var.offset];
+ gcov_var.offset += words;
+ return result;
+}
+
+
+int gcov_magic(unsigned magic, unsigned expected) {
+ if (magic == expected) return 1;
+ magic = (magic >> 16) | (magic << 16);
+ magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
+ if (magic == expected) {
+ gcov_var.endian = 1;
+ return -1;
+ }
+ return 0;
+}
+
+
+gcov_type gcov_read_counter() {
+ gcov_type value;
+ const unsigned* buffer = gcov_read_words (2);
+ if (!buffer) return 0;
+ value = from_file (buffer[0]);
+ if (sizeof (value) > sizeof (unsigned)) {
+ value |= ((gcov_type) from_file (buffer[1])) << 32;
+ } else if (buffer[1]) {
+ gcov_var.error = -1;
+ }
+ return value;
+}
+
+
+void gcov_write_block(unsigned size) {
+ if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1) {
+ gcov_var.error = 1;
+ }
+ gcov_var.start += size;
+ gcov_var.offset -= size;
+}
+
+
+const char* gcov_read_string() {
+ unsigned length = gcov_read_unsigned();
+ if (!length) return 0;
+ return (const char*) gcov_read_words(length);
+}
+
+
+bool gcov_open(const char* name, int mode) {
+ assert(!gcov_var.file);
+
+ gcov_var.start = 0;
+ gcov_var.offset = 0;
+ gcov_var.length = 0;
+ gcov_var.overread = -1u;
+ gcov_var.error = 0;
+ gcov_var.endian = 0;
+
+ if (mode >= 0) {
+ gcov_var.file = fopen(name, (mode > 0) ? "rb" : "r+b");
+ }
+
+ if (gcov_var.file) {
+ gcov_var.mode = 1;
+ } else if (mode <= 0) {
+ gcov_var.file = fopen(name, "w+b");
+ if (gcov_var.file) {
+ gcov_var.mode = mode * 2 + 1;
+ }
+ }
+ if (!gcov_var.file) return false;
+
+ setbuf(gcov_var.file, (char*)0);
+ return true;
+}
+
+
+void gcov_sync(unsigned base, unsigned length) {
+ assert(gcov_var.mode > 0);
+ base += length;
+ if (base - gcov_var.start <= gcov_var.length) {
+ gcov_var.offset = base - gcov_var.start;
+ } else {
+ gcov_var.offset = gcov_var.length = 0;
+ fseek(gcov_var.file, base << 2, SEEK_SET);
+ gcov_var.start = ftell(gcov_var.file) >> 2;
+ }
+}
+
+
+int gcov_close() {
+ if (gcov_var.file) {
+ if (gcov_var.offset && gcov_var.mode < 0) {
+ gcov_write_block(gcov_var.offset);
+ }
+ fclose(gcov_var.file);
+ gcov_var.file = 0;
+ gcov_var.length = 0;
+ }
+ free(gcov_var.buffer);
+ gcov_var.alloc = 0;
+ gcov_var.buffer = 0;
+ gcov_var.mode = 0;
+ return gcov_var.error;
+}
+
+} // namespace vts
+} // namespace android
diff --git a/sysfuzzer/libcodecoverage/gcov_basic_io.h b/sysfuzzer/libcodecoverage/gcov_basic_io.h
new file mode 100644
index 0000000..551d67e
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/gcov_basic_io.h
@@ -0,0 +1,164 @@
+#ifndef __VTS_SYSFUZZER_LIBMEASUREMENT_GCOV_BASIC_IO_H__
+#define __VTS_SYSFUZZER_LIBMEASUREMENT_GCOV_BASIC_IO_H__
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+namespace android {
+namespace vts {
+
+struct block_info;
+struct source_info;
+
+#define GCOV_DATA_MAGIC ((unsigned)0x67636461) /* "gcda" */
+
+#define GCOV_TAG_FUNCTION ((unsigned int) 0x01000000)
+#define GCOV_TAG_FUNCTION_LENGTH (3) /* or 2 */
+#define GCOV_COUNTER_ARCS 0
+#define GCOV_TAG_ARCS ((unsigned)0x01430000)
+#define GCOV_TAG_ARCS_LENGTH(NUM) (1 + (NUM) * 2)
+#define GCOV_TAG_ARCS_NUM(LENGTH) (((LENGTH) - 1) / 2)
+#define GCOV_TAG_LINES ((unsigned)0x01450000)
+#define GCOV_TAG_BLOCKS ((unsigned)0x01410000)
+#define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM)
+#define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH)
+#define GCOV_TAG_OBJECT_SUMMARY ((unsigned)0xa1000000)
+#define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2)
+
+#define GCOV_HISTOGRAM_SIZE 252
+#define GCOV_HISTOGRAM_BITVECTOR_SIZE (GCOV_HISTOGRAM_SIZE + 31) / 32
+#define GCOV_COUNTERS_SUMMABLE (GCOV_COUNTER_ARCS + 1)
+
+#define GCOV_TAG_IS_COUNTER(TAG) \
+ (!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS)
+
+#define GCOV_TAG_MASK(TAG) (((TAG) - 1) ^ (TAG))
+
+/* Return nonzero if SUB is an immediate subtag of TAG. */
+#define GCOV_TAG_IS_SUBTAG(TAG,SUB) \
+ (GCOV_TAG_MASK (TAG) >> 8 == GCOV_TAG_MASK (SUB) \
+ && !(((SUB) ^ (TAG)) & ~GCOV_TAG_MASK (TAG)))
+
+/* Return nonzero if SUB is at a sublevel to TAG. */
+#define GCOV_TAG_IS_SUBLEVEL(TAG,SUB) \
+ (GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB))
+
+
+typedef long long gcov_type;
+
+enum {
+GCOV_COUNTERS
+};
+
+
+#define assert(EXPR) { if (!(EXPR)) exit(-1); }
+
+#define GCOV_VERSION ((unsigned)0x34303670) /* 406p */
+
+#define GCOV_TAG_BUILD_INFO ((unsigned)0xa7000000)
+#define GCOV_TAG_PROGRAM_SUMMARY ((unsigned)0xa3000000)
+
+#define XCNEWVEC(T, N) ((T*) calloc((N), sizeof(T)))
+
+#define GCOV_TAG_COUNTER_BASE ((unsigned) 0x01a10000)
+#define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 2)
+
+/* Convert a counter index to a tag. */
+#define GCOV_TAG_FOR_COUNTER(COUNT) \
+ (GCOV_TAG_COUNTER_BASE + ((unsigned)(COUNT) << 17))
+
+/* Convert a tag to a counter. */
+#define GCOV_COUNTER_FOR_TAG(TAG) \
+ ((unsigned)(((TAG) - GCOV_TAG_COUNTER_BASE) >> 17))
+
+/* Check whether a tag is a counter tag. */
+#define GCOV_TAG_IS_COUNTER(TAG) \
+ (!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS)
+
+#define GCOV_UNSIGNED2STRING(ARRAY,VALUE) \
+ ((ARRAY)[0] = (char)((VALUE) >> 24), \
+ (ARRAY)[1] = (char)((VALUE) >> 16), \
+ (ARRAY)[2] = (char)((VALUE) >> 8), \
+ (ARRAY)[3] = (char)((VALUE) >> 0))
+
+#define GCOV_BLOCK_SIZE (1 << 10)
+
+
+typedef struct arc_info {
+ /* source and destination blocks. */
+ struct block_info *src;
+ struct block_info *dst;
+
+ /* transition counts. */
+ gcov_type count;
+ /* used in cycle search, so that we do not clobber original counts. */
+ gcov_type cs_count;
+
+ unsigned int count_valid : 1;
+ unsigned int on_tree : 1;
+ unsigned int fake : 1;
+ unsigned int fall_through : 1;
+
+ /* Arc to a catch handler. */
+ unsigned int is_throw : 1;
+
+ /* Arc is for a function that abnormally returns. */
+ unsigned int is_call_non_return : 1;
+
+ /* Arc is for catch/setjmp. */
+ unsigned int is_nonlocal_return : 1;
+
+ /* Is an unconditional branch. */
+ unsigned int is_unconditional : 1;
+
+ /* Loop making arc. */
+ unsigned int cycle : 1;
+
+ /* Next branch on line. */
+ struct arc_info *line_next;
+
+ /* Links to next arc on src and dst lists. */
+ struct arc_info *succ_next;
+ struct arc_info *pred_next;
+} arc_t;
+
+
+struct gcov_var_t
+{
+ FILE *file;
+ unsigned start; /* Position of first byte of block */
+ unsigned offset; /* Read/write position within the block. */
+ unsigned length; /* Read limit in the block. */
+ unsigned overread; /* Number of words overread. */
+ int error; /* < 0 overflow, > 0 disk error. */
+ int mode; /* < 0 writing, > 0 reading */
+ int endian; /* Swap endianness. */
+ /* Holds a variable length block, as the compiler can write
+ strings and needs to backtrack. */
+ size_t alloc;
+ unsigned *buffer;
+};
+
+
+unsigned gcov_position (void);
+int gcov_is_error();
+unsigned gcov_read_string_array(char **string_array, unsigned num_strings);
+unsigned gcov_read_unsigned();
+void gcov_allocate(unsigned length);
+const unsigned* gcov_read_words(unsigned words);
+int gcov_magic(unsigned magic, unsigned expected);
+gcov_type gcov_read_counter();
+void gcov_write_block(unsigned size);
+const char* gcov_read_string();
+bool gcov_open(const char *name, int mode);
+void gcov_sync(unsigned base, unsigned length);
+int gcov_close();
+
+} // namespace vts
+} // namespace android
+
+#endif
diff --git a/sysfuzzer/libcodecoverage/testdata/lights.gcda b/sysfuzzer/libcodecoverage/testdata/lights.gcda
new file mode 100644
index 0000000..d200289
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/testdata/lights.gcda
Binary files differ
diff --git a/sysfuzzer/libcodecoverage/testdata/lights.gcno b/sysfuzzer/libcodecoverage/testdata/lights.gcno
new file mode 100644
index 0000000..608d0fb
--- /dev/null
+++ b/sysfuzzer/libcodecoverage/testdata/lights.gcno
Binary files differ
diff --git a/sysfuzzer/libmeasurement/vts_measurement.cpp b/sysfuzzer/libmeasurement/vts_measurement.cpp
index 3664dc3..deb8e6e 100644
--- a/sysfuzzer/libmeasurement/vts_measurement.cpp
+++ b/sysfuzzer/libmeasurement/vts_measurement.cpp
@@ -23,15 +23,59 @@
#endif
#include <stdlib.h>
+#include <iostream>
+
+#define COVERAGE_SANCOV 0
+
+#if COVERAGE_SANCOV
+#include <sanitizer/coverage_interface.h>
+#endif
+
#include <vector>
using namespace std;
+#if COVERAGE_SANCOV
+
+extern "C" {
+// Re-declare some of the sanitizer functions as "weak" so that
+// libFuzzer can be linked w/o the sanitizers and sanitizer-coverage
+// (in which case it will complain at start-up time).
+__attribute__((weak)) void __sanitizer_print_stack_trace();
+__attribute__((weak)) void __sanitizer_reset_coverage();
+__attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs();
+__attribute__((weak)) size_t __sanitizer_get_total_unique_coverage();
+__attribute__((weak))
+void __sanitizer_set_death_callback(void (*callback)(void));
+__attribute__((weak)) size_t __sanitizer_get_number_of_counters();
+__attribute__((weak))
+uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
+}
+
+#define CHECK_WEAK_API_FUNCTION(fn) \
+ do { \
+ if (!fn) \
+ MissingWeakApiFunction(#fn); \
+ } while (false)
+
+static void MissingWeakApiFunction(const char *FnName) {
+ cerr << "ERROR: " << FnName << " is not defined. Exiting.\n"
+ << "Did you use -fsanitize-coverage=... to build your code?" << endl;
+ exit(1);
+}
+#endif
namespace android {
namespace vts {
void VtsMeasurement::Start() {
+#if COVERAGE_SANCOV
+ cout << "reset coverage";
+ CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage);
+ __sanitizer_reset_coverage();
+ cout << endl;
+#endif
+
#if USE_CTIME
gettimeofday(&tv_, NULL);
#else
@@ -65,6 +109,11 @@
result->push_back(stop_time_usecs - start_time_usecs);
#endif
+#if COVERAGE_SANCOV
+ cout << "coverage: ";
+ cout << __sanitizer_get_total_unique_caller_callee_pairs() << endl;
+#endif
+
return result;
}