Форум: "Прочее";
Текущий архив: 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