如何在没有调试器的情况下显示运行时发生异常的行号?
How to display line number where an exception happens during runtime without a debugger?
我在运行时发生了一个不可重现的异常,因此我无法在 IDE/debugger 中调试它。我想知道代码中发生这种情况的位置,所以我用 try/except 语句包围了代码,插入了一个 'raise exception' 语句进行测试,并像这样显示堆栈跟踪以查看它是否有效:
on e: exception do begin
showmessage(e.StackTrace);
end;
但是显示的消息是空的。为什么它是空的?还有另一种方法可以知道异常发生在哪里吗?使用 Delphi XE.
Exception.StackTrace documentation indicates that the default implementation returns an empty string, and that in order to use the functionality you need to provide a GetStackInfoStringProc 过程。它还建议使用来自第三方提供商的一些实现(免费的和商业的),而不是自己编写。
这是该文档的(简短)摘录 - 请访问相关链接的文档页面:
By default, StackTrace is always an empty string. If you want StackTrace to contain an actual value, you must assign GetStackInfoStringProc a procedure that can generate a string from the stack information.
Using Exception.StackTrace
In order to use the StackTrace property to obtain the stack trace for exceptions, you have to use (or implement) a stack trace provider. There are a number of third-party solutions, both commercial and free.
Some of the stack trace providers are:
- JEDI Code Library (the JclDebug and the JCLHookExcept unit).
- EurekaLog
- madExcept
For more information on how to use some of the above third-party stack trace providers, see the following blog posts:
- Working with Delphi’s new Exception.StackTrace (Tobias Gurock, 2009).
- CodeVerge - How to use Exception.StackTrace (2008).
However the message displayed was empty. Why was it empty?
正如 Ken 所说,根据其文档,StackTrace
属性 未默认实现。您必须安装具有堆栈跟踪功能的第 3 方异常记录器才能连接 StackTrace
属性.
Is there another way to know where an exception happened?
如果没有可行的堆栈跟踪,您将必须获取实际发生异常的代码指令的内存地址,然后将其与存储在生成的 .map
文件中的地址列表进行比较,以便您编译可执行文件(如果在项目选项中启用,这也是堆栈跟踪所必需的)。这样,您可以推断出崩溃代码属于哪个函数,但不一定是确切的代码行。
如果异常是 EExternal
-derived exception (like EAccessViolation
), you can get the memory address from the EExternal.ExceptionRecord
field (Windows only), or the EExternal.ExceptionAddress
field (*Nix/OSX/iOS). Otherwise, use the System.ExceptAddr()
函数。
另一种解决方案是使用synopse框架,看看文档中的TSQLLog
class。
您只需生成地图文件(由框架转换为 .mab
)并随您的应用程序分发。
在您的项目文件中添加此用途:Syncommons
、momrmot
和 synlog
。
uses
Vcl.Forms,
SynCommons,
mORMot,
SynLog,
F_calc in 'F_calc.pas' {Form1};
{$R *.res}
begin
TSQLLog.Family.Level := LOG_STACKTRACE; // LOG_VERBOSE
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
将生成一个日志文件。
您可以使用此示例程序(在框架中)阅读它:
Synopse\SQLite3\Samples - Exception logging\logview.dpr
我在运行时发生了一个不可重现的异常,因此我无法在 IDE/debugger 中调试它。我想知道代码中发生这种情况的位置,所以我用 try/except 语句包围了代码,插入了一个 'raise exception' 语句进行测试,并像这样显示堆栈跟踪以查看它是否有效:
on e: exception do begin
showmessage(e.StackTrace);
end;
但是显示的消息是空的。为什么它是空的?还有另一种方法可以知道异常发生在哪里吗?使用 Delphi XE.
Exception.StackTrace documentation indicates that the default implementation returns an empty string, and that in order to use the functionality you need to provide a GetStackInfoStringProc 过程。它还建议使用来自第三方提供商的一些实现(免费的和商业的),而不是自己编写。
这是该文档的(简短)摘录 - 请访问相关链接的文档页面:
By default, StackTrace is always an empty string. If you want StackTrace to contain an actual value, you must assign GetStackInfoStringProc a procedure that can generate a string from the stack information.
Using Exception.StackTrace
In order to use the StackTrace property to obtain the stack trace for exceptions, you have to use (or implement) a stack trace provider. There are a number of third-party solutions, both commercial and free.
Some of the stack trace providers are:
- JEDI Code Library (the JclDebug and the JCLHookExcept unit).
- EurekaLog
- madExcept
For more information on how to use some of the above third-party stack trace providers, see the following blog posts:
- Working with Delphi’s new Exception.StackTrace (Tobias Gurock, 2009).
- CodeVerge - How to use Exception.StackTrace (2008).
However the message displayed was empty. Why was it empty?
正如 Ken 所说,根据其文档,StackTrace
属性 未默认实现。您必须安装具有堆栈跟踪功能的第 3 方异常记录器才能连接 StackTrace
属性.
Is there another way to know where an exception happened?
如果没有可行的堆栈跟踪,您将必须获取实际发生异常的代码指令的内存地址,然后将其与存储在生成的 .map
文件中的地址列表进行比较,以便您编译可执行文件(如果在项目选项中启用,这也是堆栈跟踪所必需的)。这样,您可以推断出崩溃代码属于哪个函数,但不一定是确切的代码行。
如果异常是 EExternal
-derived exception (like EAccessViolation
), you can get the memory address from the EExternal.ExceptionRecord
field (Windows only), or the EExternal.ExceptionAddress
field (*Nix/OSX/iOS). Otherwise, use the System.ExceptAddr()
函数。
另一种解决方案是使用synopse框架,看看文档中的TSQLLog
class。
您只需生成地图文件(由框架转换为 .mab
)并随您的应用程序分发。
在您的项目文件中添加此用途:Syncommons
、momrmot
和 synlog
。
uses
Vcl.Forms,
SynCommons,
mORMot,
SynLog,
F_calc in 'F_calc.pas' {Form1};
{$R *.res}
begin
TSQLLog.Family.Level := LOG_STACKTRACE; // LOG_VERBOSE
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
将生成一个日志文件。 您可以使用此示例程序(在框架中)阅读它:
Synopse\SQLite3\Samples - Exception logging\logview.dpr