| Elliott Hughes | 2faa5f1 | 2012-01-30 14:42:07 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2011 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 |  */ | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 16 |  | 
| Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 17 | #include "utils.h" | 
 | 18 |  | 
| Christopher Ferris | 943af7d | 2014-01-16 12:41:46 -0800 | [diff] [blame] | 19 | #include <inttypes.h> | 
| Elliott Hughes | 92b3b56 | 2011-09-08 16:32:26 -0700 | [diff] [blame] | 20 | #include <pthread.h> | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 21 | #include <sys/stat.h> | 
| Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 22 | #include <sys/syscall.h> | 
 | 23 | #include <sys/types.h> | 
| Brian Carlstrom | 4cf5e57 | 2014-02-25 11:47:48 -0800 | [diff] [blame] | 24 | #include <sys/wait.h> | 
| Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 25 | #include <unistd.h> | 
| Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 26 | #include <memory> | 
| Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 27 |  | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 28 | #include "art_field-inl.h" | 
| Brian Carlstrom | 6449c62 | 2014-02-10 23:48:36 -0800 | [diff] [blame] | 29 | #include "base/stl_util.h" | 
| Elliott Hughes | 7616005 | 2012-12-12 16:31:20 -0800 | [diff] [blame] | 30 | #include "base/unix_file/fd_file.h" | 
| Ian Rogers | 4f6ad8a | 2013-03-18 15:27:28 -0700 | [diff] [blame] | 31 | #include "dex_file-inl.h" | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 32 | #include "mirror/art_method-inl.h" | 
| Ian Rogers | 4f6ad8a | 2013-03-18 15:27:28 -0700 | [diff] [blame] | 33 | #include "mirror/class-inl.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 34 | #include "mirror/class_loader.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 35 | #include "mirror/object-inl.h" | 
 | 36 | #include "mirror/object_array-inl.h" | 
 | 37 | #include "mirror/string.h" | 
| buzbee | c143c55 | 2011-08-20 17:38:58 -0700 | [diff] [blame] | 38 | #include "os.h" | 
| Kenny Root | 067d20f | 2014-03-05 14:57:21 -0800 | [diff] [blame] | 39 | #include "scoped_thread_state_change.h" | 
| Ian Rogers | a672490 | 2013-09-23 09:23:37 -0700 | [diff] [blame] | 40 | #include "utf-inl.h" | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 41 |  | 
| Elliott Hughes | 4ae722a | 2012-03-13 11:08:51 -0700 | [diff] [blame] | 42 | #if defined(__APPLE__) | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 43 | #include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED | 
| Elliott Hughes | f149843 | 2012-03-28 19:34:27 -0700 | [diff] [blame] | 44 | #include <sys/syscall.h> | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 45 | #include <sys/time.h> | 
| Elliott Hughes | 4ae722a | 2012-03-13 11:08:51 -0700 | [diff] [blame] | 46 | #endif | 
 | 47 |  | 
| Christopher Ferris | 7b5f0cf | 2013-11-01 15:18:45 -0700 | [diff] [blame] | 48 | #include <backtrace/Backtrace.h>  // For DumpNativeStack. | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 49 |  | 
| Elliott Hughes | 058a6de | 2012-05-24 19:13:02 -0700 | [diff] [blame] | 50 | #if defined(__linux__) | 
| Elliott Hughes | e1aee69 | 2012-01-17 16:40:10 -0800 | [diff] [blame] | 51 | #include <linux/unistd.h> | 
| Elliott Hughes | e1aee69 | 2012-01-17 16:40:10 -0800 | [diff] [blame] | 52 | #endif | 
 | 53 |  | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 54 | namespace art { | 
 | 55 |  | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 56 | #if defined(__linux__) | 
 | 57 | static constexpr bool kUseAddr2line = !kIsTargetBuild; | 
 | 58 | #endif | 
 | 59 |  | 
| Elliott Hughes | 11d1b0c | 2012-01-23 16:57:47 -0800 | [diff] [blame] | 60 | pid_t GetTid() { | 
| Brian Carlstrom | f3a2641 | 2012-08-24 11:06:02 -0700 | [diff] [blame] | 61 | #if defined(__APPLE__) | 
 | 62 |   uint64_t owner; | 
 | 63 |   CHECK_PTHREAD_CALL(pthread_threadid_np, (NULL, &owner), __FUNCTION__);  // Requires Mac OS 10.6 | 
 | 64 |   return owner; | 
| Elliott Hughes | 323aa86 | 2014-08-20 15:00:04 -0700 | [diff] [blame] | 65 | #elif defined(__BIONIC__) | 
 | 66 |   return gettid(); | 
| Elliott Hughes | 11d1b0c | 2012-01-23 16:57:47 -0800 | [diff] [blame] | 67 | #else | 
| Elliott Hughes | 11d1b0c | 2012-01-23 16:57:47 -0800 | [diff] [blame] | 68 |   return syscall(__NR_gettid); | 
 | 69 | #endif | 
 | 70 | } | 
 | 71 |  | 
| Elliott Hughes | 289be85 | 2012-06-12 13:57:20 -0700 | [diff] [blame] | 72 | std::string GetThreadName(pid_t tid) { | 
 | 73 |   std::string result; | 
 | 74 |   if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) { | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 75 |     result.resize(result.size() - 1);  // Lose the trailing '\n'. | 
| Elliott Hughes | 289be85 | 2012-06-12 13:57:20 -0700 | [diff] [blame] | 76 |   } else { | 
 | 77 |     result = "<unknown>"; | 
 | 78 |   } | 
 | 79 |   return result; | 
 | 80 | } | 
 | 81 |  | 
| Elliott Hughes | 6d3fc56 | 2014-08-27 11:47:01 -0700 | [diff] [blame] | 82 | void GetThreadStack(pthread_t thread, void** stack_base, size_t* stack_size, size_t* guard_size) { | 
| Elliott Hughes | e188419 | 2012-04-23 12:38:15 -0700 | [diff] [blame] | 83 | #if defined(__APPLE__) | 
| Brian Carlstrom | 2921201 | 2013-09-12 22:18:30 -0700 | [diff] [blame] | 84 |   *stack_size = pthread_get_stacksize_np(thread); | 
| Ian Rogers | 120f1c7 | 2012-09-28 17:17:10 -0700 | [diff] [blame] | 85 |   void* stack_addr = pthread_get_stackaddr_np(thread); | 
| Elliott Hughes | e188419 | 2012-04-23 12:38:15 -0700 | [diff] [blame] | 86 |  | 
 | 87 |   // Check whether stack_addr is the base or end of the stack. | 
 | 88 |   // (On Mac OS 10.7, it's the end.) | 
 | 89 |   int stack_variable; | 
 | 90 |   if (stack_addr > &stack_variable) { | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 91 |     *stack_base = reinterpret_cast<uint8_t*>(stack_addr) - *stack_size; | 
| Elliott Hughes | e188419 | 2012-04-23 12:38:15 -0700 | [diff] [blame] | 92 |   } else { | 
| Brian Carlstrom | 2921201 | 2013-09-12 22:18:30 -0700 | [diff] [blame] | 93 |     *stack_base = stack_addr; | 
| Elliott Hughes | e188419 | 2012-04-23 12:38:15 -0700 | [diff] [blame] | 94 |   } | 
| Elliott Hughes | 6d3fc56 | 2014-08-27 11:47:01 -0700 | [diff] [blame] | 95 |  | 
 | 96 |   // This is wrong, but there doesn't seem to be a way to get the actual value on the Mac. | 
 | 97 |   pthread_attr_t attributes; | 
 | 98 |   CHECK_PTHREAD_CALL(pthread_attr_init, (&attributes), __FUNCTION__); | 
 | 99 |   CHECK_PTHREAD_CALL(pthread_attr_getguardsize, (&attributes, guard_size), __FUNCTION__); | 
 | 100 |   CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), __FUNCTION__); | 
| Elliott Hughes | e188419 | 2012-04-23 12:38:15 -0700 | [diff] [blame] | 101 | #else | 
 | 102 |   pthread_attr_t attributes; | 
| Ian Rogers | 120f1c7 | 2012-09-28 17:17:10 -0700 | [diff] [blame] | 103 |   CHECK_PTHREAD_CALL(pthread_getattr_np, (thread, &attributes), __FUNCTION__); | 
| Brian Carlstrom | 2921201 | 2013-09-12 22:18:30 -0700 | [diff] [blame] | 104 |   CHECK_PTHREAD_CALL(pthread_attr_getstack, (&attributes, stack_base, stack_size), __FUNCTION__); | 
| Elliott Hughes | 6d3fc56 | 2014-08-27 11:47:01 -0700 | [diff] [blame] | 105 |   CHECK_PTHREAD_CALL(pthread_attr_getguardsize, (&attributes, guard_size), __FUNCTION__); | 
| Elliott Hughes | e188419 | 2012-04-23 12:38:15 -0700 | [diff] [blame] | 106 |   CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), __FUNCTION__); | 
| Elliott Hughes | 839cc30 | 2014-08-28 10:24:44 -0700 | [diff] [blame] | 107 |  | 
 | 108 | #if defined(__GLIBC__) | 
 | 109 |   // If we're the main thread, check whether we were run with an unlimited stack. In that case, | 
 | 110 |   // glibc will have reported a 2GB stack for our 32-bit process, and our stack overflow detection | 
 | 111 |   // will be broken because we'll die long before we get close to 2GB. | 
 | 112 |   bool is_main_thread = (::art::GetTid() == getpid()); | 
 | 113 |   if (is_main_thread) { | 
 | 114 |     rlimit stack_limit; | 
 | 115 |     if (getrlimit(RLIMIT_STACK, &stack_limit) == -1) { | 
 | 116 |       PLOG(FATAL) << "getrlimit(RLIMIT_STACK) failed"; | 
 | 117 |     } | 
 | 118 |     if (stack_limit.rlim_cur == RLIM_INFINITY) { | 
 | 119 |       size_t old_stack_size = *stack_size; | 
 | 120 |  | 
 | 121 |       // Use the kernel default limit as our size, and adjust the base to match. | 
 | 122 |       *stack_size = 8 * MB; | 
 | 123 |       *stack_base = reinterpret_cast<uint8_t*>(*stack_base) + (old_stack_size - *stack_size); | 
 | 124 |  | 
 | 125 |       VLOG(threads) << "Limiting unlimited stack (reported as " << PrettySize(old_stack_size) << ")" | 
 | 126 |                     << " to " << PrettySize(*stack_size) | 
 | 127 |                     << " with base " << *stack_base; | 
 | 128 |     } | 
 | 129 |   } | 
 | 130 | #endif | 
 | 131 |  | 
| Elliott Hughes | e188419 | 2012-04-23 12:38:15 -0700 | [diff] [blame] | 132 | #endif | 
 | 133 | } | 
 | 134 |  | 
| Elliott Hughes | d92bec4 | 2011-09-02 17:04:36 -0700 | [diff] [blame] | 135 | bool ReadFileToString(const std::string& file_name, std::string* result) { | 
| Andreas Gampe | a6dfdae | 2015-02-24 15:50:19 -0800 | [diff] [blame] | 136 |   File file; | 
 | 137 |   if (!file.Open(file_name, O_RDONLY)) { | 
| Elliott Hughes | d92bec4 | 2011-09-02 17:04:36 -0700 | [diff] [blame] | 138 |     return false; | 
 | 139 |   } | 
| buzbee | c143c55 | 2011-08-20 17:38:58 -0700 | [diff] [blame] | 140 |  | 
| Elliott Hughes | 3b6baaa | 2011-10-14 19:13:56 -0700 | [diff] [blame] | 141 |   std::vector<char> buf(8 * KB); | 
| buzbee | c143c55 | 2011-08-20 17:38:58 -0700 | [diff] [blame] | 142 |   while (true) { | 
| Andreas Gampe | a6dfdae | 2015-02-24 15:50:19 -0800 | [diff] [blame] | 143 |     int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[0], buf.size())); | 
| Elliott Hughes | d92bec4 | 2011-09-02 17:04:36 -0700 | [diff] [blame] | 144 |     if (n == -1) { | 
 | 145 |       return false; | 
| buzbee | c143c55 | 2011-08-20 17:38:58 -0700 | [diff] [blame] | 146 |     } | 
| Elliott Hughes | d92bec4 | 2011-09-02 17:04:36 -0700 | [diff] [blame] | 147 |     if (n == 0) { | 
 | 148 |       return true; | 
 | 149 |     } | 
| Elliott Hughes | 3b6baaa | 2011-10-14 19:13:56 -0700 | [diff] [blame] | 150 |     result->append(&buf[0], n); | 
| buzbee | c143c55 | 2011-08-20 17:38:58 -0700 | [diff] [blame] | 151 |   } | 
| buzbee | c143c55 | 2011-08-20 17:38:58 -0700 | [diff] [blame] | 152 | } | 
 | 153 |  | 
| Andreas Gampe | a6dfdae | 2015-02-24 15:50:19 -0800 | [diff] [blame] | 154 | bool PrintFileToLog(const std::string& file_name, LogSeverity level) { | 
 | 155 |   File file; | 
 | 156 |   if (!file.Open(file_name, O_RDONLY)) { | 
 | 157 |     return false; | 
 | 158 |   } | 
 | 159 |  | 
 | 160 |   constexpr size_t kBufSize = 256;  // Small buffer. Avoid stack overflow and stack size warnings. | 
 | 161 |   char buf[kBufSize + 1];           // +1 for terminator. | 
 | 162 |   size_t filled_to = 0; | 
 | 163 |   while (true) { | 
 | 164 |     DCHECK_LT(filled_to, kBufSize); | 
 | 165 |     int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[filled_to], kBufSize - filled_to)); | 
 | 166 |     if (n <= 0) { | 
 | 167 |       // Print the rest of the buffer, if it exists. | 
 | 168 |       if (filled_to > 0) { | 
 | 169 |         buf[filled_to] = 0; | 
 | 170 |         LOG(level) << buf; | 
 | 171 |       } | 
 | 172 |       return n == 0; | 
 | 173 |     } | 
 | 174 |     // Scan for '\n'. | 
 | 175 |     size_t i = filled_to; | 
 | 176 |     bool found_newline = false; | 
 | 177 |     for (; i < filled_to + n; ++i) { | 
 | 178 |       if (buf[i] == '\n') { | 
 | 179 |         // Found a line break, that's something to print now. | 
 | 180 |         buf[i] = 0; | 
 | 181 |         LOG(level) << buf; | 
 | 182 |         // Copy the rest to the front. | 
 | 183 |         if (i + 1 < filled_to + n) { | 
 | 184 |           memmove(&buf[0], &buf[i + 1], filled_to + n - i - 1); | 
 | 185 |           filled_to = filled_to + n - i - 1; | 
 | 186 |         } else { | 
 | 187 |           filled_to = 0; | 
 | 188 |         } | 
 | 189 |         found_newline = true; | 
 | 190 |         break; | 
 | 191 |       } | 
 | 192 |     } | 
 | 193 |     if (found_newline) { | 
 | 194 |       continue; | 
 | 195 |     } else { | 
 | 196 |       filled_to += n; | 
 | 197 |       // Check if we must flush now. | 
 | 198 |       if (filled_to == kBufSize) { | 
 | 199 |         buf[kBufSize] = 0; | 
 | 200 |         LOG(level) << buf; | 
 | 201 |         filled_to = 0; | 
 | 202 |       } | 
 | 203 |     } | 
 | 204 |   } | 
 | 205 | } | 
 | 206 |  | 
| Elliott Hughes | e27955c | 2011-08-26 15:21:24 -0700 | [diff] [blame] | 207 | std::string GetIsoDate() { | 
 | 208 |   time_t now = time(NULL); | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 209 |   tm tmbuf; | 
 | 210 |   tm* ptm = localtime_r(&now, &tmbuf); | 
| Elliott Hughes | e27955c | 2011-08-26 15:21:24 -0700 | [diff] [blame] | 211 |   return StringPrintf("%04d-%02d-%02d %02d:%02d:%02d", | 
 | 212 |       ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday, | 
 | 213 |       ptm->tm_hour, ptm->tm_min, ptm->tm_sec); | 
 | 214 | } | 
 | 215 |  | 
| Elliott Hughes | 7162ad9 | 2011-10-27 14:08:42 -0700 | [diff] [blame] | 216 | uint64_t MilliTime() { | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 217 | #if defined(__linux__) | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 218 |   timespec now; | 
| Elliott Hughes | 7162ad9 | 2011-10-27 14:08:42 -0700 | [diff] [blame] | 219 |   clock_gettime(CLOCK_MONOTONIC, &now); | 
| Ian Rogers | 0f67847 | 2014-03-10 16:18:37 -0700 | [diff] [blame] | 220 |   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000); | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 221 | #else  // __APPLE__ | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 222 |   timeval now; | 
| Elliott Hughes | ad6c9c3 | 2012-01-19 17:39:12 -0800 | [diff] [blame] | 223 |   gettimeofday(&now, NULL); | 
| Ian Rogers | 0f67847 | 2014-03-10 16:18:37 -0700 | [diff] [blame] | 224 |   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_usec / UINT64_C(1000); | 
| Elliott Hughes | ad6c9c3 | 2012-01-19 17:39:12 -0800 | [diff] [blame] | 225 | #endif | 
| Elliott Hughes | 7162ad9 | 2011-10-27 14:08:42 -0700 | [diff] [blame] | 226 | } | 
 | 227 |  | 
| jeffhao | a9ef3fd | 2011-12-13 18:33:43 -0800 | [diff] [blame] | 228 | uint64_t MicroTime() { | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 229 | #if defined(__linux__) | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 230 |   timespec now; | 
| jeffhao | a9ef3fd | 2011-12-13 18:33:43 -0800 | [diff] [blame] | 231 |   clock_gettime(CLOCK_MONOTONIC, &now); | 
| Ian Rogers | 0f67847 | 2014-03-10 16:18:37 -0700 | [diff] [blame] | 232 |   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000); | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 233 | #else  // __APPLE__ | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 234 |   timeval now; | 
| Elliott Hughes | ad6c9c3 | 2012-01-19 17:39:12 -0800 | [diff] [blame] | 235 |   gettimeofday(&now, NULL); | 
| Ian Rogers | 0f67847 | 2014-03-10 16:18:37 -0700 | [diff] [blame] | 236 |   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_usec; | 
| Elliott Hughes | ad6c9c3 | 2012-01-19 17:39:12 -0800 | [diff] [blame] | 237 | #endif | 
| jeffhao | a9ef3fd | 2011-12-13 18:33:43 -0800 | [diff] [blame] | 238 | } | 
 | 239 |  | 
| Elliott Hughes | 83df2ac | 2011-10-11 16:37:54 -0700 | [diff] [blame] | 240 | uint64_t NanoTime() { | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 241 | #if defined(__linux__) | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 242 |   timespec now; | 
| Elliott Hughes | 83df2ac | 2011-10-11 16:37:54 -0700 | [diff] [blame] | 243 |   clock_gettime(CLOCK_MONOTONIC, &now); | 
| Ian Rogers | 0f67847 | 2014-03-10 16:18:37 -0700 | [diff] [blame] | 244 |   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec; | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 245 | #else  // __APPLE__ | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 246 |   timeval now; | 
| Elliott Hughes | ad6c9c3 | 2012-01-19 17:39:12 -0800 | [diff] [blame] | 247 |   gettimeofday(&now, NULL); | 
| Ian Rogers | 0f67847 | 2014-03-10 16:18:37 -0700 | [diff] [blame] | 248 |   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_usec * UINT64_C(1000); | 
| Elliott Hughes | ad6c9c3 | 2012-01-19 17:39:12 -0800 | [diff] [blame] | 249 | #endif | 
| Elliott Hughes | 83df2ac | 2011-10-11 16:37:54 -0700 | [diff] [blame] | 250 | } | 
 | 251 |  | 
| Elliott Hughes | 0512f02 | 2012-03-15 22:10:52 -0700 | [diff] [blame] | 252 | uint64_t ThreadCpuNanoTime() { | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 253 | #if defined(__linux__) | 
| Elliott Hughes | 7b9d996 | 2012-04-20 18:48:18 -0700 | [diff] [blame] | 254 |   timespec now; | 
| Elliott Hughes | 0512f02 | 2012-03-15 22:10:52 -0700 | [diff] [blame] | 255 |   clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); | 
| Ian Rogers | 0f67847 | 2014-03-10 16:18:37 -0700 | [diff] [blame] | 256 |   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec; | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 257 | #else  // __APPLE__ | 
| Elliott Hughes | 0512f02 | 2012-03-15 22:10:52 -0700 | [diff] [blame] | 258 |   UNIMPLEMENTED(WARNING); | 
 | 259 |   return -1; | 
 | 260 | #endif | 
 | 261 | } | 
 | 262 |  | 
| Ian Rogers | 56edc43 | 2013-01-18 16:51:51 -0800 | [diff] [blame] | 263 | void NanoSleep(uint64_t ns) { | 
 | 264 |   timespec tm; | 
 | 265 |   tm.tv_sec = 0; | 
 | 266 |   tm.tv_nsec = ns; | 
 | 267 |   nanosleep(&tm, NULL); | 
 | 268 | } | 
 | 269 |  | 
| Brian Carlstrom | bcc2926 | 2012-11-02 11:36:03 -0700 | [diff] [blame] | 270 | void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts) { | 
 | 271 |   int64_t endSec; | 
 | 272 |  | 
 | 273 |   if (absolute) { | 
 | 274 | #if !defined(__APPLE__) | 
 | 275 |     clock_gettime(clock, ts); | 
 | 276 | #else | 
 | 277 |     UNUSED(clock); | 
 | 278 |     timeval tv; | 
 | 279 |     gettimeofday(&tv, NULL); | 
 | 280 |     ts->tv_sec = tv.tv_sec; | 
 | 281 |     ts->tv_nsec = tv.tv_usec * 1000; | 
 | 282 | #endif | 
 | 283 |   } else { | 
 | 284 |     ts->tv_sec = 0; | 
 | 285 |     ts->tv_nsec = 0; | 
 | 286 |   } | 
 | 287 |   endSec = ts->tv_sec + ms / 1000; | 
 | 288 |   if (UNLIKELY(endSec >= 0x7fffffff)) { | 
 | 289 |     std::ostringstream ss; | 
 | 290 |     LOG(INFO) << "Note: end time exceeds epoch: " << ss.str(); | 
 | 291 |     endSec = 0x7ffffffe; | 
 | 292 |   } | 
 | 293 |   ts->tv_sec = endSec; | 
 | 294 |   ts->tv_nsec = (ts->tv_nsec + (ms % 1000) * 1000000) + ns; | 
 | 295 |  | 
 | 296 |   // Catch rollover. | 
 | 297 |   if (ts->tv_nsec >= 1000000000L) { | 
 | 298 |     ts->tv_sec++; | 
 | 299 |     ts->tv_nsec -= 1000000000L; | 
 | 300 |   } | 
 | 301 | } | 
 | 302 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 303 | std::string PrettyDescriptor(mirror::String* java_descriptor) { | 
| Brian Carlstrom | e24fa61 | 2011-09-29 00:53:55 -0700 | [diff] [blame] | 304 |   if (java_descriptor == NULL) { | 
 | 305 |     return "null"; | 
 | 306 |   } | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 307 |   return PrettyDescriptor(java_descriptor->ToModifiedUtf8().c_str()); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 308 | } | 
| Elliott Hughes | 5174fe6 | 2011-08-23 15:12:35 -0700 | [diff] [blame] | 309 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 310 | std::string PrettyDescriptor(mirror::Class* klass) { | 
| Ian Rogers | 6d4d9fc | 2011-11-30 16:24:48 -0800 | [diff] [blame] | 311 |   if (klass == NULL) { | 
 | 312 |     return "null"; | 
 | 313 |   } | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 314 |   std::string temp; | 
 | 315 |   return PrettyDescriptor(klass->GetDescriptor(&temp)); | 
| Ian Rogers | 6d4d9fc | 2011-11-30 16:24:48 -0800 | [diff] [blame] | 316 | } | 
 | 317 |  | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 318 | std::string PrettyDescriptor(const char* descriptor) { | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 319 |   // Count the number of '['s to get the dimensionality. | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 320 |   const char* c = descriptor; | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 321 |   size_t dim = 0; | 
 | 322 |   while (*c == '[') { | 
 | 323 |     dim++; | 
 | 324 |     c++; | 
 | 325 |   } | 
 | 326 |  | 
 | 327 |   // Reference or primitive? | 
 | 328 |   if (*c == 'L') { | 
 | 329 |     // "[[La/b/C;" -> "a.b.C[][]". | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 330 |     c++;  // Skip the 'L'. | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 331 |   } else { | 
 | 332 |     // "[[B" -> "byte[][]". | 
 | 333 |     // To make life easier, we make primitives look like unqualified | 
 | 334 |     // reference types. | 
 | 335 |     switch (*c) { | 
 | 336 |     case 'B': c = "byte;"; break; | 
 | 337 |     case 'C': c = "char;"; break; | 
 | 338 |     case 'D': c = "double;"; break; | 
 | 339 |     case 'F': c = "float;"; break; | 
 | 340 |     case 'I': c = "int;"; break; | 
 | 341 |     case 'J': c = "long;"; break; | 
 | 342 |     case 'S': c = "short;"; break; | 
 | 343 |     case 'Z': c = "boolean;"; break; | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 344 |     case 'V': c = "void;"; break;  // Used when decoding return types. | 
| Elliott Hughes | 5174fe6 | 2011-08-23 15:12:35 -0700 | [diff] [blame] | 345 |     default: return descriptor; | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 346 |     } | 
 | 347 |   } | 
 | 348 |  | 
 | 349 |   // At this point, 'c' is a string of the form "fully/qualified/Type;" | 
 | 350 |   // or "primitive;". Rewrite the type with '.' instead of '/': | 
 | 351 |   std::string result; | 
 | 352 |   const char* p = c; | 
 | 353 |   while (*p != ';') { | 
 | 354 |     char ch = *p++; | 
 | 355 |     if (ch == '/') { | 
 | 356 |       ch = '.'; | 
 | 357 |     } | 
 | 358 |     result.push_back(ch); | 
 | 359 |   } | 
 | 360 |   // ...and replace the semicolon with 'dim' "[]" pairs: | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 361 |   for (size_t i = 0; i < dim; ++i) { | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 362 |     result += "[]"; | 
 | 363 |   } | 
 | 364 |   return result; | 
 | 365 | } | 
 | 366 |  | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 367 | std::string PrettyField(ArtField* f, bool with_type) { | 
| Elliott Hughes | a250199 | 2011-08-26 19:39:54 -0700 | [diff] [blame] | 368 |   if (f == NULL) { | 
 | 369 |     return "null"; | 
 | 370 |   } | 
| Elliott Hughes | 54e7df1 | 2011-09-16 11:47:04 -0700 | [diff] [blame] | 371 |   std::string result; | 
 | 372 |   if (with_type) { | 
| Mathieu Chartier | 61c5ebc | 2014-06-05 17:42:53 -0700 | [diff] [blame] | 373 |     result += PrettyDescriptor(f->GetTypeDescriptor()); | 
| Elliott Hughes | 54e7df1 | 2011-09-16 11:47:04 -0700 | [diff] [blame] | 374 |     result += ' '; | 
 | 375 |   } | 
| Ian Rogers | 08f1f50 | 2014-12-02 15:04:37 -0800 | [diff] [blame] | 376 |   std::string temp; | 
 | 377 |   result += PrettyDescriptor(f->GetDeclaringClass()->GetDescriptor(&temp)); | 
| Elliott Hughes | a250199 | 2011-08-26 19:39:54 -0700 | [diff] [blame] | 378 |   result += '.'; | 
| Mathieu Chartier | 61c5ebc | 2014-06-05 17:42:53 -0700 | [diff] [blame] | 379 |   result += f->GetName(); | 
| Elliott Hughes | a250199 | 2011-08-26 19:39:54 -0700 | [diff] [blame] | 380 |   return result; | 
 | 381 | } | 
 | 382 |  | 
| Brian Carlstrom | 6f29d0e | 2012-05-11 15:50:29 -0700 | [diff] [blame] | 383 | std::string PrettyField(uint32_t field_idx, const DexFile& dex_file, bool with_type) { | 
| Elliott Hughes | 60641a7 | 2013-02-27 14:36:16 -0800 | [diff] [blame] | 384 |   if (field_idx >= dex_file.NumFieldIds()) { | 
 | 385 |     return StringPrintf("<<invalid-field-idx-%d>>", field_idx); | 
 | 386 |   } | 
| Brian Carlstrom | 6f29d0e | 2012-05-11 15:50:29 -0700 | [diff] [blame] | 387 |   const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); | 
 | 388 |   std::string result; | 
 | 389 |   if (with_type) { | 
 | 390 |     result += dex_file.GetFieldTypeDescriptor(field_id); | 
 | 391 |     result += ' '; | 
 | 392 |   } | 
 | 393 |   result += PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(field_id)); | 
 | 394 |   result += '.'; | 
 | 395 |   result += dex_file.GetFieldName(field_id); | 
 | 396 |   return result; | 
 | 397 | } | 
 | 398 |  | 
| Mathieu Chartier | 18c24b6 | 2012-09-10 08:54:25 -0700 | [diff] [blame] | 399 | std::string PrettyType(uint32_t type_idx, const DexFile& dex_file) { | 
| Elliott Hughes | 60641a7 | 2013-02-27 14:36:16 -0800 | [diff] [blame] | 400 |   if (type_idx >= dex_file.NumTypeIds()) { | 
 | 401 |     return StringPrintf("<<invalid-type-idx-%d>>", type_idx); | 
 | 402 |   } | 
| Mathieu Chartier | 18c24b6 | 2012-09-10 08:54:25 -0700 | [diff] [blame] | 403 |   const DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx); | 
| Mathieu Chartier | 4c70d77 | 2012-09-10 14:08:32 -0700 | [diff] [blame] | 404 |   return PrettyDescriptor(dex_file.GetTypeDescriptor(type_id)); | 
| Mathieu Chartier | 18c24b6 | 2012-09-10 08:54:25 -0700 | [diff] [blame] | 405 | } | 
 | 406 |  | 
| Elliott Hughes | 9058f2b | 2012-03-22 18:06:48 -0700 | [diff] [blame] | 407 | std::string PrettyArguments(const char* signature) { | 
 | 408 |   std::string result; | 
 | 409 |   result += '('; | 
 | 410 |   CHECK_EQ(*signature, '('); | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 411 |   ++signature;  // Skip the '('. | 
| Elliott Hughes | 9058f2b | 2012-03-22 18:06:48 -0700 | [diff] [blame] | 412 |   while (*signature != ')') { | 
 | 413 |     size_t argument_length = 0; | 
 | 414 |     while (signature[argument_length] == '[') { | 
 | 415 |       ++argument_length; | 
 | 416 |     } | 
 | 417 |     if (signature[argument_length] == 'L') { | 
 | 418 |       argument_length = (strchr(signature, ';') - signature + 1); | 
 | 419 |     } else { | 
 | 420 |       ++argument_length; | 
 | 421 |     } | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 422 |     { | 
 | 423 |       std::string argument_descriptor(signature, argument_length); | 
 | 424 |       result += PrettyDescriptor(argument_descriptor.c_str()); | 
 | 425 |     } | 
| Elliott Hughes | 9058f2b | 2012-03-22 18:06:48 -0700 | [diff] [blame] | 426 |     if (signature[argument_length] != ')') { | 
 | 427 |       result += ", "; | 
 | 428 |     } | 
 | 429 |     signature += argument_length; | 
 | 430 |   } | 
 | 431 |   CHECK_EQ(*signature, ')'); | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 432 |   ++signature;  // Skip the ')'. | 
| Elliott Hughes | 9058f2b | 2012-03-22 18:06:48 -0700 | [diff] [blame] | 433 |   result += ')'; | 
 | 434 |   return result; | 
 | 435 | } | 
 | 436 |  | 
 | 437 | std::string PrettyReturnType(const char* signature) { | 
 | 438 |   const char* return_type = strchr(signature, ')'); | 
 | 439 |   CHECK(return_type != NULL); | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 440 |   ++return_type;  // Skip ')'. | 
| Elliott Hughes | 9058f2b | 2012-03-22 18:06:48 -0700 | [diff] [blame] | 441 |   return PrettyDescriptor(return_type); | 
 | 442 | } | 
 | 443 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 444 | std::string PrettyMethod(mirror::ArtMethod* m, bool with_signature) { | 
| Ian Rogers | 16ce092 | 2014-01-10 14:59:36 -0800 | [diff] [blame] | 445 |   if (m == nullptr) { | 
| Elliott Hughes | a0b8feb | 2011-08-20 09:50:55 -0700 | [diff] [blame] | 446 |     return "null"; | 
 | 447 |   } | 
| Mathieu Chartier | bfd9a43 | 2014-05-21 17:43:44 -0700 | [diff] [blame] | 448 |   std::string result(PrettyDescriptor(m->GetDeclaringClassDescriptor())); | 
| Elliott Hughes | a0b8feb | 2011-08-20 09:50:55 -0700 | [diff] [blame] | 449 |   result += '.'; | 
| Mathieu Chartier | bfd9a43 | 2014-05-21 17:43:44 -0700 | [diff] [blame] | 450 |   result += m->GetName(); | 
| Ian Rogers | 16ce092 | 2014-01-10 14:59:36 -0800 | [diff] [blame] | 451 |   if (UNLIKELY(m->IsFastNative())) { | 
 | 452 |     result += "!"; | 
 | 453 |   } | 
| Elliott Hughes | a0b8feb | 2011-08-20 09:50:55 -0700 | [diff] [blame] | 454 |   if (with_signature) { | 
| Mathieu Chartier | bfd9a43 | 2014-05-21 17:43:44 -0700 | [diff] [blame] | 455 |     const Signature signature = m->GetSignature(); | 
| Ian Rogers | d91d6d6 | 2013-09-25 20:26:14 -0700 | [diff] [blame] | 456 |     std::string sig_as_string(signature.ToString()); | 
 | 457 |     if (signature == Signature::NoSignature()) { | 
 | 458 |       return result + sig_as_string; | 
| Elliott Hughes | f8c1193 | 2012-03-23 19:53:59 -0700 | [diff] [blame] | 459 |     } | 
| Ian Rogers | d91d6d6 | 2013-09-25 20:26:14 -0700 | [diff] [blame] | 460 |     result = PrettyReturnType(sig_as_string.c_str()) + " " + result + | 
 | 461 |         PrettyArguments(sig_as_string.c_str()); | 
| Elliott Hughes | a0b8feb | 2011-08-20 09:50:55 -0700 | [diff] [blame] | 462 |   } | 
 | 463 |   return result; | 
 | 464 | } | 
 | 465 |  | 
| Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 466 | std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with_signature) { | 
| Elliott Hughes | 60641a7 | 2013-02-27 14:36:16 -0800 | [diff] [blame] | 467 |   if (method_idx >= dex_file.NumMethodIds()) { | 
 | 468 |     return StringPrintf("<<invalid-method-idx-%d>>", method_idx); | 
 | 469 |   } | 
| Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 470 |   const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); | 
 | 471 |   std::string result(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(method_id))); | 
 | 472 |   result += '.'; | 
 | 473 |   result += dex_file.GetMethodName(method_id); | 
 | 474 |   if (with_signature) { | 
| Ian Rogers | d91d6d6 | 2013-09-25 20:26:14 -0700 | [diff] [blame] | 475 |     const Signature signature = dex_file.GetMethodSignature(method_id); | 
 | 476 |     std::string sig_as_string(signature.ToString()); | 
 | 477 |     if (signature == Signature::NoSignature()) { | 
 | 478 |       return result + sig_as_string; | 
| Elliott Hughes | f8c1193 | 2012-03-23 19:53:59 -0700 | [diff] [blame] | 479 |     } | 
| Ian Rogers | d91d6d6 | 2013-09-25 20:26:14 -0700 | [diff] [blame] | 480 |     result = PrettyReturnType(sig_as_string.c_str()) + " " + result + | 
 | 481 |         PrettyArguments(sig_as_string.c_str()); | 
| Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 482 |   } | 
 | 483 |   return result; | 
 | 484 | } | 
 | 485 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 486 | std::string PrettyTypeOf(mirror::Object* obj) { | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 487 |   if (obj == NULL) { | 
 | 488 |     return "null"; | 
 | 489 |   } | 
 | 490 |   if (obj->GetClass() == NULL) { | 
 | 491 |     return "(raw)"; | 
 | 492 |   } | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 493 |   std::string temp; | 
 | 494 |   std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor(&temp))); | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 495 |   if (obj->IsClass()) { | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 496 |     result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor(&temp)) + ">"; | 
| Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 497 |   } | 
 | 498 |   return result; | 
 | 499 | } | 
 | 500 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 501 | std::string PrettyClass(mirror::Class* c) { | 
| Elliott Hughes | 54e7df1 | 2011-09-16 11:47:04 -0700 | [diff] [blame] | 502 |   if (c == NULL) { | 
 | 503 |     return "null"; | 
 | 504 |   } | 
 | 505 |   std::string result; | 
 | 506 |   result += "java.lang.Class<"; | 
| Ian Rogers | 6d4d9fc | 2011-11-30 16:24:48 -0800 | [diff] [blame] | 507 |   result += PrettyDescriptor(c); | 
| Elliott Hughes | 54e7df1 | 2011-09-16 11:47:04 -0700 | [diff] [blame] | 508 |   result += ">"; | 
 | 509 |   return result; | 
 | 510 | } | 
 | 511 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 512 | std::string PrettyClassAndClassLoader(mirror::Class* c) { | 
| Ian Rogers | d81871c | 2011-10-03 13:57:23 -0700 | [diff] [blame] | 513 |   if (c == NULL) { | 
 | 514 |     return "null"; | 
 | 515 |   } | 
 | 516 |   std::string result; | 
 | 517 |   result += "java.lang.Class<"; | 
| Ian Rogers | 6d4d9fc | 2011-11-30 16:24:48 -0800 | [diff] [blame] | 518 |   result += PrettyDescriptor(c); | 
| Ian Rogers | d81871c | 2011-10-03 13:57:23 -0700 | [diff] [blame] | 519 |   result += ","; | 
 | 520 |   result += PrettyTypeOf(c->GetClassLoader()); | 
 | 521 |   // TODO: add an identifying hash value for the loader | 
 | 522 |   result += ">"; | 
 | 523 |   return result; | 
 | 524 | } | 
 | 525 |  | 
| Andreas Gampe | c0d8229 | 2014-09-23 10:38:30 -0700 | [diff] [blame] | 526 | std::string PrettyJavaAccessFlags(uint32_t access_flags) { | 
 | 527 |   std::string result; | 
 | 528 |   if ((access_flags & kAccPublic) != 0) { | 
 | 529 |     result += "public "; | 
 | 530 |   } | 
 | 531 |   if ((access_flags & kAccProtected) != 0) { | 
 | 532 |     result += "protected "; | 
 | 533 |   } | 
 | 534 |   if ((access_flags & kAccPrivate) != 0) { | 
 | 535 |     result += "private "; | 
 | 536 |   } | 
 | 537 |   if ((access_flags & kAccFinal) != 0) { | 
 | 538 |     result += "final "; | 
 | 539 |   } | 
 | 540 |   if ((access_flags & kAccStatic) != 0) { | 
 | 541 |     result += "static "; | 
 | 542 |   } | 
 | 543 |   if ((access_flags & kAccTransient) != 0) { | 
 | 544 |     result += "transient "; | 
 | 545 |   } | 
 | 546 |   if ((access_flags & kAccVolatile) != 0) { | 
 | 547 |     result += "volatile "; | 
 | 548 |   } | 
 | 549 |   if ((access_flags & kAccSynchronized) != 0) { | 
 | 550 |     result += "synchronized "; | 
 | 551 |   } | 
 | 552 |   return result; | 
 | 553 | } | 
 | 554 |  | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 555 | std::string PrettySize(int64_t byte_count) { | 
| Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 556 |   // The byte thresholds at which we display amounts.  A byte count is displayed | 
 | 557 |   // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1]. | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 558 |   static const int64_t kUnitThresholds[] = { | 
| Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 559 |     0,              // B up to... | 
 | 560 |     3*1024,         // KB up to... | 
 | 561 |     2*1024*1024,    // MB up to... | 
 | 562 |     1024*1024*1024  // GB from here. | 
 | 563 |   }; | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 564 |   static const int64_t kBytesPerUnit[] = { 1, KB, MB, GB }; | 
| Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 565 |   static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" }; | 
| Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 566 |   const char* negative_str = ""; | 
 | 567 |   if (byte_count < 0) { | 
 | 568 |     negative_str = "-"; | 
 | 569 |     byte_count = -byte_count; | 
 | 570 |   } | 
| Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 571 |   int i = arraysize(kUnitThresholds); | 
 | 572 |   while (--i > 0) { | 
 | 573 |     if (byte_count >= kUnitThresholds[i]) { | 
 | 574 |       break; | 
 | 575 |     } | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 576 |   } | 
| Brian Carlstrom | 474cc79 | 2014-03-07 14:18:15 -0800 | [diff] [blame] | 577 |   return StringPrintf("%s%" PRId64 "%s", | 
 | 578 |                       negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]); | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 579 | } | 
 | 580 |  | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 581 | std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) { | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 582 |   if (nano_duration == 0) { | 
 | 583 |     return "0"; | 
 | 584 |   } else { | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 585 |     return FormatDuration(nano_duration, GetAppropriateTimeUnit(nano_duration), | 
 | 586 |                           max_fraction_digits); | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 587 |   } | 
 | 588 | } | 
 | 589 |  | 
 | 590 | TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration) { | 
 | 591 |   const uint64_t one_sec = 1000 * 1000 * 1000; | 
 | 592 |   const uint64_t one_ms  = 1000 * 1000; | 
 | 593 |   const uint64_t one_us  = 1000; | 
 | 594 |   if (nano_duration >= one_sec) { | 
 | 595 |     return kTimeUnitSecond; | 
 | 596 |   } else if (nano_duration >= one_ms) { | 
 | 597 |     return kTimeUnitMillisecond; | 
 | 598 |   } else if (nano_duration >= one_us) { | 
 | 599 |     return kTimeUnitMicrosecond; | 
 | 600 |   } else { | 
 | 601 |     return kTimeUnitNanosecond; | 
 | 602 |   } | 
 | 603 | } | 
 | 604 |  | 
 | 605 | uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit) { | 
 | 606 |   const uint64_t one_sec = 1000 * 1000 * 1000; | 
 | 607 |   const uint64_t one_ms  = 1000 * 1000; | 
 | 608 |   const uint64_t one_us  = 1000; | 
 | 609 |  | 
 | 610 |   switch (time_unit) { | 
 | 611 |     case kTimeUnitSecond: | 
 | 612 |       return one_sec; | 
 | 613 |     case kTimeUnitMillisecond: | 
 | 614 |       return one_ms; | 
 | 615 |     case kTimeUnitMicrosecond: | 
 | 616 |       return one_us; | 
 | 617 |     case kTimeUnitNanosecond: | 
 | 618 |       return 1; | 
 | 619 |   } | 
 | 620 |   return 0; | 
 | 621 | } | 
 | 622 |  | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 623 | std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit, | 
 | 624 |                            size_t max_fraction_digits) { | 
 | 625 |   const char* unit = nullptr; | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 626 |   uint64_t divisor = GetNsToTimeUnitDivisor(time_unit); | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 627 |   switch (time_unit) { | 
 | 628 |     case kTimeUnitSecond: | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 629 |       unit = "s"; | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 630 |       break; | 
 | 631 |     case kTimeUnitMillisecond: | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 632 |       unit = "ms"; | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 633 |       break; | 
 | 634 |     case kTimeUnitMicrosecond: | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 635 |       unit = "us"; | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 636 |       break; | 
 | 637 |     case kTimeUnitNanosecond: | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 638 |       unit = "ns"; | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 639 |       break; | 
 | 640 |   } | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 641 |   const uint64_t whole_part = nano_duration / divisor; | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 642 |   uint64_t fractional_part = nano_duration % divisor; | 
 | 643 |   if (fractional_part == 0) { | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 644 |     return StringPrintf("%" PRIu64 "%s", whole_part, unit); | 
| Mathieu Chartier | 0325e62 | 2012-09-05 14:22:51 -0700 | [diff] [blame] | 645 |   } else { | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 646 |     static constexpr size_t kMaxDigits = 30; | 
| Andreas Gampe | 829b4ba | 2014-06-26 13:49:36 -0700 | [diff] [blame] | 647 |     size_t avail_digits = kMaxDigits; | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 648 |     char fraction_buffer[kMaxDigits]; | 
 | 649 |     char* ptr = fraction_buffer; | 
 | 650 |     uint64_t multiplier = 10; | 
 | 651 |     // This infinite loops if fractional part is 0. | 
| Andreas Gampe | 829b4ba | 2014-06-26 13:49:36 -0700 | [diff] [blame] | 652 |     while (avail_digits > 1 && fractional_part * multiplier < divisor) { | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 653 |       multiplier *= 10; | 
 | 654 |       *ptr++ = '0'; | 
| Andreas Gampe | 829b4ba | 2014-06-26 13:49:36 -0700 | [diff] [blame] | 655 |       avail_digits--; | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 656 |     } | 
| Andreas Gampe | 829b4ba | 2014-06-26 13:49:36 -0700 | [diff] [blame] | 657 |     snprintf(ptr, avail_digits, "%" PRIu64, fractional_part); | 
| Mathieu Chartier | f5997b4 | 2014-06-20 10:37:54 -0700 | [diff] [blame] | 658 |     fraction_buffer[std::min(kMaxDigits - 1, max_fraction_digits)] = '\0'; | 
 | 659 |     return StringPrintf("%" PRIu64 ".%s%s", whole_part, fraction_buffer, unit); | 
| Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 660 |   } | 
 | 661 | } | 
 | 662 |  | 
| Ian Rogers | 576ca0c | 2014-06-06 15:58:22 -0700 | [diff] [blame] | 663 | std::string PrintableChar(uint16_t ch) { | 
 | 664 |   std::string result; | 
 | 665 |   result += '\''; | 
 | 666 |   if (NeedsEscaping(ch)) { | 
 | 667 |     StringAppendF(&result, "\\u%04x", ch); | 
 | 668 |   } else { | 
 | 669 |     result += ch; | 
 | 670 |   } | 
 | 671 |   result += '\''; | 
 | 672 |   return result; | 
 | 673 | } | 
 | 674 |  | 
| Ian Rogers | 68b5685 | 2014-08-29 20:19:11 -0700 | [diff] [blame] | 675 | std::string PrintableString(const char* utf) { | 
| Elliott Hughes | 82914b6 | 2012-04-09 15:56:29 -0700 | [diff] [blame] | 676 |   std::string result; | 
 | 677 |   result += '"'; | 
| Ian Rogers | 68b5685 | 2014-08-29 20:19:11 -0700 | [diff] [blame] | 678 |   const char* p = utf; | 
| Elliott Hughes | 82914b6 | 2012-04-09 15:56:29 -0700 | [diff] [blame] | 679 |   size_t char_count = CountModifiedUtf8Chars(p); | 
 | 680 |   for (size_t i = 0; i < char_count; ++i) { | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 681 |     uint32_t ch = GetUtf16FromUtf8(&p); | 
| Elliott Hughes | 82914b6 | 2012-04-09 15:56:29 -0700 | [diff] [blame] | 682 |     if (ch == '\\') { | 
 | 683 |       result += "\\\\"; | 
 | 684 |     } else if (ch == '\n') { | 
 | 685 |       result += "\\n"; | 
 | 686 |     } else if (ch == '\r') { | 
 | 687 |       result += "\\r"; | 
 | 688 |     } else if (ch == '\t') { | 
 | 689 |       result += "\\t"; | 
| Elliott Hughes | 82914b6 | 2012-04-09 15:56:29 -0700 | [diff] [blame] | 690 |     } else { | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 691 |       const uint16_t leading = GetLeadingUtf16Char(ch); | 
 | 692 |  | 
 | 693 |       if (NeedsEscaping(leading)) { | 
 | 694 |         StringAppendF(&result, "\\u%04x", leading); | 
 | 695 |       } else { | 
 | 696 |         result += leading; | 
 | 697 |       } | 
 | 698 |  | 
 | 699 |       const uint32_t trailing = GetTrailingUtf16Char(ch); | 
 | 700 |       if (trailing != 0) { | 
 | 701 |         // All high surrogates will need escaping. | 
 | 702 |         StringAppendF(&result, "\\u%04x", trailing); | 
 | 703 |       } | 
| Elliott Hughes | 82914b6 | 2012-04-09 15:56:29 -0700 | [diff] [blame] | 704 |     } | 
 | 705 |   } | 
 | 706 |   result += '"'; | 
 | 707 |   return result; | 
 | 708 | } | 
 | 709 |  | 
| Elliott Hughes | d8c00d0 | 2012-01-30 14:08:31 -0800 | [diff] [blame] | 710 | // See http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/design.html#wp615 for the full rules. | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 711 | std::string MangleForJni(const std::string& s) { | 
 | 712 |   std::string result; | 
 | 713 |   size_t char_count = CountModifiedUtf8Chars(s.c_str()); | 
 | 714 |   const char* cp = &s[0]; | 
 | 715 |   for (size_t i = 0; i < char_count; ++i) { | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 716 |     uint32_t ch = GetUtf16FromUtf8(&cp); | 
| Elliott Hughes | d8c00d0 | 2012-01-30 14:08:31 -0800 | [diff] [blame] | 717 |     if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) { | 
 | 718 |       result.push_back(ch); | 
 | 719 |     } else if (ch == '.' || ch == '/') { | 
 | 720 |       result += "_"; | 
 | 721 |     } else if (ch == '_') { | 
 | 722 |       result += "_1"; | 
 | 723 |     } else if (ch == ';') { | 
 | 724 |       result += "_2"; | 
 | 725 |     } else if (ch == '[') { | 
 | 726 |       result += "_3"; | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 727 |     } else { | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 728 |       const uint16_t leading = GetLeadingUtf16Char(ch); | 
 | 729 |       const uint32_t trailing = GetTrailingUtf16Char(ch); | 
 | 730 |  | 
 | 731 |       StringAppendF(&result, "_0%04x", leading); | 
 | 732 |       if (trailing != 0) { | 
 | 733 |         StringAppendF(&result, "_0%04x", trailing); | 
 | 734 |       } | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 735 |     } | 
 | 736 |   } | 
 | 737 |   return result; | 
 | 738 | } | 
 | 739 |  | 
| Brian Carlstrom | f91c8c3 | 2011-09-21 17:30:34 -0700 | [diff] [blame] | 740 | std::string DotToDescriptor(const char* class_name) { | 
 | 741 |   std::string descriptor(class_name); | 
 | 742 |   std::replace(descriptor.begin(), descriptor.end(), '.', '/'); | 
 | 743 |   if (descriptor.length() > 0 && descriptor[0] != '[') { | 
 | 744 |     descriptor = "L" + descriptor + ";"; | 
 | 745 |   } | 
 | 746 |   return descriptor; | 
 | 747 | } | 
 | 748 |  | 
| Elliott Hughes | f1a5adc | 2012-02-10 18:09:35 -0800 | [diff] [blame] | 749 | std::string DescriptorToDot(const char* descriptor) { | 
| Elliott Hughes | 2435a57 | 2012-02-17 16:07:41 -0800 | [diff] [blame] | 750 |   size_t length = strlen(descriptor); | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 751 |   if (length > 1) { | 
 | 752 |     if (descriptor[0] == 'L' && descriptor[length - 1] == ';') { | 
 | 753 |       // Descriptors have the leading 'L' and trailing ';' stripped. | 
 | 754 |       std::string result(descriptor + 1, length - 2); | 
 | 755 |       std::replace(result.begin(), result.end(), '/', '.'); | 
 | 756 |       return result; | 
 | 757 |     } else { | 
 | 758 |       // For arrays the 'L' and ';' remain intact. | 
 | 759 |       std::string result(descriptor); | 
 | 760 |       std::replace(result.begin(), result.end(), '/', '.'); | 
 | 761 |       return result; | 
 | 762 |     } | 
| Elliott Hughes | 2435a57 | 2012-02-17 16:07:41 -0800 | [diff] [blame] | 763 |   } | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 764 |   // Do nothing for non-class/array descriptors. | 
| Elliott Hughes | 2435a57 | 2012-02-17 16:07:41 -0800 | [diff] [blame] | 765 |   return descriptor; | 
| Elliott Hughes | 91bf6cd | 2012-02-14 17:27:48 -0800 | [diff] [blame] | 766 | } | 
 | 767 |  | 
 | 768 | std::string DescriptorToName(const char* descriptor) { | 
| Elliott Hughes | f1a5adc | 2012-02-10 18:09:35 -0800 | [diff] [blame] | 769 |   size_t length = strlen(descriptor); | 
| Elliott Hughes | 2435a57 | 2012-02-17 16:07:41 -0800 | [diff] [blame] | 770 |   if (descriptor[0] == 'L' && descriptor[length - 1] == ';') { | 
 | 771 |     std::string result(descriptor + 1, length - 2); | 
 | 772 |     return result; | 
 | 773 |   } | 
 | 774 |   return descriptor; | 
| Brian Carlstrom | aded5f7 | 2011-10-07 17:15:04 -0700 | [diff] [blame] | 775 | } | 
 | 776 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 777 | std::string JniShortName(mirror::ArtMethod* m) { | 
| Mathieu Chartier | bfd9a43 | 2014-05-21 17:43:44 -0700 | [diff] [blame] | 778 |   std::string class_name(m->GetDeclaringClassDescriptor()); | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 779 |   // Remove the leading 'L' and trailing ';'... | 
| Elliott Hughes | f5a7a47 | 2011-10-07 14:31:02 -0700 | [diff] [blame] | 780 |   CHECK_EQ(class_name[0], 'L') << class_name; | 
 | 781 |   CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name; | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 782 |   class_name.erase(0, 1); | 
 | 783 |   class_name.erase(class_name.size() - 1, 1); | 
 | 784 |  | 
| Mathieu Chartier | bfd9a43 | 2014-05-21 17:43:44 -0700 | [diff] [blame] | 785 |   std::string method_name(m->GetName()); | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 786 |  | 
 | 787 |   std::string short_name; | 
 | 788 |   short_name += "Java_"; | 
 | 789 |   short_name += MangleForJni(class_name); | 
 | 790 |   short_name += "_"; | 
 | 791 |   short_name += MangleForJni(method_name); | 
 | 792 |   return short_name; | 
 | 793 | } | 
 | 794 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 795 | std::string JniLongName(mirror::ArtMethod* m) { | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 796 |   std::string long_name; | 
 | 797 |   long_name += JniShortName(m); | 
 | 798 |   long_name += "__"; | 
 | 799 |  | 
| Mathieu Chartier | bfd9a43 | 2014-05-21 17:43:44 -0700 | [diff] [blame] | 800 |   std::string signature(m->GetSignature().ToString()); | 
| Elliott Hughes | 79082e3 | 2011-08-25 12:07:32 -0700 | [diff] [blame] | 801 |   signature.erase(0, 1); | 
 | 802 |   signature.erase(signature.begin() + signature.find(')'), signature.end()); | 
 | 803 |  | 
 | 804 |   long_name += MangleForJni(signature); | 
 | 805 |  | 
 | 806 |   return long_name; | 
 | 807 | } | 
 | 808 |  | 
| jeffhao | 10037c8 | 2012-01-23 15:06:23 -0800 | [diff] [blame] | 809 | // Helper for IsValidPartOfMemberNameUtf8(), a bit vector indicating valid low ascii. | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 810 | uint32_t DEX_MEMBER_VALID_LOW_ASCII[4] = { | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 811 |   0x00000000,  // 00..1f low control characters; nothing valid | 
 | 812 |   0x03ff2010,  // 20..3f digits and symbols; valid: '0'..'9', '$', '-' | 
 | 813 |   0x87fffffe,  // 40..5f uppercase etc.; valid: 'A'..'Z', '_' | 
 | 814 |   0x07fffffe   // 60..7f lowercase etc.; valid: 'a'..'z' | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 815 | }; | 
 | 816 |  | 
| jeffhao | 10037c8 | 2012-01-23 15:06:23 -0800 | [diff] [blame] | 817 | // Helper for IsValidPartOfMemberNameUtf8(); do not call directly. | 
 | 818 | bool IsValidPartOfMemberNameUtf8Slow(const char** pUtf8Ptr) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 819 |   /* | 
 | 820 |    * It's a multibyte encoded character. Decode it and analyze. We | 
 | 821 |    * accept anything that isn't (a) an improperly encoded low value, | 
 | 822 |    * (b) an improper surrogate pair, (c) an encoded '\0', (d) a high | 
 | 823 |    * control character, or (e) a high space, layout, or special | 
 | 824 |    * character (U+00a0, U+2000..U+200f, U+2028..U+202f, | 
 | 825 |    * U+fff0..U+ffff). This is all specified in the dex format | 
 | 826 |    * document. | 
 | 827 |    */ | 
 | 828 |  | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 829 |   const uint32_t pair = GetUtf16FromUtf8(pUtf8Ptr); | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 830 |  | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 831 |   const uint16_t leading = GetLeadingUtf16Char(pair); | 
 | 832 |   const uint32_t trailing = GetTrailingUtf16Char(pair); | 
 | 833 |  | 
 | 834 |   if (trailing == 0) { | 
 | 835 |     // Perform follow-up tests based on the high 8 bits of the | 
 | 836 |     // lower surrogate. | 
 | 837 |     switch (leading >> 8) { | 
 | 838 |     case 0x00: | 
 | 839 |       // It's only valid if it's above the ISO-8859-1 high space (0xa0). | 
 | 840 |       return (leading > 0x00a0); | 
 | 841 |     case 0xd8: | 
 | 842 |     case 0xd9: | 
 | 843 |     case 0xda: | 
 | 844 |     case 0xdb: | 
 | 845 |       // It looks like a leading surrogate but we didn't find a trailing | 
 | 846 |       // surrogate if we're here. | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 847 |       return false; | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 848 |     case 0xdc: | 
 | 849 |     case 0xdd: | 
 | 850 |     case 0xde: | 
 | 851 |     case 0xdf: | 
 | 852 |       // It's a trailing surrogate, which is not valid at this point. | 
 | 853 |       return false; | 
 | 854 |     case 0x20: | 
 | 855 |     case 0xff: | 
 | 856 |       // It's in the range that has spaces, controls, and specials. | 
 | 857 |       switch (leading & 0xfff8) { | 
 | 858 |       case 0x2000: | 
 | 859 |       case 0x2008: | 
 | 860 |       case 0x2028: | 
 | 861 |       case 0xfff0: | 
 | 862 |       case 0xfff8: | 
 | 863 |         return false; | 
 | 864 |       } | 
 | 865 |       break; | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 866 |     } | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 867 |  | 
 | 868 |     return true; | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 869 |   } | 
| Narayan Kamath | a5afcfc | 2015-01-29 20:06:46 +0000 | [diff] [blame] | 870 |  | 
 | 871 |   // We have a surrogate pair. Check that trailing surrogate is well formed. | 
 | 872 |   return (trailing >= 0xdc00 && trailing <= 0xdfff); | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 873 | } | 
 | 874 |  | 
 | 875 | /* Return whether the pointed-at modified-UTF-8 encoded character is | 
 | 876 |  * valid as part of a member name, updating the pointer to point past | 
 | 877 |  * the consumed character. This will consume two encoded UTF-16 code | 
 | 878 |  * points if the character is encoded as a surrogate pair. Also, if | 
 | 879 |  * this function returns false, then the given pointer may only have | 
 | 880 |  * been partially advanced. | 
 | 881 |  */ | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 882 | static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 883 |   uint8_t c = (uint8_t) **pUtf8Ptr; | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 884 |   if (LIKELY(c <= 0x7f)) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 885 |     // It's low-ascii, so check the table. | 
 | 886 |     uint32_t wordIdx = c >> 5; | 
 | 887 |     uint32_t bitIdx = c & 0x1f; | 
 | 888 |     (*pUtf8Ptr)++; | 
 | 889 |     return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0; | 
 | 890 |   } | 
 | 891 |  | 
 | 892 |   // It's a multibyte encoded character. Call a non-inline function | 
 | 893 |   // for the heavy lifting. | 
| jeffhao | 10037c8 | 2012-01-23 15:06:23 -0800 | [diff] [blame] | 894 |   return IsValidPartOfMemberNameUtf8Slow(pUtf8Ptr); | 
 | 895 | } | 
 | 896 |  | 
 | 897 | bool IsValidMemberName(const char* s) { | 
 | 898 |   bool angle_name = false; | 
 | 899 |  | 
| Elliott Hughes | b25c3f6 | 2012-03-26 16:35:06 -0700 | [diff] [blame] | 900 |   switch (*s) { | 
| jeffhao | 10037c8 | 2012-01-23 15:06:23 -0800 | [diff] [blame] | 901 |     case '\0': | 
 | 902 |       // The empty string is not a valid name. | 
 | 903 |       return false; | 
 | 904 |     case '<': | 
 | 905 |       angle_name = true; | 
 | 906 |       s++; | 
 | 907 |       break; | 
 | 908 |   } | 
 | 909 |  | 
 | 910 |   while (true) { | 
 | 911 |     switch (*s) { | 
 | 912 |       case '\0': | 
 | 913 |         return !angle_name; | 
 | 914 |       case '>': | 
 | 915 |         return angle_name && s[1] == '\0'; | 
 | 916 |     } | 
 | 917 |  | 
 | 918 |     if (!IsValidPartOfMemberNameUtf8(&s)) { | 
 | 919 |       return false; | 
 | 920 |     } | 
 | 921 |   } | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 922 | } | 
 | 923 |  | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 924 | enum ClassNameType { kName, kDescriptor }; | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 925 | template<ClassNameType kType, char kSeparator> | 
 | 926 | static bool IsValidClassName(const char* s) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 927 |   int arrayCount = 0; | 
 | 928 |   while (*s == '[') { | 
 | 929 |     arrayCount++; | 
 | 930 |     s++; | 
 | 931 |   } | 
 | 932 |  | 
 | 933 |   if (arrayCount > 255) { | 
 | 934 |     // Arrays may have no more than 255 dimensions. | 
 | 935 |     return false; | 
 | 936 |   } | 
 | 937 |  | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 938 |   ClassNameType type = kType; | 
 | 939 |   if (type != kDescriptor && arrayCount != 0) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 940 |     /* | 
 | 941 |      * If we're looking at an array of some sort, then it doesn't | 
 | 942 |      * matter if what is being asked for is a class name; the | 
 | 943 |      * format looks the same as a type descriptor in that case, so | 
 | 944 |      * treat it as such. | 
 | 945 |      */ | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 946 |     type = kDescriptor; | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 947 |   } | 
 | 948 |  | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 949 |   if (type == kDescriptor) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 950 |     /* | 
 | 951 |      * We are looking for a descriptor. Either validate it as a | 
 | 952 |      * single-character primitive type, or continue on to check the | 
 | 953 |      * embedded class name (bracketed by "L" and ";"). | 
 | 954 |      */ | 
 | 955 |     switch (*(s++)) { | 
 | 956 |     case 'B': | 
 | 957 |     case 'C': | 
 | 958 |     case 'D': | 
 | 959 |     case 'F': | 
 | 960 |     case 'I': | 
 | 961 |     case 'J': | 
 | 962 |     case 'S': | 
 | 963 |     case 'Z': | 
 | 964 |       // These are all single-character descriptors for primitive types. | 
 | 965 |       return (*s == '\0'); | 
 | 966 |     case 'V': | 
 | 967 |       // Non-array void is valid, but you can't have an array of void. | 
 | 968 |       return (arrayCount == 0) && (*s == '\0'); | 
 | 969 |     case 'L': | 
 | 970 |       // Class name: Break out and continue below. | 
 | 971 |       break; | 
 | 972 |     default: | 
 | 973 |       // Oddball descriptor character. | 
 | 974 |       return false; | 
 | 975 |     } | 
 | 976 |   } | 
 | 977 |  | 
 | 978 |   /* | 
 | 979 |    * We just consumed the 'L' that introduces a class name as part | 
 | 980 |    * of a type descriptor, or we are looking for an unadorned class | 
 | 981 |    * name. | 
 | 982 |    */ | 
 | 983 |  | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 984 |   bool sepOrFirst = true;  // first character or just encountered a separator. | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 985 |   for (;;) { | 
 | 986 |     uint8_t c = (uint8_t) *s; | 
 | 987 |     switch (c) { | 
 | 988 |     case '\0': | 
 | 989 |       /* | 
 | 990 |        * Premature end for a type descriptor, but valid for | 
 | 991 |        * a class name as long as we haven't encountered an | 
 | 992 |        * empty component (including the degenerate case of | 
 | 993 |        * the empty string ""). | 
 | 994 |        */ | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 995 |       return (type == kName) && !sepOrFirst; | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 996 |     case ';': | 
 | 997 |       /* | 
 | 998 |        * Invalid character for a class name, but the | 
 | 999 |        * legitimate end of a type descriptor. In the latter | 
 | 1000 |        * case, make sure that this is the end of the string | 
 | 1001 |        * and that it doesn't end with an empty component | 
 | 1002 |        * (including the degenerate case of "L;"). | 
 | 1003 |        */ | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 1004 |       return (type == kDescriptor) && !sepOrFirst && (s[1] == '\0'); | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 1005 |     case '/': | 
 | 1006 |     case '.': | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 1007 |       if (c != kSeparator) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 1008 |         // The wrong separator character. | 
 | 1009 |         return false; | 
 | 1010 |       } | 
 | 1011 |       if (sepOrFirst) { | 
 | 1012 |         // Separator at start or two separators in a row. | 
 | 1013 |         return false; | 
 | 1014 |       } | 
 | 1015 |       sepOrFirst = true; | 
 | 1016 |       s++; | 
 | 1017 |       break; | 
 | 1018 |     default: | 
| jeffhao | 10037c8 | 2012-01-23 15:06:23 -0800 | [diff] [blame] | 1019 |       if (!IsValidPartOfMemberNameUtf8(&s)) { | 
| Elliott Hughes | 64bf5a3 | 2011-09-20 14:43:12 -0700 | [diff] [blame] | 1020 |         return false; | 
 | 1021 |       } | 
 | 1022 |       sepOrFirst = false; | 
 | 1023 |       break; | 
 | 1024 |     } | 
 | 1025 |   } | 
 | 1026 | } | 
 | 1027 |  | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 1028 | bool IsValidBinaryClassName(const char* s) { | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 1029 |   return IsValidClassName<kName, '.'>(s); | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 1030 | } | 
 | 1031 |  | 
 | 1032 | bool IsValidJniClassName(const char* s) { | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 1033 |   return IsValidClassName<kName, '/'>(s); | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 1034 | } | 
 | 1035 |  | 
 | 1036 | bool IsValidDescriptor(const char* s) { | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 1037 |   return IsValidClassName<kDescriptor, '/'>(s); | 
| Elliott Hughes | 906e685 | 2011-10-28 14:52:10 -0700 | [diff] [blame] | 1038 | } | 
 | 1039 |  | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1040 | void Split(const std::string& s, char separator, std::vector<std::string>* result) { | 
| Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 1041 |   const char* p = s.data(); | 
 | 1042 |   const char* end = p + s.size(); | 
 | 1043 |   while (p != end) { | 
| Elliott Hughes | 48436bb | 2012-02-07 15:23:28 -0800 | [diff] [blame] | 1044 |     if (*p == separator) { | 
| Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 1045 |       ++p; | 
 | 1046 |     } else { | 
 | 1047 |       const char* start = p; | 
| Elliott Hughes | 48436bb | 2012-02-07 15:23:28 -0800 | [diff] [blame] | 1048 |       while (++p != end && *p != separator) { | 
 | 1049 |         // Skip to the next occurrence of the separator. | 
| Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 1050 |       } | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1051 |       result->push_back(std::string(start, p - start)); | 
| Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 1052 |     } | 
 | 1053 |   } | 
 | 1054 | } | 
 | 1055 |  | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1056 | std::string Trim(const std::string& s) { | 
| Dave Allison | 7020278 | 2013-10-22 17:52:19 -0700 | [diff] [blame] | 1057 |   std::string result; | 
 | 1058 |   unsigned int start_index = 0; | 
 | 1059 |   unsigned int end_index = s.size() - 1; | 
 | 1060 |  | 
 | 1061 |   // Skip initial whitespace. | 
 | 1062 |   while (start_index < s.size()) { | 
 | 1063 |     if (!isspace(s[start_index])) { | 
 | 1064 |       break; | 
 | 1065 |     } | 
 | 1066 |     start_index++; | 
 | 1067 |   } | 
 | 1068 |  | 
 | 1069 |   // Skip terminating whitespace. | 
 | 1070 |   while (end_index >= start_index) { | 
 | 1071 |     if (!isspace(s[end_index])) { | 
 | 1072 |       break; | 
 | 1073 |     } | 
 | 1074 |     end_index--; | 
 | 1075 |   } | 
 | 1076 |  | 
 | 1077 |   // All spaces, no beef. | 
 | 1078 |   if (end_index < start_index) { | 
 | 1079 |     return ""; | 
 | 1080 |   } | 
 | 1081 |   // Start_index is the first non-space, end_index is the last one. | 
 | 1082 |   return s.substr(start_index, end_index - start_index + 1); | 
 | 1083 | } | 
 | 1084 |  | 
| Elliott Hughes | 48436bb | 2012-02-07 15:23:28 -0800 | [diff] [blame] | 1085 | template <typename StringT> | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1086 | std::string Join(const std::vector<StringT>& strings, char separator) { | 
| Elliott Hughes | 48436bb | 2012-02-07 15:23:28 -0800 | [diff] [blame] | 1087 |   if (strings.empty()) { | 
 | 1088 |     return ""; | 
 | 1089 |   } | 
 | 1090 |  | 
 | 1091 |   std::string result(strings[0]); | 
 | 1092 |   for (size_t i = 1; i < strings.size(); ++i) { | 
 | 1093 |     result += separator; | 
 | 1094 |     result += strings[i]; | 
 | 1095 |   } | 
 | 1096 |   return result; | 
 | 1097 | } | 
 | 1098 |  | 
 | 1099 | // Explicit instantiations. | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1100 | template std::string Join<std::string>(const std::vector<std::string>& strings, char separator); | 
 | 1101 | template std::string Join<const char*>(const std::vector<const char*>& strings, char separator); | 
| Elliott Hughes | 48436bb | 2012-02-07 15:23:28 -0800 | [diff] [blame] | 1102 |  | 
| Elliott Hughes | f1a5adc | 2012-02-10 18:09:35 -0800 | [diff] [blame] | 1103 | bool StartsWith(const std::string& s, const char* prefix) { | 
 | 1104 |   return s.compare(0, strlen(prefix), prefix) == 0; | 
 | 1105 | } | 
 | 1106 |  | 
| Brian Carlstrom | 7a967b3 | 2012-03-28 15:23:10 -0700 | [diff] [blame] | 1107 | bool EndsWith(const std::string& s, const char* suffix) { | 
 | 1108 |   size_t suffix_length = strlen(suffix); | 
 | 1109 |   size_t string_length = s.size(); | 
 | 1110 |   if (suffix_length > string_length) { | 
 | 1111 |     return false; | 
 | 1112 |   } | 
 | 1113 |   size_t offset = string_length - suffix_length; | 
 | 1114 |   return s.compare(offset, suffix_length, suffix) == 0; | 
 | 1115 | } | 
 | 1116 |  | 
| Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 1117 | void SetThreadName(const char* thread_name) { | 
| Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 1118 |   int hasAt = 0; | 
 | 1119 |   int hasDot = 0; | 
| Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 1120 |   const char* s = thread_name; | 
| Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 1121 |   while (*s) { | 
 | 1122 |     if (*s == '.') { | 
 | 1123 |       hasDot = 1; | 
 | 1124 |     } else if (*s == '@') { | 
 | 1125 |       hasAt = 1; | 
 | 1126 |     } | 
 | 1127 |     s++; | 
 | 1128 |   } | 
| Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 1129 |   int len = s - thread_name; | 
| Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 1130 |   if (len < 15 || hasAt || !hasDot) { | 
| Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 1131 |     s = thread_name; | 
| Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 1132 |   } else { | 
| Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 1133 |     s = thread_name + len - 15; | 
| Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 1134 |   } | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 1135 | #if defined(__linux__) | 
| Elliott Hughes | 7c6a61e | 2012-03-12 18:01:41 -0700 | [diff] [blame] | 1136 |   // pthread_setname_np fails rather than truncating long strings. | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 1137 |   char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel. | 
| Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 1138 |   strncpy(buf, s, sizeof(buf)-1); | 
 | 1139 |   buf[sizeof(buf)-1] = '\0'; | 
 | 1140 |   errno = pthread_setname_np(pthread_self(), buf); | 
 | 1141 |   if (errno != 0) { | 
 | 1142 |     PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'"; | 
 | 1143 |   } | 
| Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 1144 | #else  // __APPLE__ | 
| Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 1145 |   pthread_setname_np(thread_name); | 
| Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 1146 | #endif | 
 | 1147 | } | 
 | 1148 |  | 
| Brian Carlstrom | 2921201 | 2013-09-12 22:18:30 -0700 | [diff] [blame] | 1149 | void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) { | 
 | 1150 |   *utime = *stime = *task_cpu = 0; | 
| Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 1151 |   std::string stats; | 
| Elliott Hughes | 8a31b50 | 2012-04-30 19:36:11 -0700 | [diff] [blame] | 1152 |   if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) { | 
| Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 1153 |     return; | 
 | 1154 |   } | 
 | 1155 |   // Skip the command, which may contain spaces. | 
 | 1156 |   stats = stats.substr(stats.find(')') + 2); | 
 | 1157 |   // Extract the three fields we care about. | 
 | 1158 |   std::vector<std::string> fields; | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1159 |   Split(stats, ' ', &fields); | 
| Brian Carlstrom | 2921201 | 2013-09-12 22:18:30 -0700 | [diff] [blame] | 1160 |   *state = fields[0][0]; | 
 | 1161 |   *utime = strtoull(fields[11].c_str(), NULL, 10); | 
 | 1162 |   *stime = strtoull(fields[12].c_str(), NULL, 10); | 
 | 1163 |   *task_cpu = strtoull(fields[36].c_str(), NULL, 10); | 
| Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 1164 | } | 
 | 1165 |  | 
| Elliott Hughes | 1bac54f | 2012-03-16 12:48:31 -0700 | [diff] [blame] | 1166 | std::string GetSchedulerGroupName(pid_t tid) { | 
 | 1167 |   // /proc/<pid>/cgroup looks like this: | 
 | 1168 |   // 2:devices:/ | 
 | 1169 |   // 1:cpuacct,cpu:/ | 
 | 1170 |   // We want the third field from the line whose second field contains the "cpu" token. | 
 | 1171 |   std::string cgroup_file; | 
 | 1172 |   if (!ReadFileToString(StringPrintf("/proc/self/task/%d/cgroup", tid), &cgroup_file)) { | 
 | 1173 |     return ""; | 
 | 1174 |   } | 
 | 1175 |   std::vector<std::string> cgroup_lines; | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1176 |   Split(cgroup_file, '\n', &cgroup_lines); | 
| Elliott Hughes | 1bac54f | 2012-03-16 12:48:31 -0700 | [diff] [blame] | 1177 |   for (size_t i = 0; i < cgroup_lines.size(); ++i) { | 
 | 1178 |     std::vector<std::string> cgroup_fields; | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1179 |     Split(cgroup_lines[i], ':', &cgroup_fields); | 
| Elliott Hughes | 1bac54f | 2012-03-16 12:48:31 -0700 | [diff] [blame] | 1180 |     std::vector<std::string> cgroups; | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1181 |     Split(cgroup_fields[1], ',', &cgroups); | 
| Andreas Gampe | 277ccbd | 2014-11-03 21:36:10 -0800 | [diff] [blame] | 1182 |     for (size_t j = 0; j < cgroups.size(); ++j) { | 
 | 1183 |       if (cgroups[j] == "cpu") { | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 1184 |         return cgroup_fields[2].substr(1);  // Skip the leading slash. | 
| Elliott Hughes | 1bac54f | 2012-03-16 12:48:31 -0700 | [diff] [blame] | 1185 |       } | 
 | 1186 |     } | 
 | 1187 |   } | 
 | 1188 |   return ""; | 
 | 1189 | } | 
 | 1190 |  | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1191 | #if defined(__linux__) | 
| Andreas Gampe | 00bd2da | 2015-01-09 15:05:46 -0800 | [diff] [blame] | 1192 |  | 
 | 1193 | ALWAYS_INLINE | 
 | 1194 | static inline void WritePrefix(std::ostream* os, const char* prefix, bool odd) { | 
 | 1195 |   if (prefix != nullptr) { | 
 | 1196 |     *os << prefix; | 
 | 1197 |   } | 
 | 1198 |   *os << "  "; | 
 | 1199 |   if (!odd) { | 
 | 1200 |     *os << " "; | 
 | 1201 |   } | 
 | 1202 | } | 
 | 1203 |  | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1204 | static bool RunCommand(std::string cmd, std::ostream* os, const char* prefix) { | 
 | 1205 |   FILE* stream = popen(cmd.c_str(), "r"); | 
 | 1206 |   if (stream) { | 
 | 1207 |     if (os != nullptr) { | 
 | 1208 |       bool odd_line = true;               // We indent them differently. | 
| Andreas Gampe | 00bd2da | 2015-01-09 15:05:46 -0800 | [diff] [blame] | 1209 |       bool wrote_prefix = false;          // Have we already written a prefix? | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1210 |       constexpr size_t kMaxBuffer = 128;  // Relatively small buffer. Should be OK as we're on an | 
 | 1211 |                                           // alt stack, but just to be sure... | 
 | 1212 |       char buffer[kMaxBuffer]; | 
 | 1213 |       while (!feof(stream)) { | 
 | 1214 |         if (fgets(buffer, kMaxBuffer, stream) != nullptr) { | 
 | 1215 |           // Split on newlines. | 
 | 1216 |           char* tmp = buffer; | 
 | 1217 |           for (;;) { | 
 | 1218 |             char* new_line = strchr(tmp, '\n'); | 
 | 1219 |             if (new_line == nullptr) { | 
 | 1220 |               // Print the rest. | 
 | 1221 |               if (*tmp != 0) { | 
| Andreas Gampe | 00bd2da | 2015-01-09 15:05:46 -0800 | [diff] [blame] | 1222 |                 if (!wrote_prefix) { | 
 | 1223 |                   WritePrefix(os, prefix, odd_line); | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1224 |                 } | 
| Andreas Gampe | 00bd2da | 2015-01-09 15:05:46 -0800 | [diff] [blame] | 1225 |                 wrote_prefix = true; | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1226 |                 *os << tmp; | 
 | 1227 |               } | 
 | 1228 |               break; | 
 | 1229 |             } | 
| Andreas Gampe | 00bd2da | 2015-01-09 15:05:46 -0800 | [diff] [blame] | 1230 |             if (!wrote_prefix) { | 
 | 1231 |               WritePrefix(os, prefix, odd_line); | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1232 |             } | 
 | 1233 |             char saved = *(new_line + 1); | 
 | 1234 |             *(new_line + 1) = 0; | 
 | 1235 |             *os << tmp; | 
 | 1236 |             *(new_line + 1) = saved; | 
 | 1237 |             tmp = new_line + 1; | 
 | 1238 |             odd_line = !odd_line; | 
| Andreas Gampe | 00bd2da | 2015-01-09 15:05:46 -0800 | [diff] [blame] | 1239 |             wrote_prefix = false; | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1240 |           } | 
 | 1241 |         } | 
 | 1242 |       } | 
 | 1243 |     } | 
 | 1244 |     pclose(stream); | 
 | 1245 |     return true; | 
 | 1246 |   } else { | 
 | 1247 |     return false; | 
 | 1248 |   } | 
 | 1249 | } | 
 | 1250 |  | 
 | 1251 | static void Addr2line(const std::string& map_src, uintptr_t offset, std::ostream& os, | 
 | 1252 |                       const char* prefix) { | 
 | 1253 |   std::string cmdline(StringPrintf("addr2line --functions --inlines --demangle -e %s %zx", | 
 | 1254 |                                    map_src.c_str(), offset)); | 
 | 1255 |   RunCommand(cmdline.c_str(), &os, prefix); | 
 | 1256 | } | 
 | 1257 | #endif | 
 | 1258 |  | 
| Christopher Ferris | a2cee18 | 2014-04-16 19:13:59 -0700 | [diff] [blame] | 1259 | void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, | 
| Andreas Gampe | 628a61a | 2015-01-07 22:08:35 -0800 | [diff] [blame] | 1260 |     mirror::ArtMethod* current_method, void* ucontext_ptr) { | 
| Ian Rogers | 83597d0 | 2014-11-20 10:29:00 -0800 | [diff] [blame] | 1261 | #if __linux__ | 
| Andreas Gampe | d757632 | 2014-10-24 22:13:45 -0700 | [diff] [blame] | 1262 |   // b/18119146 | 
 | 1263 |   if (RUNNING_ON_VALGRIND != 0) { | 
 | 1264 |     return; | 
 | 1265 |   } | 
 | 1266 |  | 
| Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 1267 |   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid)); | 
| Andreas Gampe | 628a61a | 2015-01-07 22:08:35 -0800 | [diff] [blame] | 1268 |   if (!backtrace->Unwind(0, reinterpret_cast<ucontext*>(ucontext_ptr))) { | 
| Christopher Ferris | 7b5f0cf | 2013-11-01 15:18:45 -0700 | [diff] [blame] | 1269 |     os << prefix << "(backtrace::Unwind failed for thread " << tid << ")\n"; | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1270 |     return; | 
| Christopher Ferris | 7b5f0cf | 2013-11-01 15:18:45 -0700 | [diff] [blame] | 1271 |   } else if (backtrace->NumFrames() == 0) { | 
| Elliott Hughes | 225f5a1 | 2012-06-11 11:23:48 -0700 | [diff] [blame] | 1272 |     os << prefix << "(no native stack frames for thread " << tid << ")\n"; | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1273 |     return; | 
 | 1274 |   } | 
 | 1275 |  | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1276 |   // Check whether we have and should use addr2line. | 
 | 1277 |   bool use_addr2line; | 
 | 1278 |   if (kUseAddr2line) { | 
 | 1279 |     // Try to run it to see whether we have it. Push an argument so that it doesn't assume a.out | 
 | 1280 |     // and print to stderr. | 
| Andreas Gampe | 941c551 | 2015-01-15 10:38:19 -0800 | [diff] [blame] | 1281 |     use_addr2line = (gAborting > 0) && RunCommand("addr2line -h", nullptr, nullptr); | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1282 |   } else { | 
 | 1283 |     use_addr2line = false; | 
 | 1284 |   } | 
 | 1285 |  | 
| Christopher Ferris | 943af7d | 2014-01-16 12:41:46 -0800 | [diff] [blame] | 1286 |   for (Backtrace::const_iterator it = backtrace->begin(); | 
 | 1287 |        it != backtrace->end(); ++it) { | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1288 |     // We produce output like this: | 
| Christopher Ferris | a2cee18 | 2014-04-16 19:13:59 -0700 | [diff] [blame] | 1289 |     // ]    #00 pc 000075bb8  /system/lib/libc.so (unwind_backtrace_thread+536) | 
 | 1290 |     // In order for parsing tools to continue to function, the stack dump | 
 | 1291 |     // format must at least adhere to this format: | 
 | 1292 |     //  #XX pc <RELATIVE_ADDR>  <FULL_PATH_TO_SHARED_LIBRARY> ... | 
 | 1293 |     // The parsers require a single space before and after pc, and two spaces | 
 | 1294 |     // after the <RELATIVE_ADDR>. There can be any prefix data before the | 
 | 1295 |     // #XX. <RELATIVE_ADDR> has to be a hex number but with no 0x prefix. | 
 | 1296 |     os << prefix << StringPrintf("#%02zu pc ", it->num); | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1297 |     bool try_addr2line = false; | 
| Christopher Ferris | a1c9665 | 2015-02-06 13:18:58 -0800 | [diff] [blame] | 1298 |     if (!BacktraceMap::IsValid(it->map)) { | 
| Christopher Ferris | a2cee18 | 2014-04-16 19:13:59 -0700 | [diff] [blame] | 1299 |       os << StringPrintf("%08" PRIxPTR "  ???", it->pc); | 
| Christopher Ferris | 7b5f0cf | 2013-11-01 15:18:45 -0700 | [diff] [blame] | 1300 |     } else { | 
| Christopher Ferris | a1c9665 | 2015-02-06 13:18:58 -0800 | [diff] [blame] | 1301 |       os << StringPrintf("%08" PRIxPTR "  ", it->pc - it->map.start); | 
 | 1302 |       os << it->map.name; | 
| Andreas Gampe | 3ef69b4 | 2015-01-26 10:38:34 -0800 | [diff] [blame] | 1303 |       os << " ("; | 
| Christopher Ferris | a2cee18 | 2014-04-16 19:13:59 -0700 | [diff] [blame] | 1304 |       if (!it->func_name.empty()) { | 
 | 1305 |         os << it->func_name; | 
 | 1306 |         if (it->func_offset != 0) { | 
 | 1307 |           os << "+" << it->func_offset; | 
 | 1308 |         } | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1309 |         try_addr2line = true; | 
| Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 1310 |       } else if ( | 
 | 1311 |           current_method != nullptr && Locks::mutator_lock_->IsSharedHeld(Thread::Current()) && | 
 | 1312 |           current_method->PcIsWithinQuickCode(it->pc)) { | 
| Brian Carlstrom | 474cc79 | 2014-03-07 14:18:15 -0800 | [diff] [blame] | 1313 |         const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode(); | 
 | 1314 |         os << JniLongName(current_method) << "+" | 
 | 1315 |            << (it->pc - reinterpret_cast<uintptr_t>(start_of_code)); | 
| Kenny Root | 067d20f | 2014-03-05 14:57:21 -0800 | [diff] [blame] | 1316 |       } else { | 
 | 1317 |         os << "???"; | 
 | 1318 |       } | 
| Christopher Ferris | a2cee18 | 2014-04-16 19:13:59 -0700 | [diff] [blame] | 1319 |       os << ")"; | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1320 |     } | 
| Christopher Ferris | a2cee18 | 2014-04-16 19:13:59 -0700 | [diff] [blame] | 1321 |     os << "\n"; | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1322 |     if (try_addr2line && use_addr2line) { | 
| Christopher Ferris | a1c9665 | 2015-02-06 13:18:58 -0800 | [diff] [blame] | 1323 |       Addr2line(it->map.name, it->pc - it->map.start, os, prefix); | 
| Andreas Gampe | 8e1cb91 | 2015-01-08 20:11:09 -0800 | [diff] [blame] | 1324 |     } | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1325 |   } | 
| Nicolas Geoffray | e6ac4fd | 2014-11-04 13:03:29 +0000 | [diff] [blame] | 1326 | #else | 
| Andreas Gampe | 9387c72 | 2015-01-08 11:32:22 -0800 | [diff] [blame] | 1327 |   UNUSED(os, tid, prefix, current_method, ucontext_ptr); | 
| Ian Rogers | c5f1773 | 2014-06-05 20:48:42 -0700 | [diff] [blame] | 1328 | #endif | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1329 | } | 
 | 1330 |  | 
| Elliott Hughes | 058a6de | 2012-05-24 19:13:02 -0700 | [diff] [blame] | 1331 | #if defined(__APPLE__) | 
 | 1332 |  | 
 | 1333 | // TODO: is there any way to get the kernel stack on Mac OS? | 
 | 1334 | void DumpKernelStack(std::ostream&, pid_t, const char*, bool) {} | 
 | 1335 |  | 
 | 1336 | #else | 
 | 1337 |  | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1338 | void DumpKernelStack(std::ostream& os, pid_t tid, const char* prefix, bool include_count) { | 
| Elliott Hughes | 12a9502 | 2012-05-24 21:41:38 -0700 | [diff] [blame] | 1339 |   if (tid == GetTid()) { | 
 | 1340 |     // There's no point showing that we're reading our stack out of /proc! | 
 | 1341 |     return; | 
 | 1342 |   } | 
 | 1343 |  | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1344 |   std::string kernel_stack_filename(StringPrintf("/proc/self/task/%d/stack", tid)); | 
 | 1345 |   std::string kernel_stack; | 
 | 1346 |   if (!ReadFileToString(kernel_stack_filename, &kernel_stack)) { | 
| Elliott Hughes | 058a6de | 2012-05-24 19:13:02 -0700 | [diff] [blame] | 1347 |     os << prefix << "(couldn't read " << kernel_stack_filename << ")\n"; | 
| jeffhao | c4c3ee2 | 2012-05-25 16:16:32 -0700 | [diff] [blame] | 1348 |     return; | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1349 |   } | 
 | 1350 |  | 
 | 1351 |   std::vector<std::string> kernel_stack_frames; | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 1352 |   Split(kernel_stack, '\n', &kernel_stack_frames); | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1353 |   // We skip the last stack frame because it's always equivalent to "[<ffffffff>] 0xffffffff", | 
 | 1354 |   // which looking at the source appears to be the kernel's way of saying "that's all, folks!". | 
 | 1355 |   kernel_stack_frames.pop_back(); | 
 | 1356 |   for (size_t i = 0; i < kernel_stack_frames.size(); ++i) { | 
| Brian Carlstrom | 474cc79 | 2014-03-07 14:18:15 -0800 | [diff] [blame] | 1357 |     // Turn "[<ffffffff8109156d>] futex_wait_queue_me+0xcd/0x110" | 
 | 1358 |     // into "futex_wait_queue_me+0xcd/0x110". | 
| Elliott Hughes | 46e251b | 2012-05-22 15:10:45 -0700 | [diff] [blame] | 1359 |     const char* text = kernel_stack_frames[i].c_str(); | 
 | 1360 |     const char* close_bracket = strchr(text, ']'); | 
 | 1361 |     if (close_bracket != NULL) { | 
 | 1362 |       text = close_bracket + 2; | 
 | 1363 |     } | 
 | 1364 |     os << prefix; | 
 | 1365 |     if (include_count) { | 
 | 1366 |       os << StringPrintf("#%02zd ", i); | 
 | 1367 |     } | 
 | 1368 |     os << text << "\n"; | 
 | 1369 |   } | 
 | 1370 | } | 
 | 1371 |  | 
 | 1372 | #endif | 
 | 1373 |  | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1374 | const char* GetAndroidRoot() { | 
 | 1375 |   const char* android_root = getenv("ANDROID_ROOT"); | 
 | 1376 |   if (android_root == NULL) { | 
 | 1377 |     if (OS::DirectoryExists("/system")) { | 
 | 1378 |       android_root = "/system"; | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 1379 |     } else { | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1380 |       LOG(FATAL) << "ANDROID_ROOT not set and /system does not exist"; | 
 | 1381 |       return ""; | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 1382 |     } | 
 | 1383 |   } | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1384 |   if (!OS::DirectoryExists(android_root)) { | 
 | 1385 |     LOG(FATAL) << "Failed to find ANDROID_ROOT directory " << android_root; | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 1386 |     return ""; | 
 | 1387 |   } | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1388 |   return android_root; | 
 | 1389 | } | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 1390 |  | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1391 | const char* GetAndroidData() { | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1392 |   std::string error_msg; | 
 | 1393 |   const char* dir = GetAndroidDataSafe(&error_msg); | 
 | 1394 |   if (dir != nullptr) { | 
 | 1395 |     return dir; | 
 | 1396 |   } else { | 
 | 1397 |     LOG(FATAL) << error_msg; | 
 | 1398 |     return ""; | 
 | 1399 |   } | 
 | 1400 | } | 
 | 1401 |  | 
 | 1402 | const char* GetAndroidDataSafe(std::string* error_msg) { | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1403 |   const char* android_data = getenv("ANDROID_DATA"); | 
 | 1404 |   if (android_data == NULL) { | 
 | 1405 |     if (OS::DirectoryExists("/data")) { | 
 | 1406 |       android_data = "/data"; | 
 | 1407 |     } else { | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1408 |       *error_msg = "ANDROID_DATA not set and /data does not exist"; | 
 | 1409 |       return nullptr; | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1410 |     } | 
 | 1411 |   } | 
 | 1412 |   if (!OS::DirectoryExists(android_data)) { | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1413 |     *error_msg = StringPrintf("Failed to find ANDROID_DATA directory %s", android_data); | 
 | 1414 |     return nullptr; | 
| Brian Carlstrom | a56fcd6 | 2012-02-04 21:23:01 -0800 | [diff] [blame] | 1415 |   } | 
 | 1416 |   return android_data; | 
 | 1417 | } | 
 | 1418 |  | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1419 | void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache, | 
| Andreas Gampe | 3c13a79 | 2014-09-18 20:56:04 -0700 | [diff] [blame] | 1420 |                     bool* have_android_data, bool* dalvik_cache_exists, bool* is_global_cache) { | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1421 |   CHECK(subdir != nullptr); | 
 | 1422 |   std::string error_msg; | 
 | 1423 |   const char* android_data = GetAndroidDataSafe(&error_msg); | 
 | 1424 |   if (android_data == nullptr) { | 
 | 1425 |     *have_android_data = false; | 
 | 1426 |     *dalvik_cache_exists = false; | 
| Andreas Gampe | 3c13a79 | 2014-09-18 20:56:04 -0700 | [diff] [blame] | 1427 |     *is_global_cache = false; | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1428 |     return; | 
 | 1429 |   } else { | 
 | 1430 |     *have_android_data = true; | 
 | 1431 |   } | 
 | 1432 |   const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data)); | 
 | 1433 |   *dalvik_cache = dalvik_cache_root + subdir; | 
 | 1434 |   *dalvik_cache_exists = OS::DirectoryExists(dalvik_cache->c_str()); | 
| Andreas Gampe | 3c13a79 | 2014-09-18 20:56:04 -0700 | [diff] [blame] | 1435 |   *is_global_cache = strcmp(android_data, "/data") == 0; | 
 | 1436 |   if (create_if_absent && !*dalvik_cache_exists && !*is_global_cache) { | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1437 |     // Don't create the system's /data/dalvik-cache/... because it needs special permissions. | 
 | 1438 |     *dalvik_cache_exists = ((mkdir(dalvik_cache_root.c_str(), 0700) == 0 || errno == EEXIST) && | 
 | 1439 |                             (mkdir(dalvik_cache->c_str(), 0700) == 0 || errno == EEXIST)); | 
 | 1440 |   } | 
 | 1441 | } | 
 | 1442 |  | 
| Andreas Gampe | 40da286 | 2015-02-27 12:49:04 -0800 | [diff] [blame^] | 1443 | static std::string GetDalvikCacheImpl(const char* subdir, | 
 | 1444 |                                       const bool create_if_absent, | 
 | 1445 |                                       const bool abort_on_error) { | 
| Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 1446 |   CHECK(subdir != nullptr); | 
| Brian Carlstrom | 41ccffd | 2014-05-06 10:37:30 -0700 | [diff] [blame] | 1447 |   const char* android_data = GetAndroidData(); | 
 | 1448 |   const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", android_data)); | 
| Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 1449 |   const std::string dalvik_cache = dalvik_cache_root + subdir; | 
| Andreas Gampe | 40da286 | 2015-02-27 12:49:04 -0800 | [diff] [blame^] | 1450 |   if (!OS::DirectoryExists(dalvik_cache.c_str())) { | 
 | 1451 |     if (!create_if_absent) { | 
 | 1452 |       // TODO: Check callers. Traditional behavior is to not to abort, even when abort_on_error. | 
 | 1453 |       return ""; | 
 | 1454 |     } | 
 | 1455 |  | 
| Brian Carlstrom | 41ccffd | 2014-05-06 10:37:30 -0700 | [diff] [blame] | 1456 |     // Don't create the system's /data/dalvik-cache/... because it needs special permissions. | 
| Andreas Gampe | 40da286 | 2015-02-27 12:49:04 -0800 | [diff] [blame^] | 1457 |     if (strcmp(android_data, "/data") == 0) { | 
 | 1458 |       if (abort_on_error) { | 
 | 1459 |         LOG(FATAL) << "Failed to find dalvik-cache directory " << dalvik_cache | 
 | 1460 |                    << ", cannot create /data dalvik-cache."; | 
 | 1461 |         UNREACHABLE(); | 
| Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 1462 |       } | 
| Andreas Gampe | 40da286 | 2015-02-27 12:49:04 -0800 | [diff] [blame^] | 1463 |       return ""; | 
 | 1464 |     } | 
 | 1465 |  | 
 | 1466 |     int result = mkdir(dalvik_cache_root.c_str(), 0700); | 
 | 1467 |     if (result != 0 && errno != EEXIST) { | 
 | 1468 |       if (abort_on_error) { | 
 | 1469 |         PLOG(FATAL) << "Failed to create dalvik-cache root directory " << dalvik_cache_root; | 
 | 1470 |         UNREACHABLE(); | 
 | 1471 |       } | 
 | 1472 |       return ""; | 
 | 1473 |     } | 
 | 1474 |  | 
 | 1475 |     result = mkdir(dalvik_cache.c_str(), 0700); | 
 | 1476 |     if (result != 0) { | 
 | 1477 |       if (abort_on_error) { | 
| Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 1478 |         PLOG(FATAL) << "Failed to create dalvik-cache directory " << dalvik_cache; | 
| Andreas Gampe | 40da286 | 2015-02-27 12:49:04 -0800 | [diff] [blame^] | 1479 |         UNREACHABLE(); | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 1480 |       } | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 1481 |       return ""; | 
 | 1482 |     } | 
 | 1483 |   } | 
| Brian Carlstrom | 7675e16 | 2013-06-10 16:18:04 -0700 | [diff] [blame] | 1484 |   return dalvik_cache; | 
| Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 1485 | } | 
 | 1486 |  | 
| Andreas Gampe | 40da286 | 2015-02-27 12:49:04 -0800 | [diff] [blame^] | 1487 | std::string GetDalvikCache(const char* subdir, const bool create_if_absent) { | 
 | 1488 |   return GetDalvikCacheImpl(subdir, create_if_absent, false); | 
 | 1489 | } | 
 | 1490 |  | 
 | 1491 | std::string GetDalvikCacheOrDie(const char* subdir, const bool create_if_absent) { | 
 | 1492 |   return GetDalvikCacheImpl(subdir, create_if_absent, true); | 
 | 1493 | } | 
 | 1494 |  | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1495 | bool GetDalvikCacheFilename(const char* location, const char* cache_location, | 
 | 1496 |                             std::string* filename, std::string* error_msg) { | 
| Ian Rogers | e606010 | 2013-05-16 12:01:04 -0700 | [diff] [blame] | 1497 |   if (location[0] != '/') { | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1498 |     *error_msg = StringPrintf("Expected path in location to be absolute: %s", location); | 
 | 1499 |     return false; | 
| Ian Rogers | e606010 | 2013-05-16 12:01:04 -0700 | [diff] [blame] | 1500 |   } | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 1501 |   std::string cache_file(&location[1]);  // skip leading slash | 
| Alex Light | 6e183f2 | 2014-07-18 14:57:04 -0700 | [diff] [blame] | 1502 |   if (!EndsWith(location, ".dex") && !EndsWith(location, ".art") && !EndsWith(location, ".oat")) { | 
| Brian Carlstrom | 30e2ea4 | 2013-06-19 23:25:37 -0700 | [diff] [blame] | 1503 |     cache_file += "/"; | 
 | 1504 |     cache_file += DexFile::kClassesDex; | 
 | 1505 |   } | 
| Brian Carlstrom | b7bbba4 | 2011-10-13 14:58:47 -0700 | [diff] [blame] | 1506 |   std::replace(cache_file.begin(), cache_file.end(), '/', '@'); | 
| Alex Light | a59dd80 | 2014-07-02 16:28:08 -0700 | [diff] [blame] | 1507 |   *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str()); | 
 | 1508 |   return true; | 
 | 1509 | } | 
 | 1510 |  | 
 | 1511 | std::string GetDalvikCacheFilenameOrDie(const char* location, const char* cache_location) { | 
 | 1512 |   std::string ret; | 
 | 1513 |   std::string error_msg; | 
 | 1514 |   if (!GetDalvikCacheFilename(location, cache_location, &ret, &error_msg)) { | 
 | 1515 |     LOG(FATAL) << error_msg; | 
 | 1516 |   } | 
 | 1517 |   return ret; | 
| Brian Carlstrom | b7bbba4 | 2011-10-13 14:58:47 -0700 | [diff] [blame] | 1518 | } | 
 | 1519 |  | 
| Brian Carlstrom | 2afe494 | 2014-05-19 10:25:33 -0700 | [diff] [blame] | 1520 | static void InsertIsaDirectory(const InstructionSet isa, std::string* filename) { | 
| Brian Carlstrom | 0e12bdc | 2014-05-14 17:44:28 -0700 | [diff] [blame] | 1521 |   // in = /foo/bar/baz | 
 | 1522 |   // out = /foo/bar/<isa>/baz | 
 | 1523 |   size_t pos = filename->rfind('/'); | 
 | 1524 |   CHECK_NE(pos, std::string::npos) << *filename << " " << isa; | 
 | 1525 |   filename->insert(pos, "/", 1); | 
 | 1526 |   filename->insert(pos + 1, GetInstructionSetString(isa)); | 
 | 1527 | } | 
 | 1528 |  | 
 | 1529 | std::string GetSystemImageFilename(const char* location, const InstructionSet isa) { | 
 | 1530 |   // location = /system/framework/boot.art | 
 | 1531 |   // filename = /system/framework/<isa>/boot.art | 
 | 1532 |   std::string filename(location); | 
| Brian Carlstrom | 2afe494 | 2014-05-19 10:25:33 -0700 | [diff] [blame] | 1533 |   InsertIsaDirectory(isa, &filename); | 
| Brian Carlstrom | 0e12bdc | 2014-05-14 17:44:28 -0700 | [diff] [blame] | 1534 |   return filename; | 
 | 1535 | } | 
 | 1536 |  | 
| Brian Carlstrom | 7c3d13a | 2013-09-04 17:15:11 -0700 | [diff] [blame] | 1537 | bool IsZipMagic(uint32_t magic) { | 
 | 1538 |   return (('P' == ((magic >> 0) & 0xff)) && | 
 | 1539 |           ('K' == ((magic >> 8) & 0xff))); | 
| jeffhao | 262bf46 | 2011-10-20 18:36:32 -0700 | [diff] [blame] | 1540 | } | 
 | 1541 |  | 
| Brian Carlstrom | 7c3d13a | 2013-09-04 17:15:11 -0700 | [diff] [blame] | 1542 | bool IsDexMagic(uint32_t magic) { | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 1543 |   return DexFile::IsMagicValid(reinterpret_cast<const uint8_t*>(&magic)); | 
| Brian Carlstrom | 7a967b3 | 2012-03-28 15:23:10 -0700 | [diff] [blame] | 1544 | } | 
 | 1545 |  | 
| Brian Carlstrom | 7c3d13a | 2013-09-04 17:15:11 -0700 | [diff] [blame] | 1546 | bool IsOatMagic(uint32_t magic) { | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 1547 |   return (memcmp(reinterpret_cast<const uint8_t*>(magic), | 
| Brian Carlstrom | 7c3d13a | 2013-09-04 17:15:11 -0700 | [diff] [blame] | 1548 |                  OatHeader::kOatMagic, | 
 | 1549 |                  sizeof(OatHeader::kOatMagic)) == 0); | 
| jeffhao | 262bf46 | 2011-10-20 18:36:32 -0700 | [diff] [blame] | 1550 | } | 
 | 1551 |  | 
| Brian Carlstrom | 6449c62 | 2014-02-10 23:48:36 -0800 | [diff] [blame] | 1552 | bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { | 
 | 1553 |   const std::string command_line(Join(arg_vector, ' ')); | 
 | 1554 |  | 
 | 1555 |   CHECK_GE(arg_vector.size(), 1U) << command_line; | 
 | 1556 |  | 
 | 1557 |   // Convert the args to char pointers. | 
 | 1558 |   const char* program = arg_vector[0].c_str(); | 
 | 1559 |   std::vector<char*> args; | 
| Brian Carlstrom | 35d8b8e | 2014-02-25 10:51:11 -0800 | [diff] [blame] | 1560 |   for (size_t i = 0; i < arg_vector.size(); ++i) { | 
 | 1561 |     const std::string& arg = arg_vector[i]; | 
 | 1562 |     char* arg_str = const_cast<char*>(arg.c_str()); | 
 | 1563 |     CHECK(arg_str != nullptr) << i; | 
 | 1564 |     args.push_back(arg_str); | 
| Brian Carlstrom | 6449c62 | 2014-02-10 23:48:36 -0800 | [diff] [blame] | 1565 |   } | 
 | 1566 |   args.push_back(NULL); | 
 | 1567 |  | 
 | 1568 |   // fork and exec | 
 | 1569 |   pid_t pid = fork(); | 
 | 1570 |   if (pid == 0) { | 
 | 1571 |     // no allocation allowed between fork and exec | 
 | 1572 |  | 
 | 1573 |     // change process groups, so we don't get reaped by ProcessManager | 
 | 1574 |     setpgid(0, 0); | 
 | 1575 |  | 
 | 1576 |     execv(program, &args[0]); | 
 | 1577 |  | 
| Brian Carlstrom | 13db9aa | 2014-02-27 12:44:32 -0800 | [diff] [blame] | 1578 |     PLOG(ERROR) << "Failed to execv(" << command_line << ")"; | 
 | 1579 |     exit(1); | 
| Brian Carlstrom | 6449c62 | 2014-02-10 23:48:36 -0800 | [diff] [blame] | 1580 |   } else { | 
 | 1581 |     if (pid == -1) { | 
 | 1582 |       *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", | 
 | 1583 |                                 command_line.c_str(), strerror(errno)); | 
 | 1584 |       return false; | 
 | 1585 |     } | 
 | 1586 |  | 
 | 1587 |     // wait for subprocess to finish | 
 | 1588 |     int status; | 
 | 1589 |     pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); | 
 | 1590 |     if (got_pid != pid) { | 
 | 1591 |       *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " | 
 | 1592 |                                 "wanted %d, got %d: %s", | 
 | 1593 |                                 command_line.c_str(), pid, got_pid, strerror(errno)); | 
 | 1594 |       return false; | 
 | 1595 |     } | 
 | 1596 |     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { | 
 | 1597 |       *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", | 
 | 1598 |                                 command_line.c_str()); | 
 | 1599 |       return false; | 
 | 1600 |     } | 
 | 1601 |   } | 
 | 1602 |   return true; | 
 | 1603 | } | 
 | 1604 |  | 
| Tong Shen | 547cdfd | 2014-08-05 01:54:19 -0700 | [diff] [blame] | 1605 | void EncodeUnsignedLeb128(uint32_t data, std::vector<uint8_t>* dst) { | 
| Yevgeny Rouban | e3ea838 | 2014-08-08 16:29:38 +0700 | [diff] [blame] | 1606 |   Leb128Encoder(dst).PushBackUnsigned(data); | 
| Tong Shen | 547cdfd | 2014-08-05 01:54:19 -0700 | [diff] [blame] | 1607 | } | 
 | 1608 |  | 
 | 1609 | void EncodeSignedLeb128(int32_t data, std::vector<uint8_t>* dst) { | 
| Yevgeny Rouban | e3ea838 | 2014-08-08 16:29:38 +0700 | [diff] [blame] | 1610 |   Leb128Encoder(dst).PushBackSigned(data); | 
| Tong Shen | 547cdfd | 2014-08-05 01:54:19 -0700 | [diff] [blame] | 1611 | } | 
 | 1612 |  | 
| Mathieu Chartier | 7643327 | 2014-09-26 14:32:37 -0700 | [diff] [blame] | 1613 | std::string PrettyDescriptor(Primitive::Type type) { | 
 | 1614 |   return PrettyDescriptor(Primitive::Descriptor(type)); | 
 | 1615 | } | 
 | 1616 |  | 
| Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 1617 | }  // namespace art |