]> git.saurik.com Git - apple/javascriptcore.git/blame - interpreter/VMInspector.cpp
JavaScriptCore-1218.0.1.tar.gz
[apple/javascriptcore.git] / interpreter / VMInspector.cpp
CommitLineData
93a37866
A
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)