当我们使用 CTRL + Break 中断时如何在 WinDbg 中查看真实的调用堆栈
How to see real call stack in WinDbg when we break with CTRL + Break
当我们有一个常规断点时,调试器会在那里中断,我们会看到调用堆栈。但是如果我们使用 CTRL + Break 中断执行呢?我希望当前的 运行 线程会中断它所在的位置,但我通常看到的是以下内容:
# ChildEBP RetAddr
00 02b7fdc4 7762f216 ntdll!DbgBreakPoint
01 02b7fdf4 76c0336a ntdll!DbgUiRemoteBreakin+0x3c
02 02b7fe00 775c9902 kernel32!BaseThreadInitThunk+0xe
03 02b7fe40 775c98d5 ntdll!__RtlUserThreadStart+0x70
04 02b7fe58 00000000 ntdll!_RtlUserThreadStart+0x1b
*** WARNING: Unable to verify checksum for ThreadDemo.exe
但是我怎样才能得到被中断的当前线程的实际代码呢?
我是 运行 一个长循环,如下所示,需要一些时间,我希望它能在那里中断。
void Bank::Deposit(void* param)
{
Bank * bank = (Bank *)param;
char *who = (char*) bank->bankName;
int i;
printf("%s: begin deposite\n", who);
for (i = 0; i < 1000000000; i++) {
bank->balance = bank->balance + 1;
}
printf("%s: done\n", who);
return;
}
在这种情况下,当它中断时,另一个线程确实中断了这个函数,但这是一个简单的演示。当我有很多线程时,我如何知道在真实的 windows 应用程序中应用程序真正停止的位置(以及它在做什么)?
按 ctrl-c 时没有 'current thread that is running'。零个、一个或多个线程 可能 是 运行,因此调试器甚至不会尝试找出 'which' 一个要中断的线程 - 它会自行中断线。仅仅因为您有一个当时可能是 运行 的线程(但不一定如此)并不会改变这一点。
但你可以得到你想要的。当您按下 ctrl-c 时,它会中断调试器线程并停止所有其他线程。您可以通过键入以下内容列出所有线程及其调用堆栈:
~*k
您还可以通过键入以下内容切换到另一个线程:
~Ns
其中 N 是要切换到的线程的 ID。
一旦您将 'current thread' 设置为您想要的,您可以键入 k
以列出其调用堆栈和其他线程特定命令。
编辑:
有关 windbg 线程特定命令的完整列表,请参阅 this
当您按下 Ctrl+C 或 Ctrl+Break ,该键盘事件由调试器处理。这意味着当时至少有一个调试器线程 运行ning 而不是你的。弄清楚哪个线程之前 运行ning 不是那么容易。
调试器将使用调用堆栈上的 int 3
指令将新线程注入您的应用程序。此线程不会立即 运行ning,它首先必须由操作系统调度到 运行。这需要上下文切换。
当达到 int 3
时,进程中的所有线程都会暂停,并且调试器会收到有关异常的通知。因此,在您按下一个键和线程实际停止之间,经过了大约 15 毫秒到大约 30 毫秒的时间。
不过,这没什么好担心的。鉴于人类的平均反应时间为 25 毫秒,数百万条 CPU 指令发生在使您想停止线程的观察结果与实际停止之间。
正如 Sean Cline 在评论和 Mike Vine 的回答中提到的那样,其他线程仍然存在。您可以使用 ~
列出它们,使用 ~*k
显示它们的调用堆栈或使用 ~
[= 切换到特定线程15=].
当我们有一个常规断点时,调试器会在那里中断,我们会看到调用堆栈。但是如果我们使用 CTRL + Break 中断执行呢?我希望当前的 运行 线程会中断它所在的位置,但我通常看到的是以下内容:
# ChildEBP RetAddr
00 02b7fdc4 7762f216 ntdll!DbgBreakPoint
01 02b7fdf4 76c0336a ntdll!DbgUiRemoteBreakin+0x3c
02 02b7fe00 775c9902 kernel32!BaseThreadInitThunk+0xe
03 02b7fe40 775c98d5 ntdll!__RtlUserThreadStart+0x70
04 02b7fe58 00000000 ntdll!_RtlUserThreadStart+0x1b
*** WARNING: Unable to verify checksum for ThreadDemo.exe
但是我怎样才能得到被中断的当前线程的实际代码呢?
我是 运行 一个长循环,如下所示,需要一些时间,我希望它能在那里中断。
void Bank::Deposit(void* param)
{
Bank * bank = (Bank *)param;
char *who = (char*) bank->bankName;
int i;
printf("%s: begin deposite\n", who);
for (i = 0; i < 1000000000; i++) {
bank->balance = bank->balance + 1;
}
printf("%s: done\n", who);
return;
}
在这种情况下,当它中断时,另一个线程确实中断了这个函数,但这是一个简单的演示。当我有很多线程时,我如何知道在真实的 windows 应用程序中应用程序真正停止的位置(以及它在做什么)?
按 ctrl-c 时没有 'current thread that is running'。零个、一个或多个线程 可能 是 运行,因此调试器甚至不会尝试找出 'which' 一个要中断的线程 - 它会自行中断线。仅仅因为您有一个当时可能是 运行 的线程(但不一定如此)并不会改变这一点。
但你可以得到你想要的。当您按下 ctrl-c 时,它会中断调试器线程并停止所有其他线程。您可以通过键入以下内容列出所有线程及其调用堆栈:
~*k
您还可以通过键入以下内容切换到另一个线程:
~Ns
其中 N 是要切换到的线程的 ID。
一旦您将 'current thread' 设置为您想要的,您可以键入 k
以列出其调用堆栈和其他线程特定命令。
编辑:
有关 windbg 线程特定命令的完整列表,请参阅 this
当您按下 Ctrl+C 或 Ctrl+Break ,该键盘事件由调试器处理。这意味着当时至少有一个调试器线程 运行ning 而不是你的。弄清楚哪个线程之前 运行ning 不是那么容易。
调试器将使用调用堆栈上的 int 3
指令将新线程注入您的应用程序。此线程不会立即 运行ning,它首先必须由操作系统调度到 运行。这需要上下文切换。
当达到 int 3
时,进程中的所有线程都会暂停,并且调试器会收到有关异常的通知。因此,在您按下一个键和线程实际停止之间,经过了大约 15 毫秒到大约 30 毫秒的时间。
不过,这没什么好担心的。鉴于人类的平均反应时间为 25 毫秒,数百万条 CPU 指令发生在使您想停止线程的观察结果与实际停止之间。
正如 Sean Cline 在评论和 Mike Vine 的回答中提到的那样,其他线程仍然存在。您可以使用 ~
列出它们,使用 ~*k
显示它们的调用堆栈或使用 ~