1// Copyright 2009 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// Get the Debug object exposed from the debug context global object.
30Debug = debug.Debug
31
32listenerComplete = false;
33exception = false;
34
35function safeEval(code) {
36  try {
37    return eval('(' + code + ')');
38  } catch (e) {
39    assertEquals(void 0, e);
40    return undefined;
41  }
42}
43
44
45// Send an evaluation request and return the handle of the result.
46function evaluateRequest(exec_state, arguments) {
47  // Get the debug command processor.
48  var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
49
50  // The base part of all evaluate requests.
51  var base_request = '"seq":0,"type":"request","command":"evaluate"'
52
53  // Generate request with the supplied arguments.
54  var request;
55  if (arguments) {
56    request = '{' + base_request + ',"arguments":' + arguments + '}';
57  } else {
58    request = '{' + base_request + '}'
59  }
60
61  var response = safeEval(dcp.processDebugJSONRequest(request));
62  assertTrue(response.success, request + ' -> ' + response.message);
63
64  return response.body.handle;
65}
66
67
68// Send a lookup request and return the evaluated JSON response.
69function lookupRequest(exec_state, arguments, success) {
70  // Get the debug command processor.
71  var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
72
73  // The base part of all lookup requests.
74  var base_request = '"seq":0,"type":"request","command":"lookup"'
75
76  // Generate request with the supplied arguments.
77  var request;
78  if (arguments) {
79    request = '{' + base_request + ',"arguments":' + arguments + '}';
80  } else {
81    request = '{' + base_request + '}'
82  }
83
84  var response = safeEval(dcp.processDebugJSONRequest(request));
85  if (success) {
86    assertTrue(response.success, request + ' -> ' + response.message);
87  } else {
88    assertFalse(response.success, request + ' -> ' + response.message);
89  }
90  assertEquals(response.running, dcp.isRunning(), request + ' -> expected not running');
91
92  return response;
93}
94
95
96function listener(event, exec_state, event_data, data) {
97  try {
98  if (event == Debug.DebugEvent.Break) {
99    // Test some illegal lookup requests.
100    lookupRequest(exec_state, void 0, false);
101    lookupRequest(exec_state, '{"handles":["a"]}', false);
102    lookupRequest(exec_state, '{"handles":[-1]}', false);
103
104    // Evaluate and get some handles.
105    var handle_o = evaluateRequest(exec_state, '{"expression":"o"}');
106    var handle_p = evaluateRequest(exec_state, '{"expression":"p"}');
107    var handle_b = evaluateRequest(exec_state, '{"expression":"a"}');
108    var handle_a = evaluateRequest(exec_state, '{"expression":"b","frame":1}');
109    assertEquals(handle_o, handle_a);
110    assertEquals(handle_a, handle_b);
111    assertFalse(handle_o == handle_p, "o and p have he same handle");
112
113    var response;
114    var count;
115    response = lookupRequest(exec_state, '{"handles":[' + handle_o + ']}', true);
116    var obj = response.body[handle_o];
117    assertTrue(!!obj, 'Object not found: ' + handle_o);
118    assertEquals(handle_o, obj.handle);
119    count = 0;
120    for (i in obj.properties) {
121      switch (obj.properties[i].name) {
122        case 'o':
123          obj.properties[i].ref = handle_o;
124          count++;
125          break;
126        case 'p':
127          obj.properties[i].ref = handle_p;
128          count++;
129          break;
130      }
131    }
132    assertEquals(2, count, 'Either "o" or "p" not found');
133    response = lookupRequest(exec_state, '{"handles":[' + handle_p + ']}', true);
134    obj = response.body[handle_p];
135    assertTrue(!!obj, 'Object not found: ' + handle_p);
136    assertEquals(handle_p, obj.handle);
137
138    // Check handles for functions on the stack.
139    var handle_f = evaluateRequest(exec_state, '{"expression":"f"}');
140    var handle_g = evaluateRequest(exec_state, '{"expression":"g"}');
141    var handle_caller = evaluateRequest(exec_state, '{"expression":"f.caller"}');
142
143    assertFalse(handle_f == handle_g, "f and g have he same handle");
144    assertEquals(handle_g, handle_caller, "caller for f should be g");
145
146    response = lookupRequest(exec_state, '{"handles":[' + handle_f + ']}', true);
147    obj = response.body[handle_f];
148    assertEquals(handle_f, obj.handle);
149
150    count = 0;
151    for (i in obj.properties) {
152      var ref = obj.properties[i].ref;
153      var arguments = '{"handles":[' + ref + ']}';
154      switch (obj.properties[i].name) {
155        case 'name':
156          var response_name;
157          response_name = lookupRequest(exec_state, arguments, true);
158          assertEquals('string', response_name.body[ref].type);
159          assertEquals("f", response_name.body[ref].value);
160          count++;
161          break;
162        case 'length':
163          var response_length;
164          response_length = lookupRequest(exec_state, arguments, true);
165          assertEquals('number', response_length.body[ref].type);
166          assertEquals(1, response_length.body[ref].value);
167          count++;
168          break;
169        case 'caller':
170          assertEquals(handle_g, obj.properties[i].ref);
171          count++;
172          break;
173      }
174    }
175    assertEquals(3, count, 'Either "name", "length" or "caller" not found');
176
177
178    // Resolve all at once.
179    var refs = [];
180    for (i in obj.properties) {
181      refs.push(obj.properties[i].ref);
182    }
183
184    var arguments = '{"handles":[' + refs.join(',') + ']}';
185    response = lookupRequest(exec_state, arguments, true);
186    count = 0;
187    for (i in obj.properties) {
188      var ref = obj.properties[i].ref;
189      var val = response.body[ref];
190      assertTrue(!!val, 'Failed to lookup "' + obj.properties[i].name + '"');
191      switch (obj.properties[i].name) {
192        case 'name':
193          assertEquals('string', val.type);
194          assertEquals("f", val.value);
195          count++;
196          break;
197        case 'length':
198          assertEquals('number', val.type);
199          assertEquals(1, val.value);
200          count++;
201          break;
202        case 'caller':
203          assertEquals('function', val.type);
204          assertEquals(handle_g, ref);
205          count++;
206          break;
207      }
208    }
209    assertEquals(3, count, 'Either "name", "length" or "caller" not found');
210
211    count = 0;
212    for (var handle in response.body) {
213      assertTrue(refs.indexOf(parseInt(handle)) != -1,
214                 'Handle not in the request: ' + handle);
215      count++;
216    }
217    assertEquals(count, obj.properties.length,
218                 'Unexpected number of resolved objects');
219
220
221    // Indicate that all was processed.
222    listenerComplete = true;
223  }
224  } catch (e) {
225    exception = e
226  };
227};
228
229// Add the debug event listener.
230Debug.setListener(listener);
231
232function f(a) {
233  debugger;
234};
235
236function g(b) {
237  f(b);
238};
239
240// Set a break point at return in f and invoke g to hit the breakpoint.
241Debug.setBreakPoint(f, 2, 0);
242o = {};
243p = {}
244o.o = o;
245o.p = p;
246p.o = o;
247p.p = p;
248g(o);
249
250assertFalse(exception, "exception in listener")
251// Make sure that the debug event listener vas invoked.
252assertTrue(listenerComplete, "listener did not run to completion: " + exception);
253