1/* 2 * Copyright (C) 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "VMInspector.h" 28 29#if ENABLE(VMINSPECTOR) 30 31#include <stdio.h> 32#include <wtf/ASCIICType.h> 33#include <wtf/text/WTFString.h> 34 35namespace JSC { 36 37const char* VMInspector::getTypeName(JSValue value) 38{ 39 if (value.isInt32()) 40 return "<Int32>"; 41 if (value.isBoolean()) 42 return "<Boolean>"; 43 if (value.isNull()) 44 return "<Empty>"; 45 if (value.isUndefined()) 46 return "<Undefined>"; 47 if (value.isCell()) 48 return "<Cell>"; 49 if (value.isEmpty()) 50 return "<Empty>"; 51 return ""; 52} 53 54void VMInspector::dumpFrame0(CallFrame* frame) 55{ 56 dumpFrame(frame, 0, 0, 0, 0); 57} 58 59void VMInspector::dumpFrame(CallFrame* frame, const char* prefix, 60 const char* funcName, const char* file, int line) 61{ 62 int frameCount = VMInspector::countFrames(frame); 63 if (frameCount < 0) 64 return; 65 66 Instruction* vPC = 0; 67 if (frame->codeBlock()) 68 vPC = frame->currentVPC(); 69 70 #define CAST reinterpret_cast 71 72 if (prefix) 73 printf("%s ", prefix); 74 75 printf("frame [%d] %p { cb %p:%s, retPC %p:%s, scope %p:%s, callee %p:%s, callerFrame %p:%s, argc %d, vPC %p }", 76 frameCount, frame, 77 CAST<void*>(frame[JSStack::CodeBlock].payload()), 78 getTypeName(frame[JSStack::CodeBlock].jsValue()), 79 CAST<void*>(frame[JSStack::ReturnPC].payload()), 80 getTypeName(frame[JSStack::ReturnPC].jsValue()), 81 CAST<void*>(frame[JSStack::ScopeChain].payload()), 82 getTypeName(frame[JSStack::ScopeChain].jsValue()), 83 CAST<void*>(frame[JSStack::Callee].payload()), 84 getTypeName(frame[JSStack::Callee].jsValue()), 85 CAST<void*>(frame[JSStack::CallerFrame].callFrame()), 86 getTypeName(frame[JSStack::CallerFrame].jsValue()), 87 frame[JSStack::ArgumentCount].payload(), 88 vPC); 89 90 if (funcName || file || (line >= 0)) { 91 printf(" @"); 92 if (funcName) 93 printf(" %s", funcName); 94 if (file) 95 printf(" %s", file); 96 if (line >= 0) 97 printf(":%d", line); 98 } 99 printf("\n"); 100} 101 102int VMInspector::countFrames(CallFrame* frame) 103{ 104 int count = -1; 105 while (frame && !frame->hasHostCallFrameFlag()) { 106 count++; 107 frame = frame->callerFrame(); 108 } 109 return count; 110} 111 112 113//============================================================================ 114// class FormatPrinter 115// - implements functionality to support fprintf. 116// 117// The FormatPrinter classes do the real formatting and printing. 118// By default, the superclass FormatPrinter will print to stdout (printf). 119// Each of the subclass will implement the other ...printf() options. 120// The subclasses are: 121// 122// FileFormatPrinter - fprintf 123// StringFormatPrinter - sprintf 124// StringNFormatPrinter - snprintf 125 126class FormatPrinter { 127public: 128 virtual ~FormatPrinter() { } 129 130 void print(const char* format, va_list args); 131 132protected: 133 // Low level printers: 134 bool printArg(const char* format, ...); 135 virtual bool printArg(const char* format, va_list args); 136 137 // JS type specific printers: 138 void printWTFString(va_list args, bool verbose); 139}; 140 141 142// The public print() function is the real workhorse behind the printf 143// family of functions. print() deciphers the % formatting, translate them 144// to primitive formats, and dispatches to underlying printArg() functions 145// to do the printing. 146// 147// The non-public internal printArg() function is virtual and is responsible 148// for handling the variations between printf, fprintf, sprintf, and snprintf. 149 150void FormatPrinter::print(const char* format, va_list args) 151{ 152 const char* p = format; 153 const char* errorStr; 154 155 // buffer is only used for 2 purposes: 156 // 1. To temporarily hold a copy of normal chars (not needing formatting) 157 // to be passed to printArg() and printed. 158 // 159 // The incoming format string may contain a string of normal chars much 160 // longer than 128, but we handle this by breaking them out to 128 chars 161 // fragments and printing each fragment before re-using the buffer to 162 // load up the next fragment. 163 // 164 // 2. To hold a single "%..." format to be passed to printArg() to process 165 // a single va_arg. 166 167 char buffer[129]; // 128 chars + null terminator. 168 char* end = &buffer[sizeof(buffer) - 1]; 169 const char* startOfFormatSpecifier = 0; 170 171 while (true) { 172 char c = *p++; 173 char* curr = buffer; 174 175 // Print leading normal chars: 176 while (c != '\0' && c != '%') { 177 *curr++ = c; 178 if (curr == end) { 179 // Out of buffer space. Flush the fragment, and start over. 180 *curr = '\0'; 181 bool success = printArg("%s", buffer); 182 if (!success) { 183 errorStr = buffer; 184 goto handleError; 185 } 186 curr = buffer; 187 } 188 c = *p++; 189 } 190 // If we have stuff in the buffer, flush the fragment: 191 if (curr != buffer) { 192 ASSERT(curr < end + 1); 193 *curr = '\0'; 194 bool success = printArg("%s", buffer); 195 if (!success) { 196 errorStr = buffer; 197 goto handleError; 198 } 199 } 200 201 // End if there are not more chars to print: 202 if (c == '\0') 203 break; 204 205 // If we get here, we've must have seen a '%': 206 startOfFormatSpecifier = p - 1; 207 ASSERT(*startOfFormatSpecifier == '%'); 208 c = *p++; 209 210 // Check for "%%" case: 211 if (c == '%') { 212 bool success = printArg("%c", '%'); 213 if (!success) { 214 errorStr = p - 2; 215 goto handleError; 216 } 217 continue; 218 } 219 220 // Check for JS (%J<x>) formatting extensions: 221 if (c == 'J') { 222 bool verbose = false; 223 224 c = *p++; 225 if (UNLIKELY(c == '\0')) { 226 errorStr = p - 2; // Rewind to % in "%J\0" 227 goto handleError; 228 } 229 230 if (c == '+') { 231 verbose = true; 232 c= *p++; 233 if (UNLIKELY(c == '\0')) { 234 errorStr = p - 3; // Rewind to % in "%J+\0" 235 goto handleError; 236 } 237 } 238 239 switch (c) { 240 // %Js - WTF::String* 241 case 's': { 242 printWTFString(args, verbose); 243 continue; 244 } 245 } // END switch. 246 247 // Check for non-JS extensions: 248 } else if (c == 'b') { 249 int value = va_arg(args, int); 250 printArg("%s", value ? "TRUE" : "FALSE"); 251 continue; 252 } 253 254 // If we didn't handle the format in one of the above cases, 255 // rewind p and let the standard formatting check handle it 256 // if possible: 257 p = startOfFormatSpecifier; 258 ASSERT(*p == '%'); 259 260 // Check for standard formatting: 261 // A format specifier always starts with a % and ends with some 262 // alphabet. We'll do the simple thing and scan until the next 263 // alphabet, or the end of string. 264 265 // In the following, we're going to use buffer as storage for a copy 266 // of a single format specifier. Hence, conceptually, we can think of 267 // 'buffer' as synonymous with 'argFormat' here: 268 269#define ABORT_IF_FORMAT_TOO_LONG(curr) \ 270 do { \ 271 if (UNLIKELY(curr >= end)) \ 272 goto formatTooLong; \ 273 } while (false) 274 275 curr = buffer; 276 *curr++ = *p++; // Output the first % in the format specifier. 277 c = *p++; // Grab the next char in the format specifier. 278 279 // Checks for leading modifiers e.g. "%-d": 280 // 0, -, ' ', +, '\'' 281 if (c == '0' || c == '-' || c == ' ' || c == '+' || c == '\'' || c == '#') { 282 ABORT_IF_FORMAT_TOO_LONG(curr); 283 *curr++ = c; 284 c = *p++; 285 } 286 287 // Checks for decimal digit field width modifiers e.g. "%2f": 288 while (c >= '0' && c <= '9') { 289 ABORT_IF_FORMAT_TOO_LONG(curr); 290 *curr++ = c; 291 c = *p++; 292 } 293 294 // Checks for '.' e.g. "%2.f": 295 if (c == '.') { 296 ABORT_IF_FORMAT_TOO_LONG(curr); 297 *curr++ = c; 298 c = *p++; 299 300 // Checks for decimal digit precision modifiers e.g. "%.2f": 301 while (c >= '0' && c <= '9') { 302 ABORT_IF_FORMAT_TOO_LONG(curr); 303 *curr++ = c; 304 c = *p++; 305 } 306 } 307 308 // Checks for the modifier <m> where <m> can be: 309 // l, h, j, t, z 310 // e.g. "%ld" 311 if (c == 'l' || c == 'h' || c == 'j' || c == 't' || c == 'z' || c == 'L') { 312 ABORT_IF_FORMAT_TOO_LONG(curr); 313 *curr++ = c; 314 char prevChar = c; 315 c = *p++; 316 317 // Checks for the modifier ll or hh in %<x><m>: 318 if ((prevChar == 'l' || prevChar == 'h') && c == prevChar) { 319 ABORT_IF_FORMAT_TOO_LONG(curr); 320 *curr++ = c; 321 c = *p++; 322 } 323 } 324 325 // Checks for %<x> where <x> can be: 326 // d, i, n, o, u, x, X 327 // But hey, we're just going to do the simple thing and allow any 328 // alphabet. The user is expected to pass correct format specifiers. 329 // We won't do any format checking here. We'll just pass it on, and the 330 // underlying ...printf() implementation may do the needed checking 331 // at its discretion. 332 while (c != '\0' && !isASCIIAlpha(c)) { 333 ABORT_IF_FORMAT_TOO_LONG(curr); 334 *curr++ = c; 335 c = *p++; 336 } 337 338 ABORT_IF_FORMAT_TOO_LONG(curr); 339 *curr++ = c; 340 if (c == '\0') { 341 // Uh oh. Bad format. We should have gotten an alphabet instead. 342 // Print the supposed format as a string instead: 343 errorStr = buffer; 344 goto handleError; 345 } 346 347 // Otherwise, we have the alpha that terminates the format. 348 // Terminate the buffer (i.e. argFormat) string: 349 ASSERT(isASCIIAlpha(c)); 350 ABORT_IF_FORMAT_TOO_LONG(curr); 351 *curr = '\0'; 352 353 bool success = printArg(buffer, args); 354 if (!success) { 355 errorStr = buffer; 356 goto handleError; 357 } 358 } 359#undef ABORT_IF_FORMAT_TOO_LONG 360 361 return; 362 363formatTooLong: 364 // Print the error string: 365 ASSERT(!!startOfFormatSpecifier); 366 p = startOfFormatSpecifier; 367 ASSERT(p >= format); 368 printArg("ERROR @ Format too long at \"%s\"\n", p); 369 return; 370 371handleError: 372 // We've got an error. Can't do any more work. Print an error message if 373 // possible and then just return. 374 375 // The errorStr may be pointing into the middle of buffer, or the original 376 // format string. Move the string to buffer for consistency, and also so 377 // that we can strip it of newlines below. 378 if (errorStr != buffer) { 379 size_t length = strlen(errorStr); 380 if (length > sizeof(buffer) - 1) 381 length = sizeof(buffer) - 1; 382 memmove(buffer, errorStr, length); 383 buffer[length] = '\0'; // Terminate the moved error string. 384 } 385 // Strip the newlines: 386 char* cp = buffer; 387 while (*cp) { 388 if (*cp == '\n' || *cp == '\r') 389 *cp = ' '; 390 cp++; 391 } 392 // Print the error string: 393 printArg("ERROR @ \"%s\"\n", buffer); 394} 395 396 397bool FormatPrinter::printArg(const char* format, ...) 398{ 399 va_list args; 400 va_start(args, format); 401 bool success = printArg(format, args); 402 va_end(args); 403 return success; 404} 405 406bool FormatPrinter::printArg(const char* format, va_list args) 407{ 408 int count = ::vprintf(format, args); 409 return (count >= 0); // Fail if less than 0 chars printed. 410} 411 412 413// %Js - WTF::String* 414// verbose mode prints: WTF::String "<your string>" 415void FormatPrinter::printWTFString(va_list args, bool verbose) 416{ 417 const String* str = va_arg(args, const String*); 418 419 // Print verbose header if appropriate: 420 if (verbose) 421 printArg("WTF::String \""); 422 423 // Print the string itself: 424 if (!str->isEmpty()) { 425 if (str->is8Bit()) { 426 const LChar* chars = str->characters8(); 427 printArg("%s", reinterpret_cast<const char*>(chars)); 428 } else { 429 const UChar* chars = str->characters16(); 430 printArg("%S", reinterpret_cast<const wchar_t*>(chars)); 431 } 432 } 433 434 // Print verbose footer if appropriate: 435 if (verbose) 436 printArg("\""); 437} 438 439 440//============================================================================ 441// class FileFormatPrinter 442// - implements functionality to support fprintf. 443 444class FileFormatPrinter: public FormatPrinter { 445public: 446 FileFormatPrinter(FILE*); 447private: 448 virtual bool printArg(const char* format, va_list args); 449 450 FILE* m_file; 451}; 452 453FileFormatPrinter::FileFormatPrinter(FILE* file) 454 : m_file(file) 455{ 456} 457 458bool FileFormatPrinter::printArg(const char* format, va_list args) 459{ 460 int count = ::vfprintf(m_file, format, args); 461 return (count >= 0); // Fail if less than 0 chars printed. 462} 463 464 465//============================================================================ 466// class StringFormatPrinter 467// - implements functionality to support sprintf. 468 469class StringFormatPrinter: public FormatPrinter { 470public: 471 StringFormatPrinter(char* buffer); 472private: 473 virtual bool printArg(const char* format, va_list args); 474 475 char* m_buffer; 476}; 477 478StringFormatPrinter::StringFormatPrinter(char* buffer) 479 : m_buffer(buffer) 480{ 481} 482 483bool StringFormatPrinter::printArg(const char* format, va_list args) 484{ 485 int count = ::vsprintf(m_buffer, format, args); 486 m_buffer += count; 487 return (count >= 0); // Fail if less than 0 chars printed. 488} 489 490 491//============================================================================ 492// class StringNFormatPrinter 493// - implements functionality to support snprintf. 494 495class StringNFormatPrinter: public FormatPrinter { 496public: 497 StringNFormatPrinter(char* buffer, size_t); 498private: 499 virtual bool printArg(const char* format, va_list args); 500 501 char* m_buffer; 502 size_t m_size; 503}; 504 505 506StringNFormatPrinter::StringNFormatPrinter(char* buffer, size_t size) 507 : m_buffer(buffer) 508 , m_size(size) 509{ 510} 511 512bool StringNFormatPrinter::printArg(const char* format, va_list args) 513{ 514 if (m_size > 0) { 515 int count = ::vsnprintf(m_buffer, m_size, format, args); 516 517 // According to vsnprintf specs, ... 518 bool success = (count >= 0); 519 if (static_cast<size_t>(count) >= m_size) { 520 // If count > size, then we didn't have enough buffer space. 521 count = m_size; 522 } 523 524 // Adjust the buffer to what's left if appropriate: 525 if (success) { 526 m_buffer += count; 527 m_size -= count; 528 } 529 return success; 530 } 531 // No more room to print. Declare it a fail: 532 return false; 533} 534 535 536//============================================================================ 537// VMInspector printf family of methods: 538 539void VMInspector::fprintf(FILE* file, const char* format, ...) 540{ 541 va_list args; 542 va_start(args, format); 543 FileFormatPrinter(file).print(format, args); 544 va_end(args); 545} 546 547void VMInspector::printf(const char* format, ...) 548{ 549 va_list args; 550 va_start(args, format); 551 FormatPrinter().print(format, args); 552 va_end(args); 553} 554 555void VMInspector::sprintf(char* buffer, const char* format, ...) 556{ 557 va_list args; 558 va_start(args, format); 559 StringFormatPrinter(buffer).print(format, args); 560 va_end(args); 561} 562 563void VMInspector::snprintf(char* buffer, size_t size, const char* format, ...) 564{ 565 va_list args; 566 va_start(args, format); 567 StringNFormatPrinter(buffer, size).print(format, args); 568 va_end(args); 569} 570 571} // namespace JSC 572 573#endif // ENABLE(VMINSPECTOR) 574