Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame^] | 1 | // Copyright 2008 the V8 project authors. All rights reserved. |
| 2 | // Redistribution and use in source and binary forms, with or without |
| 3 | // modification, are permitted provided that the following conditions are |
| 4 | // met: |
| 5 | // |
| 6 | // * Redistributions of source code must retain the above copyright |
| 7 | // notice, this list of conditions and the following disclaimer. |
| 8 | // * Redistributions in binary form must reproduce the above |
| 9 | // copyright notice, this list of conditions and the following |
| 10 | // disclaimer in the documentation and/or other materials provided |
| 11 | // with the distribution. |
| 12 | // * Neither the name of Google Inc. nor the names of its |
| 13 | // contributors may be used to endorse or promote products derived |
| 14 | // from this software without specific prior written permission. |
| 15 | // |
| 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | |
| 28 | // Flags: --expose-debug-as debug |
| 29 | // The functions used for testing backtraces. They are at the top to make the |
| 30 | // testing of source line/column easier. |
| 31 | function f(x, y) { |
| 32 | a=1; |
| 33 | }; |
| 34 | |
| 35 | var m = function() { |
| 36 | new f(1); |
| 37 | }; |
| 38 | |
| 39 | function g() { |
| 40 | m(); |
| 41 | }; |
| 42 | |
| 43 | |
| 44 | // Get the Debug object exposed from the debug context global object. |
| 45 | Debug = debug.Debug |
| 46 | |
| 47 | listenerCalled = false; |
| 48 | exception = false; |
| 49 | |
| 50 | |
| 51 | function ParsedResponse(json) { |
| 52 | this.response_ = eval('(' + json + ')'); |
| 53 | this.refs_ = []; |
| 54 | if (this.response_.refs) { |
| 55 | for (var i = 0; i < this.response_.refs.length; i++) { |
| 56 | this.refs_[this.response_.refs[i].handle] = this.response_.refs[i]; |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | |
| 62 | ParsedResponse.prototype.response = function() { |
| 63 | return this.response_; |
| 64 | } |
| 65 | |
| 66 | |
| 67 | ParsedResponse.prototype.body = function() { |
| 68 | return this.response_.body; |
| 69 | } |
| 70 | |
| 71 | |
| 72 | ParsedResponse.prototype.lookup = function(handle) { |
| 73 | return this.refs_[handle]; |
| 74 | } |
| 75 | |
| 76 | |
| 77 | function listener(event, exec_state, event_data, data) { |
| 78 | try { |
| 79 | if (event == Debug.DebugEvent.Break) { |
| 80 | // The expected backtrace is |
| 81 | // 0: f |
| 82 | // 1: m |
| 83 | // 2: g |
| 84 | // 3: [anonymous] |
| 85 | |
| 86 | var response; |
| 87 | var backtrace; |
| 88 | var frame; |
| 89 | var source; |
| 90 | |
| 91 | // Get the debug command processor. |
| 92 | var dcp = exec_state.debugCommandProcessor(); |
| 93 | |
| 94 | // Get the backtrace. |
| 95 | var json; |
| 96 | json = '{"seq":0,"type":"request","command":"backtrace"}' |
| 97 | var resp = dcp.processDebugJSONRequest(json); |
| 98 | response = new ParsedResponse(resp); |
| 99 | backtrace = response.body(); |
| 100 | assertEquals(0, backtrace.fromFrame); |
| 101 | assertEquals(4, backtrace.toFrame); |
| 102 | assertEquals(4, backtrace.totalFrames); |
| 103 | var frames = backtrace.frames; |
| 104 | assertEquals(4, frames.length); |
| 105 | for (var i = 0; i < frames.length; i++) { |
| 106 | assertEquals('frame', frames[i].type); |
| 107 | } |
| 108 | assertEquals(0, frames[0].index); |
| 109 | assertEquals("f", response.lookup(frames[0].func.ref).name); |
| 110 | assertEquals(1, frames[1].index); |
| 111 | assertEquals("", response.lookup(frames[1].func.ref).name); |
| 112 | assertEquals("m", response.lookup(frames[1].func.ref).inferredName); |
| 113 | assertEquals(2, frames[2].index); |
| 114 | assertEquals("g", response.lookup(frames[2].func.ref).name); |
| 115 | assertEquals(3, frames[3].index); |
| 116 | assertEquals("", response.lookup(frames[3].func.ref).name); |
| 117 | |
| 118 | // Get backtrace with two frames. |
| 119 | json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":1,"toFrame":3}}' |
| 120 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 121 | backtrace = response.body(); |
| 122 | assertEquals(1, backtrace.fromFrame); |
| 123 | assertEquals(3, backtrace.toFrame); |
| 124 | assertEquals(4, backtrace.totalFrames); |
| 125 | var frames = backtrace.frames; |
| 126 | assertEquals(2, frames.length); |
| 127 | for (var i = 0; i < frames.length; i++) { |
| 128 | assertEquals('frame', frames[i].type); |
| 129 | } |
| 130 | assertEquals(1, frames[0].index); |
| 131 | assertEquals("", response.lookup(frames[0].func.ref).name); |
| 132 | assertEquals("m", response.lookup(frames[0].func.ref).inferredName); |
| 133 | assertEquals(2, frames[1].index); |
| 134 | assertEquals("g", response.lookup(frames[1].func.ref).name); |
| 135 | |
| 136 | // Get backtrace with bottom two frames. |
| 137 | json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":0,"toFrame":2, "bottom":true}}' |
| 138 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 139 | backtrace = response.body(); |
| 140 | assertEquals(2, backtrace.fromFrame); |
| 141 | assertEquals(4, backtrace.toFrame); |
| 142 | assertEquals(4, backtrace.totalFrames); |
| 143 | var frames = backtrace.frames; |
| 144 | assertEquals(2, frames.length); |
| 145 | for (var i = 0; i < frames.length; i++) { |
| 146 | assertEquals('frame', frames[i].type); |
| 147 | } |
| 148 | assertEquals(2, frames[0].index); |
| 149 | assertEquals("g", response.lookup(frames[0].func.ref).name); |
| 150 | assertEquals(3, frames[1].index); |
| 151 | assertEquals("", response.lookup(frames[1].func.ref).name); |
| 152 | |
| 153 | // Get the individual frames. |
| 154 | json = '{"seq":0,"type":"request","command":"frame"}' |
| 155 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 156 | frame = response.body(); |
| 157 | assertEquals(0, frame.index); |
| 158 | assertEquals("f", response.lookup(frame.func.ref).name); |
| 159 | assertTrue(frame.constructCall); |
| 160 | assertEquals(31, frame.line); |
| 161 | assertEquals(3, frame.column); |
| 162 | assertEquals(2, frame.arguments.length); |
| 163 | assertEquals('x', frame.arguments[0].name); |
| 164 | assertEquals('number', response.lookup(frame.arguments[0].value.ref).type); |
| 165 | assertEquals(1, response.lookup(frame.arguments[0].value.ref).value); |
| 166 | assertEquals('y', frame.arguments[1].name); |
| 167 | assertEquals('undefined', response.lookup(frame.arguments[1].value.ref).type); |
| 168 | |
| 169 | json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":0}}' |
| 170 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 171 | frame = response.body(); |
| 172 | assertEquals(0, frame.index); |
| 173 | assertEquals("f", response.lookup(frame.func.ref).name); |
| 174 | assertEquals(31, frame.line); |
| 175 | assertEquals(3, frame.column); |
| 176 | assertEquals(2, frame.arguments.length); |
| 177 | assertEquals('x', frame.arguments[0].name); |
| 178 | assertEquals('number', response.lookup(frame.arguments[0].value.ref).type); |
| 179 | assertEquals(1, response.lookup(frame.arguments[0].value.ref).value); |
| 180 | assertEquals('y', frame.arguments[1].name); |
| 181 | assertEquals('undefined', response.lookup(frame.arguments[1].value.ref).type); |
| 182 | |
| 183 | json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":1}}' |
| 184 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 185 | frame = response.body(); |
| 186 | assertEquals(1, frame.index); |
| 187 | assertEquals("", response.lookup(frame.func.ref).name); |
| 188 | assertEquals("m", response.lookup(frame.func.ref).inferredName); |
| 189 | assertFalse(frame.constructCall); |
| 190 | assertEquals(35, frame.line); |
| 191 | assertEquals(2, frame.column); |
| 192 | assertEquals(0, frame.arguments.length); |
| 193 | |
| 194 | json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":3}}' |
| 195 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 196 | frame = response.body(); |
| 197 | assertEquals(3, frame.index); |
| 198 | assertEquals("", response.lookup(frame.func.ref).name); |
| 199 | |
| 200 | // Source slices for the individual frames (they all refer to this script). |
| 201 | json = '{"seq":0,"type":"request","command":"source",' + |
| 202 | '"arguments":{"frame":0,"fromLine":30,"toLine":32}}' |
| 203 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 204 | source = response.body(); |
| 205 | assertEquals("function f(x, y) {", source.source.substring(0, 18)); |
| 206 | assertEquals(30, source.fromLine); |
| 207 | assertEquals(32, source.toLine); |
| 208 | |
| 209 | json = '{"seq":0,"type":"request","command":"source",' + |
| 210 | '"arguments":{"frame":1,"fromLine":31,"toLine":32}}' |
| 211 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 212 | source = response.body(); |
| 213 | assertEquals(" a=1;", source.source.substring(0, 6)); |
| 214 | assertEquals(31, source.fromLine); |
| 215 | assertEquals(32, source.toLine); |
| 216 | |
| 217 | json = '{"seq":0,"type":"request","command":"source",' + |
| 218 | '"arguments":{"frame":2,"fromLine":35,"toLine":36}}' |
| 219 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 220 | source = response.body(); |
| 221 | assertEquals(" new f(1);", source.source.substring(0, 11)); |
| 222 | assertEquals(35, source.fromLine); |
| 223 | assertEquals(36, source.toLine); |
| 224 | |
| 225 | // Test line interval way beyond this script will result in an error. |
| 226 | json = '{"seq":0,"type":"request","command":"source",' + |
| 227 | '"arguments":{"frame":0,"fromLine":10000,"toLine":20000}}' |
| 228 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 229 | assertFalse(response.response().success); |
| 230 | |
| 231 | // Test without arguments. |
| 232 | json = '{"seq":0,"type":"request","command":"source"}' |
| 233 | response = new ParsedResponse(dcp.processDebugJSONRequest(json)); |
| 234 | source = response.body(); |
| 235 | assertEquals(Debug.findScript(f).source, source.source); |
| 236 | |
| 237 | listenerCalled = true; |
| 238 | } |
| 239 | } catch (e) { |
| 240 | exception = e |
| 241 | }; |
| 242 | }; |
| 243 | |
| 244 | // Add the debug event listener. |
| 245 | Debug.setListener(listener); |
| 246 | |
| 247 | // Set a break point and call to invoke the debug event listener. |
| 248 | Debug.setBreakPoint(f, 0, 0); |
| 249 | g(); |
| 250 | |
| 251 | // Make sure that the debug event listener vas invoked. |
| 252 | assertFalse(exception, "exception in listener"); |
| 253 | assertTrue(listenerCalled); |
| 254 | |