Compare commits
8 Commits
6128fe43b9
...
Branch_Gao
| Author | SHA1 | Date | |
|---|---|---|---|
| 136a40cbe3 | |||
| b9741f3cc7 | |||
| e70f401895 | |||
| 40ff13d05f | |||
| dff961add1 | |||
| f19003b239 | |||
| db0ee7322a | |||
| b20adf0a85 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -20,3 +20,7 @@ ncscope.*
|
||||
|
||||
__pycache__
|
||||
.vscode
|
||||
|
||||
.cache/
|
||||
compile_commands.json
|
||||
|
||||
|
||||
@ -530,3 +530,22 @@ CONFIG_BT_HCIUART_H4=y
|
||||
# CONFIG_BT_HCIVHCI is not set
|
||||
# CONFIG_BT_MRVL is not set
|
||||
# CONFIG_BT_MTKSDIO is not set
|
||||
|
||||
# 死锁检测
|
||||
CONFIG_LOCK_STAT=y
|
||||
CONFIG_PROVE_LOCKING=y
|
||||
|
||||
# Ftracer
|
||||
CONFIG_FUNCTION_TRACER=y
|
||||
CONFIG_PSTORE_FTRACE=y
|
||||
|
||||
# Sysrq
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
|
||||
# Pstore
|
||||
CONFIG_PSTORE=y
|
||||
# Frontend
|
||||
CONFIG_PSTORE_PMSG=y
|
||||
CONFIG_PSTORE_CONSOLE=y
|
||||
# Backend
|
||||
CONFIG_PSTORE_RAM=y
|
||||
|
||||
@ -21,5 +21,12 @@
|
||||
compatible = "ion-region";
|
||||
size = <0x0 CVIMMAP_ION_SIZE>;
|
||||
};
|
||||
|
||||
ramoops@9fd00000 {
|
||||
compatible = "ramoops";
|
||||
reg = <0 0x9fd00000 0 0x100000>;
|
||||
record-size = <0x4000>;
|
||||
console-size = <0x4000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@ -7,3 +7,4 @@ tmpfs /tmp tmpfs mode=1777 0 0
|
||||
tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0
|
||||
sysfs /sys sysfs defaults 0 0
|
||||
debug /sys/kernel/debug debugfs defaults 0 0
|
||||
pstore /sys/fs/pstore pstore defaults 0 0
|
||||
|
||||
@ -378,6 +378,42 @@ void pstore_record_init(struct pstore_record *record,
|
||||
record->time = ns_to_timespec64(ktime_get_real_fast_ns());
|
||||
}
|
||||
|
||||
static const char *key_words[] = {
|
||||
// faults
|
||||
"Unable to handle kernel",
|
||||
"Unhandled fault",
|
||||
"Unhandled prefetch abort",
|
||||
// panic
|
||||
"Kernel panic",
|
||||
// oom
|
||||
"invoked oom-killer",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static size_t kmsg_data_strip(char *data, int len)
|
||||
{
|
||||
char *tmp, *first = NULL;
|
||||
int i;
|
||||
size_t ret = 0;
|
||||
|
||||
for (i=0; key_words[i]; i++) {
|
||||
tmp = strnstr(data, key_words[i], len);
|
||||
if (tmp) {
|
||||
if (!first || (tmp < first)) {
|
||||
ret = len - (first - data);
|
||||
first = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (first && ret > 0)
|
||||
memmove(data, first, ret);
|
||||
else
|
||||
ret = len;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* callback from kmsg_dump. Save as much as we can (up to kmsg_bytes) from the
|
||||
* end of the buffer.
|
||||
@ -407,7 +443,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
|
||||
|
||||
oopscount++;
|
||||
while (total < kmsg_bytes) {
|
||||
char *dst;
|
||||
char *dst, *keyword;
|
||||
size_t dst_size;
|
||||
int header_size;
|
||||
int zipped_len = -1;
|
||||
@ -439,6 +475,14 @@ static void pstore_dump(struct kmsg_dumper *dumper,
|
||||
dst_size, &dump_size))
|
||||
break;
|
||||
|
||||
// dump_size = kmsg_data_strip(dst + header_size, dump_size);
|
||||
|
||||
keyword = strnstr(dst + header_size, "Unable to handle kernel", dump_size);
|
||||
if (keyword) {
|
||||
dump_size -= (keyword - (dst + header_size));
|
||||
memmove(dst + header_size, keyword, dump_size);
|
||||
}
|
||||
|
||||
if (big_oops_buf) {
|
||||
zipped_len = pstore_compress(dst, psinfo->buf,
|
||||
header_size + dump_size,
|
||||
|
||||
@ -49,6 +49,9 @@ ifeq (, ${CONFIG_NO_TP})
|
||||
OTHERS += cp_ext_tp
|
||||
endif
|
||||
|
||||
KO_LIST += testing
|
||||
OTHERS += cp_testing
|
||||
|
||||
$(info ** [ KO_LIST ] ** = $(KO_LIST))
|
||||
|
||||
export CROSS_COMPILE=$(patsubst "%",%,$(CONFIG_CROSS_COMPILE_KERNEL))
|
||||
@ -69,12 +72,18 @@ wireless:
|
||||
wiegand-gpio:
|
||||
@$(call MAKE_EXT_KO, extdrv/${@})
|
||||
|
||||
testing:
|
||||
@$(call MAKE_EXT_KO, extdrv/${@})
|
||||
|
||||
cp_ext_wireless:
|
||||
@find extdrv/wireless -name '*.ko' -print -exec cp {} $(INSTALL_DIR)/3rd/ \;
|
||||
|
||||
cp_ext_tp:
|
||||
@find extdrv/tp -name '*.ko' -print -exec cp {} $(INSTALL_DIR)/3rd/ \;
|
||||
|
||||
cp_testing:
|
||||
@find extdrv/testing -name '*.ko' -print -exec cp {} $(INSTALL_DIR)/3rd/ \;
|
||||
|
||||
clean:
|
||||
@for subdir in $(SUBDIRS); do cd $$subdir && $(MAKE) clean && cd $(CUR_DIR); done
|
||||
@rm -f $(INSTALL_DIR)/*.ko
|
||||
|
||||
24
osdrv/extdrv/testing/Makefile
Normal file
24
osdrv/extdrv/testing/Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
#
|
||||
# Makefile for the Linux testings.
|
||||
#
|
||||
|
||||
obj-m += test_ps.o
|
||||
|
||||
all:
|
||||
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_DIR) M=$(shell pwd) modules
|
||||
|
||||
strip:
|
||||
$(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded
|
||||
|
||||
clean:
|
||||
find . -name *.d -delete
|
||||
find . -name *.ko | xargs -i rm -rf {}
|
||||
find . -name Module.symvers | xargs -i rm -rf {}
|
||||
find . -name Module.markers | xargs -i rm -rf {}
|
||||
find . -name modules.order | xargs -i rm -rf {}
|
||||
find . -name *.mod.c | xargs -i rm -rf {}
|
||||
find . -name *.mod | xargs -i rm -rf {}
|
||||
find . -name *.o | xargs -i rm -rf {}
|
||||
find . -name *.cmd | xargs -i rm -rf {}
|
||||
find . -name *~ | xargs -i rm -rf {}
|
||||
rm -fr .tmp_versions
|
||||
140
osdrv/extdrv/testing/test_ps.c
Normal file
140
osdrv/extdrv/testing/test_ps.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
static unsigned int test_type;
|
||||
module_param(test_type, uint, 0400);
|
||||
MODULE_PARM_DESC(test_type, "set to 1 to try to OOM (default 0)");
|
||||
|
||||
static int trigger_oops(void)
|
||||
{
|
||||
int *ptr = (int *)0; // 强制类型转换0地址为指针并尝试读取
|
||||
|
||||
printk(KERN_ALERT "Dereferenced NULL pointer value: %d\n", *ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trigger_oom(void)
|
||||
{
|
||||
void *memory = NULL;
|
||||
size_t memory_size = 0;
|
||||
|
||||
printk(KERN_INFO "oom_trigger: Initializing the oom_trigger LKM\n");
|
||||
|
||||
memory_size = 100*1024*1024;
|
||||
while (1) { // 尝试分配大块内存
|
||||
memory = vmalloc(memory_size);
|
||||
if (!memory) {
|
||||
printk(KERN_ALERT "oom_trigger: Memory allocation failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// 仅为防止编译器优化,实际不访问分配的内存
|
||||
memset(memory, 0, memory_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_data = 0;
|
||||
static struct rcu_head test_rcu_head;
|
||||
|
||||
static void bad_rcu_callback(struct rcu_head *head)
|
||||
{
|
||||
// 违规操作:在RCU回调函数中睡眠,这可能导致RCU grace period过长
|
||||
msleep(1000);
|
||||
|
||||
// 违规操作:修改被RCU保护的数据结构
|
||||
test_data++; // 不应在RCU回调中修改全局变量
|
||||
|
||||
pr_info("Bad RCU callback executed\n");
|
||||
}
|
||||
|
||||
static void trigger_rcu(void)
|
||||
{
|
||||
pr_info("RCU error module loaded\n");
|
||||
|
||||
call_rcu(&test_rcu_head, bad_rcu_callback);
|
||||
}
|
||||
|
||||
static int is_ready_thread1, is_ready_thread2;
|
||||
static struct task_struct *thread1;
|
||||
static struct task_struct *thread2;
|
||||
|
||||
static DEFINE_MUTEX(mutex_a);
|
||||
static DEFINE_MUTEX(mutex_b);
|
||||
|
||||
static int thread_func(void *data)
|
||||
{
|
||||
char *name = (char *) data;
|
||||
|
||||
if (!strcmp(name, "Thread1")) {
|
||||
printk(KERN_INFO "%s: Acquiring mutex A...\n", name);
|
||||
mutex_lock(&mutex_a);
|
||||
is_ready_thread1 = 1;
|
||||
while (!is_ready_thread2);
|
||||
printk(KERN_INFO "%s: Got mutex A. Now trying to acquire mutex B...\n", name);
|
||||
mutex_lock(&mutex_b); // This will block, causing deadlock
|
||||
printk(KERN_INFO "%s: Got mutex B.\n", name);
|
||||
} else {
|
||||
printk(KERN_INFO "%s: Acquiring mutex B...\n", name);
|
||||
mutex_lock(&mutex_b);
|
||||
is_ready_thread2 = 1;
|
||||
while (!is_ready_thread1);
|
||||
printk(KERN_INFO "%s: Got mutex B. Now trying to acquire mutex A...\n", name);
|
||||
mutex_lock(&mutex_a); // This will block, causing deadlock
|
||||
printk(KERN_INFO "%s: Got mutex A.\n", name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trigger_deadlock(void)
|
||||
{
|
||||
thread1 = kthread_run(thread_func, (void *) "Thread1", "thread1");
|
||||
if (IS_ERR(thread1)) {
|
||||
printk(KERN_ERR "Failed to create thread1\n");
|
||||
return PTR_ERR(thread1);
|
||||
}
|
||||
|
||||
thread2 = kthread_run(thread_func, (void *) "Thread2", "thread2");
|
||||
if (IS_ERR(thread2)) {
|
||||
printk(KERN_ERR "Failed to create thread2\n");
|
||||
kthread_stop(thread1);
|
||||
return PTR_ERR(thread2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trigger_init(void) {
|
||||
if (test_type == 0)
|
||||
trigger_oops();
|
||||
else if (test_type == 1)
|
||||
trigger_oom();
|
||||
else if (test_type == 2)
|
||||
trigger_rcu();
|
||||
else if (test_type == 3)
|
||||
trigger_deadlock();
|
||||
|
||||
return 0; // 加载模块不应该有返回值,但这里返回0避免编译警告。
|
||||
}
|
||||
|
||||
static void __exit trigger_exit(void) {
|
||||
if (test_type == 3) {
|
||||
kthread_stop(thread1);
|
||||
kthread_stop(thread2);
|
||||
printk(KERN_INFO "Deadlock trigger exit.\n");
|
||||
}
|
||||
}
|
||||
|
||||
module_init(trigger_init);
|
||||
module_exit(trigger_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user