-
Notifications
You must be signed in to change notification settings - Fork 4
/
debug.js
217 lines (189 loc) · 6.78 KB
/
debug.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Copyright (C) 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview An optional part of the SES initialization process
* that saves potentially valuable debugging aids on the side before
* startSES.js would remove these, and adds a debugging API which uses
* these without compromising SES security.
*
* <p>NOTE: The currently exposed debugging API is far from
* settled. This module is currently in an exploratory phase.
*
* <p>Meant to be run sometime after repairs are done and a working
* WeakMap is available, but before startSES.js. initSES.js includes
* this. initSESPlus.js does not.
*
* //provides ses.UnsafeError,
* //provides ses.getCWStack ses.stackString ses.getStack
* @author Mark S. Miller
* @requires WeakMap, this
* @overrides Error, ses, debugModule
*/
var Error;
var ses;
(function debugModule(global) {
"use strict";
/**
* Save away the original Error constructor as ses.UnsafeError and
* make it otherwise unreachable. Replace it with a reachable
* wrapping constructor with the same standard behavior.
*
* <p>When followed by the rest of SES initialization, the
* UnsafeError we save off here is exempt from whitelist-based
* extra property removal and primordial freezing. Thus, we can
* use any platform specific APIs defined on Error for privileged
* debugging operations, unless explicitly turned off below.
*/
var UnsafeError = Error;
ses.UnsafeError = Error;
function FakeError(message) {
return UnsafeError(message);
}
FakeError.prototype = UnsafeError.prototype;
FakeError.prototype.constructor = FakeError;
Error = FakeError;
/**
* Should be a function of an argument object (normally an error
* instance) that returns the stack trace associated with argument
* in Causeway format.
*
* <p>See http://wiki.erights.org/wiki/Causeway_Platform_Developer
*
* <p>Currently, there is no one portable technique for doing
* this. So instead, each platform specific branch of the if below
* should assign something useful to getCWStack.
*/
ses.getCWStack = function uselessGetCWStack(err) { return void 0; };
if ('captureStackTrace' in UnsafeError) {
(function() {
// Assuming http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
// So this section is v8 specific.
UnsafeError.prepareStackTrace = function(err, sst) {
ssts.set(err, sst);
return void 0;
};
var unsafeCaptureStackTrace = UnsafeError.captureStackTrace;
// TODO(erights): This seems to be write only. Can this be made
// safe enough to expose to untrusted code?
UnsafeError.captureStackTrace = function(obj, opt_MyError) {
var wasFrozen = Object.isFrozen(obj);
var stackDesc = Object.getOwnPropertyDescriptor(obj, 'stack');
try {
var result = unsafeCaptureStackTrace(obj, opt_MyError);
var ignore = obj.stack;
return result;
} finally {
if (wasFrozen && !Object.isFrozen(obj)) {
if (stackDesc) {
Object.defineProperty(obj, 'stack', stackDesc);
} else {
delete obj.stack;
}
Object.freeze(obj);
}
}
};
var ssts = WeakMap(); // error -> sst
/**
* Returns a stack in Causeway format.
*
* <p>Based on
* http://code.google.com/p/causeway/source/browse/trunk/src/js/com/teleometry/causeway/purchase_example/workers/makeCausewayLogger.js
*/
function getCWStack(err) {
var sst = ssts.get(err);
if (sst === void 0 && err instanceof Error) {
// We hope it triggers prepareStackTrace
var ignore = err.stack;
sst = ssts.get(err);
}
if (sst === void 0) { return void 0; }
return { calls: sst.map(function(frame) {
return {
name: '' + (frame.getFunctionName() ||
frame.getMethodName() || '?'),
source: '' + (frame.getFileName() || '?'),
span: [ [ frame.getLineNumber(), frame.getColumnNumber() ] ]
};
})};
};
ses.getCWStack = getCWStack;
})();
} else if (global.opera) {
(function() {
// Since pre-ES5 browsers are disqualified, we can assume a
// minimum of Opera 11.60.
})();
} else if (new Error().stack) {
(function() {
var FFFramePattern = (/^([^@]*)@(.*?):?(\d*)$/);
// stacktracejs.org suggests that this indicates FF. Really?
function getCWStack(err) {
var stack = err.stack;
if (!stack) { return void 0; }
var lines = stack.split('\n');
var frames = lines.map(function(line) {
var match = FFFramePattern.exec(line);
if (match) {
return {
name: match[1].trim() || '?',
source: match[2].trim() || '?',
span: [[+match[3]]]
};
} else {
return {
name: line.trim() || '?',
source: '?',
span: []
};
}
});
return { calls: frames };
}
ses.getCWStack = getCWStack;
})();
} else {
(function() {
// Including Safari and IE10.
})();
}
/**
* Turn a Causeway stack into a v8-like stack traceback string.
*/
function stackString(cwStack) {
if (!cwStack) { return void 0; }
var calls = cwStack.calls;
var result = calls.map(function(call) {
var spanString = call.span.map(function(subSpan) {
return subSpan.join(':');
}).join('::');
if (spanString) { spanString = ':' + spanString; }
return ' at ' + call.name + ' (' + call.source + spanString + ')';
});
return result.join('\n');
};
ses.stackString = stackString;
/**
* Return the v8-like stack traceback string associated with err.
*/
function getStack(err) {
if (err !== Object(err)) { return void 0; }
var cwStack = ses.getCWStack(err);
if (!cwStack) { return void 0; }
var result = ses.stackString(cwStack);
if (err instanceof Error) { result = err + '\n' + result; }
return result;
};
ses.getStack = getStack;
})(this);