101263c6cSJonas Devlieghere#!/usr/bin/env python 201263c6cSJonas Devlieghere 301263c6cSJonas Devlieghereimport binascii 401263c6cSJonas Devlieghereimport json 501263c6cSJonas Devlieghereimport optparse 601263c6cSJonas Devlieghereimport os 701263c6cSJonas Devlieghereimport pprint 801263c6cSJonas Devlieghereimport socket 901263c6cSJonas Devlieghereimport string 1001263c6cSJonas Devlieghereimport subprocess 1101263c6cSJonas Devlieghereimport sys 1201263c6cSJonas Devlieghereimport threading 1301263c6cSJonas Devlieghereimport time 1401263c6cSJonas Devlieghere 1501263c6cSJonas Devlieghere 1601263c6cSJonas Devliegheredef dump_memory(base_addr, data, num_per_line, outfile): 1701263c6cSJonas Devlieghere data_len = len(data) 1801263c6cSJonas Devlieghere hex_string = binascii.hexlify(data) 1901263c6cSJonas Devlieghere addr = base_addr 2001263c6cSJonas Devlieghere ascii_str = "" 2101263c6cSJonas Devlieghere i = 0 2201263c6cSJonas Devlieghere while i < data_len: 2301263c6cSJonas Devlieghere outfile.write("0x%8.8x: " % (addr + i)) 2401263c6cSJonas Devlieghere bytes_left = data_len - i 2501263c6cSJonas Devlieghere if bytes_left >= num_per_line: 2601263c6cSJonas Devlieghere curr_data_len = num_per_line 2701263c6cSJonas Devlieghere else: 2801263c6cSJonas Devlieghere curr_data_len = bytes_left 2901263c6cSJonas Devlieghere hex_start_idx = i * 2 3001263c6cSJonas Devlieghere hex_end_idx = hex_start_idx + curr_data_len * 2 3101263c6cSJonas Devlieghere curr_hex_str = hex_string[hex_start_idx:hex_end_idx] 3201263c6cSJonas Devlieghere # 'curr_hex_str' now contains the hex byte string for the 3301263c6cSJonas Devlieghere # current line with no spaces between bytes 3401263c6cSJonas Devlieghere t = iter(curr_hex_str) 3501263c6cSJonas Devlieghere # Print hex bytes separated by space 3601263c6cSJonas Devlieghere outfile.write(" ".join(a + b for a, b in zip(t, t))) 3701263c6cSJonas Devlieghere # Print two spaces 3801263c6cSJonas Devlieghere outfile.write(" ") 3901263c6cSJonas Devlieghere # Calculate ASCII string for bytes into 'ascii_str' 4001263c6cSJonas Devlieghere ascii_str = "" 4101263c6cSJonas Devlieghere for j in range(i, i + curr_data_len): 4201263c6cSJonas Devlieghere ch = data[j] 4301263c6cSJonas Devlieghere if ch in string.printable and ch not in string.whitespace: 4401263c6cSJonas Devlieghere ascii_str += "%c" % (ch) 4501263c6cSJonas Devlieghere else: 4601263c6cSJonas Devlieghere ascii_str += "." 4701263c6cSJonas Devlieghere # Print ASCII representation and newline 4801263c6cSJonas Devlieghere outfile.write(ascii_str) 4901263c6cSJonas Devlieghere i = i + curr_data_len 5001263c6cSJonas Devlieghere outfile.write("\n") 5101263c6cSJonas Devlieghere 5201263c6cSJonas Devlieghere 5301263c6cSJonas Devliegheredef read_packet(f, verbose=False, trace_file=None): 5401263c6cSJonas Devlieghere """Decode a JSON packet that starts with the content length and is 5501263c6cSJonas Devlieghere followed by the JSON bytes from a file 'f'. Returns None on EOF. 5601263c6cSJonas Devlieghere """ 5701263c6cSJonas Devlieghere line = f.readline().decode("utf-8") 5801263c6cSJonas Devlieghere if len(line) == 0: 5901263c6cSJonas Devlieghere return None # EOF. 6001263c6cSJonas Devlieghere 6101263c6cSJonas Devlieghere # Watch for line that starts with the prefix 6201263c6cSJonas Devlieghere prefix = "Content-Length: " 6301263c6cSJonas Devlieghere if line.startswith(prefix): 6401263c6cSJonas Devlieghere # Decode length of JSON bytes 6501263c6cSJonas Devlieghere if verbose: 6601263c6cSJonas Devlieghere print('content: "%s"' % (line)) 6701263c6cSJonas Devlieghere length = int(line[len(prefix) :]) 6801263c6cSJonas Devlieghere if verbose: 6901263c6cSJonas Devlieghere print('length: "%u"' % (length)) 7001263c6cSJonas Devlieghere # Skip empty line 7101263c6cSJonas Devlieghere line = f.readline() 7201263c6cSJonas Devlieghere if verbose: 7301263c6cSJonas Devlieghere print('empty: "%s"' % (line)) 7401263c6cSJonas Devlieghere # Read JSON bytes 7501263c6cSJonas Devlieghere json_str = f.read(length) 7601263c6cSJonas Devlieghere if verbose: 7701263c6cSJonas Devlieghere print('json: "%s"' % (json_str)) 7801263c6cSJonas Devlieghere if trace_file: 7901263c6cSJonas Devlieghere trace_file.write("from adaptor:\n%s\n" % (json_str)) 8001263c6cSJonas Devlieghere # Decode the JSON bytes into a python dictionary 8101263c6cSJonas Devlieghere return json.loads(json_str) 8201263c6cSJonas Devlieghere 832a32afddSDavid Spickett raise Exception("unexpected malformed message from lldb-dap: " + line) 8401263c6cSJonas Devlieghere 8501263c6cSJonas Devlieghere 8601263c6cSJonas Devliegheredef packet_type_is(packet, packet_type): 8701263c6cSJonas Devlieghere return "type" in packet and packet["type"] == packet_type 8801263c6cSJonas Devlieghere 8901263c6cSJonas Devlieghere 9001263c6cSJonas Devliegheredef dump_dap_log(log_file): 9101263c6cSJonas Devlieghere print("========= DEBUG ADAPTER PROTOCOL LOGS =========") 9201263c6cSJonas Devlieghere if log_file is None: 9301263c6cSJonas Devlieghere print("no log file available") 9401263c6cSJonas Devlieghere else: 9501263c6cSJonas Devlieghere with open(log_file, "r") as file: 9601263c6cSJonas Devlieghere print(file.read()) 9701263c6cSJonas Devlieghere print("========= END =========") 9801263c6cSJonas Devlieghere 9901263c6cSJonas Devlieghere 10001263c6cSJonas Devliegheredef read_packet_thread(vs_comm, log_file): 10101263c6cSJonas Devlieghere done = False 10201263c6cSJonas Devlieghere try: 10301263c6cSJonas Devlieghere while not done: 10401263c6cSJonas Devlieghere packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file) 10501263c6cSJonas Devlieghere # `packet` will be `None` on EOF. We want to pass it down to 10601263c6cSJonas Devlieghere # handle_recv_packet anyway so the main thread can handle unexpected 1072a32afddSDavid Spickett # termination of lldb-dap and stop waiting for new packets. 10801263c6cSJonas Devlieghere done = not vs_comm.handle_recv_packet(packet) 10901263c6cSJonas Devlieghere finally: 11001263c6cSJonas Devlieghere dump_dap_log(log_file) 11101263c6cSJonas Devlieghere 11201263c6cSJonas Devlieghere 11301263c6cSJonas Devlieghereclass DebugCommunication(object): 11401263c6cSJonas Devlieghere def __init__(self, recv, send, init_commands, log_file=None): 11501263c6cSJonas Devlieghere self.trace_file = None 11601263c6cSJonas Devlieghere self.send = send 11701263c6cSJonas Devlieghere self.recv = recv 11801263c6cSJonas Devlieghere self.recv_packets = [] 11901263c6cSJonas Devlieghere self.recv_condition = threading.Condition() 12001263c6cSJonas Devlieghere self.recv_thread = threading.Thread( 12101263c6cSJonas Devlieghere target=read_packet_thread, args=(self, log_file) 12201263c6cSJonas Devlieghere ) 12301263c6cSJonas Devlieghere self.process_event_body = None 12401263c6cSJonas Devlieghere self.exit_status = None 12501263c6cSJonas Devlieghere self.initialize_body = None 12601263c6cSJonas Devlieghere self.thread_stop_reasons = {} 12701263c6cSJonas Devlieghere self.breakpoint_events = [] 12801263c6cSJonas Devlieghere self.progress_events = [] 12901263c6cSJonas Devlieghere self.reverse_requests = [] 13001263c6cSJonas Devlieghere self.sequence = 1 13101263c6cSJonas Devlieghere self.threads = None 13201263c6cSJonas Devlieghere self.recv_thread.start() 13301263c6cSJonas Devlieghere self.output_condition = threading.Condition() 13401263c6cSJonas Devlieghere self.output = {} 13501263c6cSJonas Devlieghere self.configuration_done_sent = False 13601263c6cSJonas Devlieghere self.frame_scopes = {} 13701263c6cSJonas Devlieghere self.init_commands = init_commands 13801263c6cSJonas Devlieghere self.disassembled_instructions = {} 13901263c6cSJonas Devlieghere 14001263c6cSJonas Devlieghere @classmethod 14101263c6cSJonas Devlieghere def encode_content(cls, s): 14201263c6cSJonas Devlieghere return ("Content-Length: %u\r\n\r\n%s" % (len(s), s)).encode("utf-8") 14301263c6cSJonas Devlieghere 14401263c6cSJonas Devlieghere @classmethod 14501263c6cSJonas Devlieghere def validate_response(cls, command, response): 14601263c6cSJonas Devlieghere if command["command"] != response["command"]: 14701263c6cSJonas Devlieghere raise ValueError("command mismatch in response") 14801263c6cSJonas Devlieghere if command["seq"] != response["request_seq"]: 14901263c6cSJonas Devlieghere raise ValueError("seq mismatch in response") 15001263c6cSJonas Devlieghere 15101263c6cSJonas Devlieghere def get_modules(self): 15201263c6cSJonas Devlieghere module_list = self.request_modules()["body"]["modules"] 15301263c6cSJonas Devlieghere modules = {} 15401263c6cSJonas Devlieghere for module in module_list: 15501263c6cSJonas Devlieghere modules[module["name"]] = module 15601263c6cSJonas Devlieghere return modules 15701263c6cSJonas Devlieghere 15801263c6cSJonas Devlieghere def get_output(self, category, timeout=0.0, clear=True): 15901263c6cSJonas Devlieghere self.output_condition.acquire() 16001263c6cSJonas Devlieghere output = None 16101263c6cSJonas Devlieghere if category in self.output: 16201263c6cSJonas Devlieghere output = self.output[category] 16301263c6cSJonas Devlieghere if clear: 16401263c6cSJonas Devlieghere del self.output[category] 16501263c6cSJonas Devlieghere elif timeout != 0.0: 16601263c6cSJonas Devlieghere self.output_condition.wait(timeout) 16701263c6cSJonas Devlieghere if category in self.output: 16801263c6cSJonas Devlieghere output = self.output[category] 16901263c6cSJonas Devlieghere if clear: 17001263c6cSJonas Devlieghere del self.output[category] 17101263c6cSJonas Devlieghere self.output_condition.release() 17201263c6cSJonas Devlieghere return output 17301263c6cSJonas Devlieghere 17411a4d43fSMiro Bucko def collect_output(self, category, timeout_secs, pattern, clear=True): 17511a4d43fSMiro Bucko end_time = time.time() + timeout_secs 17601263c6cSJonas Devlieghere collected_output = "" 17701263c6cSJonas Devlieghere while end_time > time.time(): 17801263c6cSJonas Devlieghere output = self.get_output(category, timeout=0.25, clear=clear) 17901263c6cSJonas Devlieghere if output: 18001263c6cSJonas Devlieghere collected_output += output 18111a4d43fSMiro Bucko if pattern is not None and pattern in output: 18211a4d43fSMiro Bucko break 18301263c6cSJonas Devlieghere return collected_output if collected_output else None 18401263c6cSJonas Devlieghere 18501263c6cSJonas Devlieghere def enqueue_recv_packet(self, packet): 18601263c6cSJonas Devlieghere self.recv_condition.acquire() 18701263c6cSJonas Devlieghere self.recv_packets.append(packet) 18801263c6cSJonas Devlieghere self.recv_condition.notify() 18901263c6cSJonas Devlieghere self.recv_condition.release() 19001263c6cSJonas Devlieghere 19101263c6cSJonas Devlieghere def handle_recv_packet(self, packet): 19201263c6cSJonas Devlieghere """Called by the read thread that is waiting for all incoming packets 19301263c6cSJonas Devlieghere to store the incoming packet in "self.recv_packets" in a thread safe 19401263c6cSJonas Devlieghere way. This function will then signal the "self.recv_condition" to 19501263c6cSJonas Devlieghere indicate a new packet is available. Returns True if the caller 19601263c6cSJonas Devlieghere should keep calling this function for more packets. 19701263c6cSJonas Devlieghere """ 19801263c6cSJonas Devlieghere # If EOF, notify the read thread by enqueuing a None. 19901263c6cSJonas Devlieghere if not packet: 20001263c6cSJonas Devlieghere self.enqueue_recv_packet(None) 20101263c6cSJonas Devlieghere return False 20201263c6cSJonas Devlieghere 20301263c6cSJonas Devlieghere # Check the packet to see if is an event packet 20401263c6cSJonas Devlieghere keepGoing = True 20501263c6cSJonas Devlieghere packet_type = packet["type"] 20601263c6cSJonas Devlieghere if packet_type == "event": 20701263c6cSJonas Devlieghere event = packet["event"] 20801263c6cSJonas Devlieghere body = None 20901263c6cSJonas Devlieghere if "body" in packet: 21001263c6cSJonas Devlieghere body = packet["body"] 21101263c6cSJonas Devlieghere # Handle the event packet and cache information from these packets 21201263c6cSJonas Devlieghere # as they come in 21301263c6cSJonas Devlieghere if event == "output": 21401263c6cSJonas Devlieghere # Store any output we receive so clients can retrieve it later. 21501263c6cSJonas Devlieghere category = body["category"] 21601263c6cSJonas Devlieghere output = body["output"] 21701263c6cSJonas Devlieghere self.output_condition.acquire() 21801263c6cSJonas Devlieghere if category in self.output: 21901263c6cSJonas Devlieghere self.output[category] += output 22001263c6cSJonas Devlieghere else: 22101263c6cSJonas Devlieghere self.output[category] = output 22201263c6cSJonas Devlieghere self.output_condition.notify() 22301263c6cSJonas Devlieghere self.output_condition.release() 22401263c6cSJonas Devlieghere # no need to add 'output' event packets to our packets list 22501263c6cSJonas Devlieghere return keepGoing 22601263c6cSJonas Devlieghere elif event == "process": 22701263c6cSJonas Devlieghere # When a new process is attached or launched, remember the 22801263c6cSJonas Devlieghere # details that are available in the body of the event 22901263c6cSJonas Devlieghere self.process_event_body = body 23001263c6cSJonas Devlieghere elif event == "stopped": 23101263c6cSJonas Devlieghere # Each thread that stops with a reason will send a 23201263c6cSJonas Devlieghere # 'stopped' event. We need to remember the thread stop 23301263c6cSJonas Devlieghere # reasons since the 'threads' command doesn't return 23401263c6cSJonas Devlieghere # that information. 23501263c6cSJonas Devlieghere self._process_stopped() 23601263c6cSJonas Devlieghere tid = body["threadId"] 23701263c6cSJonas Devlieghere self.thread_stop_reasons[tid] = body 23801263c6cSJonas Devlieghere elif event == "breakpoint": 23901263c6cSJonas Devlieghere # Breakpoint events come in when a breakpoint has locations 24001263c6cSJonas Devlieghere # added or removed. Keep track of them so we can look for them 24101263c6cSJonas Devlieghere # in tests. 24201263c6cSJonas Devlieghere self.breakpoint_events.append(packet) 24301263c6cSJonas Devlieghere # no need to add 'breakpoint' event packets to our packets list 24401263c6cSJonas Devlieghere return keepGoing 24501263c6cSJonas Devlieghere elif event.startswith("progress"): 24601263c6cSJonas Devlieghere # Progress events come in as 'progressStart', 'progressUpdate', 24701263c6cSJonas Devlieghere # and 'progressEnd' events. Keep these around in case test 24801263c6cSJonas Devlieghere # cases want to verify them. 24901263c6cSJonas Devlieghere self.progress_events.append(packet) 25001263c6cSJonas Devlieghere # No need to add 'progress' event packets to our packets list. 25101263c6cSJonas Devlieghere return keepGoing 25201263c6cSJonas Devlieghere 25301263c6cSJonas Devlieghere elif packet_type == "response": 25401263c6cSJonas Devlieghere if packet["command"] == "disconnect": 25501263c6cSJonas Devlieghere keepGoing = False 25601263c6cSJonas Devlieghere self.enqueue_recv_packet(packet) 25701263c6cSJonas Devlieghere return keepGoing 25801263c6cSJonas Devlieghere 25901263c6cSJonas Devlieghere def send_packet(self, command_dict, set_sequence=True): 26001263c6cSJonas Devlieghere """Take the "command_dict" python dictionary and encode it as a JSON 26101263c6cSJonas Devlieghere string and send the contents as a packet to the VSCode debug 26201263c6cSJonas Devlieghere adaptor""" 26301263c6cSJonas Devlieghere # Set the sequence ID for this command automatically 26401263c6cSJonas Devlieghere if set_sequence: 26501263c6cSJonas Devlieghere command_dict["seq"] = self.sequence 26601263c6cSJonas Devlieghere self.sequence += 1 26701263c6cSJonas Devlieghere # Encode our command dictionary as a JSON string 26801263c6cSJonas Devlieghere json_str = json.dumps(command_dict, separators=(",", ":")) 26901263c6cSJonas Devlieghere if self.trace_file: 27001263c6cSJonas Devlieghere self.trace_file.write("to adaptor:\n%s\n" % (json_str)) 27101263c6cSJonas Devlieghere length = len(json_str) 27201263c6cSJonas Devlieghere if length > 0: 27301263c6cSJonas Devlieghere # Send the encoded JSON packet and flush the 'send' file 27401263c6cSJonas Devlieghere self.send.write(self.encode_content(json_str)) 27501263c6cSJonas Devlieghere self.send.flush() 27601263c6cSJonas Devlieghere 27701263c6cSJonas Devlieghere def recv_packet(self, filter_type=None, filter_event=None, timeout=None): 27801263c6cSJonas Devlieghere """Get a JSON packet from the VSCode debug adaptor. This function 27901263c6cSJonas Devlieghere assumes a thread that reads packets is running and will deliver 28001263c6cSJonas Devlieghere any received packets by calling handle_recv_packet(...). This 28101263c6cSJonas Devlieghere function will wait for the packet to arrive and return it when 28201263c6cSJonas Devlieghere it does.""" 28301263c6cSJonas Devlieghere while True: 28401263c6cSJonas Devlieghere try: 28501263c6cSJonas Devlieghere self.recv_condition.acquire() 28601263c6cSJonas Devlieghere packet = None 28701263c6cSJonas Devlieghere while True: 28801263c6cSJonas Devlieghere for i, curr_packet in enumerate(self.recv_packets): 28901263c6cSJonas Devlieghere if not curr_packet: 29001263c6cSJonas Devlieghere raise EOFError 29101263c6cSJonas Devlieghere packet_type = curr_packet["type"] 29201263c6cSJonas Devlieghere if filter_type is None or packet_type in filter_type: 29301263c6cSJonas Devlieghere if filter_event is None or ( 29401263c6cSJonas Devlieghere packet_type == "event" 29501263c6cSJonas Devlieghere and curr_packet["event"] in filter_event 29601263c6cSJonas Devlieghere ): 29701263c6cSJonas Devlieghere packet = self.recv_packets.pop(i) 29801263c6cSJonas Devlieghere break 29901263c6cSJonas Devlieghere if packet: 30001263c6cSJonas Devlieghere break 30101263c6cSJonas Devlieghere # Sleep until packet is received 30201263c6cSJonas Devlieghere len_before = len(self.recv_packets) 30301263c6cSJonas Devlieghere self.recv_condition.wait(timeout) 30401263c6cSJonas Devlieghere len_after = len(self.recv_packets) 30501263c6cSJonas Devlieghere if len_before == len_after: 30601263c6cSJonas Devlieghere return None # Timed out 30701263c6cSJonas Devlieghere return packet 30801263c6cSJonas Devlieghere except EOFError: 30901263c6cSJonas Devlieghere return None 31001263c6cSJonas Devlieghere finally: 31101263c6cSJonas Devlieghere self.recv_condition.release() 31201263c6cSJonas Devlieghere 31301263c6cSJonas Devlieghere return None 31401263c6cSJonas Devlieghere 31501263c6cSJonas Devlieghere def send_recv(self, command): 31601263c6cSJonas Devlieghere """Send a command python dictionary as JSON and receive the JSON 31701263c6cSJonas Devlieghere response. Validates that the response is the correct sequence and 31801263c6cSJonas Devlieghere command in the reply. Any events that are received are added to the 31901263c6cSJonas Devlieghere events list in this object""" 32001263c6cSJonas Devlieghere self.send_packet(command) 32101263c6cSJonas Devlieghere done = False 32201263c6cSJonas Devlieghere while not done: 32301263c6cSJonas Devlieghere response_or_request = self.recv_packet(filter_type=["response", "request"]) 32401263c6cSJonas Devlieghere if response_or_request is None: 32501263c6cSJonas Devlieghere desc = 'no response for "%s"' % (command["command"]) 32601263c6cSJonas Devlieghere raise ValueError(desc) 32701263c6cSJonas Devlieghere if response_or_request["type"] == "response": 32801263c6cSJonas Devlieghere self.validate_response(command, response_or_request) 32901263c6cSJonas Devlieghere return response_or_request 33001263c6cSJonas Devlieghere else: 33101263c6cSJonas Devlieghere self.reverse_requests.append(response_or_request) 33201263c6cSJonas Devlieghere if response_or_request["command"] == "runInTerminal": 33301263c6cSJonas Devlieghere subprocess.Popen( 33401263c6cSJonas Devlieghere response_or_request["arguments"]["args"], 33501263c6cSJonas Devlieghere env=response_or_request["arguments"]["env"], 33601263c6cSJonas Devlieghere ) 33701263c6cSJonas Devlieghere self.send_packet( 33801263c6cSJonas Devlieghere { 33901263c6cSJonas Devlieghere "type": "response", 34001263c6cSJonas Devlieghere "seq": -1, 34101263c6cSJonas Devlieghere "request_seq": response_or_request["seq"], 34201263c6cSJonas Devlieghere "success": True, 34301263c6cSJonas Devlieghere "command": "runInTerminal", 34401263c6cSJonas Devlieghere "body": {}, 34501263c6cSJonas Devlieghere }, 34601263c6cSJonas Devlieghere set_sequence=False, 34701263c6cSJonas Devlieghere ) 34801263c6cSJonas Devlieghere elif response_or_request["command"] == "startDebugging": 34901263c6cSJonas Devlieghere self.send_packet( 35001263c6cSJonas Devlieghere { 35101263c6cSJonas Devlieghere "type": "response", 35201263c6cSJonas Devlieghere "seq": -1, 35301263c6cSJonas Devlieghere "request_seq": response_or_request["seq"], 35401263c6cSJonas Devlieghere "success": True, 35501263c6cSJonas Devlieghere "command": "startDebugging", 35601263c6cSJonas Devlieghere "body": {}, 35701263c6cSJonas Devlieghere }, 35801263c6cSJonas Devlieghere set_sequence=False, 35901263c6cSJonas Devlieghere ) 36001263c6cSJonas Devlieghere else: 36101263c6cSJonas Devlieghere desc = 'unknown reverse request "%s"' % ( 36201263c6cSJonas Devlieghere response_or_request["command"] 36301263c6cSJonas Devlieghere ) 36401263c6cSJonas Devlieghere raise ValueError(desc) 36501263c6cSJonas Devlieghere 36601263c6cSJonas Devlieghere return None 36701263c6cSJonas Devlieghere 36801263c6cSJonas Devlieghere def wait_for_event(self, filter=None, timeout=None): 36901263c6cSJonas Devlieghere while True: 37001263c6cSJonas Devlieghere return self.recv_packet( 37101263c6cSJonas Devlieghere filter_type="event", filter_event=filter, timeout=timeout 37201263c6cSJonas Devlieghere ) 37301263c6cSJonas Devlieghere return None 37401263c6cSJonas Devlieghere 37501263c6cSJonas Devlieghere def wait_for_stopped(self, timeout=None): 37601263c6cSJonas Devlieghere stopped_events = [] 37701263c6cSJonas Devlieghere stopped_event = self.wait_for_event( 37801263c6cSJonas Devlieghere filter=["stopped", "exited"], timeout=timeout 37901263c6cSJonas Devlieghere ) 38001263c6cSJonas Devlieghere exited = False 38101263c6cSJonas Devlieghere while stopped_event: 38201263c6cSJonas Devlieghere stopped_events.append(stopped_event) 38301263c6cSJonas Devlieghere # If we exited, then we are done 38401263c6cSJonas Devlieghere if stopped_event["event"] == "exited": 38501263c6cSJonas Devlieghere self.exit_status = stopped_event["body"]["exitCode"] 38601263c6cSJonas Devlieghere exited = True 38701263c6cSJonas Devlieghere break 38801263c6cSJonas Devlieghere # Otherwise we stopped and there might be one or more 'stopped' 38901263c6cSJonas Devlieghere # events for each thread that stopped with a reason, so keep 39001263c6cSJonas Devlieghere # checking for more 'stopped' events and return all of them 39101263c6cSJonas Devlieghere stopped_event = self.wait_for_event(filter="stopped", timeout=0.25) 39201263c6cSJonas Devlieghere if exited: 39301263c6cSJonas Devlieghere self.threads = [] 39401263c6cSJonas Devlieghere return stopped_events 39501263c6cSJonas Devlieghere 39601263c6cSJonas Devlieghere def wait_for_exited(self): 39701263c6cSJonas Devlieghere event_dict = self.wait_for_event("exited") 39801263c6cSJonas Devlieghere if event_dict is None: 39901263c6cSJonas Devlieghere raise ValueError("didn't get exited event") 40001263c6cSJonas Devlieghere return event_dict 40101263c6cSJonas Devlieghere 40201263c6cSJonas Devlieghere def wait_for_terminated(self): 40301263c6cSJonas Devlieghere event_dict = self.wait_for_event("terminated") 40401263c6cSJonas Devlieghere if event_dict is None: 40501263c6cSJonas Devlieghere raise ValueError("didn't get terminated event") 40601263c6cSJonas Devlieghere return event_dict 40701263c6cSJonas Devlieghere 40801263c6cSJonas Devlieghere def get_initialize_value(self, key): 40901263c6cSJonas Devlieghere """Get a value for the given key if it there is a key/value pair in 41001263c6cSJonas Devlieghere the "initialize" request response body. 41101263c6cSJonas Devlieghere """ 41201263c6cSJonas Devlieghere if self.initialize_body and key in self.initialize_body: 41301263c6cSJonas Devlieghere return self.initialize_body[key] 41401263c6cSJonas Devlieghere return None 41501263c6cSJonas Devlieghere 41601263c6cSJonas Devlieghere def get_threads(self): 41701263c6cSJonas Devlieghere if self.threads is None: 41801263c6cSJonas Devlieghere self.request_threads() 41901263c6cSJonas Devlieghere return self.threads 42001263c6cSJonas Devlieghere 42101263c6cSJonas Devlieghere def get_thread_id(self, threadIndex=0): 42201263c6cSJonas Devlieghere """Utility function to get the first thread ID in the thread list. 42301263c6cSJonas Devlieghere If the thread list is empty, then fetch the threads. 42401263c6cSJonas Devlieghere """ 42501263c6cSJonas Devlieghere if self.threads is None: 42601263c6cSJonas Devlieghere self.request_threads() 42701263c6cSJonas Devlieghere if self.threads and threadIndex < len(self.threads): 42801263c6cSJonas Devlieghere return self.threads[threadIndex]["id"] 42901263c6cSJonas Devlieghere return None 43001263c6cSJonas Devlieghere 43101263c6cSJonas Devlieghere def get_stackFrame(self, frameIndex=0, threadId=None): 43201263c6cSJonas Devlieghere """Get a single "StackFrame" object from a "stackTrace" request and 43301263c6cSJonas Devlieghere return the "StackFrame" as a python dictionary, or None on failure 43401263c6cSJonas Devlieghere """ 43501263c6cSJonas Devlieghere if threadId is None: 43601263c6cSJonas Devlieghere threadId = self.get_thread_id() 43701263c6cSJonas Devlieghere if threadId is None: 43801263c6cSJonas Devlieghere print("invalid threadId") 43901263c6cSJonas Devlieghere return None 44001263c6cSJonas Devlieghere response = self.request_stackTrace(threadId, startFrame=frameIndex, levels=1) 44101263c6cSJonas Devlieghere if response: 44201263c6cSJonas Devlieghere return response["body"]["stackFrames"][0] 44301263c6cSJonas Devlieghere print("invalid response") 44401263c6cSJonas Devlieghere return None 44501263c6cSJonas Devlieghere 44601263c6cSJonas Devlieghere def get_completions(self, text, frameId=None): 44701263c6cSJonas Devlieghere if frameId is None: 44801263c6cSJonas Devlieghere stackFrame = self.get_stackFrame() 44901263c6cSJonas Devlieghere frameId = stackFrame["id"] 45001263c6cSJonas Devlieghere response = self.request_completions(text, frameId) 45101263c6cSJonas Devlieghere return response["body"]["targets"] 45201263c6cSJonas Devlieghere 453b8d38bb5Sjeffreytan81 def get_scope_variables(self, scope_name, frameIndex=0, threadId=None, is_hex=None): 45401263c6cSJonas Devlieghere stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) 45501263c6cSJonas Devlieghere if stackFrame is None: 45601263c6cSJonas Devlieghere return [] 45701263c6cSJonas Devlieghere frameId = stackFrame["id"] 45801263c6cSJonas Devlieghere if frameId in self.frame_scopes: 45901263c6cSJonas Devlieghere frame_scopes = self.frame_scopes[frameId] 46001263c6cSJonas Devlieghere else: 46101263c6cSJonas Devlieghere scopes_response = self.request_scopes(frameId) 46201263c6cSJonas Devlieghere frame_scopes = scopes_response["body"]["scopes"] 46301263c6cSJonas Devlieghere self.frame_scopes[frameId] = frame_scopes 46401263c6cSJonas Devlieghere for scope in frame_scopes: 46501263c6cSJonas Devlieghere if scope["name"] == scope_name: 46601263c6cSJonas Devlieghere varRef = scope["variablesReference"] 467b8d38bb5Sjeffreytan81 variables_response = self.request_variables(varRef, is_hex=is_hex) 46801263c6cSJonas Devlieghere if variables_response: 46901263c6cSJonas Devlieghere if "body" in variables_response: 47001263c6cSJonas Devlieghere body = variables_response["body"] 47101263c6cSJonas Devlieghere if "variables" in body: 47201263c6cSJonas Devlieghere vars = body["variables"] 47301263c6cSJonas Devlieghere return vars 47401263c6cSJonas Devlieghere return [] 47501263c6cSJonas Devlieghere 47601263c6cSJonas Devlieghere def get_global_variables(self, frameIndex=0, threadId=None): 47701263c6cSJonas Devlieghere return self.get_scope_variables( 47801263c6cSJonas Devlieghere "Globals", frameIndex=frameIndex, threadId=threadId 47901263c6cSJonas Devlieghere ) 48001263c6cSJonas Devlieghere 481b8d38bb5Sjeffreytan81 def get_local_variables(self, frameIndex=0, threadId=None, is_hex=None): 48201263c6cSJonas Devlieghere return self.get_scope_variables( 483b8d38bb5Sjeffreytan81 "Locals", frameIndex=frameIndex, threadId=threadId, is_hex=is_hex 48401263c6cSJonas Devlieghere ) 48501263c6cSJonas Devlieghere 48601263c6cSJonas Devlieghere def get_registers(self, frameIndex=0, threadId=None): 48701263c6cSJonas Devlieghere return self.get_scope_variables( 48801263c6cSJonas Devlieghere "Registers", frameIndex=frameIndex, threadId=threadId 48901263c6cSJonas Devlieghere ) 49001263c6cSJonas Devlieghere 491b8d38bb5Sjeffreytan81 def get_local_variable(self, name, frameIndex=0, threadId=None, is_hex=None): 492b8d38bb5Sjeffreytan81 locals = self.get_local_variables( 493b8d38bb5Sjeffreytan81 frameIndex=frameIndex, threadId=threadId, is_hex=is_hex 494b8d38bb5Sjeffreytan81 ) 49501263c6cSJonas Devlieghere for local in locals: 49601263c6cSJonas Devlieghere if "name" in local and local["name"] == name: 49701263c6cSJonas Devlieghere return local 49801263c6cSJonas Devlieghere return None 49901263c6cSJonas Devlieghere 500b8d38bb5Sjeffreytan81 def get_local_variable_value(self, name, frameIndex=0, threadId=None, is_hex=None): 50101263c6cSJonas Devlieghere variable = self.get_local_variable( 502b8d38bb5Sjeffreytan81 name, frameIndex=frameIndex, threadId=threadId, is_hex=is_hex 50301263c6cSJonas Devlieghere ) 50401263c6cSJonas Devlieghere if variable and "value" in variable: 50501263c6cSJonas Devlieghere return variable["value"] 50601263c6cSJonas Devlieghere return None 50701263c6cSJonas Devlieghere 508b8d38bb5Sjeffreytan81 def get_local_variable_child( 509b8d38bb5Sjeffreytan81 self, name, child_name, frameIndex=0, threadId=None, is_hex=None 510b8d38bb5Sjeffreytan81 ): 511df6f756aSZequan Wu local = self.get_local_variable(name, frameIndex, threadId) 512df6f756aSZequan Wu if local["variablesReference"] == 0: 513df6f756aSZequan Wu return None 514b8d38bb5Sjeffreytan81 children = self.request_variables(local["variablesReference"], is_hex=is_hex)[ 515b8d38bb5Sjeffreytan81 "body" 516b8d38bb5Sjeffreytan81 ]["variables"] 517df6f756aSZequan Wu for child in children: 518df6f756aSZequan Wu if child["name"] == child_name: 519df6f756aSZequan Wu return child 520df6f756aSZequan Wu return None 521df6f756aSZequan Wu 52201263c6cSJonas Devlieghere def replay_packets(self, replay_file_path): 52301263c6cSJonas Devlieghere f = open(replay_file_path, "r") 52401263c6cSJonas Devlieghere mode = "invalid" 52501263c6cSJonas Devlieghere set_sequence = False 52601263c6cSJonas Devlieghere command_dict = None 52701263c6cSJonas Devlieghere while mode != "eof": 52801263c6cSJonas Devlieghere if mode == "invalid": 52901263c6cSJonas Devlieghere line = f.readline() 53001263c6cSJonas Devlieghere if line.startswith("to adapter:"): 53101263c6cSJonas Devlieghere mode = "send" 53201263c6cSJonas Devlieghere elif line.startswith("from adapter:"): 53301263c6cSJonas Devlieghere mode = "recv" 53401263c6cSJonas Devlieghere elif mode == "send": 53501263c6cSJonas Devlieghere command_dict = read_packet(f) 53601263c6cSJonas Devlieghere # Skip the end of line that follows the JSON 53701263c6cSJonas Devlieghere f.readline() 53801263c6cSJonas Devlieghere if command_dict is None: 53901263c6cSJonas Devlieghere raise ValueError("decode packet failed from replay file") 54001263c6cSJonas Devlieghere print("Sending:") 54101263c6cSJonas Devlieghere pprint.PrettyPrinter(indent=2).pprint(command_dict) 54201263c6cSJonas Devlieghere # raw_input('Press ENTER to send:') 54301263c6cSJonas Devlieghere self.send_packet(command_dict, set_sequence) 54401263c6cSJonas Devlieghere mode = "invalid" 54501263c6cSJonas Devlieghere elif mode == "recv": 54601263c6cSJonas Devlieghere print("Replay response:") 54701263c6cSJonas Devlieghere replay_response = read_packet(f) 54801263c6cSJonas Devlieghere # Skip the end of line that follows the JSON 54901263c6cSJonas Devlieghere f.readline() 55001263c6cSJonas Devlieghere pprint.PrettyPrinter(indent=2).pprint(replay_response) 55101263c6cSJonas Devlieghere actual_response = self.recv_packet() 55201263c6cSJonas Devlieghere if actual_response: 55301263c6cSJonas Devlieghere type = actual_response["type"] 55401263c6cSJonas Devlieghere print("Actual response:") 55501263c6cSJonas Devlieghere if type == "response": 55601263c6cSJonas Devlieghere self.validate_response(command_dict, actual_response) 55701263c6cSJonas Devlieghere pprint.PrettyPrinter(indent=2).pprint(actual_response) 55801263c6cSJonas Devlieghere else: 55901263c6cSJonas Devlieghere print("error: didn't get a valid response") 56001263c6cSJonas Devlieghere mode = "invalid" 56101263c6cSJonas Devlieghere 56201263c6cSJonas Devlieghere def request_attach( 56301263c6cSJonas Devlieghere self, 56401263c6cSJonas Devlieghere program=None, 56501263c6cSJonas Devlieghere pid=None, 56601263c6cSJonas Devlieghere waitFor=None, 56701263c6cSJonas Devlieghere trace=None, 56801263c6cSJonas Devlieghere initCommands=None, 56901263c6cSJonas Devlieghere preRunCommands=None, 57001263c6cSJonas Devlieghere stopCommands=None, 57101263c6cSJonas Devlieghere exitCommands=None, 57201263c6cSJonas Devlieghere attachCommands=None, 57301263c6cSJonas Devlieghere terminateCommands=None, 57401263c6cSJonas Devlieghere coreFile=None, 57501263c6cSJonas Devlieghere postRunCommands=None, 57601263c6cSJonas Devlieghere sourceMap=None, 577a52be0ccSSanthosh Kumar Ellendula gdbRemotePort=None, 578a52be0ccSSanthosh Kumar Ellendula gdbRemoteHostname=None, 57901263c6cSJonas Devlieghere ): 58001263c6cSJonas Devlieghere args_dict = {} 58101263c6cSJonas Devlieghere if pid is not None: 58201263c6cSJonas Devlieghere args_dict["pid"] = pid 58301263c6cSJonas Devlieghere if program is not None: 58401263c6cSJonas Devlieghere args_dict["program"] = program 58501263c6cSJonas Devlieghere if waitFor is not None: 58601263c6cSJonas Devlieghere args_dict["waitFor"] = waitFor 58701263c6cSJonas Devlieghere if trace: 58801263c6cSJonas Devlieghere args_dict["trace"] = trace 58901263c6cSJonas Devlieghere args_dict["initCommands"] = self.init_commands 59001263c6cSJonas Devlieghere if initCommands: 59101263c6cSJonas Devlieghere args_dict["initCommands"].extend(initCommands) 59201263c6cSJonas Devlieghere if preRunCommands: 59301263c6cSJonas Devlieghere args_dict["preRunCommands"] = preRunCommands 59401263c6cSJonas Devlieghere if stopCommands: 59501263c6cSJonas Devlieghere args_dict["stopCommands"] = stopCommands 59601263c6cSJonas Devlieghere if exitCommands: 59701263c6cSJonas Devlieghere args_dict["exitCommands"] = exitCommands 59801263c6cSJonas Devlieghere if terminateCommands: 59901263c6cSJonas Devlieghere args_dict["terminateCommands"] = terminateCommands 60001263c6cSJonas Devlieghere if attachCommands: 60101263c6cSJonas Devlieghere args_dict["attachCommands"] = attachCommands 60201263c6cSJonas Devlieghere if coreFile: 60301263c6cSJonas Devlieghere args_dict["coreFile"] = coreFile 60401263c6cSJonas Devlieghere if postRunCommands: 60501263c6cSJonas Devlieghere args_dict["postRunCommands"] = postRunCommands 60601263c6cSJonas Devlieghere if sourceMap: 60701263c6cSJonas Devlieghere args_dict["sourceMap"] = sourceMap 608a52be0ccSSanthosh Kumar Ellendula if gdbRemotePort is not None: 609a52be0ccSSanthosh Kumar Ellendula args_dict["gdb-remote-port"] = gdbRemotePort 610a52be0ccSSanthosh Kumar Ellendula if gdbRemoteHostname is not None: 611a52be0ccSSanthosh Kumar Ellendula args_dict["gdb-remote-hostname"] = gdbRemoteHostname 61201263c6cSJonas Devlieghere command_dict = {"command": "attach", "type": "request", "arguments": args_dict} 61301263c6cSJonas Devlieghere return self.send_recv(command_dict) 61401263c6cSJonas Devlieghere 61501263c6cSJonas Devlieghere def request_configurationDone(self): 61601263c6cSJonas Devlieghere command_dict = { 61701263c6cSJonas Devlieghere "command": "configurationDone", 61801263c6cSJonas Devlieghere "type": "request", 61901263c6cSJonas Devlieghere "arguments": {}, 62001263c6cSJonas Devlieghere } 62101263c6cSJonas Devlieghere response = self.send_recv(command_dict) 62201263c6cSJonas Devlieghere if response: 62301263c6cSJonas Devlieghere self.configuration_done_sent = True 62401263c6cSJonas Devlieghere return response 62501263c6cSJonas Devlieghere 62601263c6cSJonas Devlieghere def _process_stopped(self): 62701263c6cSJonas Devlieghere self.threads = None 62801263c6cSJonas Devlieghere self.frame_scopes = {} 62901263c6cSJonas Devlieghere 63001263c6cSJonas Devlieghere def request_continue(self, threadId=None): 63101263c6cSJonas Devlieghere if self.exit_status is not None: 63201263c6cSJonas Devlieghere raise ValueError("request_continue called after process exited") 63301263c6cSJonas Devlieghere # If we have launched or attached, then the first continue is done by 63401263c6cSJonas Devlieghere # sending the 'configurationDone' request 63501263c6cSJonas Devlieghere if not self.configuration_done_sent: 63601263c6cSJonas Devlieghere return self.request_configurationDone() 63701263c6cSJonas Devlieghere args_dict = {} 63801263c6cSJonas Devlieghere if threadId is None: 63901263c6cSJonas Devlieghere threadId = self.get_thread_id() 64001263c6cSJonas Devlieghere args_dict["threadId"] = threadId 64101263c6cSJonas Devlieghere command_dict = { 64201263c6cSJonas Devlieghere "command": "continue", 64301263c6cSJonas Devlieghere "type": "request", 64401263c6cSJonas Devlieghere "arguments": args_dict, 64501263c6cSJonas Devlieghere } 64601263c6cSJonas Devlieghere response = self.send_recv(command_dict) 64701263c6cSJonas Devlieghere # Caller must still call wait_for_stopped. 64801263c6cSJonas Devlieghere return response 64901263c6cSJonas Devlieghere 65001263c6cSJonas Devlieghere def request_restart(self, restartArguments=None): 65101263c6cSJonas Devlieghere command_dict = { 65201263c6cSJonas Devlieghere "command": "restart", 65301263c6cSJonas Devlieghere "type": "request", 65401263c6cSJonas Devlieghere } 65501263c6cSJonas Devlieghere if restartArguments: 65601263c6cSJonas Devlieghere command_dict["arguments"] = restartArguments 65701263c6cSJonas Devlieghere 65801263c6cSJonas Devlieghere response = self.send_recv(command_dict) 65901263c6cSJonas Devlieghere # Caller must still call wait_for_stopped. 66001263c6cSJonas Devlieghere return response 66101263c6cSJonas Devlieghere 66201263c6cSJonas Devlieghere def request_disconnect(self, terminateDebuggee=None): 66301263c6cSJonas Devlieghere args_dict = {} 66401263c6cSJonas Devlieghere if terminateDebuggee is not None: 66501263c6cSJonas Devlieghere if terminateDebuggee: 66601263c6cSJonas Devlieghere args_dict["terminateDebuggee"] = True 66701263c6cSJonas Devlieghere else: 66801263c6cSJonas Devlieghere args_dict["terminateDebuggee"] = False 66901263c6cSJonas Devlieghere command_dict = { 67001263c6cSJonas Devlieghere "command": "disconnect", 67101263c6cSJonas Devlieghere "type": "request", 67201263c6cSJonas Devlieghere "arguments": args_dict, 67301263c6cSJonas Devlieghere } 67401263c6cSJonas Devlieghere return self.send_recv(command_dict) 67501263c6cSJonas Devlieghere 67601263c6cSJonas Devlieghere def request_disassemble( 67701263c6cSJonas Devlieghere self, memoryReference, offset=-50, instructionCount=200, resolveSymbols=True 67801263c6cSJonas Devlieghere ): 67901263c6cSJonas Devlieghere args_dict = { 68001263c6cSJonas Devlieghere "memoryReference": memoryReference, 68101263c6cSJonas Devlieghere "offset": offset, 68201263c6cSJonas Devlieghere "instructionCount": instructionCount, 68301263c6cSJonas Devlieghere "resolveSymbols": resolveSymbols, 68401263c6cSJonas Devlieghere } 68501263c6cSJonas Devlieghere command_dict = { 68601263c6cSJonas Devlieghere "command": "disassemble", 68701263c6cSJonas Devlieghere "type": "request", 68801263c6cSJonas Devlieghere "arguments": args_dict, 68901263c6cSJonas Devlieghere } 69001263c6cSJonas Devlieghere instructions = self.send_recv(command_dict)["body"]["instructions"] 69101263c6cSJonas Devlieghere for inst in instructions: 69201263c6cSJonas Devlieghere self.disassembled_instructions[inst["address"]] = inst 69301263c6cSJonas Devlieghere 6943acb1eacSAdrian Vogelsgesang def request_readMemory(self, memoryReference, offset, count): 6953acb1eacSAdrian Vogelsgesang args_dict = { 6963acb1eacSAdrian Vogelsgesang "memoryReference": memoryReference, 6973acb1eacSAdrian Vogelsgesang "offset": offset, 6983acb1eacSAdrian Vogelsgesang "count": count, 6993acb1eacSAdrian Vogelsgesang } 7003acb1eacSAdrian Vogelsgesang command_dict = { 7013acb1eacSAdrian Vogelsgesang "command": "readMemory", 7023acb1eacSAdrian Vogelsgesang "type": "request", 7033acb1eacSAdrian Vogelsgesang "arguments": args_dict, 7043acb1eacSAdrian Vogelsgesang } 7053acb1eacSAdrian Vogelsgesang return self.send_recv(command_dict) 7063acb1eacSAdrian Vogelsgesang 70701263c6cSJonas Devlieghere def request_evaluate(self, expression, frameIndex=0, threadId=None, context=None): 70801263c6cSJonas Devlieghere stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) 70901263c6cSJonas Devlieghere if stackFrame is None: 71001263c6cSJonas Devlieghere return [] 71101263c6cSJonas Devlieghere args_dict = { 71201263c6cSJonas Devlieghere "expression": expression, 71301263c6cSJonas Devlieghere "context": context, 71401263c6cSJonas Devlieghere "frameId": stackFrame["id"], 71501263c6cSJonas Devlieghere } 71601263c6cSJonas Devlieghere command_dict = { 71701263c6cSJonas Devlieghere "command": "evaluate", 71801263c6cSJonas Devlieghere "type": "request", 71901263c6cSJonas Devlieghere "arguments": args_dict, 72001263c6cSJonas Devlieghere } 72101263c6cSJonas Devlieghere return self.send_recv(command_dict) 72201263c6cSJonas Devlieghere 7235b4100ccSJohn Harrison def request_exceptionInfo(self, threadId=None): 7245b4100ccSJohn Harrison if threadId is None: 7255b4100ccSJohn Harrison threadId = self.get_thread_id() 7265b4100ccSJohn Harrison args_dict = {"threadId": threadId} 7275b4100ccSJohn Harrison command_dict = { 7285b4100ccSJohn Harrison "command": "exceptionInfo", 7295b4100ccSJohn Harrison "type": "request", 7305b4100ccSJohn Harrison "arguments": args_dict, 7315b4100ccSJohn Harrison } 7325b4100ccSJohn Harrison return self.send_recv(command_dict) 7335b4100ccSJohn Harrison 73401263c6cSJonas Devlieghere def request_initialize(self, sourceInitFile): 73501263c6cSJonas Devlieghere command_dict = { 73601263c6cSJonas Devlieghere "command": "initialize", 73701263c6cSJonas Devlieghere "type": "request", 73801263c6cSJonas Devlieghere "arguments": { 73901263c6cSJonas Devlieghere "adapterID": "lldb-native", 74001263c6cSJonas Devlieghere "clientID": "vscode", 74101263c6cSJonas Devlieghere "columnsStartAt1": True, 74201263c6cSJonas Devlieghere "linesStartAt1": True, 74301263c6cSJonas Devlieghere "locale": "en-us", 74401263c6cSJonas Devlieghere "pathFormat": "path", 74501263c6cSJonas Devlieghere "supportsRunInTerminalRequest": True, 74601263c6cSJonas Devlieghere "supportsVariablePaging": True, 74701263c6cSJonas Devlieghere "supportsVariableType": True, 74801263c6cSJonas Devlieghere "supportsStartDebuggingRequest": True, 74901263c6cSJonas Devlieghere "sourceInitFile": sourceInitFile, 75001263c6cSJonas Devlieghere }, 75101263c6cSJonas Devlieghere } 75201263c6cSJonas Devlieghere response = self.send_recv(command_dict) 75301263c6cSJonas Devlieghere if response: 75401263c6cSJonas Devlieghere if "body" in response: 75501263c6cSJonas Devlieghere self.initialize_body = response["body"] 75601263c6cSJonas Devlieghere return response 75701263c6cSJonas Devlieghere 75801263c6cSJonas Devlieghere def request_launch( 75901263c6cSJonas Devlieghere self, 76001263c6cSJonas Devlieghere program, 76101263c6cSJonas Devlieghere args=None, 76201263c6cSJonas Devlieghere cwd=None, 76301263c6cSJonas Devlieghere env=None, 76401263c6cSJonas Devlieghere stopOnEntry=False, 76501263c6cSJonas Devlieghere disableASLR=True, 76601263c6cSJonas Devlieghere disableSTDIO=False, 76701263c6cSJonas Devlieghere shellExpandArguments=False, 76801263c6cSJonas Devlieghere trace=False, 76901263c6cSJonas Devlieghere initCommands=None, 77001263c6cSJonas Devlieghere preRunCommands=None, 77101263c6cSJonas Devlieghere stopCommands=None, 77201263c6cSJonas Devlieghere exitCommands=None, 77301263c6cSJonas Devlieghere terminateCommands=None, 77401263c6cSJonas Devlieghere sourcePath=None, 77501263c6cSJonas Devlieghere debuggerRoot=None, 77601263c6cSJonas Devlieghere launchCommands=None, 77701263c6cSJonas Devlieghere sourceMap=None, 77801263c6cSJonas Devlieghere runInTerminal=False, 77901263c6cSJonas Devlieghere postRunCommands=None, 78001263c6cSJonas Devlieghere enableAutoVariableSummaries=False, 78119ecdedcSAdrian Vogelsgesang displayExtendedBacktrace=False, 78201263c6cSJonas Devlieghere enableSyntheticChildDebugging=False, 78385ee3fc7Sjeffreytan81 commandEscapePrefix=None, 784d9ec4b24SWalter Erquinigo customFrameFormat=None, 7851654d7dcSWalter Erquinigo customThreadFormat=None, 78601263c6cSJonas Devlieghere ): 78701263c6cSJonas Devlieghere args_dict = {"program": program} 78801263c6cSJonas Devlieghere if args: 78901263c6cSJonas Devlieghere args_dict["args"] = args 79001263c6cSJonas Devlieghere if cwd: 79101263c6cSJonas Devlieghere args_dict["cwd"] = cwd 79201263c6cSJonas Devlieghere if env: 79301263c6cSJonas Devlieghere args_dict["env"] = env 79401263c6cSJonas Devlieghere if stopOnEntry: 79501263c6cSJonas Devlieghere args_dict["stopOnEntry"] = stopOnEntry 79601263c6cSJonas Devlieghere if disableSTDIO: 79701263c6cSJonas Devlieghere args_dict["disableSTDIO"] = disableSTDIO 79801263c6cSJonas Devlieghere if shellExpandArguments: 79901263c6cSJonas Devlieghere args_dict["shellExpandArguments"] = shellExpandArguments 80001263c6cSJonas Devlieghere if trace: 80101263c6cSJonas Devlieghere args_dict["trace"] = trace 80201263c6cSJonas Devlieghere args_dict["initCommands"] = self.init_commands 80301263c6cSJonas Devlieghere if initCommands: 80401263c6cSJonas Devlieghere args_dict["initCommands"].extend(initCommands) 80501263c6cSJonas Devlieghere if preRunCommands: 80601263c6cSJonas Devlieghere args_dict["preRunCommands"] = preRunCommands 80701263c6cSJonas Devlieghere if stopCommands: 80801263c6cSJonas Devlieghere args_dict["stopCommands"] = stopCommands 80901263c6cSJonas Devlieghere if exitCommands: 81001263c6cSJonas Devlieghere args_dict["exitCommands"] = exitCommands 81101263c6cSJonas Devlieghere if terminateCommands: 81201263c6cSJonas Devlieghere args_dict["terminateCommands"] = terminateCommands 81301263c6cSJonas Devlieghere if sourcePath: 81401263c6cSJonas Devlieghere args_dict["sourcePath"] = sourcePath 81501263c6cSJonas Devlieghere if debuggerRoot: 81601263c6cSJonas Devlieghere args_dict["debuggerRoot"] = debuggerRoot 81701263c6cSJonas Devlieghere if launchCommands: 81801263c6cSJonas Devlieghere args_dict["launchCommands"] = launchCommands 81901263c6cSJonas Devlieghere if sourceMap: 82001263c6cSJonas Devlieghere args_dict["sourceMap"] = sourceMap 82101263c6cSJonas Devlieghere if runInTerminal: 82201263c6cSJonas Devlieghere args_dict["runInTerminal"] = runInTerminal 82301263c6cSJonas Devlieghere if postRunCommands: 82401263c6cSJonas Devlieghere args_dict["postRunCommands"] = postRunCommands 825d9ec4b24SWalter Erquinigo if customFrameFormat: 826d9ec4b24SWalter Erquinigo args_dict["customFrameFormat"] = customFrameFormat 8271654d7dcSWalter Erquinigo if customThreadFormat: 8281654d7dcSWalter Erquinigo args_dict["customThreadFormat"] = customThreadFormat 829d9ec4b24SWalter Erquinigo 830b4e1af00SMichael Buch args_dict["disableASLR"] = disableASLR 83101263c6cSJonas Devlieghere args_dict["enableAutoVariableSummaries"] = enableAutoVariableSummaries 83201263c6cSJonas Devlieghere args_dict["enableSyntheticChildDebugging"] = enableSyntheticChildDebugging 83319ecdedcSAdrian Vogelsgesang args_dict["displayExtendedBacktrace"] = displayExtendedBacktrace 83410664813SWalter Erquinigo args_dict["commandEscapePrefix"] = commandEscapePrefix 83501263c6cSJonas Devlieghere command_dict = {"command": "launch", "type": "request", "arguments": args_dict} 83601263c6cSJonas Devlieghere response = self.send_recv(command_dict) 83701263c6cSJonas Devlieghere 83801263c6cSJonas Devlieghere if response["success"]: 83901263c6cSJonas Devlieghere # Wait for a 'process' and 'initialized' event in any order 84001263c6cSJonas Devlieghere self.wait_for_event(filter=["process", "initialized"]) 84101263c6cSJonas Devlieghere self.wait_for_event(filter=["process", "initialized"]) 84201263c6cSJonas Devlieghere return response 84301263c6cSJonas Devlieghere 8446257a98bSAdrian Vogelsgesang def request_next(self, threadId, granularity="statement"): 84501263c6cSJonas Devlieghere if self.exit_status is not None: 84601263c6cSJonas Devlieghere raise ValueError("request_continue called after process exited") 8476257a98bSAdrian Vogelsgesang args_dict = {"threadId": threadId, "granularity": granularity} 84801263c6cSJonas Devlieghere command_dict = {"command": "next", "type": "request", "arguments": args_dict} 84901263c6cSJonas Devlieghere return self.send_recv(command_dict) 85001263c6cSJonas Devlieghere 8516257a98bSAdrian Vogelsgesang def request_stepIn(self, threadId, targetId, granularity="statement"): 85201263c6cSJonas Devlieghere if self.exit_status is not None: 8532f2e31c3Sjeffreytan81 raise ValueError("request_stepIn called after process exited") 8546257a98bSAdrian Vogelsgesang args_dict = { 8556257a98bSAdrian Vogelsgesang "threadId": threadId, 8566257a98bSAdrian Vogelsgesang "targetId": targetId, 8576257a98bSAdrian Vogelsgesang "granularity": granularity, 8586257a98bSAdrian Vogelsgesang } 85901263c6cSJonas Devlieghere command_dict = {"command": "stepIn", "type": "request", "arguments": args_dict} 86001263c6cSJonas Devlieghere return self.send_recv(command_dict) 86101263c6cSJonas Devlieghere 8622f2e31c3Sjeffreytan81 def request_stepInTargets(self, frameId): 8632f2e31c3Sjeffreytan81 if self.exit_status is not None: 8642f2e31c3Sjeffreytan81 raise ValueError("request_stepInTargets called after process exited") 8652f2e31c3Sjeffreytan81 args_dict = {"frameId": frameId} 8662f2e31c3Sjeffreytan81 command_dict = { 8672f2e31c3Sjeffreytan81 "command": "stepInTargets", 8682f2e31c3Sjeffreytan81 "type": "request", 8692f2e31c3Sjeffreytan81 "arguments": args_dict, 8702f2e31c3Sjeffreytan81 } 8712f2e31c3Sjeffreytan81 return self.send_recv(command_dict) 8722f2e31c3Sjeffreytan81 87301263c6cSJonas Devlieghere def request_stepOut(self, threadId): 87401263c6cSJonas Devlieghere if self.exit_status is not None: 8752f2e31c3Sjeffreytan81 raise ValueError("request_stepOut called after process exited") 87601263c6cSJonas Devlieghere args_dict = {"threadId": threadId} 87701263c6cSJonas Devlieghere command_dict = {"command": "stepOut", "type": "request", "arguments": args_dict} 87801263c6cSJonas Devlieghere return self.send_recv(command_dict) 87901263c6cSJonas Devlieghere 88001263c6cSJonas Devlieghere def request_pause(self, threadId=None): 88101263c6cSJonas Devlieghere if self.exit_status is not None: 8822f2e31c3Sjeffreytan81 raise ValueError("request_pause called after process exited") 88301263c6cSJonas Devlieghere if threadId is None: 88401263c6cSJonas Devlieghere threadId = self.get_thread_id() 88501263c6cSJonas Devlieghere args_dict = {"threadId": threadId} 88601263c6cSJonas Devlieghere command_dict = {"command": "pause", "type": "request", "arguments": args_dict} 88701263c6cSJonas Devlieghere return self.send_recv(command_dict) 88801263c6cSJonas Devlieghere 88901263c6cSJonas Devlieghere def request_scopes(self, frameId): 89001263c6cSJonas Devlieghere args_dict = {"frameId": frameId} 89101263c6cSJonas Devlieghere command_dict = {"command": "scopes", "type": "request", "arguments": args_dict} 89201263c6cSJonas Devlieghere return self.send_recv(command_dict) 89301263c6cSJonas Devlieghere 89401263c6cSJonas Devlieghere def request_setBreakpoints(self, file_path, line_array, data=None): 89501263c6cSJonas Devlieghere """data is array of parameters for breakpoints in line_array. 89601263c6cSJonas Devlieghere Each parameter object is 1:1 mapping with entries in line_entry. 89701263c6cSJonas Devlieghere It contains optional location/hitCondition/logMessage parameters. 89801263c6cSJonas Devlieghere """ 89901263c6cSJonas Devlieghere (dir, base) = os.path.split(file_path) 90001263c6cSJonas Devlieghere source_dict = {"name": base, "path": file_path} 90101263c6cSJonas Devlieghere args_dict = { 90201263c6cSJonas Devlieghere "source": source_dict, 90301263c6cSJonas Devlieghere "sourceModified": False, 90401263c6cSJonas Devlieghere } 90501263c6cSJonas Devlieghere if line_array is not None: 90601263c6cSJonas Devlieghere args_dict["lines"] = "%s" % line_array 90701263c6cSJonas Devlieghere breakpoints = [] 90801263c6cSJonas Devlieghere for i, line in enumerate(line_array): 90901263c6cSJonas Devlieghere breakpoint_data = None 91001263c6cSJonas Devlieghere if data is not None and i < len(data): 91101263c6cSJonas Devlieghere breakpoint_data = data[i] 91201263c6cSJonas Devlieghere bp = {"line": line} 91301263c6cSJonas Devlieghere if breakpoint_data is not None: 914*ceeb08b9SMichael Buch if "condition" in breakpoint_data and breakpoint_data["condition"]: 91501263c6cSJonas Devlieghere bp["condition"] = breakpoint_data["condition"] 916*ceeb08b9SMichael Buch if ( 917*ceeb08b9SMichael Buch "hitCondition" in breakpoint_data 918*ceeb08b9SMichael Buch and breakpoint_data["hitCondition"] 919*ceeb08b9SMichael Buch ): 92001263c6cSJonas Devlieghere bp["hitCondition"] = breakpoint_data["hitCondition"] 921*ceeb08b9SMichael Buch if ( 922*ceeb08b9SMichael Buch "logMessage" in breakpoint_data 923*ceeb08b9SMichael Buch and breakpoint_data["logMessage"] 924*ceeb08b9SMichael Buch ): 92501263c6cSJonas Devlieghere bp["logMessage"] = breakpoint_data["logMessage"] 92601263c6cSJonas Devlieghere breakpoints.append(bp) 92701263c6cSJonas Devlieghere args_dict["breakpoints"] = breakpoints 92801263c6cSJonas Devlieghere 92901263c6cSJonas Devlieghere command_dict = { 93001263c6cSJonas Devlieghere "command": "setBreakpoints", 93101263c6cSJonas Devlieghere "type": "request", 93201263c6cSJonas Devlieghere "arguments": args_dict, 93301263c6cSJonas Devlieghere } 93401263c6cSJonas Devlieghere return self.send_recv(command_dict) 93501263c6cSJonas Devlieghere 93601263c6cSJonas Devlieghere def request_setExceptionBreakpoints(self, filters): 93701263c6cSJonas Devlieghere args_dict = {"filters": filters} 93801263c6cSJonas Devlieghere command_dict = { 93901263c6cSJonas Devlieghere "command": "setExceptionBreakpoints", 94001263c6cSJonas Devlieghere "type": "request", 94101263c6cSJonas Devlieghere "arguments": args_dict, 94201263c6cSJonas Devlieghere } 94301263c6cSJonas Devlieghere return self.send_recv(command_dict) 94401263c6cSJonas Devlieghere 94501263c6cSJonas Devlieghere def request_setFunctionBreakpoints(self, names, condition=None, hitCondition=None): 94601263c6cSJonas Devlieghere breakpoints = [] 94701263c6cSJonas Devlieghere for name in names: 94801263c6cSJonas Devlieghere bp = {"name": name} 94901263c6cSJonas Devlieghere if condition is not None: 95001263c6cSJonas Devlieghere bp["condition"] = condition 95101263c6cSJonas Devlieghere if hitCondition is not None: 95201263c6cSJonas Devlieghere bp["hitCondition"] = hitCondition 95301263c6cSJonas Devlieghere breakpoints.append(bp) 95401263c6cSJonas Devlieghere args_dict = {"breakpoints": breakpoints} 95501263c6cSJonas Devlieghere command_dict = { 95601263c6cSJonas Devlieghere "command": "setFunctionBreakpoints", 95701263c6cSJonas Devlieghere "type": "request", 95801263c6cSJonas Devlieghere "arguments": args_dict, 95901263c6cSJonas Devlieghere } 96001263c6cSJonas Devlieghere return self.send_recv(command_dict) 96101263c6cSJonas Devlieghere 962df6f756aSZequan Wu def request_dataBreakpointInfo( 963df6f756aSZequan Wu self, variablesReference, name, frameIndex=0, threadId=None 964df6f756aSZequan Wu ): 965df6f756aSZequan Wu stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) 966df6f756aSZequan Wu if stackFrame is None: 967df6f756aSZequan Wu return [] 968df6f756aSZequan Wu args_dict = { 969df6f756aSZequan Wu "variablesReference": variablesReference, 970df6f756aSZequan Wu "name": name, 971df6f756aSZequan Wu "frameId": stackFrame["id"], 972df6f756aSZequan Wu } 973df6f756aSZequan Wu command_dict = { 974df6f756aSZequan Wu "command": "dataBreakpointInfo", 975df6f756aSZequan Wu "type": "request", 976df6f756aSZequan Wu "arguments": args_dict, 977df6f756aSZequan Wu } 978df6f756aSZequan Wu return self.send_recv(command_dict) 979df6f756aSZequan Wu 980df6f756aSZequan Wu def request_setDataBreakpoint(self, dataBreakpoints): 981df6f756aSZequan Wu """dataBreakpoints is a list of dictionary with following fields: 982df6f756aSZequan Wu { 983df6f756aSZequan Wu dataId: (address in hex)/(size in bytes) 984df6f756aSZequan Wu accessType: read/write/readWrite 985df6f756aSZequan Wu [condition]: string 986df6f756aSZequan Wu [hitCondition]: string 987df6f756aSZequan Wu } 988df6f756aSZequan Wu """ 989df6f756aSZequan Wu args_dict = {"breakpoints": dataBreakpoints} 990df6f756aSZequan Wu command_dict = { 991df6f756aSZequan Wu "command": "setDataBreakpoints", 992df6f756aSZequan Wu "type": "request", 993df6f756aSZequan Wu "arguments": args_dict, 994df6f756aSZequan Wu } 995df6f756aSZequan Wu return self.send_recv(command_dict) 996df6f756aSZequan Wu 99701263c6cSJonas Devlieghere def request_compileUnits(self, moduleId): 99801263c6cSJonas Devlieghere args_dict = {"moduleId": moduleId} 99901263c6cSJonas Devlieghere command_dict = { 100001263c6cSJonas Devlieghere "command": "compileUnits", 100101263c6cSJonas Devlieghere "type": "request", 100201263c6cSJonas Devlieghere "arguments": args_dict, 100301263c6cSJonas Devlieghere } 100401263c6cSJonas Devlieghere response = self.send_recv(command_dict) 100501263c6cSJonas Devlieghere return response 100601263c6cSJonas Devlieghere 100701263c6cSJonas Devlieghere def request_completions(self, text, frameId=None): 1008a5876befSAdrian Vogelsgesang args_dict = {"text": text, "column": len(text) + 1} 100901263c6cSJonas Devlieghere if frameId: 101001263c6cSJonas Devlieghere args_dict["frameId"] = frameId 101101263c6cSJonas Devlieghere command_dict = { 101201263c6cSJonas Devlieghere "command": "completions", 101301263c6cSJonas Devlieghere "type": "request", 101401263c6cSJonas Devlieghere "arguments": args_dict, 101501263c6cSJonas Devlieghere } 101601263c6cSJonas Devlieghere return self.send_recv(command_dict) 101701263c6cSJonas Devlieghere 101801263c6cSJonas Devlieghere def request_modules(self): 101901263c6cSJonas Devlieghere return self.send_recv({"command": "modules", "type": "request"}) 102001263c6cSJonas Devlieghere 102101263c6cSJonas Devlieghere def request_stackTrace( 102201263c6cSJonas Devlieghere self, threadId=None, startFrame=None, levels=None, dump=False 102301263c6cSJonas Devlieghere ): 102401263c6cSJonas Devlieghere if threadId is None: 102501263c6cSJonas Devlieghere threadId = self.get_thread_id() 102601263c6cSJonas Devlieghere args_dict = {"threadId": threadId} 102701263c6cSJonas Devlieghere if startFrame is not None: 102801263c6cSJonas Devlieghere args_dict["startFrame"] = startFrame 102901263c6cSJonas Devlieghere if levels is not None: 103001263c6cSJonas Devlieghere args_dict["levels"] = levels 103101263c6cSJonas Devlieghere command_dict = { 103201263c6cSJonas Devlieghere "command": "stackTrace", 103301263c6cSJonas Devlieghere "type": "request", 103401263c6cSJonas Devlieghere "arguments": args_dict, 103501263c6cSJonas Devlieghere } 103601263c6cSJonas Devlieghere response = self.send_recv(command_dict) 103701263c6cSJonas Devlieghere if dump: 103801263c6cSJonas Devlieghere for idx, frame in enumerate(response["body"]["stackFrames"]): 103901263c6cSJonas Devlieghere name = frame["name"] 104001263c6cSJonas Devlieghere if "line" in frame and "source" in frame: 104101263c6cSJonas Devlieghere source = frame["source"] 104201263c6cSJonas Devlieghere if "sourceReference" not in source: 104301263c6cSJonas Devlieghere if "name" in source: 104401263c6cSJonas Devlieghere source_name = source["name"] 104501263c6cSJonas Devlieghere line = frame["line"] 104601263c6cSJonas Devlieghere print("[%3u] %s @ %s:%u" % (idx, name, source_name, line)) 104701263c6cSJonas Devlieghere continue 104801263c6cSJonas Devlieghere print("[%3u] %s" % (idx, name)) 104901263c6cSJonas Devlieghere return response 105001263c6cSJonas Devlieghere 105101263c6cSJonas Devlieghere def request_threads(self): 105201263c6cSJonas Devlieghere """Request a list of all threads and combine any information from any 105301263c6cSJonas Devlieghere "stopped" events since those contain more information about why a 105401263c6cSJonas Devlieghere thread actually stopped. Returns an array of thread dictionaries 105501263c6cSJonas Devlieghere with information about all threads""" 105601263c6cSJonas Devlieghere command_dict = {"command": "threads", "type": "request", "arguments": {}} 105701263c6cSJonas Devlieghere response = self.send_recv(command_dict) 105801263c6cSJonas Devlieghere body = response["body"] 105901263c6cSJonas Devlieghere # Fill in "self.threads" correctly so that clients that call 106001263c6cSJonas Devlieghere # self.get_threads() or self.get_thread_id(...) can get information 106101263c6cSJonas Devlieghere # on threads when the process is stopped. 106201263c6cSJonas Devlieghere if "threads" in body: 106301263c6cSJonas Devlieghere self.threads = body["threads"] 106401263c6cSJonas Devlieghere for thread in self.threads: 106501263c6cSJonas Devlieghere # Copy the thread dictionary so we can add key/value pairs to 106601263c6cSJonas Devlieghere # it without affecting the original info from the "threads" 106701263c6cSJonas Devlieghere # command. 106801263c6cSJonas Devlieghere tid = thread["id"] 106901263c6cSJonas Devlieghere if tid in self.thread_stop_reasons: 107001263c6cSJonas Devlieghere thread_stop_info = self.thread_stop_reasons[tid] 107101263c6cSJonas Devlieghere copy_keys = ["reason", "description", "text"] 107201263c6cSJonas Devlieghere for key in copy_keys: 107301263c6cSJonas Devlieghere if key in thread_stop_info: 107401263c6cSJonas Devlieghere thread[key] = thread_stop_info[key] 107501263c6cSJonas Devlieghere else: 107601263c6cSJonas Devlieghere self.threads = None 107701263c6cSJonas Devlieghere return response 107801263c6cSJonas Devlieghere 1079b8d38bb5Sjeffreytan81 def request_variables( 1080b8d38bb5Sjeffreytan81 self, variablesReference, start=None, count=None, is_hex=None 1081b8d38bb5Sjeffreytan81 ): 108201263c6cSJonas Devlieghere args_dict = {"variablesReference": variablesReference} 108301263c6cSJonas Devlieghere if start is not None: 108401263c6cSJonas Devlieghere args_dict["start"] = start 108501263c6cSJonas Devlieghere if count is not None: 108601263c6cSJonas Devlieghere args_dict["count"] = count 1087b8d38bb5Sjeffreytan81 if is_hex is not None: 1088b8d38bb5Sjeffreytan81 args_dict["format"] = {"hex": is_hex} 108901263c6cSJonas Devlieghere command_dict = { 109001263c6cSJonas Devlieghere "command": "variables", 109101263c6cSJonas Devlieghere "type": "request", 109201263c6cSJonas Devlieghere "arguments": args_dict, 109301263c6cSJonas Devlieghere } 109401263c6cSJonas Devlieghere return self.send_recv(command_dict) 109501263c6cSJonas Devlieghere 109601263c6cSJonas Devlieghere def request_setVariable(self, containingVarRef, name, value, id=None): 109701263c6cSJonas Devlieghere args_dict = { 109801263c6cSJonas Devlieghere "variablesReference": containingVarRef, 109901263c6cSJonas Devlieghere "name": name, 110001263c6cSJonas Devlieghere "value": str(value), 110101263c6cSJonas Devlieghere } 110201263c6cSJonas Devlieghere if id is not None: 110301263c6cSJonas Devlieghere args_dict["id"] = id 110401263c6cSJonas Devlieghere command_dict = { 110501263c6cSJonas Devlieghere "command": "setVariable", 110601263c6cSJonas Devlieghere "type": "request", 110701263c6cSJonas Devlieghere "arguments": args_dict, 110801263c6cSJonas Devlieghere } 110901263c6cSJonas Devlieghere return self.send_recv(command_dict) 111001263c6cSJonas Devlieghere 11110cc2cd78SAdrian Vogelsgesang def request_locations(self, locationReference): 11120cc2cd78SAdrian Vogelsgesang args_dict = { 11130cc2cd78SAdrian Vogelsgesang "locationReference": locationReference, 11140cc2cd78SAdrian Vogelsgesang } 11150cc2cd78SAdrian Vogelsgesang command_dict = { 11160cc2cd78SAdrian Vogelsgesang "command": "locations", 11170cc2cd78SAdrian Vogelsgesang "type": "request", 11180cc2cd78SAdrian Vogelsgesang "arguments": args_dict, 11190cc2cd78SAdrian Vogelsgesang } 11200cc2cd78SAdrian Vogelsgesang return self.send_recv(command_dict) 11210cc2cd78SAdrian Vogelsgesang 112201263c6cSJonas Devlieghere def request_testGetTargetBreakpoints(self): 112301263c6cSJonas Devlieghere """A request packet used in the LLDB test suite to get all currently 112401263c6cSJonas Devlieghere set breakpoint infos for all breakpoints currently set in the 112501263c6cSJonas Devlieghere target. 112601263c6cSJonas Devlieghere """ 112701263c6cSJonas Devlieghere command_dict = { 112801263c6cSJonas Devlieghere "command": "_testGetTargetBreakpoints", 112901263c6cSJonas Devlieghere "type": "request", 113001263c6cSJonas Devlieghere "arguments": {}, 113101263c6cSJonas Devlieghere } 113201263c6cSJonas Devlieghere return self.send_recv(command_dict) 113301263c6cSJonas Devlieghere 113401263c6cSJonas Devlieghere def terminate(self): 113501263c6cSJonas Devlieghere self.send.close() 113601263c6cSJonas Devlieghere # self.recv.close() 113701263c6cSJonas Devlieghere 113889c27d6bSSanthosh Kumar Ellendula def request_setInstructionBreakpoints(self, memory_reference=[]): 113989c27d6bSSanthosh Kumar Ellendula breakpoints = [] 114089c27d6bSSanthosh Kumar Ellendula for i in memory_reference: 114189c27d6bSSanthosh Kumar Ellendula args_dict = { 114289c27d6bSSanthosh Kumar Ellendula "instructionReference": i, 114389c27d6bSSanthosh Kumar Ellendula } 114489c27d6bSSanthosh Kumar Ellendula breakpoints.append(args_dict) 114589c27d6bSSanthosh Kumar Ellendula args_dict = {"breakpoints": breakpoints} 114689c27d6bSSanthosh Kumar Ellendula command_dict = { 114789c27d6bSSanthosh Kumar Ellendula "command": "setInstructionBreakpoints", 114889c27d6bSSanthosh Kumar Ellendula "type": "request", 114989c27d6bSSanthosh Kumar Ellendula "arguments": args_dict, 115089c27d6bSSanthosh Kumar Ellendula } 115189c27d6bSSanthosh Kumar Ellendula return self.send_recv(command_dict) 115201263c6cSJonas Devlieghere 115301263c6cSJonas Devlieghereclass DebugAdaptorServer(DebugCommunication): 115401263c6cSJonas Devlieghere def __init__( 115510664813SWalter Erquinigo self, 115610664813SWalter Erquinigo executable=None, 115710664813SWalter Erquinigo port=None, 115810664813SWalter Erquinigo init_commands=[], 115910664813SWalter Erquinigo log_file=None, 116010664813SWalter Erquinigo env=None, 116101263c6cSJonas Devlieghere ): 116201263c6cSJonas Devlieghere self.process = None 116301263c6cSJonas Devlieghere if executable is not None: 116401263c6cSJonas Devlieghere adaptor_env = os.environ.copy() 116501263c6cSJonas Devlieghere if env is not None: 116601263c6cSJonas Devlieghere adaptor_env.update(env) 116701263c6cSJonas Devlieghere 116801263c6cSJonas Devlieghere if log_file: 116901263c6cSJonas Devlieghere adaptor_env["LLDBDAP_LOG"] = log_file 117001263c6cSJonas Devlieghere self.process = subprocess.Popen( 117101263c6cSJonas Devlieghere [executable], 117201263c6cSJonas Devlieghere stdin=subprocess.PIPE, 117301263c6cSJonas Devlieghere stdout=subprocess.PIPE, 117401263c6cSJonas Devlieghere stderr=subprocess.PIPE, 117501263c6cSJonas Devlieghere env=adaptor_env, 117601263c6cSJonas Devlieghere ) 117701263c6cSJonas Devlieghere DebugCommunication.__init__( 117801263c6cSJonas Devlieghere self, self.process.stdout, self.process.stdin, init_commands, log_file 117901263c6cSJonas Devlieghere ) 118001263c6cSJonas Devlieghere elif port is not None: 118101263c6cSJonas Devlieghere s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 118201263c6cSJonas Devlieghere s.connect(("127.0.0.1", port)) 118301263c6cSJonas Devlieghere DebugCommunication.__init__( 118401263c6cSJonas Devlieghere self, s.makefile("r"), s.makefile("w"), init_commands 118501263c6cSJonas Devlieghere ) 118601263c6cSJonas Devlieghere 118701263c6cSJonas Devlieghere def get_pid(self): 118801263c6cSJonas Devlieghere if self.process: 118901263c6cSJonas Devlieghere return self.process.pid 119001263c6cSJonas Devlieghere return -1 119101263c6cSJonas Devlieghere 119201263c6cSJonas Devlieghere def terminate(self): 119301263c6cSJonas Devlieghere super(DebugAdaptorServer, self).terminate() 119401263c6cSJonas Devlieghere if self.process is not None: 119501263c6cSJonas Devlieghere self.process.terminate() 119601263c6cSJonas Devlieghere self.process.wait() 119701263c6cSJonas Devlieghere self.process = None 119801263c6cSJonas Devlieghere 119901263c6cSJonas Devlieghere 120001263c6cSJonas Devliegheredef attach_options_specified(options): 120101263c6cSJonas Devlieghere if options.pid is not None: 120201263c6cSJonas Devlieghere return True 120301263c6cSJonas Devlieghere if options.waitFor: 120401263c6cSJonas Devlieghere return True 120501263c6cSJonas Devlieghere if options.attach: 120601263c6cSJonas Devlieghere return True 120701263c6cSJonas Devlieghere if options.attachCmds: 120801263c6cSJonas Devlieghere return True 120901263c6cSJonas Devlieghere return False 121001263c6cSJonas Devlieghere 121101263c6cSJonas Devlieghere 121201263c6cSJonas Devliegheredef run_vscode(dbg, args, options): 121301263c6cSJonas Devlieghere dbg.request_initialize(options.sourceInitFile) 121401263c6cSJonas Devlieghere if attach_options_specified(options): 121501263c6cSJonas Devlieghere response = dbg.request_attach( 121601263c6cSJonas Devlieghere program=options.program, 121701263c6cSJonas Devlieghere pid=options.pid, 121801263c6cSJonas Devlieghere waitFor=options.waitFor, 121901263c6cSJonas Devlieghere attachCommands=options.attachCmds, 122001263c6cSJonas Devlieghere initCommands=options.initCmds, 122101263c6cSJonas Devlieghere preRunCommands=options.preRunCmds, 122201263c6cSJonas Devlieghere stopCommands=options.stopCmds, 122301263c6cSJonas Devlieghere exitCommands=options.exitCmds, 122401263c6cSJonas Devlieghere terminateCommands=options.terminateCmds, 122501263c6cSJonas Devlieghere ) 122601263c6cSJonas Devlieghere else: 122701263c6cSJonas Devlieghere response = dbg.request_launch( 122801263c6cSJonas Devlieghere options.program, 122901263c6cSJonas Devlieghere args=args, 123001263c6cSJonas Devlieghere env=options.envs, 123101263c6cSJonas Devlieghere cwd=options.workingDir, 123201263c6cSJonas Devlieghere debuggerRoot=options.debuggerRoot, 123301263c6cSJonas Devlieghere sourcePath=options.sourcePath, 123401263c6cSJonas Devlieghere initCommands=options.initCmds, 123501263c6cSJonas Devlieghere preRunCommands=options.preRunCmds, 123601263c6cSJonas Devlieghere stopCommands=options.stopCmds, 123701263c6cSJonas Devlieghere exitCommands=options.exitCmds, 123801263c6cSJonas Devlieghere terminateCommands=options.terminateCmds, 123901263c6cSJonas Devlieghere ) 124001263c6cSJonas Devlieghere 124101263c6cSJonas Devlieghere if response["success"]: 124201263c6cSJonas Devlieghere if options.sourceBreakpoints: 124301263c6cSJonas Devlieghere source_to_lines = {} 124401263c6cSJonas Devlieghere for file_line in options.sourceBreakpoints: 124501263c6cSJonas Devlieghere (path, line) = file_line.split(":") 124601263c6cSJonas Devlieghere if len(path) == 0 or len(line) == 0: 124701263c6cSJonas Devlieghere print('error: invalid source with line "%s"' % (file_line)) 124801263c6cSJonas Devlieghere 124901263c6cSJonas Devlieghere else: 125001263c6cSJonas Devlieghere if path in source_to_lines: 125101263c6cSJonas Devlieghere source_to_lines[path].append(int(line)) 125201263c6cSJonas Devlieghere else: 125301263c6cSJonas Devlieghere source_to_lines[path] = [int(line)] 125401263c6cSJonas Devlieghere for source in source_to_lines: 125501263c6cSJonas Devlieghere dbg.request_setBreakpoints(source, source_to_lines[source]) 125601263c6cSJonas Devlieghere if options.funcBreakpoints: 125701263c6cSJonas Devlieghere dbg.request_setFunctionBreakpoints(options.funcBreakpoints) 125801263c6cSJonas Devlieghere dbg.request_configurationDone() 125901263c6cSJonas Devlieghere dbg.wait_for_stopped() 126001263c6cSJonas Devlieghere else: 126101263c6cSJonas Devlieghere if "message" in response: 126201263c6cSJonas Devlieghere print(response["message"]) 126301263c6cSJonas Devlieghere dbg.request_disconnect(terminateDebuggee=True) 126401263c6cSJonas Devlieghere 126501263c6cSJonas Devlieghere 126601263c6cSJonas Devliegheredef main(): 126701263c6cSJonas Devlieghere parser = optparse.OptionParser( 126801263c6cSJonas Devlieghere description=( 1269c5c11f34SJohn Harrison "A testing framework for the Visual Studio Code Debug Adaptor protocol" 127001263c6cSJonas Devlieghere ) 127101263c6cSJonas Devlieghere ) 127201263c6cSJonas Devlieghere 127301263c6cSJonas Devlieghere parser.add_option( 127401263c6cSJonas Devlieghere "--vscode", 127501263c6cSJonas Devlieghere type="string", 127601263c6cSJonas Devlieghere dest="vscode_path", 127701263c6cSJonas Devlieghere help=( 127801263c6cSJonas Devlieghere "The path to the command line program that implements the " 127901263c6cSJonas Devlieghere "Visual Studio Code Debug Adaptor protocol." 128001263c6cSJonas Devlieghere ), 128101263c6cSJonas Devlieghere default=None, 128201263c6cSJonas Devlieghere ) 128301263c6cSJonas Devlieghere 128401263c6cSJonas Devlieghere parser.add_option( 128501263c6cSJonas Devlieghere "--program", 128601263c6cSJonas Devlieghere type="string", 128701263c6cSJonas Devlieghere dest="program", 128801263c6cSJonas Devlieghere help="The path to the program to debug.", 128901263c6cSJonas Devlieghere default=None, 129001263c6cSJonas Devlieghere ) 129101263c6cSJonas Devlieghere 129201263c6cSJonas Devlieghere parser.add_option( 129301263c6cSJonas Devlieghere "--workingDir", 129401263c6cSJonas Devlieghere type="string", 129501263c6cSJonas Devlieghere dest="workingDir", 129601263c6cSJonas Devlieghere default=None, 129701263c6cSJonas Devlieghere help="Set the working directory for the process we launch.", 129801263c6cSJonas Devlieghere ) 129901263c6cSJonas Devlieghere 130001263c6cSJonas Devlieghere parser.add_option( 130101263c6cSJonas Devlieghere "--sourcePath", 130201263c6cSJonas Devlieghere type="string", 130301263c6cSJonas Devlieghere dest="sourcePath", 130401263c6cSJonas Devlieghere default=None, 130501263c6cSJonas Devlieghere help=( 130601263c6cSJonas Devlieghere "Set the relative source root for any debug info that has " 130701263c6cSJonas Devlieghere "relative paths in it." 130801263c6cSJonas Devlieghere ), 130901263c6cSJonas Devlieghere ) 131001263c6cSJonas Devlieghere 131101263c6cSJonas Devlieghere parser.add_option( 131201263c6cSJonas Devlieghere "--debuggerRoot", 131301263c6cSJonas Devlieghere type="string", 131401263c6cSJonas Devlieghere dest="debuggerRoot", 131501263c6cSJonas Devlieghere default=None, 131601263c6cSJonas Devlieghere help=( 13172a32afddSDavid Spickett "Set the working directory for lldb-dap for any object files " 131801263c6cSJonas Devlieghere "with relative paths in the Mach-o debug map." 131901263c6cSJonas Devlieghere ), 132001263c6cSJonas Devlieghere ) 132101263c6cSJonas Devlieghere 132201263c6cSJonas Devlieghere parser.add_option( 132301263c6cSJonas Devlieghere "-r", 132401263c6cSJonas Devlieghere "--replay", 132501263c6cSJonas Devlieghere type="string", 132601263c6cSJonas Devlieghere dest="replay", 132701263c6cSJonas Devlieghere help=( 132801263c6cSJonas Devlieghere "Specify a file containing a packet log to replay with the " 132901263c6cSJonas Devlieghere "current Visual Studio Code Debug Adaptor executable." 133001263c6cSJonas Devlieghere ), 133101263c6cSJonas Devlieghere default=None, 133201263c6cSJonas Devlieghere ) 133301263c6cSJonas Devlieghere 133401263c6cSJonas Devlieghere parser.add_option( 133501263c6cSJonas Devlieghere "-g", 133601263c6cSJonas Devlieghere "--debug", 133701263c6cSJonas Devlieghere action="store_true", 133801263c6cSJonas Devlieghere dest="debug", 133901263c6cSJonas Devlieghere default=False, 134001263c6cSJonas Devlieghere help="Pause waiting for a debugger to attach to the debug adaptor", 134101263c6cSJonas Devlieghere ) 134201263c6cSJonas Devlieghere 134301263c6cSJonas Devlieghere parser.add_option( 134401263c6cSJonas Devlieghere "--sourceInitFile", 134501263c6cSJonas Devlieghere action="store_true", 134601263c6cSJonas Devlieghere dest="sourceInitFile", 134701263c6cSJonas Devlieghere default=False, 13482a32afddSDavid Spickett help="Whether lldb-dap should source .lldbinit file or not", 134901263c6cSJonas Devlieghere ) 135001263c6cSJonas Devlieghere 135101263c6cSJonas Devlieghere parser.add_option( 135201263c6cSJonas Devlieghere "--port", 135301263c6cSJonas Devlieghere type="int", 135401263c6cSJonas Devlieghere dest="port", 135501263c6cSJonas Devlieghere help="Attach a socket to a port instead of using STDIN for VSCode", 135601263c6cSJonas Devlieghere default=None, 135701263c6cSJonas Devlieghere ) 135801263c6cSJonas Devlieghere 135901263c6cSJonas Devlieghere parser.add_option( 136001263c6cSJonas Devlieghere "--pid", 136101263c6cSJonas Devlieghere type="int", 136201263c6cSJonas Devlieghere dest="pid", 136301263c6cSJonas Devlieghere help="The process ID to attach to", 136401263c6cSJonas Devlieghere default=None, 136501263c6cSJonas Devlieghere ) 136601263c6cSJonas Devlieghere 136701263c6cSJonas Devlieghere parser.add_option( 136801263c6cSJonas Devlieghere "--attach", 136901263c6cSJonas Devlieghere action="store_true", 137001263c6cSJonas Devlieghere dest="attach", 137101263c6cSJonas Devlieghere default=False, 137201263c6cSJonas Devlieghere help=( 137301263c6cSJonas Devlieghere "Specify this option to attach to a process by name. The " 137401263c6cSJonas Devlieghere "process name is the basename of the executable specified with " 137501263c6cSJonas Devlieghere "the --program option." 137601263c6cSJonas Devlieghere ), 137701263c6cSJonas Devlieghere ) 137801263c6cSJonas Devlieghere 137901263c6cSJonas Devlieghere parser.add_option( 138001263c6cSJonas Devlieghere "-f", 138101263c6cSJonas Devlieghere "--function-bp", 138201263c6cSJonas Devlieghere type="string", 138301263c6cSJonas Devlieghere action="append", 138401263c6cSJonas Devlieghere dest="funcBreakpoints", 138501263c6cSJonas Devlieghere help=( 138601263c6cSJonas Devlieghere "Specify the name of a function to break at. " 138701263c6cSJonas Devlieghere "Can be specified more than once." 138801263c6cSJonas Devlieghere ), 138901263c6cSJonas Devlieghere default=[], 139001263c6cSJonas Devlieghere ) 139101263c6cSJonas Devlieghere 139201263c6cSJonas Devlieghere parser.add_option( 139301263c6cSJonas Devlieghere "-s", 139401263c6cSJonas Devlieghere "--source-bp", 139501263c6cSJonas Devlieghere type="string", 139601263c6cSJonas Devlieghere action="append", 139701263c6cSJonas Devlieghere dest="sourceBreakpoints", 139801263c6cSJonas Devlieghere default=[], 139901263c6cSJonas Devlieghere help=( 140001263c6cSJonas Devlieghere "Specify source breakpoints to set in the format of " 140101263c6cSJonas Devlieghere "<source>:<line>. " 140201263c6cSJonas Devlieghere "Can be specified more than once." 140301263c6cSJonas Devlieghere ), 140401263c6cSJonas Devlieghere ) 140501263c6cSJonas Devlieghere 140601263c6cSJonas Devlieghere parser.add_option( 140701263c6cSJonas Devlieghere "--attachCommand", 140801263c6cSJonas Devlieghere type="string", 140901263c6cSJonas Devlieghere action="append", 141001263c6cSJonas Devlieghere dest="attachCmds", 141101263c6cSJonas Devlieghere default=[], 141201263c6cSJonas Devlieghere help=( 141301263c6cSJonas Devlieghere "Specify a LLDB command that will attach to a process. " 141401263c6cSJonas Devlieghere "Can be specified more than once." 141501263c6cSJonas Devlieghere ), 141601263c6cSJonas Devlieghere ) 141701263c6cSJonas Devlieghere 141801263c6cSJonas Devlieghere parser.add_option( 141901263c6cSJonas Devlieghere "--initCommand", 142001263c6cSJonas Devlieghere type="string", 142101263c6cSJonas Devlieghere action="append", 142201263c6cSJonas Devlieghere dest="initCmds", 142301263c6cSJonas Devlieghere default=[], 142401263c6cSJonas Devlieghere help=( 142501263c6cSJonas Devlieghere "Specify a LLDB command that will be executed before the target " 142601263c6cSJonas Devlieghere "is created. Can be specified more than once." 142701263c6cSJonas Devlieghere ), 142801263c6cSJonas Devlieghere ) 142901263c6cSJonas Devlieghere 143001263c6cSJonas Devlieghere parser.add_option( 143101263c6cSJonas Devlieghere "--preRunCommand", 143201263c6cSJonas Devlieghere type="string", 143301263c6cSJonas Devlieghere action="append", 143401263c6cSJonas Devlieghere dest="preRunCmds", 143501263c6cSJonas Devlieghere default=[], 143601263c6cSJonas Devlieghere help=( 143701263c6cSJonas Devlieghere "Specify a LLDB command that will be executed after the target " 143801263c6cSJonas Devlieghere "has been created. Can be specified more than once." 143901263c6cSJonas Devlieghere ), 144001263c6cSJonas Devlieghere ) 144101263c6cSJonas Devlieghere 144201263c6cSJonas Devlieghere parser.add_option( 144301263c6cSJonas Devlieghere "--stopCommand", 144401263c6cSJonas Devlieghere type="string", 144501263c6cSJonas Devlieghere action="append", 144601263c6cSJonas Devlieghere dest="stopCmds", 144701263c6cSJonas Devlieghere default=[], 144801263c6cSJonas Devlieghere help=( 144901263c6cSJonas Devlieghere "Specify a LLDB command that will be executed each time the" 145001263c6cSJonas Devlieghere "process stops. Can be specified more than once." 145101263c6cSJonas Devlieghere ), 145201263c6cSJonas Devlieghere ) 145301263c6cSJonas Devlieghere 145401263c6cSJonas Devlieghere parser.add_option( 145501263c6cSJonas Devlieghere "--exitCommand", 145601263c6cSJonas Devlieghere type="string", 145701263c6cSJonas Devlieghere action="append", 145801263c6cSJonas Devlieghere dest="exitCmds", 145901263c6cSJonas Devlieghere default=[], 146001263c6cSJonas Devlieghere help=( 146101263c6cSJonas Devlieghere "Specify a LLDB command that will be executed when the process " 146201263c6cSJonas Devlieghere "exits. Can be specified more than once." 146301263c6cSJonas Devlieghere ), 146401263c6cSJonas Devlieghere ) 146501263c6cSJonas Devlieghere 146601263c6cSJonas Devlieghere parser.add_option( 146701263c6cSJonas Devlieghere "--terminateCommand", 146801263c6cSJonas Devlieghere type="string", 146901263c6cSJonas Devlieghere action="append", 147001263c6cSJonas Devlieghere dest="terminateCmds", 147101263c6cSJonas Devlieghere default=[], 147201263c6cSJonas Devlieghere help=( 147301263c6cSJonas Devlieghere "Specify a LLDB command that will be executed when the debugging " 147401263c6cSJonas Devlieghere "session is terminated. Can be specified more than once." 147501263c6cSJonas Devlieghere ), 147601263c6cSJonas Devlieghere ) 147701263c6cSJonas Devlieghere 147801263c6cSJonas Devlieghere parser.add_option( 147901263c6cSJonas Devlieghere "--env", 148001263c6cSJonas Devlieghere type="string", 148101263c6cSJonas Devlieghere action="append", 148201263c6cSJonas Devlieghere dest="envs", 148301263c6cSJonas Devlieghere default=[], 148401263c6cSJonas Devlieghere help=("Specify environment variables to pass to the launched " "process."), 148501263c6cSJonas Devlieghere ) 148601263c6cSJonas Devlieghere 148701263c6cSJonas Devlieghere parser.add_option( 148801263c6cSJonas Devlieghere "--waitFor", 148901263c6cSJonas Devlieghere action="store_true", 149001263c6cSJonas Devlieghere dest="waitFor", 149101263c6cSJonas Devlieghere default=False, 149201263c6cSJonas Devlieghere help=( 149301263c6cSJonas Devlieghere "Wait for the next process to be launched whose name matches " 149401263c6cSJonas Devlieghere "the basename of the program specified with the --program " 149501263c6cSJonas Devlieghere "option" 149601263c6cSJonas Devlieghere ), 149701263c6cSJonas Devlieghere ) 149801263c6cSJonas Devlieghere 149901263c6cSJonas Devlieghere (options, args) = parser.parse_args(sys.argv[1:]) 150001263c6cSJonas Devlieghere 150101263c6cSJonas Devlieghere if options.vscode_path is None and options.port is None: 150201263c6cSJonas Devlieghere print( 150301263c6cSJonas Devlieghere "error: must either specify a path to a Visual Studio Code " 150401263c6cSJonas Devlieghere "Debug Adaptor vscode executable path using the --vscode " 15052a32afddSDavid Spickett "option, or a port to attach to for an existing lldb-dap " 150601263c6cSJonas Devlieghere "using the --port option" 150701263c6cSJonas Devlieghere ) 150801263c6cSJonas Devlieghere return 150901263c6cSJonas Devlieghere dbg = DebugAdaptorServer(executable=options.vscode_path, port=options.port) 151001263c6cSJonas Devlieghere if options.debug: 151101263c6cSJonas Devlieghere raw_input('Waiting for debugger to attach pid "%i"' % (dbg.get_pid())) 151201263c6cSJonas Devlieghere if options.replay: 151301263c6cSJonas Devlieghere dbg.replay_packets(options.replay) 151401263c6cSJonas Devlieghere else: 151501263c6cSJonas Devlieghere run_vscode(dbg, args, options) 151601263c6cSJonas Devlieghere dbg.terminate() 151701263c6cSJonas Devlieghere 151801263c6cSJonas Devlieghere 151901263c6cSJonas Devlieghereif __name__ == "__main__": 152001263c6cSJonas Devlieghere main() 1521