fix bsod anaylse
This commit is contained in:
@@ -9,6 +9,7 @@ use sysinfo::{System, Disks};
|
|||||||
use wmi::{COMLibrary, WMIConnection};
|
use wmi::{COMLibrary, WMIConnection};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
// [修复] 移除了未使用的 Write
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use tauri::Emitter;
|
use tauri::Emitter;
|
||||||
@@ -231,16 +232,16 @@ where T: Deref<Target = [u8]>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// [修复] BlueScreenView 外部调用分析 (使用 CSV crate 解析)
|
// [修复] BlueScreenView 外部调用分析 (适配新的命令行格式和 CSV 列)
|
||||||
fn analyze_with_bluescreenview(dump_path: &Path) -> Result<BsodAnalysisReport, String> {
|
fn analyze_with_bluescreenview(dump_path: &Path) -> Result<BsodAnalysisReport, String> {
|
||||||
let bsv_exe = "BlueScreenView.exe";
|
let bsv_exe = "BlueScreenView.exe";
|
||||||
|
|
||||||
let mut temp_csv_path = std::env::temp_dir();
|
let mut temp_csv_path = std::env::temp_dir();
|
||||||
temp_csv_path.push(format!("bsod_report_{}.csv", chrono::Utc::now().timestamp_millis()));
|
temp_csv_path.push(format!("bsod_report_{}.csv", chrono::Utc::now().timestamp_millis()));
|
||||||
|
|
||||||
|
// [修改] 命令行格式: BlueScreenView.exe <DumpFile> /scomma <OutFile>
|
||||||
let status = Command::new(bsv_exe)
|
let status = Command::new(bsv_exe)
|
||||||
.arg("/LoadFrom")
|
.arg(dump_path.to_string_lossy().to_string()) // 直接传文件路径
|
||||||
.arg(dump_path.to_string_lossy().to_string())
|
|
||||||
.arg("/scomma")
|
.arg("/scomma")
|
||||||
.arg(temp_csv_path.to_string_lossy().to_string())
|
.arg(temp_csv_path.to_string_lossy().to_string())
|
||||||
.status();
|
.status();
|
||||||
@@ -256,36 +257,28 @@ fn analyze_with_bluescreenview(dump_path: &Path) -> Result<BsodAnalysisReport, S
|
|||||||
|
|
||||||
// 使用 csv crate 解析
|
// 使用 csv crate 解析
|
||||||
let mut rdr = csv::ReaderBuilder::new()
|
let mut rdr = csv::ReaderBuilder::new()
|
||||||
.has_headers(false) // 命令行模式可能没有表头,或者我们手动处理
|
.has_headers(false) // 命令行模式导出的 CSV 没有 Header,第一行就是数据
|
||||||
.from_reader(content.as_bytes());
|
.from_reader(content.as_bytes());
|
||||||
|
|
||||||
for result in rdr.records() {
|
for result in rdr.records() {
|
||||||
if let Ok(record) = result {
|
if let Ok(record) = result {
|
||||||
// BlueScreenView 的列索引通常是:
|
// BlueScreenView CSV 格式 (基于上传的文件):
|
||||||
// 0: Dump File
|
// Index 0: Dump File (112525-7375-01.dmp)
|
||||||
// 1: Crash Time
|
// Index 2: Bug Check String (MEMORY_MANAGEMENT)
|
||||||
// 2: Bug Check String
|
// Index 3: Bug Check Code (0x0000001a)
|
||||||
// 3: Bug Check Code
|
// Index 8: Caused By Driver (ntoskrnl.exe)
|
||||||
// ...
|
// Index 15: Crash Address (ntoskrnl.exe+41e230)
|
||||||
// 8: Caused By Driver (关键列)
|
|
||||||
// ...
|
|
||||||
// 15: Crash Address (可能位置)
|
|
||||||
|
|
||||||
// 我们至少需要前9列才能提供有意义的信息
|
if record.len() > 15 {
|
||||||
if record.len() >= 9 {
|
// 第一行就是数据,不需要跳过 Header
|
||||||
// 跳过可能的表头行
|
|
||||||
if &record[0] == "Dump File" { continue; }
|
|
||||||
|
|
||||||
let bug_check_string = &record[2];
|
let bug_check_string = &record[2];
|
||||||
let bug_check_code = &record[3];
|
let bug_check_code = &record[3];
|
||||||
let caused_by_driver = &record[8]; // Index 8 是最常见的 Caused By Driver 位置
|
let caused_by_driver = &record[8];
|
||||||
|
let crash_addr = &record[15];
|
||||||
// 尝试获取崩溃地址,如果不够长就填 N/A
|
|
||||||
let crash_addr = if record.len() > 15 { &record[15] } else { "N/A" };
|
|
||||||
|
|
||||||
let (human, recommend) = translate_bugcheck_str(bug_check_code);
|
let (human, recommend) = translate_bugcheck_str(bug_check_code);
|
||||||
|
|
||||||
// 优先使用 Bug Check String,如果为空则使用翻译结果
|
// 优先使用 BlueScreenView 识别出的 Bug Check String
|
||||||
let final_reason = if !bug_check_string.is_empty() { bug_check_string.to_string() } else { human };
|
let final_reason = if !bug_check_string.is_empty() { bug_check_string.to_string() } else { human };
|
||||||
|
|
||||||
return Ok(BsodAnalysisReport {
|
return Ok(BsodAnalysisReport {
|
||||||
@@ -300,7 +293,7 @@ fn analyze_with_bluescreenview(dump_path: &Path) -> Result<BsodAnalysisReport, S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err("BlueScreenView 输出为空或未能解析到有效列(文件可能已损坏)。".to_string())
|
Err("BlueScreenView 输出为空或格式无法识别。".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 辅助函数:检查文件头签名并返回类型
|
// 辅助函数:检查文件头签名并返回类型
|
||||||
@@ -393,7 +386,7 @@ async fn analyze_minidump_bytes(file_content: Vec<u8>) -> Result<BsodAnalysisRep
|
|||||||
|
|
||||||
match dump_type {
|
match dump_type {
|
||||||
DumpType::Minidump => {
|
DumpType::Minidump => {
|
||||||
// [修复] 先将 Minidump::read 错误转为 String,确保链式调用类型一致
|
// [修复] 修复 Error 类型转换
|
||||||
let native_result = Minidump::read(file_content.clone())
|
let native_result = Minidump::read(file_content.clone())
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
.and_then(|dump| analyze_dump_data_native(dump));
|
.and_then(|dump| analyze_dump_data_native(dump));
|
||||||
@@ -413,7 +406,6 @@ async fn analyze_minidump_bytes(file_content: Vec<u8>) -> Result<BsodAnalysisRep
|
|||||||
let mut temp_dump_path = std::env::temp_dir();
|
let mut temp_dump_path = std::env::temp_dir();
|
||||||
temp_dump_path.push(format!("temp_dump_{}.dmp", chrono::Utc::now().timestamp_millis()));
|
temp_dump_path.push(format!("temp_dump_{}.dmp", chrono::Utc::now().timestamp_millis()));
|
||||||
|
|
||||||
// 既然上面判断文件有效,这里大概率可以写入
|
|
||||||
if let Err(_) = fs::write(&temp_dump_path, &file_content) {
|
if let Err(_) = fs::write(&temp_dump_path, &file_content) {
|
||||||
return Err("无法写入临时文件进行分析".to_string());
|
return Err("无法写入临时文件进行分析".to_string());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user