头文件
#include <execinfo.h>
获取程序的堆栈信息的函数
/* Store up to SIZE return address of the current program state in
ARRAY and return the exact number of values stored. */
int backtrace(void **array, int size);
/* Return names of functions from the backtrace list in ARRAY in a newly
malloc()ed memory block. 我们必须手动释放该空间 */
char **backtrace_symbols(void *const *array, int size);
/* This function is similar to backtrace_symbols() but it writes the result
immediately to a file. */
void backtrace_symbols_fd(void *const *array, int size, int fd);
注意点:
1.backtrace的实现依赖于栈指针(fp寄存器), 在gcc编译过程中任何非零的优化等级(-On参数)
或者加入了栈指针优化参数-fomit-frame-pointer后多将不能正确得到程序栈信息;
2.backtrace_symbols的实现需要符号名称的支持,在gcc编译过程中需要加入-rdynamic参数;
3.内联函数没有栈帧,它在编译过程中被展开在调用的位置;
4.尾调用优化(Tail-call Optimization)将复用当前函数栈,而不再生成新的函数栈,这将导致栈信息不能正确被获取。
void print_stack_info()
{
int j, nptrs;
void *buffer[BACKTRACE_SIZE];
char **strings;
nptrs = backtrace(buffer, BACKTRACE_SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL)
{
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf("%s\n",strings[j]);
free(strings);
}
相比C语言,C++支持函数重载、类、模版等各种特性,如果C++的符号修饰仍按照C那样直接使用对应名称,虽然可读性很好,却不可避免的会出现各种错乱
于是C++符号修饰别名(mangled name)被设计出来,用来解决上述问题,然而修饰规则取决于编译器实现,没有统一标准,比如gcc、msvc就各有一套,但好在
都提供了相应接口进行解析(demangle),这里有个网站http://demangler.com/可以在线解析
头文件 #include <cxxabi.h>
GNU char *name = abi::__cxa_demangle(MANGLED_NAME, NULL, NULL, &status);
利用该特性对函数异常类的封装
virtual 虚析构函数是为了多态时释放子类的资源
virtual what() 实现多态的效果 std::Exception中存在what()的虚函数
throw()表示该函数能抛除所有的类型的异常
class Exception:public std::Exception
{
public:
explict Exception(const char* msg);
explict Exception(const string& msg);
virtual ~Exception() throw();
virtual const char* what() const throw();
const char* stackTrace() const throw();
private:
void fillStackTrace();
void demangle();
string err_message;
string stack_info;
};
Exception::Exception(const char* msg): err_message(msg)
{
fillStackTrace();
}
Exception::Exception(const string& msg):err_message(msg)
{
fillStackTrace();
}
Exception::~Exception() throw ()
{
}
const char* Exception::what() const throw()
{
return err_message.c_str();
}
const char* Exception::stackTrace() const throw()
{
return stack_info.c_str();
}
ssacnf 的格式化输入
1、 * 亦可用于格式中, (即 %*d 和 %*s) 加了星号 (*) 表示跳过此数据不读入. (也就是不把此数据读入参数中)
2、{a|b|c}表示a,b,c中选一,[d],表示可以有d也可以没有d。
3、width表示读取宽度。
4、{h | l | I64 | L}:参数的size,通常h表示单字节size,I表示2字节 size,L表示4字节size(double例外),l64表示8字节size。
5、type :这就很多了,就是%s,%d之类。
6、特别的:%*[width] [{h | l | I64 | L}]type 表示满足该条件的被过滤掉,不会向目标参数中写入值
%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)
%[aB'] 匹配a、B、'中一员,贪婪性
%[^a] 匹配非a的任意字符,贪婪性
//函数修饰名--->函数名
string Exception::demangle(const char *mangle_name)
{
size_t size;
int status;
char temp[120];
if(1 == sscanf(mangle_name, "%*[^(]%*[^_]%127[^)+]", temp))
{
if(NULL != (demangled = abi::cxa_demangle(temp, NULL, &size, &status)))
{
string result(demangled);
free(demangled);
retutn result;
}
}
if(1 == sscanf(mangle_name, "%127s", temp))
return temp;
return mangle_name;
}
void Exception::fillStackTrace()
{
const int len = 200;
void* buffer[len];
//该函数用与获取当前线程的调用堆栈
int nptrs = ::backtrace(buffer, len);
//backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组
char** strings = ::backtrace_symbols(buffer, nptrs);
if (strings)
{
for (int i = 0; i < nptrs; ++i)
{
stack_.append(demangle(strings[i]));
stack_.push_back('\n');
}
free(strings);
}
}
#include <execinfo.h>
获取程序的堆栈信息的函数
/* Store up to SIZE return address of the current program state in
ARRAY and return the exact number of values stored. */
int backtrace(void **array, int size);
/* Return names of functions from the backtrace list in ARRAY in a newly
malloc()ed memory block. 我们必须手动释放该空间 */
char **backtrace_symbols(void *const *array, int size);
/* This function is similar to backtrace_symbols() but it writes the result
immediately to a file. */
void backtrace_symbols_fd(void *const *array, int size, int fd);
注意点:
1.backtrace的实现依赖于栈指针(fp寄存器), 在gcc编译过程中任何非零的优化等级(-On参数)
或者加入了栈指针优化参数-fomit-frame-pointer后多将不能正确得到程序栈信息;
2.backtrace_symbols的实现需要符号名称的支持,在gcc编译过程中需要加入-rdynamic参数;
3.内联函数没有栈帧,它在编译过程中被展开在调用的位置;
4.尾调用优化(Tail-call Optimization)将复用当前函数栈,而不再生成新的函数栈,这将导致栈信息不能正确被获取。
void print_stack_info()
{
int j, nptrs;
void *buffer[BACKTRACE_SIZE];
char **strings;
nptrs = backtrace(buffer, BACKTRACE_SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL)
{
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf("%s\n",strings[j]);
free(strings);
}
相比C语言,C++支持函数重载、类、模版等各种特性,如果C++的符号修饰仍按照C那样直接使用对应名称,虽然可读性很好,却不可避免的会出现各种错乱
于是C++符号修饰别名(mangled name)被设计出来,用来解决上述问题,然而修饰规则取决于编译器实现,没有统一标准,比如gcc、msvc就各有一套,但好在
都提供了相应接口进行解析(demangle),这里有个网站http://demangler.com/可以在线解析
头文件 #include <cxxabi.h>
GNU char *name = abi::__cxa_demangle(MANGLED_NAME, NULL, NULL, &status);
利用该特性对函数异常类的封装
virtual 虚析构函数是为了多态时释放子类的资源
virtual what() 实现多态的效果 std::Exception中存在what()的虚函数
throw()表示该函数能抛除所有的类型的异常
class Exception:public std::Exception
{
public:
explict Exception(const char* msg);
explict Exception(const string& msg);
virtual ~Exception() throw();
virtual const char* what() const throw();
const char* stackTrace() const throw();
private:
void fillStackTrace();
void demangle();
string err_message;
string stack_info;
};
Exception::Exception(const char* msg): err_message(msg)
{
fillStackTrace();
}
Exception::Exception(const string& msg):err_message(msg)
{
fillStackTrace();
}
Exception::~Exception() throw ()
{
}
const char* Exception::what() const throw()
{
return err_message.c_str();
}
const char* Exception::stackTrace() const throw()
{
return stack_info.c_str();
}
ssacnf 的格式化输入
1、 * 亦可用于格式中, (即 %*d 和 %*s) 加了星号 (*) 表示跳过此数据不读入. (也就是不把此数据读入参数中)
2、{a|b|c}表示a,b,c中选一,[d],表示可以有d也可以没有d。
3、width表示读取宽度。
4、{h | l | I64 | L}:参数的size,通常h表示单字节size,I表示2字节 size,L表示4字节size(double例外),l64表示8字节size。
5、type :这就很多了,就是%s,%d之类。
6、特别的:%*[width] [{h | l | I64 | L}]type 表示满足该条件的被过滤掉,不会向目标参数中写入值
%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)
%[aB'] 匹配a、B、'中一员,贪婪性
%[^a] 匹配非a的任意字符,贪婪性
//函数修饰名--->函数名
string Exception::demangle(const char *mangle_name)
{
size_t size;
int status;
char temp[120];
if(1 == sscanf(mangle_name, "%*[^(]%*[^_]%127[^)+]", temp))
{
if(NULL != (demangled = abi::cxa_demangle(temp, NULL, &size, &status)))
{
string result(demangled);
free(demangled);
retutn result;
}
}
if(1 == sscanf(mangle_name, "%127s", temp))
return temp;
return mangle_name;
}
void Exception::fillStackTrace()
{
const int len = 200;
void* buffer[len];
//该函数用与获取当前线程的调用堆栈
int nptrs = ::backtrace(buffer, len);
//backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组
char** strings = ::backtrace_symbols(buffer, nptrs);
if (strings)
{
for (int i = 0; i < nptrs; ++i)
{
stack_.append(demangle(strings[i]));
stack_.push_back('\n');
}
free(strings);
}
}