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