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.\n Error: %s" % (MSG ))
0 commit comments