Как вы можете узнать, кто создает все ваши потоки в программе delphi?
Если у вас есть чистый набор кода Delphi, и все потоки создаются с помощью TThread, вы можете установить точку останова в методе (- ах) конструктора (TThread.Create) и узнайте, кто создал ваши потоки. Вы даже можете попытаться назвать все свои потоки, используя функцию, встроенную в объект Delphi TThread, которая позволяет установить имя отладки для каждого потока.
но как вы определяете постоянные, труднодоступные дополнительные потоки, которые все еще анонимны (без имени отладки) и которые появляются, скажем, во время инициализации модуля, когда приложение запускается. Я могу сделать один шаг через инициализацию модуля, но я не могу определить все исходные модули (скажем, 900+ разделов инициализации модуля, которые сделаны), которые, вероятно, создадут потоки, и я не понял, как добавить отладочное сообщение (используя свойства точки останова и сообщения), которое будет сбрасывать каждое имя блока во время его инициализации. Творческое использование точек останова, установленных в системе.pas, с журналированием-сообщения позволяют мне нужно делать некоторые вещи при отладке тривиально простых приложений, но чем сложнее мое приложение растет, тем больше я чувствую себя слепым по потокам, как созданным в середине запуска приложения, так и созданным во время ввода модуля (то есть до того, как вы шагнете в первую строку кода в своем проекте dpr).
Я хотел бы знать, какие передовые методы вы могли бы найти, чтобы определить и выяснить, кто создал конкретный поток. Если бы мы использовали как отладчик GDB вместо отладчика, как ядра отладчика Дельфи (Турбо отладчик?), который встроен в Delphi IDE, я думаю, мы могли бы установить точку останова на функции Windows api, такой как BeginThread. Но я не думаю, что смогу сделать это в Дельфах.
Update: я не знал, что вы можете установить точку останова в разделе реализации windows.pas для внешних библиотек Windows, таких как kernel32.файл DLL.
Update 2: кажется, что ответ Дэвида H-лучшая идея для general использовать. Я также просматриваю небольшую вспомогательную библиотеку кода, которую я пишу прямо сейчас, которая поддерживает словарь идентификаторов потоков, которые были замечены раньше, и которая назначает некоторые имена отладки в противном случае неназванным потокам, основываясь на их времени создания (какую функцию мы вызывали непосредственно перед тем, как мы заметили, что новый поток существует). Я думаю, что это поможет мне сузить мои 40 + нумерованные потоки, чтобы они все были названы, хотя некоторые из них созданы во внешних библиотеках C/C++ или COM процессы.
3 ответов
Я, вероятно, буду использовать такие инструменты, как Процесс Explorer и madExcept, но есть много инструментов, которые могут быть полезны.
Я не верю, что Delphi использует Turbo Debugger. Более того, Delphi отлично способен устанавливать точки останова на точках входа kernel32, таких как CreateThread.
Я бы запустил с включенным DCUs отладки и установил точку останова на реализации CreateThread в Windows.первенство. Как только вы сломаете там переключатель к окну CPU и шаг в рутину. Вы увидите JMP DWORD PTR [address]
инструкция. Перешагните через это и Эй presto, теперь вы отлаживаете в kernel32. Здесь вы можете установить точку останова.
теперь, если вы сбросите приложение и снова начнете отладку, вы нарушите все вызовы kernel32.CreateThread, которые происходят из вашего процесса. Проверка стека вызовов расскажет вам, как вы туда попали. Это выглядит примерно так:
наконец, я не уверен, почему вас беспокоит ваше приложение, создающее потоки. Большинство приложений приличного размера создают много потоков – это совершенно нормально. С какими проблемами вы сталкиваетесь?
... Я думаю, мы могли бы установить точку останова на функции Windows api, как BeginThread себя. Но я не думаю, что смогу сделать это в Дельфах.
конечно, вы можете.
включить проект, параметры, компилятор Delphi, компиляцию, отладку, использовать debug .каждом из модулей DCU. (Это способ найти его в Delphi XE, точное местоположение может отличаться в разных версиях Delphi).
перекомпиляции.
открыть Системный блок и поставить точку останова на результат: = CreateThread ... в функции BeginThread.
запустите программу и дождитесь срабатывания точки останова.
открыть окно процессора (просмотр, отладка окон, Окна процессора, весь процессор).
окно CPU отобразит что-то вроде этого:
System.pas.16559: Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P,
00406A97 8B4508 mov eax,[ebp+]
00406A9A 50 push eax
00406A9B 8B450C mov eax,[ebp+c]
00406A9E 50 push eax
00406A9F 53 push ebx
00406AA0 B81C6A4000 mov eax,406a1c
00406AA5 50 push eax
00406AA6 8B45F8 mov eax,[ebp-]
00406AA9 50 push eax
00406AAA 8B45FC mov eax,[ebp-]
00406AAD 50 push eax
00406AAE E855BBFFFF call CreateThread
00406AB3 8BF0 mov esi,eax
Нажмите в окно CPU на линии ' вызов Функции createthread'.
Нажмите Клавишу F4.
Нажмите Клавишу F7.
вы будете расположены в таблице отправки:
CreateThread:
00402608 FF2594AA4F00 jmp dword ptr [4faa94]
0040260E 8BC0 mov eax,eax
нажмите F5, чтобы поставить точку останова здесь.
повторно запустите программу (Ctrl-F2, F9).
точка останова будет срабатывать каждый раз при создании потока. Точка останова появится в WindowsAPIs.ИНК at
function CreateThread(SecurityAttributes: Pointer; StackSize: LongWord;
ThreadFunc: TThreadFunc; Parameter: Pointer;
CreationFlags: LongWord; var ThreadId: LongWord): Integer; stdcall;
external kernel name 'CreateThread';
(по крайней мере, в Delphi XE).
вы мая все еще пропускают некоторые вызовы создания потока. Я не знаю, будет ли этот метод ловить потоки, созданные внутри Direct X, например.
фактически BeginThread является функцией в системе.pas, хотя и "частный" (нет объявления функции в разделе интерфейса). Таким образом, используя debug dcu, вы можете просто установить точку останова в функции BeginThread и изучить трассировку стека оттуда.
другой вариант-подключить функцию BeginThread с помощью madCodeHook или KBSM (IIRC). Внутри функции закрепления вы можете использовать что-то вроде:
UseOurStuff := Assigned(Parameter) and IsInstanceOfType(Parameter, TThread);
if Assigned(Parameter) then
if UseOurStuff then
ThreadClassName := Instance.ClassName
else
ThreadClassName := 'Non-object Parameter thread'
else
ThreadClassName := 'NIL Parameter thread';
таким образом, вы можете регистрировать все создаваемые потоки, независимо откуда они приходят. Единственные, которые вам не хватает, - это потоки, созданные путем прямого вызова Windows API CreateThread. Но вы можете использовать те же методы подключения, чтобы получить ваши руки на этих вызовах.
обновление
Oh, IsInstanceOfType-одна из наших библиотечных функций, но она в основном принимает нетипизированный указатель и проверяет, ссылается ли он на объект данного класса.