/** @function: static int __init srecorder_init(void) @brief: dump @param: reason @return: none @note: **/ static int __init srecorder_init(void) { SRECORDER_PRINTK("Initialization %016lx %016lx.\n", params[0], params[1]); srecorder_init_symbols(); srecorder_init_dev(); srecorder_ioremap_dts_memory(); srecorder_init_log_headers(); srecorder_resigter_notifiers(); #ifdef CONFIG_KPROBES srecorder_resigter_jprobes(); #endif srecorder_enable_log_category_flags(); srecorder_enable_log_type_flags(); SRECORDER_PRINTK("Initialization done.\n"); return 0; }
/** @function: int srecorder_save_log(char *file_path, char *pbuf, int data_len) @brief: 在内核中将信息保存到文件中 @param: file_path 文件路径 @param: pbuf 存放信息的内存起始地址 @param: pbuf 要保存的数据长度 @return: 0 - 成功;-1-失败 @note: */ int srecorder_save_log(char *file_path, char *pbuf, int data_len) { mm_segment_t old_fs; loff_t pos; struct file *fp; if (NULL == file_path || NULL == pbuf || data_len <= 0) { SRECORDER_PRINTK("File [%s] line [%d] invalid param!\n", __FILE__, __LINE__); return -1; } /*0644文件读写执行权限,所有者:读写、用户组:读、其他:读*/ fp = filp_open(file_path, O_WRONLY | O_CREAT, 0644); if (NULL != fp) { old_fs = get_fs(); set_fs(KERNEL_DS); pos = 0; vfs_write(fp, pbuf, data_len, &pos); /* char buf[1024]; memset(buf, 0, sizeof(buf)); pos = 0; vfs_read(fp, buf, sizeof(buf) - 1, &pos);*/ filp_close(fp, NULL); set_fs(old_fs); } return 0; }
/** @function: int srecorder_get_crash_time(srecorder_reserved_mem_info_for_log_t *pmem_info) @brief: 记录死机发生的时间,顺便记录死机的原因。 @param: pmem_info SRecorder的保留内存信息 @return: 0 - 成功;-1-失败 @note: */ int srecorder_get_crash_time(srecorder_reserved_mem_info_t *pmem_info) { struct timeval tv; /* struct timex txc; */ struct rtc_time tm; int bytes_read = 0; char *pbuf = NULL; psrecorder_info_header_t pinfo_header = NULL; if (unlikely(NULL == pmem_info)) { SRECORDER_PRINTK("File [%s] line [%d] invalid param or kernel symbol addr!\n", __FILE__, __LINE__); return -1; } if (srecorder_get_bit(CRASH_REASON_TIME)) { SRECORDER_PRINTK("Crash reason and time have been dumped successfully!\n"); return 0; } memset(&tv, 0, sizeof(struct timeval)); /* memset(&txc, 0, sizeof(struct timex)); */ memset(&tm, 0, sizeof(struct rtc_time)); if (0 != srecorder_write_info_header(pmem_info, CRASH_REASON_TIME, &pinfo_header)) { return -1; } do_gettimeofday(&tv); tv.tv_sec -= sys_tz.tz_minuteswest * 60; /* 一分钟=60秒 */ rtc_time_to_tm(tv.tv_sec, &tm); pbuf = pmem_info->start_addr + pmem_info->bytes_read; bytes_read = SRECORDER_SNPRINTF(pmem_info->start_addr + pmem_info->bytes_read, pmem_info->bytes_left, "Crash reason: %s %s Crash Time: %04d%02d%02d-%02d:%02d:%02d\n", (NULL == pmem_info->crash_reason1) ? ("") : (pmem_info->crash_reason1), (NULL == pmem_info->crash_reason2) ? ("") : (pmem_info->crash_reason2), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); srecorder_renew_meminfo(pmem_info, bytes_read); srecorder_validate_info_header(pinfo_header, pmem_info->bytes_per_type); return 0; }
/** @function: int srecorder_validate_info_header(srecorder_info_header_t *pheader, unsigned long data_len) @brief: 对各种定位信息的头部并进行校验 @param: pheader 各类信息的校验头 @param: data_len 每类信息的数据长度,不包括校验头的数据 @return: 0 - 成功;-1-失败 @note: */ int srecorder_validate_info_header(srecorder_info_header_t *pheader, unsigned long data_len) { #ifndef CONFIG_SRECORDER_DUMP_LOG_TO_STORAGECARD unsigned long buf[2] = {0, 0}; if (unlikely(NULL == pheader)) { SRECORDER_PRINTK("File [%s] line [%d] invalid param!\n", __FILE__, __LINE__); return -1; } pheader->data_len = data_len; buf[0] = (unsigned long)pheader->type; buf[1] = (unsigned long)pheader->data_len; pheader->crc32 = srecorder_get_crc32((unsigned char *)buf, sizeof(buf)); #endif return 0; }
/** @function:int srecorder_write_info_header(srecorder_reserved_mem_info_for_log_t *pmem_info, srecorder_info_type_e type, psrecorder_info_header_t *pinfo_header) @brief: 初始化给类信息的头部数据结构 @param: pmem_info SRecorder的保留内存信息 @param: type 信息类型 @param: pinfo_header 信息头部校验数据结构 @return: 0 - 成功;-1-失败 @note: */ int srecorder_write_info_header(srecorder_reserved_mem_info_t *pmem_info, srecorder_info_type_e type, psrecorder_info_header_t *pinfo_header) { int bytes_read = 0; /* 删除此处定义 */ #ifndef CONFIG_SRECORDER_DUMP_LOG_TO_STORAGECARD int info_header_size = sizeof(srecorder_info_header_t); #endif if (unlikely(NULL == pmem_info || NULL == pmem_info->start_addr || NULL == pinfo_header || (LOG_TYPE_COUNT <= (int)type || (int)type < 0))) { SRECORDER_PRINTK("File [%s] line [%d] invalid param!\n", __FILE__, __LINE__); return -1; } #ifndef CONFIG_SRECORDER_DUMP_LOG_TO_STORAGECARD /*把校验信息的头部结构留出来*/ /* 删除此处 */ if ((pmem_info->bytes_read + info_header_size) > pmem_info->mem_size) { return -1; } *pinfo_header = (psrecorder_info_header_t)(pmem_info->start_addr + pmem_info->bytes_read); memset(*pinfo_header, 0, info_header_size); ((psrecorder_info_header_t)*pinfo_header)->type = type; pmem_info->bytes_read += (info_header_size); #endif pmem_info->bytes_per_type = 0; bytes_read = SRECORDER_SNPRINTF(pmem_info->start_addr + pmem_info->bytes_read, pmem_info->bytes_left, "%s\n", s_srecorder_head_info[type].desciprion); srecorder_renew_meminfo(pmem_info, bytes_read); return 0; }
/** @function: int srecorder_get_modem_log(srecorder_reserved_mem_info_for_log_t *pmem_info) @brief: 读取modem死机堆栈和运行日志 @param: pmem_info SRecorder的保留内存信息 @return: 0 - 成功;-1-失败 @note: */ int srecorder_get_modem_log(srecorder_reserved_mem_info_t *pmem_info) { psrecorder_info_header_t pinfo_header = NULL; if (unlikely(NULL == pmem_info)) { SRECORDER_PRINTK("File [%s] line [%d] invalid param or kernel symbol addr!\n", __FILE__, __LINE__); return -1; } if (srecorder_log_has_been_dumped(MODEM_ERR_BIT7)) { SRECORDER_PRINTK("modem err has been dumped successfully!\n"); } if (srecorder_log_has_been_dumped(MODEM_ERR_F3_BIT8)) { SRECORDER_PRINTK("modem err f3 has been dumped successfully!\n"); } if (pmem_info->dump_modem_crash_log_only) { #if defined(CONFIG_DUMP_MODEM_LOG_BY_FIQ) if (pmem_info->do_delay_when_dump_modem_log) { /* do delay about 10ms */ unsigned long ips = 0; ips = cpufreq_get_directly(smp_processor_id()) * 1000; /* KHZ = 1000*/ if (unlikely(0x0 == ips)) { ips = CONFIG_CPU_FREQ_DEFAULT_VALUE; } if (likely(0x0 != CONFIG_DUMP_MODEM_LOG_DELAY_MAX_MS)) { srecorder_do_delay(ips / (1000 / CONFIG_DUMP_MODEM_LOG_DELAY_MAX_MS)); } } #endif #if !defined(CONFIG_ARCH_MSM8930) if (!srecorder_log_has_been_dumped(MODEM_ERR_BIT7)) { if (0 != srecorder_write_info_header(pmem_info, MODEM_ERR_BIT7, &pinfo_header)) { return -1; } srecorder_debug_modem_err(pmem_info); srecorder_validate_info_header(pinfo_header, pmem_info->bytes_per_type); } #else #endif #if !defined(CONFIG_ARCH_MSM8930) if (!srecorder_log_has_been_dumped(MODEM_ERR_F3_BIT8)) { if (0 != srecorder_write_info_header(pmem_info, MODEM_ERR_F3_BIT8, &pinfo_header)) { return -1; } srecorder_debug_modem_err_f3(pmem_info); srecorder_validate_info_header(pinfo_header, pmem_info->bytes_per_type); } #else #endif } return 0; }
/** @function: static int srecorder_get_symbol_kallsyms_lookup_name(const char *line, int len) @brief: 给s_kernel_symbols_table表中的内核符号找到对应的地址 @param: line - 在/proc/kallsyms中所读的一行内容 @param: len - 暂时没用 @return: 0 - 成功;<0-失败 @note: */ static int srecorder_get_symbol_kallsyms_lookup_name(const char *line, int len) { int ret = 0; srec_ksym_addr_t address; char *psymbolname = NULL; char *pmodulename = NULL; char dummy; if (NULL == line) { SRECORDER_PRINTK("File [%s] line [%d] invalid param!\n", __FILE__, __LINE__); return -EINVAL; } psymbolname = kmalloc(NAME_MAX, GFP_KERNEL); if (NULL == psymbolname) { ret = -ENOMEM; goto err_out; } pmodulename = kmalloc(NAME_MAX, GFP_KERNEL); if (NULL == pmodulename) { ret = -ENOMEM; goto err_out; } memset(psymbolname, 0, NAME_MAX); memset(pmodulename, 0, NAME_MAX); /* * 包含kallsyms_lookup_name的line的格式为"[address] [type] [symboleName]" * 遇到"[address] [type] [symboleName] [moduleName]"格式直接返回 * /proc/kallsyms中每行一般3个参数 */ if (3 != sscanf(line, "%lx %c %s [%s]", &address, &dummy, psymbolname, pmodulename)) { ret = -ENOENT; goto err_out; } /*判断是否是需要的符号kallsyms_lookup_name*/ if (strncmp(KALLSYMS_LOOKUP_NAME_FUNC, psymbolname, NAME_MAX) != 0) { ret = -ENOENT; goto err_out; } s_kallsyms_lookup_name = (kallsyms_lookup_name_func)address; ret = 0; err_out: if (NULL != psymbolname) { kfree(psymbolname); psymbolname = NULL; } if (NULL != pmodulename) { kfree(pmodulename); pmodulename = NULL; } return ret; }
/** @function: int srecorder_register_external_log(unsigned id, void(*callback)(void*)) @brief: @param: @return: @note: **/ int srecorder_register_external_log(unsigned id, void(*callback)(void*)) { log_registration_entry_t* tmp_entry = NULL; log_registration_entry_t* log_entry = NULL; if (external_flag == 0) { SRECORDER_PRINTK("The dump flag of external log isn't enabled\n"); return -1; } if (id == 0 || callback == NULL) { return -1; } /* allocate one entry first to safely use spinlock */ log_entry = kzalloc(sizeof(log_registration_entry_t), GFP_KERNEL); if (log_entry == NULL) { return -1; } if (spin_trylock(&srecorder_registration_lock) == 0) { goto out; } if (spin_trylock(&srecorder_list_lock) == 0) { goto reg_out; } tmp_entry = p_log_registration_list; while (tmp_entry != NULL) { if (tmp_entry->info.log_id == id) { goto list_out; } tmp_entry = tmp_entry->next; } log_entry->info.log_id = id; log_entry->callback = callback; log_entry->next = p_log_registration_list; p_log_registration_list = log_entry; spin_unlock(&srecorder_list_lock); spin_unlock(&srecorder_registration_lock); return 0; list_out: spin_unlock(&srecorder_list_lock); reg_out: spin_unlock(&srecorder_registration_lock); out: kfree(log_entry); return -1; }