在HMI项目中会将所有的minidump regions 都打包压缩到minidump.gz中,然后在售后出现问题时,这个minidump.gz会被打包到bugreport日志中。关于解析这个minidump的解析,涉及两部分。一是解压minidump.gz,二是解密minidump。
本文不仅适用于HMI项目,如果是其他项目的高通平台,请忽略解压minidump.gz部分。解密minidump过程在高通平台上是通用的
解压minidump.gz
关于minidump.gz解压有两个方式,分别是本地解压和在线解压(推荐)
本地解压
下面介绍一下minidump.gz的解析方法:
将minidump.gz 从/data/vendor/diag/目录下adb pull出来后,无法通过windows工具进行解压,猜测不是标准的gz格式。只能通过linux专用工具进行解压。
工具如下:
minidump_linux_unzip
~/tmp/minidump$ minidump_linux_unzip d minidump.gz minidump
miniz.c example5 (demonstrates tinfl/tdefl)
Mode: d, Level: 9
Input File: "minidump.gz"
Output File: "minidump"
Input file size: 21121752
Total input bytes: 21121752
Total output bytes: 209715200
Success.
生成解压后的minidump文件。
拆分minidump
上一步解压出来的minidump,先重命名为rawdump,需要进行拆分成各个bin,使用py脚本对minidump进行拆分,工具如下:
命令是:
python tz_decryption_tool.py -s .\rawdump .
备注:如果tz加密了的情况下,解析出来的minidump regions也还是加密的状态,还需要给这个镜像解密,这也是不推荐的原因
在线解压
将minidump.gz上传到小米解密网址上进行解密
https://security.pt.xiaomi.com/#/decrypt_signer/upload
解密后会生成两个out 和 split 两个目录,其中out目录下的文件为解密后的文件。
将out内的全部文件复制替换到split中
随后将split目录中的md_TZ_DIAG.bin文件删除,并md_TZ_DIAG_decr.bin重命名为md_TZ_DIAG.bin
生成ap_minidump.elf
执行以下脚本,将所有HLOS区域组合在一起以支持解析器,生成ap_minidump.elf文件(解析APPS的关键)
python generate_appself.py <split_out_path>
# Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
# Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 and
# only version 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
import sys
import os
import string
import struct
outputfile = "ap_minidump.elf"
def add_file(fo, path, delete):
try:
fi = open_file(path, "rb")
except:
print("Not able to open file %s" % (path))
return -1
while True:
buf = fi.read(4096)
if len(buf) == 0:
break
fo.write(buf)
fi.close()
if delete:
os.unlink(os.path.join(out_folder, path))
return 0
def open_file(name, op):
path = os.path.join(out_folder, name)
out_file = open(path, op)
return out_file
def get_strings(buf, length):
offset = 0
string = ""
nlist = []
begin = False
str_tbl = ""
while offset < length:
str_tbl = ""
if not begin:
(ch,) = struct.unpack_from("<B", buf, offset)
str_tbl += chr(ch)
(ch,) = struct.unpack_from("<B", buf, offset+1)
str_tbl += chr(ch)
(ch,) = struct.unpack_from("<B", buf, offset+2)
str_tbl += chr(ch)
(ch,) = struct.unpack_from("<B", buf, offset+3)
str_tbl += chr(ch)
(ch,) = struct.unpack_from("<B", buf, offset+4)
str_tbl += chr(ch)
(ch,) = struct.unpack_from("<B", buf, offset+5)
str_tbl += chr(ch)
(ch,) = struct.unpack_from("<B", buf, offset+6)
str_tbl += chr(ch)
if str_tbl == "STR_TBL":
begin = True
offset += 6
else:
offset += 1
continue
(ch,) = struct.unpack_from("<B", buf, offset)
offset += 1
if (ch >= 0x30 and ch < 0x80) or ch==0x2e:
string += chr(ch)
elif (string != "" and len(string) >= 3 and
string != 'linux_banner' and string != 'minidump_table'):
nlist.append(string)
string = ""
else:
string = ""
if ch == 0:
(ch1,) = struct.unpack_from("<B", buf, offset+1)
if ch1 == 0:
(ch2,) = struct.unpack_from("<B", buf, offset+2)
if ch2 == 0:
return nlist
return nlist
def generate_elf():
delete = False
elfhd = os.path.join(out_folder, "md_KELF_HEADER.BIN")
elfhd_new = os.path.join(out_folder, "md_KELF_HDR.BIN")
fo = open_file(outputfile, "wb")
if os.path.exists(elfhd):
fi = open_file("md_KELF_HEADER.BIN", "rb")
hsize = os.path.getsize(elfhd)
elif os.path.exists(elfhd_new):
fi = open_file("md_KELF_HDR.BIN", "rb")
hsize = os.path.getsize(elfhd_new)
else:
print("ELF header binary is missing")
sys.exit(2)
print("ELF header size %d" % hsize)
buf = fi.read(hsize)
fo.write(buf)
nlist = get_strings(buf, len(buf))
for names in nlist:
filepath = "md_" + names + ".BIN"
# print ("%s size %x\n" % (filepath, os.path.getsize(filepath)))
ret = add_file(fo, filepath, delete)
if ret == -1:
print("Exting!!")
fo.close()
fi.close()
os.unlink(os.path.join(out_folder, outputfile))
return
fi.close()
fo.close()
def help():
print("\nThis script generates ap_minidump.elf from QPST dump for LDRP\n")
print("\nProvide QPST minidump location\n")
if __name__ == '__main__':
args = sys.argv
if len(args) > 1:
out_folder = args[1]
else:
help()
sys.exit(2)
print("using outfodler %s" % out_folder)
generate_elf()
按照正常dump的方式解析minidump
dump路径为 split目录
预期结果:APPS TZ RPM都可以正常解析