聊一聊 .NET Dump 中的 Linux信号机制

一:背景

1. 讲故事

.NET程序 在Linux上崩溃时,我们可以配置一些参考拿到对应程序的core文件,拿到core文件后用windbg打开,往往会看到这样的一句信息 Signal SIGABRT code SI_USER (Sent by kill, sigsend, raise),参考如下:


(1.1d): Signal SIGABRT code SI_USER (Sent by kill, sigsend, raise)
libc_so!wait4+0x57:
00007fbd`09313c17 483d00f0ffff    cmp     rax,0FFFFFFFFFFFFF000h
0:023> ? 1d
Evaluate expression: 29 = 00000000`0000001d
0:023> ~29s
*** WARNING: Unable to verify timestamp for libSystem.Native.so
libc_so!read+0x4c:
00007fbd`0933829c 483d00f0ffff    cmp     rax,0FFFFFFFFFFFFF000h

从字面上看是 kill,sigsend,raise 发出了携带 SI_USER 代码的 SIGABRT 信号,看起来和Linux信号机制有关,那具体是什么意思呢?这就是本篇和大家详聊的。

二:Linux 信号机制

1. 信号机制简介

简单的说Linux信号是一种进程间通信机制,大概可以做三件事情。

  • 通知进程发生了某种事件,比如:段错误。
  • 允许进程间发送简单的消息。
  • 控制进程行为,比如:终止、暂停、继续等。

在 linux 上有60多个信号,默认能产生core文件的有11个,这也是我们最关心的,整理成表格如下:

信号名称信号编号说明
SIGQUIT3通常由 Ctrl+\ 触发
SIGILL4非法指令
SIGABRT6由 abort() 函数产生
SIGFPE8浮点异常
SIGSEGV11段错误(非法内存访问)
SIGBUS7总线错误(内存访问对齐问题等)
SIGSYS31错误的系统调用
SIGTRAP5跟踪/断点陷阱
SIGXCPU24超出 CPU 时间限制
SIGXFSZ25超出文件大小限制
SIGEMT7EMT 指令(某些架构)

有了这些基础之后就可以解读 Signal SIGABRT code SI_USER (Sent by kill, sigsend, raise) 这句话了。

1) SIGABRT

全称 signal abort ,是一种能产生 core 的信号。

2) SI_USER

在 linux 源码中有这样一句代码(type == PIDTYPE_PID) ? SI_TKILL : SI_USER,参考如下:


static void prepare_kill_siginfo(int sig, struct kernel_siginfo *info,enum pid_type type)
{clear_siginfo(info);info->si_signo = sig;info->si_errno = 0;info->si_code = (type == PIDTYPE_PID) ? SI_TKILL : SI_USER;info->si_pid = task_tgid_vnr(current);info->si_uid = from_kuid_munged(current_user_ns(), current_uid());
}

代码中的 kernel_siginfo.si_code 字段用来表示信号的来源,比如说 SI_USER 表示信号来源于用户进程,而后者的 SI_TKILL 表示信号来源于 tgkill,tkill 系统调用。

3) kill,sigsend,raise

熟悉 linux 的朋友应该对 killraise 方法非常熟悉,毕竟他们遵守 POSIX 标准,至于他们有什么区别,看签名就知道了。。。


/* Raise signal SIG, i.e., send SIG to yourself.  */
extern int raise (int __sig) __THROW;/* Send signal SIG to process number PID.  If PID is zero,send SIG to all processes in the current process's process group.If PID is < -1, send SIG to all processes in process group - PID.  */
#ifdef __USE_POSIX
extern int kill (__pid_t __pid, int __sig) __THROW;
#endif /* Use POSIX.  */

相比前面的函数,这个 sigsend 就不是 POSIX 标准了,只在部分Unix上可用,比如 Solaris,SunOS,不过功能还是很强大的,不仅可以指定 pid,还可以指定 pidgroup 以及 user 来批量的 kill 进程,这里做个了解即可,签名如下:


int sigsend(idtype_t idtype, id_t id, int sig);

这些信息汇总之后更准确的意思就是:你的程序可能调用了 kill(SIGABRT) ,raise(SIGABRT),abort 引发的程序崩溃,那是不是这样的呢?可以用 windbg 的 ~* k 观察每个线程的调用栈,最终还真给找到了。


0:023> k# Child-SP          RetAddr               Call Site
00 00007fbd`03c62a70 00007fbd`090bf635     libc_so!wait4+0x57
01 00007fbd`03c62aa0 00007fbd`090c0580     libcoreclr!PROCCreateCrashDump+0x275 [/__w/1/s/src/coreclr/pal/src/thread/process.cpp @ 2307] 
02 00007fbd`03c62b00 00007fbd`090be22f     libcoreclr!PROCCreateCrashDumpIfEnabled+0x770 [/__w/1/s/src/coreclr/pal/src/thread/process.cpp @ 2524] 
03 00007fbd`03c62b90 00007fbd`090be159 (T) libcoreclr!PROCAbort+0x2f [/__w/1/s/src/coreclr/pal/src/thread/process.cpp @ 2555] 
04 (Inline Function) --------`-------- (T) libcoreclr!PROCEndProcess+0x7c [/__w/1/s/src/coreclr/pal/src/thread/process.cpp @ 1352] 
05 00007fbd`03c62bb0 00007fbd`08db667f (T) libcoreclr!TerminateProcess+0x84 [/__w/1/s/src/coreclr/pal/inc/pal_mstypes.h @ 1249] 
...
09 00007fbd`03c63950 00007fbd`08d4524e     libcoreclr!UMEntryThunk::Terminate+0x38 [/__w/1/s/src/coreclr/inc/clrtypes.h @ 260] 
0a (Inline Function) --------`--------     libcoreclr!InteropSyncBlockInfo::FreeUMEntryThunk+0x24 [/__w/1/s/src/coreclr/vm/syncblk.cpp @ 119] 
19 00007fbd`03c63e30 00007fbd`092c91f5     libcoreclr!CorUnix::CPalThread::ThreadEntry+0x1fe [/__w/1/s/src/coreclr/pal/inc/pal.h @ 1763] 
1a 00007fbd`03c63ee0 00007fbd`09348b00     libc_so!pthread_condattr_setpshared+0x515
1b 00007fbd`03c63f80 ffffffff`ffffffff     libc_so!_clone+0x40
1c 00007fbd`03c63f88 00000000`00000000     0xffffffff`ffffffff

在上面的代码中我们看到了 libcoreclr!PROCAbort 函数,在 coreclr 中方法定义如下:


/*++
Function:PROCAbort()Aborts the process after calling the shutdown cleanup handler. This functionshould be called instead of calling abort() directly.Parameters:signal - POSIX signal numberDoes not return
--*/
PAL_NORETURN
VOID
PROCAbort(int signal)
{// Do any shutdown cleanup before aborting or creating a core dumpPROCNotifyProcessShutdown();PROCCreateCrashDumpIfEnabled(signal);// Restore the SIGABORT handler to prevent recursionSEHCleanupAbort();// Abort the process after waiting for the core dump to completeabort();
}VOID PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, bool serialize)
{// If enabled, launch the create minidump utility and wait until it completesif (!g_argvCreateDump.empty()){std::vector<const char*> argv(g_argvCreateDump);...}
}

卦中的代码逻辑非常清楚,在 abort 退出之前,先通过 PROCCreateCrashDumpIfEnabled(signal) 方法踩了一个dump,也就是说 dump 中看到的信息就是用他来填充的,可以观察 libcoreclr!g_argvCreateDump 全局变量,参考如下:


0:023> x libcoreclr!*g_argvCreateDump*
00007fbd`09192360 libcoreclr!g_argvCreateDump = {size=8}
0:023> dx -r1 (*((libcoreclr!std::vector<const char *, std::allocator<const char *> > *)0x7fbd09192360))
(*((libcoreclr!std::vector<const char *, std::allocator<const char *> > *)0x7fbd09192360))                 : {size=8} [Type: std::vector<const char *, std::allocator<const char *> >][<Raw View>]     [Type: std::vector<const char *, std::allocator<const char *> >][size]           : 8[capacity]       : 8[0]              : 0x5555b5d71140 : "/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.15/createdump" [Type: char *][1]              : 0x7fbd08b61d8f : "--name" [Type: char *][2]              : 0x7ffd1b7e1cec : "/db/xxxx/crash.dmp" [Type: char *][3]              : 0x7fbd08b6ce5f : "--full" [Type: char *][4]              : 0x7fbd08b4c7ee : "--diag" [Type: char *][5]              : 0x7fbd08b58630 : "--crashreport" [Type: char *][6]              : 0x5555b5dd7230 : "1" [Type: char *][7]              : 0x0 [Type: char *]

2. C代码眼见为实

为了能够让大家有一个更加贴切的眼见为实,我们用 C 代码亲自演示一下,为产生 core 文件,配置如下:


root@ubuntu2404:/data2# ulimit -c unlimited 
root@ubuntu2404:/data2# echo /data2/core-%e-%p-%t  | sudo tee /proc/sys/kernel/core_pattern
/data2/core-%e-%p-%t

配置好之后,大家可以使用 abort,kill,raise 这三个方法的任何一个,这里我就用 kill 来演示吧。


#include <stdio.h>
#include <signal.h>
#include <unistd.h>void sig_handler(int signo, siginfo_t *info, void *context)
{fprintf(stderr, "Received signal: %d (sent by PID: %d, UID: %d)\n",signo, info->si_pid, info->si_uid);
}int main()
{struct sigaction sa;sa.sa_sigaction = sig_handler;sa.sa_flags = SIGABRT;sigemptyset(&sa.sa_mask);if (sigaction(SIGSEGV, &sa, NULL) == -1){perror("sigaction");return 1;}printf("My PID: %d\n", getpid());printf("Press Enter to send SIGABRT to myself...\n");getchar();kill(getpid(), SIGABRT);  // 第一种方式// raise(SIGABRT);        // 第二种方式//  abort();              //第三方方式printf("This line may not be reached.\n");return 0;
}

ternimal 如下:


root@ubuntu2404:/data2# ./app
My PID: 7403
Press Enter to send SIGABRT to myself...Aborted (core dumped)
root@ubuntu2404:/data2# 
root@ubuntu2404:/data2# ls -lh
total 160K
-rwxr-xr-x 1 root root  21K May 27 10:25 app
-rw-r--r-- 1 root root  813 May 27 10:25 app.c
-rw------- 1 root root 432K May 27 10:25 core-app-7403-1748312729

用 windbg 打开 core-app-7403-1748312729 文件,熟悉的画面又回来了,哈哈。截图如下:

三:总结

要分析linux 上的.NET程序崩溃,理解Linux信号机制是一个必须要过的基础,调试之路艰难哈。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/81568.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在uniapp H5中实现路由守卫

目录 Vue3 app.config.globalProperties 1. 创建 Vue 应用实例 2. 添加全局属性或方法 3. 在组件中使用全局属性或方法 beforeEach在uniapp的注册 1、在H5中这两个对象是都存在的。「router:route」但是功能并不全面,具体可参考下图。 2、刚刚测试了一下,在微信小程序…

无人机降落伞设计要点难点及原理!

一、设计要点 1. 伞体结构与折叠方式 伞体需采用轻量化且高强度的材料&#xff08;如抗撕裂尼龙或芳纶纤维&#xff09;&#xff0c;并通过多重折叠设计&#xff08;如三重折叠缝合&#xff09;减少展开时的阻力&#xff0c;同时增强局部承力区域的强度。 伞衣的几何参数&am…

AI时代新词-AI增强现实(AI - Enhanced Reality)

一、什么是AI增强现实&#xff08;AI - Enhanced Reality&#xff09;&#xff1f; AI增强现实&#xff08;AI - Enhanced Reality&#xff09;是指将人工智能&#xff08;AI&#xff09;技术与增强现实&#xff08;Augmented Reality&#xff0c;简称AR&#xff09;技术相结合…

基于Matlab实现各种光谱数据预处理

在IT领域&#xff0c;尤其是在数据分析和科学研究中&#xff0c;光谱数据的预处理是至关重要的步骤。光谱数据通常包含了丰富的信息&#xff0c;但往往受到噪声、杂散光、背景信号等因素的影响&#xff0c;需要通过预处理来提取有效信号&#xff0c;提高分析的准确性和可靠性。…

用 commitizen-go 来实现标准化你的Git提交信息 【windows 版】

前言 团队中有部分人的 commit 信息比较随意&#xff0c;因此想用工具来进行约束&#xff0c; web 项目可以使用 commitizen 来实现&#xff0c; 但是 golang 又该用什么来约束呢&#xff0c; 在 Github 上找到 commitizen-go 可以做为 commitizen 平替&#xff0c;但该说明文…

为什么共现矩阵是高维稀疏的

为什么共现矩阵是高维稀疏的&#xff1f; 共现矩阵&#xff08;Co-occurrence Matrix&#xff09;的高维稀疏性是其固有特性&#xff0c;主要由以下原因导致&#xff1a; 1. 高维性的根本原因 词汇表大小决定维度&#xff1a; 共现矩阵的维度为 ( V \times V )&#xff0c;其…

OpenLayers 加载鼠标位置控件

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图控件是一些用来与地图进行简单交互的工具&#xff0c;地图库预先封装好&#xff0c;可以供开发者直接使用。OpenLayers具有大部分常用的控件&#x…

知识宇宙-学习篇:学编程为什么从C语言开始学起?

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、C语言的历史地位与影响力1. 编程语言的"鼻祖"2. 现代技术的基础 二、…

手机IP地址更换的影响与操作指南

在移动互联网时代&#xff0c;IP地址如同手机的“网络身份证”&#xff0c;其变更可能对上网体验、隐私安全及服务访问产生连锁反应。无论是为了绕过地域限制、保护隐私&#xff0c;还是解决网络冲突&#xff0c;了解IP更换的影响与正确操作方法都至关重要。本文将系统分析影响…

基于Alibaba Cloud Linux + 宝塔面板安装 LibreOffice 全攻略流程

LibreOffice 是一款功能强大的办公软件,默认使用开放文档格式 (OpenDocument Format , ODF), 并支持 *.docx, *.xlsx, *.pptx 等其他格式。 官网:https://www.libreoffice.org/ 或 https://zh-cn.libreoffice.org/ Alibaba Cloud Linux 3(Soaring Falcon) 是阿里云自主研发…

UniApp 微信小程序绑定动态样式 :style 避坑指南

在使用 UniApp 开发跨端应用时&#xff0c;绑定动态样式 :style 是非常常见的操作。然而&#xff0c;很多开发者在编译为 微信小程序 时会遇到一个奇怪的问题&#xff1a; 原本在 H5 中可以正常渲染的样式&#xff0c;在微信小程序中却不生效&#xff01; 让我们通过一个示例来…

WebSocket学习总结

WebSocket 是一种基于TCP的网络通信协议&#xff0c;允许浏览器和服务器之间进行全双工、实时、低延迟的双向数据传输。它突破了传统HTTP协议的限制&#xff08;请求-响应模式&#xff09;&#xff0c;特别适合需要实时通信的场景&#xff08;如聊天、实时数据推送、游戏等&…

【screen-recorder-tts】RPG 游戏字幕语音实时合成,让无声文字游戏变有声

screen-recorder-tts RPG 游戏字幕语音实时合成&#xff0c;让无声文字游戏变有声&#xff01; 欢迎大佬们提 PR&#xff0c;一起完善这个项目&#xff01;&#xff01;&#xff01; Real-time TTS for RPG game subtitles, turning silent text games into audio experienc…

深入解析Spring Boot与Redis的缓存集成实践

深入解析Spring Boot与Redis的缓存集成实践 引言 在现代Web应用中&#xff0c;缓存技术是提升系统性能的重要手段之一。Redis作为一种高性能的内存数据库&#xff0c;广泛应用于缓存场景。本文将详细介绍如何在Spring Boot项目中集成Redis&#xff0c;并探讨其在实际开发中的…

4月报 | SeaTunnel支持TDengine的多表Sink功能

各位热爱 Apache SeaTunnel 的小伙伴们&#xff0c;今年 4 月份月报更新啦&#xff01;这里将记录 SeaTunnel 社区每月的重要更新&#xff0c;欢迎关注&#xff01; 在本月的众多更新中&#xff0c;最令人关注的一项新特性是——TDengine 多表 Sink 功能的支持&#xff08;由 …

vue项目表格甘特图开发

🧩 甘特图可以管理项目进度,生产进度等信息,管理者可以更直观的查看内容。 1. 基础环境搭建 引入 dhtmlx-gantt 插件引入插件样式 dhtmlxgantt.css引入必要的扩展模块(如 markers、tooltip)创建 Vue 组件并挂载 DOM 容器初始化 gantt 图表配置2. 数据准备与处理 定义任务…

华为HCIP-Cloud-Service认证H13-821V2.0-002

1.以下关于 HiLens 关键能力的说法错误的是?&#xff08;C&#xff09; A.HiLens 能提供模型优化框架、自动压缩模型能力&#xff0c;将模型转换为目标芯片所支持的模 型格式 B.在 HLens 平台上开发的 Ski11 可以运行到任何基于华为海思芯片的设备上 C.HilLens 平台只能导入从…

【教程】给Apache服务器装上轻量级的防DDoS模块

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 背景说明 最近我的网站在被人疯狂刷流量&#xff0c;导致正常访问都不行&#xff0c;没办法只好找找怎么给他限制一下。 apache自带有一个防刷模块mod_…

pytorch 15.2 学习率调度在PyTorch中的实现方法

文章目录 一、优化器与状态字典&#xff08;state_dict&#xff09;1.1 优化器相关参数介绍1.2 模型的本地保存与读取方法 二、LambdaLR基本使用方法三、LambdaLR学习率调度实验3.1 前期准备与匿名函数定义 学习率调度作为模型优化的重要方法&#xff0c;也集成在了PyTorch的 …

【FAQ】spring boot 3 集成 nacos

拉取依赖&#xff1a; <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-alibaba-nacos-config</artifactId><version>2023.0.3.2</version> </dependency>配置 nacos 配置 注意&#xff1a;如果配置文…