Пример #1
0
    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)
Пример #2
0
    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)
Пример #3
0
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
Пример #4
0
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
Пример #5
0
    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)