如何在没有调试器的情况下显示运行时发生异常的行号?

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:

For more information on how to use some of the above third-party stack trace providers, see the following blog posts:

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)并随您的应用程序分发。

在您的项目文件中添加此用途:Syncommonsmomrmotsynlog

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