Diagnostics: Fix demangling (#1215)

Rename to better names
More comments
Less branches
This commit is contained in:
David Markowitz 2023-10-09 13:31:43 -07:00 committed by GitHub
parent 500ae4d6e5
commit e96fd56fbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 57 deletions

View File

@ -12,7 +12,7 @@ set(DCOMMON_SOURCES
"NiPoint3.cpp" "NiPoint3.cpp"
"NiQuaternion.cpp" "NiQuaternion.cpp"
"SHA512.cpp" "SHA512.cpp"
"Type.cpp" "Demangler.cpp"
"ZCompression.cpp" "ZCompression.cpp"
"BrickByBrickFix.cpp" "BrickByBrickFix.cpp"
"BinaryPathFinder.cpp" "BinaryPathFinder.cpp"

29
dCommon/Demangler.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "Demangler.h"
#ifdef __GNUG__
#include <cstdlib>
#include <cxxabi.h>
#include <memory>
#include <typeinfo>
std::string Demangler::Demangle(const char* name) {
// some arbitrary value to eliminate the compiler warning
// -4 is not a valid return value for __cxa_demangle so we'll use that.
int status = -4;
// __cxa_demangle requires that we free the returned char*
std::unique_ptr<char, void (*)(void*)> res{
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status == 0) ? res.get() : "";
}
#else // __GNUG__
// does nothing if not g++
std::string Demangler::Demangle(const char* name) {
return name;
}
#endif // __GNUG__

9
dCommon/Demangler.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <string>
namespace Demangler {
// Given a char* containing a mangled name, return a std::string containing the demangled name.
// If the function fails for any reason, it returns an empty string.
std::string Demangle(const char* name);
}

View File

@ -107,7 +107,7 @@ static void ErrorCallback(void* data, const char* msg, int errnum) {
} }
#endif #endif
#include "Type.h" #include "Demangler.h"
void GenerateDump() { void GenerateDump() {
std::string cmd = "sudo gcore " + std::to_string(getpid()); std::string cmd = "sudo gcore " + std::to_string(getpid());
@ -122,41 +122,43 @@ void CatchUnhandled(int sig) {
if (Diagnostics::GetProduceMemoryDump()) { if (Diagnostics::GetProduceMemoryDump()) {
GenerateDump(); GenerateDump();
} }
constexpr uint8_t MaxStackTrace = 32;
void* array[10]; void* array[MaxStackTrace];
size_t size; size_t size;
// get void*'s for all entries on the stack // get void*'s for all entries on the stack
size = backtrace(array, 10); size = backtrace(array, MaxStackTrace);
#if defined(__GNUG__) and defined(__dynamic) # if defined(__GNUG__)
// Loop through the returned addresses, and get the symbols to be demangled // Loop through the returned addresses, and get the symbols to be demangled
char** strings = backtrace_symbols(array, size); char** strings = backtrace_symbols(array, size);
// Print the stack trace // Print the stack trace
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name // Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]'
// and extract '_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress' from it to be demangled into a proper name
std::string functionName = strings[i]; std::string functionName = strings[i];
std::string::size_type start = functionName.find('('); std::string::size_type start = functionName.find('(');
std::string::size_type end = functionName.find('+'); std::string::size_type end = functionName.find('+');
if (start != std::string::npos && end != std::string::npos) { if (start != std::string::npos && end != std::string::npos) {
std::string demangled = functionName.substr(start + 1, end - start - 1); std::string demangled = functionName.substr(start + 1, end - start - 1);
demangled = demangle(functionName.c_str()); demangled = Demangler::Demangle(demangled.c_str());
if (demangled.empty()) { // If the demangled string is not empty, then we can replace the mangled string with the demangled one
Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str()); if (!demangled.empty()) {
} else { demangled.push_back('(');
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str()); demangled += functionName.substr(end);
functionName = demangled;
} }
} else {
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
} }
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
} }
#else # else // defined(__GNUG__)
backtrace_symbols_fd(array, size, STDOUT_FILENO); backtrace_symbols_fd(array, size, STDOUT_FILENO);
#endif # endif // defined(__GNUG__)
FILE* file = fopen(fileName.c_str(), "w+"); FILE* file = fopen(fileName.c_str(), "w+");
if (file != NULL) { if (file != NULL) {
@ -166,7 +168,7 @@ void CatchUnhandled(int sig) {
fclose(file); fclose(file);
} }
#else #else // __include_backtrace__
struct backtrace_state* state = backtrace_create_state( struct backtrace_state* state = backtrace_create_state(
Diagnostics::GetProcessFileName().c_str(), Diagnostics::GetProcessFileName().c_str(),
@ -177,7 +179,7 @@ void CatchUnhandled(int sig) {
struct bt_ctx ctx = { state, 0 }; struct bt_ctx ctx = { state, 0 };
Bt(state); Bt(state);
#endif #endif // __include_backtrace__
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -1,27 +0,0 @@
#include "Type.h"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res{
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status == 0) ? res.get() : name;
}
#else
// does nothing if not g++
std::string demangle(const char* name) {
return name;
}
#endif

View File

@ -1,12 +0,0 @@
#pragma once
#include <string>
#include <typeinfo>
std::string demangle(const char* name);
template <class T>
std::string type(const T& t) {
return demangle(typeid(t).name());
}