1 /* 2 * Copyright (C) 2012 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 #ifndef __TEST_UTILS_H 18 #define __TEST_UTILS_H 19 20 #include <inttypes.h> 21 #include <sys/mman.h> 22 #include <sys/types.h> 23 #include <sys/wait.h> 24 #include <unistd.h> 25 26 #include <atomic> 27 #include <string> 28 #include <regex> 29 30 #include <android-base/file.h> 31 #include <android-base/stringprintf.h> 32 33 #include "private/ScopeGuard.h" 34 35 struct map_record { 36 uintptr_t addr_start; 37 uintptr_t addr_end; 38 39 int perms; 40 41 size_t offset; 42 43 dev_t device; 44 ino_t inode; 45 46 std::string pathname; 47 }; 48 49 class Maps { 50 public: 51 static bool parse_maps(std::vector<map_record>* maps) { 52 FILE* fp = fopen("/proc/self/maps", "re"); 53 if (fp == nullptr) { 54 return false; 55 } 56 57 auto fp_guard = make_scope_guard([&]() { 58 fclose(fp); 59 }); 60 61 char line[BUFSIZ]; 62 while (fgets(line, sizeof(line), fp) != nullptr) { 63 map_record record; 64 uint32_t dev_major, dev_minor; 65 int path_offset; 66 char prot[5]; // sizeof("rwxp") 67 if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %n", 68 &record.addr_start, &record.addr_end, prot, &record.offset, 69 &dev_major, &dev_minor, &record.inode, &path_offset) == 7) { 70 record.perms = 0; 71 if (prot[0] == 'r') { 72 record.perms |= PROT_READ; 73 } 74 if (prot[1] == 'w') { 75 record.perms |= PROT_WRITE; 76 } 77 if (prot[2] == 'x') { 78 record.perms |= PROT_EXEC; 79 } 80 81 // TODO: parse shared/private? 82 83 record.device = makedev(dev_major, dev_minor); 84 record.pathname = line + path_offset; 85 if (!record.pathname.empty() && record.pathname.back() == '\n') { 86 record.pathname.pop_back(); 87 } 88 maps->push_back(record); 89 } 90 } 91 92 return true; 93 } 94 }; 95 96 extern "C" pid_t gettid(); 97 98 static inline void WaitUntilThreadSleep(std::atomic<pid_t>& tid) { 99 while (tid == 0) { 100 usleep(1000); 101 } 102 std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load()); 103 std::regex regex {R"(\s+S\s+)"}; 104 105 while (true) { 106 std::string content; 107 ASSERT_TRUE(android::base::ReadFileToString(filename, &content)); 108 if (std::regex_search(content, regex)) { 109 break; 110 } 111 usleep(1000); 112 } 113 } 114 115 static inline void AssertChildExited(int pid, int expected_exit_status) { 116 int status; 117 ASSERT_EQ(pid, waitpid(pid, &status, 0)); 118 ASSERT_TRUE(WIFEXITED(status)); 119 ASSERT_EQ(expected_exit_status, WEXITSTATUS(status)); 120 } 121 122 // The absolute path to the executable 123 const std::string& get_executable_path(); 124 125 #endif 126