dmp文件读取(四)- Exception


| 阅读 |,阅读约 2 分钟
| 复制链接:

Overview

dmp文件读取(四)

前面两篇文章,已经把分析dmp所需要的准备工作:线程信息、模块信息的读取都分析完了。今天该崩溃的主角出场:异常(Exception) Stream的读取

Exception Stream概述

  • Exception Stream记录了进程崩溃时,崩溃现场的基本信息
  • 崩溃信息包括:
    • 崩溃时的线程id
    • 异常状态码
    • 异常标识
    • 异常的内存地址
    • 寄存器信息
    • 其他信息
  • 以上信息都保存在MDRawExceptionStream

Exception Stream读取入口

  • dump的GetException方法,获取dmp文件中的崩溃信息
  • 读取的模块列表信息保存在MinidumpException中
1ProcessResult MinidumpProcessor::Process(
2    Minidump *dump, ProcessState *process_state) {
3    ...
4    // 异常信息读取入口
5    MinidumpException *exception = dump->GetException();
6    ...
7}

MinidumpException

  • Exception Stream的类型为MD_EXCEPTION_STREAM
  • 存储在dmp文件中的exectpion信息,反序列化之后保存为MDRawExceptionStream对象
 1class MinidumpException : public MinidumpStream {
 2 public:
 3  virtual ~MinidumpException();
 4
 5  const MDRawExceptionStream* exception() const {
 6    return valid_ ? &exception_ : NULL;
 7  }
 8
 9  // The thread ID is used to determine if a thread is the exception thread,
10  // so a special getter is provided to retrieve this data from the
11  // MDRawExceptionStream structure.  Returns false if the thread ID cannot
12  // be determined.
13  bool GetThreadID(uint32_t *thread_id) const;
14
15  MinidumpContext* GetContext();
16
17  // Print a human-readable representation of the object to stdout.
18  void Print();
19
20 private:
21  friend class Minidump;
22
23  static const uint32_t kStreamType = MD_EXCEPTION_STREAM;
24
25  explicit MinidumpException(Minidump* minidump);
26
27  bool Read(uint32_t expected_size) override;
28
29  MDRawExceptionStream exception_;
30  MinidumpContext*     context_;
31
32  DISALLOW_COPY_AND_ASSIGN(MinidumpException);
33};

MDRawExceptionStream

 1typedef struct {
 2  // 线程id
 3  uint32_t             thread_id;        
 4  uint32_t             __align;
 5  
 6  // 异常详情
 7  MDException          exception_record;
 8  
 9  // 线程上下文
10  MDLocationDescriptor thread_context;  
11} MDRawExceptionStream;  /* MINIDUMP_EXCEPTION_STREAM */

Exception stream读取核心代码

  • 这部分实现和上一篇介绍的一样,此处不再赘述
1MinidumpException* Minidump::GetException() {
2  MinidumpException* exception;
3  return GetStream(&exception);
4}

Read方法

  • 该方法和前面介绍的也基本相同
  • 先读取数据信息到exception_对象中
  • 根据大小端判断是否需要做高低位交换
  • 读取完毕,崩溃现场信息就保存在MinidumpException对象中,为后续真正分析做准备
 1bool MinidumpException::Read(uint32_t expected_size) {
 2  // Invalidate cached data.
 3  delete context_;
 4  context_ = NULL;
 5
 6  valid_ = false;
 7
 8  if (expected_size != sizeof(exception_)) {
 9    BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
10                    " != " << sizeof(exception_);
11    return false;
12  }
13
14  if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
15    BPLOG(ERROR) << "MinidumpException cannot read exception";
16    return false;
17  }
18
19  if (minidump_->swap()) {
20    Swap(&exception_.thread_id);
21    // exception_.__align is for alignment only and does not need to be
22    // swapped.
23    Swap(&exception_.exception_record.exception_code);
24    Swap(&exception_.exception_record.exception_flags);
25    Swap(&exception_.exception_record.exception_record);
26    Swap(&exception_.exception_record.exception_address);
27    Swap(&exception_.exception_record.number_parameters);
28    // exception_.exception_record.__align is for alignment only and does not
29    // need to be swapped.
30    for (unsigned int parameter_index = 0;
31         parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
32         ++parameter_index) {
33      Swap(&exception_.exception_record.exception_information[parameter_index]);
34    }
35    Swap(&exception_.thread_context);
36  }
37
38  valid_ = true;
39  return true;
40}