/* * 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 "GcdaFile.h" #include #include #include #include #include #include namespace android { namespace vts { bool GcdaFile::Open() { if (filename_.length() < 1) return false; if (gcov_var_.file) return false; memset(&gcov_var_, 0, sizeof(gcov_var_)); gcov_var_.overread = -1u; gcov_var_.file = fopen(filename_.c_str(), "rb"); if (!gcov_var_.file) return false; gcov_var_.mode = 0; setbuf(gcov_var_.file, (char*)0); return true; } int GcdaFile::Close() { if (gcov_var_.file) { 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; } void GcdaFile::Sync(unsigned base, unsigned length) { if (!gcov_var_.file) return; 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; } } unsigned GcdaFile::ReadStringArray(char** string_array, unsigned num_strings) { unsigned i; unsigned j; unsigned len = 0; for (j = 0; j < num_strings; j++) { unsigned string_len = ReadUnsigned(); string_array[j] = (char*)malloc(string_len * sizeof(unsigned)); // xmalloc for (i = 0; i < string_len; i++) { ((unsigned*)string_array[j])[i] = ReadUnsigned(); } len += (string_len + 1); } return len; } unsigned GcdaFile::ReadUnsigned() { const unsigned* buffer = ReadWords(1); if (!buffer) return 0; return FromFile(buffer[0]); } void GcdaFile::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* GcdaFile::ReadWords(unsigned words) { const unsigned* result; unsigned excess = gcov_var_.length - gcov_var_.offset; if (!gcov_var_.file) return 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) { 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 GcdaFile::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 GcdaFile::ReadCounter() { gcov_type value; const unsigned* buffer = ReadWords(2); if (!buffer) return 0; value = FromFile(buffer[0]); if (sizeof(value) > sizeof(unsigned)) { value |= ((gcov_type)FromFile(buffer[1])) << 32; } else if (buffer[1]) { gcov_var_.error = -1; } return value; } void GcdaFile::WriteBlock(unsigned size) { int num_words = fwrite(gcov_var_.buffer, size << 2, 1, gcov_var_.file); if (num_words != 1) { gcov_var_.error = 1; } gcov_var_.start += size; gcov_var_.offset -= size; } const char* GcdaFile::ReadString() { unsigned length = ReadUnsigned(); if (!length) return 0; return (const char*)ReadWords(length); } } // namespace vts } // namespace android