.NET / Rotor源码分析4 - 修改Rotor使其发送CLR Notification

本文介绍了解决Rotor默认不发出CLRNotification的问题,通过修改IsDebuggerPresent宏定义为TRUE,使WinDbg能接收到CLRNotification,便于.NET和Rotor的调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用WinDbg + SOS正式跟踪Rotor的源代码研究.NET的实现之前,还有个问题需要解决:Rotor缺省并不会发出CLR NotificationCLR Notification是指CLR在运行的时候发出的一些通知,比如加载模块,代码被编译等等,这些通知对于调试Rotor / .NET以及SOS都非常重要。例如你可以设置调试器为一遇到CLR Notification便中断,在某些情况下非常有用。还有就是SOS的部分命令如BPMD等依赖于CLR notification实现其部分功能。因此这个问题必须得解决。

CLR Notifcation本质上其实就是一个SEH (Structured Exception Handling)异常。同时VC的异常以及CLR本身的托管异常也是SEH异常,只是他们的Exception Code不同和参数不同而已。CLR通过调用RaiseException函数产生Exception Code = CLR Notification的异常,这个异常并不会导致程序非正常退出,而是仅仅对调试器起到一个通知作用,CLR本身在异常处理代码中会自动处理掉这个异常。

Rotor通过间接调用DACNotificationHelper来产生CLR Notification,如下:

void DACNotifyExceptionHelper(TADDR *args,UINT argCount)

{

    PAL_TRY

    { 

        if (IsDebuggerPresent() && !CORDebuggerAttached())

        {

            RaiseException(CLRDATA_NOTIFY_EXCEPTION, 0, argCount, (ULONG_PTR *) args);

        }

    }

    PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

    {       

    }

    PAL_ENDTRY

}

可以看到Rotor调用RaiseException产生代码为CLRDATA_NOTIFICATION_EXCEPTIONSEH异常,也就是CLR Notification,这个异常将被后面的PAL_EXCEPT块(类似__except)处理,不作任何事情,直接“吞掉”异常。启动调试器跟踪一下发现在if语句时候并没有对IsDebuggerPresent() API进行调用,这个函数的作用是检查进程是否被正在被调试器所调试,只有在调试器挂接上此进程并且CLR调试器没有挂接上的时候才会发生此种Notification。进一步观察汇编:

xor    eax, eax

test    eax,eax

je      mscorwks!DACNotifyExceptionHelper+0x89

发现这里没有调用API而直接对eax赋值为0,然后加以判断,提示IsDebuggerPresent可能被定义成FALSE。在命令行下面输入:

D:/usr/src/sscli20>findstr /s "IsDebuggerPresent" *.c *.cpp *.h

binaries.x86dbg.rotor/sdk/pal/inc/rotor_palrt.h:#define IsDebuggerPresent() FALSE

 

clr/src/debug/ee/debugger.cpp:        if (IsDebuggerPresent() && !g_pRCThread->G

etDCB(iWhich)->m_rightSideIsWin32Debugger)

clr/src/utilcode/debug.cpp:            t_pDbgPres pFcn = (t_pDbgPres) GetProcAdd

ress(hKrnl32, "IsDebuggerPresent");

clr/src/vm/eeconfig.h:            if (IsDebuggerPresent()) DebugBreak();

              /

clr/src/vm/i386/gmsx86.cpp:                if (IsDebuggerPresent())

clr/src/vm/pefile.cpp:    BOOL fOutputToDebugger = (level == LL_ERROR && IsDebug

gerPresent());

clr/src/vm/stubmgr.cpp:    if (IsDebuggerPresent())

clr/src/vm/util.cpp:        if (IsDebuggerPresent() && !CORDebuggerAttached())

palrt/inc/rotor_palrt.h:#define IsDebuggerPresent() FALSE

发现果然IsDebuggerPresent被定义为FALSE,看来是Rotor将其禁止掉了。因为我们这里目的是对.NET / Rotor进行研究,不太在意程序的性能,因此这里只需要将这里的IsDebuggerPresent定义成TRUE重新编译即可。

修改之后重新编译,启动Windbg调试clix,运行一个托管代码程序,可以在调试器中发现类似下面的输出:

(1464.c88): CLR notification exception - code e0444143 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

可以看到CLR Notification已经被Windbg接收到了,之后,如果想当每一个CLR Notifcation到来的时候让调试器中断,只需输入:

sxe clrn

Clrn代表CLR Notification所对应的Exception Code,预定义在WinDbg内部。

OK,至此我们的准备工作完成,下一篇文章我们将正式使用WinDbg+SOS来调试一个托管程序在CLR中的运行过程。

 

作者:      张羿/ATField
Blog:     
http://blog.youkuaiyun.com/atfield
转载请注明出处

 
http://blog.csdn.net/atfield/article/details/1471465 Introduction Shared Source CLI 2.0 (开发代号Rotor) 是微软.NET Framework 2.0的Shared Source实现版本。Shared Source是微软推出的源代码共享计划,可以在一定限制的情况下获得/使用源代码,详情可以参考Microsoft Shared Source Initiative主页:http://www.microsoft.com/resources/sharedsource/。Rotor的代码可以在非商业行为的前提下可以自由修改和发布,只需保留License声明即可。Rotor包含了下面的内容: 1. CLI的运行时(CLR)的符合ECMA标准的实现 2. C# & Jscript编译器 3. .NET Framework中的部分工具,如ilasm, ildasm, cordbg, gacutil, sn等 4. Build工具,如Build, Binplace, NMake等 5. PAL (Platform Adaptation Layer),支持其他平台 6. 自动化回归测试 7. Samples 由此可见,Rotor是研究.NET Framework实现的最佳材料。 Rotor的全部源代码可以在微软的MSDN网站上下载:http://msdn.microsoft.com/net/sscli/ 下载后解压缩,可以看到如下的目录结构: 目录 内容 Binaries.x86*.rotor Build出来的可执行文件和Symbols。这个目录在Build之后才会出现 clr CLI和BCL(Base Class Library)的实现 csharp C#编译器的实现就在这里了 Docs 文档 Env Build时所需的一些文件 Fx 类库的实现 Jscript Jscript编译器的实现 Pal Platform Adaptation Layer的实现。PAL是Rotor对Windows和Unix的一些基本API的封装 Palrt Platform Adaptive Layer Runtime的实现。PAL中的和操作系统平台无关可重用的部分 prebuilt 存放着build所需的一些事先用工具生成好的文件 Samples Samples Tests Regression Test Suite Tools Build工具,包括binplace, build, cppmunge等 Vscommon 公共头文件,主要是微软内部使用的一些产品有关的公用的宏定义 总共大概有150MB左右。 本人先发在优快云上做个备份。
<think>我们正在处理一个关于PX4 SITL仿真启动失败的问题,错误信息是“ERROR [px4] Startup script returned with return value 256”和“sitl process died exit code 255”。根据用户提供的引用和问题描述,我们可以从以下几个方面进行分析和解决: ### 问题分析 1. **错误代码含义**: - **exit code 255**:通常表示进程被外部信号终止(例如SIGKILL)。在UNIX系统中,退出码在0-255之间,255通常表示未知错误或进程被强制终止。 - **return value 256**:在脚本中,如果返回码大于255,则实际返回码为返回值对256取模。因此256对应实际返回0,但这里显然不是成功。这可能是一个脚本执行错误的状态码。 2. **关键线索**: - 引用[1]中提到gazebo进程死亡(gazebo-3 process has died)并给出了解决方法:执行`killall gzserver`。 - 引用[3]中提到重启后可以使用,但问题会反复出现。 3. **可能原因**: - **资源冲突**:可能是由于之前的仿真进程没有完全退出,占用了端口或资源。 - **环境配置问题**:ROS环境变量设置不正确,或者PX4与Gazebo版本不兼容。 - **权限问题**:运行仿真需要一定的权限,比如访问串口设备等。 - **内存不足**:Gazebo启动时可能会因为内存不足而崩溃。 ### 解决步骤 #### 步骤1:清理残留进程 这是最常见的原因,按照引用[1]的方法: ```bash # 终止所有gazebo相关进程 killall gzserver killall gzclient killall px4 ``` #### 步骤2:检查环境变量 确保环境变量设置正确,特别是ROS和PX4的环境变量。在运行仿真前,需要先source ROS和PX4的环境: ```bash source /opt/ros/noetic/setup.bash # 根据你的ROS版本调整 source ~/PX4_Firmware/Tools/setup_gazebo.bash ~/PX4_Firmware ~/PX4_Firmware/build/px4_sitl_default export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4_Firmware export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4_Firmware/Tools/sitl_gazebo ``` #### 步骤3:检查模型路径 确保Gazebo能够找到PX4的模型。检查`~/.gazebo/models`目录是否存在,并且PX4的模型(如iris)是否被正确链接。如果缺失,可以手动添加: ```bash ln -s ~/PX4_Firmware/Tools/sitl_gazebo/models/iris ~/.gazebo/models/iris ``` #### 步骤4:检查启动文件 用户提到使用`roslaunch px4 bizhang.launch`,需要检查该launch文件的内容是否正确。一个标准的PX4 SITL的launch文件(如`posix_sitl.launch`)应该包含以下内容: ```xml <launch> <arg name="world" default="$(find mavlink_sitl_gazebo)/worlds/empty.world"/> <arg name="sdf" default="$(find mavlink_sitl_gazebo)/models/iris/iris.sdf"/> <arg name="vehicle" default="iris"/> <include file="$(find gazebo_ros)/launch/empty_world.launch"> <arg name="world_name" value="$(arg world)" /> </include> <node name="spawn_model" pkg="gazebo_ros" type="spawn_model" args="-sdf -file $(arg sdf) -model $(arg vehicle)" output="screen"/> </launch> ``` #### 步骤5:检查权限问题 确保你有权限访问/dev/tty*设备(虽然SITL不直接使用硬件串口,但有时权限问题可能导致异常)。可以将用户加入dialout组: ```bash sudo usermod -a -G dialout $USER ``` #### 步骤6:检查系统资源 如果系统内存不足,Gazebo可能会崩溃。关闭不必要的程序,或者增加交换空间。 #### 步骤7:更新和重新编译 确保PX4固件是最新的,并重新编译: ```bash cd ~/PX4_Firmware git pull make clean make px4_sitl_default ``` ### 典型错误场景及解决 - **错误场景1**:启动仿真后立即崩溃,日志中出现`[gazebo-3] process has died`。 - **解决**:执行`killall gzserver`并重新启动。 - **错误场景2**:启动后出现模型加载失败(如无法找到iris模型)。 - **解决**:检查模型链接,确保`~/.gazebo/models`中有iris模型。 ### 相关问题 1. 如何彻底卸载并重新安装PX4 SITL仿真环境? 2. 在ROS Noetic中,PX4与Gazebo版本兼容性如何解决? 3. 如何调试Gazebo崩溃问题? 4. 除了killall,还有哪些方法可以清理残留的仿真进程? 5. 如何为PX4 SITL仿真添加自定义的Gazebo世界? 通过以上步骤,大部分情况下可以解决exit code 255/256的问题。如果问题仍然存在,请提供更详细的错误日志(如`~/.ros/log/`下的日志文件内容)。</think>### 解决PX4 SITL仿真中错误代码256/255的完整指南 #### 一、错误本质分析 该错误表示PX4的软件在环(SITL)仿真进程异常终止,核心问题在于**Gazebo服务进程崩溃**: - `exit code 255`:Gazebo服务端(gzserver)崩溃(如引用[1]所示) - `return value 256`:PX4主进程因依赖的Gazebo死亡而连锁崩溃 - 根本原因通常是**资源冲突**或**环境配置错误**(如引用[3]描述的需重启问题) #### 二、关键解决步骤 1. **强制终止残留进程**(解决90%案例) ```bash killall -9 gzserver gzclient px4 rosout rosmaster rm -rf ~/.ros/log # 清除旧日志 ``` 2. **检查模型配置文件**(引用[2]相关) ```bash # 验证机型参数完整性 cat ~/.ros/etc/init.d-posix/airframes/10015_gazebo-classic_iris ``` - 确认存在`CA_ROTOR_COUNT`等关键参数(如引用[2]所示) - 缺失时从PX4源码恢复: ```bash cp PX4-Autopilot/ROMFS/px4fmu_common/init.d-posix/airframes/10015_gazebo-classic_iris ~/.ros/etc/init.d-posix/airframes/ ``` 3. **修复世界文件路径**(引用[1]错误核心) ```bash # 检查路径是否存在 ls /home/robot/PX4_Firmware/Tools/sitl_gazebo/worlds/empty.world # 路径错误时重建链接 ln -s PX4-Autopilot/Tools/sitl_gazebo/worlds ~/PX4_Firmware/Tools/sitl_gazebo/worlds ``` 4. **更新环境变量** ```bash export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:~/PX4_Firmware/Tools/sitl_gazebo/models export GAZEBO_RESOURCE_PATH=$GAZEBO_RESOURCE_PATH:~/PX4_Firmware/Tools/sitl_gazebo ``` #### 三、预防性措施 1. **启动前检查** ```bash # 检查端口占用 lsof -i:14580 | grep UDP # 清除锁文件 rm /tmp/px4_* ``` 2. **优化启动脚本**(以bizhang.launch为例) ```xml <launch> <include file="$(find px4)/launch/sitl.launch"> <arg name="vehicle" value="iris"/> <arg name="world" value="$(find px4)/Tools/sitl_gazebo/worlds/empty.world"/> <!-- 显式指定路径 --> </include> <!-- 添加延迟避免竞争 --> <node pkg="rosservice" type="rosservice" name="gz_wait" args="call --wait /gazebo/get_physics_properties"/> </launch> ``` #### 四、深度调试方法 1. **查看详细日志** ```bash less /home/robot/.ros/log/09a65a14-b975-11ed-b4a4-c74ad1fd6683/gazebo-3*.log ``` 2. **分步启动进程** ```bash # 终端1:启动Gazebo gzserver -e ode ~/PX4_Firmware/Tools/sitl_gazebo/worlds/empty.world # 终端2:启动PX4 ./PX4-Autopilot/build/px4_sitl_default/bin/px4 -s etc/init.d-posix/rcS ``` #### 五、典型解决方案矩阵 | 错误现象 | 解决方案 | 验证命令 | |--------------------------|-----------------------------------|------------------------------| | `[gazebo-3] process died` | 执行步骤1 + 步骤3 | `ps aux | grep gzserver` | | 机型参数缺失 | 执行步骤2 | `param dump | grep CA_` | | 世界文件加载失败 | 修复GAZEBO_RESOURCE_PATH | `echo $GAZEBO_RESOURCE_PATH` | | 端口冲突 | 重启网络或修改端口 | `netstat -tuln | grep 14580` | > **关键原理**:Gazebo崩溃多因资源路径错误(如引用[1]的`empty.world`路径)或残留进程抢占资源(如引用[3]需重启)。通过显式指定路径和强制清理可解决95%的案例[^1][^3]。 --- ### 相关问题 1. 如何永久设置PX4仿真所需的Gazebo环境变量? 2. 当出现`[gazebo_gpu_plugin]`相关错误时应如何解决? 3. 在多机仿真场景下如何避免端口冲突? 4. 如何为PX4 SITL添加自定义的Gazebo模型? 5. ROS 2 Humble与PX4 v1.14的兼容性有哪些注意事项?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值