| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | # Copyright (c) 2014-present PlatformIO <contact@platformio.org> | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # 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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | from os.path import isdir, isfile, join | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-04 17:47:26 +03:00
										 |  |  | from twisted.internet import error  # pylint: disable=import-error | 
					
						
							| 
									
										
										
										
											2019-05-10 13:00:53 +03:00
										 |  |  | from twisted.internet import reactor  # pylint: disable=import-error | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-27 20:23:03 +03:00
										 |  |  | from platformio import exception, fs, util | 
					
						
							| 
									
										
										
										
											2019-09-23 23:27:55 +03:00
										 |  |  | from platformio.debug.process import BaseProcess | 
					
						
							| 
									
										
										
										
											2019-05-27 22:25:22 +03:00
										 |  |  | from platformio.proc import where_is_program | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DebugServer(BaseProcess): | 
					
						
							|  |  |  |     def __init__(self, debug_options, env_options): | 
					
						
							|  |  |  |         self.debug_options = debug_options | 
					
						
							|  |  |  |         self.env_options = env_options | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._debug_port = None | 
					
						
							|  |  |  |         self._transport = None | 
					
						
							| 
									
										
										
										
											2019-07-04 17:47:26 +03:00
										 |  |  |         self._process_ended = False | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def spawn(self, patterns):  # pylint: disable=too-many-branches | 
					
						
							|  |  |  |         systype = util.get_systype() | 
					
						
							|  |  |  |         server = self.debug_options.get("server") | 
					
						
							|  |  |  |         if not server: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         server = self.apply_patterns(server, patterns) | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         server_executable = server["executable"] | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |         if not server_executable: | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         if server["cwd"]: | 
					
						
							|  |  |  |             server_executable = join(server["cwd"], server_executable) | 
					
						
							|  |  |  |         if ( | 
					
						
							|  |  |  |             "windows" in systype | 
					
						
							|  |  |  |             and not server_executable.endswith(".exe") | 
					
						
							|  |  |  |             and isfile(server_executable + ".exe") | 
					
						
							|  |  |  |         ): | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |             server_executable = server_executable + ".exe" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not isfile(server_executable): | 
					
						
							| 
									
										
										
										
											2019-05-27 22:25:22 +03:00
										 |  |  |             server_executable = where_is_program(server_executable) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |         if not isfile(server_executable): | 
					
						
							|  |  |  |             raise exception.DebugInvalidOptions( | 
					
						
							|  |  |  |                 "\nCould not launch Debug Server '%s'. Please check that it " | 
					
						
							|  |  |  |                 "is installed and is included in a system PATH\n\n" | 
					
						
							|  |  |  |                 "See documentation or contact contact@platformio.org:\n" | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |                 "http://docs.platformio.org/page/plus/debugging.html\n" | 
					
						
							|  |  |  |                 % server_executable | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self._debug_port = ":3333" | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |         openocd_pipe_allowed = all( | 
					
						
							|  |  |  |             [not self.debug_options["port"], "openocd" in server_executable] | 
					
						
							| 
									
										
										
										
											2019-09-27 14:13:53 +03:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |         if openocd_pipe_allowed: | 
					
						
							|  |  |  |             args = [] | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             if server["cwd"]: | 
					
						
							|  |  |  |                 args.extend(["-s", server["cwd"]]) | 
					
						
							|  |  |  |             args.extend( | 
					
						
							|  |  |  |                 ["-c", "gdb_port pipe; tcl_port disabled; telnet_port disabled"] | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             args.extend(server["arguments"]) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |             str_args = " ".join( | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |                 [arg if arg.startswith("-") else '"%s"' % arg for arg in args] | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2019-07-15 14:20:14 +03:00
										 |  |  |             self._debug_port = '| "%s" %s' % (server_executable, str_args) | 
					
						
							| 
									
										
										
										
											2019-08-27 20:23:03 +03:00
										 |  |  |             self._debug_port = fs.to_unix_path(self._debug_port) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |         else: | 
					
						
							|  |  |  |             env = os.environ.copy() | 
					
						
							|  |  |  |             # prepend server "lib" folder to LD path | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             if ( | 
					
						
							|  |  |  |                 "windows" not in systype | 
					
						
							|  |  |  |                 and server["cwd"] | 
					
						
							|  |  |  |                 and isdir(join(server["cwd"], "lib")) | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 ld_key = ( | 
					
						
							|  |  |  |                     "DYLD_LIBRARY_PATH" if "darwin" in systype else "LD_LIBRARY_PATH" | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 env[ld_key] = join(server["cwd"], "lib") | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |                 if os.environ.get(ld_key): | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |                     env[ld_key] = "%s:%s" % (env[ld_key], os.environ.get(ld_key)) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |             # prepend BIN to PATH | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |             if server["cwd"] and isdir(join(server["cwd"], "bin")): | 
					
						
							|  |  |  |                 env["PATH"] = "%s%s%s" % ( | 
					
						
							|  |  |  |                     join(server["cwd"], "bin"), | 
					
						
							|  |  |  |                     os.pathsep, | 
					
						
							|  |  |  |                     os.environ.get("PATH", os.environ.get("Path", "")), | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |             self._transport = reactor.spawnProcess( | 
					
						
							|  |  |  |                 self, | 
					
						
							| 
									
										
										
										
											2019-09-23 23:13:48 +03:00
										 |  |  |                 server_executable, | 
					
						
							|  |  |  |                 [server_executable] + server["arguments"], | 
					
						
							|  |  |  |                 path=server["cwd"], | 
					
						
							|  |  |  |                 env=env, | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |             if "mspdebug" in server_executable.lower(): | 
					
						
							|  |  |  |                 self._debug_port = ":2000" | 
					
						
							|  |  |  |             elif "jlink" in server_executable.lower(): | 
					
						
							|  |  |  |                 self._debug_port = ":2331" | 
					
						
							| 
									
										
										
										
											2019-06-27 15:13:16 +03:00
										 |  |  |             elif "qemu" in server_executable.lower(): | 
					
						
							|  |  |  |                 self._debug_port = ":1234" | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return self._transport | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_debug_port(self): | 
					
						
							|  |  |  |         return self._debug_port | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-04 17:47:26 +03:00
										 |  |  |     def processEnded(self, reason): | 
					
						
							|  |  |  |         self._process_ended = True | 
					
						
							|  |  |  |         super(DebugServer, self).processEnded(reason) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |     def terminate(self): | 
					
						
							| 
									
										
										
										
											2019-07-04 17:47:26 +03:00
										 |  |  |         if self._process_ended or not self._transport: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |             self._transport.signalProcess("KILL") | 
					
						
							| 
									
										
										
										
											2019-07-04 17:47:26 +03:00
										 |  |  |         except (OSError, error.ProcessExitedAlready): | 
					
						
							|  |  |  |             pass |