• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "fuzz_tester/FuzzerBase.h"
18 
19 #include <dirent.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/mman.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <fstream>
28 #include <iostream>
29 #include <sstream>
30 #include <string>
31 #include <vector>
32 
33 #include "test/vts/proto/ComponentSpecificationMessage.pb.h"
34 
35 #include "component_loader/DllLoader.h"
36 #include "utils/InterfaceSpecUtil.h"
37 
38 #include "GcdaParser.h"
39 
40 using namespace std;
41 using namespace android;
42 
43 #define USE_GCOV 1
44 
45 #if SANCOV
46 extern "C" {
47 typedef unsigned long uptr;
48 
49 #define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
50 SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_cov(uint32_t * guard)51 void __sanitizer_cov(uint32_t* guard) {
52   printf("sancov\n");
53   coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
54                     guard);
55 }
56 
57 SANITIZER_INTERFACE_ATTRIBUTE
__asan_memset(void * block,int c,uptr size)58 void* __asan_memset(void* block, int c, uptr size) {
59   ASAN_MEMSET_IMPL(nullptr, block, c, size);
60   return block;
61 }
62 
63 SANITIZER_INTERFACE_ATTRIBUTE
__asan_register_globals()64 void __asan_register_globals() {}
65 SANITIZER_INTERFACE_ATTRIBUTE
__asan_unregister_globals()66 void __asan_unregister_globals() {}
67 SANITIZER_INTERFACE_ATTRIBUTE
__asan_handle_no_return()68 void __asan_handle_no_return() {}
69 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_load1()70 void __asan_report_load1() {}
71 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_load2()72 void __asan_report_load2() {}
73 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_load4()74 void __asan_report_load4() {}
75 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_load8()76 void __asan_report_load8() {}
77 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_load16()78 void __asan_report_load16() {}
79 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_store1()80 void __asan_report_store1() {}
81 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_store2()82 void __asan_report_store2() {}
83 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_store4()84 void __asan_report_store4() {}
85 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_store8()86 void __asan_report_store8() {}
87 SANITIZER_INTERFACE_ATTRIBUTE
__asan_report_store16()88 void __asan_report_store16() {}
89 SANITIZER_INTERFACE_ATTRIBUTE
__asan_set_error_report_callback()90 void __asan_set_error_report_callback() {}
91 
92 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_1(uptr size,uptr real_stack)93 uptr __asan_stack_malloc_1(uptr size, uptr real_stack) {
94   return (uptr)malloc(size);
95 }
96 
97 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_2(uptr size,uptr real_stack)98 uptr __asan_stack_malloc_2(uptr size, uptr real_stack) {
99   return (uptr)malloc(size);
100 }
101 
102 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_3(uptr size,uptr real_stack)103 uptr __asan_stack_malloc_3(uptr size, uptr real_stack) {
104   return (uptr)malloc(size);
105 }
106 
107 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_4(uptr size,uptr real_stack)108 uptr __asan_stack_malloc_4(uptr size, uptr real_stack) {
109   return (uptr)malloc(size);
110 }
111 
112 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_5(uptr size,uptr real_stack)113 uptr __asan_stack_malloc_5(uptr size, uptr real_stack) {
114   return (uptr)malloc(size);
115 }
116 
117 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_6(uptr size,uptr real_stack)118 uptr __asan_stack_malloc_6(uptr size, uptr real_stack) {
119   return (uptr)malloc(size);
120 }
121 
122 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_7(uptr size,uptr real_stack)123 uptr __asan_stack_malloc_7(uptr size, uptr real_stack) {
124   return (uptr)malloc(size);
125 }
126 
127 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_8(uptr size,uptr real_stack)128 uptr __asan_stack_malloc_8(uptr size, uptr real_stack) {
129   return (uptr)malloc(size);
130 }
131 
132 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_9(uptr size,uptr real_stack)133 uptr __asan_stack_malloc_9(uptr size, uptr real_stack) {
134   return (uptr)malloc(size);
135 }
136 
137 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_malloc_10(uptr size,uptr real_stack)138 uptr __asan_stack_malloc_10(uptr size, uptr real_stack) {
139   return (uptr)malloc(size);
140 }
141 
142 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_1(uptr ptr,uptr size,uptr real_stack)143 void __asan_stack_free_1(uptr ptr, uptr size, uptr real_stack) {
144   free((void*)ptr);
145 }
146 
147 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_2(uptr ptr,uptr size,uptr real_stack)148 void __asan_stack_free_2(uptr ptr, uptr size, uptr real_stack) {
149   free((void*)ptr);
150 }
151 
152 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_3(uptr ptr,uptr size,uptr real_stack)153 void __asan_stack_free_3(uptr ptr, uptr size, uptr real_stack) {
154   free((void*)ptr);
155 }
156 
157 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_4(uptr ptr,uptr size,uptr real_stack)158 void __asan_stack_free_4(uptr ptr, uptr size, uptr real_stack) {
159   free((void*)ptr);
160 }
161 
162 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_5(uptr ptr,uptr size,uptr real_stack)163 void __asan_stack_free_5(uptr ptr, uptr size, uptr real_stack) {
164   free((void*)ptr);
165 }
166 
167 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_6(uptr ptr,uptr size,uptr real_stack)168 void __asan_stack_free_6(uptr ptr, uptr size, uptr real_stack) {
169   free((void*)ptr);
170 }
171 
172 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_7(uptr ptr,uptr size,uptr real_stack)173 void __asan_stack_free_7(uptr ptr, uptr size, uptr real_stack) {
174   free((void*)ptr);
175 }
176 
177 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_8(uptr ptr,uptr size,uptr real_stack)178 void __asan_stack_free_8(uptr ptr, uptr size, uptr real_stack) {
179   free((void*)ptr);
180 }
181 
182 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_9(uptr ptr,uptr size,uptr real_stack)183 void __asan_stack_free_9(uptr ptr, uptr size, uptr real_stack) {
184   free((void*)ptr);
185 }
186 
187 SANITIZER_INTERFACE_ATTRIBUTE
__asan_stack_free_10(uptr ptr,uptr size,uptr real_stack)188 void __asan_stack_free_10(uptr ptr, uptr size, uptr real_stack) {
189   free((void*)ptr);
190 }
191 
192 SANITIZER_INTERFACE_ATTRIBUTE
__asan_version_mismatch_check_v6()193 void __asan_version_mismatch_check_v6() {
194   // Do nothing.
195 }
196 
__sanitizer_cov_module_init(int32_t * guards,uptr npcs,uint8_t * counters,const char * comp_unit_name)197 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(
198     int32_t* guards, uptr npcs, uint8_t* counters, const char* comp_unit_name) {
199 }
200 
201 SANITIZER_INTERFACE_ATTRIBUTE
__asan_init()202 void __asan_init() {
203   static int inited = 0;
204   if (inited) return;
205   inited = 1;
206 #if __WORDSIZE == 64
207   unsigned long start = 0x100000000000;
208   unsigned long size = 0x100000000000;
209 #else
210   unsigned long start = 0x20000000;
211   unsigned long size = 0x20000000;
212 #endif
213   void* res = mmap((void*)start, size, PROT_READ | PROT_WRITE,
214                    MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
215   if (res == (void*)start) {
216     fprintf(stderr, "Fake AddressSanitizer run-time initialized ok at %p\n",
217             res);
218   } else {
219     fprintf(stderr,
220             "Fake AddressSanitizer run-time failed to initialize.\n"
221             "You have been warned. Aborting.");
222     abort();
223   }
224 }
225 }
226 #endif
227 
228 namespace android {
229 namespace vts {
230 
231 const string default_gcov_output_basepath = "/data/misc/gcov";
232 
RemoveDir(char * path)233 static void RemoveDir(char* path) {
234   struct dirent* entry = NULL;
235   DIR* dir = opendir(path);
236 
237   while ((entry = readdir(dir)) != NULL) {
238     DIR* sub_dir = NULL;
239     FILE* file = NULL;
240     char abs_path[4096] = {0};
241 
242     if (*(entry->d_name) != '.') {
243       sprintf(abs_path, "%s/%s", path, entry->d_name);
244       if ((sub_dir = opendir(abs_path)) != NULL) {
245         closedir(sub_dir);
246         RemoveDir(abs_path);
247       } else if ((file = fopen(abs_path, "r")) != NULL) {
248         fclose(file);
249         remove(abs_path);
250       }
251     }
252   }
253   remove(path);
254 }
255 
FuzzerBase(int target_class)256 FuzzerBase::FuzzerBase(int target_class)
257     : device_(NULL),
258       hmi_(NULL),
259       target_dll_path_(NULL),
260       target_class_(target_class),
261       component_filename_(NULL),
262       gcov_output_basepath_(NULL) {}
263 
~FuzzerBase()264 FuzzerBase::~FuzzerBase() { free(component_filename_); }
265 
wfn()266 void wfn() {
267   cout << __func__ << endl;
268 }
269 
ffn()270 void ffn() {
271   cout << __func__ << endl;
272 }
273 
LoadTargetComponent(const char * target_dll_path)274 bool FuzzerBase::LoadTargetComponent(const char* target_dll_path) {
275   cout << __func__ << ":" << __LINE__ << " entry" << endl;
276   if (target_dll_path && target_dll_path_ &&
277       !strcmp(target_dll_path, target_dll_path_)) {
278     cout << __func__ << " skip loading" << endl;
279     return true;
280   }
281 
282   if (!target_loader_.Load(target_dll_path)) return false;
283   target_dll_path_ = (char*)malloc(strlen(target_dll_path) + 1);
284   strcpy(target_dll_path_, target_dll_path);
285   cout << __FUNCTION__ << ":" << __LINE__ << " loaded the target" << endl;
286   if (target_class_ == HAL_LEGACY) return true;
287   cout << __FUNCTION__ << ":" << __LINE__ << " loaded a non-legacy HAL file."
288        << endl;
289   if (target_class_ == HAL_CONVENTIONAL) {
290     hmi_ = target_loader_.InitConventionalHal();
291     if (!hmi_) {
292       free(target_dll_path_);
293       target_dll_path_ = NULL;
294       return false;
295     }
296   }
297 #if SANCOV
298   cout << __FUNCTION__ << "sancov reset "
299        << target_loader_.SancovResetCoverage() << endl;
300 #endif
301 
302   if (target_dll_path_) {
303     cout << __func__ << ":" << __LINE__ << " target DLL path "
304          << target_dll_path_ << endl;
305     string target_path(target_dll_path_);
306 
307     size_t offset = target_path.rfind("/", target_path.length());
308     if (offset != string::npos) {
309       string filename =
310           target_path.substr(offset + 1, target_path.length() - offset);
311       filename = filename.substr(0, filename.length() - 3 /* for .so */);
312       component_filename_ = (char*)malloc(filename.length() + 1);
313       strcpy(component_filename_, filename.c_str());
314       cout << __FUNCTION__ << ":" << __LINE__
315            << " module file name: " << component_filename_ << endl;
316     }
317     cout << __FUNCTION__ << ":" << __LINE__ << " target_dll_path "
318          << target_dll_path_ << endl;
319   }
320 
321 #if USE_GCOV
322   cout << __FUNCTION__ << ": gcov init " << target_loader_.GcovInit(wfn, ffn)
323        << endl;
324 #endif
325   return true;
326 }
327 
SetTargetObject(void * object_pointer)328 bool FuzzerBase::SetTargetObject(void* object_pointer) {
329   device_ = NULL;
330   hmi_ = reinterpret_cast<struct hw_module_t*>(object_pointer);
331   return true;
332 }
333 
GetService(bool,const char *)334 bool FuzzerBase::GetService(bool /*get_stub*/, const char* /*service_name*/) {
335   cerr << __func__ << " not impl" << endl;
336   return false;
337 }
338 
OpenConventionalHal(const char * module_name)339 int FuzzerBase::OpenConventionalHal(const char* module_name) {
340   cout << __func__ << endl;
341   if (module_name) cout << __func__ << " " << module_name << endl;
342   device_ = target_loader_.OpenConventionalHal(module_name);
343   if (!device_) return -1;
344   cout << __func__ << " device_" << device_ << endl;
345   return 0;
346 }
347 
Fuzz(vts::ComponentSpecificationMessage * message,void ** result)348 bool FuzzerBase::Fuzz(vts::ComponentSpecificationMessage* message,
349                       void** result) {
350   cout << __func__ << " Fuzzing target component: "
351        << "class " << message->component_class() << " type "
352        << message->component_type() << " version "
353        << message->component_type_version() << endl;
354 
355   string function_name_prefix = GetFunctionNamePrefix(*message);
356   function_name_prefix_ = function_name_prefix.c_str();
357   for (vts::FunctionSpecificationMessage func_msg :
358        *message->mutable_interface()->mutable_api()) {
359     Fuzz(&func_msg, result, "");
360   }
361   return true;
362 }
363 
FunctionCallBegin()364 void FuzzerBase::FunctionCallBegin() {
365   char product_path[4096];
366   char product[128];
367   char module_basepath[4096];
368 
369   cout << __func__ << ":" << __LINE__ << " begin" << endl;
370   snprintf(product_path, 4096, "%s/%s", default_gcov_output_basepath.c_str(),
371            "proc/self/cwd/out/target/product");
372   DIR* srcdir = opendir(product_path);
373   if (!srcdir) {
374     cerr << __func__ << " couldn't open " << product_path << endl;
375     return;
376   }
377 
378   int dir_count = 0;
379   struct dirent* dent;
380   while ((dent = readdir(srcdir)) != NULL) {
381     struct stat st;
382     if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
383       continue;
384     }
385     if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
386       cerr << __func__ << " error " << dent->d_name << endl;
387       continue;
388     }
389     if (S_ISDIR(st.st_mode)) {
390       cout << __func__ << ":" << __LINE__ << " dir " << dent->d_name << endl;
391       strcpy(product, dent->d_name);
392       dir_count++;
393     }
394   }
395   closedir(srcdir);
396   if (dir_count != 1) {
397     cerr << __func__ << " more than one product dir found." << endl;
398     return;
399   }
400 
401   int n = snprintf(module_basepath, 4096, "%s/%s/obj/SHARED_LIBRARIES",
402                    product_path, product);
403   if (n <= 0 || n >= 4096) {
404     cerr << __func__ << " couln't get module_basepath" << endl;
405     return;
406   }
407   srcdir = opendir(module_basepath);
408   if (!srcdir) {
409     cerr << __func__ << " couln't open " << module_basepath << endl;
410     return;
411   }
412 
413   if (component_filename_ != NULL) {
414     dir_count = 0;
415     string target = string(component_filename_) + "_intermediates";
416     bool hit = false;
417     cout << __func__ << ":" << __LINE__ << endl;
418     while ((dent = readdir(srcdir)) != NULL) {
419       struct stat st;
420       if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
421         continue;
422       }
423       if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
424         cerr << __func__ << " error " << dent->d_name << endl;
425         continue;
426       }
427       if (S_ISDIR(st.st_mode)) {
428         cout << "module_basepath " << string(dent->d_name) << endl;
429         if (string(dent->d_name) == target) {
430           cout << "hit" << endl;
431           hit = true;
432         }
433         dir_count++;
434       }
435     }
436     if (hit) {
437       free(gcov_output_basepath_);
438       gcov_output_basepath_ =
439           (char*)malloc(strlen(module_basepath) + target.length() + 2);
440       if (!gcov_output_basepath_) {
441         cerr << __FUNCTION__ << ": couldn't alloc memory" << endl;
442         return;
443       }
444       sprintf(gcov_output_basepath_, "%s/%s", module_basepath, target.c_str());
445       RemoveDir(gcov_output_basepath_);
446     }
447   } else {
448     cerr << __func__ << ":" << __LINE__ << " component_filename_ is NULL"
449          << endl;
450   }
451   // TODO: check how it works when there already is a file.
452   closedir(srcdir);
453   cout << __func__ << ":" << __LINE__ << " end" << endl;
454 }
455 
ReadGcdaFile(const string & basepath,const string & filename,FunctionSpecificationMessage * msg)456 bool FuzzerBase::ReadGcdaFile(
457     const string& basepath, const string& filename,
458     FunctionSpecificationMessage* msg) {
459 #if VTS_GCOV_DEBUG
460       cout << __func__ << ":" << __LINE__
461            << " file = " << dent->d_name << endl;
462 #endif
463   if (string(filename).rfind(".gcda") != string::npos) {
464     string buffer = basepath + "/" + filename;
465     vector<unsigned> processed_data =
466       android::vts::GcdaRawCoverageParser(buffer.c_str()).Parse();
467     for (const auto& data : processed_data) {
468       msg->mutable_processed_coverage_data()->Add(data);
469     }
470 
471     FILE* gcda_file = fopen(buffer.c_str(), "rb");
472     if (!gcda_file) {
473       cerr << __func__ << ":" << __LINE__
474            << " Unable to open a gcda file. " << buffer << endl;
475     } else {
476       cout << __func__ << ":" << __LINE__
477            << " Opened a gcda file. " << buffer << endl;
478       fseek(gcda_file, 0, SEEK_END);
479       long gcda_file_size = ftell(gcda_file);
480 #if VTS_GCOV_DEBUG
481       cout << __func__ << ":" << __LINE__
482            << " File size " << gcda_file_size << " bytes" << endl;
483 #endif
484       fseek(gcda_file, 0, SEEK_SET);
485 
486       char* gcda_file_buffer = (char*)malloc(gcda_file_size + 1);
487       if (!gcda_file_buffer) {
488         cerr << __func__ << ":" << __LINE__
489              << "Unable to allocate memory to read a gcda file. " << endl;
490       } else {
491         if (fread(gcda_file_buffer, gcda_file_size, 1, gcda_file) != 1) {
492           cerr << __func__ << ":" << __LINE__
493                << "File read error" << endl;
494         } else {
495 #if VTS_GCOV_DEBUG
496           cout << __func__ << ":" << __LINE__
497                << " GCDA field populated." << endl;
498 #endif
499           gcda_file_buffer[gcda_file_size] = '\0';
500           NativeCodeCoverageRawDataMessage* raw_msg =
501               msg->mutable_raw_coverage_data()->Add();
502           raw_msg->set_file_path(filename.c_str());
503           string gcda_file_buffer_string(gcda_file_buffer, gcda_file_size);
504           raw_msg->set_gcda(gcda_file_buffer_string);
505           free(gcda_file_buffer);
506         }
507       }
508       fclose(gcda_file);
509     }
510 #if USE_GCOV_DEBUG
511     if (result) {
512       for (unsigned int index = 0; index < result->size(); index++) {
513         cout << result->at(index) << endl;
514       }
515     }
516 #endif
517     return true;
518   }
519   return false;
520 }
521 
ScanAllGcdaFiles(const string & basepath,FunctionSpecificationMessage * msg)522 bool FuzzerBase::ScanAllGcdaFiles(
523     const string& basepath, FunctionSpecificationMessage* msg) {
524   DIR* srcdir = opendir(basepath.c_str());
525   if (!srcdir) {
526     cerr << __func__ << ":" << __LINE__
527          << " couln't open " << basepath << endl;
528     return false;
529   }
530 
531   struct dirent* dent;
532   while ((dent = readdir(srcdir)) != NULL) {
533 #if VTS_GCOV_DEBUG
534     cout << __func__ << ":" << __LINE__
535          << " readdir(" << basepath << ") for " << dent->d_name << endl;
536 #endif
537     struct stat st;
538     if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
539       continue;
540     }
541     if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
542       cerr << "error " << dent->d_name << endl;
543       continue;
544     }
545     if (S_ISDIR(st.st_mode)) {
546       ScanAllGcdaFiles(basepath + "/" + dent->d_name, msg);
547     } else {
548       ReadGcdaFile(basepath, dent->d_name, msg);
549     }
550   }
551 #if VTS_GCOV_DEBUG
552   cout << __func__ << ":" << __LINE__
553        << " closedir(" << srcdir << ")" << endl;
554 #endif
555   closedir(srcdir);
556   return true;
557 }
558 
FunctionCallEnd(FunctionSpecificationMessage * msg)559 bool FuzzerBase::FunctionCallEnd(FunctionSpecificationMessage* msg) {
560   cout << __func__ << ": gcov flush " << endl;
561 #if USE_GCOV
562   target_loader_.GcovFlush();
563   // find the file.
564   if (!gcov_output_basepath_) {
565     cerr << __FUNCTION__ << ": no gcov basepath set" << endl;
566     return ScanAllGcdaFiles(default_gcov_output_basepath, msg);
567   }
568   DIR* srcdir = opendir(gcov_output_basepath_);
569   if (!srcdir) {
570     cerr << __func__ << " couln't open " << gcov_output_basepath_ << endl;
571     return false;
572   }
573 
574   struct dirent* dent;
575   while ((dent = readdir(srcdir)) != NULL) {
576     cout << __func__ << ": readdir(" << srcdir << ") for " << dent->d_name
577          << endl;
578 
579     struct stat st;
580     if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
581       continue;
582     }
583     if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
584       cerr << "error " << dent->d_name << endl;
585       continue;
586     }
587     if (!S_ISDIR(st.st_mode)
588         && ReadGcdaFile(gcov_output_basepath_, dent->d_name, msg)) {
589       break;
590     }
591   }
592   cout << __func__ << ": closedir(" << srcdir << ")" << endl;
593   closedir(srcdir);
594 #endif
595   return true;
596 }
597 
598 }  // namespace vts
599 }  // namespace android
600