| 
									
										
										
										
											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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # pylint: disable=too-many-arguments, too-many-statements | 
					
						
							|  |  |  | # pylint: disable=too-many-locals, too-many-branches | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2019-05-10 15:45:52 +03:00
										 |  |  | from os.path import isfile, join | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | import click | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from platformio import exception, util | 
					
						
							|  |  |  | from platformio.commands.debug import helpers | 
					
						
							|  |  |  | from platformio.managers.core import inject_contrib_pysite | 
					
						
							| 
									
										
										
										
											2019-05-10 15:45:52 +03:00
										 |  |  | from platformio.project.config import ProjectConfig | 
					
						
							| 
									
										
										
										
											2019-05-27 22:25:22 +03:00
										 |  |  | from platformio.project.helpers import is_platformio_project | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 23:42:15 +03:00
										 |  |  | @click.command("debug", | 
					
						
							|  |  |  |                context_settings=dict(ignore_unknown_options=True), | 
					
						
							|  |  |  |                short_help="PIO Unified Debugger") | 
					
						
							|  |  |  | @click.option("-d", | 
					
						
							|  |  |  |               "--project-dir", | 
					
						
							|  |  |  |               default=os.getcwd, | 
					
						
							|  |  |  |               type=click.Path(exists=True, | 
					
						
							|  |  |  |                               file_okay=False, | 
					
						
							|  |  |  |                               dir_okay=True, | 
					
						
							|  |  |  |                               writable=True, | 
					
						
							|  |  |  |                               resolve_path=True)) | 
					
						
							|  |  |  | @click.option("-c", | 
					
						
							|  |  |  |               "--project-conf", | 
					
						
							|  |  |  |               type=click.Path(exists=True, | 
					
						
							|  |  |  |                               file_okay=True, | 
					
						
							|  |  |  |                               dir_okay=False, | 
					
						
							|  |  |  |                               readable=True, | 
					
						
							|  |  |  |                               resolve_path=True)) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | @click.option("--environment", "-e", metavar="<environment>") | 
					
						
							|  |  |  | @click.option("--verbose", "-v", is_flag=True) | 
					
						
							|  |  |  | @click.option("--interface", type=click.Choice(["gdb"])) | 
					
						
							|  |  |  | @click.argument("__unprocessed", nargs=-1, type=click.UNPROCESSED) | 
					
						
							|  |  |  | @click.pass_context | 
					
						
							| 
									
										
										
										
											2019-05-10 13:12:41 +03:00
										 |  |  | def cli(ctx, project_dir, project_conf, environment, verbose, interface, | 
					
						
							|  |  |  |         __unprocessed): | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |     try: | 
					
						
							|  |  |  |         util.ensure_udev_rules() | 
					
						
							|  |  |  |     except NameError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     except exception.InvalidUdevRules as e: | 
					
						
							|  |  |  |         for line in str(e).split("\n") + [""]: | 
					
						
							|  |  |  |             click.echo( | 
					
						
							|  |  |  |                 ('~"%s\\n"' if helpers.is_mi_mode(__unprocessed) else "%s") % | 
					
						
							|  |  |  |                 line) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-27 22:25:22 +03:00
										 |  |  |     if not is_platformio_project(project_dir) and os.getenv("CWD"): | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |         project_dir = os.getenv("CWD") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with util.cd(project_dir): | 
					
						
							| 
									
										
										
										
											2019-05-10 15:45:52 +03:00
										 |  |  |         config = ProjectConfig.get_instance( | 
					
						
							|  |  |  |             project_conf or join(project_dir, "platformio.ini")) | 
					
						
							|  |  |  |         config.validate(envs=[environment] if environment else None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         env_name = environment or helpers.get_default_debug_env(config) | 
					
						
							|  |  |  |         env_options = config.items(env=env_name, as_dict=True) | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |         if not set(env_options.keys()) >= set(["platform", "board"]): | 
					
						
							|  |  |  |             raise exception.ProjectEnvsNotAvailable() | 
					
						
							|  |  |  |         debug_options = helpers.validate_debug_options(ctx, env_options) | 
					
						
							|  |  |  |         assert debug_options | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not interface: | 
					
						
							|  |  |  |         return helpers.predebug_project(ctx, project_dir, env_name, False, | 
					
						
							|  |  |  |                                         verbose) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     configuration = helpers.load_configuration(ctx, project_dir, env_name) | 
					
						
							|  |  |  |     if not configuration: | 
					
						
							|  |  |  |         raise exception.DebugInvalidOptions( | 
					
						
							|  |  |  |             "Could not load debug configuration") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if "--version" in __unprocessed: | 
					
						
							|  |  |  |         result = util.exec_command([configuration['gdb_path'], "--version"]) | 
					
						
							|  |  |  |         if result['returncode'] == 0: | 
					
						
							|  |  |  |             return click.echo(result['out']) | 
					
						
							|  |  |  |         raise exception.PlatformioException("\n".join( | 
					
						
							|  |  |  |             [result['out'], result['err']])) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 14:45:48 +03:00
										 |  |  |     debug_options['load_cmds'] = helpers.configure_esp32_load_cmds( | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |         debug_options, configuration) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rebuild_prog = False | 
					
						
							| 
									
										
										
										
											2019-05-31 14:45:48 +03:00
										 |  |  |     preload = debug_options['load_cmds'] == ["preload"] | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  |     load_mode = debug_options['load_mode'] | 
					
						
							|  |  |  |     if load_mode == "always": | 
					
						
							|  |  |  |         rebuild_prog = ( | 
					
						
							|  |  |  |             preload | 
					
						
							|  |  |  |             or not helpers.has_debug_symbols(configuration['prog_path'])) | 
					
						
							|  |  |  |     elif load_mode == "modified": | 
					
						
							|  |  |  |         rebuild_prog = ( | 
					
						
							|  |  |  |             helpers.is_prog_obsolete(configuration['prog_path']) | 
					
						
							|  |  |  |             or not helpers.has_debug_symbols(configuration['prog_path'])) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         rebuild_prog = not isfile(configuration['prog_path']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if preload or (not rebuild_prog and load_mode != "always"): | 
					
						
							|  |  |  |         # don't load firmware through debug server | 
					
						
							| 
									
										
										
										
											2019-05-31 14:45:48 +03:00
										 |  |  |         debug_options['load_cmds'] = [] | 
					
						
							| 
									
										
										
										
											2019-04-19 19:56:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if rebuild_prog: | 
					
						
							|  |  |  |         if helpers.is_mi_mode(__unprocessed): | 
					
						
							|  |  |  |             output = helpers.GDBBytesIO() | 
					
						
							|  |  |  |             click.echo('~"Preparing firmware for debugging...\\n"') | 
					
						
							|  |  |  |             with helpers.capture_std_streams(output): | 
					
						
							|  |  |  |                 helpers.predebug_project(ctx, project_dir, env_name, preload, | 
					
						
							|  |  |  |                                          verbose) | 
					
						
							|  |  |  |             output.close() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             click.echo("Preparing firmware for debugging...") | 
					
						
							|  |  |  |             helpers.predebug_project(ctx, project_dir, env_name, preload, | 
					
						
							|  |  |  |                                      verbose) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # save SHA sum of newly created prog | 
					
						
							|  |  |  |         if load_mode == "modified": | 
					
						
							|  |  |  |             helpers.is_prog_obsolete(configuration['prog_path']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not isfile(configuration['prog_path']): | 
					
						
							|  |  |  |         raise exception.DebugInvalidOptions("Program/firmware is missed") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # run debugging client | 
					
						
							|  |  |  |     inject_contrib_pysite() | 
					
						
							|  |  |  |     from platformio.commands.debug.client import GDBClient, reactor | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     client = GDBClient(project_dir, __unprocessed, debug_options, env_options) | 
					
						
							|  |  |  |     client.spawn(configuration['gdb_path'], configuration['prog_path']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     reactor.run() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return True |