Cogs.Core
DebugUtils.cpp
1#include "DebugUtils.h"
2
3#if defined( _WIN32 )
4 #define WIN32_LEAN_AND_MEAN
5 #include <Windows.h>
6 #include <dbghelp.h>
7#endif
8
9#if defined(_WIN32)
10
12 return IsDebuggerPresent();
13}
14
15std::string Cogs::getCallstack() {
16 std::string callstack;
17 void* addresses[200];
18 int noofaddresses = CaptureStackBackTrace(0, 199, addresses, nullptr);
19 char buffer[1000];
20
21 for(int idx = 0; idx < noofaddresses; ++idx) {
22 char local[sizeof(IMAGEHLP_SYMBOL64) + 992];
23 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(local);
24 DWORD64 realaddr = reinterpret_cast<DWORD64>(addresses[idx]) - 1;
25 DWORD64 symdisp;
26
27 buffer[0] = 0;
28
29 memset(local, 0, sizeof(local));
30
31 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
32 symbol->MaxNameLength = sizeof(local) - sizeof(IMAGEHLP_SYMBOL64);
33
34 if(SymGetSymFromAddr64(GetCurrentProcess(), realaddr, &symdisp, symbol) || (!GetLastError() && symbol->Name[0])) {
35 char symname[4096];
36 DWORD linedisp;
37 IMAGEHLP_LINE64 line;
38
39 UnDecorateSymbolName(symbol->Name, symname, sizeof(symname), UNDNAME_COMPLETE);
40
41 memset(&line, 0, sizeof(line));
42 line.SizeOfStruct = sizeof(line);
43
44 if(SymGetLineFromAddr64(GetCurrentProcess(), realaddr, &linedisp, &line)) {
45 sprintf(buffer, "%p - %s (%s:%d)\n", reinterpret_cast<void*>(realaddr), symname, line.FileName, line.LineNumber);
46 }
47 else {
48 sprintf(buffer, "%p - %s\n", reinterpret_cast<void*>(realaddr), symname);
49 }
50 }
51 else {
52 sprintf(buffer, "%p - (Unknown)\n", reinterpret_cast<void*>(realaddr));
53 }
54 callstack += buffer;
55 }
56 return callstack;
57}
58
59#elif defined(__linux__)
60
61#include <cxxabi.h> // Needs libc++-dev on Ubuntu.
62#include <dlfcn.h>
63#include <fcntl.h>
64#include <unistd.h>
65#include <unwind.h>
66
68 char buf[4096];
69 int fd = open("/proc/self/status", O_RDONLY);
70
71 if (fd >= 0) {
72 ssize_t bytesread = read(fd, buf, sizeof(buf) - 1);
73
74 close(fd);
75
76 if (bytesread > 0) {
77 buf[bytesread] = 0;
78
79 constexpr char tracerPidString[] = "TracerPid:";
80 const char* ptr = strstr(buf, tracerPidString);
81
82 if (ptr) {
83 ptr += sizeof(tracerPidString) - 1;
84
85 for (const char* end = buf + bytesread; ptr <= end; ++ptr) {
86 if (!isspace(*ptr)) {
87 return ::isdigit(*ptr) != 0 && *ptr != '0';
88 }
89 }
90 }
91 }
92 }
93 return false;
94}
95
96struct BacktraceState {
97 void** current;
98 void** end;
99};
100
101_Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg)
102{
103 BacktraceState* state = static_cast<BacktraceState*>(arg);
104 uintptr_t pc = _Unwind_GetIP(context);
105
106 if (pc) {
107 if (state->current == state->end) {
108 return _URC_END_OF_STACK;
109 }
110 *state->current++ = reinterpret_cast<void*>(pc);
111 }
112 return _URC_NO_REASON;
113}
114
115std::string Cogs::getCallstack() {
116 std::string callstack;
117 void* addresses[200];
118 BacktraceState state = {addresses, addresses + 200};
119
120 _Unwind_Backtrace(&unwindCallback, &state);
121
122 for (int idx = 0, addrCount = static_cast<int>(state.current - addresses); idx < addrCount; ++idx) {
123 Dl_info info;
124 char hexAddr[21] = { '0', 'x', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', ':', ' ', 0 };
125 uint64_t addrValue = reinterpret_cast<uint64_t>(addresses[idx]);
126
127 for (int idx = 18; addrValue; addrValue >>= 4) {
128 hexAddr[--idx] = "0123456789ABCDEF"[addrValue & 0x0F];
129 }
130
131 callstack += hexAddr;
132
133 if (dladdr(addresses[idx], &info)) {
134 if (info.dli_sname) {
135 int status;
136 char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
137
138 if (demangled) {
139 if (status == 0) {
140 callstack += demangled;
141 }
142 free(demangled);
143 }
144 else {
145 callstack += info.dli_sname;
146 }
147 }
148 else if (info.dli_fname) {
149 callstack += info.dli_fname;
150 }
151 }
152 callstack += "\n";
153 }
154 return callstack;
155}
156
157#elif defined(__APPLE__)
158
159#include <assert.h>
160#include <stdbool.h>
161#include <unistd.h>
162#include <sys/types.h>
163#include <sys/sysctl.h>
164
166 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
167 struct kinfo_proc info = {};
168 size_t size = sizeof(info);
169 int junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0);
170
171 assert(junk == 0);
172 return info.kp_proc.p_flag & P_TRACED;
173}
174
175std::string Cogs::getCallstack() {
176 return "Sorry, callstack retrieval not implemented for Apple platforms.";
177}
178
179#endif
COGSFOUNDATION_API bool isBeingDebugged()
Return true if the application is running under a debugger.
COGSFOUNDATION_API std::string getCallstack()
Returns the current callstack as a string.