Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2013.07.28;
Скачать: [xml.tar.bz2];

Вниз

Раскрутка стека в Eureka log   Найти похожие ветки 

 
Pit   (2013-03-06 16:04) [0]

Надеюсь на Розыча, но верю во всех :)

Нужна раскрутка стека в произвольном месте программы. Я в свое время писал это, но где-то потерялось. Может, есть уже отлаженный код.

Как я это себе вижу - вызываем что-то типа:

function getCallStack: string

она возвращает список указателей. Например:

$00AAB3CC
$00BBCE9D
$00B2CCFF
...


Вторая функция:

getCallStackWithName: string

Возвращает вместе с именами уже методов:

TForm.blabla1
TForm.blabla2
TForm.blabla3
...


Розыч даже обещал вместе с указанием номеров строк кода.

Чем все упрощается - есть подключенная Еврика версии 6.x - я никогда не использовал её API (оно же наверняка есть), куда смотреть?


 
Pit   (2013-03-06 16:08) [1]

Серия вопросов еще:

1) когда происходит исключение - можно выцепить адрес кода, где произошло исключение. То есть, в секции except..end можно определить адрес инструкции, где произошло исключение. Как его определить? я подзабыл...

2) нужно адрес перевести в название метода, которому соответствует этот адрес :-) Тоже, наверное, с помощью еврики легко сделать (перекликается со стартовым постом). А еще лучше - в номер строки.


 
Игорь Шевченко ©   (2013-03-06 18:14) [2]


> Может, есть уже отлаженный код


Если без еврики, то jcldebug


 
брат Птибурдукова   (2013-03-06 18:19) [3]


> Если без еврики, то jcldebug
Крайне не любит вложенные процедуры. Если таковые имеются, пользоваться осторожно и снисходительно.


 
Pit   (2013-03-06 18:23) [4]

коллеги, как в секции except..end вытащить адрес инструкции, где возникло исключение?


 
Игорь Шевченко ©   (2013-03-06 18:28) [5]


> как в секции except..end вытащить адрес инструкции, где
> возникло исключение?


function ExceptAddr: Pointer;


 
Pit   (2013-03-06 18:44) [6]


> function ExceptAddr: Pointer;

это где такая функция?


 
брат Птибурдукова   (2013-03-06 18:54) [7]

Ты не поверишь... В модуле System.


 
Pit   (2013-03-06 19:02) [8]

тьфу ты, я подумал что это метод у Exception, обыскал как только мог и не нашел)


 
Rouse_ ©   (2013-03-06 19:03) [9]

Стек какой? Стек вызовов или стек SEH фреймов?
Еврика на работе, но на память могу сказать что в главном модуле есть и та и та функция (вроде даже как самостоятельные они) которые показывают трассу обоих видов.

Вообще на исходниках есть один из авторов эврики: http://forum.sources.ru/index.php?showuser=80667

Я обычно при непонятках всегда с ним напрямую связываюсь, отвечает достаточно оперативно (по крайней мере мне), а так вообще у них неплохой саппорт есть.


 
Pit   (2013-03-06 19:31) [10]

А не подскажите... Если преобразовывать из внутреннего формата в строчки, то как пример вывод еврики:

-----------------------------------------------------------------------------
|Address |Module      |Unit        |Class |Procedure/Method           |Line |
-----------------------------------------------------------------------------
|004AB772|Project1.exe|Unit1.pas   |      |bbb                        |32[2]|
|004AB76C|Project1.exe|Unit1.pas   |      |bbb                        |30[0]|
|004AB77C|Project1.exe|Unit1.pas   |      |aaa                        |37[1]|


Что это за значения в квадратных скобках у номера линии в исходниках?

Да, строчки 32, 30, 37 - все верно. Но что за [2], [0], [1]


 
Rouse_ ©   (2013-03-06 20:16) [11]

Оффсет от самой первой строки с начала входа в процедуру/функцию (ноль - база).


 
Германн ©   (2013-03-07 02:56) [12]


> Rouse_ ©   (06.03.13 19:03) [9]
>
> Стек какой? Стек вызовов или стек SEH фреймов?
> Еврика на работе, но на память могу сказать что в главном
> модуле есть и та и та функция (вроде даже как самостоятельные
> они) которые показывают трассу обоих видов.
>
> Вообще на исходниках есть один из авторов эврики: http://forum.
> sources.ru/index.php?showuser=80667
>
> Я обычно при непонятках всегда с ним напрямую связываюсь,
>  отвечает достаточно оперативно (по крайней мере мне), а
> так вообще у них неплохой саппорт есть.
>

Как мне когда-то ответил Александр - этот суппорт и есть он сам :)


 
Германн ©   (2013-03-07 03:06) [13]


>
> Что это за значения в квадратных скобках у номера линии
> в исходниках?

Кстати в стандартную поставку Эврики входит их вьювер, который определяет себя как программу для"обработки" файлов *.elf Как ты не увидел её, я не понимаю.


 
Pit   (2013-03-07 10:52) [14]


> Как ты не увидел её, я не понимаю.

как ты делаешь такие выводы - не понимаю.


 
Pit   (2013-03-07 11:17) [15]

А может кто видел утилиту (писал?), которая получив в текстовом виде какого-нибудь формата callstack (адреса) и с другой стороны имея MAP-файл - выдавала Callstack в текстовом виде, как делает еврика?

То есть, задумка в том, что приложение БЕЗ еврики раскручивает стек и в лог пишет раскрученные адреса. А потом уже "на базе" из этих адресов и MAP-файла от соответствующей версии строится стек.
Лень писать анализатор MAP-файла... как-то так)


 
Игорь Шевченко ©   (2013-03-07 11:23) [16]


> Лень писать анализатор MAP-файла... как-то так)


unit DelphiMapParser;

interface

procedure ParseDelphiMap(const AMapFileName: string);

implementation
uses
 SysUtils, Classes,
 image, symtab;

const
 UsableMapSectionID = "  Address             Publics by Value";
 LineNumbersID = "Line numbers for ";
 BoundResourcesID = "Bound resource files";

procedure ParseDelphiMap(const AMapFileName: string);

 procedure ProcessSymbolAddressFromMap(const AMapLine: string);
 var
   Section: Integer;
   Address: Cardinal;
   Symbol: string;
 begin
   if Length(AMapLine) > 22 then
   begin
     Section := StrToIntDef("$" + Copy(AMapLine, 2, 4), 9999);
     Address := StrToIntDef("$" + Copy(AMapLine, 7, 8), 0);
     Symbol := Copy(AMapLine, 22, MaxInt);
     if (Section <= g_SectionCount) and g_Sections[Section].ContainsCode then
     begin
       Inc(Address, g_Sections[Section].VirtualAddress);
       if not Assigned(SymbolTable.FindSymbol(Address)) then
         SymbolTable.AddSymbol(Address, Symbol);
     end;
   end;
 end;

 procedure ProcessLineNumbersFromMap(const AMapLine: string; var F: TextFile);

   procedure ProcessLineNumbersLine(const AMapLine, ASegment: string);

     procedure ProcessLineNumber(const ALineNumber: PChar; const ASegment:
       string);
     var
       Section: Integer;
       Address: Cardinal;
       Symbol: string;
       LineNo: Integer;
       Worker: string;
     begin
       SetString(Worker, ALineNumber, 6);
       LineNo := StrToIntDef(Trim(Worker), 0);
       SetString(Worker, ALineNumber + 7, 4);
       Section := StrToIntDef("$" + Worker, 9999);
       SetString(Worker, ALineNumber + 12, 8);
       Address := StrToIntDef("$" + Worker, 0);
       if (Section <= g_SectionCount) and g_Sections[Section].ContainsCode then
       begin
         Symbol := Format("%s_line#_%d", [ASegment, LineNo]);
         Inc(Address, g_Sections[Section].VirtualAddress);
         if not Assigned(SymbolTable.FindSymbol(Address)) then
           SymbolTable.AddSymbol(Address, Symbol);
       end;
     end;

     //   152 0001:00004128
   const
     LineNumberLength = 20;
   var
     I: Integer;
   begin
     //each line numbers line consist of up to 4 sections, 20 characters each.
     I := 1;
     while I < Length(AMapLine) do
     begin
       ProcessLineNumber(@AMapLine[I], ASegment);
       Inc(I, LineNumberLength);
     end;

   end;

 var
   Segment: string;
   S: string;
 begin
   Segment := Copy(AMapLine, Length(LineNumbersID) + 1, Pos("(", AMapLine) -
     Length(LineNumbersID) - 1); //+1-1 fencepost error :)
   readln(F, S); //skip empty line after the line numbers section header
   while not Eof(F) do
   begin
     readln(F, S);
     if Length(S) = 0 then
       Break; //end of line numbers section
     ProcessLineNumbersLine(S, Segment);
   end;
 end;

var
 MapF: TextFile;
 S: string;
begin
 AssignFile(MapF, AMapFileName);
 Reset(MapF);
 try
   while not Eof(MapF) do
   begin
     readln(MapF, S);
     if S = UsableMapSectionID then
       Break;
   end;
   if Eof(MapF) then
     Exit; //Illegal map
   readln(MapF, S); //Skip empty line
   //Next lines till empty line have the following format:
   // 0001:00000000       System.AllocMem
   // for code segments index in section table is used to determine section RVA
   // to add to address specified in map to compute symbol RVA in image.
   while not Eof(MapF) do
   begin
     readln(MapF, S);
     if Length(S) = 0 then
       Break;
     ProcessSymbolAddressFromMap(S);
   end;
   //Next lines are sections of line numbers
   while not Eof(MapF) do
   begin
     readln(MapF, S);
     if Copy(S, 1, Length(LineNumbersID)) = LineNumbersID then
       ProcessLineNumbersFromMap(S, MapF);
   end;
 finally
   CloseFile(MapF);
 end;
end;

end.


как канва ?


 
Rouse_ ©   (2013-03-07 11:35) [17]


> То есть, задумка в том, что приложение БЕЗ еврики раскручивает
> стек и в лог пишет раскрученные адреса.


Без еврики раньше пользовался решением от Jedy используя вот такой юнит:

unit SimpleExceptionLog;

interface

{$IFDEF DEBUG}
uses
 Windows,
 Classes,
 JclDebug,
 JclHookExcept,
 TypInfo,
 SysUtils,
 Forms;

 procedure ShowCallStack(ShowResultMessage: Boolean;
   const Prefix: string = "");
 function GetCallStack(LogStart: Integer = 3): string;
 procedure SetLogPath(const Value: string);

{$ENDIF}

implementation

{$IFDEF DEBUG}

var
 _LogPath: string = "";

 procedure SetLogPath(const Value: string);
 begin
   if Value <> "" then
     _LogPath := IncludeTrailingPathDelimiter(Value);
 end;

 function GetVersionInt(const Value: string): Int64Rec;
 var
 VerInfoSize, Dummy: DWORD;
 PFixed : Pointer;
 M: TMemoryStream;
 FlName : PChar;
 FixLength : UINT;
 FVersionMS : Cardinal;
 FVersionLS : Cardinal;
 begin
 Result.Lo := 0;
 Result.Hi := 0;
 FlName := PChar(Value);
 VerInfoSize := GetFileVersionInfoSize(FlName, Dummy);
 if VerInfoSize = 0 then Exit;
 M := TMemoryStream.Create;
 try
   M.Size := VerInfoSize;
   if GetFileVersionInfo(FlName, 0, VerInfoSize, M.Memory) then
   begin
     if VerQueryValue(M.Memory, "\", PFixed, FixLength) then
     begin
       FVersionMS := PVSFixedFileInfo(PFixed)^.dwFileVersionMS;
       FVersionLS := PVSFixedFileInfo(PFixed)^.dwFileVersionLS;
       Result.Words[0] := LongRec(FVersionLS).Lo;
       Result.Words[1] := LongRec(FVersionLS).Hi;
       Result.Words[2] := LongRec(FVersionMS).Lo;
       Result.Words[3] := LongRec(FVersionMS).Hi;
     end;
   end;
 finally
   M.Free;
 end;
 end;

 procedure LogException(ExceptObj: TObject;
   ExceptAddr: Pointer; IsOS: Boolean);
 var
   mmLog: TStringList;
   ExcceptionLog, AppName, LogPath, VerStr: string;
   ModInfo: TJclLocationInfo;
   I: Integer;
   ExceptionHandled: Boolean;
   HandlerLocation: Pointer;
   ExceptFrame: TJclExceptFrame;
   FS: TFormatSettings;
   Ver: Int64Rec;
 begin
   LogPath := GetModuleName(HInstance);
   Ver := GetVersionInt(LogPath);
   VerStr := Format("%d.%d.%d.%d", [
     Ver.Words[3], Ver.Words[2], Ver.Words[1], Ver.Words[0]]);
   AppName := ExtractFileName(LogPath);

   if _LogPath <> "" then
     LogPath := _LogPath + "ErrorLogs\"
   else
     LogPath := IncludeTrailingPathDelimiter(ExtractFilePath(LogPath)) + "ErrorLogs\";

   ForceDirectories(LogPath);
   if ExceptObj.ClassName = "ELicenceError" then Exit;
   if ExceptObj.ClassName = "EGuardantStealthException" then Exit;
   mmLog := TStringList.Create;
   try
     mmLog.Add(AppName + " (ver " + VerStr +
       ") exception data: " + DateTimeToStr(Now));
     ExcceptionLog := "Exception " + ExceptObj.ClassName;
     if ExceptObj is Exception then
       ExcceptionLog := ExcceptionLog + ": " + Exception(ExceptObj).Message;
     if IsOS then
       ExcceptionLog := ExcceptionLog + " (OS Exception)";
     mmLog.Add(ExcceptionLog);
     ModInfo := GetLocationInfo(ExceptAddr);
     mmLog.Add(Format(
       "  Exception occured at $%p (Module "%s", Procedure "%s", Unit "%s", Line %d)",
       [ModInfo.Address,
        ModInfo.UnitName,
        ModInfo.ProcedureName,
        ModInfo.SourceName,
        ModInfo.LineNumber]));
     if stExceptFrame in JclStackTrackingOptions then
     begin
       mmLog.Add("  Except frame-dump:");
       I := 0;
       ExceptionHandled := False;
       if JclLastExceptFrameList <> nil then
       begin
         while (not ExceptionHandled) and
           (I < JclLastExceptFrameList.Count) do
         begin
           ExceptFrame := JclLastExceptFrameList.Items[I];
           ExceptionHandled := ExceptFrame.HandlerInfo(ExceptObj, HandlerLocation);
           if (ExceptFrame.FrameKind = efkFinally) or
               (ExceptFrame.FrameKind = efkUnknown) or
               not ExceptionHandled then
             HandlerLocation := ExceptFrame.CodeLocation;
           ModInfo := GetLocationInfo(HandlerLocation);

           ExcceptionLog := Format(
             "    Frame at $%p (type: %s",
             [ExceptFrame.FrameLocation,
              GetEnumName(TypeInfo(TExceptFrameKind), Ord(ExceptFrame.FrameKind))]);

           if ExceptionHandled then
             ExcceptionLog := ExcceptionLog + ", handles exception)"
           else
             ExcceptionLog := ExcceptionLog + ")";
           mmLog.Add(ExcceptionLog);
           if ExceptionHandled then
             mmLog.Add(Format(
               "      Handler at $%p",
               [HandlerLocation]))
           else
             mmLog.Add(Format(
               "      Code at $%p",
               [HandlerLocation]));
           mmLog.Add(Format(
             "      Module "%s", Procedure "%s", Unit "%s", Line %d",
             [ModInfo.UnitName,
              ModInfo.ProcedureName,
              ModInfo.SourceName,
              ModInfo.LineNumber]));
           mmLog.Add("");
           Inc(I);
         end;
       end;
     end;
     GetLocaleFormatSettings(GetThreadLocale, FS);
     FS.DateSeparator := ".";
     FS.TimeSeparator := "-";
     FS.ShortDateFormat := "dd.MM.yyyy";
     AppName := ChangeFileExt(AppName, "");
     LogPath := LogPath + AppName + "(" +
       StringReplace(DateTimeToStr(Now, FS), ":", "-", [rfReplaceAll]) + ")_error.log";
     mmLog.SaveToFile(LogPath);
     ExcceptionLog := mmLog.Text;
   finally
     mmLog.Free;
   end;
 end;


 
Rouse_ ©   (2013-03-07 11:35) [18]

Не влезло:

procedure ShowCallStack(ShowResultMessage: Boolean;
   const Prefix: string = "");
 var
   StackInfoList: TJclStackInfoList;
   S, SS: TStringList;
   P, LogPath, AppName, ShortAppName, VerStr: string;
   ST: TSystemTime;
   Ver: Int64Rec;
 begin
   LogPath := GetModuleName(HInstance);
   Ver := GetVersionInt(LogPath);
   VerStr := Format("%d.%d.%d.%d", [
     Ver.Words[3], Ver.Words[2], Ver.Words[1], Ver.Words[0]]);
   AppName := ExtractFileName(LogPath);
   LogPath := IncludeTrailingPathDelimiter(
     ExtractFilePath(LogPath)) + "ErrorLogs\";
   ForceDirectories(LogPath);
   DateTimeToSystemTime(Now, ST);
   ShortAppName := ChangeFileExt(AppName, "");
   P := LogPath + Format("callstack_%s_%d.log", [ShortAppName, ST.wDay]);
   SS := TStringList.Create;
   try
     SS.Add("======================================================================== ========================================");
     SS.Add(AppName + " (ver " + VerStr +
       ") callstack data: " + DateTimeToStr(Now));
     if Prefix <> "" then
       SS.Add(Prefix);
     SS.Add("======================================================================== ========================================");
     StackInfoList := JclCreateStackList(true, 3, nil);
     try
       StackInfoList.AddToStrings(SS, true, true, true);
     finally
       StackInfoList.Free;
     end;

     S := TStringList.Create;
     try
       if FileExists(P) then
         S.LoadFromFile(P);
       S.Add(SS.Text);
       S.SaveToFile(P);
     finally
       S.Free;
     end;
     if ShowResultMessage then
       MessageBox(0, PChar(SS.Text),
         "CallStack dumped", MB_ICONINFORMATION);
   finally
     SS.Free;
   end;

 end;

 function GetCallStack(LogStart: Integer): string;
 var
   StackInfoList: TJclStackInfoList;
   SS: TStringList;
 begin
   SS := TStringList.Create;
   try
     SS.Add("======================================================================== ========================================");
     SS.Add("callstack data: " + DateTimeToStr(Now));
     SS.Add("======================================================================== ========================================");
     StackInfoList := JclCreateStackList(true, LogStart, nil);
     try
       StackInfoList.AddToStrings(SS, true, true, true);
     finally
       StackInfoList.Free;
     end;
     Result := SS.Text;
   finally
     SS.Free;
   end;
 end;

{$ENDIF}

initialization

 {$IFDEF DEBUG}
   JclStackTrackingOptions := JclStackTrackingOptions + [stExceptFrame];
   JclStartExceptionTracking;
   JclAddExceptNotifier(LogException);
 {$ENDIF}

end.


 
Pit   (2013-03-07 12:37) [19]


> как канва ?

Разбираться надо)

А можно пример вызова, как этим пользоваться?
Я понял функцию, куда передать MAP-файл можно)


 
Eraser ©   (2013-03-07 12:38) [20]

кстати, анализатор map файлов есть в утилите ExceptionReportConverter.exe из JEDI.


 
Игорь Шевченко ©   (2013-03-07 12:53) [21]

Pit   (07.03.13 12:37) [19]

Готовой у меня нету. Принцип - анализируется MAP и строится таблица символов и номеров строк в юнитах.

Возможно, другие исходники будут более полезны



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2013.07.28;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.004 c
15-1362341410
Хыхы
2013-03-04 00:10
2013.07.28
Singleton в Delphi


15-1362377389
O'ShinW
2013-03-04 10:09
2013.07.28
Почем нынче и в какие сроки раскрутят сайт? Опыт у кого есть?


2-1353496539
Xmen
2012-11-21 15:15
2013.07.28
Работа с потоком как организовать?


15-1362523636
Хыхы
2013-03-06 02:47
2013.07.28
Какими горячими клавишами...


15-1361513222
JohnKorsh
2013-02-22 10:07
2013.07.28
"Ненужные" COM порты.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский