relay_event_normalization/mechanism.rs
1use relay_event_schema::processor::{self, ProcessingAction};
2use relay_event_schema::protocol::{Event, Mechanism, OsContext};
3use relay_protocol::{Annotated, Error};
4
5fn get_errno_name(errno: i64, os_hint: OsHint) -> Option<&'static str> {
6 Some(match os_hint {
7 OsHint::Linux => match errno {
8 1 => "EPERM", // Operation not permitted
9 2 => "ENOENT", // No such file or directory
10 3 => "ESRCH", // No such process
11 4 => "EINTR", // Interrupted system call
12 5 => "EIO", // I/O error
13 6 => "ENXIO", // No such device or address
14 7 => "E2BIG", // Argument list too long
15 8 => "ENOEXEC", // Exec format error
16 9 => "EBADF", // Bad file number
17 10 => "ECHILD", // No child processes
18 11 => "EAGAIN", // Try again
19 12 => "ENOMEM", // Out of memory
20 13 => "EACCES", // Permission denied
21 14 => "EFAULT", // Bad address
22 15 => "ENOTBLK", // Block device required
23 16 => "EBUSY", // Device or resource busy
24 17 => "EEXIST", // File exists
25 18 => "EXDEV", // Cross-device link
26 19 => "ENODEV", // No such device
27 20 => "ENOTDIR", // Not a directory
28 21 => "EISDIR", // Is a directory
29 22 => "EINVAL", // Invalid argument
30 23 => "ENFILE", // File table overflow
31 24 => "EMFILE", // Too many open files
32 25 => "ENOTTY", // Not a typewriter
33 26 => "ETXTBSY", // Text file busy
34 27 => "EFBIG", // File too large
35 28 => "ENOSPC", // No space left on device
36 29 => "ESPIPE", // Illegal seek
37 30 => "EROFS", // Read-only file system
38 31 => "EMLINK", // Too many links
39 32 => "EPIPE", // Broken pipe
40 33 => "EDOM", // Math argument out of domain of func
41 34 => "ERANGE", // Math result not representable
42
43 35 => "EDEADLK", // Resource deadlock would occur
44 36 => "ENAMETOOLONG", // File name too long
45 37 => "ENOLCK", // No record locks available
46
47 38 => "ENOSYS", // Invalid system call number
48
49 39 => "ENOTEMPTY", // Directory not empty
50 40 => "ELOOP", // Too many symbolic links encountered
51 42 => "ENOMSG", // No message of desired type
52 43 => "EIDRM", // Identifier removed
53 44 => "ECHRNG", // Channel number out of range
54 45 => "EL2NSYNC", // Level 2 not synchronized
55 46 => "EL3HLT", // Level 3 halted
56 47 => "EL3RST", // Level 3 reset
57 48 => "ELNRNG", // Link number out of range
58 49 => "EUNATCH", // Protocol driver not attached
59 50 => "ENOCSI", // No CSI structure available
60 51 => "EL2HLT", // Level 2 halted
61 52 => "EBADE", // Invalid exchange
62 53 => "EBADR", // Invalid request descriptor
63 54 => "EXFULL", // Exchange full
64 55 => "ENOANO", // No anode
65 56 => "EBADRQC", // Invalid request code
66 57 => "EBADSLT", // Invalid slot
67
68 59 => "EBFONT", // Bad font file format
69 60 => "ENOSTR", // Device not a stream
70 61 => "ENODATA", // No data available
71 62 => "ETIME", // Timer expired
72 63 => "ENOSR", // Out of streams resources
73 64 => "ENONET", // Machine is not on the network
74 65 => "ENOPKG", // Package not installed
75 66 => "EREMOTE", // Object is remote
76 67 => "ENOLINK", // Link has been severed
77 68 => "EADV", // Advertise error
78 69 => "ESRMNT", // Srmount error
79 70 => "ECOMM", // Communication error on send
80 71 => "EPROTO", // Protocol error
81 72 => "EMULTIHOP", // Multihop attempted
82 73 => "EDOTDOT", // RFS specific error
83 74 => "EBADMSG", // Not a data message
84 75 => "EOVERFLOW", // Value too large for defined data type
85 76 => "ENOTUNIQ", // Name not unique on network
86 77 => "EBADFD", // File descriptor in bad state
87 78 => "EREMCHG", // Remote address changed
88 79 => "ELIBACC", // Can not access a needed shared library
89 80 => "ELIBBAD", // Accessing a corrupted shared library
90 81 => "ELIBSCN", // .lib section in a.out corrupted
91 82 => "ELIBMAX", // Attempting to link in too many shared libraries
92 83 => "ELIBEXEC", // Cannot exec a shared library directly
93 84 => "EILSEQ", // Illegal byte sequence
94 85 => "ERESTART", // Interrupted system call should be restarted
95 86 => "ESTRPIPE", // Streams pipe error
96 87 => "EUSERS", // Too many users
97 88 => "ENOTSOCK", // Socket operation on non-socket
98 89 => "EDESTADDRREQ", // Destination address required
99 90 => "EMSGSIZE", // Message too long
100 91 => "EPROTOTYPE", // Protocol wrong type for socket
101 92 => "ENOPROTOOPT", // Protocol not available
102 93 => "EPROTONOSUPPORT", // Protocol not supported
103 94 => "ESOCKTNOSUPPORT", // Socket type not supported
104 95 => "EOPNOTSUPP", // Operation not supported on transport endpoint
105 96 => "EPFNOSUPPORT", // Protocol family not supported
106 97 => "EAFNOSUPPORT", // Address family not supported by protocol
107 98 => "EADDRINUSE", // Address already in use
108 99 => "EADDRNOTAVAIL", // Cannot assign requested address
109 100 => "ENETDOWN", // Network is down
110 101 => "ENETUNREACH", // Network is unreachable
111 102 => "ENETRESET", // Network dropped connection because of reset
112 103 => "ECONNABORTED", // Software caused connection abort
113 104 => "ECONNRESET", // Connection reset by peer
114 105 => "ENOBUFS", // No buffer space available
115 106 => "EISCONN", // Transport endpoint is already connected
116 107 => "ENOTCONN", // Transport endpoint is not connected
117 108 => "ESHUTDOWN", // Cannot send after transport endpoint shutdown
118 109 => "ETOOMANYREFS", // Too many references: cannot splice
119 110 => "ETIMEDOUT", // Connection timed out
120 111 => "ECONNREFUSED", // Connection refused
121 112 => "EHOSTDOWN", // Host is down
122 113 => "EHOSTUNREACH", // No route to host
123 114 => "EALREADY", // Operation already in progress
124 115 => "EINPROGRESS", // Operation now in progress
125 116 => "ESTALE", // Stale file handle
126 117 => "EUCLEAN", // Structure needs cleaning
127 118 => "ENOTNAM", // Not a XENIX named type file
128 119 => "ENAVAIL", // No XENIX semaphores available
129 120 => "EISNAM", // Is a named type file
130 121 => "EREMOTEIO", // Remote I/O error
131 122 => "EDQUOT", // Quota exceeded
132
133 123 => "ENOMEDIUM", // No medium found
134 124 => "EMEDIUMTYPE", // Wrong medium type
135 125 => "ECANCELED", // Operation Canceled
136 126 => "ENOKEY", // Required key not available
137 127 => "EKEYEXPIRED", // Key has expired
138 128 => "EKEYREVOKED", // Key has been revoked
139 129 => "EKEYREJECTED", // Key was rejected by service
140
141 130 => "EOWNERDEAD", // Owner died
142 131 => "ENOTRECOVERABLE", // State not recoverable
143
144 132 => "ERFKILL", // Operation not possible due to RF-kill
145
146 133 => "EHWPOISON", // Memory page has hardware error
147 _ => return None,
148 },
149 OsHint::Darwin => match errno {
150 1 => "EPERM", // Operation not permitted
151 2 => "ENOENT", // No such file or directory
152 3 => "ESRCH", // No such process
153 4 => "EINTR", // Interrupted system call
154 5 => "EIO", // Input/output error
155 6 => "ENXIO", // Device not configured
156 7 => "E2BIG", // Argument list too long
157 8 => "ENOEXEC", // Exec format error
158 9 => "EBADF", // Bad file descriptor
159 10 => "ECHILD", // No child processes
160 11 => "EDEADLK", // Resource deadlock avoided
161 12 => "ENOMEM", // Cannot allocate memory
162 13 => "EACCES", // Permission denied
163 14 => "EFAULT", // Bad address
164 15 => "ENOTBLK", // Block device required
165 16 => "EBUSY", // Device / Resource busy
166 17 => "EEXIST", // File exists
167 18 => "EXDEV", // Cross-device link
168 19 => "ENODEV", // Operation not supported by device
169 20 => "ENOTDIR", // Not a directory
170 21 => "EISDIR", // Is a directory
171 22 => "EINVAL", // Invalid argument
172 23 => "ENFILE", // Too many open files in system
173 24 => "EMFILE", // Too many open files
174 25 => "ENOTTY", // Inappropriate ioctl for device
175 26 => "ETXTBSY", // Text file busy
176 27 => "EFBIG", // File too large
177 28 => "ENOSPC", // No space left on device
178 29 => "ESPIPE", // Illegal seek
179 30 => "EROFS", // Read-only file system
180 31 => "EMLINK", // Too many links
181 32 => "EPIPE", // Broken pipe
182
183 // math software
184 33 => "EDOM", // Numerical argument out of domain
185 34 => "ERANGE", // Result too large
186
187 // non - blocking and interrupt i / o
188 35 => "EAGAIN", // Resource temporarily unavailable
189 36 => "EINPROGRESS", // Operation now in progress
190 37 => "EALREADY", // Operation already in progress
191
192 // ipc / network software - - argument errors
193 38 => "ENOTSOCK", // Socket operation on non-socket
194 39 => "EDESTADDRREQ", // Destination address required
195 40 => "EMSGSIZE", // Message too long
196 41 => "EPROTOTYPE", // Protocol wrong type for socket
197 42 => "ENOPROTOOPT", // Protocol not available
198 43 => "EPROTONOSUPPORT", // Protocol not supported
199 44 => "ESOCKTNOSUPPORT", // Socket type not supported
200 45 => "ENOTSUP", // Operation not supported
201
202 46 => "EPFNOSUPPORT", // Protocol family not supported
203 47 => "EAFNOSUPPORT", // Address family not supported by protocol family
204 48 => "EADDRINUSE", // Address already in use
205 49 => "EADDRNOTAVAIL", // Can"t assign requested address
206
207 // ipc / network software - - operational errors
208 50 => "ENETDOWN", // Network is down
209 51 => "ENETUNREACH", // Network is unreachable
210 52 => "ENETRESET", // Network dropped connection on reset
211 53 => "ECONNABORTED", // Software caused connection abort
212 54 => "ECONNRESET", // Connection reset by peer
213 55 => "ENOBUFS", // No buffer space available
214 56 => "EISCONN", // Socket is already connected
215 57 => "ENOTCONN", // Socket is not connected
216 58 => "ESHUTDOWN", // Can"t send after socket shutdown
217 59 => "ETOOMANYREFS", // Too many references: can"t splice
218 60 => "ETIMEDOUT", // Operation timed out
219 61 => "ECONNREFUSED", // Connection refused
220
221 62 => "ELOOP", // Too many levels of symbolic links
222 63 => "ENAMETOOLONG", // File name too long
223
224 // should be rearranged
225 64 => "EHOSTDOWN", // Host is down
226 65 => "EHOSTUNREACH", // No route to host
227 66 => "ENOTEMPTY", // Directory not empty
228
229 // quotas & mush
230 67 => "EPROCLIM", // Too many processes
231 68 => "EUSERS", // Too many users
232 69 => "EDQUOT", // Disc quota exceeded
233
234 // Network File System
235 70 => "ESTALE", // Stale NFS file handle
236 71 => "EREMOTE", // Too many levels of remote in path
237 72 => "EBADRPC", // RPC struct is bad
238 73 => "ERPCMISMATCH", // RPC version wrong
239 74 => "EPROGUNAVAIL", // RPC prog. not avail
240 75 => "EPROGMISMATCH", // Program version wrong
241 76 => "EPROCUNAVAIL", // Bad procedure for program
242
243 77 => "ENOLCK", // No locks available
244 78 => "ENOSYS", // Function not implemented
245
246 79 => "EFTYPE", // Inappropriate file type or format
247 80 => "EAUTH", // Authentication error
248 81 => "ENEEDAUTH", // Need authenticator
249
250 // Intelligent device errors
251 82 => "EPWROFF", // Device power is off
252 83 => "EDEVERR", // Device error, e.g. paper out
253
254 84 => "EOVERFLOW", // Value too large to be stored in data type
255
256 // Program loading errors
257 85 => "EBADEXEC", // Bad executable
258 86 => "EBADARCH", // Bad CPU type in executable
259 87 => "ESHLIBVERS", // Shared library version mismatch
260 88 => "EBADMACHO", // Malformed Macho file
261
262 89 => "ECANCELED", // Operation canceled
263
264 90 => "EIDRM", // Identifier removed
265 91 => "ENOMSG", // No message of desired type
266 92 => "EILSEQ", // Illegal byte sequence
267 93 => "ENOATTR", // Attribute not found
268
269 94 => "EBADMSG", // Bad message
270 95 => "EMULTIHOP", // Reserved
271 96 => "ENODATA", // No message available on STREAM
272 97 => "ENOLINK", // Reserved
273 98 => "ENOSR", // No STREAM resources
274 99 => "ENOSTR", // Not a STREAM
275 100 => "EPROTO", // Protocol error
276 101 => "ETIME", // STREAM ioctl timeout
277
278 102 => "EOPNOTSUPP", // Operation not supported on socket
279 103 => "ENOPOLICY", // No such policy registered
280 104 => "ENOTRECOVERABLE", // State not recoverable
281 105 => "EOWNERDEAD", // Previous owner died
282 106 => "EQFULL", // Interface output queue is full
283 _ => return None,
284 },
285 OsHint::Windows => match errno {
286 1 => "EPERM",
287 2 => "ENOENT",
288 3 => "ESRCH",
289 4 => "EINTR",
290 5 => "EIO",
291 6 => "ENXIO",
292 7 => "E2BIG",
293 8 => "ENOEXEC",
294 9 => "EBADF",
295 10 => "ECHILD",
296 11 => "EAGAIN",
297 12 => "ENOMEM",
298 13 => "EACCES",
299 14 => "EFAULT",
300 16 => "EBUSY",
301 17 => "EEXIST",
302 18 => "EXDEV",
303 19 => "ENODEV",
304 20 => "ENOTDIR",
305 21 => "EISDIR",
306 23 => "ENFILE",
307 24 => "EMFILE",
308 25 => "ENOTTY",
309 27 => "EFBIG",
310 28 => "ENOSPC",
311 29 => "ESPIPE",
312 30 => "EROFS",
313 31 => "EMLINK",
314 32 => "EPIPE",
315 33 => "EDOM",
316 36 => "EDEADLK",
317 38 => "ENAMETOOLONG",
318 39 => "ENOLCK",
319 40 => "ENOSYS",
320 41 => "ENOTEMPTY",
321
322 // Error codes used in the Secure CRT functions
323 22 => "EINVAL",
324 34 => "ERANGE",
325 42 => "EILSEQ",
326 80 => "STRUNCATE",
327
328 // POSIX Supplement
329 100 => "EADDRINUSE",
330 101 => "EADDRNOTAVAIL",
331 102 => "EAFNOSUPPORT",
332 103 => "EALREADY",
333 104 => "EBADMSG",
334 105 => "ECANCELED",
335 106 => "ECONNABORTED",
336 107 => "ECONNREFUSED",
337 108 => "ECONNRESET",
338 109 => "EDESTADDRREQ",
339 110 => "EHOSTUNREACH",
340 111 => "EIDRM",
341 112 => "EINPROGRESS",
342 113 => "EISCONN",
343 114 => "ELOOP",
344 115 => "EMSGSIZE",
345 116 => "ENETDOWN",
346 117 => "ENETRESET",
347 118 => "ENETUNREACH",
348 119 => "ENOBUFS",
349 120 => "ENODATA",
350 121 => "ENOLINK",
351 122 => "ENOMSG",
352 123 => "ENOPROTOOPT",
353 124 => "ENOSR",
354 125 => "ENOSTR",
355 126 => "ENOTCONN",
356 127 => "ENOTRECOVERABLE",
357 128 => "ENOTSOCK",
358 129 => "ENOTSUP",
359 130 => "EOPNOTSUPP",
360 131 => "EOTHER",
361 132 => "EOVERFLOW",
362 133 => "EOWNERDEAD",
363 134 => "EPROTO",
364 135 => "EPROTONOSUPPORT",
365 136 => "EPROTOTYPE",
366 137 => "ETIME",
367 138 => "ETIMEDOUT",
368 139 => "ETXTBSY",
369 140 => "EWOULDBLOCK",
370 _ => return None,
371 },
372 })
373}
374
375fn get_signal_name(signo: i64, os_hint: OsHint) -> Option<&'static str> {
376 // Linux signals have been taken from <uapi/asm-generic/signal.h>
377 Some(match os_hint {
378 OsHint::Linux => match signo {
379 1 => "SIGHUP", // Hangup.
380 2 => "SIGINT", // Terminal interrupt signal.
381 3 => "SIGQUIT", // Terminal quit signal.
382 4 => "SIGILL", // Illegal instruction.
383 5 => "SIGTRAP",
384 6 => "SIGABRT", // Process abort signal.
385 7 => "SIGBUS",
386 8 => "SIGFPE", // Erroneous arithmetic operation.
387 9 => "SIGKILL", // Kill (cannot be caught or ignored).
388 10 => "SIGUSR1", // User-defined signal 1.
389 11 => "SIGSEGV", // Invalid memory reference.
390 12 => "SIGUSR2", // User-defined signal 2.
391 13 => "SIGPIPE", // Write on a pipe with no one to read it.
392 14 => "SIGALRM", // Alarm clock.
393 15 => "SIGTERM", // Termination signal.
394 16 => "SIGSTKFLT",
395 17 => "SIGCHLD", // Child process terminated or stopped.
396 18 => "SIGCONT", // Continue executing, if stopped.
397 19 => "SIGSTOP", // Stop executing (cannot be caught or ignored).
398 20 => "SIGTSTP", // Terminal stop signal.
399 21 => "SIGTTIN", // Background process attempting read.
400 22 => "SIGTTOU", // Background process attempting write.
401 23 => "SIGURG", // High bandwidth data is available at a socket.
402 24 => "SIGXCPU", // CPU time limit exceeded.
403 25 => "SIGXFSZ", // File size limit exceeded.
404 26 => "SIGVTALRM", // Virtual timer expired.
405 27 => "SIGPROF", // Profiling timer expired.
406 28 => "SIGWINCH",
407 29 => "SIGIO",
408 30 => "SIGPWR",
409 31 => "SIGSYS",
410 _ => return None,
411 },
412 OsHint::Darwin => match signo {
413 1 => "SIGHUP", // hangup
414 2 => "SIGINT", // interrupt
415 3 => "SIGQUIT", // quit
416 4 => "SIGILL", // illegal instruction (not reset when caught)
417 5 => "SIGTRAP", // trace trap (not reset when caught)
418 6 => "SIGABRT", // abort()
419 // if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
420 7 => "SIGPOLL", // pollable event ([XSR] generated, not supported)
421 // if (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE)
422 // 7 => "SIGEMT", // EMT instruction
423 8 => "SIGFPE", // floating point exception
424 9 => "SIGKILL", // kill (cannot be caught or ignored)
425 10 => "SIGBUS", // bus error
426 11 => "SIGSEGV", // segmentation violation
427 12 => "SIGSYS", // bad argument to system call
428 13 => "SIGPIPE", // write on a pipe with no one to read it
429 14 => "SIGALRM", // alarm clock
430 15 => "SIGTERM", // software termination signal from kill
431 16 => "SIGURG", // urgent condition on IO channel
432 17 => "SIGSTOP", // sendable stop signal not from tty
433 18 => "SIGTSTP", // stop signal from tty
434 19 => "SIGCONT", // continue a stopped process
435 20 => "SIGCHLD", // to parent on child stop or exit
436 21 => "SIGTTIN", // to readers pgrp upon background tty read
437 22 => "SIGTTOU", // like TTIN for output if (tp->t_local<OSTOP)
438 23 => "SIGIO", // input/output possible signal
439 24 => "SIGXCPU", // exceeded CPU time limit
440 25 => "SIGXFSZ", // exceeded file size limit
441 26 => "SIGVTALRM", // virtual time alarm
442 27 => "SIGPROF", // profiling time alarm
443 28 => "SIGWINCH", // window size changes
444 29 => "SIGINFO", // information request
445 30 => "SIGUSR1", // user defined signal 1
446 31 => "SIGUSR2", // user defined signal 2
447 _ => return None,
448 },
449 _ => return None,
450 })
451}
452
453fn get_signal_code_name(signo: i64, codeno: i64) -> Option<&'static str> {
454 // Codes for Darwin `si_code`
455 Some(match signo {
456 // Codes for SIGILL
457 4 => match codeno {
458 0 => "ILL_NOOP", // if only I knew...
459 1 => "ILL_ILLOPC", // [XSI] illegal opcode
460 2 => "ILL_ILLTRP", // [XSI] illegal trap
461 3 => "ILL_PRVOPC", // [XSI] privileged opcode
462 4 => "ILL_ILLOPN", // [XSI] illegal operand -NOTIMP
463 5 => "ILL_ILLADR", // [XSI] illegal addressing mode -NOTIMP
464 6 => "ILL_PRVREG", // [XSI] privileged register -NOTIMP
465 7 => "ILL_COPROC", // [XSI] coprocessor error -NOTIMP
466 8 => "ILL_BADSTK", // [XSI] internal stack error -NOTIMP
467 _ => return None,
468 },
469
470 // Codes for SIGFPE
471 8 => match codeno {
472 0 => "FPE_NOOP", // if only I knew...
473 1 => "FPE_FLTDIV", // [XSI] floating point divide by zero
474 2 => "FPE_FLTOVF", // [XSI] floating point overflow
475 3 => "FPE_FLTUND", // [XSI] floating point underflow
476 4 => "FPE_FLTRES", // [XSI] floating point inexact result
477 5 => "FPE_FLTINV", // [XSI] invalid floating point operation
478 6 => "FPE_FLTSUB", // [XSI] subscript out of range -NOTIMP
479 7 => "FPE_INTDIV", // [XSI] integer divide by zero
480 8 => "FPE_INTOVF", // [XSI] integer overflow
481 _ => return None,
482 },
483
484 // Codes for SIGSEGV
485 11 => match codeno {
486 0 => "SEGV_NOOP", // if only I knew...
487 1 => "SEGV_MAPERR", // [XSI] address not mapped to object
488 2 => "SEGV_ACCERR", // [XSI] invalid permission for mapped object
489 _ => return None,
490 },
491
492 // Codes for SIGBUS
493 10 => match codeno {
494 0 => "BUS_NOOP", // if only I knew...
495 1 => "BUS_ADRALN", // [XSI] Invalid address alignment
496 2 => "BUS_ADRERR", // [XSI] Nonexistent physical address -NOTIMP
497 3 => "BUS_OBJERR", // [XSI] Object-specific HW error - NOTIMP
498 _ => return None,
499 },
500
501 // Codes for SIGTRAP
502 5 => match codeno {
503 1 => "TRAP_BRKPT", // [XSI] Process breakpoint -NOTIMP
504 2 => "TRAP_TRACE", // [XSI] Process trace trap -NOTIMP
505 _ => return None,
506 },
507
508 // Codes for SIGCHLD
509 20 => match codeno {
510 0 => "CLD_NOOP", // if only I knew...
511 1 => "CLD_EXITED", // [XSI] child has exited
512 2 => "CLD_KILLED", // [XSI] terminated abnormally, no core file
513 3 => "CLD_DUMPED", // [XSI] terminated abnormally, core file
514 4 => "CLD_TRAPPED", // [XSI] traced child has trapped
515 5 => "CLD_STOPPED", // [XSI] child has stopped
516 6 => "CLD_CONTINUED", // [XSI] stopped child has continued
517 _ => return None,
518 },
519
520 // Codes for SIGPOLL
521 7 => match codeno {
522 1 => "POLL_IN", // [XSR] Data input available
523 2 => "POLL_OUT", // [XSR] Output buffers available
524 3 => "POLL_MSG", // [XSR] Input message available
525 4 => "POLL_ERR", // [XSR] I/O error
526 5 => "POLL_PRI", // [XSR] High priority input available
527 6 => "POLL_HUP", // [XSR] Device disconnected
528 _ => return None,
529 },
530 _ => return None,
531 })
532}
533
534fn get_mach_exception_name(number: i64) -> Option<&'static str> {
535 // Mach exception codes used in Darwin.
536 Some(match number {
537 1 => "EXC_BAD_ACCESS", // Could not access memory
538 2 => "EXC_BAD_INSTRUCTION", // Instruction failed
539 3 => "EXC_ARITHMETIC", // Arithmetic exception
540 4 => "EXC_EMULATION", // Emulation instruction
541 5 => "EXC_SOFTWARE", // Software generated exception
542 6 => "EXC_BREAKPOINT", // Trace, breakpoint, etc.
543 7 => "EXC_SYSCALL", // System calls.
544 8 => "EXC_MACH_SYSCALL", // Mach system calls.
545 9 => "EXC_RPC_ALERT", // RPC alert
546 10 => "EXC_CRASH", // Abnormal process exit
547 11 => "EXC_RESOURCE", // Hit resource consumption limit
548 12 => "EXC_GUARD", // Violated guarded resource protections
549 13 => "EXC_CORPSE_NOTIFY", // Abnormal process exited to corpse state
550 _ => return None,
551 })
552}
553
554/// Internal utility trait to indicate the OS.
555#[derive(Debug, PartialEq, Clone, Copy)]
556pub enum OsHint {
557 Windows,
558 Linux,
559 Darwin,
560}
561
562impl OsHint {
563 fn from_name(name: &str) -> Option<OsHint> {
564 match name.to_lowercase().as_ref() {
565 "ios" | "watchos" | "tvos" | "macos" => Some(OsHint::Darwin),
566 "linux" | "android" => Some(OsHint::Linux),
567 "windows" => Some(OsHint::Windows),
568 _ => None,
569 }
570 }
571
572 pub fn from_event(event: &Event) -> Option<OsHint> {
573 if let Some(debug_meta) = event.debug_meta.value()
574 && let Some(sdk_info) = debug_meta.system_sdk.value()
575 && let Some(name) = sdk_info.sdk_name.as_str()
576 {
577 return Self::from_name(name);
578 }
579
580 if let Some(os_context) = event.context::<OsContext>()
581 && let Some(name) = os_context.name.as_str()
582 {
583 return Self::from_name(name);
584 }
585
586 None
587 }
588}
589
590/// Normalizes the exception mechanism in place.
591pub fn normalize_mechanism(mechanism: &mut Mechanism, os_hint: Option<OsHint>) {
592 let _ = processor::apply(&mut mechanism.help_link, |value, meta| {
593 if value.starts_with("http://") || value.starts_with("https://") {
594 Ok(())
595 } else {
596 meta.add_error(Error::expected("http URL"));
597 Err(ProcessingAction::DeleteValueSoft)
598 }
599 });
600
601 let meta = match mechanism.meta.value_mut() {
602 Some(meta) => meta,
603 None => return,
604 };
605
606 if let Some(os_hint) = os_hint {
607 if let Some(cerror) = meta.errno.value_mut()
608 && cerror.name.value().is_none()
609 && let Some(errno) = cerror.number.value()
610 && let Some(name) = get_errno_name(*errno, os_hint)
611 {
612 cerror.name = Annotated::new(name.to_owned());
613 }
614
615 if let Some(signal) = meta.signal.value_mut()
616 && let Some(signo) = signal.number.value()
617 {
618 if signal.name.value().is_none()
619 && let Some(name) = get_signal_name(*signo, os_hint)
620 {
621 signal.name = Annotated::new(name.to_owned());
622 }
623
624 if os_hint == OsHint::Darwin
625 && signal.code_name.value().is_none()
626 && let Some(code) = signal.code.value()
627 && let Some(code_name) = get_signal_code_name(*signo, *code)
628 {
629 signal.code_name = Annotated::new(code_name.to_owned());
630 }
631 }
632 }
633
634 if let Some(mach_exception) = meta.mach_exception.value_mut()
635 && let Some(number) = mach_exception.ty.value()
636 && mach_exception.name.value().is_none()
637 && let Some(name) = get_mach_exception_name(*number)
638 {
639 mach_exception.name = Annotated::new(name.to_owned());
640 }
641}
642
643#[cfg(test)]
644mod tests {
645 use relay_event_schema::protocol::{CError, MachException, MechanismMeta, PosixSignal};
646 use relay_protocol::SerializableAnnotated;
647 use similar_asserts::assert_eq;
648
649 use super::*;
650
651 #[test]
652 fn test_normalize_missing() {
653 let mut mechanism = Mechanism {
654 ty: Annotated::new("generic".to_owned()),
655 ..Default::default()
656 };
657
658 let old_mechanism = mechanism.clone();
659
660 normalize_mechanism(&mut mechanism, None);
661
662 assert_eq!(mechanism, old_mechanism);
663 }
664
665 #[test]
666 fn test_normalize_errno() {
667 let mut mechanism = Mechanism {
668 ty: Annotated::new("generic".to_owned()),
669 meta: Annotated::new(MechanismMeta {
670 errno: Annotated::new(CError {
671 number: Annotated::new(2),
672 ..Default::default()
673 }),
674 ..Default::default()
675 }),
676 ..Default::default()
677 };
678
679 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
680
681 let errno = mechanism.meta.value().unwrap().errno.value().unwrap();
682 assert_eq!(
683 errno,
684 &CError {
685 number: Annotated::new(2),
686 name: Annotated::new("ENOENT".to_owned()),
687 }
688 );
689 }
690
691 #[test]
692 fn test_normalize_errno_override() {
693 let mut mechanism = Mechanism {
694 ty: Annotated::new("generic".to_owned()),
695 meta: Annotated::new(MechanismMeta {
696 errno: Annotated::new(CError {
697 number: Annotated::new(2),
698 name: Annotated::new("OVERRIDDEN".to_owned()),
699 }),
700 ..Default::default()
701 }),
702 ..Default::default()
703 };
704
705 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
706
707 let errno = mechanism.meta.value().unwrap().errno.value().unwrap();
708 assert_eq!(
709 errno,
710 &CError {
711 number: Annotated::new(2),
712 name: Annotated::new("OVERRIDDEN".to_owned()),
713 }
714 );
715 }
716
717 #[test]
718 fn test_normalize_errno_fail() {
719 let mut mechanism = Mechanism {
720 ty: Annotated::new("generic".to_owned()),
721 meta: Annotated::new(MechanismMeta {
722 errno: Annotated::new(CError {
723 number: Annotated::new(2),
724 ..Default::default()
725 }),
726 ..Default::default()
727 }),
728 ..Default::default()
729 };
730
731 normalize_mechanism(&mut mechanism, None);
732
733 let errno = mechanism.meta.value().unwrap().errno.value().unwrap();
734 assert_eq!(
735 errno,
736 &CError {
737 number: Annotated::new(2),
738 ..Default::default()
739 }
740 );
741 }
742
743 #[test]
744 fn test_normalize_signal() {
745 let mut mechanism = Mechanism {
746 ty: Annotated::new("generic".to_owned()),
747 meta: Annotated::new(MechanismMeta {
748 signal: Annotated::new(PosixSignal {
749 number: Annotated::new(11),
750 code: Annotated::new(0),
751 ..Default::default()
752 }),
753 ..Default::default()
754 }),
755 ..Default::default()
756 };
757
758 normalize_mechanism(&mut mechanism, Some(OsHint::Darwin));
759
760 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
761 assert_eq!(
762 signal,
763 &PosixSignal {
764 number: Annotated::new(11),
765 code: Annotated::new(0),
766 name: Annotated::new("SIGSEGV".to_owned()),
767 code_name: Annotated::new("SEGV_NOOP".to_owned()),
768 }
769 );
770 }
771
772 #[test]
773 fn test_normalize_partial_signal() {
774 let mut mechanism = Mechanism {
775 ty: Annotated::new("generic".to_owned()),
776 meta: Annotated::new(MechanismMeta {
777 signal: Annotated::new(PosixSignal {
778 number: Annotated::new(11),
779 ..Default::default()
780 }),
781 ..Default::default()
782 }),
783 ..Default::default()
784 };
785
786 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
787
788 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
789
790 assert_eq!(
791 signal,
792 &PosixSignal {
793 number: Annotated::new(11),
794 name: Annotated::new("SIGSEGV".to_owned()),
795 ..Default::default()
796 }
797 );
798 }
799
800 #[test]
801 fn test_normalize_signal_override() {
802 let mut mechanism = Mechanism {
803 ty: Annotated::new("generic".to_owned()),
804 meta: Annotated::new(MechanismMeta {
805 signal: Annotated::new(PosixSignal {
806 number: Annotated::new(11),
807 code: Annotated::new(0),
808 name: Annotated::new("OVERRIDDEN".to_owned()),
809 code_name: Annotated::new("OVERRIDDEN".to_owned()),
810 }),
811 ..Default::default()
812 }),
813 ..Default::default()
814 };
815
816 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
817
818 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
819
820 assert_eq!(
821 signal,
822 &PosixSignal {
823 number: Annotated::new(11),
824 code: Annotated::new(0),
825 name: Annotated::new("OVERRIDDEN".to_owned()),
826 code_name: Annotated::new("OVERRIDDEN".to_owned()),
827 }
828 );
829 }
830
831 #[test]
832 fn test_normalize_signal_fail() {
833 let mut mechanism = Mechanism {
834 ty: Annotated::new("generic".to_owned()),
835 meta: Annotated::new(MechanismMeta {
836 signal: Annotated::new(PosixSignal {
837 number: Annotated::new(11),
838 code: Annotated::new(0),
839 ..Default::default()
840 }),
841 ..Default::default()
842 }),
843 ..Default::default()
844 };
845
846 normalize_mechanism(&mut mechanism, None);
847
848 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
849
850 assert_eq!(
851 signal,
852 &PosixSignal {
853 number: Annotated::new(11),
854 code: Annotated::new(0),
855 ..Default::default()
856 }
857 );
858 }
859
860 #[test]
861 fn test_normalize_mach() {
862 let mut mechanism = Mechanism {
863 ty: Annotated::new("generic".to_owned()),
864 meta: Annotated::new(MechanismMeta {
865 mach_exception: Annotated::new(MachException {
866 ty: Annotated::new(1),
867 code: Annotated::new(1),
868 subcode: Annotated::new(8),
869 ..Default::default()
870 }),
871 ..Default::default()
872 }),
873 ..Default::default()
874 };
875
876 // We do not need SDK information here because mach exceptions only
877 // occur on Darwin
878
879 normalize_mechanism(&mut mechanism, None);
880
881 let mach_exception = mechanism
882 .meta
883 .value()
884 .unwrap()
885 .mach_exception
886 .value()
887 .unwrap();
888
889 assert_eq!(
890 mach_exception,
891 &MachException {
892 ty: Annotated::new(1),
893 code: Annotated::new(1),
894 subcode: Annotated::new(8),
895 name: Annotated::new("EXC_BAD_ACCESS".to_owned()),
896 }
897 );
898 }
899
900 #[test]
901 fn test_normalize_mach_override() {
902 let mut mechanism = Mechanism {
903 ty: Annotated::new("generic".to_owned()),
904 meta: Annotated::new(MechanismMeta {
905 mach_exception: Annotated::new(MachException {
906 ty: Annotated::new(1),
907 code: Annotated::new(1),
908 subcode: Annotated::new(8),
909 name: Annotated::new("OVERRIDE".to_owned()),
910 }),
911 ..Default::default()
912 }),
913 ..Default::default()
914 };
915
916 // We do not need SDK information here because mach exceptions only
917 // occur on Darwin
918
919 normalize_mechanism(&mut mechanism, None);
920
921 let mach_exception = mechanism
922 .meta
923 .value()
924 .unwrap()
925 .mach_exception
926 .value()
927 .unwrap();
928 assert_eq!(
929 mach_exception,
930 &MachException {
931 ty: Annotated::new(1),
932 code: Annotated::new(1),
933 subcode: Annotated::new(8),
934 name: Annotated::new("OVERRIDE".to_owned()),
935 }
936 );
937 }
938
939 #[test]
940 fn test_normalize_mach_fail() {
941 let mut mechanism = Mechanism {
942 ty: Annotated::new("generic".to_owned()),
943 meta: Annotated::new(MechanismMeta {
944 mach_exception: Annotated::new(MachException {
945 ty: Annotated::new(99),
946 code: Annotated::new(1),
947 subcode: Annotated::new(8),
948 ..Default::default()
949 }),
950 ..Default::default()
951 }),
952 ..Default::default()
953 };
954
955 // We do not need SDK information here because mach exceptions only
956 // occur on Darwin
957
958 normalize_mechanism(&mut mechanism, None);
959
960 let mach_exception = mechanism
961 .meta
962 .value()
963 .unwrap()
964 .mach_exception
965 .value()
966 .unwrap();
967 assert_eq!(
968 mach_exception,
969 &MachException {
970 ty: Annotated::new(99),
971 code: Annotated::new(1),
972 subcode: Annotated::new(8),
973 ..Default::default()
974 }
975 );
976 }
977
978 #[test]
979 fn test_normalize_http_url() {
980 let mut good_mechanism = Mechanism {
981 ty: Annotated::new("generic".to_owned()),
982 help_link: Annotated::new("https://example.com/".to_owned()),
983 ..Default::default()
984 };
985
986 normalize_mechanism(&mut good_mechanism, None);
987 insta::assert_ron_snapshot!(SerializableAnnotated(&Annotated::new(good_mechanism)), @r###"
988 {
989 "type": "generic",
990 "help_link": "https://example.com/",
991 }
992 "###);
993
994 let mut bad_mechanism = Mechanism {
995 ty: Annotated::new("generic".to_owned()),
996 help_link: Annotated::new("javascript:alert(document.cookie)".to_owned()),
997 ..Default::default()
998 };
999
1000 normalize_mechanism(&mut bad_mechanism, None);
1001 insta::assert_ron_snapshot!(SerializableAnnotated(&Annotated::new(bad_mechanism)), @r###"
1002 {
1003 "type": "generic",
1004 "help_link": (),
1005 "_meta": {
1006 "help_link": {
1007 "": Meta(Some(MetaInner(
1008 err: [
1009 [
1010 "invalid_data",
1011 {
1012 "reason": "expected http URL",
1013 },
1014 ],
1015 ],
1016 val: Some("javascript:alert(document.cookie)"),
1017 ))),
1018 },
1019 },
1020 }
1021 "###);
1022 }
1023}