public override void ConnectGDBToStub(IDebugStartService service, ISimpleGDBSession session) { bool programNow; if (_Settings.ProgramFLASHUsingExternalTool) { programNow = false; } else { switch (_Settings.ProgramMode) { case ProgramMode.Disabled: programNow = false; break; case ProgramMode.Auto: programNow = !service.IsCurrentFirmwareAlreadyProgrammed(); break; default: programNow = true; break; } } foreach (var cmd in _Settings.StartupCommands) { bool isLoad = cmd.Trim() == "load"; if (isLoad) { if (service.Mode == EmbeddedDebugMode.Attach) { session.RunGDBCommand("mon halt"); } else { var sequence = ESP8266StartupSequence.BuildSequence(service, (ESP8266OpenOCDSettings)_Settings, (l, i) => session.SendInformationalOutput(l), programNow, _Context.Method?.Directory); using (var ctx = session.CreateScopedProgressReporter("Programming FLASH", new string[] { "Programming FLASH..." })) { if (RunSequence(ctx, service, session, sequence)) { service.OnFirmwareProgrammedSuccessfully(); } } } } else { session.RunGDBCommand(cmd); } } }
public void ConnectGDBToStub(IDebugStartService service, ISimpleGDBSession session) { bool programFLASH = false; if (service.Mode != EmbeddedDebugMode.Attach && service.Mode != EmbeddedDebugMode.ConnectionTest) { switch (_Settings.ProgramMode) { case ProgramMode.Auto: programFLASH = !service.IsCurrentFirmwareAlreadyProgrammed(); break; case ProgramMode.Enabled: programFLASH = true; break; } } DoConnect(service, session, _Settings, _COMPort, programFLASH); if (_Settings.ProgramMode == ProgramMode.Auto) { service.OnFirmwareProgrammedSuccessfully(); } }
public void ConnectGDBToStub(IDebugStartService service, ISimpleGDBSession session) { var info = service.TargetFileInfo; var result = session.RunGDBCommand($"-target-select remote :{LocalGDBEndpoint}"); if (result.MainStatus != "^connected") { throw new Exception("Failed to connect to gdb stub"); } result = session.RunGDBCommand("mon reset"); if (!result.IsDone) { throw new Exception("Failed to reset target"); } if (_Settings.FLASHDriver == TiXDSFLASHDriver.CC3220) { var sections = info.GetLoadableSections() .Where(section => section.LoadAddress.HasValue && section.LoadAddress.Value >= FLASHBase && section.LoadAddress.Value < (FLASHBase + MaximumFLASHSize)) .ToArray(); if (sections.Length == 0) { if (service.Mode != EmbeddedDebugMode.ConnectionTest) { session.SendInformationalOutput("No FLASH sections found in " + info.Path); result = session.RunGDBCommand("load"); if (!result.IsDone) { throw new Exception("Failed to reset target"); } } } else { bool skipLoad = false; switch (_Settings.ProgramMode) { case ProgramMode.Disabled: skipLoad = true; break; case ProgramMode.Auto: if (service.IsCurrentFirmwareAlreadyProgrammed()) { skipLoad = true; } break; } if (service.Mode == EmbeddedDebugMode.Attach || service.Mode == EmbeddedDebugMode.ConnectionTest) { skipLoad = true; } if (!skipLoad) { var resources = _Settings.FLASHResources ?? new FLASHResource[0]; using (var progr = session.CreateScopedProgressReporter("Programming FLASH...", new[] { "Erasing FLASH", "Programing FLASH" })) { var stub = new LoadedProgrammingStub(service.GetPathWithoutSpaces(Path.Combine(_BaseDir, "CC3220SF.bin")), session, _Settings); uint totalSize = 0; int totalItems = sections.Length + resources.Length; int itemsDone = 0; foreach (var sec in sections) { stub.EraseMemory((uint)sec.LoadAddress.Value, (uint)sec.Size); totalSize += (uint)sec.Size; progr.ReportTaskProgress(itemsDone, totalItems, $"Erasing {sec.Name}..."); } foreach (var r in resources) { r.ExpandedPath = service.ExpandProjectVariables(r.Path, true, true); r.Data = File.ReadAllBytes(r.ExpandedPath); stub.EraseMemory(FLASHBase + (uint)r.ParsedOffset, (uint)r.Data.Length); totalSize += (uint)r.Data.Length; progr.ReportTaskProgress(itemsDone, totalItems, $"Erasing area for {Path.GetFileName(r.ExpandedPath)}..."); } progr.ReportTaskCompletion(true); var path = service.GetPathWithoutSpaces(info.Path); uint doneTotal = 0; foreach (var sec in sections) { for (uint done = 0; done < (uint)sec.Size; done++) { uint todo = Math.Min(stub.ProgramBufferSize, (uint)sec.Size - done); progr.ReportTaskProgress(doneTotal, totalSize, $"Programming {sec.Name}..."); stub.ProgramMemory((uint)sec.LoadAddress.Value + done, path, (uint)sec.OffsetInFile + done, todo, sec.Name); doneTotal += todo; done += todo; } } foreach (var r in resources) { var imgName = Path.GetFileName(r.ExpandedPath); for (uint done = 0; done < (uint)r.Data.Length; done++) { uint todo = Math.Min(stub.ProgramBufferSize, (uint)r.Data.Length - done); progr.ReportTaskProgress(doneTotal, totalSize, $"Programming {imgName}..."); stub.ProgramMemory((uint)FLASHBase + (uint)r.ParsedOffset + done, path, done, todo, imgName); doneTotal += todo; done += todo; } } } } service.OnFirmwareProgrammedSuccessfully(); session.RunGDBCommand("set $pc=resetISR", false); } } }
public IGDBStubInstance StartGDBStub(IDebugStartService startService, DebugStartContext context) { var settings = context.Configuration as TiXDSDebugSettings ?? throw new Exception("Missing debug method settings"); var exe = new TiXDSSettingsEditor(settings).GDBAgentExecutable; if (string.IsNullOrEmpty(exe) || !File.Exists(exe)) { throw new Exception("Missing TI XDS stub: " + exe); } string configFile = null; switch (settings.FLASHDriver) { case TiXDSFLASHDriver.CC3220: configFile = "cc3220s.dat"; break; case TiXDSFLASHDriver.UniFLASH: configFile = Path.Combine(context.Method.Directory, "rm57x.dat"); break; } if (settings.FLASHDriver == TiXDSFLASHDriver.UniFLASH && startService.Mode != EmbeddedDebugMode.ConnectionTest && startService.Mode != EmbeddedDebugMode.Attach) { bool skipLoad = false; switch (settings.ProgramMode) { case ProgramMode.Disabled: skipLoad = true; break; case ProgramMode.Auto: if (startService.IsCurrentFirmwareAlreadyProgrammed()) { skipLoad = true; } break; } if (!skipLoad) { string uniFLASHDir = Path.Combine(context.Method.Directory, "UniFLASH"); var programTool = startService.LaunchCommandLineTool(new CommandLineToolLaunchInfo { Command = Path.Combine(uniFLASHDir, "dslite.bat"), Arguments = $@"--config={uniFLASHDir}\user_files\configs\rm57l8xx.ccxml {startService.TargetPath} --verbose", ShowInGDBStubWindow = true }); using (var logFile = new FileStream(Path.Combine(Path.GetDirectoryName(startService.TargetPath), "UniFLASH.log"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { programTool.LineReceived += (s, e) => { try { byte[] data = Encoding.UTF8.GetBytes(e.Line + "\r\n"); logFile.Write(data, 0, data.Length); logFile.Flush(); } catch { }; }; while (programTool.IsRunning) { Thread.Sleep(100); } if (programTool.ExitCode != 0) { throw new Exception($"UniFLASH exited with code {programTool.ExitCode}. Please check UniFLASH.log."); } } startService.OnFirmwareProgrammedSuccessfully(); } } if (!string.IsNullOrEmpty(settings.CustomConfigFile)) { configFile = settings.CustomConfigFile; } var tool = startService.LaunchCommandLineTool(new CommandLineToolLaunchInfo { Command = exe, WorkingDirectory = Path.GetDirectoryName(exe), Arguments = configFile }); return(new StubInstance(context.Method.Directory, settings, tool)); }
public virtual void ConnectGDBToStub(IDebugStartService service, ISimpleGDBSession session) { foreach (var cmd in _Settings.StartupCommands) { if (service.Mode == EmbeddedDebugMode.Attach) { if (SkipCommandOnAttach(cmd)) { continue; } } bool isLoad = cmd.Trim() == "load"; if (isLoad) { switch (_Settings.ProgramMode) { case ProgramMode.Disabled: continue; case ProgramMode.Auto: if (service.IsCurrentFirmwareAlreadyProgrammed()) { continue; } break; } } if (isLoad) { if (isLoad && RunLoadCommand(service, session, cmd)) { service.OnFirmwareProgrammedSuccessfully(); } } else { session.RunGDBCommand(cmd); } } if (service.Mode != EmbeddedDebugMode.Attach && RISCVOpenOCDSettingsEditor.IsE300CPU(service.MCU)) { bool autoReset = _Settings.ResetMode == RISCVResetMode.nSRST; if (autoReset) { //Issuing the reset signal will only trigger the 'software reset' interrupt that causes a halt by default. //Resetting it and then setting $pc to _start does the trick, but results in strange chip resets later. //Resetting the target via nSRST and reconnecting afterwards seems to do the trick session.RunGDBCommand("mon hifive_reset"); //Manually manipulating nSRST with a gdb session active wreaks havoc in the internal gdb/gdbserver state machine, //so we simply reconnect gdb to OpenOCD. session.RunGDBCommand("-target-disconnect"); } else { service.GUIService.Report("Please reset the board by pressing the 'reset' button and wait 1-2 seconds for the reset to complete. Then press 'OK'.", System.Windows.Forms.MessageBoxIcon.Information); session.RunGDBCommand("mon halt"); session.RunGDBCommand("-target-disconnect"); } session.RunGDBCommand("-target-select remote :$$SYS:GDB_PORT$$"); var expr = session.EvaluateExpression("(void *)$pc == _start"); if (expr?.TrimStart('0', 'x') != "1") { session.SendInformationalOutput("Warning: unexpected value of $pc after a reset"); session.RunGDBCommand("set $pc = _start"); } //After resetting the CPU seems to be stuck in some state where resuming it will effectively keep it stalled, but //resuming, halting and then finally resuming again does the job. The line below does the first resume-halt pair. try { session.ResumeAndWaitForStop(200); } catch { //VisualGDB will throw a 'timed out' exception. } //If this step is skipped, subsequent break-in requests will fail using (var r = session.CreateScopedProgressReporter("Waiting for the board to initialize", new[] { "Waiting for board..." })) { int delayInTenthsOfSecond = 10; for (int i = 0; i < delayInTenthsOfSecond; i++) { Thread.Sleep(100); r.ReportTaskProgress(i, delayInTenthsOfSecond); } } } }
public virtual void ConnectGDBToStub(IDebugStartService service, ISimpleGDBSession session) { string[] regularStartupCommands = new[] { "-gdb-set breakpoint pending on", "-gdb-set detach-on-fork on", "-gdb-set python print-stack none", "-gdb-set print object on", "-gdb-set print sevenbit-strings on", "-gdb-set host-charset UTF-8", "-gdb-set target-charset WINDOWS-1252", "-gdb-set target-wide-charset UTF-16", "-gdb-set pagination off", "-gdb-set auto-solib-add on", "inferior 1", "set remotetimeout 10", "set tcp connect-timeout 30", }; SimpleGDBCommandResult result; foreach (var cmd in regularStartupCommands) { result = session.RunGDBCommand(cmd); if (!result.IsDone) { throw new Exception("GDB command failed: " + cmd); } } session.EnableAsyncMode(GDBAsyncMode.AsyncWithTemporaryBreaks, true, true); session.ConnectToExtendedRemote(null, _GDBPort, true); result = session.RunGDBCommand("mon is_target_connected"); if (!result.IsDone) { throw new Exception("The target did not report connection state"); } if (result.StubOutput?.FirstOrDefault(l => l.Trim() == "Connection status=connected.") == null) { throw new Exception("The Renesas gdb stub is not connected to the target."); } result = ParseAndApplyIOAccessWidths(service, session, result); result = session.RunGDBCommand("monitor get_no_hw_bkpts_available"); if (result.IsDone && result.StubOutput != null) { foreach (var line in result.StubOutput) { if (int.TryParse(line.Trim(), out var tmp)) { session.RunGDBCommand($"set remote hardware-breakpoint-limit " + tmp); break; } } } result = session.RunGDBCommand("monitor get_target_max_address"); if (result.IsDone && result.StubOutput != null) { foreach (var line in result.StubOutput) { string trimmedLine = line.Trim(); if (trimmedLine.StartsWith("0x") && int.TryParse(trimmedLine.Substring(2), System.Globalization.NumberStyles.HexNumber, null, out var tmp)) { session.RunGDBCommand($"mem 0x0 0x{tmp + 1:x} rw 8 nocache"); break; } } } result = session.RunGDBCommand("monitor configuration_complete"); if (_LoadFLASH) { result = session.RunGDBCommand("monitor prg_download_start_on_connect"); result = session.RunGDBCommand("load"); if (!result.IsDone) { throw new Exception("Failed to program FLASH memory"); } service.OnFirmwareProgrammedSuccessfully(); result = session.RunGDBCommand("monitor prg_download_end"); } string[] finalCommands = new[] { "monitor reset", "monitor enable_stopped_notify_on_connect", "monitor enable_execute_on_connect", }; using (var awaiter = session.InterceptFirstStoppedEvent()) { foreach (var cmd in finalCommands) { result = session.RunGDBCommand(cmd); if (!result.IsDone) { throw new Exception("GDB command failed: " + cmd); } } while (!awaiter.WaitForStop(100)) { session.RunGDBCommand("monitor do_nothing"); } } }