def get_debug_tool_name(self, custom=None): debug_tools = self._manifest.get("debug", {}).get("tools") tool_name = custom if tool_name == "custom": return tool_name if not debug_tools: telemetry.send_event("Debug", "Request", self.id) raise DebugSupportError(self._manifest["name"]) if tool_name: if tool_name in debug_tools: return tool_name raise DebugInvalidOptionsError( "Unknown debug tool `%s`. Please use one of `%s` or `custom`" % (tool_name, ", ".join(sorted(list(debug_tools))))) # automatically select best tool data = {"default": [], "onboard": [], "external": []} for key, value in debug_tools.items(): if value.get("default"): data["default"].append(key) elif value.get("onboard"): data["onboard"].append(key) data["external"].append(key) for key, value in data.items(): if not value: continue return sorted(value)[0] assert any(item for item in data)
def spawn(self, gdb_path, prog_path): session_hash = gdb_path + prog_path self._session_id = sha1(hashlib_encode_data(session_hash)).hexdigest() self._kill_previous_session() patterns = { "PROJECT_DIR": self.project_dir, "PROG_PATH": prog_path, "PROG_DIR": dirname(prog_path), "PROG_NAME": basename(splitext(prog_path)[0]), "DEBUG_PORT": self.debug_options["port"], "UPLOAD_PROTOCOL": self.debug_options["upload_protocol"], "INIT_BREAK": self.debug_options["init_break"] or "", "LOAD_CMDS": "\n".join(self.debug_options["load_cmds"] or []), } yield self._debug_server.spawn(patterns) if not patterns["DEBUG_PORT"]: patterns["DEBUG_PORT"] = self._debug_server.get_debug_port() self.generate_pioinit(self._gdbsrc_dir, patterns) # start GDB client args = [ "piogdb", "-q", "--directory", self._gdbsrc_dir, "--directory", self.project_dir, "-l", "10", ] args.extend(self.args) if not gdb_path: raise DebugInvalidOptionsError("GDB client is not configured") gdb_data_dir = self._get_data_dir(gdb_path) if gdb_data_dir: args.extend(["--data-directory", gdb_data_dir]) args.append(patterns["PROG_PATH"]) transport = reactor.spawnProcess(self, gdb_path, args, path=self.project_dir, env=os.environ) defer.returnValue(transport)
def reveal_debug_port(env_debug_port, tool_name, tool_settings): def _get_pattern(): if not env_debug_port: return None if set(["*", "?", "[", "]"]) & set(env_debug_port): return env_debug_port return None def _is_match_pattern(port): pattern = _get_pattern() if not pattern: return True return fnmatch(port, pattern) def _look_for_serial_port(hwids): for item in util.get_serialports(filter_hwid=True): if not _is_match_pattern(item["port"]): continue port = item["port"] if tool_name.startswith("blackmagic"): if ( "windows" in util.get_systype() and port.startswith("COM") and len(port) > 4 ): port = "\\\\.\\%s" % port if "GDB" in item["description"]: return port for hwid in hwids: hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "") if hwid_str in item["hwid"]: return port return None if env_debug_port and not _get_pattern(): return env_debug_port if not tool_settings.get("require_debug_port"): return None debug_port = _look_for_serial_port(tool_settings.get("hwids", [])) if not debug_port: raise DebugInvalidOptionsError("Please specify `debug_port` for environment") return debug_port
def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unprocessed): app.set_session_var("custom_project_conf", project_conf) # use env variables from Eclipse or CLion for sysenv in ("CWD", "PWD", "PLATFORMIO_PROJECT_DIR"): if is_platformio_project(project_dir): break if os.getenv(sysenv): project_dir = os.getenv(sysenv) with fs.cd(project_dir): config = ProjectConfig.get_instance(project_conf) 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) if not set(env_options.keys()) >= set(["platform", "board"]): raise ProjectEnvsNotAvailableError() 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 = load_project_ide_data(project_dir, env_name) if not configuration: raise DebugInvalidOptionsError("Could not load debug configuration") if "--version" in __unprocessed: result = proc.exec_command([configuration["gdb_path"], "--version"]) if result["returncode"] == 0: return click.echo(result["out"]) raise exception.PlatformioException("\n".join( [result["out"], result["err"]])) try: fs.ensure_udev_rules() except exception.InvalidUdevRules as e: click.echo( helpers.escape_gdbmi_stream("~", str(e) + "\n") if helpers.is_gdbmi_mode() else str(e) + "\n", nl=False, ) debug_options["load_cmds"] = helpers.configure_esp32_load_cmds( debug_options, configuration) rebuild_prog = False preload = debug_options["load_cmds"] == ["preload"] 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 debug_options["load_cmds"] = [] if rebuild_prog: if helpers.is_gdbmi_mode(): click.echo( helpers.escape_gdbmi_stream( "~", "Preparing firmware for debugging...\n"), nl=False, ) stream = helpers.GDBMIConsoleStream() with util.capture_std_streams(stream): helpers.predebug_project(ctx, project_dir, env_name, preload, verbose) stream.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 DebugInvalidOptionsError("Program/firmware is missed") # run debugging client inject_contrib_pysite() # pylint: disable=import-outside-toplevel from platformio.commands.debug.process.client import GDBClient, reactor client = GDBClient(project_dir, __unprocessed, debug_options, env_options) client.spawn(configuration["gdb_path"], configuration["prog_path"]) signal.signal(signal.SIGINT, lambda *args, **kwargs: None) reactor.run() return True
def spawn(self, patterns): # pylint: disable=too-many-branches systype = util.get_systype() server = self.debug_options.get("server") if not server: defer.returnValue(None) server = self.apply_patterns(server, patterns) server_executable = server["executable"] if not server_executable: defer.returnValue(None) 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")): server_executable = server_executable + ".exe" if not isfile(server_executable): server_executable = where_is_program(server_executable) if not isfile(server_executable): raise DebugInvalidOptionsError( "\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 [email protected]:\n" "https://docs.platformio.org/page/plus/debugging.html\n" % server_executable) openocd_pipe_allowed = all( [not self.debug_options["port"], "openocd" in server_executable]) if openocd_pipe_allowed: args = [] if server["cwd"]: args.extend(["-s", server["cwd"]]) args.extend([ "-c", "gdb_port pipe; tcl_port disabled; telnet_port disabled" ]) args.extend(server["arguments"]) str_args = " ".join( [arg if arg.startswith("-") else '"%s"' % arg for arg in args]) self._debug_port = '| "%s" %s' % (server_executable, str_args) self._debug_port = fs.to_unix_path(self._debug_port) defer.returnValue(self._debug_port) env = os.environ.copy() # prepend server "lib" folder to LD path 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") if os.environ.get(ld_key): env[ld_key] = "%s:%s" % (env[ld_key], os.environ.get(ld_key)) # prepend BIN to PATH 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", "")), ) self._transport = reactor.spawnProcess( self, server_executable, [server_executable] + server["arguments"], path=server["cwd"], env=env, ) if "mspdebug" in server_executable.lower(): self._debug_port = ":2000" elif "jlink" in server_executable.lower(): self._debug_port = ":2331" elif "qemu" in server_executable.lower(): self._debug_port = ":1234" yield self._wait_until_ready() defer.returnValue(self._debug_port)