Page 1 of 1

ARM Debugging (and most likely other remote debugging)

Posted: Wed May 28, 2014 8:50 pm
by tlang
Hi together,
the current version of CodeLite is still unusable for remote debugging on embedded platforms. For the ARM Coretex M3 familiy of controllers there had been a debugger DLL released a few years ago by Ac.Verbek, but this member seems to have left the forum a few years ago and unfortunately has never released any sources.

The major problem is that you cannot use the Windows Kenrnel's DebugBreak call to generate an exception in the debugged application once it is running. As the local gdb is started without a console it is also difficult to impossible to use the console control handler functions to send a SIGINT (CTRL+C) to the local GDB. So the gdb has to be set to be set to async mode to allow the interrupt being sent by an mi command. In case of remote debugging the correct interrupt mechanism has to be used then.

Below is a patch (the relevant changes are altogether in debuggergdb.cpp) for the debugger DLL, with a J-Link and SEGGER DGB server (and of course the correct settings in the project) I'm now at least able to do some basic debugging.
  • Defects:
  • Every time I hit the pause button a dialog box will appear complaining about the "Program received signal SIGTRAP". Actually this shouldn't happen but I assume the debugger DLL becomes out of sync (there is only a flag to suppress this dialog, but even switching to counting in the breakpoint manager didn't solve the problem)
  • When stepping at the end of a function the stack seems to become corrupted and the HardFault handler of the controller is triggered. As stepping does work within Eclipse (with yagarto tool chain and corresponding plugin) I assume it's not a problem of GDB but CodeLite somehow modifying the memory. This has to be investigated further...
I would be interested in any comments if these changes break other projects (the Linux code is yet untested but I assume it should work the same way as the Windows code).

Regards,
Torsten

P. S. I will do further investigatioons after the weekend but at least wanted to share my results.

Code: Select all

 Debugger/debuggergdb.cpp                | 27 ++++++++++++++++++++++--
 LiteEditor.workspace                    | 15 +++++++++----
 LiteEditor/LiteEditor.project           | 37 +++++++++++++++++++++++++--------
 codelite_utils/codelite_utils.workspace |  1 -
 cppchecker/CppChecker.project           |  1 +
 5 files changed, 65 insertions(+), 16 deletions(-)

diff --git a/Debugger/debuggergdb.cpp b/Debugger/debuggergdb.cpp
index 96b5b06..fc9c356 100644
--- a/Debugger/debuggergdb.cpp
+++ b/Debugger/debuggergdb.cpp
@@ -520,7 +520,19 @@ bool DbgGdb::Interrupt()
         m_observer->UpdateAddLine( wxString::Format( wxT( "Interrupting debugee process: %ld" ), m_debuggeePid ) );
 
 #ifdef __WXMSW__
-        if ( DebugBreakProcessFunc ) {
+        if ( GetIsRemoteDebugging() != false) {
+            // TL: Create CRTL+C event for the local gdb (will break the target process)
+            //return WriteCommand( wxT( "interpreter-exec mi interrupt" ), new DbgCmdHandlerAsyncCmd( m_observer, this ) );
+            return WriteCommand( wxT( "-exec-interrupt" ), new DbgCmdHandlerAsyncCmd( m_observer, this ) );
+            /*
+            bool result;
+            AttachConsole(( DWORD )m_gdbProcess->GetPid());
+            SetConsoleCtrlHandler(NULL, TRUE);
+            result = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+            FreeConsole();
+            return result;
+            */
+        } else if ( DebugBreakProcessFunc ) {
             // we have DebugBreakProcess
             HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ( DWORD )m_debuggeePid );
             BOOL res = DebugBreakProcessFunc( process );
@@ -532,7 +544,12 @@ bool DbgGdb::Interrupt()
         // debuggee process
         return false;
 #else
-        kill( m_debuggeePid, SIGINT );
+        if ( GetIsRemoteDebugging() != false) {
+            // TL: Create CRTL+C event for the local gdb (will break the target process)
+            return WriteCommand( wxT( "-exec-interrupt" ), new DbgCmdHandlerAsyncCmd( m_observer, this ) );
+        } else {
+            kill( m_debuggeePid, SIGINT );
+        }
         return true;
 #endif
     } else {
@@ -1020,6 +1037,12 @@ bool DbgGdb::DoInitializeGdb(const DebugSessionInfo& sessionInfo)
     ExecuteCmd( wxT( "set  new-console on" ) );
 #endif
     ExecuteCmd( wxT( "set unwindonsignal on" ) );
+    
+    // TL: Activate async mode when remote debugging (required for -exec-interrupt
+    //     which requires a asynchronically running command parser)
+    if ( GetIsRemoteDebugging() != false ) {
+      ExecuteCmd( wxT("set target-async 1" ) );
+    }
 
     wxString breakinsertcmd(wxT("-break-insert "));
 
diff --git a/LiteEditor.workspace b/LiteEditor.workspace
index b62ee86..17b5755 100644
--- a/LiteEditor.workspace
+++ b/LiteEditor.workspace
@@ -45,8 +45,9 @@
   <Environment>
     <![CDATA[]]>
   </Environment>
+  <Project Name="DebuggerJLink" Path="DebuggerJLink/DebuggerJLink.project" Active="No"/>
   <BuildMatrix>
-    <WorkspaceConfiguration Name="Win Release Unicode" Selected="no">
+    <WorkspaceConfiguration Name="Win Release Unicode" Selected="yes">
       <Project Name="abbreviation" ConfigName="WinReleaseUnicode"/>
       <Project Name="CallGraph" ConfigName="WinReleaseUnicode"/>
       <Project Name="CMakePlugin" ConfigName="WinReleaseUnicode"/>
@@ -61,6 +62,7 @@
       <Project Name="DatabaseExplorer" ConfigName="WinReleaseUnicode"/>
       <Project Name="databaselayer_sqlite" ConfigName="WinReleaseUnicode"/>
       <Project Name="DebuggerGDB" ConfigName="WinReleaseUnicode"/>
+      <Project Name="DebuggerJLink" ConfigName="WinReleaseUnicode"/>
       <Project Name="ExternalTools" ConfigName="WinReleaseUnicode"/>
       <Project Name="git" ConfigName="WinReleaseUnicode"/>
       <Project Name="Gizmos" ConfigName="WinReleaseUnicode"/>
@@ -119,6 +121,7 @@
       <Project Name="wxshapeframework" ConfigName="WinDebugUnicode"/>
       <Project Name="wxsqlite3" ConfigName="WinDebugUnicode"/>
       <Project Name="ZoomNavigator" ConfigName="WinDebugUnicode"/>
+      <Project Name="DebuggerJLink" ConfigName="WinDebugUnicode"/>
     </WorkspaceConfiguration>
     <WorkspaceConfiguration Name="CMake_Release" Selected="yes">
       <Project Name="ZoomNavigator" ConfigName="DebugUnicode"/>
@@ -156,8 +159,9 @@
       <Project Name="CMakePlugin" ConfigName="WinDebugUnicode"/>
       <Project Name="CodeLiteDiff" ConfigName="DebugUnicode"/>
       <Project Name="LLDBDebugger" ConfigName="DebugUnicode"/>
+      <Project Name="DebuggerJLink" ConfigName="WinDebugUnicode"/>
     </WorkspaceConfiguration>
-    <WorkspaceConfiguration Name="CMake_Debug" Selected="no">
+    <WorkspaceConfiguration Name="CMake_Debug" Selected="yes">
       <Project Name="ZoomNavigator" ConfigName="WinReleaseUnicode"/>
       <Project Name="wxsqlite3" ConfigName="WinReleaseUnicode"/>
       <Project Name="wxshapeframework" ConfigName="WinReleaseUnicode"/>
@@ -193,8 +197,9 @@
       <Project Name="CMakePlugin" ConfigName="WinDebugUnicode"/>
       <Project Name="CodeLiteDiff" ConfigName="DebugUnicode"/>
       <Project Name="LLDBDebugger" ConfigName="DebugUnicode"/>
+      <Project Name="DebuggerJLink" ConfigName="WinDebugUnicode"/>
     </WorkspaceConfiguration>
-    <WorkspaceConfiguration Name="OSX_Debug" Selected="no">
+    <WorkspaceConfiguration Name="OSX_Debug" Selected="yes">
       <Project Name="ZoomNavigator" ConfigName="DebugUnicode"/>
       <Project Name="wxsqlite3" ConfigName="WinReleaseUnicode"/>
       <Project Name="wxshapeframework" ConfigName="WinReleaseUnicode"/>
@@ -230,8 +235,9 @@
       <Project Name="CMakePlugin" ConfigName="WinDebugUnicode"/>
       <Project Name="CodeLiteDiff" ConfigName="DebugUnicode"/>
       <Project Name="LLDBDebugger" ConfigName="DebugUnicode"/>
+      <Project Name="DebuggerJLink" ConfigName="WinDebugUnicode"/>
     </WorkspaceConfiguration>
-    <WorkspaceConfiguration Name="OSX_Release" Selected="no">
+    <WorkspaceConfiguration Name="OSX_Release" Selected="yes">
       <Project Name="ZoomNavigator" ConfigName="DebugUnicode"/>
       <Project Name="wxsqlite3" ConfigName="WinReleaseUnicode"/>
       <Project Name="wxshapeframework" ConfigName="WinReleaseUnicode"/>
@@ -267,6 +273,7 @@
       <Project Name="abbreviation" ConfigName="WinDebugUnicode"/>
       <Project Name="CodeLiteDiff" ConfigName="DebugUnicode"/>
       <Project Name="LLDBDebugger" ConfigName="DebugUnicode"/>
+      <Project Name="DebuggerJLink" ConfigName="WinDebugUnicode"/>
     </WorkspaceConfiguration>
   </BuildMatrix>
 </CodeLite_Workspace>
diff --git a/LiteEditor/LiteEditor.project b/LiteEditor/LiteEditor.project
index 9e2d0df..9af4cd2 100644
--- a/LiteEditor/LiteEditor.project
+++ b/LiteEditor/LiteEditor.project
@@ -654,6 +654,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -711,6 +712,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
     <Project Name="Copyright"/>
@@ -728,6 +730,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
     <Project Name="Copyright"/>
@@ -749,6 +752,7 @@
     <Project Name="CodeLite"/>
     <Project Name="plugin_sdk"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
   </Dependencies>
   <VirtualDirectory Name="ClangCodeCompletion">
     <File Name="clang_code_completion.h"/>
@@ -787,6 +791,7 @@
     <Project Name="CodeLite"/>
     <Project Name="plugin_sdk"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="CodeFormatter"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -901,6 +906,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
     <Project Name="Copyright"/>
@@ -913,6 +919,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -926,6 +933,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -939,6 +947,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
     <Project Name="Copyright"/>
@@ -978,6 +987,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -992,6 +1002,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -1006,6 +1017,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -1020,6 +1032,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -1034,6 +1047,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -1048,6 +1062,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -1062,6 +1077,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Subversion"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
@@ -1078,6 +1094,7 @@
     <Project Name="plugin_sdk"/>
     <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
     <Project Name="Copyright"/>
@@ -1102,7 +1119,7 @@
     <Project Name="CodeLiteDiff"/>
     <Project Name="LLDBDebugger"/>
   </Dependencies>
-  <Dependencies Name="WinReleaseUnicode">
+  <Dependencies Name="WinDebugUnicode">
     <Project Name="PCH"/>
     <Project Name="sqlite3"/>
     <Project Name="wxsqlite3"/>
@@ -1110,8 +1127,9 @@
     <Project Name="wxshapeframework"/>
     <Project Name="CodeLite"/>
     <Project Name="plugin_sdk"/>
-    <Project Name="DebuggerGDB"/>
     <Project Name="CodeFormatter"/>
+    <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
     <Project Name="Copyright"/>
@@ -1129,13 +1147,14 @@
     <Project Name="DatabaseExplorer"/>
     <Project Name="CallGraph"/>
     <Project Name="ZoomNavigator"/>
+    <Project Name="CodeBeautifier"/>
     <Project Name="SFTP"/>
     <Project Name="Tweaks"/>
     <Project Name="CMakePlugin"/>
     <Project Name="CodeLiteDiff"/>
     <Project Name="LLDBDebugger"/>
   </Dependencies>
-  <Dependencies Name="WinDebugUnicode">
+  <Dependencies Name="WinReleaseUnicode">
     <Project Name="PCH"/>
     <Project Name="sqlite3"/>
     <Project Name="wxsqlite3"/>
@@ -1143,8 +1162,9 @@
     <Project Name="wxshapeframework"/>
     <Project Name="CodeLite"/>
     <Project Name="plugin_sdk"/>
-    <Project Name="CodeFormatter"/>
     <Project Name="DebuggerGDB"/>
+    <Project Name="DebuggerJLink"/>
+    <Project Name="CodeFormatter"/>
     <Project Name="Gizmos"/>
     <Project Name="Cscope"/>
     <Project Name="Copyright"/>
@@ -1162,7 +1182,6 @@
     <Project Name="DatabaseExplorer"/>
     <Project Name="CallGraph"/>
     <Project Name="ZoomNavigator"/>
-    <Project Name="CodeBeautifier"/>
     <Project Name="SFTP"/>
     <Project Name="Tweaks"/>
     <Project Name="CMakePlugin"/>
@@ -1587,8 +1606,7 @@ resources.cpp: resources.xrc
         <CustomPostBuild/>
         <CustomPreBuild>resources.cpp
 resources.cpp: resources.xrc
-	wxrc /c /v /o resources.cpp resources.xrc
-</CustomPreBuild>
+	wxrc /c /v /o resources.cpp resources.xrc</CustomPreBuild>
       </AdditionalRules>
       <Completion EnableCpp11="yes">
         <ClangCmpFlagsC/>
@@ -1620,7 +1638,7 @@ resources.cpp: resources.xrc
       </Linker>
       <ResourceCompiler Options="$(shell wx-config --rcflags)" Required="yes"/>
       <General OutputFile="$(IntermediateDirectory)/codelite.exe" IntermediateDirectory="./Release" Command=".\codelite.exe" CommandArguments="-b ." UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="../Runtime" PauseExecWhenProcTerminates="no" IsGUIProgram="yes" IsEnabled="yes"/>
-      <Environment EnvVarSetName="Default" DbgSetName="Default">
+      <Environment EnvVarSetName="Default" DbgSetName="">
         <![CDATA[PATH=../sdk/clang/lib;$(WXWIN)\lib\gcc_dll;$(PATH)]]>
       </Environment>
       <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="">
@@ -1646,7 +1664,8 @@ resources.cpp: resources.xrc
         <CustomPostBuild/>
         <CustomPreBuild>resources.cpp
 resources.cpp: resources.xrc
-	wxrc /c /v /o resources.cpp resources.xrc</CustomPreBuild>
+	wxrc /c /v /o resources.cpp resources.xrc
+</CustomPreBuild>
       </AdditionalRules>
       <Completion EnableCpp11="yes">
         <ClangCmpFlagsC/>
diff --git a/codelite_utils/codelite_utils.workspace b/codelite_utils/codelite_utils.workspace
index 8889d82..3e12736 100644
--- a/codelite_utils/codelite_utils.workspace
+++ b/codelite_utils/codelite_utils.workspace
@@ -2,7 +2,6 @@
 <CodeLite_Workspace Name="codelite_utils" Database="./codelite_utils.tags">
   <Project Name="build_all" Path="build_all.project" Active="Yes"/>
   <Project Name="codelite_launcher" Path="../codelite_launcher/codelite_launcher.project" Active="No"/>
-  <Project Name="autorev" Path="../AutoRevision/autorev/autorev.project" Active="No"/>
   <Project Name="makedir" Path="../TestDir/makedir.project" Active="No"/>
   <Project Name="le_exec" Path="../le_exec/le_exec.project" Active="No"/>
   <Project Name="codelite_cppcheck" Path="../sdk/codelite_cppcheck/codelite_cppcheck.project" Active="No"/>
diff --git a/cppchecker/CppChecker.project b/cppchecker/CppChecker.project
index f100051..ae14f22 100644
--- a/cppchecker/CppChecker.project
+++ b/cppchecker/CppChecker.project
@@ -11,6 +11,7 @@
     <File Name="cppchecksettingsdlg.h"/>
     <File Name="cppchecksettingsdlgbase.cpp"/>
     <File Name="cppchecksettingsdlgbase.h"/>
+    <File Name="cppchecksettingsdlg_cppchecker_bitmaps.cpp"/>
   </VirtualDirectory>
   <VirtualDirectory Name="include">
     <File Name="cppchecker.h"/>

Re: ARM Debugging (and most likely other remote debugging)

Posted: Mon Jun 02, 2014 3:54 am
by Gibbon1
I have little to add except I'm also doing ARM development using codelite. I've never really got the debugger working on it.

Better remote debugging would be very nice to have, especially as the cancer :evil: that is Eclipse is totally invading the embedded world.

Re: ARM Debugging (and most likely other remote debugging)

Posted: Mon Jun 02, 2014 9:55 am
by eranif
If I could only try a simple hello world debugging - I am sure I could improve it ;)
Anyone knows a good tutorial for real newbies in the embedded world?

Eran

Re: ARM Debugging (and most likely other remote debugging)

Posted: Tue Jun 03, 2014 4:32 am
by Gibbon1
Would it help if you had a 'rig' to debug with?

I could get you a Freescale Kinetis KL25 Dev board, a P&E Micro Multilink and a bare metal codelite project that works.

Re: ARM Debugging (and most likely other remote debugging)

Posted: Tue Jun 03, 2014 1:30 pm
by tlang
eranif wrote:If I could only try a simple hello world debugging - I am sure I could improve it ;)
Anyone knows a good tutorial for real newbies in the embedded world?

Eran
Hi Eran,
at least the problem of stepping out of a function leading to a crash seems to be related to SEGGER's V4.80a debug server. Older versions and the current version do not show this effect.

So IMHO what remains to be solved is the problem that the local and remote debugger get out of sync after some steps.

The major problem with remote debugging is that that there is no child process you can use the DebugBreak on and on the other hand I didn't find a reliable way yet to send a SIGINT to the local gdb instance (it's only documented for applications having a console). Which is why I switched to asynchronous mode. Normally, when you debug locally, you don't use the async mode, so the mi parser is blocked as long as the debuggee process doesn't release control (which you do by the DebugBreak call in the kernel). With async mode you're able to send further commands which may be acknowledged with an error message if they require a stopped target/debuggee.

I believe the remaining problem with the out-of-sync debugger has nothing to do with the SEGGER debug server or embedded project, so perhaps you can try out a remote debugging of a simple "hello world" on a Windows or Linux system to check out.

I currently can no longer spend time for investigation as I now have another project on my desk but I hope I can return and investigate further in near future.

For the time being I have found another wxWidgets based IDE (emIDE) which looks not so "polished" and modern as CodeLite but is specialized on embedded projects and even brings along a J-Link plugin. Unfortunetaly the sources of the J-Link plugin have not been released (at least as far as I can see) so there's no chance to throw a glance at their implementation.

Regards,
Torsten

Re: ARM Debugging (and most likely other remote debugging)

Posted: Wed Jun 11, 2014 2:27 pm
by tlang
Hi Eran,
I just had some time to look again into the problems. At least I got the Windows version working in synchronous mode with the following changes to your repository version a74943cb1c38343378f04171c416c932e69beb98 as of 2014-05-26, 15:55:51. Please note that there's some dead code from my experiments, the Un*x version will be broken with this code as I did not change the interrupt generation as needed for sync mode (I assume it could be sufficient to send a SIGINT to the gdb process).

At least now debugging is quite stable (stepping, continuing, interrupting work, but the IDE doesn't jump to the current code line after a click on the pause button).

Perhaps someone can try out remote debugging from Windows to Windows or Windows to Linux to check if my code also works with other than embedded projects, if yes the Un*x code still needs to be adapted...

Regards,
Torsten