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 #if defined(__LP64__) 36 #define PATH_TO_SYSTEM_LIB "/system/lib64/" 37 #else 38 #define PATH_TO_SYSTEM_LIB "/system/lib/" 39 #endif 40 41 #if defined(__BIONIC__) 42 #define KNOWN_FAILURE_ON_BIONIC(x) xfail_ ## x 43 #else 44 #define KNOWN_FAILURE_ON_BIONIC(x) x 45 #endif 46 47 #if defined(__linux__) 48 49 struct map_record { 50 uintptr_t addr_start; 51 uintptr_t addr_end; 52 53 int perms; 54 55 size_t offset; 56 57 dev_t device; 58 ino_t inode; 59 60 std::string pathname; 61 }; 62 63 class Maps { 64 public: 65 static bool parse_maps(std::vector<map_record>* maps) { 66 FILE* fp = fopen("/proc/self/maps", "re"); 67 if (fp == nullptr) { 68 return false; 69 } 70 71 auto fp_guard = make_scope_guard([&]() { 72 fclose(fp); 73 }); 74 75 char line[BUFSIZ]; 76 while (fgets(line, sizeof(line), fp) != nullptr) { 77 map_record record; 78 uint32_t dev_major, dev_minor; 79 int path_offset; 80 char prot[5]; // sizeof("rwxp") 81 if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %n", 82 &record.addr_start, &record.addr_end, prot, &record.offset, 83 &dev_major, &dev_minor, &record.inode, &path_offset) == 7) { 84 record.perms = 0; 85 if (prot[0] == 'r') { 86 record.perms |= PROT_READ; 87 } 88 if (prot[1] == 'w') { 89 record.perms |= PROT_WRITE; 90 } 91 if (prot[2] == 'x') { 92 record.perms |= PROT_EXEC; 93 } 94 95 // TODO: parse shared/private? 96 97 record.device = makedev(dev_major, dev_minor); 98 record.pathname = line + path_offset; 99 if (!record.pathname.empty() && record.pathname.back() == '\n') { 100 record.pathname.pop_back(); 101 } 102 maps->push_back(record); 103 } 104 } 105 106 return true; 107 } 108 }; 109 110 extern "C" pid_t gettid(); 111 112 #endif 113 114 static inline void WaitUntilThreadSleep(std::atomic<pid_t>& tid) { 115 while (tid == 0) { 116 usleep(1000); 117 } 118 std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load()); 119 std::regex regex {R"(\s+S\s+)"}; 120 121 while (true) { 122 std::string content; 123 ASSERT_TRUE(android::base::ReadFileToString(filename, &content)); 124 if (std::regex_search(content, regex)) { 125 break; 126 } 127 usleep(1000); 128 } 129 } 130 131 static inline void AssertChildExited(int pid, int expected_exit_status) { 132 int status; 133 ASSERT_EQ(pid, waitpid(pid, &status, 0)); 134 if (expected_exit_status >= 0) { 135 ASSERT_TRUE(WIFEXITED(status)); 136 ASSERT_EQ(expected_exit_status, WEXITSTATUS(status)); 137 } else { 138 ASSERT_TRUE(WIFSIGNALED(status)); 139 ASSERT_EQ(-expected_exit_status, WTERMSIG(status)); 140 } 141 } 142 143 // The absolute path to the executable 144 const std::string& get_executable_path(); 145 146 // Access to argc/argv/envp 147 int get_argc(); 148 char** get_argv(); 149 char** get_envp(); 150 151 // ExecTestHelper is only used in bionic and glibc tests. 152 #ifndef __APPLE__ 153 class ExecTestHelper { 154 public: 155 char** GetArgs() { 156 return const_cast<char**>(args_.data()); 157 } 158 char** GetEnv() { 159 return const_cast<char**>(env_.data()); 160 } 161 162 void SetArgs(const std::vector<const char*> args) { 163 args_ = args; 164 } 165 void SetEnv(const std::vector<const char*> env) { 166 env_ = env; 167 } 168 169 void Run(const std::function<void()>& child_fn, int expected_exit_status, 170 const char* expected_output) { 171 int fds[2]; 172 ASSERT_NE(pipe(fds), -1); 173 174 pid_t pid = fork(); 175 ASSERT_NE(pid, -1); 176 177 if (pid == 0) { 178 // Child. 179 close(fds[0]); 180 dup2(fds[1], STDOUT_FILENO); 181 dup2(fds[1], STDERR_FILENO); 182 if (fds[1] != STDOUT_FILENO && fds[1] != STDERR_FILENO) close(fds[1]); 183 child_fn(); 184 FAIL(); 185 } 186 187 // Parent. 188 close(fds[1]); 189 std::string output; 190 char buf[BUFSIZ]; 191 ssize_t bytes_read; 192 while ((bytes_read = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)))) > 0) { 193 output.append(buf, bytes_read); 194 } 195 close(fds[0]); 196 197 AssertChildExited(pid, expected_exit_status); 198 if (expected_output != nullptr) { 199 ASSERT_EQ(expected_output, output); 200 } 201 } 202 203 private: 204 std::vector<const char*> args_; 205 std::vector<const char*> env_; 206 }; 207 #endif 208 209 #endif 210