forked from xuos/xiuos
				
			
		
			
				
	
	
		
			346 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
# Copyright JS Foundation and other contributors, http://js.foundation
 | 
						|
#
 | 
						|
# 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.
 | 
						|
 | 
						|
from __future__ import print_function
 | 
						|
from cmd import Cmd
 | 
						|
from pprint import pprint
 | 
						|
import math
 | 
						|
import socket
 | 
						|
import sys
 | 
						|
import logging
 | 
						|
import time
 | 
						|
import jerry_client_main
 | 
						|
 | 
						|
from jerry_client_websocket import WebSocket
 | 
						|
from jerry_client_rawpacket import RawPacket
 | 
						|
from jerry_client_tcp import Socket
 | 
						|
 | 
						|
def write(string):
 | 
						|
    print(string, end='')
 | 
						|
 | 
						|
class DebuggerPrompt(Cmd):
 | 
						|
    # pylint: disable=too-many-instance-attributes,too-many-arguments
 | 
						|
    def __init__(self, debugger):
 | 
						|
        Cmd.__init__(self)
 | 
						|
        self.debugger = debugger
 | 
						|
        self.stop = False
 | 
						|
        self.quit = False
 | 
						|
 | 
						|
    def precmd(self, line):
 | 
						|
        self.stop = False
 | 
						|
        if self.debugger.non_interactive:
 | 
						|
            print("%s" % line)
 | 
						|
        return line
 | 
						|
 | 
						|
    def postcmd(self, stop, line):
 | 
						|
        return self.stop
 | 
						|
 | 
						|
    def do_quit(self, _):
 | 
						|
        """ Exit JerryScript debugger """
 | 
						|
        self.debugger.quit()
 | 
						|
        self.quit = True
 | 
						|
        self.stop = True
 | 
						|
 | 
						|
    def do_display(self, args):
 | 
						|
        """ Toggle source code display after breakpoints """
 | 
						|
        if args:
 | 
						|
            line_num = src_check_args(args)
 | 
						|
            if line_num >= 0:
 | 
						|
                self.debugger.display = line_num
 | 
						|
        else:
 | 
						|
            print("Non-negative integer number expected, 0 turns off this function")
 | 
						|
 | 
						|
    def do_break(self, args):
 | 
						|
        """ Insert breakpoints on the given lines or functions """
 | 
						|
        write(self.debugger.set_break(args))
 | 
						|
    do_b = do_break
 | 
						|
 | 
						|
    def do_list(self, _):
 | 
						|
        """ Lists the available breakpoints """
 | 
						|
        write(self.debugger.breakpoint_list())
 | 
						|
 | 
						|
    def do_delete(self, args):
 | 
						|
        """ Delete the given breakpoint, use 'delete all|active|pending' to clear all the given breakpoints """
 | 
						|
        write(self.debugger.delete(args))
 | 
						|
 | 
						|
    def do_exception(self, args):
 | 
						|
        """ Config the exception handler module """
 | 
						|
        write(self.debugger.exception(args))
 | 
						|
 | 
						|
    def do_next(self, args):
 | 
						|
        """ Next breakpoint in the same code block """
 | 
						|
        self.stop = True
 | 
						|
        if not args:
 | 
						|
            args = 0
 | 
						|
            self.debugger.next()
 | 
						|
            return
 | 
						|
 | 
						|
        try:
 | 
						|
            args = int(args)
 | 
						|
            if args <= 0:
 | 
						|
                raise ValueError(args)
 | 
						|
 | 
						|
            while args > 0:
 | 
						|
                self.debugger.next()
 | 
						|
                time.sleep(0.1)
 | 
						|
 | 
						|
                while True:
 | 
						|
                    result = self.debugger.process_messages()
 | 
						|
                    res_type = result.get_type()
 | 
						|
 | 
						|
                    if res_type == result.END:
 | 
						|
                        self.quit = True
 | 
						|
                        return
 | 
						|
                    elif res_type == result.TEXT:
 | 
						|
                        write(result.get_text())
 | 
						|
                    elif res_type == result.PROMPT:
 | 
						|
                        break
 | 
						|
 | 
						|
                args -= 1
 | 
						|
        except ValueError as val_errno:
 | 
						|
            print("Error: expected a positive integer: %s" % val_errno)
 | 
						|
    do_n = do_next
 | 
						|
 | 
						|
    def do_step(self, _):
 | 
						|
        """ Next breakpoint, step into functions """
 | 
						|
        self.debugger.step()
 | 
						|
        self.stop = True
 | 
						|
    do_s = do_step
 | 
						|
 | 
						|
    def do_continue(self, _):
 | 
						|
        """ Continue execution """
 | 
						|
        self.debugger.do_continue()
 | 
						|
        self.stop = True
 | 
						|
        if not self.debugger.non_interactive:
 | 
						|
            print("Press enter to stop JavaScript execution.")
 | 
						|
    do_c = do_continue
 | 
						|
 | 
						|
    def do_finish(self, _):
 | 
						|
        """ Continue running until the current function returns """
 | 
						|
        self.debugger.finish()
 | 
						|
        self.stop = True
 | 
						|
    do_f = do_finish
 | 
						|
 | 
						|
    def do_backtrace(self, args):
 | 
						|
        """ Get backtrace data from debugger """
 | 
						|
        write(self.debugger.backtrace(args))
 | 
						|
        self.stop = True
 | 
						|
    do_bt = do_backtrace
 | 
						|
 | 
						|
    def do_src(self, args):
 | 
						|
        """ Get current source code """
 | 
						|
        if args:
 | 
						|
            line_num = src_check_args(args)
 | 
						|
            if line_num >= 0:
 | 
						|
                write(self.debugger.print_source(line_num, 0))
 | 
						|
        else:
 | 
						|
            write(self.debugger.print_source(0, 0))
 | 
						|
    do_source = do_src
 | 
						|
 | 
						|
    def do_scroll(self, _):
 | 
						|
        """ Scroll the source up or down """
 | 
						|
        while True:
 | 
						|
            key = sys.stdin.readline()
 | 
						|
            if key == 'w\n':
 | 
						|
                _scroll_direction(self.debugger, "up")
 | 
						|
            elif key == 's\n':
 | 
						|
                _scroll_direction(self.debugger, "down")
 | 
						|
            elif key == 'q\n':
 | 
						|
                break
 | 
						|
            else:
 | 
						|
                print("Invalid key")
 | 
						|
 | 
						|
    def do_eval(self, args):
 | 
						|
        """ Evaluate JavaScript source code """
 | 
						|
        self.debugger.eval(args)
 | 
						|
        self.stop = True
 | 
						|
    do_e = do_eval
 | 
						|
    do_print = do_eval
 | 
						|
    do_p = do_eval
 | 
						|
 | 
						|
    def do_eval_at(self, args):
 | 
						|
        """ Evaluate JavaScript source code at a scope chain level """
 | 
						|
 | 
						|
        code = ''
 | 
						|
        index = 0
 | 
						|
        try:
 | 
						|
            args = args.split(" ", 1)
 | 
						|
 | 
						|
            index = int(args[0])
 | 
						|
 | 
						|
            if len(args) == 2:
 | 
						|
                code = args[1]
 | 
						|
 | 
						|
            if index < 0 or index > 65535:
 | 
						|
                raise ValueError("Invalid scope chain index: %d (must be between 0 and 65535)" % index)
 | 
						|
 | 
						|
        except ValueError as val_errno:
 | 
						|
            print("Error: %s" % (val_errno))
 | 
						|
            return
 | 
						|
 | 
						|
        self.debugger.eval_at(code, index)
 | 
						|
        self.stop = True
 | 
						|
 | 
						|
    def do_throw(self, args):
 | 
						|
        """ Throw an exception """
 | 
						|
        self.debugger.throw(args)
 | 
						|
        self.stop = True
 | 
						|
 | 
						|
    def do_abort(self, args):
 | 
						|
        """ Throw an exception which cannot be caught """
 | 
						|
        self.debugger.abort(args)
 | 
						|
        self.stop = True
 | 
						|
 | 
						|
    def do_restart(self, _):
 | 
						|
        """ Restart the engine's debug session """
 | 
						|
        self.debugger.restart()
 | 
						|
        self.stop = True
 | 
						|
    do_res = do_restart
 | 
						|
 | 
						|
    def do_scope(self, _):
 | 
						|
        """ Get lexical environment chain """
 | 
						|
        self.debugger.scope_chain()
 | 
						|
        self.stop = True
 | 
						|
 | 
						|
    def do_variables(self, args):
 | 
						|
        """ Get scope variables from debugger """
 | 
						|
        write(self.debugger.scope_variables(args))
 | 
						|
        self.stop = True
 | 
						|
 | 
						|
    def do_memstats(self, _):
 | 
						|
        """ Memory statistics """
 | 
						|
        self.debugger.memstats()
 | 
						|
        self.stop = True
 | 
						|
    do_ms = do_memstats
 | 
						|
 | 
						|
    def do_dump(self, args):
 | 
						|
        """ Dump all of the debugger data """
 | 
						|
        if args:
 | 
						|
            print("Error: No argument expected")
 | 
						|
        else:
 | 
						|
            pprint(self.debugger.function_list)
 | 
						|
 | 
						|
    # pylint: disable=invalid-name
 | 
						|
    def do_EOF(self, _):
 | 
						|
        """ Exit JerryScript debugger """
 | 
						|
        print("Unexpected end of input. Connection closed.")
 | 
						|
        self.debugger.quit()
 | 
						|
        self.quit = True
 | 
						|
        self.stop = True
 | 
						|
 | 
						|
def _scroll_direction(debugger, direction):
 | 
						|
    """ Helper function for do_scroll """
 | 
						|
    debugger.src_offset_diff = int(max(math.floor(debugger.display / 3), 1))
 | 
						|
    if direction == "up":
 | 
						|
        debugger.src_offset -= debugger.src_offset_diff
 | 
						|
    else:
 | 
						|
        debugger.src_offset += debugger.src_offset_diff
 | 
						|
    print(debugger.print_source(debugger.display, debugger.src_offset)['value'])
 | 
						|
 | 
						|
def src_check_args(args):
 | 
						|
    try:
 | 
						|
        line_num = int(args)
 | 
						|
        if line_num < 0:
 | 
						|
            print("Error: Non-negative integer number expected")
 | 
						|
            return -1
 | 
						|
 | 
						|
        return line_num
 | 
						|
    except ValueError as val_errno:
 | 
						|
        print("Error: Non-negative integer number expected: %s" % (val_errno))
 | 
						|
        return -1
 | 
						|
 | 
						|
# pylint: disable=too-many-branches,too-many-locals,too-many-statements
 | 
						|
def main():
 | 
						|
    args = jerry_client_main.arguments_parse()
 | 
						|
 | 
						|
    channel = None
 | 
						|
    protocol = None
 | 
						|
 | 
						|
    if args.protocol == "tcp":
 | 
						|
        address = None
 | 
						|
        if ":" not in args.address:
 | 
						|
            address = (args.address, 5001) # use default port
 | 
						|
        else:
 | 
						|
            host, port = args.address.split(":")
 | 
						|
            address = (host, int(port))
 | 
						|
 | 
						|
        protocol = Socket(address)
 | 
						|
    elif args.protocol == "serial":
 | 
						|
        from jerry_client_serial import Serial
 | 
						|
        protocol = Serial(args.serial_config)
 | 
						|
    else:
 | 
						|
        print("Unsupported transmission protocol")
 | 
						|
        return -1
 | 
						|
 | 
						|
    if args.channel == "websocket":
 | 
						|
        channel = WebSocket(protocol=protocol)
 | 
						|
    elif args.channel == "rawpacket":
 | 
						|
        channel = RawPacket(protocol=protocol)
 | 
						|
    else:
 | 
						|
        print("Unsupported communication channel")
 | 
						|
        return -1
 | 
						|
 | 
						|
    debugger = jerry_client_main.JerryDebugger(channel)
 | 
						|
    debugger.non_interactive = args.non_interactive
 | 
						|
 | 
						|
    logging.debug("Connected to JerryScript")
 | 
						|
 | 
						|
    prompt = DebuggerPrompt(debugger)
 | 
						|
    prompt.prompt = "(jerry-debugger) "
 | 
						|
 | 
						|
    if args.color:
 | 
						|
        debugger.set_colors()
 | 
						|
 | 
						|
    if args.display:
 | 
						|
        debugger.display = args.display
 | 
						|
        prompt.do_display(args.display)
 | 
						|
    else:
 | 
						|
        prompt.stop = False
 | 
						|
 | 
						|
    if args.exception is not None:
 | 
						|
        prompt.do_exception(str(args.exception))
 | 
						|
 | 
						|
    if args.client_source:
 | 
						|
        debugger.store_client_sources(args.client_source)
 | 
						|
 | 
						|
    while True:
 | 
						|
        if prompt.quit:
 | 
						|
            break
 | 
						|
 | 
						|
        result = debugger.process_messages()
 | 
						|
        res_type = result.get_type()
 | 
						|
 | 
						|
        if res_type == result.END:
 | 
						|
            break
 | 
						|
        elif res_type == result.PROMPT:
 | 
						|
            prompt.cmdloop()
 | 
						|
        elif res_type == result.TEXT:
 | 
						|
            write(result.get_text())
 | 
						|
        continue
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    try:
 | 
						|
        main()
 | 
						|
    except socket.error as error_msg:
 | 
						|
        ERRNO = error_msg.errno
 | 
						|
        MSG = str(error_msg)
 | 
						|
        if ERRNO == 111:
 | 
						|
            sys.exit("Failed to connect to the JerryScript debugger.")
 | 
						|
        elif ERRNO == 32 or ERRNO == 104:
 | 
						|
            sys.exit("Connection closed.")
 | 
						|
        else:
 | 
						|
            sys.exit("Failed to connect to the JerryScript debugger.\nError: %s" % (MSG))
 |