Home | History | Annotate | Download | only in libcodecoverage
      1 /*
      2  * Copyright 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "GcdaFile.h"
     18 
     19 #include <inttypes.h>
     20 #include <stdarg.h>
     21 #include <stdint.h>
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 
     26 namespace android {
     27 namespace vts {
     28 
     29 bool GcdaFile::Open() {
     30   if (filename_.length() < 1) return false;
     31   if (gcov_var_.file) return false;
     32 
     33   memset(&gcov_var_, 0, sizeof(gcov_var_));
     34   gcov_var_.overread = -1u;
     35 
     36   gcov_var_.file = fopen(filename_.c_str(), "rb");
     37   if (!gcov_var_.file) return false;
     38   gcov_var_.mode = 0;
     39   setbuf(gcov_var_.file, (char*)0);
     40   return true;
     41 }
     42 
     43 int GcdaFile::Close() {
     44   if (gcov_var_.file) {
     45     fclose(gcov_var_.file);
     46     gcov_var_.file = 0;
     47     gcov_var_.length = 0;
     48   }
     49   free(gcov_var_.buffer);
     50   gcov_var_.alloc = 0;
     51   gcov_var_.buffer = 0;
     52   gcov_var_.mode = 0;
     53   return gcov_var_.error;
     54 }
     55 
     56 void GcdaFile::Sync(unsigned base, unsigned length) {
     57   if (!gcov_var_.file) return;
     58 
     59   base += length;
     60   if (base - gcov_var_.start <= gcov_var_.length) {
     61     gcov_var_.offset = base - gcov_var_.start;
     62   } else {
     63     gcov_var_.offset = gcov_var_.length = 0;
     64     fseek(gcov_var_.file, base << 2, SEEK_SET);
     65     gcov_var_.start = ftell(gcov_var_.file) >> 2;
     66   }
     67 }
     68 unsigned GcdaFile::ReadStringArray(char** string_array, unsigned num_strings) {
     69   unsigned i;
     70   unsigned j;
     71   unsigned len = 0;
     72 
     73   for (j = 0; j < num_strings; j++) {
     74     unsigned string_len = ReadUnsigned();
     75     string_array[j] = (char*)malloc(string_len * sizeof(unsigned));  // xmalloc
     76     for (i = 0; i < string_len; i++) {
     77       ((unsigned*)string_array[j])[i] = ReadUnsigned();
     78     }
     79     len += (string_len + 1);
     80   }
     81   return len;
     82 }
     83 
     84 unsigned GcdaFile::ReadUnsigned() {
     85   const unsigned* buffer = ReadWords(1);
     86 
     87   if (!buffer) return 0;
     88   return FromFile(buffer[0]);
     89 }
     90 
     91 void GcdaFile::Allocate(unsigned length) {
     92   size_t new_size = gcov_var_.alloc;
     93 
     94   if (!new_size) new_size = GCOV_BLOCK_SIZE;
     95   new_size += length;
     96   new_size *= 2;
     97   gcov_var_.alloc = new_size;
     98   gcov_var_.buffer = (unsigned*)realloc(gcov_var_.buffer, new_size << 2);
     99 }
    100 
    101 const unsigned* GcdaFile::ReadWords(unsigned words) {
    102   const unsigned* result;
    103   unsigned excess = gcov_var_.length - gcov_var_.offset;
    104 
    105   if (!gcov_var_.file) return 0;
    106 
    107   if (excess < words) {
    108     gcov_var_.start += gcov_var_.offset;
    109     memmove(gcov_var_.buffer, gcov_var_.buffer + gcov_var_.offset, excess * 4);
    110     gcov_var_.offset = 0;
    111     gcov_var_.length = excess;
    112     if (gcov_var_.length + words > gcov_var_.alloc) {
    113       Allocate(gcov_var_.length + words);
    114     }
    115     excess = gcov_var_.alloc - gcov_var_.length;
    116     excess = fread(gcov_var_.buffer + gcov_var_.length, 1, excess << 2,
    117                    gcov_var_.file) >> 2;
    118     gcov_var_.length += excess;
    119     if (gcov_var_.length < words) {
    120       gcov_var_.overread += words - gcov_var_.length;
    121       gcov_var_.length = 0;
    122       return 0;
    123     }
    124   }
    125   result = &gcov_var_.buffer[gcov_var_.offset];
    126   gcov_var_.offset += words;
    127   return result;
    128 }
    129 
    130 int GcdaFile::Magic(unsigned magic, unsigned expected) {
    131   if (magic == expected) return 1;
    132   magic = (magic >> 16) | (magic << 16);
    133   magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
    134   if (magic == expected) {
    135     gcov_var_.endian = 1;
    136     return -1;
    137   }
    138   return 0;
    139 }
    140 
    141 gcov_type GcdaFile::ReadCounter() {
    142   gcov_type value;
    143   const unsigned* buffer = ReadWords(2);
    144   if (!buffer) return 0;
    145   value = FromFile(buffer[0]);
    146   if (sizeof(value) > sizeof(unsigned)) {
    147     value |= ((gcov_type)FromFile(buffer[1])) << 32;
    148   } else if (buffer[1]) {
    149     gcov_var_.error = -1;
    150   }
    151   return value;
    152 }
    153 
    154 void GcdaFile::WriteBlock(unsigned size) {
    155   int num_words = fwrite(gcov_var_.buffer, size << 2, 1, gcov_var_.file);
    156   if (num_words != 1) {
    157     gcov_var_.error = 1;
    158   }
    159   gcov_var_.start += size;
    160   gcov_var_.offset -= size;
    161 }
    162 
    163 const char* GcdaFile::ReadString() {
    164   unsigned length = ReadUnsigned();
    165   if (!length) return 0;
    166   return (const char*)ReadWords(length);
    167 }
    168 
    169 }  // namespace vts
    170 }  // namespace android
    171