diff --git a/tools/acrn-crashlog/acrnprobe/android_events.c b/tools/acrn-crashlog/acrnprobe/android_events.c index d88f4a288..56c7e1f2f 100644 --- a/tools/acrn-crashlog/acrnprobe/android_events.c +++ b/tools/acrn-crashlog/acrnprobe/android_events.c @@ -448,3 +448,47 @@ void refresh_vm_history(struct sender_t *sender, } } } + +int android_event_analyze(const char *msg, size_t len, char **result, + size_t *rsize) +{ + char *data; + char *tail; + size_t data_len; + char event[ANDROID_WORD_LEN]; + char longtime[ANDROID_WORD_LEN]; + char type[ANDROID_WORD_LEN]; + char rest[PATH_MAX]; + char vmkey[ANDROID_WORD_LEN]; + const char * const format = + ANDROID_ENEVT_FMT ANDROID_KEY_FMT ANDROID_LONGTIME_FMT + ANDROID_TYPE_FMT ANDROID_LINE_REST_FMT; + + if (str_split_ere(msg, len, format, strlen(format), event, + sizeof(event), vmkey, sizeof(vmkey), longtime, + sizeof(longtime), type, sizeof(type), rest, + sizeof(rest)) != 5) { + LOGE("try to analyze an invalid line (%s), skip\n", msg); + return -1; + } + + data_len = strnlen(vmkey, sizeof(vmkey)) + 1; + data_len += strnlen(event, sizeof(event)) + 1; + data_len += strnlen(type, sizeof(type)) + 1; + data_len += strnlen(rest, sizeof(rest)) + 1; + + data = malloc(data_len); + if (!data) + return -1; + tail = (char *)mempcpy(data, vmkey, strnlen(vmkey, sizeof(vmkey))); + *(tail++) = '\0'; + tail = (char *)mempcpy(tail, event, strnlen(event, sizeof(event))); + *(tail++) = '\0'; + tail = (char *)mempcpy(tail, type, strnlen(type, sizeof(type))); + *(tail++) = '\0'; + *(char *)mempcpy(tail, rest, strnlen(rest, sizeof(rest))) = '\0'; + + *result = data; + *rsize = data_len; + return 0; +} diff --git a/tools/acrn-crashlog/acrnprobe/crash_reclassify.c b/tools/acrn-crashlog/acrnprobe/crash_reclassify.c index 8f78c274b..929c84443 100644 --- a/tools/acrn-crashlog/acrnprobe/crash_reclassify.c +++ b/tools/acrn-crashlog/acrnprobe/crash_reclassify.c @@ -125,38 +125,56 @@ static int crash_match_content(const struct crash_t *crash, const char *file) crash_has_mightcontents(crash, file); } -static ssize_t _get_data(const char *file, const struct crash_t *crash, - char **data, const int index) +static int _get_data(const char *file, const struct crash_t *crash, + char **data, size_t *dsize, const int index) { const char *search_key; char *value; char *end; + char *data_new; ssize_t size; const size_t max_size = 255; search_key = crash->data[index]; if (!search_key) - return 0; + goto empty; value = strrstr(file, search_key); if (!value) - return 0; + goto empty; end = strchr(value, '\n'); if (!end) - return 0; + goto empty; size = MIN(max_size, (size_t)(end - value)); if (!size) - return 0; + goto empty; - *data = malloc(size + 1); - if (*data == NULL) - return -ENOMEM; + data_new = realloc(*data, *dsize + size + 1); + if (!data_new) { + LOGE("failed to realloc\n"); + return -1; + } - strncpy(*data, value, size); - *(*data + size) = 0; - return size; + strncpy(data_new + *dsize, value, size); + *(data_new + *dsize + size) = 0; + + *data = data_new; + *dsize += size; + return 0; +empty: + data_new = realloc(*data, *dsize + 1); + if (!data_new) { + LOGE("failed to realloc\n"); + return -1; + } + + *(data_new + *dsize) = 0; + + *data = data_new; + *dsize += 1; + return 0; } /** @@ -165,48 +183,29 @@ static ssize_t _get_data(const char *file, const struct crash_t *crash, * * @param file Starting address of file cache. * @param crash Crash need checking. - * @param[out] data0 Searched result, according to 'data0' configuread in crash. - * @param[out] data1 Searched result, according to 'data1' configuread in crash. - * @param[out] data2 Searched result, according to 'data2' configuread in crash. + * @param[out] data Searched result, according to 'data' configuread in crash. * * @return 0 if successful, or -1 if not. */ static int get_data(const char *file, const struct crash_t *crash, - char **data0, size_t *d0len, char **data1, - size_t *d1len, char **data2, size_t *d2len) + char **r_data, size_t *r_dsize) { - ssize_t res; + char *data = NULL; + size_t dsize = 0; + int i; /* to find strings which match conf words */ - res = _get_data(file, crash, data0, 0); - if (res < 0) - goto fail; - *d0len = (size_t)res; - - res = _get_data(file, crash, data1, 1); - if (res < 0) - goto free_data0; - *d1len = (size_t)res; - - res = _get_data(file, crash, data2, 2); - if (res < 0) - goto free_data1; - *d2len = (size_t)res; + for (i = 0; i < DATA_MAX; i++) { + if (_get_data(file, crash, &data, &dsize, i) == -1) + goto fail; + } + *r_data = data; + *r_dsize = dsize; return 0; -free_data1: - if (*data1) - free(*data1); -free_data0: - if (*data0) - free(*data0); fail: - *data0 = NULL; - *data1 = NULL; - *data2 = NULL; - *d0len = 0; - *d1len = 0; - *d2len = 0; + if (data) + free(data); return -1; } @@ -276,18 +275,14 @@ static struct crash_t *crash_find_matched_child(const struct crash_t *crash, * * @param rcrash Root crash obtained from channel. * @param rtrfile_fmt Path fmt of trigger file of root crash. - * @param[out] data0 Searched result, according to 'data0' configuread in crash. - * @param[out] data1 Searched result, according to 'data1' configuread in crash. - * @param[out] data2 Searched result, according to 'data2' configuread in crash. + * @param[out] data Searched result, according to 'data' configuread in crash. * * @return a pointer to the calculated crash structure if successful, * or NULL if not. */ static struct crash_t *crash_reclassify_by_content(const struct crash_t *rcrash, const char *rtrfile_fmt, - char **data0, size_t *d0len, - char **data1, size_t *d1len, - char **data2, size_t *d2len) + char **data, size_t *dsize) { int count; const struct crash_t *crash; @@ -298,15 +293,9 @@ static struct crash_t *crash_reclassify_by_content(const struct crash_t *rcrash, unsigned long size; int i; - if (!rcrash || !data0 || !d0len || !data1 || !d1len || !data2 || !d2len) + if (!rcrash || !data || !dsize) return NULL; - *data0 = NULL; - *data1 = NULL; - *data2 = NULL; - *d0len = 0; - *d1len = 0; - *d2len = 0; crash = rcrash; while (1) { @@ -339,8 +328,7 @@ static struct crash_t *crash_reclassify_by_content(const struct crash_t *rcrash, if (!size) goto free_files; - if (get_data(content, ret_crash, data0, d0len, data1, d1len, - data2, d2len) == -1) + if (get_data(content, ret_crash, data, dsize) == -1) LOGE("failed to get data\n"); free(content); diff --git a/tools/acrn-crashlog/acrnprobe/include/android_events.h b/tools/acrn-crashlog/acrnprobe/include/android_events.h index 292998033..20bd7346d 100644 --- a/tools/acrn-crashlog/acrnprobe/include/android_events.h +++ b/tools/acrn-crashlog/acrnprobe/include/android_events.h @@ -41,5 +41,6 @@ struct vm_event_t { void refresh_vm_history(struct sender_t *sender, int (*fn)(const char*, size_t, const struct vm_t *)); - +int android_event_analyze(const char *msg, size_t len, char **result, + size_t *rsize); #endif diff --git a/tools/acrn-crashlog/acrnprobe/include/load_conf.h b/tools/acrn-crashlog/acrnprobe/include/load_conf.h index 7956d9277..57e6191bb 100644 --- a/tools/acrn-crashlog/acrnprobe/include/load_conf.h +++ b/tools/acrn-crashlog/acrnprobe/include/load_conf.h @@ -92,7 +92,6 @@ struct crash_t { int wd; int level; struct crash_t *(*reclassify)(const struct crash_t *, const char*, - char**, size_t *, char**, size_t *, char**, size_t *); }; diff --git a/tools/acrn-crashlog/acrnprobe/sender.c b/tools/acrn-crashlog/acrnprobe/sender.c index 53b983dcc..75cf073ba 100644 --- a/tools/acrn-crashlog/acrnprobe/sender.c +++ b/tools/acrn-crashlog/acrnprobe/sender.c @@ -720,9 +720,8 @@ static void telemd_send(struct event_t *e) } #endif -static void crashlog_send_crash(struct event_t *e) +static void crashlog_send_crash(struct event_t *e, char *data, size_t dlen) { - struct crash_t *crash; char *key; char *data0; char *data1; @@ -730,34 +729,14 @@ static void crashlog_send_crash(struct event_t *e) size_t d0len; size_t d1len; size_t d2len; - char *trfile = NULL; - struct crash_t *rcrash = (struct crash_t *)e->private; - - if (!strcmp(rcrash->trigger->type, "dir")) { - if (asprintf(&trfile, "%s/%s", rcrash->trigger->path, - e->path) == -1) { - LOGE("out of memory\n"); - return; - } - } - - crash = rcrash->reclassify(rcrash, trfile, &data0, &d0len, &data1, - &d1len, &data2, &d2len); - if (trfile) - free(trfile); - if (crash == NULL) { - LOGE("failed to reclassify rcrash (%s)\n", rcrash->name); - return; - } - /* change the class for other senders */ - e->private = (void *)crash; + struct crash_t *crash = (struct crash_t *)e->private; key = generate_event_id("CRASH", 5, (const char *)crash->name, crash->name_len, KEY_SHORT); if (key == NULL) { LOGE("failed to generate event id, error (%s)\n", strerror(errno)); - goto free_data; + return; } /* check space before collecting logs */ @@ -766,6 +745,12 @@ static void crashlog_send_crash(struct event_t *e) goto free_key; } + data0 = strings_ind(data, dlen, 0, &d0len); + data1 = strings_ind(data, dlen, 1, &d1len); + data2 = strings_ind(data, dlen, 2, &d2len); + if (!data1 || !data1 || !data2) + goto free_key; + if (to_collect_logs(crash) || !strcmp(e->channel, "inotify")) { struct log_t *log; int id; @@ -816,13 +801,6 @@ static void crashlog_send_crash(struct event_t *e) free_key: free(key); -free_data: - if (data0) - free(data0); - if (data1) - free(data1); - if (data2) - free(data2); } static void crashlog_send_info(struct event_t *e) @@ -906,39 +884,35 @@ static void crashlog_send_reboot(void) free(key); } -static void crashlog_send_vmevent(struct event_t *e) +static void crashlog_send_vmevent(struct event_t *e, char *data, size_t dlen) { - char event[ANDROID_WORD_LEN]; - char longtime[ANDROID_WORD_LEN]; - char type[ANDROID_WORD_LEN]; - char rest[PATH_MAX]; - char vmkey[ANDROID_WORD_LEN]; - char *vmlogpath = NULL; + char *vmkey; + char *event; + char *type; + char *rest; + size_t klen; + size_t elen; + size_t tlen; + size_t rlen; + char *vmlogpath; char *key; char *log; int res; int cnt; ext2_filsys datafs; struct sender_t *crashlog = get_sender_by_name("crashlog"); - struct vm_event_t *vme; + struct vm_event_t *vme = (struct vm_event_t *)e->private; enum vmrecord_mark_t mark = SUCCESS; - const char * const vm_format = - ANDROID_ENEVT_FMT ANDROID_KEY_FMT ANDROID_LONGTIME_FMT - ANDROID_TYPE_FMT ANDROID_LINE_REST_FMT; - if (!crashlog) return; - vme = (struct vm_event_t *)e->private; - res = str_split_ere(vme->vm_msg, vme->vm_msg_len, vm_format, - strlen(vm_format), event, sizeof(event), - vmkey, sizeof(vmkey), longtime, sizeof(longtime), - type, sizeof(type), rest, sizeof(rest)); - if (res != 5) { - LOGE("get an invalid line from (%s), skip\n", vme->vm->name); + vmkey = strings_ind(data, dlen, 0, &klen); + event = strings_ind(data, dlen, 1, &elen); + type = strings_ind(data, dlen, 2, &tlen); + rest = strings_ind(data, dlen, 3, &rlen); + if (!vmkey || !event || !type || !rest) return; - } key = generate_event_id("SOS", 3, (const char *)vmkey, strnlen(vmkey, ANDROID_WORD_LEN), KEY_SHORT); @@ -1013,12 +987,60 @@ mark_record: return; } +static int crashlog_event_analyze(struct event_t *e, char **result, + size_t *rsize) +{ + struct crash_t *rcrash; + struct crash_t *crash; + char *trfile = NULL; + struct vm_event_t *vme; + + switch (e->event_type) { + case CRASH: + rcrash = (struct crash_t *)e->private; + if (!strcmp(rcrash->trigger->type, "dir")) { + if (asprintf(&trfile, "%s/%s", rcrash->trigger->path, + e->path) == -1) { + LOGE("failed to asprintf\n"); + return -1; + } + } + crash = rcrash->reclassify(rcrash, trfile, result, rsize); + if (trfile) + free(trfile); + if (!crash) { + LOGE("failed to reclassify (%s)\n", rcrash->name); + return -1; + } + /* change the class */ + e->private = (void *)crash; + break; + case VM: + vme = (struct vm_event_t *)e->private; + if (android_event_analyze(vme->vm_msg, vme->vm_msg_len, + result, rsize) == -1) { + LOGE("failed to analyze android event\n"); + return -1; + } + break; + default: + break; + } + return 0; +} + static void crashlog_send(struct event_t *e) { int id; struct log_t *log; + size_t rsize = 0; + char *result = NULL; + if (crashlog_event_analyze(e, &result, &rsize) == -1) { + LOGE("failed to analyze event\n"); + return; + } for_each_log(id, log, conf) { if (!log) continue; @@ -1027,7 +1049,7 @@ static void crashlog_send(struct event_t *e) } switch (e->event_type) { case CRASH: - crashlog_send_crash(e); + crashlog_send_crash(e, result, rsize); break; case INFO: crashlog_send_info(e); @@ -1039,11 +1061,13 @@ static void crashlog_send(struct event_t *e) crashlog_send_reboot(); break; case VM: - crashlog_send_vmevent(e); + crashlog_send_vmevent(e, result, rsize); break; default: LOGE("unsupoorted event type %d\n", e->event_type); } + if (result) + free(result); } int init_sender(void) diff --git a/tools/acrn-crashlog/common/include/strutils.h b/tools/acrn-crashlog/common/include/strutils.h index d5ac2cb55..61c9bf035 100644 --- a/tools/acrn-crashlog/common/include/strutils.h +++ b/tools/acrn-crashlog/common/include/strutils.h @@ -16,6 +16,7 @@ ssize_t strlinelen(const char *str, size_t size); char *strrstr(const char *s, const char *str); char *strtrim(char *str, size_t len); int strcnt(char *str, char c); +char *strings_ind(char *strings, size_t size, int index, size_t *slen); int str_split_ere(const char *str, size_t slen, const char *fmt, size_t flen, ...); #endif diff --git a/tools/acrn-crashlog/common/strutils.c b/tools/acrn-crashlog/common/strutils.c index 17c173c18..dab47c4dc 100644 --- a/tools/acrn-crashlog/common/strutils.c +++ b/tools/acrn-crashlog/common/strutils.c @@ -156,6 +156,39 @@ int strcnt(char *str, char c) return cnt; } +char *strings_ind(char *strings, size_t size, int index, size_t *slen) +{ + int i = 0; + size_t len; + char *start = strings; + char *str_tail; + size_t left; + + if (!strings || !size) + return NULL; + + str_tail = memchr((void *)strings, '\0', size); + if (!str_tail) + return NULL; + + while (1) { + len = str_tail - start; + if (i++ == index) + break; + left = strings + size - str_tail - 1; + if (!left) + return NULL; + start = str_tail + 1; + str_tail = memchr((void *)start, '\0', left); + if (!str_tail) + break; + } + + if (slen) + *slen = len; + return start; +} + static int reg_match(const char *str, const char *pattern, char *matched_sub, size_t matched_space, size_t *end_off)