| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef NDEBUG | 5 #ifndef NDEBUG |
| 6 | 6 |
| 7 #include "debug.h" | 7 #include "debug.h" |
| 8 | 8 |
| 9 namespace playground { | 9 namespace playground { |
| 10 | 10 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 for (std::map<int, std::string>::const_iterator iter = | 117 for (std::map<int, std::string>::const_iterator iter = |
| 118 syscallNamesMap_.begin(); | 118 syscallNamesMap_.begin(); |
| 119 iter != syscallNamesMap_.end(); | 119 iter != syscallNamesMap_.end(); |
| 120 ++iter) { | 120 ++iter) { |
| 121 syscallNames_[iter->first] = iter->second.c_str(); | 121 syscallNames_[iter->first] = iter->second.c_str(); |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 } | 124 } |
| 125 } | 125 } |
| 126 | 126 |
| 127 void Debug::message(const char* msg) { | 127 bool Debug::enter() { |
| 128 // Increment the recursion level in TLS storage. This allows us to |
| 129 // make system calls from within our debugging functions, without triggering |
| 130 // additional debugging output. |
| 131 // |
| 132 // This function can be called from both the sandboxed process and from the |
| 133 // trusted process. Only the sandboxed process needs to worry about |
| 134 // recursively calling system calls. The trusted process doesn't intercept |
| 135 // system calls and thus doesn't have this problem. It also doesn't have |
| 136 // a TLS. We explicitly set the segment selector to zero, when in the |
| 137 // trusted process, so that we can avoid tracking recursion levels. |
| 138 int level; |
| 139 #if defined(__x86_64__) |
| 140 asm volatile("mov %%gs, %0\n" |
| 141 "test %0, %0\n" |
| 142 "jz 1f\n" |
| 143 "movl %%gs:0x1050-0xD8, %0\n" |
| 144 "incl %%gs:0x1050-0xD8\n" |
| 145 "1:\n" |
| 146 : "=r"(level) |
| 147 : |
| 148 : "memory"); |
| 149 #elif defined(__i386__) |
| 150 asm volatile("mov %%fs, %0\n" |
| 151 "test %0, %0\n" |
| 152 "jz 1f\n" |
| 153 "movl %%fs:0x1034-0x54, %0\n" |
| 154 "incl %%fs:0x1034-0x54\n" |
| 155 "1:\n" |
| 156 : "=r"(level) |
| 157 : |
| 158 : "memory"); |
| 159 #else |
| 160 #error "Unsupported target platform" |
| 161 #endif |
| 162 return !level; |
| 163 } |
| 164 |
| 165 bool Debug::leave() { |
| 166 // Decrement the recursion level in TLS storage. This allows us to |
| 167 // make system calls from within our debugging functions, without triggering |
| 168 // additional debugging output. |
| 169 // |
| 170 // This function can be called from both the sandboxed process and from the |
| 171 // trusted process. Only the sandboxed process needs to worry about |
| 172 // recursively calling system calls. The trusted process doesn't intercept |
| 173 // system calls and thus doesn't have this problem. It also doesn't have |
| 174 // a TLS. We explicitly set the segment selector to zero, when in the |
| 175 // trusted process, so that we can avoid tracking recursion levels. |
| 176 int level; |
| 177 #if defined(__x86_64__) |
| 178 asm volatile("mov %%gs, %0\n" |
| 179 "test %0, %0\n" |
| 180 "jz 1f\n" |
| 181 "decl %%gs:0x1050-0xD8\n" |
| 182 "movl %%gs:0x1050-0xD8, %0\n" |
| 183 "1:\n" |
| 184 : "=r"(level) |
| 185 : |
| 186 : "memory"); |
| 187 #elif defined(__i386__) |
| 188 asm volatile("mov %%fs, %0\n" |
| 189 "test %0, %0\n" |
| 190 "jz 1f\n" |
| 191 "decl %%fs:0x1034-0x54\n" |
| 192 "movl %%fs:0x1034-0x54, %0\n" |
| 193 "1:\n" |
| 194 : "=r"(level) |
| 195 : |
| 196 : "memory"); |
| 197 #else |
| 198 #error Unsupported target platform |
| 199 #endif |
| 200 return !level; |
| 201 } |
| 202 |
| 203 void Debug::_message(const char* msg) { |
| 128 if (enabled_) { | 204 if (enabled_) { |
| 129 Sandbox::SysCalls sys; | 205 Sandbox::SysCalls sys; |
| 130 size_t len = strlen(msg); | 206 size_t len = strlen(msg); |
| 131 if (len && msg[len-1] != '\n') { | 207 if (len && msg[len-1] != '\n') { |
| 132 // Write operations should be atomic, so that we don't interleave | 208 // Write operations should be atomic, so that we don't interleave |
| 133 // messages from multiple threads. Append a newline, if it is not | 209 // messages from multiple threads. Append a newline, if it is not |
| 134 // already there. | 210 // already there. |
| 135 char copy[len + 1]; | 211 char copy[len + 1]; |
| 136 memcpy(copy, msg, len); | 212 memcpy(copy, msg, len); |
| 137 copy[len] = '\n'; | 213 copy[len] = '\n'; |
| 138 Sandbox::write(sys, 2, copy, len + 1); | 214 Sandbox::write(sys, 2, copy, len + 1); |
| 139 } else { | 215 } else { |
| 140 Sandbox::write(sys, 2, msg, len); | 216 Sandbox::write(sys, 2, msg, len); |
| 141 } | 217 } |
| 142 } | 218 } |
| 143 } | 219 } |
| 144 | 220 |
| 145 void Debug::syscall(int sysnum, const char* msg, int call) { | 221 void Debug::message(const char* msg) { |
| 222 if (enabled_) { |
| 223 if (enter()) { |
| 224 _message(msg); |
| 225 } |
| 226 leave(); |
| 227 } |
| 228 } |
| 229 |
| 230 void Debug::gettimeofday(long long* tm) { |
| 231 if (tm) { |
| 232 struct timeval tv; |
| 233 #if defined(__i386__) |
| 234 // Zero out the lastSyscallNum, so that we don't try to coalesce |
| 235 // calls to gettimeofday(). For debugging purposes, we need the |
| 236 // exact time. |
| 237 asm volatile("movl $0, %fs:0x102C-0x54"); |
| 238 #elif !defined(__x86_64__) |
| 239 #error Unsupported target platform |
| 240 #endif |
| 241 ::gettimeofday(&tv, NULL); |
| 242 *tm = 1000ULL*1000ULL*static_cast<unsigned>(tv.tv_sec) + |
| 243 static_cast<unsigned>(tv.tv_usec); |
| 244 } |
| 245 } |
| 246 |
| 247 void Debug::syscall(long long* tm, int sysnum, const char* msg, int call) { |
| 146 // This function gets called from the system call wrapper. Avoid calling | 248 // This function gets called from the system call wrapper. Avoid calling |
| 147 // any library functions that themselves need system calls. | 249 // any library functions that themselves need system calls. |
| 148 if (enabled_) { | 250 if (enabled_) { |
| 149 const char *sysname = NULL; | 251 if (enter() || !tm) { |
| 150 if (sysnum >= 0 && sysnum < numSyscallNames_) { | 252 gettimeofday(tm); |
| 151 sysname = syscallNames_[sysnum]; | 253 |
| 254 const char *sysname = NULL; |
| 255 if (sysnum >= 0 && sysnum < numSyscallNames_) { |
| 256 sysname = syscallNames_[sysnum]; |
| 257 } |
| 258 static const char kUnnamedMessage[] = "Unnamed syscall #"; |
| 259 char unnamed[40]; |
| 260 if (!sysname) { |
| 261 memcpy(unnamed, kUnnamedMessage, sizeof(kUnnamedMessage) - 1); |
| 262 itoa(unnamed + sizeof(kUnnamedMessage) - 1, sysnum); |
| 263 sysname = unnamed; |
| 264 } |
| 265 #if defined(__NR_socketcall) || defined(__NR_ipc) |
| 266 char extra[40]; |
| 267 *extra = '\000'; |
| 268 #if defined(__NR_socketcall) |
| 269 if (sysnum == __NR_socketcall) { |
| 270 static const char* socketcall_name[] = { |
| 271 0, "socket", "bind", "connect", "listen", "accept", "getsockname", |
| 272 "getpeername", "socketpair", "send", "recv", "sendto","recvfrom", |
| 273 "shutdown", "setsockopt", "getsockopt", "sendmsg", "recvmsg", |
| 274 "accept4" |
| 275 }; |
| 276 if (call >= 1 && |
| 277 call < (int)(sizeof(socketcall_name)/sizeof(char *))) { |
| 278 strcat(strcpy(extra, " "), socketcall_name[call]); |
| 279 } else { |
| 280 itoa(strcpy(extra, " #") + 2, call); |
| 281 } |
| 282 } |
| 283 #endif |
| 284 #if defined(__NR_ipc) |
| 285 if (sysnum == __NR_ipc) { |
| 286 static const char* ipc_name[] = { |
| 287 0, "semop", "semget", "semctl", "semtimedop", 0, 0, 0, 0, 0, 0, |
| 288 "msgsnd", "msgrcv", "msgget", "msgctl", 0, 0, 0, 0, 0, 0, |
| 289 "shmat", "shmdt", "shmget", "shmctl" }; |
| 290 if (call >= 1 && call < (int)(sizeof(ipc_name)/sizeof(char *)) && |
| 291 ipc_name[call]) { |
| 292 strcat(strcpy(extra, " "), ipc_name[call]); |
| 293 } else { |
| 294 itoa(strcpy(extra, " #") + 2, call); |
| 295 } |
| 296 } |
| 297 #endif |
| 298 #else |
| 299 static const char extra[1] = { 0 }; |
| 300 #endif |
| 301 char buf[strlen(sysname) + strlen(extra) + (msg ? strlen(msg) : 0) + 4]; |
| 302 strcat(strcat(strcat(strcat(strcpy(buf, sysname), extra), ": "), |
| 303 msg ? msg : ""), "\n"); |
| 304 _message(buf); |
| 152 } | 305 } |
| 153 char unnamed[40] = "Unnamed syscall #"; | 306 leave(); |
| 154 if (!sysname) { | |
| 155 itoa(const_cast<char *>(strrchr(sysname = unnamed, '\000')), sysnum); | |
| 156 } | |
| 157 #if defined(__NR_socketcall) || defined(__NR_ipc) | |
| 158 char extra[40]; | |
| 159 *extra = '\000'; | |
| 160 #if defined(__NR_socketcall) | |
| 161 if (sysnum == __NR_socketcall) { | |
| 162 static const char* socketcall_name[] = { | |
| 163 0, "socket", "bind", "connect", "listen", "accept", "getsockname", | |
| 164 "getpeername", "socketpair", "send", "recv", "sendto","recvfrom", | |
| 165 "shutdown", "setsockopt", "getsockopt", "sendmsg", "recvmsg", | |
| 166 "accept4" | |
| 167 }; | |
| 168 if (call >= 1 && call < (int)(sizeof(socketcall_name)/sizeof(char *))) { | |
| 169 strcat(strcpy(extra, " "), socketcall_name[call]); | |
| 170 } else { | |
| 171 itoa(strcpy(extra, " #") + 2, call); | |
| 172 } | |
| 173 } | |
| 174 #endif | |
| 175 #if defined(__NR_ipc) | |
| 176 if (sysnum == __NR_ipc) { | |
| 177 static const char* ipc_name[] = { | |
| 178 0, "semop", "semget", "semctl", "semtimedop", 0, 0, 0, 0, 0, 0, | |
| 179 "msgsnd", "msgrcv", "msgget", "msgctl", 0, 0, 0, 0, 0, 0, | |
| 180 "shmat", "shmdt", "shmget", "shmctl" }; | |
| 181 if (call >= 1 && call < (int)(sizeof(ipc_name)/sizeof(char *)) && | |
| 182 ipc_name[call]) { | |
| 183 strcat(strcpy(extra, " "), ipc_name[call]); | |
| 184 } else { | |
| 185 itoa(strcpy(extra, " #") + 2, call); | |
| 186 } | |
| 187 } | |
| 188 #endif | |
| 189 #else | |
| 190 static const char *extra = ""; | |
| 191 #endif | |
| 192 char buf[strlen(sysname) + strlen(extra) + (msg ? strlen(msg) : 0) + 4]; | |
| 193 strcat(strcat(strcat(strcat(strcpy(buf, sysname), extra), ": "), | |
| 194 msg ? msg : ""), "\n"); | |
| 195 message(buf); | |
| 196 } | 307 } |
| 197 } | 308 } |
| 198 | 309 |
| 199 char* Debug::itoa(char* s, int n) { | 310 char* Debug::itoa(char* s, int n) { |
| 200 // Remember return value | 311 // Remember return value |
| 201 char *ret = s; | 312 char *ret = s; |
| 202 | 313 |
| 203 // Insert sign for negative numbers | 314 // Insert sign for negative numbers |
| 204 if (n < 0) { | 315 if (n < 0) { |
| 205 *s++ = '-'; | 316 *s++ = '-'; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 217 // Reverse order of digits | 328 // Reverse order of digits |
| 218 while (start < s) { | 329 while (start < s) { |
| 219 char ch = *s; | 330 char ch = *s; |
| 220 *s-- = *start; | 331 *s-- = *start; |
| 221 *start++ = ch; | 332 *start++ = ch; |
| 222 } | 333 } |
| 223 | 334 |
| 224 return ret; | 335 return ret; |
| 225 } | 336 } |
| 226 | 337 |
| 338 void Debug::elapsed(long long tm, int sysnum, int call) { |
| 339 if (enabled_) { |
| 340 if (enter()) { |
| 341 // Compute the time that has passed since the system call started. |
| 342 long long delta; |
| 343 gettimeofday(&delta); |
| 344 delta -= tm; |
| 345 |
| 346 // Format "Elapsed time: %d.%03dms" without using sprintf(). |
| 347 char buf[80]; |
| 348 itoa(strrchr(strcpy(buf, "Elapsed time: "), '\000'), delta/1000); |
| 349 delta %= 1000; |
| 350 strcat(buf, delta < 100 ? delta < 10 ? ".00" : ".0" : "."); |
| 351 itoa(strrchr(buf, '\000'), delta); |
| 352 strcat(buf, "ms"); |
| 353 |
| 354 // Print system call name and elapsed time. |
| 355 syscall(NULL, sysnum, buf, call); |
| 356 } |
| 357 leave(); |
| 358 } |
| 359 } |
| 360 |
| 227 } // namespace | 361 } // namespace |
| 228 | 362 |
| 229 #endif // NDEBUG | 363 #endif // NDEBUG |
| OLD | NEW |