muduo源码学习base——Exception(带 stack trace 的异常基类)

Exception(带 stack trace 的异常基类)

  • 前置
  • Exception
    • CurrentThread::stackTrace()

前置

ABI:

  • Application Binary Interface,应用程序二进制接口,可以参考:细谈ABI

RTTI type_info:

  • RTTI:Run Time Type Identification,运行时类型识别

mangle 和 demangle

  • mangle: c++为了实现重载和重写等,对符号进行了mangling,见文章:重载的函数名部分 例如func变为_Z4funcidPi
  • demangle:还原被mangled的名字

statcktrace:

  • 栈回溯,系统自主打印进程调用栈的行为

backtrace: ———— 参考:backtrace函数

  • 标准库中有三个函数包含在头文件下:
    1.int backtrace(void **buffer, int size);
    该函数获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针数组,参数size用来指定buffer中可以保存多少个void元素 函数的返回值是实际返回的void元素个数 buffer中的void*元素实际是从堆栈中获取的返回地址
    2.char **backtrace_symbols(void *const *buffer, int size);
    该函数将backtrace函数获取的信息转化为一个字符串数组,参数buffer是backtrace获取的堆栈指针,size是backtrace返回值。函数返回值是一个指向字符串数组的指针,它包含char*元素个数为size 每个字符串包含了一个相对于buffer中对应元素的可打印信息,包括函数名、函数偏移地址和实际返回地址(backtrace_symbols生成的字符串占用的内存是malloc出来的,但是是一次性malloc出来的,释放是只需要一次性释放返回的二级指针即可)
    返回值大概是这样的: ./testexception() [0x40144f] /lib64/libc.so.6(__libc_start_main+0xf3) [0x7f5c17b90493] ./testexception() [0x4012be]
    muduo源码学习base——Exception(带 stack trace 的异常基类)_第1张图片
    编译时加上–rdynamic选项可以打印出括号里的函数名称
    在这里插入图片描述
    3.void backtrace_symbols_fd(void *const *buffer, int size, int fd);
    该函数与backtrace_symbols函数功能相同,只是它不会malloc内存,而是将结果写入文件描述符为fd的文件中,每个函数对应一行 该函数可重入

abi::__cxa_demangle:
char* abi::__cxa_demangle (const char* mangled_name, char* output_buffer, size_t* length, int* status)
mangled_name

  • 顾名思义

output_buffer

  • 内存区域,使用 malloc 分配,*length 字节,其中存储了 demangled 名称。 如果 output_buffer 不够长,则使用 realloc 对其进行扩展。 output_buffer 可以改为 NULL; 在这种情况下,demangled 名称被放置在用 malloc 分配的内存区域中

length:

  • 在output_biffer中demangled的名称个数

status:

  • 0:操作成功
  • -1内存分配错误
  • -2非有效mangle_name
  • -3有传入的参数无效

返回值:成功返回以NULL结尾的指向demangle_name的字符数组指针,失败返回NULL,注意:调用者应负责次此处的free()

Exception

最新C++11版muduo将fillStackTrace()和自定义demangle函数整合到了CurrentThread::stackTrace函数中
类图:
muduo源码学习base——Exception(带 stack trace 的异常基类)_第2张图片

  • what():打印一条自定义消息
  • stackTrace():返回stack_.c_str()
  • 在构造函数,调用CurrentThread::stackTrace,进行demangle,填充字符串stack

CurrentThread::stackTrace()

string stackTrace(bool demangle)//是否需要进行demangle
{
 string stack;
 const int max_frames = 200;//最多有200个栈地址
 void* frame[max_frames];//void **指针数组
 int nptrs = ::backtrace(frame, max_frames);//栈地址个数
 char** strings = ::backtrace_symbols(frame, nptrs);
 //strings是一个指向字符串数组的指针,它包含char*元素个数为nptrs 每个字符串包含了一个相对于frame中对应元素的可打印信息
 //通常是这样: ./testexception(main+0xc2) [0x401a5f] /lib64/libc.so.6(__libc_start_main+0xf3) [0x7f49991cf493]
 if (strings)
 {
   size_t len = 256;
   char* demangled = demangle ? static_cast<char*>(::malloc(len)) : nullptr;//用来存储demangle后的函数名
   for (int i = 1; i < nptrs; ++i)  //跳过0(0是当前函数)
   {
     if (demangle)//如果需要进行demangle
     {
       // https://panthema.net/2008/0901-stacktrace-demangled/
       //格式:相对路径() [],例如bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909]
       char* left_par = nullptr;//+左边的那一串
       char* plus = nullptr;//是否有+
       for (char* p = strings[i]; *p; ++p)
       {
         if (*p == '(')//括号里
           left_par = p;
         else if (*p == '+')
           plus = p;
       }

       if (left_par && plus)
       {
         *plus = '\0';截取'(''+'部分的mangled_name
         int status = 0;
         char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status);//进行demangle
         *plus = '+';//还原plus
         if (status == 0)//成功
         {
           demangled = ret;  // ret could be realloc()
           stack.append(strings[i], left_par+1);
           stack.append(demangled);
           stack.append(plus);
           stack.push_back('\n');
           continue;
         }
       }
     }
     // Fallback to mangled names
     stack.append(strings[i]);
     stack.push_back('\n');
   }
   free(demangled);
   free(strings);//一次性释放backtrace_symbols返回的二级指针
 }
 return stack;
}

逻辑就是将demangle和fillstacktrace整合到一起,见注释,分别从strings中取出来,一一demangle


下面是测试用例Exception_test.cc的运行结果:

  • Stack:在这里插入图片描述
  • Stack inside lambda:
    在这里插入图片描述
  • Stack inside std::function:
    在这里插入图片描述
  • Stack inside std::bind:
    muduo源码学习base——Exception(带 stack trace 的异常基类)_第3张图片
  • 原stack trace:
    在这里插入图片描述

你可能感兴趣的:(muduo,Learn,服务器)