Skip to content

Commit 9b9b9f7

Browse files
committed
feat(crashreporter): Call Stack
1 parent 2675f34 commit 9b9b9f7

30 files changed

+27188
-6556
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"cinttypes": "cpp",
7979
"typeindex": "cpp",
8080
"typeinfo": "cpp",
81-
"variant": "cpp"
81+
"variant": "cpp",
82+
"expected": "cpp"
8283
}
8384
}

src/commands/Command.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#include "Command.h"
22

3+
#include "../crashreporter/CallStack.h"
34
#include "../plugins/PluginManager.h"
45

56
Command::~Command()
67
{
7-
Plugin *plugin = g_pluginManager->FetchPlugin(this->m_pluginName);
8+
Plugin* plugin = g_pluginManager->FetchPlugin(this->m_pluginName);
89
if (!plugin)
910
return;
1011

@@ -16,10 +17,11 @@ Command::~Command()
1617

1718
void Command::Execute(int slot, std::vector<std::string> args, bool silent, std::string prefix)
1819
{
20+
REGISTER_CALLSTACK(this->m_pluginName, string_format("Command::Execute(command_name=\"%s\",slot=%d,args=\"%s\",silent=%d,prefix=\"%s\")", this->m_commandName.c_str(), slot, implode(args, " ").c_str(), silent, prefix.c_str()));
1921
if (this->m_funcPtr == nullptr)
2022
return;
2123

22-
Plugin *plugin = g_pluginManager->FetchPlugin(this->m_pluginName);
24+
Plugin* plugin = g_pluginManager->FetchPlugin(this->m_pluginName);
2325
if (!plugin)
2426
return;
2527

src/crashreporter/CallStack.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "CallStack.h"
2+
#include "../utils/utils.h"
3+
4+
std::string CallStack::RegisterPluginCallstack(std::string plugin_name, std::string stackMsg)
5+
{
6+
std::string stackID = get_uuid();
7+
if (callStacks.find(plugin_name) == callStacks.end())
8+
callStacks.insert({ plugin_name, {} });
9+
10+
while (callStacks[plugin_name].find(stackID) != callStacks[plugin_name].end())
11+
stackID = get_uuid();
12+
13+
callStacks[plugin_name].insert({ stackID, stackMsg });
14+
15+
return stackID;
16+
}
17+
void CallStack::UnregisterPluginCallstack(std::string plugin_name, std::string stackID)
18+
{
19+
if (callStacks.find(plugin_name) == callStacks.end()) return;
20+
if (callStacks[plugin_name].find(stackID) == callStacks[plugin_name].end()) return;
21+
22+
callStacks[plugin_name].erase(stackID);
23+
}
24+
25+
std::unordered_map<std::string, std::string> CallStack::GetPluginCallstack(std::string plugin_name)
26+
{
27+
if (callStacks.find(plugin_name) == callStacks.end()) return {};
28+
29+
return callStacks[plugin_name];
30+
}

src/crashreporter/CallStack.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef _callstack_h
2+
#define _callstack_h
3+
4+
#include <string>
5+
#include <map>
6+
#include <unordered_map>
7+
#include "RegisterCallStack.h"
8+
9+
#define REGISTER_CALLSTACK(plugin_name, stack_str) RegisterCallStack OUIERGBNHI9U43HBG98734VHBW9(plugin_name, stack_str)
10+
11+
class CallStack
12+
{
13+
private:
14+
std::map<std::string, std::unordered_map<std::string, std::string>> callStacks;
15+
public:
16+
CallStack() = default;
17+
18+
std::string RegisterPluginCallstack(std::string plugin_name, std::string stackMsg);
19+
void UnregisterPluginCallstack(std::string plugin_name, std::string stackID);
20+
21+
std::unordered_map<std::string, std::string> GetPluginCallstack(std::string plugin_name);
22+
};
23+
24+
extern CallStack* g_callStack;
25+
26+
#endif

src/crashreporter/CrashReport.cpp

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,60 +23,62 @@ bool BeginCrashListener() { return true; }
2323
#include "../files/Files.h"
2424
#include "../common.h"
2525
#include "../entrypoint.h"
26+
#include "../plugins/PluginManager.h"
27+
#include "CallStack.h"
2628

2729
std::string startup_cmd = "None";
2830

29-
const char *ws = " \t\n\r\f\v";
31+
const char* ws = " \t\n\r\f\v";
3032

3133
// trim from end of string (right)
32-
inline std::string &rtrim(std::string &s, const char *t = ws)
34+
inline std::string& rtrim(std::string& s, const char* t = ws)
3335
{
3436
s.erase(s.find_last_not_of(t) + 1);
3537
return s;
3638
}
3739

3840
// trim from beginning of string (left)
39-
inline std::string &ltrim(std::string &s, const char *t = ws)
41+
inline std::string& ltrim(std::string& s, const char* t = ws)
4042
{
4143
s.erase(0, s.find_first_not_of(t));
4244
return s;
4345
}
4446

4547
// trim from both ends of string (right then left)
46-
inline std::string &trim(std::string &s, const char *t = ws)
48+
inline std::string& trim(std::string& s, const char* t = ws)
4749
{
4850
return ltrim(rtrim(s, t), t);
4951
}
5052

5153
std::string BacktraceRaw(int skip = 1)
5254
{
53-
void *callstack[128];
55+
void* callstack[128];
5456
const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
5557
char buf[1024];
5658
int nFrames = backtrace(callstack, nMaxFrames);
57-
char **symbols = backtrace_symbols(callstack, nFrames);
59+
char** symbols = backtrace_symbols(callstack, nFrames);
5860

5961
std::ostringstream trace_buf;
6062
for (int i = skip; i < nFrames; i++)
6163
{
6264
Dl_info info;
6365
if (dladdr(callstack[i], &info) && info.dli_sname)
6466
{
65-
char *demangled = NULL;
67+
char* demangled = NULL;
6668
int status = -1;
6769
if (info.dli_sname[0] == '_')
6870
demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
6971
snprintf(buf, sizeof(buf), "%02d. %p %s + %zd\n",
70-
i - 1, callstack[i],
71-
status == 0 ? demangled : info.dli_sname == 0 ? symbols[i]
72-
: info.dli_sname,
73-
(char *)callstack[i] - (char *)info.dli_saddr);
72+
i - 1, callstack[i],
73+
status == 0 ? demangled : info.dli_sname == 0 ? symbols[i]
74+
: info.dli_sname,
75+
(char*)callstack[i] - (char*)info.dli_saddr);
7476
free(demangled);
7577
}
7678
else
7779
{
7880
snprintf(buf, sizeof(buf), "%02d. %p %s\n",
79-
i - 1, callstack[i], symbols[i]);
81+
i - 1, callstack[i], symbols[i]);
8082
}
8183
trace_buf << buf;
8284
}
@@ -97,11 +99,11 @@ TextTable GetBacktrace()
9799
backtraceTable.add(" Address ");
98100
backtraceTable.endOfRow();
99101

100-
void *callstack[128];
102+
void* callstack[128];
101103
const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
102104
char buf[1024];
103105
int nFrames = backtrace(callstack, nMaxFrames);
104-
char **symbols = backtrace_symbols(callstack, nFrames);
106+
char** symbols = backtrace_symbols(callstack, nFrames);
105107

106108
for (int i = 2; i < nFrames; i++)
107109
{
@@ -113,13 +115,13 @@ TextTable GetBacktrace()
113115
Dl_info info;
114116
if (dladdr(callstack[i], &info) && info.dli_sname)
115117
{
116-
char *demangled = NULL;
118+
char* demangled = NULL;
117119
int status = -1;
118120
if (info.dli_sname[0] == '_')
119121
demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
120122

121123
std::string funcName = (status == 0 ? demangled : info.dli_sname == 0 ? "-"
122-
: info.dli_sname);
124+
: info.dli_sname);
123125

124126
backtraceTable.add(string_format(" %s ", (funcName.size() > 36 ? (funcName.substr(0, 33) + "...") : funcName).c_str()));
125127
free(demangled);
@@ -136,11 +138,27 @@ TextTable GetBacktrace()
136138
return backtraceTable;
137139
}
138140

141+
std::string WritePluginsCallStack()
142+
{
143+
std::string callstacks = "";
144+
for (Plugin* plugin : g_pluginManager->GetPluginsList()) {
145+
auto callstack = g_callStack->GetPluginCallstack(plugin->GetName());
146+
if (callstack.size() > 0) {
147+
callstacks += string_format("Plugin %s:\n", plugin->GetName().c_str());
148+
for (auto it = callstack.begin(); it != callstack.end(); ++it)
149+
callstacks += string_format(" - %s\n", it->second.c_str());
150+
151+
callstacks += "\n";
152+
}
153+
}
154+
return callstacks;
155+
}
156+
139157
void signal_handler(int signumber)
140158
{
141159
try
142160
{
143-
void *tracePointers[20];
161+
void* tracePointers[20];
144162
size_t count = backtrace(tracePointers, 20);
145163

146164
PLUGIN_PRINTF("Crash Reporter", "A crash has occured and a dump has been created:\n");
@@ -153,10 +171,10 @@ void signal_handler(int signumber)
153171
if (Files::ExistsPath(file_path))
154172
Files::Delete(file_path);
155173

156-
Files::Append(file_path, string_format("================================\nCommand: %s\nMap: %s\n================================\n\n%s", startup_cmd.c_str(), engine->GetServerGlobals() ? engine->GetServerGlobals()->mapname.ToCStr() : "None", backtraceData.c_str()), false);
174+
Files::Append(file_path, string_format("================================\nCommand: %s\nMap: %s\n================================\n\n%s\n%s", startup_cmd.c_str(), engine->GetServerGlobals() ? engine->GetServerGlobals()->mapname.ToCStr() : "None", backtraceData.c_str(), WritePluginsCallStack().c_str()), false);
157175
PLUGIN_PRINTF("Crash Reporter", "A dump log file has been created at: %s\n", file_path.c_str());
158176
}
159-
catch (const std::runtime_error &e)
177+
catch (const std::runtime_error& e)
160178
{
161179
PLUGIN_PRINTF("Crash Reporter", "Error crash handling: %s\n", e.what());
162180
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include "CallStack.h"
2+
#include "RegisterCallStack.h"
3+
4+
RegisterCallStack::RegisterCallStack(std::string plugin_name, std::string stack_msg)
5+
{
6+
this->plugin_name = plugin_name;
7+
this->id = g_callStack->RegisterPluginCallstack(plugin_name, stack_msg);
8+
}
9+
RegisterCallStack::~RegisterCallStack()
10+
{
11+
g_callStack->UnregisterPluginCallstack(plugin_name, this->id);
12+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef _registercallstack_h
2+
#define _registercallstack_h
3+
4+
#include <string>
5+
6+
class RegisterCallStack
7+
{
8+
private:
9+
std::string plugin_name;
10+
std::string id;
11+
12+
public:
13+
RegisterCallStack(std::string plugin_name, std::string stack_msg);
14+
~RegisterCallStack();
15+
};
16+
17+
#endif

0 commit comments

Comments
 (0)