一:背景

1. 讲故事

最新版本 1.2402.24001.0 的WinDbg真的让人很兴奋,可以将自己伪装成 GDB 来和远程的 GDBServer 打通来实现对 Linux 上 .NET程序进行调试,这样就可以继续使用熟悉的WinDbg 命令,在这个版本中我觉得 WinDbg 不再是 WinDbg,而是 XDbg 了,画个简图如下:

简图有了,接下来就要付出实践了。

二:实操 Linux 上 .NET调试

1. 测试程序

本想在 CentOS7 上安装 .NET8,不大好装,这里就用一个现存的 .NETCore 3.1 吧,测试代码如下:


internal class Program
{
static void Main(string[] args)
{
while (true)
{
Console.WriteLine($"{DateTime.Now},tid={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
}
}

代码非常简单,就是1s输出一条记录,接下来编译成x64部署到 Centos7 上。


[root@localhost data]# ls
ConsoleApp7 ConsoleApp7.deps.json ConsoleApp7.dll ConsoleApp7.pdb ConsoleApp7.runtimeconfig.json

2. 安装GDBServer

在 linux 上安装 gdbserver 比较简单,使用 yum 安装即可 yum install gdb-gdbserver ,输出如下:


[root@localhost data]# yum install gdb-gdbserver
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirror-hk.koddos.net
* centos-sclo-rh: ftp.sjtu.edu.cn
* centos-sclo-sclo: ftp.sjtu.edu.cn
* epel: mirror.hoster.kz
* extras: ftp.sjtu.edu.cn
* updates: mirror-hk.koddos.net
Package gdb-gdbserver-7.6.1-120.el7.x86_64 already installed and latest version
Nothing to do
[root@localhost data]# gdbserver –version
Usage: gdbserver [OPTIONS] COMM PROG [ARGS ...]
gdbserver [OPTIONS] --attach COMM PID
gdbserver [OPTIONS] --multi COMM COMM may either be a tty device (for serial debugging), or
HOST:PORT to listen for a TCP connection. Options:
--debug Enable general debugging output.
--remote-debug Enable remote protocol debugging output.
--version Display version information and exit.
--wrapper WRAPPER -- Run WRAPPER to start new programs.
--once Exit after the first connection has closed.

安装好之后,接下来用 gdbserver 来启动我们的程序,并启动调试端口为 1234,参考如下:


[root@localhost data]# gdbserver 192.168.128.130:1234 dotnet ConsoleApp7.dll
Process dotnet created; pid = 3643
Listening on port 1234

3. 使用 windbg 连接

打开Windbg后,选择 Connect to remote debugger 选项, 在连接字符串中填入 gdb:server=192.168.128.130,port=1234 即可,截图如下:

连接好之后,会有一个初始中断,直接输入g就好了,输出如下:


64-bit machine not using 64-bit API ************* Path validation summary **************
Response Time (ms) Location
Deferred SRV*C:\mysymbols*https://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*C:\mysymbols*https://msdl.microsoft.com/download/symbols
Executable search path is:
Unknown System Version 0 UP Free x64
System Uptime: not available
Process Uptime: not available
Reloading current modules
ModLoad: 00005555`55554000 00005555`555770cd /usr/share/dotnet/dotnet
ModLoad: 00007fff`f7bbf000 00007fff`f7dda488 /lib64/libpthread.so.0
ModLoad: 00007fff`f79bb000 00007fff`f7bbe130 /lib64/libdl.so.2
ModLoad: 00007fff`f76b3000 00007fff`f79ba420 /lib64/libstdc++.so.6
ModLoad: 00007fff`f73b1000 00007fff`f76b2138 /lib64/libm.so.6
ModLoad: 00007fff`f719b000 00007fff`f73b0400 /lib64/libgcc_s.so.1
ModLoad: 00007fff`f6dcd000 00007fff`f719a200 /lib64/libc.so.6
ModLoad: 00007fff`f7ddb000 00007fff`f7ffe150 /lib64/ld-linux-x86-64.so.2
ModLoad: 00007fff`f7f72000 00007fff`f7fda288 /usr/share/dotnet/host/fxr/6.0.26/libhostfxr.so
ModLoad: 00007fff`f6b7c000 00007fff`f6dcc3b0 /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/libhostpolicy.so
ModLoad: 00007fff`f63e7000 00007fff`f6b7bac8 /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/libcoreclr.so
ModLoad: 00007fff`f61df000 00007fff`f63e6c38 /lib64/librt.so.1
ModLoad: 00007fff`f57d2000 00007fff`f59dd8c0 /lib64/libnuma.so.1
ModLoad: 00007fff`f3142000 00007fff`f3413dac /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/libclrjit.so
ModLoad: 00007fff`f2f31000 00007fff`f3141468 /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/System.Native.so
ModLoad: 00007fff`f2d26000 00007fff`f2f30488 /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/System.Globalization.Native.so
ModLoad: 00007fff`f29ad000 00007fff`f2d25fe0 /lib64/libicuuc.so.50
ModLoad: 00007fff`f13da000 00007fff`f29ac030 /lib64/libicudata.so.50
ModLoad: 00007fff`f0fdb000 00007fff`f13d9340 /lib64/libicui18n.so.50
...................
ReadVirtual() failed in GetXStateConfiguration() first read attempt (error == 0.)
Unable to load image /lib64/libpthread.so.0, Win32 error 0n2
*** WARNING: Unable to verify timestamp for /lib64/libpthread.so.0
Unable to load image /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/libcoreclr.so, Win32 error 0n2
*** WARNING: Unable to verify timestamp for /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.32/libcoreclr.so
libpthread_so!_pthread_cond_timedwait+0x132:
00007fff`f7bcade2 4989c6 mov r14,rax
0:000> g

有些人可能会好奇,为什么 WinDbg 能伪装成 GDB 来和 GDBServer 来通讯,这其实得益于 WinDbg 是一个宿主,它可以被很多外来的插件无线扩容自己的功能,这和 Linux 的分而治之恰恰相反。。。

接下来可以用 .chain 命令观察插件列表,其中的 GDBServerCompositionELFBinComposition 让这项功能得到实现。


0:000> .chain
Extension DLL chain:
GDBServerComposition: image 10.0.27553.1004, API 0.0.0,
[path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\GDBServerComposition.dll]
ELFBinComposition: image 10.0.27553.1004, API 0.0.0,
[path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\ELFBinComposition.dll]
dbghelp: image 10.0.27553.1004, API 10.0.6,
[path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\dbghelp.dll]
uext: image 10.0.27553.1004, API 1.0.0,
[path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\uext.dll]

接下来就可以做验证了,研究 coreclr 源码,你会发现在 Linux 上 .NET 的 Sleep 函数是借助于底层的 pthread_cond_timedwait 函数,Linux并没有提供类似Windows 的SleepEx这样的系统调用,这就比较坑了,参考如下:


PAL_ERROR CPalSynchronizationManager::ThreadNativeWait(
ThreadNativeWaitData* ptnwdNativeWaitData,
DWORD dwTimeout,
ThreadWakeupReason* ptwrWakeupReason,
DWORD* pdwSignaledObject)
{
//...
while (FALSE == ptnwdNativeWaitData->iPred)
{
if (INFINITE == dwTimeout)
{
iWaitRet = pthread_cond_wait(&ptnwdNativeWaitData->cond,
&ptnwdNativeWaitData->mutex);
}
else
{
iWaitRet = pthread_cond_timedwait(&ptnwdNativeWaitData->cond,
&ptnwdNativeWaitData->mutex,
&tsAbsTmo);
}
}
//...
}

不管怎么说,我们用 WinDbg 调试 Linux 的 .NET 程序算是大功告成了。

三:总结

现在的 WinDbg 早已今非昔比,全平台(MacOs,Linux,Windows) 通吃,这也得益于 Windbg 是一个宿主模式的架构体系,给 WinDbg 点赞!

如何用 WinDbg 调试Linux上的 .NET程序的更多相关文章

  1. Visual Studio 2017 通过SSH 调试Linux 上.NET Core

    Visual Studio 2017 通过SSH 调试Linux 上.NET Core 应用程序. 本文环境 开发环境:Win10 x64 Visual Studio 2017 部署环境:Ubuntu ...

  2. 如何在 Linux 上安装应用程序

    如何在 Linux 上安装应用程序 编译自:https://opensource.com/article/18/1/how-install-apps-linux作者: Seth Kenlon原创:LC ...

  3. 如何用golang获取linux上文件的访问/创建/修改时间

    在linux上想获取文件的元信息,我们需要使用系统调用lstat或者stat. 在golang的os包里已经把stat封装成了Stat函数,使用它比使用syscall要方便不少. 这是os.Stat的 ...

  4. 使用Windows上Eclipse远程调试Linux上的Hadoop

    一.设置Eclipse运行用户     如果以与Hadoop运行用户名(比如grid)不同的用户运行Eclipse,则无法对Hadoop运行用户所属的文件进行管理,运行Map/Reduce程序也会报& ...

  5. IDEA调试服务器上部署的程序

    提出问题: 一个程序,部署在自己的电脑上,debug调试,相信大家都会,但是,如果我想debug调试非本地部署的程序怎么办呢.比如测试服务器上部署的程序. 其实这样的需求也是经常有的,比如一个大型的项 ...

  6. 远程编写+调试服务器上的Python程序

    原帖参见(需自备梯子):https://webcache.googleusercontent.com/search?q=cache:1htdR2EXj5wJ:https://www.digitaloc ...

  7. 如何用 fiddler 调试线上代码

    有时代码上线了,突然就碰到了坑爹的错误.或者有时看别人家线上的代码,对于一个文件想 fork 下来试试效果又不想把全部文件拉到本地,都可以使用 fiddler 的线上调试功能. 比方说我们打开携程的首 ...

  8. Linux上从Java程序中调用C函数

    原则上来说,"100%纯Java"的解决方法是最好的,但有些情况下必须使用本地方法.特别是在以下三种情况: 需要访问Java平台无法访问的系统特性和设备: 通过基准测试,发现Jav ...

  9. 在Linux上编写C#程序

    自从C#开源之后,在Linux编写C#程序就成了可能.Mono-project就是开源版本的C#维护项目.在Linux平台上使用的C#开发工具为monodevelop.安装方式如下: 首先需要安装一些 ...

  10. 如何在linux上构建objective-c程序

    swfit目前还是os x独占,以后会不会扩展到其他系统还未可知,但objective-c并不只存在于os x,在linux下gcc和clang都支持obj-c哦,下面简单把如何在ubuntu上构建o ...

随机推荐

  1. 记一次 .NET某工业设计软件 崩溃分析

    一:背景 1. 讲故事 前些天有位朋友找到我,说他的软件在客户那边不知道什么原因崩掉了,从windows事件日志看崩溃在 clr 里,让我能否帮忙定位下,dump 也抓到了,既然dump有了,接下来就 ...

  2. Aqua 专为自动化测试打造的IDE

    JetBrains是一家全球知名的软件开发公司,他们公司推出的IDE几乎是编程语言的首选,IntelliJ IDEA 之于Java,PyCharm之于Python,以及GoLand之于go等. 5月2 ...

  3. 混入 - Mixins

    混入(mixins)是一种分发Vue组件中可复用功能的非常灵活的方式.混入对象可以包含任意组件选项.当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项. 混入分为:全局和局部 定义全局混 ...

  4. 自动化搭建专属 AI 绘图服务

    通义万相AIGC技术已经比较成熟,结合阿里云的计算和存储产品可以方便的搭建自己专属的 AI 绘图服务.例如<创意加速器:AI 绘画创作>这个解决方案,利用阿里自研的通义万相AIGC技术在  ...

  5. kettle从入门到精通 第四十三课 kettle 多对1表合并同步

    1.上一节课我们学习了1对多表拆分数据同步,本节课我们一起学习多对1数据同步,也就是说多张表关联之后的结果集写入一张表. 我们平常在写java应用的时候多表关联一般有两种方式: a.通过sql 语句的 ...

  6. Uncaught TypeError: $(...).datagrid is not a function

    项目中碰见异常"Uncaught TypeError: $(...).datagrid is not a function",网上查询基本上都是jQuery的重复引用,但是找了半天 ...

  7. AlertManager解析:构建高效告警系统

    本文深入探讨了AlertManager的技术细节和实际应用,从基本概念.核心组件.工作流程,到与Prometheus的集成和实战案例,旨在为专业人士提供一个全面的AlertManager技术和应用指南 ...

  8. 在线RSA公私钥PKCS格式互转工具

    在线公私钥PKCS格式转换,支持公钥PKCS1与PKCS8格式之间相互转换,私钥PKCS1与PKCS8格式之间相互转换:PKCS1定义RSA公开密钥算法加密和签名机制,PKCS8描述私有密钥信息格式, ...

  9. MySql用户与权限控制

    MySql用户与权限控制 -- 刷新权限命令 # -- 刷新mysql权限命令 flush privileges; 用户管理 1.查看用户 #查看用户 USE mysql; SELECT host,u ...

  10. mac brew install Error: No available formula with the name “*“的解决办法

    背景 在mac上使用brew安装软件发生错误 解决办法 执行以下命令即可 rm -rf /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core ...