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 
Open()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 
Close()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 
Sync(unsigned base,unsigned length)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 }
ReadStringArray(char ** string_array,unsigned num_strings)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 
ReadUnsigned()84 unsigned GcdaFile::ReadUnsigned() {
85   const unsigned* buffer = ReadWords(1);
86 
87   if (!buffer) return 0;
88   return FromFile(buffer[0]);
89 }
90 
Allocate(unsigned length)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 
ReadWords(unsigned words)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 
Magic(unsigned magic,unsigned expected)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 
ReadCounter()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 
WriteBlock(unsigned size)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 
ReadString()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