Windbg 可以显示线程名称吗?

Can Windbg display thread names?

Windbg should understand the MS exception protocol 用于将线程名称传递给调试器。

我无法让它工作。在网上看,有很多示例显示没有线程名称的“~”线程列表,这就是我所看到的。我正在调试 .NET x86 进程,我已经尝试了 WDK 8.1 x86 和 x64 版本的 Windbg。

有人知道此功能是否仍然可用吗?我错过了什么?

Does anyone know if this feature is still available?

是的,此功能仍然可用。至少对于本机应用程序。

对于 .NET 应用程序,来自“How to: Set a Thread Name in Managed Code”的方法可能优于抛出异常。

对于 .NET 线程,以下适用于 "normal" Threads(手动创建的线程,因为我不知道如何命名线程池线程):

A Thread 是 class,因此可以在 .NET 托管堆中找到:

0:000>.loadby sos clr
0:000> !dumpheap -stat -type Thread
      MT    Count    TotalSize Class Name
...
725e4960       11          572 System.Threading.Thread

请注意,还有其他输出,因为 !dumpheap 查找 class 名称的一部分。然而,方法 Table (MT) 唯一地标识了一个 class,所以这就是我们从现在开始使用的方法:

0:000> !dumpheap -short -mt 725e4960
023123d0
02312464
02313c80
...

这些是 Thread 个对象的地址。由于它是干净的输出,我们可以在循环中使用它:

0:000> .foreach (address {!dumpheap -short -mt 725e4960}) {.echo ${address} }
023123d0
02312464
02313c80    
...

在循环内部,我们可以使用地址来获取线程的更多信息。首先,让我们看看线程在内部是什么样子的:

0:000> !do 023123d0
Name:        System.Threading.Thread
...
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
...
725e3e18  400076e        c        System.String  0 instance 02313c0c m_Name
...

在偏移 +0xC 处(取决于位数!),有 m_Name 成员。那是一个字符串。让我们找出字符串的样子:

0:000> !do poi(023123d0+c)
Name:        System.String
...
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
...
725e4810  40000ac        8          System.Char  1 instance       4d m_firstChar

因此,字符串的第一个字符位于偏移量 +0x08 处。 .NET 中的字符串是 Unicode,所以我们可以用 du:

查看它
0:000> du poi(023123d0+c)+8
02313c14  "My named thread 0"

将所有这些知识合并到一个命令中:

.foreach (address {!dumpheap -short -mt 725e4960})
{
    du poi(${address}+c)+8
}

(为了便于阅读而格式化,全部放在一行中)

如果你尝试这样做,你会发现它可能会输出类似

的内容
00000008  "????????????????????????????????"

m_Namenull 时会发生这种情况。如果你关心这个,你可以添加一个 null:

检查
.foreach (address {!dumpheap -short -mt 725e4960})
{
    .if (poi(${address}+c) != 0) {
        du poi(${address}+c)+8
    }
}

(为了便于阅读而格式化,全部放在一行中)

其他改进:

  • 对线程 ID 做同样的事情
  • 美化输出(使用.printf代替dddu

最终结果:

.foreach (address {!dumpheap -short -mt 725e4960}) 
{
    .if (poi(${address}+c) != 0) 
    {
        .printf "%d ",poi(${address}+28);
        .printf "%mu\r\n", poi(${address}+c)+8
    }
}