Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 JCL Debug expert - диагностика ошибок в программе  [new]
m52
Member

Откуда:
Сообщений: 721
Здравствуйте,

Я использую DelphiXE7 update1 и хочу у себя в программе сделать диагностику ошибок средствами JEDI.
Цель: узнать, в каком модуле программы и в какой строке произошла ошибка.
Программа должна отлавливать все необработанные исключения.

Взял за основу блог Александра
http://www.gunsmoker.ru/2010/04/exception-delphi-2009.html
создал проект, включил опции в меню "Project -> JCL Debug expert" (все 3 пункта установил в "Always enabled").
Cкопировал текст программы из блога и запустил.

При нажатии на Button1 и выполнении команды
PInteger(nil)^ := 0;
возникло исключение, отловилось , стек отобразился.
Вижу название модуля unit1 и номер строки, в которой произошла ошибка - 61.

Сделал, чтобы исключение возникло на
StrToInt('a');
, но теперь в стеке не видно название моего модуля unit1 и номера строки.
Видно только непосредственное место ошибки
System.SysUtils.ConvertErrorFmt (Line 5475, "System.SysUtils.pas" + 2) + $0
а мне нужно, чтобы предыдущее место вызова тоже было видно, чтобы стало понятно, что вызов начинался с Button1Click.

Т.е. мне нужно увидеть несколько предыдущих шагов, чтобы понять, что привело к ошибке (из какого места моей программы)
Возможно ли расширить стек вызовов, чтобы увидеть несколько предыдущих шагов?
Или стек начинает формироваться уже после создания исключения, а вызовов перед этим, которые привели к ошибке, не видно?

Мой примерчик во вложении.

Заранее благодарен, Михаил.

К сообщению приложен файл (Tracer.zip - 57Kb) cкачать
1 мар 15, 12:28    [17327617]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
GunSmoker
Member

Откуда:
Сообщений: 3110
http://www.gunsmoker.ru/2015/02/stack-frames.html
1 мар 15, 13:44    [17327874]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
GunSmoker
Member

Откуда:
Сообщений: 3110
Кратко: добавьте stRawMode в JclStackTrackingOptions.
1 мар 15, 13:51    [17327888]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
m52
Member

Откуда:
Сообщений: 721
Александр,

Я добавил эту опцию к JclStackTrackingOptions, результат тот же.

initialization
  // инициализация механизма перехвата исключений
  Include(JclStackTrackingOptions, stRawMode); // стало [stTrack, stRawMode]

  Exception.GetExceptionStackInfoProc := GetExceptionStackInfoJCL;
  Exception.GetStackInfoStringProc := GetStackInfoStringJCL;
  Exception.CleanUpStackInfoProc := CleanUpStackInfoJCL;


Что еще можно попробовать сделать?
1 мар 15, 17:47    [17328566]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
rgreat
Member

Откуда:
Сообщений: 5379
MadExcept имхо лучше.
1 мар 15, 17:53    [17328581]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11193
rgreat
MadExcept имхо лучше.
Только он немного платный
1 мар 15, 17:58    [17328594]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
rgreat
Member

Откуда:
Сообщений: 5379
Фриваре версия полнофункциональна.
1 мар 15, 18:41    [17328729]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
rgreat
Member

Откуда:
Сообщений: 5379
Да и коммерческая лицензия стоит относительно недорого.
1 мар 15, 18:42    [17328734]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
m52
Member

Откуда:
Сообщений: 721
Спасибо, друзья за совет по поводу MadExcept, но я сначала хотел бы настроить диагностику ошибок, используя JEDI.
Если с JEDI не получится, то возможно рассмотрю MadExcept. Дело в том, что пакет JEDI мне нравится и я его вовсю использую.
1 мар 15, 19:22    [17328842]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
GunSmoker
Member

Откуда:
Сообщений: 3110
m52
Я добавил эту опцию к JclStackTrackingOptions, результат тот же.

Что еще можно попробовать сделать?


Извиняюсь, я думал вы JclHookExcept используете.

Для моего кода достаточно заменить False на True в первом параметре JclCreateStackList:

Было:
  if P^.ExceptionCode = cDelphiException then
    Stack := JclCreateStackList(False, 3, P^.ExceptAddr)
  else
    Stack := JclCreateStackList(False, 3, P^.ExceptionAddress);


Стало:
  if P^.ExceptionCode = cDelphiException then
    Stack := JclCreateStackList(True, 3, P^.ExceptAddr)
  else
    Stack := JclCreateStackList(True, 3, P^.ExceptionAddress);
2 мар 15, 10:03    [17330215]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
GunSmoker
Member

Откуда:
Сообщений: 3110
Примечание: в madExcept трассировка стека - лучше, чем в JCL. JCL покажет больше записей в стеке, а madExcept отфильтрует ложно-положительные. В madExcept есть простая виртуальная машина, которая пытается "выполнять" код, чтобы отслеживать перемещение данных по регистрам и стеку - таким образом madExcept узнаёт "невозможные" адреса возврата, которые не могли получиться в результате выполнения машинного кода до адреса, на который указывает адрес возврата.
2 мар 15, 10:11    [17330257]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
m52
Member

Откуда:
Сообщений: 721
Спасибо, Александр!

Вы мне очень помогли. Приятно общаться с людьми, которые хорошо разбираются в теме диагностики ошибок :)

Теперь вижу весь стек (58 строк), в том числе и строку, откуда начала происходить ошибка.
Конечно, тут бы еще фильтронуть - показать только те строки, которые относятся к модулям моего проекта.
Но среди 58 строк я свои модули и так найду, глазами. Не критично.

Похоже, MadExpert - продвинутая, но на данном этапе мне пожалуй достаточно JEDI.
Если все же понадобится MadExpert, то поизучаю позже.

Еще раз большое человеческое спасибо!
2 мар 15, 12:41    [17331111]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
GunSmoker
Member

Откуда:
Сообщений: 3110
Достаточно простой фильтр можно сделать основываясь на том факте, что для RTL/VCL модулей нет данных о номерах строках.

Например (измените имя модуля на ваше):
var
  ...
  I: Integer;
  Location: TJclLocationInfo;
begin
  ...
    try
      for I := Stack.Count - 1 downto 0 do
      begin
        Location := GetLocationInfo(Stack[I].CallerAddr);

        if (
             (Location.LineNumber = 0) and
             (Location.OffsetFromLineNumber = 0)
           ) or
           (Location.ProcedureName = 'GetExceptionStackInfoJCL') or
           (Location.ProcedureName = 'Unit1.GetExceptionStackInfoJCL') then
          Stack.Delete(I);
      end;

      Stack.AddToStrings(Str, True, True, True, True);
      ...


Этот пример предполагает, что опция "Use Debug DCUs" выключена.

Но я не рекомендовал бы так делать. Лучше иметь максимум информации. Ну или хотя бы два варианта - полный и краткий.
2 мар 15, 15:07    [17332095]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
m52
Member

Откуда:
Сообщений: 721
Александр, у меня вот такой полный стек вызовов (см.ниже).
Номера строк везде есть. Видимо, фильтровать надо как-то по-другому.

автор
Access violation at address 0061A560 in module 'Project1.exe'. Write of address 00000000.

(00219560){Project1.exe} [0061A560] Unit1.TForm1.Button1Click (Line 64, "Unit1.pas" + 2) + $4
(00027DF0){Project1.exe} [00428DF0] System.SysUtils.Exception.RaisingException (Line 21755, "System.SysUtils.pas" + 3) + $2
(000283E5){Project1.exe} [004293E5] System.SysUtils.GetExceptionObject (Line 22065, "System.SysUtils.pas" + 10) + $7
(0000768B){Project1.exe} [0040868B] System.@HandleAnyException (Line 18652, "System.pas" + 13) + $0
(00006952){Project1.exe} [00407952] System.@IsClass (Line 16131, "System.pas" + 1) + $8
(001244CB){Project1.exe} [005254CB] Vcl.Controls.TControl.Click (Line 7348, "Vcl.Controls.pas" + 9) + $8
(0013CE62){Project1.exe} [0053DE62] Vcl.StdCtrls.TCustomButton.Click (Line 5326, "Vcl.StdCtrls.pas" + 3) + $2
(00219589){Project1.exe} [0061A589] Unit1.TForm1.Button2Click (Line 70, "Unit1.pas" + 2) + $D
(001244CB){Project1.exe} [005254CB] Vcl.Controls.TControl.Click (Line 7348, "Vcl.Controls.pas" + 9) + $8
(0013CE62){Project1.exe} [0053DE62] Vcl.StdCtrls.TCustomButton.Click (Line 5326, "Vcl.StdCtrls.pas" + 3) + $2
(0013D970){Project1.exe} [0053E970] Vcl.StdCtrls.TCustomButton.CNCommand (Line 5787, "Vcl.StdCtrls.pas" + 1) + $D
(00123F5D){Project1.exe} [00524F5D] Vcl.Controls.TControl.WndProc (Line 7232, "Vcl.Controls.pas" + 91) + $6
(00128A2A){Project1.exe} [00529A2A] Vcl.Controls.TWinControl.WndProc (Line 10038, "Vcl.Controls.pas" + 153) + $6
(0013CB0C){Project1.exe} [0053DB0C] Vcl.StdCtrls.TButtonControl.WndProc (Line 5163, "Vcl.StdCtrls.pas" + 13) + $4
(00123B98){Project1.exe} [00524B98] Vcl.Controls.TControl.Perform (Line 7010, "Vcl.Controls.pas" + 10) + $8
(00128B8F){Project1.exe} [00529B8F] Vcl.Controls.DoControlMsg (Line 10107, "Vcl.Controls.pas" + 12) + $11
(00129617){Project1.exe} [0052A617] Vcl.Controls.TWinControl.WMCommand (Line 10382, "Vcl.Controls.pas" + 1) + $5
(001D145D){Project1.exe} [005D245D] Vcl.Forms.TCustomForm.WMCommand (Line 6204, "Vcl.Forms.pas" + 6) + $4
(00123F5D){Project1.exe} [00524F5D] Vcl.Controls.TControl.WndProc (Line 7232, "Vcl.Controls.pas" + 91) + $6
(00128A2A){Project1.exe} [00529A2A] Vcl.Controls.TWinControl.WndProc (Line 10038, "Vcl.Controls.pas" + 153) + $6
(0000745C){Project1.exe} [0040845C] System.TMonitor.TryEnter (Line 17596, "System.pas" + 10) + $0
(00007060){Project1.exe} [00408060] System.TMonitor.Enter (Line 17289, "System.pas" + 4) + $2
(00128A2A){Project1.exe} [00529A2A] Vcl.Controls.TWinControl.WndProc (Line 10038, "Vcl.Controls.pas" + 153) + $6
(000071EE){Project1.exe} [004081EE] System.TMonitor.Exit (Line 17393, "System.pas" + 1) + $2
(0000723F){Project1.exe} [0040823F] System.TMonitor.Exit (Line 17415, "System.pas" + 2) + $7
(0010917F){Project1.exe} [0050A17F] Vcl.Graphics.FreeMemoryContexts (Line 7051, "Vcl.Graphics.pas" + 12) + $8
(00128064){Project1.exe} [00529064] Vcl.Controls.TWinControl.MainWndProc (Line 9750, "Vcl.Controls.pas" + 3) + $6
(00128079){Project1.exe} [00529079] Vcl.Controls.TWinControl.MainWndProc (Line 9753, "Vcl.Controls.pas" + 6) + $0
(001CE2B0){Project1.exe} [005CF2B0] Vcl.Forms.TCustomForm.WndProc (Line 4427, "Vcl.Forms.pas" + 206) + $5
(000C584C){Project1.exe} [004C684C] System.Classes.StdWndProc (Line 16600, "System.Classes.pas" + 8) + $0
(00128064){Project1.exe} [00529064] Vcl.Controls.TWinControl.MainWndProc (Line 9750, "Vcl.Controls.pas" + 3) + $6
(000C584C){Project1.exe} [004C684C] System.Classes.StdWndProc (Line 16600, "System.Classes.pas" + 8) + $0
(00128B3A){Project1.exe} [00529B3A] Vcl.Controls.TWinControl.DefaultHandler (Line 10079, "Vcl.Controls.pas" + 30) + $19
(00124920){Project1.exe} [00525920] Vcl.Controls.TControl.WMLButtonUp (Line 7481, "Vcl.Controls.pas" + 1) + $6
(00123F5D){Project1.exe} [00524F5D] Vcl.Controls.TControl.WndProc (Line 7232, "Vcl.Controls.pas" + 91) + $6
(00128654){Project1.exe} [00529654] Vcl.Controls.TWinControl.WndProc (Line 9918, "Vcl.Controls.pas" + 33) + $6
(0000745C){Project1.exe} [0040845C] System.TMonitor.TryEnter (Line 17596, "System.pas" + 10) + $0
(00007060){Project1.exe} [00408060] System.TMonitor.Enter (Line 17289, "System.pas" + 4) + $2
(00006F00){Project1.exe} [00407F00] System.TMonitor.CheckOwningThread (Line 17207, "System.pas" + 2) + $0
(000071EE){Project1.exe} [004081EE] System.TMonitor.Exit (Line 17393, "System.pas" + 1) + $2
(0000723F){Project1.exe} [0040823F] System.TMonitor.Exit (Line 17415, "System.pas" + 2) + $7
(0010917F){Project1.exe} [0050A17F] Vcl.Graphics.FreeMemoryContexts (Line 7051, "Vcl.Graphics.pas" + 12) + $8
(00128064){Project1.exe} [00529064] Vcl.Controls.TWinControl.MainWndProc (Line 9750, "Vcl.Controls.pas" + 3) + $6
(00128079){Project1.exe} [00529079] Vcl.Controls.TWinControl.MainWndProc (Line 9753, "Vcl.Controls.pas" + 6) + $0
(00128253){Project1.exe} [00529253] Vcl.Controls.TWinControl.IsControlMouseMsg (Line 9806, "Vcl.Controls.pas" + 1) + $9
(000C584C){Project1.exe} [004C684C] System.Classes.StdWndProc (Line 16600, "System.Classes.pas" + 8) + $0
(00128A2A){Project1.exe} [00529A2A] Vcl.Controls.TWinControl.WndProc (Line 10038, "Vcl.Controls.pas" + 153) + $6
(0013CB0C){Project1.exe} [0053DB0C] Vcl.StdCtrls.TButtonControl.WndProc (Line 5163, "Vcl.StdCtrls.pas" + 13) + $4
(00128064){Project1.exe} [00529064] Vcl.Controls.TWinControl.MainWndProc (Line 9750, "Vcl.Controls.pas" + 3) + $6
(000C584C){Project1.exe} [004C684C] System.Classes.StdWndProc (Line 16600, "System.Classes.pas" + 8) + $0
(001D7773){Project1.exe} [005D8773] Vcl.Forms.TApplication.ProcessMessage (Line 10352, "Vcl.Forms.pas" + 23) + $1
(001D77B6){Project1.exe} [005D87B6] Vcl.Forms.TApplication.HandleMessage (Line 10382, "Vcl.Forms.pas" + 1) + $4
(001D7AE9){Project1.exe} [005D8AE9] Vcl.Forms.TApplication.Run (Line 10520, "Vcl.Forms.pas" + 26) + $3
(00222945){Project1.exe} [00623945] Project1.Project1 (Line 14, "" + 4) + $7

Я бы вообще не стал фильтровать стек, оставив все строки, но меня интересует вопрос: Этот стек формируется с самого начала работы программы? Если программа будет работать несколько часов, выполняя множество действия, то размер стека будет исчисляться мегабайтами?

Если это действительно так, то текст будет сотнями страниц.
2 мар 15, 17:58    [17333545]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
white_nigger
Member

Откуда: Тула
Сообщений: 2201
m52
Если программа будет работать несколько часов, выполняя множество действия, то размер стека будет исчисляться мегабайтами?
С какого перепуга? Только текущая вложенность вызовов
2 мар 15, 18:03    [17333579]     Ответить | Цитировать Сообщить модератору
 Re: JCL Debug expert - диагностика ошибок в программе  [new]
m52
Member

Откуда:
Сообщений: 721
А, ну вообщем-то да. Стек ведь очистится при возврате из глубин процедур и функций.
Ну тогда стек никогда большим не будет, если не произойдет бесконечная рекурсия.

Тогда и фильтровать строки стека не обязательно, т.к. их не так уж много.
2 мар 15, 20:53    [17334359]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить