浏览代码

Requesting callstack dump of another process

Source commit: fd5a5ab2c64742e6dc083da0ddc5fb2066552b5b
Martin Prikryl 7 年之前
父节点
当前提交
0d5cf994a7
共有 4 个文件被更改,包括 75 次插入10 次删除
  1. 50 0
      source/windows/ConsoleRunner.cpp
  2. 14 9
      source/windows/WinInterface.cpp
  3. 7 1
      source/windows/WinInterface.h
  4. 4 0
      source/windows/WinMain.cpp

+ 50 - 0
source/windows/ConsoleRunner.cpp

@@ -2579,6 +2579,52 @@ int __fastcall FingerprintScan(TConsole * Console, TProgramParams * Params)
   return Result;
 }
 //---------------------------------------------------------------------------
+int __fastcall DumpCallstack(TConsole * Console, TProgramParams * Params)
+{
+  int Result = RESULT_SUCCESS;
+  try
+  {
+    int ProcessId = StrToInt(Params->SwitchValue(DUMPCALLSTACK_SWITCH));
+    UnicodeString EventName = DumpCallstackEventName(ProcessId);
+    UnicodeString FileName = DumpCallstackFileName(ProcessId);
+    if (FileExists(FileName))
+    {
+      DeleteFileChecked(FileName);
+    }
+
+    HANDLE Event = OpenEvent(EVENT_ALL_ACCESS, false, EventName.c_str());
+    if (Event == NULL)
+    {
+      throw ExtException(FORMAT(L"Error communicating with process %d.", (ProcessId)), LastSysErrorMessage());
+    }
+
+    SetEvent(Event);
+    CloseHandle(Event);
+
+    ConsolePrintLine(Console, FORMAT(L"Requested callstack dump for process %d...", (ProcessId)));
+
+    int Timeout = 10;
+    while (!FileExists(FileName))
+    {
+      Sleep(1000);
+      Timeout--;
+      if (Timeout == 0)
+      {
+        throw Exception(L"Timeout");
+      }
+    }
+
+    ConsolePrintLine(Console, FORMAT(L"Callstack dumped to file \"%s\".", (FileName)));
+  }
+  catch (Exception & E)
+  {
+    Result = HandleException(Console, E);
+  }
+
+  Console->WaitBeforeExit();
+  return Result;
+}
+//---------------------------------------------------------------------------
 int __fastcall Console(TConsoleMode Mode)
 {
   DebugAssert(Mode != cmNone);
@@ -2639,6 +2685,10 @@ int __fastcall Console(TConsoleMode Mode)
         Result = FingerprintScan(Console, Params);
       }
     }
+    else if (Mode == cmDumpCallstack)
+    {
+      Result = DumpCallstack(Console, Params);
+    }
     else
     {
       Runner = new TConsoleRunner(Console);

+ 14 - 9
source/windows/WinInterface.cpp

@@ -1461,6 +1461,18 @@ void __fastcall ClickToolbarItem(TTBCustomItem * Item, bool PositionCursor)
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
+UnicodeString DumpCallstackEventName(int ProcessId)
+{
+  return FORMAT(DUMPCALLSTACK_EVENT, (ProcessId));
+}
+//---------------------------------------------------------------------------
+UnicodeString DumpCallstackFileName(int ProcessId)
+{
+  UnicodeString FileName = FORMAT(L"%s.txt", (DumpCallstackEventName(ProcessId)));
+  UnicodeString Result = TPath::Combine(SystemTemporaryDirectory(), FileName);
+  return Result;
+}
+//---------------------------------------------------------------------------
 class TCallstackThread : public TSignalThread
 {
 public:
@@ -1470,7 +1482,6 @@ protected:
   virtual void __fastcall ProcessEvent();
 
 private:
-  static UnicodeString DoGetName();
   static HANDLE DoCreateEvent();
 };
 //---------------------------------------------------------------------------
@@ -1483,8 +1494,7 @@ void __fastcall TCallstackThread::ProcessEvent()
 {
   try
   {
-    UnicodeString FileName = FORMAT(L"%s.txt", (DoGetName()));
-    UnicodeString Path = TPath::Combine(SystemTemporaryDirectory(), FileName);
+    UnicodeString Path = DumpCallstackFileName(GetCurrentProcessId());
     std::unique_ptr<TStrings> StackStrings;
     HANDLE MainThreadHandle = reinterpret_cast<HANDLE>(MainThreadID);
     if (SuspendThread(MainThreadHandle) < 0)
@@ -1514,14 +1524,9 @@ void __fastcall TCallstackThread::ProcessEvent()
   }
 }
 //---------------------------------------------------------------------------
-UnicodeString TCallstackThread::DoGetName()
-{
-  return FORMAT("WinSCPCallstack%d", (GetCurrentProcessId()));
-}
-//---------------------------------------------------------------------------
 HANDLE TCallstackThread::DoCreateEvent()
 {
-  UnicodeString Name = DoGetName();
+  UnicodeString Name = DumpCallstackEventName(GetCurrentProcessId());
   return CreateEvent(NULL, false, false, Name.c_str());
 }
 //---------------------------------------------------------------------------

+ 7 - 1
source/windows/WinInterface.h

@@ -42,6 +42,9 @@ const int mpAllowContinueOnError = 0x02;
 #define INI_SWITCH L"Ini"
 #define RAW_CONFIG_SWITCH L"RawConfig"
 #define FINGERPRINTSCAN_SWITCH L"FingerprintScan"
+#define DUMPCALLSTACK_SWITCH L"DumpCallstack"
+
+#define DUMPCALLSTACK_EVENT L"WinSCPCallstack%d"
 
 struct TMessageParams
 {
@@ -401,7 +404,7 @@ extern const UnicodeString YesButtonName;
 extern const UnicodeString OKButtonName;
 
 // windows\Console.cpp
-enum TConsoleMode { cmNone, cmScripting, cmHelp, cmBatchSettings, cmKeyGen, cmFingerprintScan };
+enum TConsoleMode { cmNone, cmScripting, cmHelp, cmBatchSettings, cmKeyGen, cmFingerprintScan, cmDumpCallstack };
 int __fastcall Console(TConsoleMode Mode);
 
 // forms\EditorPreferences.cpp
@@ -493,6 +496,9 @@ TShortCut __fastcall GetShortCutCombo(TComboBox * ComboBox);
 bool __fastcall IsCustomShortCut(TShortCut ShortCut);
 TShortCut __fastcall NormalizeCustomShortCut(TShortCut ShortCut);
 
+UnicodeString DumpCallstackEventName(int ProcessId);
+UnicodeString DumpCallstackFileName(int ProcessId);
+
 #ifdef _DEBUG
 void __fastcall ForceTracing();
 #endif

+ 4 - 0
source/windows/WinMain.cpp

@@ -783,6 +783,10 @@ int __fastcall Execute()
   {
     Mode = cmFingerprintScan;
   }
+  else if (Params->FindSwitch(DUMPCALLSTACK_SWITCH))
+  {
+    Mode = cmDumpCallstack;
+  }
   // We have to check for /console only after the other options,
   // as the /console is always used when we are run by winscp.com
   // (ambiguous use to pass console version)