Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/rapidyaml/src/c4/error.cpp
4260 views
1
#include "c4/error.hpp"
2
3
#include <stdlib.h>
4
#include <stdio.h>
5
#include <stdarg.h>
6
7
#define C4_LOGF_ERR(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
8
#define C4_LOGF_WARN(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
9
#define C4_LOGP(msg, ...) printf(msg)
10
11
#if defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
12
# include "c4/windows.hpp"
13
#elif defined(C4_PS4)
14
# include <libdbg.h>
15
#elif defined(C4_UNIX) || defined(C4_LINUX)
16
# include <sys/stat.h>
17
# include <cstring>
18
# include <fcntl.h>
19
#elif defined(C4_MACOS) || defined(C4_IOS)
20
# include <assert.h>
21
# include <stdbool.h>
22
# include <sys/types.h>
23
# include <sys/sysctl.h>
24
#endif
25
// the amalgamation tool is dumb and was omitting this include under MACOS.
26
// So do it only once:
27
#if defined(C4_UNIX) || defined(C4_LINUX) || defined(C4_MACOS) || defined(C4_IOS)
28
# include <unistd.h>
29
#endif
30
31
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
32
# include <exception>
33
#endif
34
35
#ifdef __clang__
36
# pragma clang diagnostic push
37
# pragma clang diagnostic ignored "-Wformat-nonliteral"
38
# pragma clang diagnostic ignored "-Wold-style-cast"
39
#elif defined(__GNUC__)
40
# pragma GCC diagnostic push
41
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
42
# pragma GCC diagnostic ignored "-Wold-style-cast"
43
#endif
44
45
46
//-----------------------------------------------------------------------------
47
namespace c4 {
48
49
static error_flags s_error_flags = ON_ERROR_DEFAULTS;
50
static error_callback_type s_error_callback = nullptr;
51
52
//-----------------------------------------------------------------------------
53
54
error_flags get_error_flags()
55
{
56
return s_error_flags;
57
}
58
void set_error_flags(error_flags flags)
59
{
60
s_error_flags = flags;
61
}
62
63
error_callback_type get_error_callback()
64
{
65
return s_error_callback;
66
}
67
/** Set the function which is called when an error occurs. */
68
void set_error_callback(error_callback_type cb)
69
{
70
s_error_callback = cb;
71
}
72
73
//-----------------------------------------------------------------------------
74
75
void handle_error(srcloc where, const char *fmt, ...)
76
{
77
char buf[1024];
78
size_t msglen = 0;
79
if(s_error_flags & (ON_ERROR_LOG|ON_ERROR_CALLBACK))
80
{
81
va_list args;
82
va_start(args, fmt);
83
int ilen = vsnprintf(buf, sizeof(buf), fmt, args); // ss.vprintf(fmt, args);
84
va_end(args);
85
msglen = ilen >= 0 && ilen < (int)sizeof(buf) ? static_cast<size_t>(ilen) : sizeof(buf)-1;
86
}
87
88
if(s_error_flags & ON_ERROR_LOG)
89
{
90
C4_LOGF_ERR("\n");
91
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
92
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
93
C4_LOGF_ERR("%s:%d: ERROR here: %s\n", where.file, where.line, where.func);
94
#elif defined(C4_ERROR_SHOWS_FILELINE)
95
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
96
#elif ! defined(C4_ERROR_SHOWS_FUNC)
97
C4_LOGF_ERR("ERROR: %s\n", buf);
98
#endif
99
}
100
101
if(s_error_flags & ON_ERROR_CALLBACK)
102
{
103
if(s_error_callback)
104
{
105
s_error_callback(buf, msglen/*ss.c_strp(), ss.tellp()*/);
106
}
107
}
108
109
if(s_error_flags & ON_ERROR_ABORT)
110
{
111
abort();
112
}
113
114
if(s_error_flags & ON_ERROR_THROW)
115
{
116
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
117
throw Exception(buf);
118
#else
119
abort();
120
#endif
121
}
122
}
123
124
//-----------------------------------------------------------------------------
125
126
void handle_warning(srcloc where, const char *fmt, ...)
127
{
128
va_list args;
129
char buf[1024]; //sstream<c4::string> ss;
130
va_start(args, fmt);
131
vsnprintf(buf, sizeof(buf), fmt, args);
132
va_end(args);
133
C4_LOGF_WARN("\n");
134
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
135
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf/*ss.c_strp()*/);
136
C4_LOGF_WARN("%s:%d: WARNING: here: %s\n", where.file, where.line, where.func);
137
#elif defined(C4_ERROR_SHOWS_FILELINE)
138
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf/*ss.c_strp()*/);
139
#elif ! defined(C4_ERROR_SHOWS_FUNC)
140
C4_LOGF_WARN("WARNING: %s\n", buf/*ss.c_strp()*/);
141
#endif
142
//c4::log.flush();
143
}
144
145
//-----------------------------------------------------------------------------
146
bool is_debugger_attached()
147
{
148
#if defined(C4_UNIX) || defined(C4_LINUX)
149
static bool first_call = true;
150
static bool first_call_result = false;
151
if(first_call)
152
{
153
first_call = false;
154
//! @see http://stackoverflow.com/questions/3596781/how-to-detect-if-the-current-process-is-being-run-by-gdb
155
//! (this answer: http://stackoverflow.com/a/24969863/3968589 )
156
char buf[1024] = "";
157
158
int status_fd = open("/proc/self/status", O_RDONLY);
159
if (status_fd == -1)
160
{
161
return 0;
162
}
163
164
ssize_t num_read = ::read(status_fd, buf, sizeof(buf));
165
166
if (num_read > 0)
167
{
168
static const char TracerPid[] = "TracerPid:";
169
char *tracer_pid;
170
171
if(num_read < 1024)
172
{
173
buf[num_read] = 0;
174
}
175
tracer_pid = strstr(buf, TracerPid);
176
if (tracer_pid)
177
{
178
first_call_result = !!::atoi(tracer_pid + sizeof(TracerPid) - 1);
179
}
180
}
181
}
182
return first_call_result;
183
#elif defined(C4_PS4)
184
return (sceDbgIsDebuggerAttached() != 0);
185
#elif defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
186
return IsDebuggerPresent() != 0;
187
#elif defined(C4_MACOS) || defined(C4_IOS)
188
// https://stackoverflow.com/questions/2200277/detecting-debugger-on-mac-os-x
189
// Returns true if the current process is being debugged (either
190
// running under the debugger or has a debugger attached post facto).
191
int junk;
192
int mib[4];
193
struct kinfo_proc info;
194
size_t size;
195
196
// Initialize the flags so that, if sysctl fails for some bizarre
197
// reason, we get a predictable result.
198
199
info.kp_proc.p_flag = 0;
200
201
// Initialize mib, which tells sysctl the info we want, in this case
202
// we're looking for information about a specific process ID.
203
204
mib[0] = CTL_KERN;
205
mib[1] = KERN_PROC;
206
mib[2] = KERN_PROC_PID;
207
mib[3] = getpid();
208
209
// Call sysctl.
210
211
size = sizeof(info);
212
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
213
assert(junk == 0);
214
215
// We're being debugged if the P_TRACED flag is set.
216
return ((info.kp_proc.p_flag & P_TRACED) != 0);
217
#else
218
return false;
219
#endif
220
} // is_debugger_attached()
221
222
} // namespace c4
223
224
225
#ifdef __clang__
226
# pragma clang diagnostic pop
227
#elif defined(__GNUC__)
228
# pragma GCC diagnostic pop
229
#endif
230
231