目录
1、coredump 生成
Ctl.start 启动服务,服务结束回收
system/core/init/init.cpp
ReapAnyOutstandingChildren
1、init 中while 循环会在服务退出时回收exited 状态服务;
2、InstallSignalFdHandler-》HandleSignalFd 对SIGCHLD、SIGTERM
system/core/init/sigchld_handler.cpp
ReapAnyOutstandingChildren-》
ReapOneProcess() -》
service->Reap(siginfo);->KillProcessGroup(SIGKILL, true);
do_exit_group
https://blog.csdn.net/tjcwt2011/article/details/80272127
Java 进程使能coredump
SpecializeCommon;后面执行postForkCommon。
打开coredump
NE 异常打印coredump
force_sig_info->send_signal 这里面会将信号加入对了,get_signal 会获取信号,根据sig_kernel_coredump(signr) 来确定是否调用do_coredump(&ksig->info)
USER 版本打开uart log
vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt67XX/default.mak
CFG_UART_DYNAMIC_SWITCH 配置为0
kernel-4.19/drivers/misc/mediatek/log_store/
kernel-4.9/drivers/misc/mediatek/aee/aed/
int set_emmc_config(int type, int value); 函数设置expdb 分区使能类型
vendor\mediatek\proprietary\bootable\bootloader\lk\app\mt_boot\aee\KEDump.c
int kedump_mini(void) 将异常日志写入expdb分区
2、MTK coredump
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6779/mt_pmic.c
Mrdump_tool
Mrdump Ramdump
打开rampdump
P版本
- lk/platform/mt67XX/rules.mk中 ARCH_HAVE_MT_RAMDUMP设为 yes
ARCH_HAVE_MT_RAMDUMP 时平台是否支持,优先级最高
KEDUMP_MINI 支持才会使能MTK_MRDUMP_ENABLE
MTK_MRDUMP_ENABLE 是打印coredump ,KEDUMP_MINI 是打印minidump
vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/rules.mk
MTK_MRDUMP_ENABLE 可以为dconfig/yes/no/空,控制build_mt_ramdump
2、lk/project/$(project).mk中设置MTK_MRDUMP_ENABLE = yes。【MTK_MRDUMP_ENABLE不设定时,eng版本默认应该是打开mrdump的】
Q版本
在P版本基础上,新增dconfig配置方式,配置方法是在lk/project/$(project).mk中设置MTK_MRDUMP_ENABLE = dconfig。
dconfig配置方式时候一种动态控制,根据boot_para.img里的标志位来判断是否要打开mrdump(没有烧录特定的boot_para.img则不开启mrdump)。
boot_para.img要如何生成呢?具体请看DCC上的文档:CS6000-BH8B-UMD-V1.5EN_MediaTek Logging SOP.docx里的《Dynamic enable fulldump for user load》章节
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6779/platform.c
platform_init->boot_mode_select
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6779/boot_mode.c
Kedump 开始log
mrdump_check 如果是dconfig 就会从boot_para.img中获取socid
mrdump_check-》mrdump_detection->
mrdump_check_enable()//socid
mrdump_key_secure_enable 配置长按电源键产生dump
mrdump_get_default_output_device(void)//
从环境变量mrdump_output 获取dump存储位置,internal-storage/usb/partition,环境变量没有设置就是要系统的默认配置
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/include/platform/mtk_mrdump.h
#define MRDUMP_CB_ADDR 0x0010E800
#define MRDUMP_CB_SIZE 0x1400
mrdump_control_block 对应地址与长度
从开始地址,字符串是MRDUMP_GO_DUMP,则有对应控制块
#define MRDUMP_GO_DUMP "MRDUMP09"
Kdump 位置
voprintf_info("Kdump triggerd by '%s' (address:%x, size:%lluM)\n",
mrdump_mode2string(mrdump_cblock->crash_record.reboot_mode),DRAM_PHY_ADDR, mrdump_mem_size() / 0x100000UL);
address:0x40000000, size:6144M
Check是这些模式返回1
mrdump_detect 返回1 则进入mrdump_run2,或者进入fastboot 通过usb dump ,打开背光;
kdump_ui 中根据ramdump 存储位置,显示对应界面进入dump,如下面截图:
Dump完成打印信息,如果dump 过程被中断,则在dump 存储末端写入最大长整数,否则是ramdump 长度;重启进入bootloader 启动
Dump 完成则将调用mrdump_write_result将cblock_result 写入MRDUMP_CB_ADDR 位置,对应签名MRDUMP_GO_DUMP;reset 手机重新进入bootloader 启动
Ramdupm 设备:
/sys/module/mrdump/parameters
kernel-4.19/arch/arm/kernel/traps.c
Arm_notify_die ->
int notrace notify_die
int register_die_notifier(struct notifier_block *nb)
int unregister_die_notifier(struct notifier_block *nb)
用户空间异常走force_sig_info,内核异常走die;
do_signal是内核信号处理的入口,真正的信号处理逻辑在get_signal_to_deliver函数中
coredump使用
coredump机制目前内核默认都已经集成,主要的配置接口有:
1、ulimit,通过ulimit -a查看当前配置,执行ulimit -c unlimited将core file size改为ulimited
2、/proc/sys/kernel/core_pattern,该配置项用于配置生成的core文件路径已经名字,相信信息可以通过man 5 core来查询
3、/proc/pid/core_filter,用于配置dump文件具体内容,详细信息可以通过man 5 core来查询
coredump配置、产生、分析以及分析示例 - ArnoldLu - 博客园
https://www.cnblogs.com/wangjie1990/p/11327676.html
config BUG
bool "BUG() support" if EXPERT
default y
Arch/arm64/
config GENERIC_BUG
def_bool y
depends on BUG
config GENERIC_BUG_RELATIVE_POINTERS
def_bool y
depends on GENERIC_BUG
kernel-4.19/drivers/misc/mediatek/aee/mrdump/mrdump_panic.c
mrdump_panic_init 时会注册panic() 时通知回调函数panic_blk,及die()时通知回调函数die_blk
notifier_block panic_notifier_list //列表
https://www.cnblogs.com/linhaostudy/p/9429511.html
Dump文件时进程的内存镜像。可以把程序的执行状态保存到Dump文件中。Dump文件分为内核模式Dump和用户模式Dump。其中内核模式Dump是操作系统创建的崩溃转储,例如蓝屏Dump。而在我们调试或Troubleshooting过程中使用的Dump是用户模式Dump,又分为Full Dump和Mini Dump。Full Dump包含了某个进程完整的地址空间数据,以及许多用于调试的信息。而Mini Dump根据需要可以包含不同的信息,有的可能只包含某个县城和部分模块的信息。
https://www.eefocus.com/embedded/418875
1、模块
Linux 内核主要由进程调度、内存管理、虚拟文件系统、网络接口、进程通讯 5部分组成
Kernel/driver/rtc
模块Kconfig Makefile 编译配置文件
config RTC_HCTOSYS_DEVICE
string "RTC used to set the system time"
depends on RTC_HCTOSYS
default "rtc0"
help
The RTC device that will be used to (re)initialize the system
Config 这个为三态,Y/N 编入内核/不编入,M 编译为模块
Makefile 里面
obj-$(CONFIG_RTC_LIB) += rtc-lib.o
为Y 则,obj-y+= rtc-lib.o;rtc-lib.o 编译入内核;为M 则编译为rtc-lib.ko;为N 则不编译
config RTC_LIB
Bool
Boole 类型,则只能为Y/N
Lib-y hostprogs-y 库和主机程序
当有多个文件或目录生成目标时,使用 -y/-objs
obj-m += rtc-lib.o
rtc-lib-objs := a.o b.o
rtc-lib-$(CONFIG_RTC_TIME) += xt.o
obj-$(CONFIG_RTC_LIB) += ext2/
2、System.map/kallsyms
模块编译安装
- Linux 文件系统和设备文件系统
Linux 2.4 内核devfs 文件系统,linux 2.6 基于sysfs 的udev 文件系统
/sys 是sysfs 对应目录,设备、驱动、总线都可以在这里找到对应的节点
VFS
深入理解Linux内核——VFS | linkthinking
/proc/devices 查看系统中注册的设备
/dev/ 目录是对应设备文件
主设备号指同一类设备,与驱动对应,次设备号从0 开始。
adb shell cat /sys/devices/platform/1000b000.pinctrl/mt_gpio
adb shell cat /sys/devices/platform/soc/10005000.pinctrl/mt_gpio
内核配置
内核从3.7后开始支持模块签名,这个功能使能以后,内核只允许安装特定key签名的模块。
内核配置项
CONFIG_MODULE_SIG=y
表示开启了签名机制,但是这时候模块签名或不签名都可以使用。
CONFIG_MODULE_SIG_FORCE=y
如果上述配置项使能,则模块必须有正确的签名才能正常使用。
CONFIG_MODULE_SIG_ALL=y
内核在编译的时候,并不会主动去给模块签名,除非你把上述配置项打开。
查看签名
hexdump -C my_ko.ko |tail
数字证书会打包进内核,里面有公钥等,用来解密。每编译一次,虽然配置文件每次都相同,但是生成的key pair是不同的。模块放的分区跟kernel 分区不一样,就可能导致更新内核导致签名不对。
devfs:
通过程序在设备初始化时,在/dev 创建设备文件,在卸载设备时将它删除
设备驱动程序可以指定设备名、所有者和权限,用户空间程序可以修改
不再需要指定主设备号和次设备号;register_chrdev();devfs_register()自动自动主次设备号
udev 在内核检测到设备插拔时,将事件发送到/sys 对应的sysfs 下,从而用户空间处理对应的事件
/sys/block 块设备
/sys/devices 所有设备,根据挂载的总线来组织(设备链接subsystem -> ../../../bus/platform; of_node -> ../../../firmware/devicetree/base/)
/sys/bus 总线,对应着设备(链接到/sys/devices)和驱动
/sys/firmware
/sys/class
字符设备:
file_operations定义在./include/linux/fs.h
cdev定义在./include/linux/cdev.h
平台设备
linux/platform_device.h
include/linux/device.h
和drivers/base/platform.c
*name ---如果多个相同名字,驱动通过id 区别不同设备;设备注册时会初始化到dev.init_name
设备驱动的probe,依赖于名称,Linux采取的策略是:在bus的设备链表中查找device,和对应的device_driver比对name,如果相同,则查看该设备是否已经绑定了driver(查看其dev->driver指针是否为空),如果已绑定,则不会执行probe动作,如果没有绑定,则以该device的指针为参数,调用driver的probe接口。因此,在driver的probe接口中,通过判断设备的ID,可以知道此次驱动的设备是哪个。
dev ---设备结构体,父设备为platform_bus
内核会在合适的时机检查device和device_driver的名字,如果匹配,则执行probe。其实除了名称之外,还有一些宽泛的匹配方式,例如这里提到的各种match table
Device_driver 中
const struct of_device_id *of_match_table; #compatible[128]用于与设备树compatible(dts)
const struct acpi_device_id *acpi_match_table;
Platform_driver 中
Platform_device_id
#platform_driver对象中的id_table就是用来匹配,一个驱动匹配多个C语言编码的设备信息
Early platform device/driver
内核启动时,要完成一定的初始化操作之后,才会处理device和driver的注册及probe,因此在这之前,常规的platform设备是无法使用的。但是在Linux中,有些设备需要尽早使用(如在启动过程中充当console输出的serial设备),所以platform模块提供了一种称作Early platform device/driver的机制,允许驱动开发人员,在开发驱动时,向内核注册可在内核早期启动过程中使用的driver
Match ---当有驱动或者设备注册到platform总线时,内核自动调用match函数,判断设备和驱动的name是否一致。
Platform_bus 是一个device ,只包含init_name(为“platform”),device_register 会创建/sys/devices/platform 目录,所有Platform 设备都会包含在这个目录。
Bus_register 注册总线/sys/bus/platform/
创建uevent attribute(/sys/bus/platform/uevent)、devices目录、drivers目录、drivers_probe和drivers_autoprobe两个attribute(/sys/bus/platform/drivers_probe和/sys/bus/platform/drivers_autoprobe)
设备/驱动注册过程:
Platform device/driver注册过程 - fellow_jing - 博客园
驱动开发三种方法:传统、总线、设备树
dts文件被编译成dtb文件,然后在启动内核时,传给内核,由内核来处理解析,得到一个一个的device_node(每一个节点对应一个device_node)结构体,然后解析成platform_device结构体,这里面就含有硬件描述的资源;
设备数
https://www.cnblogs.com/lizhuming/p/14621305.html
./scripts/dtc/dtc -I dts -O dtb -o tmp.dtb arch/arm/boot/dts/xxx.dts // 编译 dts 为 dtb
./scripts/dtc/dtc -I dtb -O dts -o tmp.dts arch/arm/boot/dts/xxx.dtb // 反编译 dtb 为 dts
kernel-4.19/scripts/drvgen/drvgen.mk
ALL_DRVGEN_FILE := $(MTK_PROJECT)/cust.dtsi
vendor/mediatek/proprietary/scripts/kernel_tool/dtbo_config.sh
Preloader log
vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/pal/inc/pal_log.h
vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6765/default.mak
vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6765/src/core/print.c
最后调用的是这里print()函数
CFG_UART_DYNAMIC_SWITCH 没有定义则输出到uart
这里调用pl_log_store 保存日志到sram/dram/expdb
CFG_UART_DYNAMIC_SWITCH宏开关可以配置动态打开关闭uart
在宏内set_log_switch(0/1)可以关闭打开uart log,通过log_dynamic_switch
传递到lk ,lk 再传递到kernel 设置mtk_printk_ctrl.disable_uart=0/1
在user mode和userdebug mode,如何令kernel log在lk结束后自动吐出? 方法一:fastboot comand 1) 按volumn up + power key进入 bootmenu 选择fastboot mode
2) usb连接PC端,执行命令fastboot oem p2u on
设置has_set_p2u
3) 执行fastboot continue命令
pl_log_store 里面使用DEBUG_LOG 输出日志:
vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/common/log_store/log_store_pl.c
Ram 控制台kernel 异常boot 保存kernel log 到自定义分区
如果从bl/lk 异常重启,保存pl log 到自定义分区
Preloder 后面会将日志保存到dram
store_switch_to_dram->log_store_init
vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/common/ram_console.c
Preloader 启动流程:
MTK bootloader 启动过程_jgw2008的专栏-CSDN博客
深入MTK平台bootloader启动之【 Pre-loader -> Lk】分析笔记_沉思-CSDN博客
Lk->kernel
https://blog.csdn.net/forever_2015/article/details/53047993
dct
高通 MSM8K bootloader之一: SBL1 - linux_xin - 博客园
vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct
./preloader/custom/k6875v1_64/dct
./lk/scripts/dct
./lk/target/oppo6889/dct
Codegen.dws
#ifdef USE_DTB_NO_DWS
这里会加载dtb
BOARD_PREBUILT_DTBIMAGE_DIR
ifneq ($(USE_DTB_NO_DWS),yes)
$(info **************** Use DWS ****************)
-include scripts/drvgen/drvgen.mk
else
$(info **************** Use DTB ****************)
endif
在Android L版本上 DCT tool配置的codegen.dws文件在preloader、lk、kernel中是独立的,被分开放置,其路径如下:
preloader:
alps\bootable\bootloader\preloader\custom\$(proj)\dct\dct\codegen.dws
lk:
alps\bootable\bootloader\lk\target\$(proj)\dct\dct\codegen.dws
kernel:
alps\kernel-3.10\arch\arm\mach-$(platform)\$(proj)\dct\dct\codegen.dws
or
alps\kernel-3.10\drivers\misc\mediatek\mach\$(platform)\$(proj)\dct\dct\codegen.dws
https://www.cnblogs.com/leaven/p/6295999.html
3、KE 分析
https://blog.csdn.net/qq_38350702/article/details/107321721
Crash 工具
https://www.jianshu.com/p/7d998f474033?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
https://www2.lauterbach.com/pdf/general_ref_m.pdf
Data.List
The Data.List (= List) window displays the code in assembler mnemonic and HLL
Var.Step.Till
Example: Var.Step.Till i>11. single-steps the program until the variable i becomes greater than
11. The trailing dot is very important! It is the dot that formats 11 as a decimal number.
Note: i>11. is equivalent to i>0xB
Register.view /SpotLight
修改寄存器
Data.dump main++0x30
Data.Set 修改地址内容
B::wr.we.PLIST 显示运行的脚本
设置PC
Register.Set PC 0xffffffa50aec0eb8/函数名
Data.load.elf tsts.elf /PATH E:/SOURCE
B::sYmbol.SourcePATH.List
设置递归路径:
sYmbol.spath.SetRecurseDir V:\ANDROID_R\mt6765\0520_mt6765\source
y.spath.SETRECURSEDIR <path>
设置完显示设置源码路径界面:
y.spath.list
1)去除编译路径前缀 (针对第一张图的路径去掉 \sdb\jenkins\workspace\BUILD_Branch_sofia3g_r_mr1_Cherry_Pick_ctegerrit\ 前缀)
data.load C:\zyang\Logs\Sofia3G_R\pre-merge\2015-09-09\cp_1841\mobilevisor.elf /strippart 5.
2)设置新的相对路径
y.spath.setbasedir M:\workspace\sofia3g_r_mr1_cte
3)/RelPATH 参数: 去除编译目录的绝对路径, 保留相对路径。
data.load.elf c:\slb.elf /RelPATH
Data.Load 功能
• All symbol and debug information already available in TRACE32 is removed.
• The code/data provided by is loaded to the target memory.
• The symbol and debug information provided by is loaded into TRACE32.
• The paths for the hll source files provided by are loaded into TRACE32.
• An internal symbol data base in generated out of the loaded information.
有用命令:
sYmbol.List.SECtion List the section information provided by <file> loaded by “data.load”
sYmbol.List.SOURCE to display the path information for the hll source files that was loaded from <file>
sYmbol.spath.list to display the symbol source path list.
sYmbol.spath.SetDir 设置源文件静态搜索路径
sYmbol.spath.SetDynamicDir 设置源文件动态搜索路径。如果某个路径命中源文件,则下次搜索时,该命中路径成为第一个被搜索路径。
sYmbol.spath.SetRecurseDir 设置递归搜索路径,所有其子目录都将被用于源文件搜索
data.load.elf ../../vmlinux 0x1488800000 /nocode
加上/nocode代表没有对应的sourcecode,trace32就不会去对应目录去查找源文件了。当然我们也可以通过/path来指定sourcecode目录
Area 警告
F/frame 异常堆栈
R 寄存器
https://www.lauterbach.com/pdf/frontend_gdb.pdf
B::mmu.list.pagetable 0xffffffc000000000
踩内存
https://online.mediatek.com/QuickStart/QS00090#QSS00964
4、T32 使用
trace 访问percpu
https://blog.csdn.net/weixin_46485500/article/details/119875898
var.view (struct A*)0xFFFFAAA 查看地址变量
task.Dtask 0xFFFFFFEA4FCDA280 查看对应的task 名字
FP(x29) 帧栈地址,栈底
LR(X30)
SP 保存栈指针
X0-X7: 用于子程序调用时的参数传递,X0还用于返回值传递
X8: 间接寻址结果
STP x29, x30, [sp, #0x10] ; 入栈指令
LDP x29, x30, [sp, #0x10] ; 出栈指令
LDR X5,[X6,#0x08] ;X6寄存器加0x08的和的地址值内的数据传送到X5
STR X0, [SP, #0x8] ;X0寄存器的数据传送到SP+0x8地址值指向的存储空间
ldp/stp
是 ldr/str 的衍生, 可以同时读/写两个寄存器, ldr/str只能读写一个
sub sp, sp, #0x20 ; 拉伸栈空间32(20 = 2*16)个字节
stp x0 , x1, [sp, #0x10] ; sp往上加16(10 = 1 * 16)个字节,存放x0 和 x1
ldp x1 , x0, [sp, #0x10] ; 将sp偏移16个字节的值取出来,放入x1 和 x0
LDR r0,[r1] //将R1中的值存到r0中
LDR r1,[r2,#16] //将(r2+16)地址中的内容存到r1中
LDR r1,[r2],#4 //将r2地址中的内容存到r1中,同时r2=r2+4
LDR r1,[r2,#4]! //r2=r2+4,再将r2 地址值加载到r1
gdb
prebuilts/gdb/linux-x86/bin/gdb out/target/product/symbols/system/bin/init ../../../../db.00.NE.dbg.DEC/PROCESS_COREDUMP
prebuilts/gcc/linux-x86/aarch64/aarch64-linux-gnu-6.3.1/bin/aarch64-linux-gnu-gdb out/target/product/symbols/system/bin/init db.00.NE.dbg.DEC/PROCESS_COREDUMP
--gdb 命令下设置库加载路径:
set solib-absolute-prefix /work/android/out_/target/product/symbols/
lldb调试coredump,gdb是跟gcc搭配的,lldb是跟llvm搭配的
在gdb下查看map,vector,queue的数据
https://blog.csdn.net/wxliu1989/article/details/24259539/
gdb to lldb
https://lldb.llvm.org/use/map.html
使用(lldb) target create a.out --symfile a.out.dSYM --core user_core打开核心文件
target modules add ~/a.out
在打开核心文件之前执行(lldb) settings set target.debug-file-search-paths .
在打开核心文件之前执行(lldb) setting set target.exec-search-paths .
Execute (lldb) target symbols add ~/a.out.dSYM
image lookup -vn <function>
./lldb.sh -f app_process64 -c PROCESS_NCOREDUMP