From c1f2ba31b64fedd99ce5b8399547c1fa2c7d5ca5 Mon Sep 17 00:00:00 2001 From: Liu Xinwu Date: Thu, 10 May 2018 17:13:52 +0800 Subject: [PATCH] tools: acrn-crashlog: crash reclassify operations for acrnprobe Reclassify an event according to its trigger file's content. Signed-off-by: Liu Xinwu Reviewed-by: Zhang Yanmin Reviewed-by: Liu Chuansheng Reviewed-by: Zhao Yakui Reviewed-by: Geoffroy Van Cutsem Acked-by: Eddie Dong --- .../acrnprobe/crash_reclassify.c | 284 ++++++++++++++++++ 1 file changed, 284 insertions(+) diff --git a/tools/acrn-crashlog/acrnprobe/crash_reclassify.c b/tools/acrn-crashlog/acrnprobe/crash_reclassify.c index 8b46dba09..316c2af04 100644 --- a/tools/acrn-crashlog/acrnprobe/crash_reclassify.c +++ b/tools/acrn-crashlog/acrnprobe/crash_reclassify.c @@ -3,8 +3,292 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "load_conf.h" +#include "fsutils.h" +#include "strutils.h" +#include "log_sys.h" #include "crash_reclassify.h" +/** + * Check if file contains content or not. + * This function couldn't use for binary file. + * + * @param file Starting address of file cache. + * @param content String to be searched. + * + * @return 1 if find the same string, or 0 if not. + */ +static int has_content(char *file, char *content) +{ + if (content && strstr(file, content)) + return 1; + + return 0; +} + +/** + * Check if file contains all configured contents or not. + * This function couldn't use for binary file. + * + * @param crash Crash need checking. + * @param file Starting address of file cache. + * + * @return 1 if all configured strings were found, or 0 if not. + */ +static int crash_has_all_contents(struct crash_t *crash, + char *file) +{ + int id; + int ret = 1; + char *content; + + for_each_content_crash(id, content, crash) { + if (!content) + continue; + + if (!has_content(file, content)) { + ret = 0; + break; + } + } + + return ret; +} + +/** + * Might content is a 2-D array, write as mc[exp][cnt] + * This function implements the following algorithm: + * + * r_mc[exp] = has_content(mc[exp][0]) || has_content(mc[exp][1]) || ... + * result = r_mc[0] && r_mc[1] && ... + * + * This function couldn't use for binary file. + * + * @param crash Crash need checking. + * @param file Starting address of file cache. + * + * @return 1 if result is true, or 0 if false. + */ +static int crash_has_mightcontents(struct crash_t *crash, + char *file) +{ + int ret = 1; + int ret_exp; + int expid, cntid; + char **exp; + char *content; + + for_each_expression_crash(expid, exp, crash) { + if (!exp || !exp_valid(exp)) + continue; + + ret_exp = 0; + for_each_content_expression(cntid, content, exp) { + if (!content) + continue; + + if (has_content(file, content)) { + ret_exp = 1; + break; + } + } + if (ret_exp == 0) { + ret = 0; + break; + } + } + + return ret; +} + +/** + * Judge the type of crash, according to configured content/mightcontent. + * This function couldn't use for binary file. + * + * @param crash Crash need checking. + * @param file Starting address of file cache. + * + * @return 1 if file matches these strings configured in crash, or 0 if not. + */ +static int crash_reclassify(struct crash_t *crash, char *file) +{ + return crash_has_all_contents(crash, file) && + crash_has_mightcontents(crash, file); +} + +static int _get_data(char *file, struct crash_t *crash, char **data, int index) +{ + char *search_key; + char *value; + char *end; + int size; + int max_size = 255; + + if (!data) + return 0; + + *data = NULL; + + search_key = crash->data[index]; + if (!search_key) + return 0; + + value = strrstr(file, search_key); + if (!value) + return 0; + + end = strchr(value, '\n'); + if (!end) + return 0; + + size = MIN(max_size, end - value); + *data = malloc(size + 1); + if (*data == NULL) + return -ENOMEM; + + strncpy(*data, value, size); + *(*data + size) = 0; + return size; +} + +/** + * Get segment from file, according to 'data' configuread in crash. + * This function couldn't use for binary file. + * + * @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. + * + * @return 0 if successful, or errno if not. + */ +static int get_data(char *file, struct crash_t *crash, + char **data0, char **data1, char **data2) +{ + int res; + + /* to find strings which match conf words */ + res = _get_data(file, crash, data0, 0); + if (res < 0) + goto fail; + + res = _get_data(file, crash, data1, 1); + if (res < 0) + goto free_data0; + + res = _get_data(file, crash, data2, 2); + if (res < 0) + goto free_data1; + + return 0; +free_data1: + if (data1 && *data1) + free(*data1); +free_data0: + if (data0 && *data0) + free(*data0); +fail: + return res; +} + +/** + * Judge the crash type. We only got a root crash from channel, sometimes, + * we need to calculate a more specific type. + * This function reclassify the crash type by searching trigger file's content. + * This function couldn't use for binary file. + * + * @param rcrash Root crash obtained from channel. + * @param trfile Path of trigger file. + * @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. + * + * @return a pointer to the calculated crash structure if successful, + * or NULL if not. + */ +static struct crash_t *crash_reclassify_by_content(struct crash_t *rcrash, + char *trfile, char **data0, + char **data1, char **data2) +{ + int depth; + int level; + int ret; + struct crash_t *crash; + struct crash_t *ret_crash = NULL; + void *file; + unsigned long size; + int id; + + if (!rcrash) + return NULL; + + if (trfile) { + ret = read_full_binary_file(trfile, &size, &file); + if (ret == -1) { + LOGE("read %s failed, error (%s)\n", + trfile, strerror(errno)); + return NULL; + } + } else + return rcrash; + + /* traverse every crash from leaf, return the first crash we find + * consider that we have few CRASH TYPE, so just using this simple + * implementation. + */ + depth = crash_depth(rcrash); + for (level = depth; level >= 0; level--) { + for_each_crash(id, crash, conf) { + if (!crash || + crash->trigger != rcrash->trigger || + crash->channel != rcrash->channel || + crash->level != level) + continue; + + if (crash_reclassify(crash, file)) { + ret = get_data(file, crash, data0, data1, + data2); + if (ret < 0) { + LOGE("get data error, error (%s)\n", + strerror(-ret)); + goto fail_data; + } else { + ret_crash = crash; + goto fail_data; + } + } + } + } + +fail_data: + free(file); + + return ret_crash; +} + +/** + * Initailize crash reclassify, we only got a root crash from channel, + * sometimes, we need to get a more specific type. + */ void init_crash_reclassify(void) { + int id; + struct crash_t *crash; + + for_each_crash(id, crash, conf) { + if (!crash || !is_root_crash(crash)) + continue; + + crash->reclassify = crash_reclassify_by_content; + } }