From 24988acbc40b37a4fe7f6fbdb2b0cc32e361e8c8 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:24:58 +0200 Subject: [PATCH 01/16] changes to verify process --- bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml | 4 ++-- .../com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml index c44aa77a0..e38e53e09 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml @@ -152,7 +152,7 @@ resolver="com.espressif.idf.debug.gdbjtag.openocd.SvdPathResolver"> - - + --> Date: Fri, 13 Sep 2024 12:09:00 +0200 Subject: [PATCH 02/16] Revert "changes to verify process" This reverts commit 560de098aa3ca616284a4c5cda2ac25030cb03f7. --- bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml | 4 ++-- .../com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml index e38e53e09..c44aa77a0 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml @@ -152,7 +152,7 @@ resolver="com.espressif.idf.debug.gdbjtag.openocd.SvdPathResolver"> - + Date: Fri, 13 Sep 2024 12:33:21 +0200 Subject: [PATCH 03/16] fix(port): updated code for port verification To Improved the code for the port checking and introduced retries and waiting time --- .../espressif/idf/core/util/PortChecker.java | 44 ++++++++++++++++--- .../idf/debug/gdbjtag/openocd/dsf/Launch.java | 9 ++-- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java index 053777788..593817713 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java @@ -4,6 +4,7 @@ *******************************************************************************/ package com.espressif.idf.core.util; +import java.io.IOException; import java.net.Socket; import com.espressif.idf.core.logging.Logger; @@ -24,14 +25,45 @@ private PortChecker() public static boolean isPortAvailable(int port) { - try (Socket ignored = new Socket("localhost", port)) //$NON-NLS-1$ - { - return false; - } - catch (Exception e) + int attempts = 0; + int retryCount = 3; + long retryDelayMillis = 200; + + while (attempts <= retryCount) { - return true; + try (Socket ignored = new Socket("localhost", port)) //$NON-NLS-1$ + { + // If the socket opens, the port is in use + return false; + } + catch (IOException e) + { + // Port is unavailable, retrying if there are attempts left + if (attempts == retryCount) + { + // After exhausting all retries, return false + Logger.log("Port " + port + " is not available after " + retryCount + " retries."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return false; // Failure, port is still not available + } + + attempts++; + + // Log retry attempt + Logger.log("Attempt " + attempts + " failed, retrying in " + retryDelayMillis + " ms..."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + try + { + Thread.sleep(retryDelayMillis); + } + catch (InterruptedException interruptedException) + { + Thread.currentThread().interrupt(); // Restore interrupt status + Logger.log("Port availability check interrupted."); //$NON-NLS-1$ + return false; // If interrupted, assume port unavailable and stop + } + } } + return true; //Fallback not reachable } /** diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java index 8749df392..5b96137f2 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java @@ -147,9 +147,12 @@ protected void provideDefaults(ILaunchConfigurationWorkingCopy config) throws Co fDefaultPreferences.getGdbClientExecutable()); } - int availableRemotePort = PortChecker.getAvailablePort(config.getAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, - DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT)); - config.setAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, availableRemotePort); + if (Configuration.getDoStartGdbServer(config)) + { + int availableRemotePort = PortChecker.getAvailablePort(config.getAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, + DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT)); + config.setAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, availableRemotePort); + } config.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, CustomIdfProcessFactory.ID); } From de001530e992ce8f7c591214f4957ca06c32a808 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:24:58 +0200 Subject: [PATCH 04/16] changes to verify process --- bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml | 4 ++-- .../com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml index c44aa77a0..e38e53e09 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml @@ -152,7 +152,7 @@ resolver="com.espressif.idf.debug.gdbjtag.openocd.SvdPathResolver"> - - + --> Date: Fri, 13 Sep 2024 12:09:00 +0200 Subject: [PATCH 05/16] Revert "changes to verify process" This reverts commit 560de098aa3ca616284a4c5cda2ac25030cb03f7. --- bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml | 4 ++-- .../com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml index e38e53e09..c44aa77a0 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/plugin.xml @@ -152,7 +152,7 @@ resolver="com.espressif.idf.debug.gdbjtag.openocd.SvdPathResolver"> - + Date: Mon, 16 Sep 2024 14:51:48 +0200 Subject: [PATCH 06/16] fix(debugger_tab): updated code to enable remote gdb only when server is not started --- .../idf/debug/gdbjtag/openocd/ui/TabDebugger.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/ui/TabDebugger.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/ui/TabDebugger.java index 97fafb379..f854fc656 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/ui/TabDebugger.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/ui/TabDebugger.java @@ -109,6 +109,7 @@ public class TabDebugger extends AbstractLaunchConfigurationTab private Text fTargetIpAddress; private Text fTargetPortNumber; + private Group gdbClientGroup; protected Button fUpdateThreadlistOnSuspend; @@ -470,6 +471,7 @@ public void widgetSelected(SelectionEvent e) public void widgetSelected(SelectionEvent e) { doStartGdbServerChanged(); + gdbClientGroup.setEnabled(!fDoStartGdbServer.getSelection()); if (fDoStartGdbServer.getSelection()) { fTargetIpAddress.setText(DefaultPreferences.REMOTE_IP_ADDRESS_LOCALHOST); @@ -572,16 +574,16 @@ public void modifyText(ModifyEvent e) private void createGdbClientControls(Composite parent) { - Group group = new Group(parent, SWT.NONE); + gdbClientGroup = new Group(parent, SWT.NONE); { GridLayout layout = new GridLayout(); - group.setLayout(layout); + gdbClientGroup.setLayout(layout); GridData gd = new GridData(GridData.FILL_HORIZONTAL); - group.setLayoutData(gd); - group.setText(Messages.getString("DebuggerTab.gdbSetupGroup_Text")); //$NON-NLS-1$ + gdbClientGroup.setLayoutData(gd); + gdbClientGroup.setText(Messages.getString("DebuggerTab.gdbSetupGroup_Text")); //$NON-NLS-1$ } - Composite comp = new Composite(group, SWT.NONE); + Composite comp = new Composite(gdbClientGroup, SWT.NONE); { GridLayout layout = new GridLayout(); layout.numColumns = 5; From e0fa1a50bba37064630e2d35cf1f8892306f6762 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:21:54 +0200 Subject: [PATCH 07/16] fix(openocd): fixed the port handler behavior --- .../espressif/idf/core/util/PortChecker.java | 46 ++++--------------- .../debug/gdbjtag/openocd/Configuration.java | 3 +- .../idf/debug/gdbjtag/openocd/dsf/Launch.java | 4 +- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java index 593817713..da45fd49a 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java @@ -5,6 +5,7 @@ package com.espressif.idf.core.util; import java.io.IOException; +import java.net.ServerSocket; import java.net.Socket; import com.espressif.idf.core.logging.Logger; @@ -25,45 +26,16 @@ private PortChecker() public static boolean isPortAvailable(int port) { - int attempts = 0; - int retryCount = 3; - long retryDelayMillis = 200; - - while (attempts <= retryCount) + try (ServerSocket serverSocket = new ServerSocket(port)) { - try (Socket ignored = new Socket("localhost", port)) //$NON-NLS-1$ - { - // If the socket opens, the port is in use - return false; - } - catch (IOException e) - { - // Port is unavailable, retrying if there are attempts left - if (attempts == retryCount) - { - // After exhausting all retries, return false - Logger.log("Port " + port + " is not available after " + retryCount + " retries."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - return false; // Failure, port is still not available - } - - attempts++; - - // Log retry attempt - Logger.log("Attempt " + attempts + " failed, retrying in " + retryDelayMillis + " ms..."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - - try - { - Thread.sleep(retryDelayMillis); - } - catch (InterruptedException interruptedException) - { - Thread.currentThread().interrupt(); // Restore interrupt status - Logger.log("Port availability check interrupted."); //$NON-NLS-1$ - return false; // If interrupted, assume port unavailable and stop - } - } + serverSocket.setReuseAddress(true); + return true; + } + catch (Exception e) + { + Logger.log("Port: " + port + " is not available"); //$NON-NLS-1$ //$NON-NLS-2$ + return false; } - return true; //Fallback not reachable } /** diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java index 9ecc95b11..9df696832 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java @@ -93,8 +93,7 @@ public static String[] getGdbServerCommandLineArray(ILaunchConfiguration configu lst.add(executable); int port = PortChecker - .getAvailablePort(configuration.getAttribute(ConfigurationAttributes.GDB_SERVER_GDB_PORT_NUMBER, - DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT)); + .getAvailablePort(DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT); lst.add("-c"); //$NON-NLS-1$ lst.add("gdb_port " + port); //$NON-NLS-1$ diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java index 5b96137f2..6ddcf79de 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java @@ -149,9 +149,7 @@ protected void provideDefaults(ILaunchConfigurationWorkingCopy config) throws Co if (Configuration.getDoStartGdbServer(config)) { - int availableRemotePort = PortChecker.getAvailablePort(config.getAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, - DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT)); - config.setAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, availableRemotePort); + config.setAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT); } config.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, CustomIdfProcessFactory.ID); From a926bd6f5887a87539fa1b64ac54b284bfb23da1 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Mon, 11 Nov 2024 12:49:41 +0100 Subject: [PATCH 08/16] fix(openocd): fixed the port handler for verification for other processes --- .../espressif/idf/core/util/PortChecker.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java index da45fd49a..3e8d22866 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java @@ -26,16 +26,15 @@ private PortChecker() public static boolean isPortAvailable(int port) { - try (ServerSocket serverSocket = new ServerSocket(port)) - { - serverSocket.setReuseAddress(true); - return true; - } - catch (Exception e) - { - Logger.log("Port: " + port + " is not available"); //$NON-NLS-1$ //$NON-NLS-2$ - return false; - } + try (Socket socket = new Socket("127.0.0.1", port)) { //$NON-NLS-1$ + // If connection is successful, port is in use + Logger.log("Port: " + port + " is not available (in use)"); //$NON-NLS-1$//$NON-NLS-2$ + return false; + } catch (IOException e) { + // If connection fails, port is likely available + Logger.log("Port: " + port + " is available"); //$NON-NLS-1$ //$NON-NLS-2$ + return true; + } } /** From d07c76f98b05ab51add91b57b7af9b43c72428ae Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:51:32 +0100 Subject: [PATCH 09/16] Revert "fix(openocd): fixed the port handler for verification for other processes" This reverts commit a926bd6f5887a87539fa1b64ac54b284bfb23da1. --- .../espressif/idf/core/util/PortChecker.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java index 3e8d22866..da45fd49a 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java @@ -26,15 +26,16 @@ private PortChecker() public static boolean isPortAvailable(int port) { - try (Socket socket = new Socket("127.0.0.1", port)) { //$NON-NLS-1$ - // If connection is successful, port is in use - Logger.log("Port: " + port + " is not available (in use)"); //$NON-NLS-1$//$NON-NLS-2$ - return false; - } catch (IOException e) { - // If connection fails, port is likely available - Logger.log("Port: " + port + " is available"); //$NON-NLS-1$ //$NON-NLS-2$ - return true; - } + try (ServerSocket serverSocket = new ServerSocket(port)) + { + serverSocket.setReuseAddress(true); + return true; + } + catch (Exception e) + { + Logger.log("Port: " + port + " is not available"); //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } } /** From 2c91af013d5a67e2cf351c5ab15985b81a9d9c8b Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:05:50 +0100 Subject: [PATCH 10/16] fix(gdb): fixed the port in configuration storage for gdb --- .../src/com/espressif/idf/core/util/PortChecker.java | 3 ++- .../idf/debug/gdbjtag/openocd/Configuration.java | 8 +++++++- .../espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java | 2 -- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java index da45fd49a..33c9c6d10 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/PortChecker.java @@ -5,6 +5,7 @@ package com.espressif.idf.core.util; import java.io.IOException; +import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; @@ -26,7 +27,7 @@ private PortChecker() public static boolean isPortAvailable(int port) { - try (ServerSocket serverSocket = new ServerSocket(port)) + try (ServerSocket serverSocket = new ServerSocket(port, 50, InetAddress.getByName("127.0.0.1"))) //$NON-NLS-1$ { serverSocket.setReuseAddress(true); return true; diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java index 9df696832..4d2c13dd9 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/Configuration.java @@ -18,6 +18,7 @@ import java.util.List; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.debug.gdbjtag.core.IGDBJtagConstants; import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; @@ -25,6 +26,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Platform; import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.embedcdt.core.EclipseUtils; import org.eclipse.embedcdt.core.StringUtils; import org.eclipse.embedcdt.debug.gdbjtag.core.DebugUtils; @@ -94,7 +96,11 @@ public static String[] getGdbServerCommandLineArray(ILaunchConfiguration configu int port = PortChecker .getAvailablePort(DefaultPreferences.GDB_SERVER_GDB_PORT_NUMBER_DEFAULT); - + + ILaunchConfigurationWorkingCopy configurationWorkingCopy = configuration.getWorkingCopy(); + configurationWorkingCopy.setAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, port); + configurationWorkingCopy.doSave(); + lst.add("-c"); //$NON-NLS-1$ lst.add("gdb_port " + port); //$NON-NLS-1$ diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java index 6ddcf79de..738c444e7 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java @@ -173,8 +173,6 @@ public void initializeServerConsole(IProgressMonitor monitor) throws CoreExcepti // Add the GDB server process to the launch tree newProcess = addServerProcess(Configuration.getGdbServerCommandName(fConfig)); - newProcess.setAttribute(IProcess.ATTR_CMDLINE, Configuration.getGdbServerCommandLine(fConfig)); - monitor.worked(1); } } From 63705afc612046d53bb39602b429d71c820ba5f1 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:46:31 +0100 Subject: [PATCH 11/16] fix(monitor): fixed the issue during cleanup for the launch --- .../openocd/dsf/LaunchConfigurationDelegate.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java index 69642ffb9..b7712aa21 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java @@ -698,6 +698,19 @@ protected void handleCompleted() } // -------------------------------------------------------------------- } + + @Override + /** + * This method takes care of cleaning up any resources allocated by the launch, as early as + * the call to getLaunch(), whenever the launch is cancelled or does not complete properly. + * @since 5.0 */ + protected void cleanupLaunch(ILaunch launch) throws DebugException + { + if (launch instanceof GdbLaunch) + { + launch.terminate(); + } + } /** * Perform some local validations before starting the debug session. From abe20e5f638cf3a008d42e740c70c279e3b1470a Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:53:28 +0100 Subject: [PATCH 12/16] fix(gdb_openocd): added custom handling of terminate for debugging processes --- .../debug/gdbjtag/openocd/dsf/GdbBackend.java | 1013 ++++++++++++++++- .../idf/debug/gdbjtag/openocd/dsf/Launch.java | 42 +- .../dsf/LaunchConfigurationDelegate.java | 13 - .../dsf/process/IdfRuntimeProcess.java | 5 + 4 files changed, 1008 insertions(+), 65 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java index d21eff6d7..b16ba5072 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java @@ -14,15 +14,66 @@ package com.espressif.idf.debug.gdbjtag.openocd.dsf; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.parser.util.StringUtil; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.concurrent.Sequence.Step; +import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.launching.LaunchUtils; +import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; +import org.eclipse.cdt.dsf.gdb.service.SessionType; +import org.eclipse.cdt.dsf.gdb.service.command.GDBControl.InitializationShutdownStep; +import org.eclipse.cdt.dsf.gdb.service.command.GDBControl.InitializationShutdownStep.Direction; +import org.eclipse.cdt.dsf.mi.service.IMIBackend; +import org.eclipse.cdt.dsf.mi.service.IMIBackend2; +import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent; +import org.eclipse.cdt.dsf.mi.service.IMIBackend.State; +import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.service.AbstractDsfService; +import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.utils.spawner.Spawner; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.variables.VariablesPlugin; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.ILaunchManager; import org.eclipse.embedcdt.debug.gdbjtag.core.DebugUtils; -import org.eclipse.embedcdt.debug.gdbjtag.core.dsf.GnuMcuGdbBackend; +import org.eclipse.embedcdt.debug.gdbjtag.core.dsf.GnuMcuProcesses_7_2_1.ProcessStateChangedEvent; +import org.osgi.framework.BundleContext; import com.espressif.idf.debug.gdbjtag.openocd.Activator; import com.espressif.idf.debug.gdbjtag.openocd.Configuration; @@ -32,59 +83,136 @@ * to copy a newer version locally and use it. */ -public class GdbBackend extends GnuMcuGdbBackend { - - // ------------------------------------------------------------------------ +public class GdbBackend extends AbstractDsfService implements IGDBBackend, IMIBackend2 { private final ILaunchConfiguration fLaunchConfiguration; - // ------------------------------------------------------------------------ + /* + * Parameters for launching GDB. + */ + private IPath fProgramPath; + private IPath fGDBWorkingDirectory; + private String fGDBInitFile; + private List fSharedLibPaths; + private String fProgramArguments; - public GdbBackend(DsfSession session, ILaunchConfiguration lc) { + private Properties fEnvVariables; + private SessionType fSessionType; + private Boolean fAttach; + private State fBackendState = State.NOT_INITIALIZED; - super(session, lc); + /** + * Unique ID of this service instance. + */ + private final String fBackendId; + private static int fgInstanceCounter = 0; - if (Activator.getInstance().isDebugging()) { - System.out.println("openocd.GdbBackend() " + this); - } + /* + * Service state parameters. + */ + private MonitorJob fMonitorJob; + private Process fProcess; + private int fGDBExitValue; + private int fGDBLaunchTimeout = 30; + + /** + * A Job that will set a failed status in the proper request monitor, if the + * interrupt did not succeed after a certain time. + */ + private MonitorInterruptJob fInterruptFailedJob; + + public GdbBackend(DsfSession session, ILaunchConfiguration lc) { + super(session); + fBackendId = "gdb[" + Integer.toString(fgInstanceCounter++) + "]"; //$NON-NLS-1$//$NON-NLS-2$ fLaunchConfiguration = lc; - } - // ------------------------------------------------------------------------ + try { + // Don't call verifyCProject, because the JUnit tests are not + // setting a project + ICProject cproject = LaunchUtils.getCProject(lc); + fProgramPath = LaunchUtils.verifyProgramPath(lc, cproject); + } catch (CoreException e) { + fProgramPath = new Path(""); //$NON-NLS-1$ + } + } @Override - public void initialize(final RequestMonitor rm) { + public void initialize(final RequestMonitor requestMonitor) { if (Activator.getInstance().isDebugging()) { - System.out.println("openocd.GdbBackend.initialize() " + Thread.currentThread()); + System.out.println("GnuMcuGdbBackend.initialize()"); } - super.initialize(rm); + super.initialize(new ImmediateRequestMonitor(requestMonitor) { + @Override + protected void handleSuccess() { + doInitialize(requestMonitor); + } + }); } - @Override - public void destroy() { + private void doInitialize(final RequestMonitor requestMonitor) { - if (Activator.getInstance().isDebugging()) { - System.out.println("openocd.GdbBackend.destroy() " + Thread.currentThread()); - } - super.destroy(); + final Sequence.Step[] initializeSteps = new Sequence.Step[] { + new GDBProcessStep(InitializationShutdownStep.Direction.INITIALIZING), + new MonitorJobStep(InitializationShutdownStep.Direction.INITIALIZING), + new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING), }; + + Sequence startupSequence = new Sequence(getExecutor(), requestMonitor) { + @Override + public Step[] getSteps() { + return initializeSteps; + } + }; + getExecutor().execute(startupSequence); } @Override - public void shutdown(final RequestMonitor rm) { + public void shutdown(final RequestMonitor requestMonitor) { if (Activator.getInstance().isDebugging()) { - System.out.println("openocd.GdbBackend.shutdown() " + Thread.currentThread()); + System.out.println("GnuMcuGdbBackend.shutdown()"); } - super.shutdown(rm); + + final Sequence.Step[] shutdownSteps = new Sequence.Step[] { + new RegisterStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + new MonitorJobStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + new GDBProcessStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), }; + Sequence shutdownSequence = new Sequence(getExecutor(), new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleCompleted() { + GdbBackend.super.shutdown(requestMonitor); + } + }) { + @Override + public Step[] getSteps() { + return shutdownSteps; + } + }; + getExecutor().execute(shutdownSequence); } - // ------------------------------------------------------------------------ + /** @since 4.0 */ + protected IPath getGDBPath() { + return LaunchUtils.getGDBPath(fLaunchConfiguration); + } /** - * Overridden to get the full command line, including all options, from the - * OpenOCD configuration. + * Options for GDB process. Allow subclass to override. + * + * @deprecated Use {@link #getGDBCommandLineArray()} instead + */ + @Deprecated + protected String getGDBCommandLine() { + String cmdArray[] = getGDBCommandLineArray(); + return StringUtil.join(cmdArray, " "); //$NON-NLS-1$ + } + + /** + * Options for GDB process. Returns the GDB command and its arguments as an + * array. Allow subclass to override. + * + * @since 4.6 */ protected String[] getGDBCommandLineArray() { String[] commandLineArray = Configuration.getGdbClientCommandLineArray(fLaunchConfiguration); @@ -92,12 +220,221 @@ protected String[] getGDBCommandLineArray() { return commandLineArray; } + @Override + public String getGDBInitFile() throws CoreException { + if (fGDBInitFile == null) { + String defaultGdbInit = Platform.getPreferencesService().getString(GdbPlugin.PLUGIN_ID, + IGdbDebugPreferenceConstants.PREF_DEFAULT_GDB_INIT, + IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT, null); + + fGDBInitFile = fLaunchConfiguration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, + defaultGdbInit); + } + + return fGDBInitFile; + } + + @Override + public IPath getGDBWorkingDirectory() throws CoreException { + if (fGDBWorkingDirectory == null) { + + // First try to use the user-specified working directory for the + // debugged program. + // This is fine only with local debug. + // For remote debug, the working dir of the debugged program will be + // on remote device + // and hence not applicable. In such case we may just use debugged + // program path on host + // as the working dir for GDB. + // However, we cannot find a standard/common way to distinguish + // remote debug from local + // debug. For instance, a local debug may also use gdbserver+gdb. So + // it's up to each + // debugger implementation to make the distinction. + // + IPath path = null; + String location = fLaunchConfiguration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, + (String) null); + + if (location != null) { + String expandedLocation = VariablesPlugin.getDefault().getStringVariableManager() + .performStringSubstitution(location); + if (expandedLocation.length() > 0) { + path = new Path(expandedLocation); + } + } + + if (path != null) { + // Some validity check. Should have been done by UI code. + if (path.isAbsolute()) { + File dir = new File(path.toPortableString()); + if (!dir.isDirectory()) + path = null; + } else { + IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path); + if (res instanceof IContainer && res.exists()) { + path = res.getLocation(); + } else + // Relative but not found in workspace. + path = null; + } + } + + if (path == null) { + // default working dir is the project if this config has a + // project + ICProject cp = LaunchUtils.getCProject(fLaunchConfiguration); + if (cp != null) { + IProject p = cp.getProject(); + path = p.getLocation(); + } else { + // no meaningful value found. Just return null. + } + } + + fGDBWorkingDirectory = path; + } + + if (fGDBWorkingDirectory == null) + { + fGDBWorkingDirectory = DebugUtils.getProjectOsPath(fLaunchConfiguration); + } + + return fGDBWorkingDirectory; + } + + @Override + public String getProgramArguments() throws CoreException { + if (fProgramArguments == null) { + fProgramArguments = fLaunchConfiguration + .getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, (String) null); + + if (fProgramArguments != null) { + fProgramArguments = VariablesPlugin.getDefault().getStringVariableManager() + .performStringSubstitution(fProgramArguments); + } + } + + return fProgramArguments; + } + + @Override + public IPath getProgramPath() { + return fProgramPath; + } + + @Override + public List getSharedLibraryPaths() throws CoreException { + if (fSharedLibPaths == null) { + fSharedLibPaths = fLaunchConfiguration + .getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH, new ArrayList(0)); + } + + return fSharedLibPaths; + } + + /** @since 3.0 */ + @Override + public Properties getEnvironmentVariables() throws CoreException { + if (fEnvVariables == null) { + fEnvVariables = new Properties(); + + // if the attribute ATTR_APPEND_ENVIRONMENT_VARIABLES is set, + // the LaunchManager will return both the new variables and the + // existing ones. + // That would force us to delete all the variables in GDB, and then + // re-create then all + // that is not very efficient. So, let's fool the LaunchManager into + // returning just the + // list of new variables. + + boolean append = fLaunchConfiguration.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true); + + String[] properties; + if (append) { + ILaunchConfigurationWorkingCopy wc = fLaunchConfiguration.copy(""); //$NON-NLS-1$ + // Don't save this change, it is just temporary, and in just a + // copy of our launchConfig. + wc.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, false); + properties = DebugPlugin.getDefault().getLaunchManager().getEnvironment(wc); + } else { + // We're getting rid of the environment anyway, so this call + // will only yield the new variables. + properties = DebugPlugin.getDefault().getLaunchManager().getEnvironment(fLaunchConfiguration); + } + + if (properties == null) { + properties = new String[0]; + } + + for (String property : properties) { + int idx = property.indexOf('='); + if (idx != -1) { + String key = property.substring(0, idx); + String value = property.substring(idx + 1); + fEnvVariables.setProperty(key, value); + } else { + fEnvVariables.setProperty(property, ""); //$NON-NLS-1$ + } + } + } + + return fEnvVariables; + } + + /** @since 3.0 */ + @Override + public boolean getClearEnvironment() throws CoreException { + return !fLaunchConfiguration.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true); + } + + /** @since 3.0 */ + @Override + public boolean getUpdateThreadListOnSuspend() throws CoreException { + return fLaunchConfiguration.getAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND, + IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT); + } + + protected Process launchGDBProcess() throws CoreException { + // Keep calling deprecated getGDBCommandLine() in case it was overridden + String command = getGDBCommandLine(); + // Keep calling deprecated launchGDBProcess(String) in case it was + // overridden + return launchGDBProcess(command); + } + /** - * Overridden to use our own launch environment and to add the working - * directory to exec(), although it is anyway set in a separate step - * (stepSetEnvironmentDirector in FinalLaunchSequence). + * Launch GDB process. Allow subclass to override. + * + * @deprecated Use {@link #launchGDBProcess(String[])} instead + */ + @Deprecated + protected Process launchGDBProcess(String commandLine) throws CoreException { + // Backwards-compatibility check + // If the commandLine parameter is not the same as the command line + // array we provide + // it implies that the commandLine was modified by an extender and + // should be used as + // is. If it is the same, we can use the command line array instead + // using the more robust + // non-deprecated call to launchGDBProcess. + String unmodifiedCmdLine = StringUtil.join(getGDBCommandLineArray(), " ").trim(); //$NON-NLS-1$ + if (unmodifiedCmdLine.equals(commandLine.trim()) == false) { + Process proc = DebugUtils.exec(commandLine, LaunchUtils.getLaunchEnvironment(fLaunchConfiguration)); + return proc; + } + // End of Backwards-compatibility check + + return launchGDBProcess(getGDBCommandLineArray()); + } + + /** + * Launch GDB process with command and arguments. Allow subclass to + * override. + * + * @since 4.6 */ - @Override protected Process launchGDBProcess(String[] commandLineArray) throws CoreException { File dir = null; IPath path = getGDBWorkingDirectory(); @@ -110,30 +447,616 @@ protected Process launchGDBProcess(String[] commandLineArray) throws CoreExcepti return proc; } + @Override + public Process getProcess() { + return fProcess; + } + + @Override + public OutputStream getMIOutputStream() { + return fProcess.getOutputStream(); + } + + @Override + public InputStream getMIInputStream() { + return fProcess.getInputStream(); + } + + /** @since 4.1 */ + @Override + public InputStream getMIErrorStream() { + return fProcess.getErrorStream(); + } + + @Override + public String getId() { + return fBackendId; + } + + @Override + public void interrupt() { + if (fProcess instanceof Spawner) { + Spawner gdbSpawner = (Spawner) fProcess; + + // Cygwin gdb 6.8 is capricious when it comes to interrupting the + // target. The same logic here will work with MinGW, though. And on + // linux it's irrelevant since interruptCTRLC()==interrupt(). So, + // one odd size fits all. + // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=304096#c54 + if (getSessionType() == SessionType.REMOTE) { + gdbSpawner.interrupt(); + } else { + gdbSpawner.interruptCTRLC(); + } + } + } + /** - * Overridden to also try getProjectOsPath(), if getGDBWorkingDirectory() is - * not defined. - * - * May return null. + * @since 3.0 */ @Override - public IPath getGDBWorkingDirectory() throws CoreException { + public void interruptAndWait(int timeout, RequestMonitor rm) { + if (fProcess instanceof Spawner) { + Spawner gdbSpawner = (Spawner) fProcess; - IPath path; - try { - path = super.getGDBWorkingDirectory(); - } catch (CoreException e) { - path = null; + // Cygwin gdb 6.8 is capricious when it comes to interrupting the + // target. The same logic here will work with MinGW, though. And on + // linux it's irrelevant since interruptCTRLC()==interrupt(). So, + // one odd size fits all. + // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=304096#c54 + if (getSessionType() == SessionType.REMOTE) { + gdbSpawner.interrupt(); + } else { + gdbSpawner.interruptCTRLC(); + } + fInterruptFailedJob = new MonitorInterruptJob(timeout, rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, + "Cannot interrupt.", null)); //$NON-NLS-1$ + rm.done(); } + } - if (path == null) { - path = DebugUtils.getProjectOsPath(fLaunchConfiguration); + /** + * @since 3.0 + */ + @Override + public void interruptInferiorAndWait(long pid, int timeout, RequestMonitor rm) { + if (fProcess instanceof Spawner) { + Spawner gdbSpawner = (Spawner) fProcess; + gdbSpawner.raise((int) pid, gdbSpawner.INT); + fInterruptFailedJob = new MonitorInterruptJob(timeout, rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, + "Cannot interrupt.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + @Override + public void destroy() { + // Don't close the streams ourselves as it may be too early. + // Wait for the actual user of the streams to close it. + // Bug 339379 + + if (Activator.getInstance().isDebugging()) { + System.out.println("GnuMcuGdbBackend.destroy()"); + } + + // destroy() should be supported even if it's not spawner. + if (getState() == State.STARTED) { + fProcess.destroy(); + } + } + + @Override + public State getState() { + return fBackendState; + } + + @Override + public int getExitCode() { + return fGDBExitValue; + } + + @Override + public SessionType getSessionType() { + if (fSessionType == null) { + fSessionType = LaunchUtils.getSessionType(fLaunchConfiguration); + } + return fSessionType; + } + + @Override + public boolean getIsAttachSession() { + if (fAttach == null) { + fAttach = LaunchUtils.getIsAttach(fLaunchConfiguration); + } + return fAttach; + } + + @Override + protected BundleContext getBundleContext() { + return GdbPlugin.getBundleContext(); + } + + protected class GDBProcessStep extends InitializationShutdownStep { + GDBProcessStep(Direction direction) { + super(direction); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + + if (Activator.getInstance().isDebugging()) { + System.out.println("GDBProcessStep.initialise()"); + } + + class GDBLaunchMonitor { + boolean fLaunched = false; + boolean fTimedOut = false; + } + final GDBLaunchMonitor fGDBLaunchMonitor = new GDBLaunchMonitor(); + + final RequestMonitor gdbLaunchRequestMonitor = new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleCompleted() { + if (Activator.getInstance().isDebugging()) { + System.out.println("GDBProcessStep.initialise() handleCompleted()"); + } + + if (!fGDBLaunchMonitor.fTimedOut) { + fGDBLaunchMonitor.fLaunched = true; + if (!isSuccess()) { + requestMonitor.setStatus(getStatus()); + } + requestMonitor.done(); + } + } + }; + + final Job startGdbJob = new Job("Start GDB Process Job") { //$NON-NLS-1$ + { + setSystem(true); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + + if (Activator.getInstance().isDebugging()) { + System.out.println("GDBProcessStep.initialise() Job run()"); + } + + if (gdbLaunchRequestMonitor.isCanceled()) { + gdbLaunchRequestMonitor.setStatus( + new Status(IStatus.CANCEL, GdbPlugin.PLUGIN_ID, -1, "Canceled starting GDB", null)); //$NON-NLS-1$ + gdbLaunchRequestMonitor.done(); + return Status.OK_STATUS; + } + + try { + fProcess = launchGDBProcess(); + // Need to do this on the executor for thread-safety + getExecutor().submit(new DsfRunnable() { + @Override + public void run() { + fBackendState = State.STARTED; + } + }); + // Don't send the backendStarted event yet. We wait + // until we have registered this service + // so that other services can have access to it. + } catch (CoreException e) { + gdbLaunchRequestMonitor + .setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, e.getMessage(), e)); + gdbLaunchRequestMonitor.done(); + return Status.OK_STATUS; + } + + BufferedReader inputReader = null; + BufferedReader errorReader = null; + boolean success = false; + try { + // Read initial GDB prompt + inputReader = new BufferedReader(new InputStreamReader(getMIInputStream())); + String line; + while ((line = inputReader.readLine()) != null) { + line = line.trim(); + if (line.endsWith("(gdb)")) { //$NON-NLS-1$ + success = true; + break; + } + } + + // Failed to read initial prompt, check for error + if (!success) { + errorReader = new BufferedReader(new InputStreamReader(getMIErrorStream())); + String errorInfo = errorReader.readLine(); + if (errorInfo == null) { + errorInfo = "GDB prompt not read"; //$NON-NLS-1$ + } + gdbLaunchRequestMonitor + .setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, errorInfo, null)); + } + } catch (IOException e) { + success = false; + gdbLaunchRequestMonitor.setStatus( + new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Error reading GDB output", e)); //$NON-NLS-1$ + } + + // In the case of failure, close the MI streams so + // they are not leaked. + if (!success) { + if (inputReader != null) { + try { + inputReader.close(); + } catch (IOException e) { + } + } + if (errorReader != null) { + try { + errorReader.close(); + } catch (IOException e) { + } + } + } + + gdbLaunchRequestMonitor.done(); + return Status.OK_STATUS; + } + }; + startGdbJob.schedule(); + + getExecutor().schedule(new Runnable() { + @Override + public void run() { + // Only process the event if we have not finished yet (hit + // the breakpoint). + if (!fGDBLaunchMonitor.fLaunched) { + fGDBLaunchMonitor.fTimedOut = true; + Thread jobThread = startGdbJob.getThread(); + if (jobThread != null) { + jobThread.interrupt(); + } + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + DebugException.TARGET_REQUEST_FAILED, "Timed out trying to launch GDB.", null)); //$NON-NLS-1$ + requestMonitor.done(); + } + } + }, fGDBLaunchTimeout, TimeUnit.SECONDS); + } + + @Override + protected void shutdown(final RequestMonitor requestMonitor) { + + if (Activator.getInstance().isDebugging()) { + System.out.println("GDBProcessStep.shutdown()"); + } + + if (getState() != State.STARTED) { + // gdb not started yet or already killed, don't bother starting + // a job to kill it + requestMonitor.done(); + return; + } + + new Job("Terminating GDB process.") { //$NON-NLS-1$ + { + setSystem(true); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + // Need to do this on the executor for thread-safety + // And we should wait for it to complete since we then + // check if the killing of GDB worked. + if (Activator.getInstance().isDebugging()) { + System.out.println("GDBProcessStep.shutdown() run()"); + } + getExecutor().submit(new DsfRunnable() { + @Override + public void run() { + destroy(); + + if (fMonitorJob.fMonitorExited) { + // Now that we have destroyed the process, + // and that the monitoring thread was + // killed, + // we need to set our state and send the + // event + fBackendState = State.TERMINATED; + if (Activator.getInstance().isDebugging()) { + System.out.println( + "GDBProcessStep.shutdown() run() dispatchEvent(BackendStateChangedEvent, TERMINATED)"); + } + getSession().dispatchEvent(new BackendStateChangedEvent(getSession().getId(), + getId(), State.TERMINATED), getProperties()); + } + } + }).get(); + } catch (InterruptedException e1) { + } catch (ExecutionException e1) { + } + + int attempts = 0; + while (attempts < 10) { + try { + // Don't know if we really need the exit value... + // but what the heck. + fGDBExitValue = fProcess.exitValue(); // throws + // exception + // if + // process + // not + // exited + + if (Activator.getInstance().isDebugging()) { + System.out.println("GDBProcessStep.shutdown() run() return"); + } + requestMonitor.done(); + return Status.OK_STATUS; + } catch (IllegalThreadStateException ie) { + } + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + attempts++; + } + if (Activator.getInstance().isDebugging()) { + System.out.println("GDBProcessStep.shutdown() run() REQUEST_FAILED"); + } + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + IDsfStatusConstants.REQUEST_FAILED, "GDB terminate failed", null)); //$NON-NLS-1$ + requestMonitor.done(); + return Status.OK_STATUS; + } + }.schedule(); + } + } + + protected class MonitorJobStep extends InitializationShutdownStep { + MonitorJobStep(Direction direction) { + super(direction); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + if (Activator.getInstance().isDebugging()) { + System.out.println("MonitorJobStep.initialize()"); + } + fMonitorJob = new MonitorJob(fProcess, new DsfRunnable() { + @Override + public void run() { + requestMonitor.done(); + } + }); + fMonitorJob.schedule(); + } + + @Override + protected void shutdown(RequestMonitor requestMonitor) { + + if (Activator.getInstance().isDebugging()) { + System.out.println("MonitorJobStep.shutdown()"); + } + if (fMonitorJob != null) { + fMonitorJob.kill(); + } + requestMonitor.done(); + if (Activator.getInstance().isDebugging()) { + System.out.println("MonitorJobStep.shutdown() done"); + } + } + } + + protected class RegisterStep extends InitializationShutdownStep { + RegisterStep(Direction direction) { + super(direction); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + register(new String[] { IMIBackend.class.getName(), IMIBackend2.class.getName(), + IGDBBackend.class.getName() }, new Hashtable()); + + getSession().addServiceEventListener(GdbBackend.this, null); + + /* + * This event is not consumed by any one at present, instead it's + * the GDBControlInitializedDMEvent that's used to indicate that GDB + * back end is ready for MI commands. But we still fire the event as + * it does no harm and may be needed sometime.... 09/29/2008 + * + * We send the event in the register step because that is when other + * services have access to it. + */ + getSession().dispatchEvent(new BackendStateChangedEvent(getSession().getId(), getId(), State.STARTED), + getProperties()); + + requestMonitor.done(); + } + + @Override + protected void shutdown(RequestMonitor requestMonitor) { + unregister(); + getSession().removeServiceEventListener(GdbBackend.this); + requestMonitor.done(); + } + } + + /** + * Monitors a system process, waiting for it to terminate, and then notifies + * the associated runtime process. + */ + private class MonitorJob extends Job { + boolean fMonitorExited = false; + DsfRunnable fMonitorStarted; + Process fMonProcess; + + @Override + protected IStatus run(IProgressMonitor monitor) { + synchronized (fMonProcess) { + getExecutor().submit(fMonitorStarted); + try { + fMonProcess.waitFor(); + fGDBExitValue = fMonProcess.exitValue(); + + if (Activator.getInstance().isDebugging()) { + System.out.println("MonitorJob.run() exitValue() " + fGDBExitValue); + } + + if(fProcess.isAlive() && Activator.getInstance().isDebugging()) + { + // Need to do this on the executor for thread-safety + getExecutor().submit(new DsfRunnable() { + @Override + public void run() { + + if (Activator.getInstance().isDebugging()) { + System.out.println("MonitorJob.run() run() "); + } + + destroy(); + fBackendState = State.TERMINATED; + + if (Activator.getInstance().isDebugging()) { + System.out.println( + "MonitorJob.run() run() dispatchEvent(BackendStateChangedEvent, TERMINATED)"); + } + getSession().dispatchEvent( + new BackendStateChangedEvent(getSession().getId(), getId(), State.TERMINATED), + getProperties()); + } + }); + } + + } catch (InterruptedException ie) { + // clear interrupted state + Thread.interrupted(); + } + + fMonitorExited = true; + } + return Status.OK_STATUS; } + MonitorJob(Process process, DsfRunnable monitorStarted) { + super("GDB process monitor job."); //$NON-NLS-1$ + fMonProcess = process; + fMonitorStarted = monitorStarted; + setSystem(true); + } + + void kill() { + synchronized (fMonProcess) { + if (!fMonitorExited) { + getThread().interrupt(); + } + } + } + } + + /** + * Stores the request monitor that must be dealt with for the result of the + * interrupt operation. If the interrupt successfully suspends the backend, + * the request monitor can be retrieved and completed successfully, and then + * this job should be canceled. If this job is not canceled before the time + * is up, it will imply the interrupt did not successfully suspend the + * backend, and the current job will indicate this in the request monitor. + * + * The specified timeout is used to indicate how many milliseconds this job + * should wait for. INTERRUPT_TIMEOUT_DEFAULT indicates to use the default + * of 5 seconds. The default is also use if the timeout value is 0 or + * negative. + * + * @since 3.0 + */ + protected class MonitorInterruptJob extends Job { + // Bug 310274. Until we have a preference to configure timeouts, + // we need a large enough default timeout to accommodate slow + // remote sessions. + private final static int TIMEOUT_DEFAULT_VALUE = 5000; + private final RequestMonitor fRequestMonitor; + + public MonitorInterruptJob(int timeout, RequestMonitor rm) { + super("Interrupt monitor job."); //$NON-NLS-1$ + setSystem(true); + fRequestMonitor = rm; + + if (timeout == INTERRUPT_TIMEOUT_DEFAULT || timeout <= 0) { + timeout = TIMEOUT_DEFAULT_VALUE; // default of 5 seconds + } + + schedule(timeout); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + getExecutor().submit(new DsfRunnable() { + @Override + public void run() { + fInterruptFailedJob = null; + fRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + IDsfStatusConstants.REQUEST_FAILED, "Interrupt failed.", null)); //$NON-NLS-1$ + fRequestMonitor.done(); + } + }); + return Status.OK_STATUS; + } + + public RequestMonitor getRequestMonitor() { + return fRequestMonitor; + } + } + + /** + * We use this handler to determine if the SIGINT we sent to GDB has been + * effective. We must listen for an MI event and not a higher-level + * ISuspendedEvent. The reason is that some ISuspendedEvent are not sent + * when the target stops, in cases where we don't want to views to update. + * For example, if we want to interrupt the target to set a breakpoint, this + * interruption is done silently; we will receive the MI event though. + * + *

+ * Though we send a SIGINT, we may not specifically get an MISignalEvent. + * Typically we will, but not always, so wait for an MIStoppedEvent. See + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=305178#c21 + * + * @since 3.0 + * + */ + @DsfServiceEventHandler + public void eventDispatched(final MIStoppedEvent e) { + if (fInterruptFailedJob != null) { + if (fInterruptFailedJob.cancel()) { + fInterruptFailedJob.getRequestMonitor().done(); + } + fInterruptFailedJob = null; + } + } + + /** + * Safety net, in case the GDB client does not exit on command. + * + * The event is created and triggered by Process.terminate(). + * + * @param e + */ + @DsfServiceEventHandler + public void eventDispatched(final ProcessStateChangedEvent e) { + if (Activator.getInstance().isDebugging()) { - System.out.println("openocd.GdbBackend.getGDBWorkingDirectory() " + path); + System.out.println("GnuMcuGdbBackend.eventDispatched() " + e); + } + + // When the process is terminated, also terminate the backend. + if (e.getState() == State.TERMINATED && e.getSessionId().equals(getSession().getId()) + && getState() == State.STARTED) { + + destroy(); } - return path; } // ------------------------------------------------------------------------ diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java index 738c444e7..0e10d97c4 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java @@ -32,15 +32,16 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.ISourceLocator; -import org.eclipse.debug.internal.core.LaunchConfigurationWorkingCopy; import org.eclipse.embedcdt.debug.gdbjtag.core.dsf.GnuMcuLaunch; +import org.eclipse.swt.widgets.Display; -import com.espressif.idf.core.util.PortChecker; import com.espressif.idf.debug.gdbjtag.openocd.Activator; import com.espressif.idf.debug.gdbjtag.openocd.Configuration; import com.espressif.idf.debug.gdbjtag.openocd.ConfigurationAttributes; @@ -57,6 +58,8 @@ public class Launch extends GnuMcuLaunch private DsfSession fSession; private DsfServicesTracker fTracker; private DefaultDsfExecutor fExecutor; + private IProcess openOcdServerProcess; + private IProcess gdbIProcess; // ------------------------------------------------------------------------ @@ -165,14 +168,13 @@ public void initializeServerConsole(IProgressMonitor monitor) throws CoreExcepti System.out.println("openocd.Launch.initializeServerConsole()"); } - IProcess newProcess; boolean doAddServerConsole = Configuration.getDoAddServerConsole(fConfig); if (doAddServerConsole) { // Add the GDB server process to the launch tree - newProcess = addServerProcess(Configuration.getGdbServerCommandName(fConfig)); + openOcdServerProcess = addServerProcess(Configuration.getGdbServerCommandName(fConfig)); monitor.worked(1); } } @@ -185,11 +187,10 @@ public void initializeConsoles(IProgressMonitor monitor) throws CoreException System.out.println("openocd.Launch.initializeConsoles()"); } - IProcess newProcess; { // Add the GDB client process to the launch tree. - newProcess = addClientProcess(Configuration.getGdbClientCommandName(fConfig)); - newProcess.setAttribute(IProcess.ATTR_CMDLINE, Configuration.getGdbClientCommandLine(fConfig)); + gdbIProcess = addClientProcess(Configuration.getGdbClientCommandName(fConfig)); + gdbIProcess.setAttribute(IProcess.ATTR_CMDLINE, Configuration.getGdbClientCommandLine(fConfig)); monitor.worked(1); } @@ -244,4 +245,31 @@ public Process call() throws CoreException } // ------------------------------------------------------------------------ + + @Override + public void terminate() throws DebugException + { + super.terminate(); + for(IProcess process : getProcesses()) + { + if (process != null) + { + try + { + process.terminate(); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + } + } + + @Override + public IProcess[] getProcesses() + { + return new IProcess[] { openOcdServerProcess, gdbIProcess }; + } } diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java index b7712aa21..5f59eea21 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchConfigurationDelegate.java @@ -699,19 +699,6 @@ protected void handleCompleted() // -------------------------------------------------------------------- } - @Override - /** - * This method takes care of cleaning up any resources allocated by the launch, as early as - * the call to getLaunch(), whenever the launch is cancelled or does not complete properly. - * @since 5.0 */ - protected void cleanupLaunch(ILaunch launch) throws DebugException - { - if (launch instanceof GdbLaunch) - { - launch.terminate(); - } - } - /** * Perform some local validations before starting the debug session. */ diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java index b43da1ea8..8c67d92bb 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java @@ -16,6 +16,7 @@ import org.eclipse.debug.core.model.RuntimeProcess; import org.eclipse.debug.internal.core.NullStreamsProxy; +import com.espressif.idf.core.util.StringUtil; import com.espressif.idf.debug.gdbjtag.openocd.dsf.process.monitors.StreamsProxy; /** @@ -38,6 +39,10 @@ public IdfRuntimeProcess(ILaunch launch, Process process, String name, Map Date: Mon, 18 Nov 2024 16:54:45 +0100 Subject: [PATCH 13/16] fix(disclamers): updated required docs for the classes --- .../debug/gdbjtag/openocd/dsf/GdbBackend.java | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java index b16ba5072..c45374269 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/GdbBackend.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 Liviu Ionescu. + * Copyright (c) 2006, 2012 Wind River Systems, Nokia and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -7,11 +7,29 @@ * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 - * + * * Contributors: - * Liviu Ionescu - initial version + * Nokia - initial API and implementation with some code moved from GDBControl. + * Wind River System + * Ericsson + * Marc Khouzam (Ericsson) - Use the new IMIBackend2 interface (Bug 350837) + * Mark Bozeman (Mentor Graphics) - Report GDB start failures (Bug 376203) + * Iulia Vasii (Freescale Semiconductor) - Separate GDB command from its arguments (Bug 445360) *******************************************************************************/ +/* ---------------------------------------------------------------------------- + * + * Copied here because we need the new version, but still remain compatible + * with Kepler. When dependency to Kepler will be removed, this file will + * no longer be necessary. + * + * It is identical to the newer GDBBackend, with the following changes: + * - package org.eclipse.embedcdt.debug.gdbjtag.jlink.dsf; + * - some imports + * - @SuppressWarnings("restriction") + * + * ------------------------------------------------------------------------- */ + package com.espressif.idf.debug.gdbjtag.openocd.dsf; import java.io.BufferedReader; @@ -72,17 +90,25 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.embedcdt.debug.gdbjtag.core.DebugUtils; +import org.eclipse.embedcdt.debug.gdbjtag.core.dsf.GnuMcuGdbBackend; import org.eclipse.embedcdt.debug.gdbjtag.core.dsf.GnuMcuProcesses_7_2_1.ProcessStateChangedEvent; import org.osgi.framework.BundleContext; import com.espressif.idf.debug.gdbjtag.openocd.Activator; import com.espressif.idf.debug.gdbjtag.openocd.Configuration; + /** - * The Kepler CDT GDBBackend does not allow such a simple customisation, we had - * to copy a newer version locally and use it. + * Implementation of {@link IGDBBackend} for the common case where GDB is + * launched in local file system on host PC where Eclipse runs. This also + * manages some GDB parameters from a given launch configuration.
+ *
+ * You can subclass for you special needs. + * + * @since 1.1 + * + * This class is taken from {@link GnuMcuGdbBackend} */ - public class GdbBackend extends AbstractDsfService implements IGDBBackend, IMIBackend2 { private final ILaunchConfiguration fLaunchConfiguration; From f1d737c7843c42184696f0a2ec7af5b424a69b44 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:16:27 +0100 Subject: [PATCH 14/16] fix(npe): updated code to handle npe for the getProcesses function --- .../idf/debug/gdbjtag/openocd/dsf/Launch.java | 11 ++++++++++- .../openocd/dsf/process/IdfRuntimeProcess.java | 4 ---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java index 0e10d97c4..afd947137 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java @@ -14,7 +14,9 @@ package com.espressif.idf.debug.gdbjtag.openocd.dsf; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -270,6 +272,13 @@ public void terminate() throws DebugException @Override public IProcess[] getProcesses() { - return new IProcess[] { openOcdServerProcess, gdbIProcess }; + List processes = new ArrayList<>(); + if (openOcdServerProcess != null) { + processes.add(openOcdServerProcess); + } + if (gdbIProcess != null) { + processes.add(gdbIProcess); + } + return processes.toArray(new IProcess[0]); } } diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java index 8c67d92bb..b25a451a5 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/process/IdfRuntimeProcess.java @@ -39,10 +39,6 @@ public IdfRuntimeProcess(ILaunch launch, Process process, String name, Map Date: Wed, 20 Nov 2024 17:16:13 +0100 Subject: [PATCH 15/16] fix(proc_dictionary): Add helper class to hold processes by launches Refactored the dictionary handling in the process manager to organize processes based on their respective launches. This improves code readability and reduces bugs when managing multiple launches. --- .../idf/debug/gdbjtag/openocd/dsf/Launch.java | 33 ++++++++++-- .../openocd/dsf/LaunchProcessDictionary.java | 52 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java index afd947137..a774af32d 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java @@ -34,7 +34,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; @@ -42,7 +41,6 @@ import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.ISourceLocator; import org.eclipse.embedcdt.debug.gdbjtag.core.dsf.GnuMcuLaunch; -import org.eclipse.swt.widgets.Display; import com.espressif.idf.debug.gdbjtag.openocd.Activator; import com.espressif.idf.debug.gdbjtag.openocd.Configuration; @@ -62,6 +60,9 @@ public class Launch extends GnuMcuLaunch private DefaultDsfExecutor fExecutor; private IProcess openOcdServerProcess; private IProcess gdbIProcess; + + private static final String SERVER_PROC_KEY = "SERVER_PROC"; + private static final String GDB_PROC_KEY = "GDB_PROC"; // ------------------------------------------------------------------------ @@ -105,6 +106,15 @@ public void run() // fireChanged(); } }; + + try + { + cleanUpOldLaunchProcesses(); + } + catch (CoreException e) + { + e.printStackTrace(); + } // Invoke the execution code and block waiting for the result. try @@ -121,6 +131,7 @@ public void run() new Status(IStatus.ERROR, Activator.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Error initializing launch", e); //$NON-NLS-1$ } + } @Override @@ -177,6 +188,7 @@ public void initializeServerConsole(IProgressMonitor monitor) throws CoreExcepti // Add the GDB server process to the launch tree openOcdServerProcess = addServerProcess(Configuration.getGdbServerCommandName(fConfig)); + LaunchProcessDictionary.getInstance().addProcessToDictionary(getLaunchConfiguration().getName(), SERVER_PROC_KEY, openOcdServerProcess); monitor.worked(1); } } @@ -193,7 +205,7 @@ public void initializeConsoles(IProgressMonitor monitor) throws CoreException // Add the GDB client process to the launch tree. gdbIProcess = addClientProcess(Configuration.getGdbClientCommandName(fConfig)); gdbIProcess.setAttribute(IProcess.ATTR_CMDLINE, Configuration.getGdbClientCommandLine(fConfig)); - + LaunchProcessDictionary.getInstance().addProcessToDictionary(getLaunchConfiguration().getName(), GDB_PROC_KEY, gdbIProcess); monitor.worked(1); } } @@ -281,4 +293,19 @@ public IProcess[] getProcesses() } return processes.toArray(new IProcess[0]); } + + private void cleanUpOldLaunchProcesses() throws CoreException + { + IProcess serverIProcess = LaunchProcessDictionary.getInstance().getProcessFromDictionary(getLaunchConfiguration().getName(), SERVER_PROC_KEY); + if (serverIProcess != null && !serverIProcess.isTerminated()) + { + serverIProcess.terminate(); + } + + IProcess gdbIProcess = LaunchProcessDictionary.getInstance().getProcessFromDictionary(getLaunchConfiguration().getName(), GDB_PROC_KEY); + if(gdbIProcess != null && !gdbIProcess.isTerminated()) + { + gdbIProcess.terminate(); + } + } } diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java new file mode 100644 index 000000000..52c7eb3cb --- /dev/null +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java @@ -0,0 +1,52 @@ +package com.espressif.idf.debug.gdbjtag.openocd.dsf; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.debug.core.model.IProcess; + +public class LaunchProcessDictionary +{ + private static LaunchProcessDictionary instance; + + private Map> processDictionary; + + private LaunchProcessDictionary() + { + processDictionary = new HashMap<>(); + } + + public static LaunchProcessDictionary getInstance() + { + if(instance == null) + instance = new LaunchProcessDictionary(); + + return instance; + } + + public void addProcessToDictionary(String launchName, String procName, IProcess process) + { + if (!processDictionary.containsKey(launchName)) + { + Map processMap = new HashMap<>(); + processMap.put(procName, process); + processDictionary.put(launchName, processMap); + return; + } + + Map processMap = processDictionary.get(launchName); + processMap.put(procName, process); + processDictionary.put(launchName, processMap); + } + + public IProcess getProcessFromDictionary(String launchName, String procName) + { + if (!processDictionary.containsKey(launchName)) + { + return null; + } + + return processDictionary.get(launchName).get(procName); + } + +} From 9fde5658f32adc0b6c835ea3675d4e66b41fc693 Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Wed, 20 Nov 2024 17:30:45 +0100 Subject: [PATCH 16/16] fix(process): Debug Launch to return true for disconnect and terminate --- .../idf/debug/gdbjtag/openocd/dsf/Launch.java | 30 +++++++++---------- .../openocd/dsf/LaunchProcessDictionary.java | 21 +++++++++++++ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java index a774af32d..4b2583375 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/Launch.java @@ -264,23 +264,23 @@ public Process call() throws CoreException public void terminate() throws DebugException { super.terminate(); - for(IProcess process : getProcesses()) - { - if (process != null) - { - try - { - process.terminate(); - } - catch (Exception e) - { - e.printStackTrace(); - } - - } - } + + LaunchProcessDictionary.getInstance().killAllProcessesInLaunch(getLaunchConfiguration().getName()); } + @Override + public boolean canDisconnect() + { + return true; + } + + @Override + public boolean canTerminate() + { + return true; + } + + @Override public IProcess[] getProcesses() { diff --git a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java index 52c7eb3cb..3199d8989 100644 --- a/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java +++ b/bundles/com.espressif.idf.debug.gdbjtag.openocd/src/com/espressif/idf/debug/gdbjtag/openocd/dsf/LaunchProcessDictionary.java @@ -3,6 +3,7 @@ import java.util.HashMap; import java.util.Map; +import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IProcess; public class LaunchProcessDictionary @@ -48,5 +49,25 @@ public IProcess getProcessFromDictionary(String launchName, String procName) return processDictionary.get(launchName).get(procName); } + + public void killAllProcessesInLaunch(String launchName) + { + if(!processDictionary.containsKey(launchName)) + { + return; + } + + for (IProcess process : processDictionary.get(launchName).values()) + { + try + { + process.terminate(); + } + catch (DebugException e) + { + e.printStackTrace(); + } + } + } }