1# FaultLoggerd组件 2 3## 简介 4 5Faultloggerd部件是OpenHarmony中C/C++运行时崩溃临时日志的生成及管理模块。面向基于 Rust 开发的部件,Faultloggerd 提供了Rust Panic故障日志生成能力。系统开发者可以在预设的路径下找到故障日志,定位相关问题。 6 7## 架构 8 9 10 11* Native InnerKits 接口 12 * SignalHandler:信号处理器,接收系统异常信号,触发抓取进程异常时的现场信息。 13 * BackTrace:本地回栈库,提供进程内本地回栈能力。 14 * DumpCatcher:堆栈信息抓取工具库,提供了抓取指定进程和线程的堆栈信息的能力。 15 * FaultloggerdClient:崩溃临时日志管理客户端,接收申请文件描述符、堆栈导出等请求。 16* Rust 接口 17 * PanicHandler:Rust PANIC故障处理器,封装faultloggerd回栈能力支持rust模块PANIC故障回栈。 18 * Rustc Demangle:Rust 符号demangle库,支持Rust模块mangled符号解析。 19* Faultlogger Daemon 服务 20 * FaultloggerdServer:核心服务处理模块,接收并处理客户端的请求。 21 * FaultloggerdSecure:权限校验模块,对运行时崩溃日志生成和抓取提供权限管理和校验能力。 22 * FaultloggerdConfig:崩溃临时日志管理模块。 23 * FaultloggerdPipe:数据管道传输管理模块,提供数据传输管道申请和管理能力。 24* 工具 25 * DumpCatcher Command Tool:提供命令行形式的主动抓栈工具,仅在Debug版本提供。 26 * ProcessDump:进程信息抓取二进制工具,通过命令行方式提供抓取指定进程、线程堆栈信息的能力。 27 * crasher:崩溃构造器,提供了崩溃构造和模拟能力。 28 * Rust Panic Maker:Rust PANIC 故障构造器,提供了构造Rust模块的故障构造能力。 29 30目前主要支持对以下C/C++运行时崩溃异常信号的处理: 31 32| 信号值 | 信号 | 解释 | 触发原因 | 33| ------ | --------- | --------------- | ------------------------------------------------------------ | 34| 4 | SIGILL | 非法指令 | 执行了非法指令,通常是因为可执行文件本身出现错误,或者试图执行数据段,堆栈溢出时也有可能产生这个信号。 | 35| 5 | SIGTRAP | 断点或陷阱异常 | 由断点指令或其它trap指令产生。 | 36| 6 | SIGABRT | abort发出的信号 | 调用abort函数生成的信号。 | 37| 7 | SIGBUS | 非法内存访问 | 非法地址,包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数,但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。 | 38| 8 | SIGFPE | 浮点异常 | 在发生致命的算术运算错误时发出,不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。 | 39| 11 | SIGSEGV | 无效内存访问 | 试图访问未分配给自己的内存,或试图往没有写权限的内存地址写数据。 | 40| 16 | SIGSTKFLT | 栈溢出 | 堆栈溢出。 | 41| 31 | SIGSYS | 系统调用异常 | 非法的系统调用。 | 42 43## 目录 44 45```txt 46faultloggerd/ 47├── OAT.xml 48├── common # 工具库和公共定义 49├── docs # 文档 50├── example # 样例代码 51├── frameworks # 主动抓栈实现 52├── interfaces 53│ ├── innerkits 54│ │ ├── backtrace # 本地回栈库 55│ │ ├── dump_catcher # 抓取调用栈基础库 56│ │ ├── faultloggerd_client # 崩溃临时日志管理服务客户端接口 57│ │ └── signal_handler # 异常信号处理器 58│ └── rust 59│ ├── panic_handler # Rust Panic 处理器 60│ ├── panic_report # Rust Panic 故障上报库 61│ └── rustc_demangle # Rust demangle 库 62├── services # faultloggerd 常驻服务 63├── test 64│ ├── funchook # hook 工具测试用例 65│ ├── fuzztest # 模糊测试用例 66│ ├── moduletest # 模块测试用例 67│ ├── systemtest # 系统测试用例 68│ └── unittest # 单元测试用例 69└── tools 70 ├── crasher_c # 崩溃构造器(C) 71 ├── crasher_cpp # 崩溃构造器(C++) 72 ├── dump_catcher # DumpCatcher 命令行工具 73 ├── panic_maker # Rust Panic 故障构造器 74 └── process_dump # 崩溃抓栈实现 75``` 76 77## 使用说明 78 79### 进程崩溃日志生成 80 81目前已默认开启,进程因上述异常信号崩溃将会在设备 `/data/log/faultlog/temp` 目录下生成完整的崩溃日志,可基于该崩溃日志进行问题定位和分析。 82 83> 崩溃日志介绍和常见问题指南参见:[faultloggerd FAQ](docs/usage.md) 84 85### DumpCatcher 接口 86 87DumpCatcher是提供给第三方模块使用的抓取调用栈基础库,其中包含了打印指定进程(或线程)的栈信息的接口函数。目前支持CPP调用栈和CPP-JS混合栈。 88 89接口类名:`DfxDumpCatcher` 90 91接口定义: 92* 默认(支持混合栈):`bool DumpCatch(int pid, int tid, std::string& msg);` 93* 支持输出到指定文件:`bool DumpCatchFd(int pid, int tid, std::string& msg, int fd);` 94* 支持批量抓栈:`bool DumpCatchMultiPid(const std::vector<int> &pids, std::string& msg);` 95 96接口参数说明: 97* 接口返回值: 98 * `true`:回栈成功,回栈信息存储在`msg`字符串对象中; 99 * `false`:回栈失败。 100* 输入参数: 101 * `pid`:希望回栈的进程号,如果需要回栈进程中的所有线程,则`tid`设定为`0`; 102 * `tid`:希望回栈的线程号; 103 * `fd`:指定写入回栈信息的文件句柄; 104* 输出参数: 105 * `msg`:如果回栈成功,则通过`msg`输出回栈后的信息。 106 107> 注意:此接口需要调用者是管理员(system,root)用户,或者只抓取自己用户拥有的进程信息。 108 109样例代码: 110 111* dump_catcher_demo.h 112 113```c++ 114#ifndef DUMP_CATCHER_DEMO_H 115#define DUMP_CATCHER_DEMO_H 116 117#include <inttypes.h> 118 119#define NOINLINE __attribute__((noinline)) 120 121#define GEN_TEST_FUNCTION(FuncNumA, FuncNumB) \ 122 __attribute__((noinline)) int TestFunc##FuncNumA() \ 123 { \ 124 return TestFunc##FuncNumB(); \ 125 } 126 127// test functions for callstack depth test 128int TestFunc0(void); 129int TestFunc1(void); 130int TestFunc2(void); 131int TestFunc3(void); 132int TestFunc4(void); 133int TestFunc5(void); 134int TestFunc6(void); 135int TestFunc7(void); 136int TestFunc8(void); 137int TestFunc9(void); 138int TestFunc10(void); 139 140#endif // DUMP_CATCHER_DEMO_H 141``` 142 143 * dump_catcher_demo.cpp 144 145```c++ 146#include "dump_catcher_demo.h" 147 148#include <iostream> 149#include <string> 150#include <unistd.h> 151#include "dfx_dump_catcher.h" 152using namespace std; 153 154NOINLINE int TestFunc10(void) 155{ 156 OHOS::HiviewDFX::DfxDumpCatcher dumplog; 157 string msg = ""; 158 bool ret = dumplog.DumpCatch(getpid(), gettid(), msg); 159 if (ret) { 160 cout << msg << endl; 161 } 162 return 0; 163} 164 165// auto gen function 166GEN_TEST_FUNCTION(0, 1) 167GEN_TEST_FUNCTION(1, 2) 168GEN_TEST_FUNCTION(2, 3) 169GEN_TEST_FUNCTION(3, 4) 170GEN_TEST_FUNCTION(4, 5) 171GEN_TEST_FUNCTION(5, 6) 172GEN_TEST_FUNCTION(6, 7) 173GEN_TEST_FUNCTION(7, 8) 174GEN_TEST_FUNCTION(8, 9) 175GEN_TEST_FUNCTION(9, 10) 176 177int main(int argc, char *argv[]) 178{ 179 TestFunc0(); 180 return 0; 181} 182``` 183 184* BUILD.gn: 185 186```gn 187import("//base/hiviewdfx/faultloggerd/faultloggerd.gni") 188import("//build/ohos.gni") 189 190config("dumpcatcherdemo_config") { 191 visibility = [ ":*" ] 192 193 include_dirs = [ 194 ".", 195 "//utils/native/base/include", 196 "//base/hiviewdfx/faultloggerd/interfaces/innerkits/dump_catcher/include/", 197 ] 198} 199 200ohos_executable("dumpcatcherdemo") { 201 sources = [ "dump_catcher_demo.cpp" ] 202 203 configs = [ ":dumpcatcherdemo_config" ] 204 205 deps = [ 206 "//base/hiviewdfx/faultloggerd/interfaces/innerkits/dump_catcher:libdfx_dumpcatcher", 207 "//utils/native/base:utils", 208 ] 209 210 external_deps = [ "hilog:libhilog" ] 211 212 install_enable = true 213 part_name = "faultloggerd" 214 subsystem_name = "hiviewdfx" 215} 216``` 217 218* 执行结果: 219 220```txt 221# ./dumpcatcherdemo 222#00 pc 0000000000000981(00000000004a8981) /data/test/dumpcatcherdemo 223#01 pc 0000000000000a6d(00000000004a8a6d) /data/test/dumpcatcherdemo 224#02 pc 0000000000000a63(00000000004a8a63) /data/test/dumpcatcherdemo 225#03 pc 0000000000000a59(00000000004a8a59) /data/test/dumpcatcherdemo 226#04 pc 0000000000000a4f(00000000004a8a4f) /data/test/dumpcatcherdemo 227#05 pc 0000000000000a45(00000000004a8a45) /data/test/dumpcatcherdemo 228#06 pc 0000000000000a3b(00000000004a8a3b) /data/test/dumpcatcherdemo 229#07 pc 0000000000000a31(00000000004a8a31) /data/test/dumpcatcherdemo 230#08 pc 0000000000000a27(00000000004a8a27) /data/test/dumpcatcherdemo 231#09 pc 0000000000000a1d(00000000004a8a1d) /data/test/dumpcatcherdemo 232#10 pc 0000000000000a13(00000000004a8a13) /data/test/dumpcatcherdemo 233#11 pc 0000000000000a77(00000000004a8a77) /data/test/dumpcatcherdemo 234#12 pc 00000000000c2b08(00000000b6fafb08) /system/lib/ld-musl-arm.so.1(__libc_start_main+116) 235#13 pc 0000000000000938(00000000004a8938) /data/test/dumpcatcherdemo 236#14 pc 00000000000008c4(00000000004a88c4) /data/test/dumpcatcherdemo 237``` 238 239### Backtrace 接口 240 241接口定义: 242* 获取指定线程的栈:`bool GetBacktraceStringByTid(std::string& out, int32_t tid, size_t skipFrameNum, bool fast, size_t maxFrameNums = DEFAULT_MAX_FRAME_NUM, bool enableKernelStack = true);` 243 接口参数说明: 244 * 接口返回值: 245 * `true`:回栈成功,回栈信息存储在`out`字符串对象中。 246 * `false`:回栈失败。 247 * 输入参数: 248 * `tid`:指定回栈的线程号。 249 * `skipFrameNum`:指定跳过的帧数。 250 * `fast`: 指定回栈方式。`true`: fp回栈;`false`:dwarf回栈。 251 * `maxFrameNums`: 最大回栈帧数。默认值:256。 252 * `enableKernelStack`: 使能内核栈,需要进程具有ioctl的权限。在Linux内核上不生效。默认值:true。 253 * 输出参数: 254 * `out`:如果回栈成功,则通过`out`输出回栈后的信息。 255* 获取指定线程的栈(支持混合栈):`bool GetBacktraceStringByTidWithMix(std::string& out, int32_t tid, size_t skipFrameNum, bool fast, size_t maxFrameNums = DEFAULT_MAX_FRAME_NUM, bool enableKernelStack = true);` 256 接口参数说明: 257 * 接口返回值: 258 * `true`:回栈成功,回栈信息存储在`out`字符串对象中。 259 * `false`:回栈失败。 260 * 输入参数: 261 * `tid`:指定回栈的线程号。 262 * `skipFrameNum`:指定跳过的帧数。 263 * `fast`: 指定回栈方式。`true`: fp回栈;`false`:dwarf回栈。 264 * `maxFrameNums`: 最大回栈帧数。默认值:256。 265 * `enableKernelStack`: 使能内核栈,需要进程具有ioctl的权限。在Linux内核上不生效。默认值:true。 266 * 输出参数: 267 * `out`:如果回栈成功,则通过`out`输出回栈后的信息。 268* 打印当前线程的堆栈到指定fd:`bool PrintBacktrace(int32_t fd = -1, bool fast = false, size_t maxFrameNums = DEFAULT_MAX_FRAME_NUM);` 269 接口参数说明: 270 * 接口返回值: 271 * `true`:回栈成功,回栈信息输出到指定fd。 272 * `false`:回栈失败。 273 * 输入参数: 274 * `fd`: 需要输出回栈信息的fd,小于0时认为无效。默认值:-1。 275 * `fast`: 指定回栈方式。`true`: fp回栈;`false`:dwarf回栈。默认值:false。 276 * `maxFrameNums`: 最大回栈帧数。默认值:256 277* 获取当前线程的调用栈:`bool GetBacktrace(std::string& out, bool fast = false, size_t maxFrameNums = DEFAULT_MAX_FRAME_NUM);`,`bool GetBacktrace(std::string& out, size_t skipFrameNum, bool fast = false, size_t maxFrameNums = DEFAULT_MAX_FRAME_NUM);` 278 接口参数说明: 279 * 接口返回值: 280 * `true`:回栈成功,回栈信息存储在`out`字符串对象中。 281 * `false`:回栈失败。 282 * 输入参数: 283 * `skipFrameNum`:指定跳过的帧数。 284 * `fast`: 指定回栈方式。`true`: fp回栈;`false`:dwarf回栈。默认值:false。 285 * `maxFrameNums`: 最大回栈帧数。默认值:256。 286 * 输出参数: 287 * `out`:如果回栈成功,则通过`out`输出回栈后的信息。 288* 获取当前进程的调用栈(不包含当前线程): `std::string GetProcessStacktrace(size_t maxFrameNums = DEFAULT_MAX_FRAME_NUM, bool enableKernelStack = true, bool includeThreadInfo = true);` 289 接口参数说明: 290 * 接口返回值: 291 * `std::string`:获取到的堆栈结果保存在返回值中。 292 * 输入参数: 293 * `maxFrameNums`: 最大回栈帧数。默认值:256。 294 * `enableKernelStack`: 使能内核栈,需要进程具有ioctl的权限。在Linux内核上不生效。默认值:true。 295 * `includeThreadInfo`: 获取线程状态信息。默认值:true。 296 297使用案例 298* 导入依赖 299``` 300 external_deps += [ "faultloggerd:libbacktrace_local" ] 301``` 302* 导入头文件 303``` 304#include "backtrace_local.h" 305``` 306* 调用接口使用 307``` 308namespace OHOS { 309void Test() 310{ 311 HiviewDFX::PrintBacktrace(); 312} 313} 314``` 315 316### DumpCatcher 命令行工具 317 318DumpCatcher 是指提供给用户的一个抓取调用栈命令行工具,由 DumpCatcher innerkits 接口封装实现,该工具通过 `-p`、`-t` 参数指定进程和线程,命令执行后在命令行窗口打印指定的进程的线程栈信息。 319 320工具名称:`dumpcatcher` 321 322位置:`/system/bin` 323 324参数说明: 325 326* `-p [pid]`:打印指定进程下面的所有线程栈信息; 327* `-p [pid] -t [tid]`:打印指定进程下面的指定线程信息。 328 329返回打印说明:如果栈信息解析成功,则将信息显示到标准输出。 330 331> 注意:使用此接口需要调用者是管理员(system,root)用户。 332 333### Rust Panic 故障处理器 334 335Rust Panic 故障处理器是发生panic时收集故障堆栈的处理器。需要调用注册函数进行注册, 336发生panic后在`/data/log/faultlog/faultlogger`下生成故障日志。 337 338```rust 339extern crate panic_handler; 340extern crate stacktrace_rust; 341 342fn main() { 343 panic_handler::init(); 344 ... 345} 346``` 347 348## 处理流程 349 350### 进程崩溃抓栈处理流程 351 352 353 3541. 进程运行时异常崩溃后会收到来自 `Kernel` 发送的崩溃信号,由进程在启动加载的 `SignalHandler` 模块进行信号处理; 3552. 进程接收到崩溃信号后,保存当前进程上下文,fork 出子进程执行 `ProcessDump` 二进制进行抓栈; 3563. `ProcessDump` 向 `Faultloggerd` 申请文件句柄用于存储收集到的崩溃日志数据; 3574. `ProcesDump` 将完整崩溃日志数据写入到 `/data/log/faultlog/temp` 目录下进行临时存储; 3585. `ProcessDump` 收集完崩溃日志后,上报给 `Hiview` 进行后续处理; 3594. `Hiview` 接收到新增进程崩溃故障数据后,提取简易的崩溃日志存储到 `/data/log/faultlog/faultlogger` 目录下,并生成 `HiSysevent` 故障事件。 360 361### DumpCatcher 接口/命令行工具 主动抓栈处理流程 362 363 364 3651. 进程A调用`DumpCatcher`库提供的系列接口(1B),或通过 `DumpCatcher` 命令行工具(1A),申请dump指定进程和线程的堆栈信息; 3662. 如果目前进程是当前进程,则直接调用 `BackTrace Local` 提供的能力进行本地回栈输出(2B);如果不是,则向 `Faultloggerd` 服务发送抓栈请求(2A); 3673. `Faultloggerd` 接收到抓栈请求,通过鉴权和管道申请等操作后,向目标进程发送 `SIGDUMP(35)` 信号触发主动抓栈(3); 3684. 目前进程接收到 `SIGDUMP(35)` 抓栈信号后,保存当前进程上下文,fork出子进程执行 `ProcessDump` 二进制进行抓栈,通过 `Faultloggerd` 申请到的管道返回调用栈数据(4)。 369 370### Rust Panic 故障日志收集流程 371 372// TODO 373 374## 相关仓 375 376[DFX子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/DFX%E5%AD%90%E7%B3%BB%E7%BB%9F.md) 377 378[hiviewdfx\_hiview](https://gitee.com/openharmony/hiviewdfx_hiview/blob/master/README_zh.md) 379 380[hiviewdfx\_hilog](https://gitee.com/openharmony/hiviewdfx_hilog/blob/master/README_zh.md) 381 382[hiviewdfx\_hiappevent](https://gitee.com/openharmony/hiviewdfx_hiappevent/blob/master/README_zh.md) 383 384[hiviewdfx\_hisysevent](https://gitee.com/openharmony/hiviewdfx_hisysevent/blob/master/README_zh.md) 385 386**hiviewdfx\_faultloggerd** 387 388[hiviewdfx\_hilog\_lite](https://gitee.com/openharmony/hiviewdfx_hilog_lite/blob/master/README_zh.md) 389 390[hiviewdfx\_hievent\_lite](https://gitee.com/openharmony/hiviewdfx_hievent_lite/blob/master/README_zh.md) 391 392[hiviewdfx\_hiview\_lite](https://gitee.com/openharmony/hiviewdfx_hiview_lite/blob/master/README_zh.md) 393 394