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 if let Some(sdk_info) = debug_meta.system_sdk.value() {
575 if let Some(name) = sdk_info.sdk_name.as_str() {
576 return Self::from_name(name);
577 }
578 }
579 }
580
581 if let Some(os_context) = event.context::<OsContext>() {
582 if let Some(name) = os_context.name.as_str() {
583 return Self::from_name(name);
584 }
585 }
586
587 None
588 }
589}
590
591/// Normalizes the exception mechanism in place.
592pub fn normalize_mechanism(mechanism: &mut Mechanism, os_hint: Option<OsHint>) {
593 let _ = processor::apply(&mut mechanism.help_link, |value, meta| {
594 if value.starts_with("http://") || value.starts_with("https://") {
595 Ok(())
596 } else {
597 meta.add_error(Error::expected("http URL"));
598 Err(ProcessingAction::DeleteValueSoft)
599 }
600 });
601
602 let meta = match mechanism.meta.value_mut() {
603 Some(meta) => meta,
604 None => return,
605 };
606
607 if let Some(os_hint) = os_hint {
608 if let Some(cerror) = meta.errno.value_mut() {
609 if cerror.name.value().is_none() {
610 if let Some(errno) = cerror.number.value() {
611 if let Some(name) = get_errno_name(*errno, os_hint) {
612 cerror.name = Annotated::new(name.to_owned());
613 }
614 }
615 }
616 }
617
618 if let Some(signal) = meta.signal.value_mut() {
619 if let Some(signo) = signal.number.value() {
620 if signal.name.value().is_none() {
621 if let Some(name) = get_signal_name(*signo, os_hint) {
622 signal.name = Annotated::new(name.to_owned());
623 }
624 }
625
626 if os_hint == OsHint::Darwin && signal.code_name.value().is_none() {
627 if let Some(code) = signal.code.value() {
628 if let Some(code_name) = get_signal_code_name(*signo, *code) {
629 signal.code_name = Annotated::new(code_name.to_owned());
630 }
631 }
632 }
633 }
634 }
635 }
636
637 if let Some(mach_exception) = meta.mach_exception.value_mut() {
638 if let Some(number) = mach_exception.ty.value() {
639 if mach_exception.name.value().is_none() {
640 if let Some(name) = get_mach_exception_name(*number) {
641 mach_exception.name = Annotated::new(name.to_owned());
642 }
643 }
644 }
645 }
646}
647
648#[cfg(test)]
649mod tests {
650 use relay_event_schema::protocol::{CError, MachException, MechanismMeta, PosixSignal};
651 use relay_protocol::SerializableAnnotated;
652 use similar_asserts::assert_eq;
653
654 use super::*;
655
656 #[test]
657 fn test_normalize_missing() {
658 let mut mechanism = Mechanism {
659 ty: Annotated::new("generic".to_owned()),
660 ..Default::default()
661 };
662
663 let old_mechanism = mechanism.clone();
664
665 normalize_mechanism(&mut mechanism, None);
666
667 assert_eq!(mechanism, old_mechanism);
668 }
669
670 #[test]
671 fn test_normalize_errno() {
672 let mut mechanism = Mechanism {
673 ty: Annotated::new("generic".to_owned()),
674 meta: Annotated::new(MechanismMeta {
675 errno: Annotated::new(CError {
676 number: Annotated::new(2),
677 ..Default::default()
678 }),
679 ..Default::default()
680 }),
681 ..Default::default()
682 };
683
684 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
685
686 let errno = mechanism.meta.value().unwrap().errno.value().unwrap();
687 assert_eq!(
688 errno,
689 &CError {
690 number: Annotated::new(2),
691 name: Annotated::new("ENOENT".to_owned()),
692 }
693 );
694 }
695
696 #[test]
697 fn test_normalize_errno_override() {
698 let mut mechanism = Mechanism {
699 ty: Annotated::new("generic".to_owned()),
700 meta: Annotated::new(MechanismMeta {
701 errno: Annotated::new(CError {
702 number: Annotated::new(2),
703 name: Annotated::new("OVERRIDDEN".to_owned()),
704 }),
705 ..Default::default()
706 }),
707 ..Default::default()
708 };
709
710 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
711
712 let errno = mechanism.meta.value().unwrap().errno.value().unwrap();
713 assert_eq!(
714 errno,
715 &CError {
716 number: Annotated::new(2),
717 name: Annotated::new("OVERRIDDEN".to_owned()),
718 }
719 );
720 }
721
722 #[test]
723 fn test_normalize_errno_fail() {
724 let mut mechanism = Mechanism {
725 ty: Annotated::new("generic".to_owned()),
726 meta: Annotated::new(MechanismMeta {
727 errno: Annotated::new(CError {
728 number: Annotated::new(2),
729 ..Default::default()
730 }),
731 ..Default::default()
732 }),
733 ..Default::default()
734 };
735
736 normalize_mechanism(&mut mechanism, None);
737
738 let errno = mechanism.meta.value().unwrap().errno.value().unwrap();
739 assert_eq!(
740 errno,
741 &CError {
742 number: Annotated::new(2),
743 ..Default::default()
744 }
745 );
746 }
747
748 #[test]
749 fn test_normalize_signal() {
750 let mut mechanism = Mechanism {
751 ty: Annotated::new("generic".to_owned()),
752 meta: Annotated::new(MechanismMeta {
753 signal: Annotated::new(PosixSignal {
754 number: Annotated::new(11),
755 code: Annotated::new(0),
756 ..Default::default()
757 }),
758 ..Default::default()
759 }),
760 ..Default::default()
761 };
762
763 normalize_mechanism(&mut mechanism, Some(OsHint::Darwin));
764
765 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
766 assert_eq!(
767 signal,
768 &PosixSignal {
769 number: Annotated::new(11),
770 code: Annotated::new(0),
771 name: Annotated::new("SIGSEGV".to_owned()),
772 code_name: Annotated::new("SEGV_NOOP".to_owned()),
773 }
774 );
775 }
776
777 #[test]
778 fn test_normalize_partial_signal() {
779 let mut mechanism = Mechanism {
780 ty: Annotated::new("generic".to_owned()),
781 meta: Annotated::new(MechanismMeta {
782 signal: Annotated::new(PosixSignal {
783 number: Annotated::new(11),
784 ..Default::default()
785 }),
786 ..Default::default()
787 }),
788 ..Default::default()
789 };
790
791 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
792
793 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
794
795 assert_eq!(
796 signal,
797 &PosixSignal {
798 number: Annotated::new(11),
799 name: Annotated::new("SIGSEGV".to_owned()),
800 ..Default::default()
801 }
802 );
803 }
804
805 #[test]
806 fn test_normalize_signal_override() {
807 let mut mechanism = Mechanism {
808 ty: Annotated::new("generic".to_owned()),
809 meta: Annotated::new(MechanismMeta {
810 signal: Annotated::new(PosixSignal {
811 number: Annotated::new(11),
812 code: Annotated::new(0),
813 name: Annotated::new("OVERRIDDEN".to_owned()),
814 code_name: Annotated::new("OVERRIDDEN".to_owned()),
815 }),
816 ..Default::default()
817 }),
818 ..Default::default()
819 };
820
821 normalize_mechanism(&mut mechanism, Some(OsHint::Linux));
822
823 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
824
825 assert_eq!(
826 signal,
827 &PosixSignal {
828 number: Annotated::new(11),
829 code: Annotated::new(0),
830 name: Annotated::new("OVERRIDDEN".to_owned()),
831 code_name: Annotated::new("OVERRIDDEN".to_owned()),
832 }
833 );
834 }
835
836 #[test]
837 fn test_normalize_signal_fail() {
838 let mut mechanism = Mechanism {
839 ty: Annotated::new("generic".to_owned()),
840 meta: Annotated::new(MechanismMeta {
841 signal: Annotated::new(PosixSignal {
842 number: Annotated::new(11),
843 code: Annotated::new(0),
844 ..Default::default()
845 }),
846 ..Default::default()
847 }),
848 ..Default::default()
849 };
850
851 normalize_mechanism(&mut mechanism, None);
852
853 let signal = mechanism.meta.value().unwrap().signal.value().unwrap();
854
855 assert_eq!(
856 signal,
857 &PosixSignal {
858 number: Annotated::new(11),
859 code: Annotated::new(0),
860 ..Default::default()
861 }
862 );
863 }
864
865 #[test]
866 fn test_normalize_mach() {
867 let mut mechanism = Mechanism {
868 ty: Annotated::new("generic".to_owned()),
869 meta: Annotated::new(MechanismMeta {
870 mach_exception: Annotated::new(MachException {
871 ty: Annotated::new(1),
872 code: Annotated::new(1),
873 subcode: Annotated::new(8),
874 ..Default::default()
875 }),
876 ..Default::default()
877 }),
878 ..Default::default()
879 };
880
881 // We do not need SDK information here because mach exceptions only
882 // occur on Darwin
883
884 normalize_mechanism(&mut mechanism, None);
885
886 let mach_exception = mechanism
887 .meta
888 .value()
889 .unwrap()
890 .mach_exception
891 .value()
892 .unwrap();
893
894 assert_eq!(
895 mach_exception,
896 &MachException {
897 ty: Annotated::new(1),
898 code: Annotated::new(1),
899 subcode: Annotated::new(8),
900 name: Annotated::new("EXC_BAD_ACCESS".to_owned()),
901 }
902 );
903 }
904
905 #[test]
906 fn test_normalize_mach_override() {
907 let mut mechanism = Mechanism {
908 ty: Annotated::new("generic".to_owned()),
909 meta: Annotated::new(MechanismMeta {
910 mach_exception: Annotated::new(MachException {
911 ty: Annotated::new(1),
912 code: Annotated::new(1),
913 subcode: Annotated::new(8),
914 name: Annotated::new("OVERRIDE".to_owned()),
915 }),
916 ..Default::default()
917 }),
918 ..Default::default()
919 };
920
921 // We do not need SDK information here because mach exceptions only
922 // occur on Darwin
923
924 normalize_mechanism(&mut mechanism, None);
925
926 let mach_exception = mechanism
927 .meta
928 .value()
929 .unwrap()
930 .mach_exception
931 .value()
932 .unwrap();
933 assert_eq!(
934 mach_exception,
935 &MachException {
936 ty: Annotated::new(1),
937 code: Annotated::new(1),
938 subcode: Annotated::new(8),
939 name: Annotated::new("OVERRIDE".to_owned()),
940 }
941 );
942 }
943
944 #[test]
945 fn test_normalize_mach_fail() {
946 let mut mechanism = Mechanism {
947 ty: Annotated::new("generic".to_owned()),
948 meta: Annotated::new(MechanismMeta {
949 mach_exception: Annotated::new(MachException {
950 ty: Annotated::new(99),
951 code: Annotated::new(1),
952 subcode: Annotated::new(8),
953 ..Default::default()
954 }),
955 ..Default::default()
956 }),
957 ..Default::default()
958 };
959
960 // We do not need SDK information here because mach exceptions only
961 // occur on Darwin
962
963 normalize_mechanism(&mut mechanism, None);
964
965 let mach_exception = mechanism
966 .meta
967 .value()
968 .unwrap()
969 .mach_exception
970 .value()
971 .unwrap();
972 assert_eq!(
973 mach_exception,
974 &MachException {
975 ty: Annotated::new(99),
976 code: Annotated::new(1),
977 subcode: Annotated::new(8),
978 ..Default::default()
979 }
980 );
981 }
982
983 #[test]
984 fn test_normalize_http_url() {
985 let mut good_mechanism = Mechanism {
986 ty: Annotated::new("generic".to_owned()),
987 help_link: Annotated::new("https://example.com/".to_owned()),
988 ..Default::default()
989 };
990
991 normalize_mechanism(&mut good_mechanism, None);
992 insta::assert_ron_snapshot!(SerializableAnnotated(&Annotated::new(good_mechanism)), @r#"
993 {
994 "type": "generic",
995 "help_link": "https://example.com/",
996 }
997 "#);
998
999 let mut bad_mechanism = Mechanism {
1000 ty: Annotated::new("generic".to_owned()),
1001 help_link: Annotated::new("javascript:alert(document.cookie)".to_owned()),
1002 ..Default::default()
1003 };
1004
1005 normalize_mechanism(&mut bad_mechanism, None);
1006 insta::assert_ron_snapshot!(SerializableAnnotated(&Annotated::new(bad_mechanism)), @r#"
1007 {
1008 "type": "generic",
1009 "help_link": (),
1010 "_meta": {
1011 "help_link": {
1012 "": Meta(Some(MetaInner(
1013 err: [
1014 [
1015 "invalid_data",
1016 {
1017 "reason": "expected http URL",
1018 },
1019 ],
1020 ],
1021 val: Some("javascript:alert(document.cookie)"),
1022 ))),
1023 },
1024 },
1025 }
1026 "#);
1027 }
1028}