~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/js/src/xpconnect/src/xpcdebug.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 * ***** BEGIN LICENSE BLOCK *****
 
4
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
5
 *
 
6
 * The contents of this file are subject to the Mozilla Public License Version
 
7
 * 1.1 (the "License"); you may not use this file except in compliance with
 
8
 * the License. You may obtain a copy of the License at
 
9
 * http://www.mozilla.org/MPL/
 
10
 *
 
11
 * Software distributed under the License is distributed on an "AS IS" basis,
 
12
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
13
 * for the specific language governing rights and limitations under the
 
14
 * License.
 
15
 *
 
16
 * The Original Code is Mozilla Communicator client code, released
 
17
 * March 31, 1998.
 
18
 *
 
19
 * The Initial Developer of the Original Code is
 
20
 * Netscape Communications Corporation.
 
21
 * Portions created by the Initial Developer are Copyright (C) 1999
 
22
 * the Initial Developer. All Rights Reserved.
 
23
 *
 
24
 * Contributor(s):
 
25
 *   John Bandhauer <jband@netscape.com> (original author)
 
26
 *
 
27
 * Alternatively, the contents of this file may be used under the terms of
 
28
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 
29
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
30
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
31
 * of those above. If you wish to allow use of your version of this file only
 
32
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
33
 * use your version of this file under the terms of the MPL, indicate your
 
34
 * decision by deleting the provisions above and replace them with the notice
 
35
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
36
 * the provisions above, a recipient may use your version of this file under
 
37
 * the terms of any one of the MPL, the GPL or the LGPL.
 
38
 *
 
39
 * ***** END LICENSE BLOCK ***** */
 
40
 
 
41
#include "xpcprivate.h"
 
42
#if defined(DEBUG_xpc_hacker) || defined(DEBUG)
 
43
 
 
44
#ifdef TAB
 
45
#undef TAB
 
46
#endif
 
47
#define TAB "    "
 
48
 
 
49
static const char* JSVAL2String(JSContext* cx, jsval val, JSBool* isString)
 
50
{
 
51
    const char* value = nsnull;
 
52
    JSString* value_str = JS_ValueToString(cx, val);
 
53
    if(value_str)
 
54
        value = JS_GetStringBytes(value_str);
 
55
    if(value)
 
56
    {
 
57
        const char* found = strstr(value, "function ");
 
58
        if(found && (value == found || value+1 == found || value+2 == found))
 
59
            value = "[function]";
 
60
    }
 
61
 
 
62
    if(isString)
 
63
        *isString = JSVAL_IS_STRING(val);
 
64
    return value;
 
65
}
 
66
 
 
67
static char* FormatJSFrame(JSContext* cx, JSStackFrame* fp,
 
68
                           char* buf, int num,
 
69
                           JSBool showArgs, JSBool showLocals, JSBool showThisProps)
 
70
{
 
71
    if(JS_IsNativeFrame(cx, fp))
 
72
        return JS_sprintf_append(buf, "%d [native frame]\n", num);
 
73
 
 
74
    JSPropertyDescArray callProps = {0, nsnull};
 
75
    JSPropertyDescArray thisProps = {0, nsnull};
 
76
    JSObject* thisObj = nsnull;
 
77
    JSObject* callObj = nsnull;
 
78
    const char* funname = nsnull;
 
79
    const char* filename = nsnull;
 
80
    PRInt32 lineno = 0;
 
81
    JSFunction* fun = nsnull;
 
82
    uint32 namedArgCount = 0;
 
83
    jsval val;
 
84
    const char* name;
 
85
    const char* value;
 
86
    JSBool isString;
 
87
 
 
88
    // get the info for this stack frame
 
89
 
 
90
    JSScript* script = JS_GetFrameScript(cx, fp);
 
91
    jsbytecode* pc = JS_GetFramePC(cx, fp);
 
92
    if(script && pc)
 
93
    {
 
94
        filename = JS_GetScriptFilename(cx, script);
 
95
        lineno =  (PRInt32) JS_PCToLineNumber(cx, script, pc);
 
96
        fun = JS_GetFrameFunction(cx, fp);
 
97
        if(fun)
 
98
            funname = JS_GetFunctionName(fun);
 
99
 
 
100
        if(showArgs || showLocals)
 
101
        {
 
102
            callObj = JS_GetFrameCallObject(cx, fp);
 
103
            if(callObj)
 
104
                if(!JS_GetPropertyDescArray(cx, callObj, &callProps))
 
105
                    callProps.array = nsnull;  // just to be sure
 
106
        }
 
107
 
 
108
        thisObj = JS_GetFrameThis(cx, fp);
 
109
        if(showThisProps)
 
110
        {
 
111
            if(thisObj)
 
112
                if(!JS_GetPropertyDescArray(cx, thisObj, &thisProps))
 
113
                    thisProps.array = nsnull;  // just to be sure
 
114
        }
 
115
    }
 
116
 
 
117
    // print the frame number and function name
 
118
 
 
119
    if(funname)
 
120
        buf = JS_sprintf_append(buf, "%d %s(", num, funname);
 
121
    else if(fun)
 
122
        buf = JS_sprintf_append(buf, "%d anonymous(", num);
 
123
    else
 
124
        buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num);
 
125
    if(!buf) goto out;
 
126
 
 
127
    // print the function arguments
 
128
 
 
129
    if(showArgs && callObj)
 
130
    {
 
131
        for(uint32 i = 0; i < callProps.length; i++)
 
132
        {
 
133
            JSPropertyDesc* desc = &callProps.array[i];
 
134
            if(desc->flags & JSPD_ARGUMENT)
 
135
            {
 
136
                name = JSVAL2String(cx, desc->id, &isString);
 
137
                if(!isString)
 
138
                    name = nsnull;
 
139
                value = JSVAL2String(cx, desc->value, &isString);
 
140
 
 
141
                buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
 
142
                                        namedArgCount ? ", " : "",
 
143
                                        name ? name :"",
 
144
                                        name ? " = " : "",
 
145
                                        isString ? "\"" : "",
 
146
                                        value ? value : "?unknown?",
 
147
                                        isString ? "\"" : "");
 
148
                if(!buf) goto out;
 
149
                namedArgCount++;
 
150
            }
 
151
        }
 
152
 
 
153
        // print any unnamed trailing args (found in 'arguments' object)
 
154
 
 
155
        if(JS_GetProperty(cx, callObj, "arguments", &val) &&
 
156
           JSVAL_IS_OBJECT(val))
 
157
        {
 
158
            uint32 argCount;
 
159
            JSObject* argsObj = JSVAL_TO_OBJECT(val);
 
160
            if(JS_GetProperty(cx, argsObj, "length", &val) &&
 
161
               JS_ValueToECMAUint32(cx, val, &argCount) &&
 
162
               argCount > namedArgCount)
 
163
            {
 
164
                for(uint32 k = namedArgCount; k < argCount; k++)
 
165
                {
 
166
                    char number[8];
 
167
                    JS_snprintf(number, 8, "%d", (int) k);
 
168
 
 
169
                    if(JS_GetProperty(cx, argsObj, number, &val))
 
170
                    {
 
171
                        value = JSVAL2String(cx, val, &isString);
 
172
                        buf = JS_sprintf_append(buf, "%s%s%s%s",
 
173
                                        k ? ", " : "",
 
174
                                        isString ? "\"" : "",
 
175
                                        value ? value : "?unknown?",
 
176
                                        isString ? "\"" : "");
 
177
                        if(!buf) goto out;
 
178
                    }
 
179
                }
 
180
            }
 
181
        }
 
182
    }
 
183
 
 
184
    // print filename and line number
 
185
 
 
186
    buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
 
187
                            fun ? ")" : "",
 
188
                            filename ? filename : "<unknown>",
 
189
                            lineno);
 
190
    if(!buf) goto out;
 
191
 
 
192
    // print local variables
 
193
 
 
194
    if(showLocals && callProps.array)
 
195
    {
 
196
        for(uint32 i = 0; i < callProps.length; i++)
 
197
        {
 
198
            JSPropertyDesc* desc = &callProps.array[i];
 
199
            if(desc->flags & JSPD_VARIABLE)
 
200
            {
 
201
                name = JSVAL2String(cx, desc->id, nsnull);
 
202
                value = JSVAL2String(cx, desc->value, &isString);
 
203
 
 
204
                if(name && value)
 
205
                {
 
206
                    buf = JS_sprintf_append(buf, TAB "%s = %s%s%s\n",
 
207
                                            name,
 
208
                                            isString ? "\"" : "",
 
209
                                            value,
 
210
                                            isString ? "\"" : "");
 
211
                    if(!buf) goto out;
 
212
                }
 
213
            }
 
214
        }
 
215
    }
 
216
 
 
217
    // print the value of 'this'
 
218
 
 
219
    if(showLocals && thisObj)
 
220
    {
 
221
        jsval thisJSVal = OBJECT_TO_JSVAL(thisObj);
 
222
        JSString* thisValStr;
 
223
        char* thisVal;
 
224
 
 
225
        if(nsnull != (thisValStr = JS_ValueToString(cx, thisJSVal)) &&
 
226
           nsnull != (thisVal = JS_GetStringBytes(thisValStr)))
 
227
        {
 
228
            buf = JS_sprintf_append(buf, TAB "this = %s\n", thisVal);
 
229
            if(!buf) goto out;
 
230
        }
 
231
    }
 
232
 
 
233
    // print the properties of 'this'
 
234
 
 
235
    if(showThisProps && thisProps.array)
 
236
    {
 
237
 
 
238
        for(uint32 i = 0; i < thisProps.length; i++)
 
239
        {
 
240
            JSPropertyDesc* desc = &thisProps.array[i];
 
241
            if(desc->flags & JSPD_ENUMERATE)
 
242
            {
 
243
 
 
244
                name = JSVAL2String(cx, desc->id, nsnull);
 
245
                value = JSVAL2String(cx, desc->value, &isString);
 
246
                if(name && value)
 
247
                {
 
248
                    buf = JS_sprintf_append(buf, TAB "this.%s = %s%s%s\n",
 
249
                                            name,
 
250
                                            isString ? "\"" : "",
 
251
                                            value,
 
252
                                            isString ? "\"" : "");
 
253
                    if(!buf) goto out;
 
254
                }
 
255
            }
 
256
        }
 
257
    }
 
258
 
 
259
out:
 
260
    if(callProps.array)
 
261
        JS_PutPropertyDescArray(cx, &callProps);
 
262
    if(thisProps.array)
 
263
        JS_PutPropertyDescArray(cx, &thisProps);
 
264
    return buf;
 
265
}
 
266
 
 
267
static char* FormatJSStackDump(JSContext* cx, char* buf,
 
268
                               JSBool showArgs, JSBool showLocals,
 
269
                               JSBool showThisProps)
 
270
{
 
271
    JSStackFrame* fp;
 
272
    JSStackFrame* iter = nsnull;
 
273
    int num = 0;
 
274
 
 
275
    while(nsnull != (fp = JS_FrameIterator(cx, &iter)))
 
276
    {
 
277
        buf = FormatJSFrame(cx, fp, buf, num, showArgs, showLocals, showThisProps);
 
278
        num++;
 
279
    }
 
280
 
 
281
    if(!num)
 
282
        buf = JS_sprintf_append(buf, "JavaScript stack is empty\n");
 
283
 
 
284
    return buf;
 
285
}
 
286
 
 
287
JSBool
 
288
xpc_DumpJSStack(JSContext* cx, JSBool showArgs, JSBool showLocals, JSBool showThisProps)
 
289
{
 
290
    char* buf;
 
291
 
 
292
    buf = FormatJSStackDump(cx, nsnull, showArgs, showLocals, showThisProps);
 
293
    if(buf)
 
294
    {
 
295
        printf(buf);
 
296
        JS_smprintf_free(buf);
 
297
    }
 
298
    else
 
299
        printf("Failed to format JavaScript stack for dump\n");
 
300
    return JS_TRUE;
 
301
}
 
302
 
 
303
/***************************************************************************/
 
304
 
 
305
JS_STATIC_DLL_CALLBACK(void)
 
306
xpcDumpEvalErrorReporter(JSContext *cx, const char *message,
 
307
                         JSErrorReport *report)
 
308
{
 
309
    printf("Error: %s\n", message);
 
310
}
 
311
 
 
312
JSBool
 
313
xpc_DumpEvalInJSStackFrame(JSContext* cx, JSUint32 frameno, const char* text)
 
314
{
 
315
    JSStackFrame* fp;
 
316
    JSStackFrame* iter = nsnull;
 
317
    JSUint32 num = 0;
 
318
 
 
319
    if(!cx || !text)
 
320
    {
 
321
        printf("invalid params passed to xpc_DumpEvalInJSStackFrame!\n");
 
322
        return JS_FALSE;
 
323
    }
 
324
 
 
325
    printf("js[%d]> %s\n", frameno, text);
 
326
 
 
327
    while(nsnull != (fp = JS_FrameIterator(cx, &iter)))
 
328
    {
 
329
        if(num == frameno)
 
330
            break;
 
331
        num++;
 
332
    }
 
333
 
 
334
    if(!fp)
 
335
    {
 
336
        printf("invalid frame number!\n");
 
337
        return JS_FALSE;
 
338
    }
 
339
 
 
340
    JSExceptionState* exceptionState = JS_SaveExceptionState(cx);
 
341
    JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter);
 
342
 
 
343
    jsval rval;
 
344
    JSString* str;
 
345
    const char* chars;
 
346
    if(JS_EvaluateInStackFrame(cx, fp, text, strlen(text), "eval", 1, &rval) &&
 
347
       nsnull != (str = JS_ValueToString(cx, rval)) &&
 
348
       nsnull != (chars = JS_GetStringBytes(str)))
 
349
    {
 
350
        printf("%s\n", chars);
 
351
    }
 
352
    else
 
353
        printf("eval failed!\n");
 
354
    JS_SetErrorReporter(cx, older);
 
355
    JS_RestoreExceptionState(cx, exceptionState);
 
356
    return JS_TRUE;
 
357
}
 
358
 
 
359
/***************************************************************************/
 
360
 
 
361
JSTrapStatus JS_DLL_CALLBACK
 
362
xpc_DebuggerKeywordHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
 
363
                           jsval *rval, void *closure)
 
364
{
 
365
    static const char line[] =
 
366
    "------------------------------------------------------------------------\n";
 
367
    printf(line);
 
368
    printf("Hit JavaScript \"debugger\" keyword. JS call stack...\n");
 
369
    xpc_DumpJSStack(cx, JS_TRUE, JS_TRUE, JS_FALSE);
 
370
    printf(line);
 
371
    return JSTRAP_CONTINUE;
 
372
}
 
373
 
 
374
JSBool xpc_InstallJSDebuggerKeywordHandler(JSRuntime* rt)
 
375
{
 
376
    return JS_SetDebuggerHandler(rt, xpc_DebuggerKeywordHandler, nsnull);
 
377
}
 
378
 
 
379
/***************************************************************************/
 
380
 
 
381
// The following will dump info about an object to stdout...
 
382
 
 
383
 
 
384
// Quick and dirty (debug only damnit!) class to track which JSObjects have
 
385
// been visited as we traverse.
 
386
 
 
387
class ObjectPile
 
388
{
 
389
public:
 
390
    enum result {primary, seen, overflow};
 
391
 
 
392
    result Visit(JSObject* obj)
 
393
    {
 
394
        if(member_count == max_count)
 
395
            return overflow;
 
396
        for(int i = 0; i < member_count; i++)
 
397
            if(array[i] == obj)
 
398
                return seen;
 
399
        array[member_count++] = obj;
 
400
        return primary;
 
401
    }
 
402
 
 
403
    ObjectPile() : member_count(0){}
 
404
 
 
405
private:
 
406
    enum {max_count = 50};
 
407
    JSObject* array[max_count];
 
408
    int member_count;
 
409
};
 
410
 
 
411
 
 
412
static const int tab_width = 2;
 
413
#define INDENT(_d) (_d)*tab_width, " "
 
414
 
 
415
static void PrintObjectBasics(JSObject* obj)
 
416
{
 
417
    if(OBJ_IS_NATIVE(obj))
 
418
        printf("%#p 'native' <%s>",
 
419
               obj,
 
420
               ((JSClass*)(obj->slots[JSSLOT_CLASS]-1))->name);
 
421
    else
 
422
        printf("%#p 'host'", obj);
 
423
 
 
424
}
 
425
 
 
426
static void PrintObject(JSObject* obj, int depth, ObjectPile* pile)
 
427
{
 
428
    PrintObjectBasics(obj);
 
429
 
 
430
    switch(pile->Visit(obj))
 
431
    {
 
432
    case ObjectPile::primary:
 
433
        printf("\n");
 
434
        break;
 
435
    case ObjectPile::seen:
 
436
        printf(" (SEE ABOVE)\n");
 
437
        return;
 
438
    case ObjectPile::overflow:
 
439
        printf(" (TOO MANY OBJECTS)\n");
 
440
        return;
 
441
    }
 
442
 
 
443
    if(!OBJ_IS_NATIVE(obj))
 
444
        return;
 
445
 
 
446
    JSObject* parent = (JSObject*)(obj->slots[JSSLOT_PARENT]);
 
447
    JSObject* proto  = (JSObject*)(obj->slots[JSSLOT_PROTO]);
 
448
 
 
449
    printf("%*sparent: ", INDENT(depth+1));
 
450
    if(parent)
 
451
        PrintObject(parent, depth+1, pile);
 
452
    else
 
453
        printf("null\n");
 
454
    printf("%*sproto: ", INDENT(depth+1));
 
455
    if(proto)
 
456
        PrintObject(proto, depth+1, pile);
 
457
    else
 
458
        printf("null\n");
 
459
}
 
460
 
 
461
JSBool
 
462
xpc_DumpJSObject(JSObject* obj)
 
463
{
 
464
    ObjectPile pile;
 
465
 
 
466
    printf("Debugging reminders...\n");
 
467
    printf("  class:  (JSClass*)(obj->slots[2]-1)\n");
 
468
    printf("  parent: (JSObject*)(obj->slots[1])\n");
 
469
    printf("  proto:  (JSObject*)(obj->slots[0])\n");
 
470
    printf("\n");
 
471
 
 
472
    if(obj)
 
473
        PrintObject(obj, 0, &pile);
 
474
    else
 
475
        printf("xpc_DumpJSObject passed null!\n");
 
476
 
 
477
    return JS_TRUE;
 
478
}
 
479
#endif