Skip to content

Commit 280eab2

Browse files
committed
Splitting the debugger and console part of the python debugger
Move DebuggerPrompt to jerry_client.py Implement JerryDebugger functions in the jerry_client_ws.py file Server response is displayed by jerry_client.py JerryScript-DCO-1.0-Signed-off-by: Tamas Zakor [email protected]
1 parent acdbbf2 commit 280eab2

File tree

4 files changed

+1150
-602
lines changed

4 files changed

+1150
-602
lines changed

jerry-debugger/jerry_client.py

Lines changed: 392 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,392 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright JS Foundation and other contributors, http://js.foundation
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import jerry_client_ws
18+
from cmd import Cmd
19+
from pprint import pprint
20+
import math
21+
import select
22+
import socket
23+
import struct
24+
import sys
25+
import argparse
26+
import logging
27+
import os
28+
import time
29+
30+
31+
class DebuggerPrompt(Cmd):
32+
33+
def __init__(self, debugger):
34+
Cmd.__init__(self)
35+
self.debugger = debugger
36+
self.stop = False
37+
self.quit = False
38+
self.cont = True
39+
self.debugger.non_interactive = False
40+
self.dsp = 0
41+
self.display = 0
42+
self.show = 0
43+
44+
def precmd(self, line):
45+
self.stop = False
46+
self.cont = False
47+
if self.debugger.non_interactive:
48+
print("%s" % line)
49+
return line
50+
51+
def postcmd(self, stop, line):
52+
return self.stop
53+
54+
def do_quit(self, _):
55+
""" Exit JerryScript debugger """
56+
self.debugger.quit()
57+
self.cont = False
58+
self.quit = True
59+
self.stop = True
60+
61+
def do_display(self, args):
62+
""" Toggle source code display after breakpoints """
63+
self.cont = False
64+
if args:
65+
line_num = self.src_check_args(args)
66+
if line_num >= 0:
67+
self.display = line_num
68+
else:
69+
return
70+
else:
71+
print("Non-negative integer number expected, 0 turns off this function")
72+
return
73+
if self.dsp > 0 and self.display == 0:
74+
self.debugger.stop()
75+
76+
def do_break(self, args):
77+
""" Insert breakpoints on the given lines or functions """
78+
if args == "":
79+
print("Error: Breakpoint index expected")
80+
elif ':' in args:
81+
try:
82+
args_second = int(args.split(':', 1)[1])
83+
if args_second < 0:
84+
print("Error: Positive breakpoint index expected")
85+
else:
86+
sbreak = self.debugger.set_break(args)
87+
except ValueError as val_errno:
88+
print("Error: Positive breakpoint index expected: %s" % val_errno)
89+
else:
90+
sbreak = self.debugger.set_break(args)
91+
if sbreak is not None:
92+
print(sbreak)
93+
do_b = do_break
94+
95+
def do_list(self, _):
96+
""" Lists the available breakpoints """
97+
if self.debugger.active_breakpoint_list:
98+
print("=== %sActive breakpoints %s ===" % (self.debugger.green_bg, self.debugger.nocolor))
99+
for breakpoint in self.debugger.active_breakpoint_list.values():
100+
print(" %d: %s" % (breakpoint.active_index, breakpoint))
101+
102+
if self.debugger.pending_breakpoint_list:
103+
print("=== %sPending breakpoints%s ===" % (self.debugger.yellow_bg, self.debugger.nocolor))
104+
for breakpoint in self.debugger.pending_breakpoint_list.values():
105+
print(" %d: %s (pending)" % (breakpoint.index, breakpoint))
106+
107+
if not self.debugger.active_breakpoint_list and not self.debugger.pending_breakpoint_list:
108+
print("No breakpoints")
109+
110+
def do_delete(self, args):
111+
""" Delete the given breakpoint, use 'delete all|active|pending' to clear all the given breakpoints """
112+
if not args:
113+
print("Error: Breakpoint index expected")
114+
print("Delete the given breakpoint, use 'delete all|active|pending' to clear all the given breakpoints ")
115+
elif args in ['all','pending','active']:
116+
result = self.debugger.delete(args)
117+
if len(result) > 0:
118+
print(result)
119+
else:
120+
try:
121+
breakpoint_index = int(args),
122+
result = self.debugger.delete(args)
123+
except ValueError as val_errno:
124+
result = "Error: Integer number expected, %s" % (val_errno)
125+
126+
def do_next(self, args):
127+
""" Next breakpoint in the same context """
128+
self.cont = True
129+
self.stop = True
130+
if not args:
131+
args = 0
132+
self.debugger.next()
133+
else:
134+
try:
135+
args = int(args)
136+
if args <= 0:
137+
raise ValueError(args)
138+
else:
139+
while int(args) != 0:
140+
self.debugger.next()
141+
time.sleep(0.25)
142+
self.debugger.mainloop()
143+
result = self.debugger.smessage
144+
if result[-1:] == '\n':
145+
result = result[:-1]
146+
if result != '':
147+
print(result)
148+
self.debugger.smessage = ''
149+
if self.display > 0:
150+
print_source(self.debugger, self.display, self.debugger.src_offset)
151+
args = int(args) - 1
152+
self.cmdloop()
153+
except ValueError as val_errno:
154+
print("Error: expected a positive integer: %s" % val_errno)
155+
self.cmdloop()
156+
do_n = do_next
157+
158+
def do_step(self, _):
159+
""" Next breakpoint, step into functions """
160+
self.debugger.step()
161+
self.cont = True
162+
self.stop = True
163+
do_s = do_step
164+
165+
def do_backtrace(self, args):
166+
""" Get backtrace data from debugger """
167+
self.debugger.backtrace(args)
168+
self.show = 1
169+
self.stop = True
170+
do_bt = do_backtrace
171+
172+
def do_src(self, args):
173+
""" Get current source code """
174+
if args:
175+
line_num = self.src_check_args(args)
176+
if line_num >= 0:
177+
print_source(self.debugger, line_num, 0)
178+
elif line_num == 0:
179+
print_source(self.debugger, self.debugger.default_viewrange, 0)
180+
else:
181+
return
182+
do_source = do_src
183+
184+
def do_scroll(self, _):
185+
""" Scroll the source up or down """
186+
while True:
187+
key = sys.stdin.readline()
188+
if key == 'w\n':
189+
self._scroll_direction("up")
190+
elif key == 's\n':
191+
self._scroll_direction("down")
192+
elif key == 'q\n':
193+
break
194+
else:
195+
print("Invalid key")
196+
197+
def _scroll_direction(self, direction):
198+
""" Helper function for do_scroll """
199+
self.debugger.src_offset_diff = int(max(math.floor(self.debugger.display / 3), 1))
200+
if direction == "up":
201+
self.debugger.src_offset -= self.debugger.src_offset_diff
202+
print_source(self.debugger, self.debugger.display, self.debugger.src_offset)
203+
else:
204+
self.debugger.src_offset += self.debugger.src_offset_diff
205+
print_source(self.debugger, self.debugger.display, self.debugger.src_offset)
206+
207+
def do_continue(self, _):
208+
""" Continue execution """
209+
self.debugger.get_continue()
210+
self.stop = True
211+
self.cont = True
212+
if not self.debugger.non_interactive:
213+
print("Press enter to stop JavaScript execution.")
214+
do_c = do_continue
215+
216+
def do_finish(self, _):
217+
""" Continue running until the current function returns """
218+
self.debugger.finish()
219+
self.stop = True
220+
do_f = do_finish
221+
222+
def do_dump(self, args):
223+
""" Dump all of the debugger data """
224+
if args:
225+
print("Error: No argument expected")
226+
else:
227+
pprint(self.debugger.function_list)
228+
229+
def do_eval(self, args):
230+
""" Evaluate JavaScript source code """
231+
self.debugger.eval(args)
232+
self.stop = True
233+
self.cont = True
234+
do_e = do_eval
235+
236+
def do_memstats(self, _):
237+
""" Memory statistics """
238+
self.debugger.memstats()
239+
self.stop = True
240+
self.cont = True
241+
do_ms = do_memstats
242+
243+
def do_abort(self, args):
244+
""" Throw an exception """
245+
self.debugger.abort(args)
246+
self.stop = True
247+
self.cont = True
248+
249+
def do_throw(self, args):
250+
""" Throw an exception """
251+
self.debugger.throw(args)
252+
self.stop = True
253+
self.cont = True
254+
255+
def do_exception(self, args):
256+
""" Config the exception handler module """
257+
print(self.debugger.exception(args))
258+
259+
def src_check_args(self, args):
260+
try:
261+
line_num = int(args)
262+
if line_num < 0:
263+
print("Error: Non-negative integer number expected")
264+
return -1
265+
266+
return line_num
267+
except ValueError as val_errno:
268+
print("Error: Non-negative integer number expected: %s" % (val_errno))
269+
return -1
270+
271+
272+
def print_source(debugger, line_num, offset):
273+
last_bp = debugger.last_breakpoint_hit
274+
if not last_bp:
275+
return
276+
277+
lines = last_bp.function.source
278+
if last_bp.function.source_name:
279+
print("Source: %s" % (last_bp.function.source_name))
280+
281+
if line_num == 0:
282+
start = 0
283+
end = len(last_bp.function.source)
284+
else:
285+
start = max(last_bp.line - line_num, 0)
286+
end = min(last_bp.line + line_num - 1, len(last_bp.function.source))
287+
if offset:
288+
if start + offset < 0:
289+
debugger.src_offset += debugger.src_offset_diff
290+
offset += debugger.src_offset_diff
291+
elif end + offset > len(last_bp.function.source):
292+
debugger.src_offset -= debugger.src_offset_diff
293+
offset -= debugger.src_offset_diff
294+
295+
start = max(start + offset, 0)
296+
end = min(end + offset, len(last_bp.function.source))
297+
298+
for i in range(start, end):
299+
if i == last_bp.line - 1:
300+
print("%s%4d%s %s>%s %s" % (debugger.green, i + 1, debugger.nocolor, debugger.red, \
301+
debugger.nocolor, lines[i]))
302+
else:
303+
print("%s%4d%s %s" % (debugger.green, i + 1, debugger.nocolor, lines[i]))
304+
305+
306+
def main():
307+
args = jerry_client_ws.arguments_parse()
308+
309+
debugger = jerry_client_ws.JerryDebugger(args.address)
310+
311+
non_interactive = args.non_interactive
312+
313+
logging.debug("Connected to JerryScript on %d port", debugger.port)
314+
315+
prompt = DebuggerPrompt(debugger)
316+
prompt.prompt = "(jerry-debugger) "
317+
prompt.debugger.non_interactive = non_interactive
318+
319+
if args.color:
320+
debugger.set_colors()
321+
322+
if args.display:
323+
prompt.dsp = 1
324+
debugger.display = args.display
325+
prompt.do_display(args.display)
326+
prompt.cont = False
327+
else:
328+
prompt.dsp = 0
329+
prompt.stop = False
330+
prompt.cont = False
331+
if not args.client_source:
332+
prompt.debugger.mainloop()
333+
result = prompt.debugger.smessage
334+
print(result)
335+
prompt.debugger.smessage = ''
336+
prompt.cmdloop()
337+
338+
if args.exception is not None:
339+
prompt.do_exception(str(args.exception))
340+
341+
if args.client_source is not None:
342+
if args.client_source != []:
343+
prompt.debugger.store_client_sources(args.client_source)
344+
345+
while True:
346+
if prompt.quit:
347+
break
348+
349+
prompt.debugger.mainloop()
350+
result = prompt.debugger.smessage
351+
if result == '':
352+
break
353+
354+
if result is None:
355+
continue
356+
elif '\3' in result:
357+
result = result.replace('\3','')
358+
if result[-1:] == '\n':
359+
result = result[:-1]
360+
if result != '':
361+
print(result)
362+
prompt.debugger.smessage = ''
363+
if prompt.display > 0:
364+
print_source(prompt.debugger, prompt.display, prompt.debugger.src_offset)
365+
break
366+
else:
367+
if result[-1:] == '\n':
368+
result = result[:-1]
369+
if result != '':
370+
print(result)
371+
prompt.debugger.smessage = ''
372+
if prompt.display > 0:
373+
if prompt.show == 0:
374+
print_source(prompt.debugger, prompt.display, prompt.debugger.src_offset)
375+
else:
376+
prompt.show = 0
377+
prompt.cmdloop()
378+
continue
379+
380+
381+
if __name__ == "__main__":
382+
try:
383+
main()
384+
except socket.error as error_msg:
385+
ERRNO = error_msg.errno
386+
MSG = str(error_msg)
387+
if ERRNO == 111:
388+
sys.exit("Failed to connect to the JerryScript debugger.")
389+
elif ERRNO == 32 or ERRNO == 104:
390+
sys.exit("Connection closed.")
391+
else:
392+
sys.exit("Failed to connect to the JerryScript debugger.\nError: %s" % (MSG))

0 commit comments

Comments
 (0)