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