|
70 | 70 | */ |
71 | 71 |
|
72 | 72 | #define CRASH_ALTSTACK_SIZE (64 * 1024) |
| 73 | +#define CRASH_SNAPSHOT_VERSION_V2 2 |
| 74 | + |
| 75 | +struct crash_snapshot_record_header { |
| 76 | + uint32_t magic; |
| 77 | + uint16_t version; |
| 78 | + uint16_t arch; |
| 79 | + uint32_t size; |
| 80 | +}; |
| 81 | + |
| 82 | +struct crash_snapshot_record_v2 { |
| 83 | + uint32_t magic; |
| 84 | + uint16_t version; |
| 85 | + uint16_t arch; |
| 86 | + uint32_t size; |
| 87 | + uint32_t signal; |
| 88 | + int32_t si_code; |
| 89 | + uint32_t pid; |
| 90 | + uint32_t tid; |
| 91 | + uint64_t fault_addr; |
| 92 | + uint64_t ip; |
| 93 | + uint64_t sp; |
| 94 | + uint64_t fp; |
| 95 | + uint64_t lr; |
| 96 | + uint64_t args[CRASH_SNAPSHOT_ARG_REGS]; |
| 97 | + char executable_path[CRASH_SNAPSHOT_MODULE_PATH_LEN]; |
| 98 | + uint32_t modules_count; |
| 99 | + uint32_t frames_count; |
| 100 | + struct crash_snapshot_module modules[CRASH_SNAPSHOT_MAX_MODULES]; |
| 101 | + struct crash_snapshot_frame frames[CRASH_SNAPSHOT_MAX_FRAMES]; |
| 102 | +}; |
73 | 103 |
|
74 | 104 | /* |
75 | 105 | * Process-wide and thread-local state used by the crash monitor. |
@@ -118,6 +148,8 @@ static struct crash_snapshot_module crash_cached_modules[ |
118 | 148 | CRASH_SNAPSHOT_MAX_MODULES]; |
119 | 149 | static uint32_t crash_cached_modules_count; |
120 | 150 | static char crash_cached_executable_path[CRASH_SNAPSHOT_MODULE_PATH_LEN]; |
| 151 | +static char crash_cached_process_name[CRASH_SNAPSHOT_TASK_NAME_LEN]; |
| 152 | +static __thread char crash_thread_name[CRASH_SNAPSHOT_TASK_NAME_LEN]; |
121 | 153 |
|
122 | 154 | /* |
123 | 155 | * Fatal signals considered interesting enough to capture. These all represent |
@@ -242,6 +274,47 @@ static int crash_cache_executable_path(void) |
242 | 274 | return ETR_OK; |
243 | 275 | } |
244 | 276 |
|
| 277 | +static void crash_cache_process_name(void) |
| 278 | +{ |
| 279 | + ssize_t nread; |
| 280 | + int fd; |
| 281 | + |
| 282 | + crash_cached_process_name[0] = '\0'; |
| 283 | + fd = open("/proc/self/comm", O_RDONLY | O_CLOEXEC); |
| 284 | + if (fd < 0) |
| 285 | + return; |
| 286 | + nread = read(fd, crash_cached_process_name, |
| 287 | + sizeof(crash_cached_process_name) - 1); |
| 288 | + close(fd); |
| 289 | + if (nread <= 0) { |
| 290 | + crash_cached_process_name[0] = '\0'; |
| 291 | + return; |
| 292 | + } |
| 293 | + crash_cached_process_name[nread] = '\0'; |
| 294 | + crash_trim_trailing_newline(crash_cached_process_name); |
| 295 | +} |
| 296 | + |
| 297 | +static void crash_copy_thread_name(char *dst, size_t dst_size) |
| 298 | +{ |
| 299 | + if (dst == NULL || dst_size == 0) |
| 300 | + return; |
| 301 | + dst[0] = '\0'; |
| 302 | + if (crash_thread_name[0] != '\0') { |
| 303 | + crash_copy_cstr(dst, dst_size, crash_thread_name); |
| 304 | + return; |
| 305 | + } |
| 306 | + crash_copy_cstr(dst, dst_size, crash_cached_process_name); |
| 307 | +} |
| 308 | + |
| 309 | +void crash_monitor_set_thread_name(const char *name) |
| 310 | +{ |
| 311 | + if (name == NULL || name[0] == '\0') { |
| 312 | + crash_thread_name[0] = '\0'; |
| 313 | + return; |
| 314 | + } |
| 315 | + crash_copy_cstr(crash_thread_name, sizeof(crash_thread_name), name); |
| 316 | +} |
| 317 | + |
245 | 318 | static void crash_fill_module_build_id(struct crash_snapshot_module *module) |
246 | 319 | { |
247 | 320 | uint32_t build_id_size = 0; |
@@ -290,6 +363,7 @@ static int crash_cache_modules(void) |
290 | 363 | crash_cached_modules_count = 0; |
291 | 364 | memset(crash_cached_modules, 0, sizeof(crash_cached_modules)); |
292 | 365 | (void)crash_cache_executable_path(); |
| 366 | + crash_cache_process_name(); |
293 | 367 |
|
294 | 368 | maps = fopen("/proc/self/maps", "r"); |
295 | 369 | if (maps == NULL) |
@@ -354,6 +428,7 @@ static void crash_copy_cached_modules_to_record(struct crash_snapshot_record *re |
354 | 428 | record->modules_count = crash_cached_modules_count; |
355 | 429 | crash_copy_cstr(record->executable_path, sizeof(record->executable_path), |
356 | 430 | crash_cached_executable_path); |
| 431 | + crash_copy_thread_name(record->thread_name, sizeof(record->thread_name)); |
357 | 432 | for (i = 0; i < crash_cached_modules_count; i++) |
358 | 433 | crash_copy_module(&record->modules[i], &crash_cached_modules[i]); |
359 | 434 | } |
@@ -793,6 +868,105 @@ static int crash_install_signal_handlers(void) |
793 | 868 | return ETR_OK; |
794 | 869 | } |
795 | 870 |
|
| 871 | +static void crash_upgrade_v2_record(struct crash_snapshot_record *dst, |
| 872 | + const struct crash_snapshot_record_v2 *src) |
| 873 | +{ |
| 874 | + if (dst == NULL || src == NULL) |
| 875 | + return; |
| 876 | + |
| 877 | + memset(dst, 0, sizeof(*dst)); |
| 878 | + dst->magic = src->magic; |
| 879 | + dst->version = CRASH_SNAPSHOT_VERSION; |
| 880 | + dst->arch = src->arch; |
| 881 | + dst->size = sizeof(*dst); |
| 882 | + dst->signal = src->signal; |
| 883 | + dst->si_code = src->si_code; |
| 884 | + dst->pid = src->pid; |
| 885 | + dst->tid = src->tid; |
| 886 | + dst->fault_addr = src->fault_addr; |
| 887 | + dst->ip = src->ip; |
| 888 | + dst->sp = src->sp; |
| 889 | + dst->fp = src->fp; |
| 890 | + dst->lr = src->lr; |
| 891 | + crash_copy_bytes(dst->args, sizeof(dst->args), src->args, |
| 892 | + sizeof(src->args)); |
| 893 | + crash_copy_cstr(dst->executable_path, sizeof(dst->executable_path), |
| 894 | + src->executable_path); |
| 895 | + dst->modules_count = src->modules_count; |
| 896 | + dst->frames_count = src->frames_count; |
| 897 | + crash_copy_bytes(dst->modules, sizeof(dst->modules), src->modules, |
| 898 | + sizeof(src->modules)); |
| 899 | + crash_copy_bytes(dst->frames, sizeof(dst->frames), src->frames, |
| 900 | + sizeof(src->frames)); |
| 901 | +} |
| 902 | + |
| 903 | +static int crash_read_next_pending_record(int fd, |
| 904 | + struct crash_snapshot_record *record, |
| 905 | + ssize_t *nread_out) |
| 906 | +{ |
| 907 | + struct crash_snapshot_record_header header; |
| 908 | + ssize_t nread; |
| 909 | + ssize_t remain; |
| 910 | + |
| 911 | + if (record == NULL || nread_out == NULL) |
| 912 | + return ETR_INVAL; |
| 913 | + *nread_out = 0; |
| 914 | + |
| 915 | + nread = read(fd, &header, sizeof(header)); |
| 916 | + if (nread <= 0) { |
| 917 | + *nread_out = nread; |
| 918 | + return (nread == 0) ? ETR_OK : ETR_INVAL; |
| 919 | + } |
| 920 | + if (nread != sizeof(header)) { |
| 921 | + *nread_out = nread; |
| 922 | + return ETR_INVAL; |
| 923 | + } |
| 924 | + |
| 925 | + if (header.magic != CRASH_SNAPSHOT_MAGIC) { |
| 926 | + *nread_out = sizeof(header); |
| 927 | + return ETR_NOTEXIST; |
| 928 | + } |
| 929 | + |
| 930 | + if (header.version == CRASH_SNAPSHOT_VERSION && |
| 931 | + header.size == sizeof(*record)) { |
| 932 | + struct crash_snapshot_record *on_disk = record; |
| 933 | + |
| 934 | + memset(on_disk, 0, sizeof(*on_disk)); |
| 935 | + on_disk->magic = header.magic; |
| 936 | + on_disk->version = header.version; |
| 937 | + on_disk->arch = header.arch; |
| 938 | + on_disk->size = header.size; |
| 939 | + remain = (ssize_t)sizeof(*on_disk) - (ssize_t)sizeof(header); |
| 940 | + nread = read(fd, (char *)on_disk + sizeof(header), (size_t)remain); |
| 941 | + *nread_out = sizeof(header) + nread; |
| 942 | + if (nread != remain) |
| 943 | + return ETR_INVAL; |
| 944 | + return ETR_OK; |
| 945 | + } |
| 946 | + |
| 947 | + if (header.version == CRASH_SNAPSHOT_VERSION_V2 && |
| 948 | + header.size == sizeof(struct crash_snapshot_record_v2)) { |
| 949 | + struct crash_snapshot_record_v2 old_record; |
| 950 | + |
| 951 | + memset(&old_record, 0, sizeof(old_record)); |
| 952 | + old_record.magic = header.magic; |
| 953 | + old_record.version = header.version; |
| 954 | + old_record.arch = header.arch; |
| 955 | + old_record.size = header.size; |
| 956 | + remain = (ssize_t)sizeof(old_record) - (ssize_t)sizeof(header); |
| 957 | + nread = read(fd, (char *)&old_record + sizeof(header), |
| 958 | + (size_t)remain); |
| 959 | + *nread_out = sizeof(header) + nread; |
| 960 | + if (nread != remain) |
| 961 | + return ETR_INVAL; |
| 962 | + crash_upgrade_v2_record(record, &old_record); |
| 963 | + return ETR_OK; |
| 964 | + } |
| 965 | + |
| 966 | + *nread_out = sizeof(header); |
| 967 | + return ETR_NOTEXIST; |
| 968 | +} |
| 969 | + |
796 | 970 | static void crash_log_pending_record(const struct crash_snapshot_record *record) |
797 | 971 | { |
798 | 972 | if (record == NULL) |
@@ -836,23 +1010,24 @@ int crash_monitor_consume_pending_snapshots(void) |
836 | 1010 | return ETR_INVAL; |
837 | 1011 | } |
838 | 1012 |
|
839 | | - while ((nread = read(fd, &record, sizeof(record))) == sizeof(record)) { |
840 | | - if (record.magic != CRASH_SNAPSHOT_MAGIC || |
841 | | - record.version != CRASH_SNAPSHOT_VERSION || |
842 | | - record.size != sizeof(record)) { |
| 1013 | + for (;;) { |
| 1014 | + int ret = crash_read_next_pending_record(fd, &record, &nread); |
| 1015 | + |
| 1016 | + if (ret == ETR_OK && nread == 0) |
| 1017 | + break; |
| 1018 | + if (ret == ETR_OK) { |
| 1019 | + crash_log_pending_record(&record); |
| 1020 | + continue; |
| 1021 | + } |
| 1022 | + if (ret == ETR_NOTEXIST) { |
843 | 1023 | ebpf_warning("Discard invalid crash snapshot record from %s\n", |
844 | 1024 | path); |
845 | 1025 | continue; |
846 | 1026 | } |
847 | | - crash_log_pending_record(&record); |
848 | | - } |
849 | | - |
850 | | - if (nread < 0) { |
851 | 1027 | close(fd); |
852 | 1028 | return ETR_INVAL; |
853 | 1029 | } |
854 | | - if (nread != 0) |
855 | | - ebpf_warning("Discard truncated crash snapshot file %s\n", path); |
| 1030 | + |
856 | 1031 | if (ftruncate(fd, 0) != 0) { |
857 | 1032 | close(fd); |
858 | 1033 | return ETR_INVAL; |
|
0 commit comments