头文件:hook_cxa_throw.h
#pragma once#include <dlfcn.h>#include <cstddef>#include <exception>#include <signal.h>#include <execinfo.h>#include <ucontext.h>#include <thread>#ifdef __GNUC__typedef void __attribute__((__noreturn__)) (*cxa_throw_type)(void*, void*, void(*)(void*));#elif defined(__clang__)typedef void __attribute__((__noreturn__)) (*cxa_throw_type)(void*, std::type_info*, void (_GLIBCXX_CDTOR_CALLABI*) (void*));#endifextern "C" {#define STR_HELPER(x) #x#define STR(x) STR_HELPER(x)#ifdef __clang__void __cxa_throw(void* thrown_exception, std::type_info* typeifo, void (_GLIBCXX_CDTOR_CALLABI* dest)(void*));#elif defined(__GNUC__)void __cxa_throw(void* thrown_exception, void* pvtinfo, void (*dest)(void *));#endif
头文件:hook_cxa_throw.cc
#include "hook_cxa_throw.h"#include <iostream>#include <vector>#include <string>#include <sys/time.h>cxa_throw_type orig_cxa_throw = nullptr;void load_orig_throw_code() {orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw");}std::string get_substring(const std::string& str, const std::string& str1, const std::string& str2) {if (str.empty()) {return "";}std::size_t index1 = 0;std::size_t index2 = std::string::npos;if (!str1.empty()) {index1 = str.find(str1);}if (!str2.empty()) {index2 = str.find(str2);}if (index1 != std::string::npos) {if (index2 != std::string::npos) {return str.substr(index1 + str1.length(), index2 - index1 - str1.length());} else {return str.substr(index1 + str1.length());}}return "";}struct SymbolData {std::string symbol;std::string file;std::string func1;std::string func2;std::string addr1;std::string addr2;std::string line;};void get_backtrace_symbol(char ** strings, int32_t nptrs, std::vector<SymbolData>* res) {if (strings == nullptr || nptrs <= 0 || res == nullptr) {return;}for (int j = 0; j < nptrs; ++j) {SymbolData data;data.symbol = strings[j];data.file = get_substring(data.symbol, "", "(");std::string func_addr_str = get_substring(data.symbol, "(", ")");data.func1 = get_substring(func_addr_str, "", "+");data.addr1 = get_substring(func_addr_str, "+", "");data.addr2 = get_substring(data.symbol, "[", "]");res->push_back(data);}}#ifdef __clang__void __cxa_throw(void* thrown_exception, std::type_info* typeifo, void (_GLIBCXX_CDTOR_CALLABI* dest)(void*)) {#elif defined(__GNUC__)void __cxa_throw(void* thrown_exception, void* pvtinfo, void (*dest)(void *)) {#endifif (orig_cxa_throw == nullptr) {load_orig_throw_code();}timeval now;gettimeofday(&now, NULL);void *buffer[32];int32_t nptrs = backtrace(buffer, 32);char** strings = backtrace_symbols(buffer, nptrs);std::vector<SymbolData> vec;get_backtrace_symbol(strings, nptrs, &vec);if (strings != nullptr) {free(strings);}for (auto& it : vec) {if (!it.func1.empty() || it.addr1.empty() || it.file.empty()) {it.func2 = "(" + it.func1 + "+" + it.addr1 + ")";it.line = "??:?";continue;}std::string cmd = "addr2line " + it.addr1 + " -e " + it.file + " -f -C";FILE* p = popen(cmd.c_str(), "r");if (!p) {continue;}char buff[1024] = { 0 };int32_t res_line_count = 0;while (fgets(buff, sizeof(buff), p) != nullptr) {std::string str(buff);if (!str.empty() && str.back() == '\n') {str = str.substr(0, str.length() - 1);}if (res_line_count == 0) {it.func2 = str;} else if (res_line_count == 1) {it.line = str;}++res_line_count;}pclose(p);}int32_t index = 0;std::cout << "*** Exeception catched at " << now.tv_sec << "(unix time) ***" << std::endl;for (const auto& it : vec) {std::cout << " #" << index << " " << it.addr2 << " " << it.func2<< " at " << it.line << std::endl;++index;}#ifdef __clang__orig_cxa_throw(thrown_exception, typeifo, dest);#elif defined(__GNUC__)orig_cxa_throw(thrown_exception, pvtinfo, dest);#endif}
测试程序:hook_cxa_throw_test.cc
#include <iostream>#include <stdexcept>#include "hook_cxa_throw.h"#include <unistd.h>int mytest(){try{throw "mythrow char strings";}catch(const char* sz){std::cout << sz << "\n";}::sleep(1);return 0;}int main(int argc, char* argv[]){printf("\n");mytest();mytest();mytest();mytest();return 0;}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)project(trycatch_thread)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")add_executable(hook_cxa_throw_test hook_cxa_throw_test.cc hook_cxa_throw.cc)target_link_libraries(hook_cxa_throw_test pthread dl)