@arms/rum-reactnative 0.1.2 → 0.1.3-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -1
- package/RumSdkReactnative.podspec +28 -0
- package/android/build.gradle +83 -0
- package/android/gradle.properties +6 -0
- package/android/src/main/AndroidManifest.xml +13 -0
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +512 -0
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativePackage.kt +33 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/CrashContextManager.kt +157 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/CrashHandler.kt +444 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/CrashInitProvider.kt +50 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/NdkCrashHandler.kt +66 -0
- package/android/src/main/jni/CMakeLists.txt +21 -0
- package/android/src/main/jni/rum_backtrace.c +144 -0
- package/android/src/main/jni/rum_crash_handler.c +200 -0
- package/android/src/main/jni/rum_crash_writer.c +436 -0
- package/android/src/main/jni/rum_module_info.c +355 -0
- package/android/src/main/jni/rum_module_info.h +58 -0
- package/android/src/main/jni/rum_test_crash.cpp +55 -0
- package/app.plugin.js +11 -0
- package/docs/ReactNative SDK/351/205/215/347/275/256/345/217/202/350/200/203.md" +671 -0
- package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +12 -0
- package/docs//346/216/245/345/205/245ReactNative/345/272/224/347/224/250.md +238 -0
- package/ios/PrivacyInfo.xcprivacy +93 -0
- package/ios/RumCrashReporter.h +38 -0
- package/ios/RumCrashReporter.mm +861 -0
- package/ios/RumSdkReactnative.h +5 -0
- package/ios/RumSdkReactnative.mm +291 -0
- package/ios/fishhook/fishhook.c +264 -0
- package/ios/fishhook/fishhook.h +76 -0
- package/lib/commonjs/NativeRumSdkReactnative.js +50 -0
- package/lib/commonjs/collector/action/index.js +108 -0
- package/lib/commonjs/collector/exception/crash.js +148 -0
- package/lib/commonjs/collector/exception/index.js +238 -0
- package/lib/commonjs/collector/index.js +42 -0
- package/lib/commonjs/collector/resource/api.js +286 -0
- package/lib/commonjs/collector/view/perf.js +79 -0
- package/lib/commonjs/collector/view/pv.js +88 -0
- package/lib/commonjs/expoConfigPlugin.js +37 -0
- package/lib/commonjs/index.js +29 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/plugin.js +47 -0
- package/lib/commonjs/processor/default-processor.js +27 -0
- package/lib/commonjs/processor/session-processor.js +47 -0
- package/lib/commonjs/reporter/index.js +148 -0
- package/lib/commonjs/reporter/monitor-reporter.js +43 -0
- package/lib/commonjs/shell.js +91 -0
- package/lib/commonjs/types/client.js +6 -0
- package/lib/commonjs/types/crash.js +37 -0
- package/lib/commonjs/types/index.js +2 -0
- package/lib/commonjs/utils/action.js +305 -0
- package/lib/commonjs/utils/api.js +83 -0
- package/lib/commonjs/utils/base.js +95 -0
- package/lib/commonjs/utils/crash.js +149 -0
- package/lib/commonjs/utils/platform.js +162 -0
- package/lib/commonjs/utils/session.js +158 -0
- package/lib/commonjs/utils/url.js +59 -0
- package/lib/commonjs/utils/view.js +93 -0
- package/lib/module/NativeRumSdkReactnative.js +47 -0
- package/lib/module/collector/action/index.js +45 -10
- package/lib/module/collector/exception/crash.js +143 -0
- package/lib/module/collector/exception/index.js +144 -46
- package/lib/module/collector/index.js +8 -0
- package/lib/module/collector/resource/api.js +6 -6
- package/lib/module/collector/view/pv.js +11 -0
- package/lib/module/expoConfigPlugin.js +33 -0
- package/lib/module/index.js +1 -0
- package/lib/module/processor/session-processor.js +22 -0
- package/lib/module/reporter/index.js +102 -16
- package/lib/module/reporter/monitor-reporter.js +38 -0
- package/lib/module/shell.js +11 -7
- package/lib/module/types/crash.js +33 -0
- package/lib/module/utils/action.js +299 -0
- package/lib/module/utils/crash.js +144 -0
- package/lib/module/utils/platform.js +124 -72
- package/lib/module/utils/session.js +23 -4
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/NativeRumSdkReactnative.d.ts +49 -0
- package/lib/typescript/{src → commonjs/src}/collector/action/index.d.ts +6 -0
- package/lib/typescript/commonjs/src/collector/exception/crash.d.ts +28 -0
- package/lib/typescript/{src → commonjs/src}/collector/exception/index.d.ts +7 -0
- package/lib/typescript/commonjs/src/collector/index.d.ts +6 -0
- package/lib/typescript/commonjs/src/expoConfigPlugin.d.ts +28 -0
- package/lib/typescript/commonjs/src/index.d.ts +6 -0
- package/lib/typescript/{src → commonjs/src}/processor/session-processor.d.ts +2 -0
- package/lib/typescript/{src → commonjs/src}/reporter/index.d.ts +3 -1
- package/lib/typescript/commonjs/src/reporter/monitor-reporter.d.ts +8 -0
- package/lib/typescript/{src → commonjs/src}/shell.d.ts +11 -0
- package/lib/typescript/commonjs/src/types/crash.d.ts +95 -0
- package/lib/typescript/commonjs/src/utils/action.d.ts +63 -0
- package/lib/typescript/commonjs/src/utils/crash.d.ts +12 -0
- package/lib/typescript/commonjs/src/utils/platform.d.ts +22 -0
- package/lib/typescript/{src → commonjs/src}/utils/session.d.ts +4 -0
- package/lib/typescript/module/src/NativeRumSdkReactnative.d.ts +49 -0
- package/lib/typescript/module/src/collector/action/index.d.ts +21 -0
- package/lib/typescript/module/src/collector/exception/crash.d.ts +28 -0
- package/lib/typescript/module/src/collector/exception/index.d.ts +32 -0
- package/lib/typescript/module/src/collector/index.d.ts +6 -0
- package/lib/typescript/module/src/collector/resource/api.d.ts +21 -0
- package/lib/typescript/module/src/collector/view/perf.d.ts +1 -0
- package/lib/typescript/module/src/collector/view/pv.d.ts +16 -0
- package/lib/typescript/module/src/expoConfigPlugin.d.ts +28 -0
- package/lib/typescript/module/src/index.d.ts +6 -0
- package/lib/typescript/module/src/plugin.d.ts +3 -0
- package/lib/typescript/module/src/processor/default-processor.d.ts +6 -0
- package/lib/typescript/module/src/processor/session-processor.d.ts +11 -0
- package/lib/typescript/module/src/reporter/index.d.ts +18 -0
- package/lib/typescript/module/src/reporter/monitor-reporter.d.ts +8 -0
- package/lib/typescript/module/src/shell.d.ts +57 -0
- package/lib/typescript/module/src/types/client.d.ts +27 -0
- package/lib/typescript/module/src/types/crash.d.ts +95 -0
- package/lib/typescript/module/src/types/index.d.ts +118 -0
- package/lib/typescript/module/src/utils/action.d.ts +63 -0
- package/lib/typescript/module/src/utils/api.d.ts +59 -0
- package/lib/typescript/module/src/utils/base.d.ts +8 -0
- package/lib/typescript/module/src/utils/crash.d.ts +12 -0
- package/lib/typescript/module/src/utils/platform.d.ts +22 -0
- package/lib/typescript/module/src/utils/session.d.ts +41 -0
- package/lib/typescript/module/src/utils/url.d.ts +17 -0
- package/lib/typescript/module/src/utils/view.d.ts +13 -0
- package/package.json +51 -28
- package/lib/module/collector/action/index.js.map +0 -1
- package/lib/module/collector/exception/index.js.map +0 -1
- package/lib/module/collector/resource/api.js.map +0 -1
- package/lib/module/collector/view/perf.js.map +0 -1
- package/lib/module/collector/view/pv.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/plugin.js.map +0 -1
- package/lib/module/processor/default-processor.js.map +0 -1
- package/lib/module/processor/session-processor.js.map +0 -1
- package/lib/module/reporter/index.js.map +0 -1
- package/lib/module/shell.js.map +0 -1
- package/lib/module/types/client.js.map +0 -1
- package/lib/module/types/index.js.map +0 -1
- package/lib/module/utils/api.js.map +0 -1
- package/lib/module/utils/base.js.map +0 -1
- package/lib/module/utils/platform.js.map +0 -1
- package/lib/module/utils/session.js.map +0 -1
- package/lib/module/utils/url.js.map +0 -1
- package/lib/module/utils/view.js.map +0 -1
- package/lib/typescript/src/collector/action/index.d.ts.map +0 -1
- package/lib/typescript/src/collector/exception/index.d.ts.map +0 -1
- package/lib/typescript/src/collector/resource/api.d.ts.map +0 -1
- package/lib/typescript/src/collector/view/perf.d.ts.map +0 -1
- package/lib/typescript/src/collector/view/pv.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts +0 -4
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/lib/typescript/src/plugin.d.ts.map +0 -1
- package/lib/typescript/src/processor/default-processor.d.ts.map +0 -1
- package/lib/typescript/src/processor/session-processor.d.ts.map +0 -1
- package/lib/typescript/src/reporter/index.d.ts.map +0 -1
- package/lib/typescript/src/shell.d.ts.map +0 -1
- package/lib/typescript/src/types/client.d.ts.map +0 -1
- package/lib/typescript/src/types/index.d.ts.map +0 -1
- package/lib/typescript/src/utils/api.d.ts.map +0 -1
- package/lib/typescript/src/utils/base.d.ts.map +0 -1
- package/lib/typescript/src/utils/platform.d.ts +0 -15
- package/lib/typescript/src/utils/platform.d.ts.map +0 -1
- package/lib/typescript/src/utils/session.d.ts.map +0 -1
- package/lib/typescript/src/utils/url.d.ts.map +0 -1
- package/lib/typescript/src/utils/view.d.ts.map +0 -1
- /package/lib/typescript/{src → commonjs/src}/collector/resource/api.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/collector/view/perf.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/collector/view/pv.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/plugin.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/processor/default-processor.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/types/client.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/types/index.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/utils/api.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/utils/base.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/utils/url.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/utils/view.d.ts +0 -0
- /package/lib/typescript/{package.json → module/package.json} +0 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
#include <unistd.h>
|
|
2
|
+
#include <signal.h>
|
|
3
|
+
#include <fcntl.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
#include <time.h>
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <errno.h>
|
|
8
|
+
#include <sys/ucontext.h>
|
|
9
|
+
#include "rum_module_info.h"
|
|
10
|
+
|
|
11
|
+
#define WRITE_BUF_SIZE 8192
|
|
12
|
+
#define BUILD_ID_HEX_CAP 128 // GNU build-id hex(通常 40 字符)+ 余量
|
|
13
|
+
#define MAX_REFERENCED_MODULES 32 // 按需过滤:栈帧引用的模块上限(去重后通常 3-10 个)
|
|
14
|
+
#define TRUNCATION_THRESHOLD 512 // 双侧截断阈值,与 rum_crash_handler.c 的 MAX_FRAMES 对齐
|
|
15
|
+
#define FRAMES_PER_SIDE 256 // 双侧截断时每侧保留的帧数
|
|
16
|
+
|
|
17
|
+
// async-signal-safe: write all bytes (handle partial writes / EINTR only)
|
|
18
|
+
static void safe_write(int fd, const char *buf, size_t len) {
|
|
19
|
+
size_t off = 0;
|
|
20
|
+
while (off < len) {
|
|
21
|
+
ssize_t n = write(fd, buf + off, len - off);
|
|
22
|
+
if (n > 0) {
|
|
23
|
+
off += (size_t)n;
|
|
24
|
+
} else if (n < 0) {
|
|
25
|
+
// 仅 EINTR 安全重试;其他错误(ENOSPC/EBADF/EIO)直接放弃,避免死循环
|
|
26
|
+
if (errno == EINTR) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
} else {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Append literal string to buffer; flush to fd when nearly full
|
|
37
|
+
static void buf_append(int fd, char *buf, size_t *pos, const char *s) {
|
|
38
|
+
while (*s) {
|
|
39
|
+
if (*pos >= WRITE_BUF_SIZE - 32) {
|
|
40
|
+
safe_write(fd, buf, *pos);
|
|
41
|
+
*pos = 0;
|
|
42
|
+
}
|
|
43
|
+
buf[(*pos)++] = *s++;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// async-signal-safe: append long long as decimal (handles LLONG_MIN safely)
|
|
48
|
+
static void buf_append_ll(int fd, char *buf, size_t *pos, long long val) {
|
|
49
|
+
char tmp[32];
|
|
50
|
+
int n = 0;
|
|
51
|
+
int negative = 0;
|
|
52
|
+
// 使用 unsigned long long 避免 -LLONG_MIN 溢出(未定义行为)
|
|
53
|
+
unsigned long long uval;
|
|
54
|
+
if (val < 0) {
|
|
55
|
+
negative = 1;
|
|
56
|
+
// 安全取反:-(val+1) 不会溢出,再 +1 得到正确绝对值
|
|
57
|
+
uval = (unsigned long long)(-(val + 1)) + 1ULL;
|
|
58
|
+
} else {
|
|
59
|
+
uval = (unsigned long long)val;
|
|
60
|
+
}
|
|
61
|
+
if (uval == 0) {
|
|
62
|
+
tmp[n++] = '0';
|
|
63
|
+
} else {
|
|
64
|
+
while (uval > 0) {
|
|
65
|
+
tmp[n++] = (char)('0' + (uval % 10));
|
|
66
|
+
uval /= 10;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (*pos >= WRITE_BUF_SIZE - (size_t)n - 4) {
|
|
70
|
+
safe_write(fd, buf, *pos);
|
|
71
|
+
*pos = 0;
|
|
72
|
+
}
|
|
73
|
+
if (negative) {
|
|
74
|
+
buf[(*pos)++] = '-';
|
|
75
|
+
}
|
|
76
|
+
for (int i = n - 1; i >= 0; i--) {
|
|
77
|
+
buf[(*pos)++] = tmp[i];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// async-signal-safe: append pointer as "0x..." hex (no padding)
|
|
82
|
+
static void buf_append_hex(int fd, char *buf, size_t *pos, uintptr_t val) {
|
|
83
|
+
static const char hex[] = "0123456789abcdef";
|
|
84
|
+
char tmp[20];
|
|
85
|
+
int n = 0;
|
|
86
|
+
if (val == 0) {
|
|
87
|
+
tmp[n++] = '0';
|
|
88
|
+
} else {
|
|
89
|
+
while (val > 0) {
|
|
90
|
+
tmp[n++] = hex[val & 0xF];
|
|
91
|
+
val >>= 4;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (*pos >= WRITE_BUF_SIZE - (size_t)n - 4) {
|
|
95
|
+
safe_write(fd, buf, *pos);
|
|
96
|
+
*pos = 0;
|
|
97
|
+
}
|
|
98
|
+
buf[(*pos)++] = '0';
|
|
99
|
+
buf[(*pos)++] = 'x';
|
|
100
|
+
for (int i = n - 1; i >= 0; i--) {
|
|
101
|
+
buf[(*pos)++] = tmp[i];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Map signal number to name (static, no allocation)
|
|
106
|
+
static const char *signal_name(int signum) {
|
|
107
|
+
switch (signum) {
|
|
108
|
+
case SIGSEGV: return "SIGSEGV";
|
|
109
|
+
case SIGABRT: return "SIGABRT";
|
|
110
|
+
case SIGBUS: return "SIGBUS";
|
|
111
|
+
case SIGFPE: return "SIGFPE";
|
|
112
|
+
case SIGILL: return "SIGILL";
|
|
113
|
+
case SIGTRAP: return "SIGTRAP";
|
|
114
|
+
default: return "UNKNOWN";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Emit "key":"hex_value", or "key":"hex_value" depending on trailing flag
|
|
119
|
+
static void emit_reg(int fd, char *buf, size_t *pos,
|
|
120
|
+
const char *key, uintptr_t val, int trailing_comma) {
|
|
121
|
+
buf_append(fd, buf, pos, "\"");
|
|
122
|
+
buf_append(fd, buf, pos, key);
|
|
123
|
+
buf_append(fd, buf, pos, "\":\"");
|
|
124
|
+
buf_append_hex(fd, buf, pos, val);
|
|
125
|
+
buf_append(fd, buf, pos, "\"");
|
|
126
|
+
if (trailing_comma) {
|
|
127
|
+
buf_append(fd, buf, pos, ",");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Escape and copy raw bytes into a JSON string value.
|
|
132
|
+
// Only escapes backslash, double-quote, and control chars.
|
|
133
|
+
static void buf_append_escaped(int fd, char *buf, size_t *pos,
|
|
134
|
+
const char *src, size_t len) {
|
|
135
|
+
for (size_t i = 0; i < len; i++) {
|
|
136
|
+
char c = src[i];
|
|
137
|
+
// ensure room for at most a 6-byte escape (\u00XX)
|
|
138
|
+
if (*pos >= WRITE_BUF_SIZE - 8) {
|
|
139
|
+
safe_write(fd, buf, *pos);
|
|
140
|
+
*pos = 0;
|
|
141
|
+
}
|
|
142
|
+
if (c == '\\' || c == '"') {
|
|
143
|
+
buf[(*pos)++] = '\\';
|
|
144
|
+
buf[(*pos)++] = c;
|
|
145
|
+
} else if (c == '\n') {
|
|
146
|
+
buf[(*pos)++] = '\\';
|
|
147
|
+
buf[(*pos)++] = 'n';
|
|
148
|
+
} else if (c == '\r') {
|
|
149
|
+
buf[(*pos)++] = '\\';
|
|
150
|
+
buf[(*pos)++] = 'r';
|
|
151
|
+
} else if (c == '\t') {
|
|
152
|
+
buf[(*pos)++] = '\\';
|
|
153
|
+
buf[(*pos)++] = 't';
|
|
154
|
+
} else if ((unsigned char)c < 0x20) {
|
|
155
|
+
// skip other control chars
|
|
156
|
+
} else {
|
|
157
|
+
buf[(*pos)++] = c;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 取路径 basename(最后一个 '/' 之后的部分),写入 *out_bn / *out_len。
|
|
163
|
+
static void basename_of(const char *path, int len,
|
|
164
|
+
const char **out_bn, int *out_len) {
|
|
165
|
+
const char *bn = path;
|
|
166
|
+
int bnlen = len;
|
|
167
|
+
for (int k = 0; k < len; k++) {
|
|
168
|
+
if (path[k] == '/') {
|
|
169
|
+
bn = path + k + 1;
|
|
170
|
+
bnlen = len - k - 1;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
*out_bn = bn;
|
|
174
|
+
*out_len = bnlen;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// async-signal-safe: 输出单个栈帧 JSON 对象,并收集被引用模块地址。
|
|
178
|
+
// 仅使用栈上数组、整数运算、safe_write,符合信号处理器约束。
|
|
179
|
+
static void emit_frame(int fd, char *buf, size_t *pos,
|
|
180
|
+
uintptr_t addr,
|
|
181
|
+
uintptr_t *referenced_addrs, int *referenced_count,
|
|
182
|
+
int *is_first) {
|
|
183
|
+
if (!*is_first) {
|
|
184
|
+
buf_append(fd, buf, pos, ",");
|
|
185
|
+
}
|
|
186
|
+
*is_first = 0;
|
|
187
|
+
|
|
188
|
+
buf_append(fd, buf, pos, "{\"address\":\"");
|
|
189
|
+
buf_append_hex(fd, buf, pos, addr);
|
|
190
|
+
buf_append(fd, buf, pos, "\"");
|
|
191
|
+
|
|
192
|
+
int si = rum_module_index_for_addr(addr);
|
|
193
|
+
if (si >= 0) {
|
|
194
|
+
uintptr_t base = rum_module_base_for_seg(si);
|
|
195
|
+
|
|
196
|
+
// 记录被引用模块的 image_addr(去重),供 binary_images 过滤
|
|
197
|
+
if (base != 0 && *referenced_count < MAX_REFERENCED_MODULES) {
|
|
198
|
+
int found = 0;
|
|
199
|
+
for (int r = 0; r < *referenced_count; r++) {
|
|
200
|
+
if (referenced_addrs[r] == base) {
|
|
201
|
+
found = 1;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (!found) {
|
|
206
|
+
referenced_addrs[(*referenced_count)++] = base;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
int plen = 0;
|
|
211
|
+
const char *path = rum_seg_path(si, &plen);
|
|
212
|
+
if (path != NULL && plen > 0) {
|
|
213
|
+
const char *bn;
|
|
214
|
+
int bnlen;
|
|
215
|
+
basename_of(path, plen, &bn, &bnlen);
|
|
216
|
+
buf_append(fd, buf, pos, ",\"library\":\"");
|
|
217
|
+
buf_append_escaped(fd, buf, pos, bn, (size_t)bnlen);
|
|
218
|
+
buf_append(fd, buf, pos, "\",\"image_addr\":\"");
|
|
219
|
+
buf_append_hex(fd, buf, pos, base);
|
|
220
|
+
buf_append(fd, buf, pos, "\",\"offset\":\"");
|
|
221
|
+
buf_append_hex(fd, buf, pos, addr - base);
|
|
222
|
+
buf_append(fd, buf, pos, "\"");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
buf_append(fd, buf, pos, "}");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
void rum_write_crash(int fd, int signum, siginfo_t *info, ucontext_t *uc,
|
|
229
|
+
void **frames, int frame_count) {
|
|
230
|
+
static char g_write_buf[WRITE_BUF_SIZE];
|
|
231
|
+
size_t pos = 0;
|
|
232
|
+
char *buf = g_write_buf;
|
|
233
|
+
|
|
234
|
+
// 获取秒级与毫秒级时间戳(clock_gettime 是 POSIX.1-2008 async-signal-safe)
|
|
235
|
+
struct timespec ts;
|
|
236
|
+
long long timestamp_ms = 0;
|
|
237
|
+
long long timestamp_sec = 0;
|
|
238
|
+
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
|
|
239
|
+
timestamp_ms = (long long)ts.tv_sec * 1000 + (long long)ts.tv_nsec / 1000000;
|
|
240
|
+
timestamp_sec = (long long)ts.tv_sec;
|
|
241
|
+
} else {
|
|
242
|
+
// 极端 fallback:clock_gettime 失败时退回 time()
|
|
243
|
+
timestamp_sec = (long long)time(NULL);
|
|
244
|
+
timestamp_ms = timestamp_sec * 1000;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// {"crash_id":"crash_native_{timestamp}_{pid}","timestamp":<ms>,
|
|
248
|
+
// crash_id 中保持秒级 timestamp 作为文件名标识,不影响时间显示
|
|
249
|
+
buf_append(fd, buf, &pos, "{\"crash_id\":\"crash_native_");
|
|
250
|
+
buf_append_ll(fd, buf, &pos, timestamp_sec);
|
|
251
|
+
buf_append(fd, buf, &pos, "_");
|
|
252
|
+
buf_append_ll(fd, buf, &pos, (long long)getpid());
|
|
253
|
+
buf_append(fd, buf, &pos, "\",\"timestamp\":");
|
|
254
|
+
buf_append_ll(fd, buf, &pos, timestamp_ms);
|
|
255
|
+
|
|
256
|
+
// "signal":{...},
|
|
257
|
+
buf_append(fd, buf, &pos, ",\"signal\":{\"number\":");
|
|
258
|
+
buf_append_ll(fd, buf, &pos, (long long)signum);
|
|
259
|
+
buf_append(fd, buf, &pos, ",\"name\":\"");
|
|
260
|
+
buf_append(fd, buf, &pos, signal_name(signum));
|
|
261
|
+
buf_append(fd, buf, &pos, "\"");
|
|
262
|
+
if (info != NULL) {
|
|
263
|
+
buf_append(fd, buf, &pos, ",\"code\":");
|
|
264
|
+
buf_append_ll(fd, buf, &pos, (long long)info->si_code);
|
|
265
|
+
buf_append(fd, buf, &pos, ",\"fault_address\":\"");
|
|
266
|
+
buf_append_hex(fd, buf, &pos, (uintptr_t)info->si_addr);
|
|
267
|
+
buf_append(fd, buf, &pos, "\"");
|
|
268
|
+
}
|
|
269
|
+
buf_append(fd, buf, &pos, "}");
|
|
270
|
+
|
|
271
|
+
// "pid","tid"
|
|
272
|
+
buf_append(fd, buf, &pos, ",\"pid\":");
|
|
273
|
+
buf_append_ll(fd, buf, &pos, (long long)getpid());
|
|
274
|
+
buf_append(fd, buf, &pos, ",\"tid\":");
|
|
275
|
+
buf_append_ll(fd, buf, &pos, (long long)gettid());
|
|
276
|
+
|
|
277
|
+
// "arch": per-build
|
|
278
|
+
buf_append(fd, buf, &pos, ",\"arch\":\"");
|
|
279
|
+
#if defined(__aarch64__)
|
|
280
|
+
buf_append(fd, buf, &pos, "arm64");
|
|
281
|
+
#elif defined(__arm__)
|
|
282
|
+
buf_append(fd, buf, &pos, "arm");
|
|
283
|
+
#elif defined(__x86_64__)
|
|
284
|
+
buf_append(fd, buf, &pos, "x86_64");
|
|
285
|
+
#elif defined(__i386__)
|
|
286
|
+
buf_append(fd, buf, &pos, "x86");
|
|
287
|
+
#else
|
|
288
|
+
buf_append(fd, buf, &pos, "unknown");
|
|
289
|
+
#endif
|
|
290
|
+
buf_append(fd, buf, &pos, "\"");
|
|
291
|
+
|
|
292
|
+
// "registers":{...}
|
|
293
|
+
buf_append(fd, buf, &pos, ",\"registers\":{");
|
|
294
|
+
if (uc != NULL) {
|
|
295
|
+
#if defined(__aarch64__)
|
|
296
|
+
emit_reg(fd, buf, &pos, "pc", (uintptr_t)uc->uc_mcontext.pc, 1);
|
|
297
|
+
emit_reg(fd, buf, &pos, "lr", (uintptr_t)uc->uc_mcontext.regs[30], 1);
|
|
298
|
+
emit_reg(fd, buf, &pos, "sp", (uintptr_t)uc->uc_mcontext.sp, 1);
|
|
299
|
+
emit_reg(fd, buf, &pos, "fp", (uintptr_t)uc->uc_mcontext.regs[29], 0);
|
|
300
|
+
#elif defined(__arm__)
|
|
301
|
+
emit_reg(fd, buf, &pos, "pc", (uintptr_t)uc->uc_mcontext.arm_pc, 1);
|
|
302
|
+
emit_reg(fd, buf, &pos, "lr", (uintptr_t)uc->uc_mcontext.arm_lr, 1);
|
|
303
|
+
emit_reg(fd, buf, &pos, "sp", (uintptr_t)uc->uc_mcontext.arm_sp, 1);
|
|
304
|
+
emit_reg(fd, buf, &pos, "fp", (uintptr_t)uc->uc_mcontext.arm_fp, 0);
|
|
305
|
+
#elif defined(__x86_64__)
|
|
306
|
+
emit_reg(fd, buf, &pos, "pc", (uintptr_t)uc->uc_mcontext.gregs[REG_RIP], 1);
|
|
307
|
+
emit_reg(fd, buf, &pos, "sp", (uintptr_t)uc->uc_mcontext.gregs[REG_RSP], 1);
|
|
308
|
+
emit_reg(fd, buf, &pos, "fp", (uintptr_t)uc->uc_mcontext.gregs[REG_RBP], 0);
|
|
309
|
+
#elif defined(__i386__)
|
|
310
|
+
emit_reg(fd, buf, &pos, "pc", (uintptr_t)uc->uc_mcontext.gregs[REG_EIP], 1);
|
|
311
|
+
emit_reg(fd, buf, &pos, "sp", (uintptr_t)uc->uc_mcontext.gregs[REG_ESP], 1);
|
|
312
|
+
emit_reg(fd, buf, &pos, "fp", (uintptr_t)uc->uc_mcontext.gregs[REG_EBP], 0);
|
|
313
|
+
#endif
|
|
314
|
+
}
|
|
315
|
+
buf_append(fd, buf, &pos, "}");
|
|
316
|
+
|
|
317
|
+
// 解析 /proc/self/maps(async-signal-safe),为帧提供模块归属与相对偏移
|
|
318
|
+
rum_modules_parse();
|
|
319
|
+
// 构建去重模块列表,供 emit_frame 获取模块级基址和 binary_images 枚举使用。
|
|
320
|
+
// 必须在 frames 循环前调用,确保 rum_module_base_for_seg() 能查到模块。
|
|
321
|
+
int mod_count = rum_module_build_distinct();
|
|
322
|
+
|
|
323
|
+
// binary_images 按需过滤:仅保留被栈帧引用的模块。
|
|
324
|
+
// 参照 Sentry 实践,服务端符号化时忽略未被任何栈帧引用的模块,
|
|
325
|
+
// 客户端过滤可减少 70-90% 的 binary_images 数据量。
|
|
326
|
+
// 数组大小 32 足够:帧最多 256 个,去重后引用的模块通常 3-10 个。
|
|
327
|
+
// 所有操作仅为内存读写与整数比较,符合 async-signal-safe。
|
|
328
|
+
uintptr_t referenced_addrs[MAX_REFERENCED_MODULES];
|
|
329
|
+
int referenced_count = 0;
|
|
330
|
+
|
|
331
|
+
// "frames":[{"address","library","image_addr","offset"}, ...]
|
|
332
|
+
// library/offset 供后端结合 binary_images 的 build_id 精确符号化
|
|
333
|
+
//
|
|
334
|
+
// NDK 信号处理器最多采集 MAX_FRAMES(512) 帧。frame_count 达到
|
|
335
|
+
// TRUNCATION_THRESHOLD(512) 时说明实际栈可能更长(已达到采集上限),
|
|
336
|
+
// 此时全部输出 512 帧 + 尾部标记帧(omitted_count=-1 表示实际总帧数
|
|
337
|
+
// 未知),不做双侧截断——因为 NDK 只能获取前 512 帧,前 256 + 后 256
|
|
338
|
+
// 恰好覆盖全部 512 帧,中间无省略,插入中间标记帧会造成冗余。
|
|
339
|
+
// frame_count < TRUNCATION_THRESHOLD 时全部输出,不截断。
|
|
340
|
+
// 所有操作仅为栈上数组读写与整数比较,符合 async-signal-safe。
|
|
341
|
+
buf_append(fd, buf, &pos, ",\"frames\":[");
|
|
342
|
+
int needs_tail_marker = (frame_count >= TRUNCATION_THRESHOLD);
|
|
343
|
+
int first = 1;
|
|
344
|
+
|
|
345
|
+
for (int i = 0; i < frame_count; i++) {
|
|
346
|
+
emit_frame(fd, buf, &pos, (uintptr_t)frames[i],
|
|
347
|
+
referenced_addrs, &referenced_count, &first);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (needs_tail_marker) {
|
|
351
|
+
// 尾部标记帧(omitted_count=-1 表示实际总帧数未知)
|
|
352
|
+
if (!first) {
|
|
353
|
+
buf_append(fd, buf, &pos, ",");
|
|
354
|
+
}
|
|
355
|
+
buf_append(fd, buf, &pos, "{\"truncated\":true,\"omitted_count\":-1}");
|
|
356
|
+
}
|
|
357
|
+
buf_append(fd, buf, &pos, "]");
|
|
358
|
+
|
|
359
|
+
// 在进入 binary_images 循环前,先刷新核心崩溃数据到磁盘。
|
|
360
|
+
// binary_images 枚举需调用 rum_module_build_id_hex() 读取各模块 ELF 头,
|
|
361
|
+
// 若某模块地址未映射可能触发二次 SIGSEGV。提前刷新确保 crash_id、
|
|
362
|
+
// timestamp、signal、registers、frames 等核心数据已落盘,
|
|
363
|
+
// 即使后续崩溃也能被后端解析恢复。
|
|
364
|
+
if (pos > 0) {
|
|
365
|
+
safe_write(fd, buf, pos);
|
|
366
|
+
pos = 0;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// "binary_images":[{"name","build_id","image_addr","image_size"}, ...]
|
|
370
|
+
// 仅上报带 GNU build-id 的 file-backed 模块(build-id 等价于 iOS image uuid,
|
|
371
|
+
// 用于后端精确匹配符号文件)。
|
|
372
|
+
buf_append(fd, buf, &pos, ",\"binary_images\":[");
|
|
373
|
+
int emitted = 0;
|
|
374
|
+
char bid[BUILD_ID_HEX_CAP];
|
|
375
|
+
for (int m = 0; m < mod_count; m++) {
|
|
376
|
+
uintptr_t base = rum_module_image_addr(m);
|
|
377
|
+
|
|
378
|
+
// 按需过滤:若已收集到被引用的模块地址,则跳过未被引用的模块。
|
|
379
|
+
// referenced_count == 0(未收集到引用)或 == MAX_REFERENCED_MODULES
|
|
380
|
+
// (达到上限,可能有第 33+ 个被引用模块未被记录)时不过滤,
|
|
381
|
+
// 输出全部模块作为 fallback,确保不丢失符号化信息。
|
|
382
|
+
if (referenced_count > 0 && referenced_count < MAX_REFERENCED_MODULES) {
|
|
383
|
+
int is_referenced = 0;
|
|
384
|
+
for (int r = 0; r < referenced_count; r++) {
|
|
385
|
+
if (referenced_addrs[r] == base) {
|
|
386
|
+
is_referenced = 1;
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (!is_referenced) {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
int n = rum_module_build_id_hex(base, bid, BUILD_ID_HEX_CAP - 1);
|
|
396
|
+
if (n <= 0) {
|
|
397
|
+
continue; // 无 build-id 的模块不上报
|
|
398
|
+
}
|
|
399
|
+
bid[n] = '\0';
|
|
400
|
+
|
|
401
|
+
if (emitted > 0) {
|
|
402
|
+
buf_append(fd, buf, &pos, ",");
|
|
403
|
+
}
|
|
404
|
+
emitted++;
|
|
405
|
+
|
|
406
|
+
int nlen = 0;
|
|
407
|
+
const char *name = rum_module_name(m, &nlen);
|
|
408
|
+
const char *bn = name;
|
|
409
|
+
int bnlen = nlen;
|
|
410
|
+
if (name != NULL && nlen > 0) {
|
|
411
|
+
basename_of(name, nlen, &bn, &bnlen);
|
|
412
|
+
}
|
|
413
|
+
// type 字段为 Sentry debug_meta 规范必填,ELF 平台固定 "elf"
|
|
414
|
+
buf_append(fd, buf, &pos, "{\"type\":\"elf\",\"name\":\"");
|
|
415
|
+
if (bn != NULL && bnlen > 0) {
|
|
416
|
+
buf_append_escaped(fd, buf, &pos, bn, (size_t)bnlen);
|
|
417
|
+
}
|
|
418
|
+
buf_append(fd, buf, &pos, "\",\"build_id\":\"");
|
|
419
|
+
buf_append(fd, buf, &pos, bid);
|
|
420
|
+
buf_append(fd, buf, &pos, "\",\"image_addr\":\"");
|
|
421
|
+
buf_append_hex(fd, buf, &pos, base);
|
|
422
|
+
// image_size 为数字类型(Sentry 规范要求),使用十进制写入
|
|
423
|
+
buf_append(fd, buf, &pos, "\",\"image_size\":");
|
|
424
|
+
buf_append_ll(fd, buf, &pos, (long long)rum_module_image_size(m));
|
|
425
|
+
buf_append(fd, buf, &pos, "}");
|
|
426
|
+
}
|
|
427
|
+
buf_append(fd, buf, &pos, "]");
|
|
428
|
+
|
|
429
|
+
// close JSON
|
|
430
|
+
buf_append(fd, buf, &pos, "}\n");
|
|
431
|
+
|
|
432
|
+
// flush remainder
|
|
433
|
+
if (pos > 0) {
|
|
434
|
+
safe_write(fd, buf, pos);
|
|
435
|
+
}
|
|
436
|
+
}
|