我是靠谱客的博主 鲤鱼白羊,最近开发中收集的这篇文章主要介绍oracle异常错误断点,使用高级断点技巧 - Oracle® Developer Studio 12.5: dbxtool 教程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

使用高级断点技巧

本节演示了使用断点的一些高级技巧:

使用断点计数

使用受限制的断点

拾取有用的断点计数

监视点

使用断点条件

使用弹出进行微重播

使用修复并继续

本节和示例程序受到了在 dbx 中发现的一个实际错误的启发,该错误的发现顺序与本节中所述的顺序相同。

注 -

要获取本节中显示的正确输出,示例程序必须仍“包含错误”。如果修复了错误,请从程序示例重新下载 OracleDeveloperStudio12.5-Samples 目录。

源代码包含一个名为 in 的样例输入文件,该文件会在示例程序中触发一个错误。in 包含以下代码:

display nonexistent_var# should yield an error

display var

stop in X# will cause one "stopped" message and display

stop in Y# will cause second "stopped" message and display

run

cont

cont

run

cont

cont

使用该输入文件运行程序时,输出如下所示:

$ a.out < in

> display nonexistent_var

error: Don't know about 'nonexistent_var'

> display var

will display 'var'

> stop in X

> stop in Y

> run

running ...

stopped in X

var = {

a = '100'

b = '101

c = ''

d = '102

e = '103'

f = '104'

}

> cont

stopped in Y

var = {

a = '105'

b = '106'

c = ''

d = '107'

e = '108'

f = '109'

}

> cont

exited

> run

running ...

stopped in X

var = {

a = '110'

b = '111'

c = ''

d = '112'

e = '113'

f = '114'

}

> cont

stopped in Y

var = {

a = '115'

b = '116'

c = ''

d = '117'

e = '118'

f = '119'

}

> cont

exited

> quit

Goodby

此输出可能看起来很长,但此示例的重点是展示长时间运行的复杂程序所使用的技术,在这些程序中,单步执行代码或仅仅进行跟踪是不切实际的。

请注意,显示字段 c 的值时,您将获取 的值。如果该字段包含错误地址,可能会发生这样的情形。

问题

请注意,当您第二次运行程序时,您收到了在第一次运行时没有收到的其他错误消息:

error: cannot get value of 'var.c'

error() 函数使用变量 err_silent 使错误消息在某些情况下不再出现。例如,对于 display 命令,不会显示错误消息,而会将问题显示为 c = ''。

步骤 1:反复性

第一步是设置一个调试目标并配置该目标,以便可通过单击 "Restart"(重新启动)

72a6b16794fb721202b289ee37aa732a.png

轻松地重复错误。

按如下方式开始调试程序:

如果您尚未编译示例程序,请按照 程序示例 中的说明进行操作。

选择 "Debug"(调试)> "Debug Executable"(调试可执行文件)。

在 "Debug Executable"(调试可执行文件)对话框中,浏览可执行文件或键入可执行文件的路径。

在 "Arguments"(参数)字段中,键入:

< in

可执行文件路径的目录部分显示在 "Working Directory"(工作目录)字段中。

单击 "Debug"(调试)。

7a5db987db34f4ee8fe1859a2fbdc4cc.png

在真实情形中,您可能还希望填充 "Environment"(环境)字段。

调试程序时,dbxtool 会创建一个调试目标。您可以通过选择 "Debug"(调试)> "Debug Recent"(调试近来的)并选择所需的可执行文件来使用同一调试配置。

您可以从 dbx 命令行设置其中的多个属性。这些属性将存储在调试目标配置中。

以下技巧有助于轻松保持可重复性。添加断点时,可以通过单击 "Restart"(重新启动)快速转至某个感兴趣的位置,而不必在出现各种中间断点时单击 "Continue"(继续)。

步骤 2:第一个断点

在 error() 函数输出一条错误消息时,在该函数内放置第一个断点。此断点将成为第 33 行上的一个行断点。

在较大的程序中,您可以通过键入以下内容(例如,在 "Debugger Console"(调试器控制台)窗口中)来轻松更改编辑器窗口中的当前函数:

(dbx) func error

淡紫色条表示 func 命令所找到的匹配项。

通过在编辑器窗口左边界中数字 33 的上面单击,创建行断点。

9f98e14a20722a6540fda8d0fdf1806e.png

单击 "Restart"(重新启动)

72a6b16794fb721202b289ee37aa732a.png

以运行该程序,命中断点时,堆栈跟踪会显示由于 in 文件中的模拟命令而生成的错误消息:

> display var# should yield an error

调用 error() 是预期行为。

e5bb64133d0b67319e49dc5b3afdfc9e.png

单击 "Continue"(继续)

a3cbee27e8d4315e0cb2b8a36745a2d9.png

继续执行该进程并再次命中该断点。

此时将显示一条意外的错误消息。

3390a8da58e37835cf73844daf901461.png

步骤 3:断点计数

最好是在每次运行时都能反复到达此位置,而不必在第一次命中断点之后由于以下命令而单击 "Continue"(继续):

> display var # should yield an error

您可以编辑程序或输入脚本,然后消除第一个麻烦的 display 命令。但是,您正在处理的特定输入顺序可能是重现此错误的关键,因此您不需要更改输入。

由于您关注的是第二次到达此断点,因此,可将其计数设置为 2。

在 "Breakpoints"(断点)窗口中,右键单击该断点,然后选择 "Customize"(定制)。

在 "Customize Breakpoint"(定制断点)对话框中,在 "Count Limit"(计数限制)字段中键入 2。

单击 "OK"(确定)。

bd00b749508d7bf38ce9f7b1782912ab.png

现在,您就可以反复到达您关注的位置了。

在本例中,是否选择计数 2 无关紧要。但是,有时会对某个感兴趣的位置进行多次调用。请参阅步骤 7:确定计数值以轻松选择合适的计数值。但现在,您可以先了解一下如何通过另一种方式仅在您关注的调用中在 error() 中停止。

步骤 4:受限制的断点

对于 error() 内部的断点,打开 "Customize Breakpoint"(定制断点)对话框,然后通过从 "Count Limit"(计数限制)的下拉式列表中选择 "Always stop"(总是停止)禁用断点计数。

重新运行程序。

注意两次在 error() 中停止的堆栈跟踪。第一次,在 error() 中的停止与以下屏幕相似:

e7f799e54bc9c185843ea5b3ba95537b.png

第二次,在 error() 中的停止与以下屏幕相似:

1391651cf03dd47ef428c289c5184047.png

要安排为在从 runProgram(第 [7] 帧)调用时在此断点处停止,请再次打开 "Customize Breakpoint"(定制断点)对话框并将 "While In"(满足条件)字段设置为 runProgram。

6a70e6b9fc981b3b49626f6324fbd1ce.png

步骤 5:查找原因

由于 err_silent 不 > 0,因此发出了不需要的错误消息。通过气球表达式求值看一下 err_silent 的值。

将光标放在第 31 行中 err_silent 的上方,然后等待其值显示出来。

c760fe908a739ef15708f78821e03118.png

跟随堆栈看一下设置 err_silent 的位置。

单击 "Make Caller Current"(使调用方成为当前调用方)

5c127bd9aa6d42c514fc372ddeee9ea5.png

两次以到达 evaluateField(),该函数已调用 evaluateFieldPrepare(),模拟一个可能正在处理 err_silent 的复杂函数。

51da88a823a566a96e97a86fdcbc0e45.png

再次单击 "Make Caller Current"(使调用方成为当前调用方)以到达 printField(),此处 err_silent 正在递增。printField() 也已调用 printFieldPrepare(),printFieldPrepare 也模拟一个可能正在处理 err_silent 的复杂函数。

c631e7d93613f406260717d31f55182b.png

请注意 err_silent++ 和 err_silent-- 如何将某些代码包围起来。

err_silent 可能在 printFieldPrepare() 或 evaluateFieldPrepare() 中出错,或者当控制到达 printField() 时 err_silent 已经出错。

步骤 6:更多断点计数

要查明 err_silent 是在对 printField() 的调用之前还是之后出错,请在 printField() 中放置一个断点。

选择 printField(),右键单击,然后选择 "New Breakpoint"(新建断点)。

新的断点类型已预先选择,并且 "Function"(函数)字段已使用 printfield 预先填充。

单击 "OK"(确定)。

cd8913158ef1c24b5701ccaabcf0f257.png

单击 "Restart"(重新启动)

72a6b16794fb721202b289ee37aa732a.png

第一次命中断点的时间是第一次运行期间第一次停止在第一个字段 var.a 上时。err_silent 为 0 是可以接受的。

7c0b22733680f7920a05aed8a7de2fab.png

单击 "Continue"(继续)。

err_silent 仍可以接受。

再次单击 "Continue"(继续)。

err_silent 仍可以接受。

到达对 printField() 的特定调用(该调用导致了不需要的错误消息)可能需要一段时间。您需要在 printField 断点上使用断点计数。可是应该将计数设置成什么呢?在该简单示例中,您可以尝试对运行和停止以及显示的字段进行计数,但实际上该过程可能会更加困难。有一种方法可以半自动地确定该计数。

步骤 7:确定计数值

打开 "Customize Breakpoint"(定制断点)对话框,找到 printField() 上的断点,然后将 "Count Limit"(计数限制)字段设置为无限大。

36f2e31b5f75307a3f8ee04fb81c4647.png

此设置意味着您将永远不会在此断点处停止。但是,仍将进行计数。

将 "Breakpoints"(断点)窗口设置为显示更多属性(如计数)。

单击 "Breakpoints"(断点)窗口右上角的 "Change Visible Columns"(更改可视列)按钮

873ddb3c7ca259ced47e9fbc01c7a5e5.png

选择 "Count Limit"(计数限制)、"Count"(计数)和 "While In"(满足条件)。

单击 "OK"(确定)。

dd1fe176cc6b4547bba6619c88abae09.png

再次运行程序。您将命中 error() 内部的断点,也就是受 runProgram() 限制的断点。

现在来看一下 printField() 上断点的计数。

fd973412c3e6ca5519e6c0bfc9b2d302.png

计数为 15。

再次在 "Customize Breakpoint"(定制断点)窗口中单击 "Count Limit"(计数限制)列中的下拉式列表,选择 "Use current Count value"(使用当前计数值)将当前计数传送给计数限制,然后单击 "OK"(确定)。

现在如果运行程序,您将在最后一次调用 printField() 时在该函数中停止,然后显示意外的错误消息。

步骤 8:确定具体原因

再次使用气球表达式求值检查 err_silent。现在的值为 -1。最有可能的原因是,在您到达 printField() 之前,一个 err_silent-- 执行得太多,或者一个 err_silent++ 执行得太少。

您可以通过仔细检查代码,在与该示例类似的小程序中找到这个不匹配的 err_silent 对。但是,大型程序可能包含大量的以下配对:

err_silent++;

err_silent--;

更为快捷地找到不匹配的 err_silent 对的方法是使用监视点。

错误的原因可能根本不是不匹配的 err_silent++; 和 err_silent--; 对,而是一个覆盖了 err_silent 内容的异常指针。在捕获此类问题时,监视点会比较有效。

步骤 9:使用监视点

在 err_silent 上创建监视点:

选择 err_silent 变量,右键单击,然后选择 "New Breakpoint"(新建断点)。

将 "Breakpoint Type"(断点类型)设置为 "Access"(访问)。

请注意 "Settings"(设置)部分如何变化以及 "Address"(地址)字段是如何成为 & err_silent 的。

在 "When"(时间)字段中选择 "After"(之后)。

在 "Operation"(操作)字段中选择 "Write"(写入)。

单击 "OK"(确定)。

48733ed712b7fc08a5cdc7ec4d510d30.png

运行程序。

您在 init() 处停止。err_silent 递增到了 1,之后就停止了执行。

单击 "Continue"(继续)。

您再次在 init() 中停止。

再次单击 "Continue"(继续)。

您再次在 init() 中停止。

再次单击 "Continue"(继续)。

您再次在 init() 中停止。

再次单击 "Continue"(继续)。

现在您将在 stopIn() 中停止。此时看起来也是一切正常,没有出现 -1。

可以设置断点条件,而不是反复地单击 "Continue"(继续),直到将 err_silent 设置为 -1。

步骤 10:断点条件

为您的监视点添加一个条件:

在 "Breakpoints"(断点)窗口中,右键单击 "After"(之后)写入断点,然后选择 "Customize"(定制)。

验证是否在 "When"(时间)字段中选择了 "After"(之后)。

通过选择 "After"(之后),您可以查看更改后的 err_silent 的值。

将 "Condition"(条件)字段设置为 err_silent == -1。

单击 "OK"(确定)。

4c1521e4ec0d41bcfe94870c50ad66ab.png

再次运行程序。

您在 checkThings() 处停止,这是第一次将 err_silent 设置为 -1。在您查找匹配的 err_silent++ 时,您会看清错误:err_silent 仅在该函数的 else 部分中递增。

354113936cc81324a954b0ede99dcd88.png

这是您所要寻找的错误吗?

步骤 11:通过弹出堆栈来验证诊断

有一种方法可以核实您是否确实检查完函数的 else 块,那就是在 checkThings() 上设置一个断点并运行程序。但 checkThings() 可能会被多次调用。您可以使用断点计数或受限制的断点来实现对 checkThings() 的正确调用,但重播最近所执行内容的更快方法是弹出堆栈。

选择 "Debug"(调试)> "Stack"(堆栈)> "Pop Topmost Call"(弹出最顶层调用)。

请注意 "Pop Topmost Call"(弹出最顶层调用)不会撤消任何内容。尤其是,err_silent 的值已出错,因为您正从数据调试切换到控制流调试。

进程状态恢复到包含对 checkThings() 的调用的行的开始处。

单击 "Step Into"(步入)

991b7b3fd00360939fa9a45504bf792f.png

并在再次调用 checkThings() 时进行观察。

在单步执行 checkThings() 时,您可以验证该进程是否执行了 if 块(此处 err_silent 没有递增,并且接着会递减至 -1)。

c6134b847b02ba0f69a35014ce4d43ee.png

尽管您似乎已找到编程错误,但您可能需要反复对其进行检查。

步骤 12:使用修复进一步验证诊断

请修复代码并验证错误确实已经消除。

通过将 err_silent++ 置于 if 语句的上方来修复代码。

cde3c48f449481d123ac5e6914dad2b5.png

选择 "Debug"(调试)> "Apply Code Changes"(应用代码更改),或者按 "Apply Code Changes"(应用代码更改)按钮

1ccfa8aec9dfa9c6b383ea65f12283fd.png

禁用 printField 断点和监视点,但保留 error() 中断点的启用状态。

bf2510bfddf3a8d3059ecdb7a40a1bfe.png

再次运行程序。

请注意,程序已完成但没有命中 error() 中的断点,其输出符合预期。

90ab6dea36b10974131ecfae1b69b1de.png

讨论

该示例说明了与使用断点和步进结尾处所讨论的模式相同的模式,即,用户在出错之前的某个点停止行为异常的程序,然后单步执行代码,将代码的本意与代码实际的行为相比较。主要差异在于,查找出错之前的点的过程要复杂一些。

最后

以上就是鲤鱼白羊为你收集整理的oracle异常错误断点,使用高级断点技巧 - Oracle® Developer Studio 12.5: dbxtool 教程的全部内容,希望文章能够帮你解决oracle异常错误断点,使用高级断点技巧 - Oracle® Developer Studio 12.5: dbxtool 教程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部