- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我如何获得EXCEPTION_POINTERS
,即两者:
PEXCEPTION_RECORD
和PCONTEXT
EExternal
期间的数据异常?
当 Windows 抛出异常时,它会传递 PEXCEPTION_POINTERS
;指向异常信息的指针:
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
当 Delphi 向我抛出 EExternal
时异常(exception),它只包含一半的信息,PEXCEPTION_RECORD
仅:
EExternal = class(Exception)
public
ExceptionRecord: PExceptionRecord;
end;
如何,在EExternal
期间异常(exception),我两者都可以吗?
我正在尝试使用 MiniDumpWriteDump
编写小型转储来自 Delphi 的函数。
该函数有一些可选参数:
function MiniDumpWriteDump(
hProcess: THandle; //A handle to the process for which the information is to be generated.
ProcessID: DWORD; //The identifier of the process for which the information is to be generated.
hFile: THandle; //A handle to the file in which the information is to be written.
DumpType: MINIDUMP_TYPE; //The type of information to be generated.
{in, optional}ExceptionParam: PMinidumpExceptionInformation; //A pointer to a MINIDUMP_EXCEPTION_INFORMATION structure describing the client exception that caused the minidump to be generated.
{in, optional}UserStreamParam: PMinidumpUserStreamInformation;
{in, optional}CallbackParam: PMinidumpCallbackInformation): Boolean;
在基本级别上,我可以省略三个可选参数:
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFileHandle,
nil, //PMinidumpExceptionInformation
nil,
nil);
并且成功了。缺点是小型转储缺少异常信息。该信息(可选)使用第四个 miniExceptionInfo 参数传递:
TMinidumpExceptionInformation = record
ThreadId: DWORD;
ExceptionPointers: PExceptionPointers;
ClientPointers: BOOL;
end;
PMinidumpExceptionInformation = ^TMinidumpExceptionInformation;
这很好,但我需要一种方法来访问 EXCEPTION_POINTERS
发生异常时由 Windows 提供。
TExceptionPointers
结构体包含两个成员:
EXCEPTION_POINTERS = record
ExceptionRecord : PExceptionRecord;
ContextRecord : PContext;
end;
我知道德尔福的EExternal
异常是所有“Windows”异常的基础,它包含所需的PExceptionRecord
:
EExternal = class(Exception)
public
ExceptionRecord: PExceptionRecord;
end;
但它不包含关联的 ContextRecord
。
PEXCEPTION_RECORD
足够好了吗?如果我尝试通过 EXCEPTION_POINTERS
至MiniDumpWriteDump
,离开ContextRecord
无:
procedure TDataModule1.ApplicationEvents1Exception(Sender: TObject; E: Exception);
var
ei: TExceptionPointers;
begin
if (E is EExternal) then
begin
ei.ExceptionRecord := EExternal(E).ExceptionRecord;
ei.ContextRecord := nil;
GenerateDump(@ei);
end;
...
end;
function GenerateDump(exceptionInfo: PExceptionPointers): Boolean;
var
miniEI: TMinidumpExceptionInformation;
begin
...
miniEI.ThreadID := GetCurrentThreadID();
miniEI.ExceptionPointers := exceptionInfo;
miniEI.ClientPointers := True;
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFileHandle,
@miniEI, //PMinidumpExceptionInformation
nil,
nil);
end;
然后该函数失败并出现错误 0x8007021B
Only part of a ReadProcessMemory or WriteProcessMemory request was completed
SetUnhandledExceptionFilter
?Why don't you just use
SetUnhandledExceptionFilter
and get the pointer you need?
SetUnhandledExceptionFilter(@DebugHelpExceptionFilter);
function DebugHelpExceptionFilter(const ExceptionInfo: TExceptionPointers): Longint; stdcall;
begin
GenerateDump(@ExceptionInfo);
Result := 1; //1 = EXCEPTION_EXECUTE_HANDLER
end;
问题在于,未过滤异常处理程序仅在异常未过滤时才会启动。因为这是 Delphi,并且因为我处理异常:
procedure DataModule1.ApplicationEvents1Exception(Sender: TObject; E: Exception);
var
ei: TExceptionPointers;
begin
if (E is EExternal) then
begin
//If it's EXCEPTION_IN_PAGE_ERROR then we have to terminate *now*
if EExternal(E).ExceptionRecord.ExceptionCode = EXCEPTION_IN_PAGE_ERROR then
begin
ExitProcess(1);
Exit;
end;
//Write minidump
...
end;
{$IFDEF SaveExceptionsToDatabase}
SaveExceptionToDatabase(Sender, E);
{$ENDIF}
{$IFDEF ShowExceptionForm}
ShowExceptionForm(Sender, E);
{$ENDIF}
end;
应用程序不会,我也不希望它因 WER 错误而终止。
我如何获得EXCEPTION_POINTERS
在EExternal
期间?
注意:您可以忽略背景之后的所有内容。它是不必要的填充物,旨在让我看起来更聪明。
先发制人的尖酸刻薄的 Heffernan 评论:你应该停止使用 Delphi 5。
MiniDumpWriteDump
的详细示例)最佳答案
由于 Delphi RTL 不直接公开上下文指针,而仅提取异常指针并在系统内部执行此操作,因此解决方案将在某种程度上特定于您正在使用的 Delphi 版本。
自从我安装 Delphi 5 以来已经有一段时间了,但我确实有 Delphi 2007,并且我相信 Delphi 5 和 Delphi 2007 之间的概念到目前为止基本上保持不变。
考虑到这一点,下面是如何在 Delphi 2007 中完成此操作的示例:
program Sample;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils;
var
SaveGetExceptionObject : function(P: PExceptionRecord):Exception;
// we show just the content of the general purpose registers in this example
procedure DumpContext(Context: PContext);
begin
writeln('eip:', IntToHex(Context.Eip, 8));
writeln('eax:', IntToHex(Context.Eax, 8));
writeln('ebx:', IntToHex(Context.Ebx, 8));
writeln('ecx:', IntToHex(Context.Ecx, 8));
writeln('edx:', IntToHex(Context.Edx, 8));
writeln('esi:', IntToHex(Context.Esi, 8));
writeln('edi:', IntToHex(Context.Edi, 8));
writeln('ebp:', IntToHex(Context.Ebp, 8));
writeln('esp:', IntToHex(Context.Esp, 8));
end;
// Below, we redirect the ExceptObjProc ptr to point to here
// When control reaches here we locate the context ptr on
// stack, call the dump procedure, and then call the original ptr
function HookGetExceptionObject(P: PExceptionRecord):Exception;
var
Context: PContext;
begin
asm
// This +44 value is likely to differ on a Delphi 5 setup, but probably
// not by a lot. To figure out what value you should use, set a
// break-point here, then look in the stack in the CPU window for the
// P argument value on stack, and the Context pointer should be 8 bytes
// (2 entries) above that on stack.
// Note also that the 44 is sensitive to compiler switches, calling
// conventions, and so on.
mov eax, [esp+44]
mov Context, eax
end;
DumpContext(Context);
Result := SaveGetExceptionObject(P);
end;
var
dvd, dvs, res: double; // used to force a div-by-zero error
begin
dvd := 1; dvs := 0;
SaveGetExceptionObject := ExceptObjProc;
ExceptObjProc := @HookGetExceptionObject;
try
asm
// this is just for register context verification
// - don't do this in production
mov esi, $BADF00D5;
end;
// cause a crash
res := dvd / dvs;
writeln(res);
except
on E:Exception do begin
Writeln(E.Classname, ': ', E.Message);
Readln;
end;
end;
end.
关于delphi - 如何在 EExternal 异常期间获取 EXCEPTION_POINTERS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14857106/
有人知道一个函数可以将 GetExceptionInformation() 返回的 EXCEPTION_POINTERS 结构转换为我可以记录的字符串吗? 如果已经完成,我不想自己滚动。 编辑:基本上
我如何获得EXCEPTION_POINTERS ,即两者: PEXCEPTION_RECORD和 PCONTEXT EExternal期间的数据异常? 背景 当 Windows 抛出异常时,它会传递
我可能完全误解了如何使用 Google Breakpad API,如果是这种情况,我愿意接受评论/建议/粗鲁的评论。我正在尝试调用以下 C++ 函数: bool WriteMinidumpForExc
我是一名优秀的程序员,十分优秀!