feat symbolize support mac
This commit is contained in:
parent
f97c1b7e0b
commit
c96cb23a3d
131
'
131
'
@ -1,131 +0,0 @@
|
|||||||
#include "sled/strings/utils.h"
|
|
||||||
#include <sstream>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace sled {
|
|
||||||
|
|
||||||
char
|
|
||||||
ToLower(char c)
|
|
||||||
{
|
|
||||||
return ::tolower(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
char
|
|
||||||
ToUpper(char c)
|
|
||||||
{
|
|
||||||
return ::toupper(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
ToLower(const std::string &str)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
for (auto &ch : str) { ss << ToLower(ch); }
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
ToUpper(const std::string &str)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
for (auto &ch : str) { ss << ToUpper(ch); }
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
StrJoin(const std::vector<std::string> &strings, const std::string &delim, bool skip_empty)
|
|
||||||
{
|
|
||||||
if (strings.empty()) { return ""; }
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
size_t i = 0;
|
|
||||||
while (skip_empty && i < strings.size() && strings[i].empty()) { ++i; }
|
|
||||||
if (i < strings.size()) { ss << strings[i++]; }
|
|
||||||
for (; i < strings.size(); ++i) {
|
|
||||||
if (skip_empty && strings[i].empty()) { continue; }
|
|
||||||
ss << delim << strings[i];
|
|
||||||
}
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string>
|
|
||||||
StrSplit(const std::string &str, const std::string &delim, bool skip_empty)
|
|
||||||
{
|
|
||||||
std::vector<std::string> result;
|
|
||||||
if (str.empty()) { return result; }
|
|
||||||
|
|
||||||
size_t start = 0;
|
|
||||||
size_t next_pos = str.find_first_of(delim, start);
|
|
||||||
while (next_pos != std::string::npos) {
|
|
||||||
if ((!skip_empty && next_pos == start) || next_pos > start) {
|
|
||||||
result.emplace_back(str.begin() + start, str.begin() + next_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!skip_empty) {
|
|
||||||
start = next_pos + 1;
|
|
||||||
next_pos = str.find_first_of(delim, start);
|
|
||||||
} else {
|
|
||||||
start = str.find_first_not_of(delim, next_pos);
|
|
||||||
if (start == std::string::npos) {
|
|
||||||
// all remaining characters are delimiters
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next_pos = str.find_first_of(delim, start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start < str.size()) { result.emplace_back(str.substr(start)); }
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
Trim(const std::string &str, const std::string &chars)
|
|
||||||
{
|
|
||||||
return TrimLeft(TrimRight(str, chars), chars);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
TrimLeft(const std::string &str, const std::string &chars)
|
|
||||||
{
|
|
||||||
size_t start = str.find_first_not_of(chars);
|
|
||||||
return start == std::string::npos ? "" : str.substr(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
TrimRight(const std::string &str, const std::string &chars)
|
|
||||||
{
|
|
||||||
size_t end = str.find_last_not_of(chars);
|
|
||||||
return end == std::string::npos ? "" : str.substr(0, end + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
EndsWith(const std::string &str, const std::string &suffix)
|
|
||||||
{
|
|
||||||
return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StartsWith(const std::string &str, const std::string &prefix)
|
|
||||||
{
|
|
||||||
return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
EndsWithIgnoreCase(const std::string &str, const std::string &suffix)
|
|
||||||
{
|
|
||||||
return EndsWith(ToLower(str), ToLower(suffix));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
StartsWithIgnoreCase(const std::string &str, const std::string &prefix)
|
|
||||||
{
|
|
||||||
return StartsWith(ToLower(str), ToLower(prefix));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
EqualsIgnoreCase(const std::string &lhs, const std::string &rhs)
|
|
||||||
{
|
|
||||||
return ToLower(lhs) == ToLower(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
}// namespace sled
|
|
@ -45,6 +45,7 @@ target_include_directories(sled PUBLIC src/ 3party/eigen 3party/inja
|
|||||||
target_sources(
|
target_sources(
|
||||||
sled
|
sled
|
||||||
PRIVATE src/sled/async/async.cc
|
PRIVATE src/sled/async/async.cc
|
||||||
|
src/sled/debugging/demangle.cc
|
||||||
src/sled/debugging/symbolize.cc
|
src/sled/debugging/symbolize.cc
|
||||||
src/sled/filesystem/path.cc
|
src/sled/filesystem/path.cc
|
||||||
src/sled/log/log.cc
|
src/sled/log/log.cc
|
||||||
|
2091
src/sled/debugging/demangle.cc
Normal file
2091
src/sled/debugging/demangle.cc
Normal file
File diff suppressed because it is too large
Load Diff
11
src/sled/debugging/demangle.h
Normal file
11
src/sled/debugging/demangle.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef SLED_DEBUGGING_DEMANGLE_H
|
||||||
|
#define SLED_DEBUGGING_DEMANGLE_H
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace sled {
|
||||||
|
bool Demangle(const char *mangled, char *out, size_t out_size);
|
||||||
|
std::string DemangleString(const char *mangled);
|
||||||
|
}// namespace sled
|
||||||
|
#endif// SLED_DEBUGGING_DEMANGLE_H
|
0
src/sled/debugging/demangle_test.cc
Normal file
0
src/sled/debugging/demangle_test.cc
Normal file
@ -11,15 +11,7 @@ Symbolize(const void *pc, char *out, int out_size)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
void
|
#include "symbolize_darwin.inc"
|
||||||
InitializeSymbolizer(const char *argv0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Symbolize(const void *pc, char *out, int out_size)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include "sled/debugging/symbolize_elf.inc"
|
#include "sled/debugging/symbolize_elf.inc"
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,6 +5,5 @@
|
|||||||
namespace sled {
|
namespace sled {
|
||||||
void InitializeSymbolizer(const char *argv0);
|
void InitializeSymbolizer(const char *argv0);
|
||||||
bool Symbolize(const void *pc, char *out, int out_size);
|
bool Symbolize(const void *pc, char *out, int out_size);
|
||||||
bool ReadAddrMap();
|
|
||||||
}// namespace sled
|
}// namespace sled
|
||||||
#endif// SLED_DEBUGGING_SYMBOLIZE_H
|
#endif// SLED_DEBUGGING_SYMBOLIZE_H
|
||||||
|
83
src/sled/debugging/symbolize_darwin.inc
Normal file
83
src/sled/debugging/symbolize_darwin.inc
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include "sled/debugging/demangle.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <execinfo.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace sled {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
GetSymbolString(const std::string &backtrace_line)
|
||||||
|
{
|
||||||
|
// Example Backtrace lines:
|
||||||
|
// 0 libimaging_shared.dylib 0x018c152a
|
||||||
|
// _ZNSt11_Deque_baseIN3nik7mediadb4PageESaIS2_EE17_M_initialize_mapEm + 3478
|
||||||
|
//
|
||||||
|
// or
|
||||||
|
// 0 libimaging_shared.dylib 0x0000000001895c39
|
||||||
|
// _ZN3nik4util19register_shared_ptrINS_3gpu7TextureEEEvPKvS5_ + 39
|
||||||
|
//
|
||||||
|
// or
|
||||||
|
// 0 mysterious_app 0x0124000120120009 main + 17
|
||||||
|
auto address_pos = backtrace_line.find(" 0x");
|
||||||
|
if (address_pos == std::string::npos) return std::string();
|
||||||
|
std::string symbol_view = backtrace_line.substr(address_pos + 1);
|
||||||
|
|
||||||
|
auto space_pos = symbol_view.find(" ");
|
||||||
|
if (space_pos == std::string::npos) return std::string();
|
||||||
|
symbol_view = symbol_view.substr(space_pos + 1);// to mangled symbol
|
||||||
|
|
||||||
|
auto plus_pos = symbol_view.find(" + ");
|
||||||
|
if (plus_pos == std::string::npos) return std::string();
|
||||||
|
symbol_view = symbol_view.substr(0, plus_pos);// strip remainng
|
||||||
|
|
||||||
|
return std::string(symbol_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace
|
||||||
|
|
||||||
|
void
|
||||||
|
InitializeSymbolizer(const char *argv0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Symbolize(const void *pc, char *out, int out_size)
|
||||||
|
{
|
||||||
|
if (out_size <= 0 || pc == nullptr) {
|
||||||
|
out = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This allocates a char* array.
|
||||||
|
char **frame_strings = backtrace_symbols(const_cast<void **>(&pc), 1);
|
||||||
|
|
||||||
|
if (frame_strings == nullptr) return false;
|
||||||
|
|
||||||
|
std::string symbol = GetSymbolString(frame_strings[0]);
|
||||||
|
free(frame_strings);
|
||||||
|
|
||||||
|
char tmp_buf[1024];
|
||||||
|
if (Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
|
||||||
|
size_t len = strlen(tmp_buf);
|
||||||
|
if (len + 1 <= static_cast<size_t>(out_size)) {// +1 for '\0'
|
||||||
|
assert(len < sizeof(tmp_buf));
|
||||||
|
memmove(out, tmp_buf, len + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strncpy(out, symbol.c_str(), static_cast<size_t>(out_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out[out_size - 1] != '\0') {
|
||||||
|
// strncpy() does not '\0' terminate when it truncates.
|
||||||
|
static constexpr char kEllipsis[] = "...";
|
||||||
|
size_t ellipsis_size = std::min(sizeof(kEllipsis) - 1, static_cast<size_t>(out_size) - 1);
|
||||||
|
memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
|
||||||
|
out[out_size - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}// namespace sled
|
@ -6,6 +6,17 @@ void
|
|||||||
TestFunc1()
|
TestFunc1()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
class Class {
|
||||||
|
public:
|
||||||
|
Class() {}
|
||||||
|
|
||||||
|
void MemberFunc1() {}
|
||||||
|
|
||||||
|
int MemberFunc2() { return 0; }
|
||||||
|
|
||||||
|
int MemberFunc3(int) { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
static char try_symbolize_buffer[4096];
|
static char try_symbolize_buffer[4096];
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
@ -26,13 +37,36 @@ TrySymbolize(void *pc)
|
|||||||
return TrySymbolizeWithLimit(pc, 4096);
|
return TrySymbolizeWithLimit(pc, 4096);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST(Symbolize, base)
|
template<typename TRet, typename... Args>
|
||||||
// {
|
void *
|
||||||
// char buf[1024];
|
void_cast(TRet (*fn)(Args...))
|
||||||
// EXPECT_EQ("TestFunc1", TrySymbolize((void *) &TestFunc1));
|
{
|
||||||
// }
|
return reinterpret_cast<void *>(fn);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Symbolize, ReadAddrMap) { sled::ReadAddrMap(); }
|
template<typename TClass, typename TRet, typename... Args>
|
||||||
|
void *
|
||||||
|
void_cast(TRet (TClass::*mem_func)(Args...))
|
||||||
|
{
|
||||||
|
|
||||||
|
union {
|
||||||
|
void *void_casted;
|
||||||
|
TRet (TClass::*p)(Args...);
|
||||||
|
};
|
||||||
|
|
||||||
|
p = mem_func;
|
||||||
|
return void_casted;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Symbolize, base)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
EXPECT_STREQ("TestFunc1()", TrySymbolize(void_cast(TestFunc1)));
|
||||||
|
EXPECT_STREQ("Class::MemberFunc1()", TrySymbolize(void_cast(&Class::MemberFunc1)));
|
||||||
|
EXPECT_STREQ("Class::MemberFunc2()", TrySymbolize(void_cast(&Class::MemberFunc2)));
|
||||||
|
EXPECT_STREQ("Class::MemberFunc3()", TrySymbolize(void_cast(&Class::MemberFunc3)));
|
||||||
|
EXPECT_STREQ("TrySymbolizeWithLimit()", TrySymbolize(void_cast(&TrySymbolizeWithLimit)));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
|
Loading…
Reference in New Issue
Block a user