Linux内核调试
- 格式:pdf
- 大小:414.52 KB
- 文档页数:7
Linux操作系统内核性能测试与调优操作系统是计算机系统中最核心的软件之一,它负责协调和管理计算机硬件资源以及提供统一的用户界面。
Linux操作系统因其开放源代码、稳定性和安全性而备受欢迎。
然而,在大规模和高负载的环境中,Linux操作系统的性能可能会出现瓶颈。
因此,进行内核性能测试与调优是非常重要的。
一、性能测试的重要性在处理大量数据和并发用户请求时,操作系统的性能会成为瓶颈。
通过性能测试,我们可以了解操作系统在不同负载情况下的表现,进而定位和解决性能瓶颈。
性能测试有助于提高系统的响应时间、吞吐量和并发性能,从而确保系统的稳定运行。
二、性能测试的分类1. 压力测试:通过模拟实际用户行为或产生大量虚拟用户,并观察系统在负载增加的情况下的响应时间和吞吐量。
常用的压力测试工具包括Apache JMeter和Gatling等。
2. 负载测试:通过模拟实际业务场景,并且能够测试系统在高负载情况下的响应能力和稳定性。
这种测试方法可以帮助我们发现系统在繁忙时是否仍然能够正常工作,并识别可能存在的性能瓶颈。
3. 并发测试:通过模拟多个并发用户并行执行相同或不同的操作,以验证系统在并发访问下的性能表现。
这种测试方法可以评估系统的并发处理能力和资源利用率。
三、内核性能调优的重要性Linux操作系统的性能与其内核配置息息相关。
对内核的性能调优可以提高系统的响应速度、降低延迟和提高吞吐量。
通过调整内核参数和优化内核模块,可以使操作系统更好地适应特定的工作负载。
四、内核性能调优的方法1. 内核参数调整:根据系统的工作负载特点,适当调整内核参数。
例如,可以通过修改TCP/IP堆栈参数来提高网络性能,或者通过修改文件系统参数来提高磁盘I/O性能。
2. 内核模块优化:优化内核使用的模块,选择性加载和卸载不必要的模块,以减少内核的资源占用和启动时间。
3. 中断处理优化:通过合理分配和调整中断处理的优先级,减少中断处理的开销,提高系统的性能。
Linux内核调试⽅法总结之反汇编Linux反汇编调试⽅法Linux内核模块或者应⽤程序经常因为各种各样的原因⽽崩溃,⼀般情况下都会打印函数调⽤栈信息,那么,这种情况下,我们怎么去定位问题呢?本⽂档介绍了⼀种反汇编的⽅法辅助定位此类问题。
代码⽰例如下:#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <execinfo.h>#include <fcntl.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#define PRINT_DEBUG#define MAX_BACKTRACE_LEVEL 10#define BACKTRACE_LOG_NAME "backtrace.log"static void show_reason(int sig, siginfo_t *info, void *secret){void *array[MAX_BACKTRACE_LEVEL];size_t size;#ifdef PRINT_DEBUGchar **strings;size_t i;size = backtrace(array, MAX_BACKTRACE_LEVEL);strings = backtrace_symbols(array, size);printf("Obtain %zd stack frames.\n", size);for(i = 0; i < size; i++)printf("%s\n", strings[i]);free(strings);#elseint fd = open(BACKSTRACE_LOG_NAME, O_CREAT | O_WRONLY);size = backtrace(array, MAX_BACKTRACE_LEVEL);backtrace_symbols_fd(array, size, fd);close(fd);#endifexit(0);}void die() {char *str1;char *str2;char *str3;char *str4 = NULL;strcpy(str4, "ab");}void let_it_die() {die();}int main(int argc, char **argv){struct sigaction act;act.sa_sigaction = show_reason;sigemptyset(&act.sa_mask);act.sa_flags = SA_RESTART | SA_SIGINFO;sigaction(SIGSEGV, &act, NULL);sigaction(SIGUSR1, &act, NULL);sigaction(SIGFPE, &act, NULL);sigaction(SIGILL, &act, NULL);sigaction(SIGBUS, &act, NULL);sigaction(SIGABRT, &act, NULL);sigaction(SIGSYS, &act, NULL);let_it_die();return 0;}在该⽰例中,我们通过⾃定义的信号处理函数,在程序异常时通过调⽤backtrace()和backtrace_symbols()函数获取并打印函数调⽤栈信息。
Linux调试⼯具1. 使⽤printf调试#ifdef DEBUGPrintf(“valriable x has value = %d\n”, x)#endif然后在编译选项中加⼊-DDEBUG更复杂的调试应⽤如:#define BASIC_DEBUG 1#define EXTRA_DEBUG 2#define SUPER_DEBUG 4#if (DEBUG &EXTRA_DEBUG)printf …#endif在这种情况下如果设置编译器标志为-DDEBUG=5,将启⽤BASIC_DEBUG和SUPER_DEBUG。
标志-DDEBUG=0将禁⽤所有的调试信息,也可以在程序中添加如下语句:#ifndef DEBUG#define DEBUG 0#endif2.使⽤gdb调试Gcc编译的时候要加上-g选项,让编译器在程序中添加额外的调试信息。
如果正式发布,这些调试信息可以使⽤strip命令删除。
Gdb:Backtrace栈跟踪3. 程序静态分析⼯具splintsplint功能:常识性测试并产⽣⼀些警告信息。
它可以检测未经赋值的变量使⽤,函数的参数未使⽤等异常情况。
4. 程序执⾏性能分析⼯具prof/gprof显⽰执⾏所花费的时间具体都⽤在什么操作上。
5. 内存调试ElectricFence函数库和valgrind可以⽤来检查动态内存分配的⼀些问题,包括内存泄漏。
Linux下的调试⼯具随着XP的流⾏,⼈们越来越注重软件的前期设计、后期的实现,以及贯穿于其中的测试⼯作,经过这个过程出来的⾃然是⾼质量的软件。
甚⾄有⼈声称XP会淘汰调试器!这当然是有⼀定道理的,然⽽就⽬前的现实来看,这还是⼀种理想。
在⽇常⼯作中,调试⼯具还是必不可少的。
在Linux下,调试⼯具并⾮只有gdb,还有很多其它调试⼯具,它们都各有所长,侧重⽅⾯也有所不同。
本⽂介绍⼏种笔者常⽤的调试⼯具:1. mtrace在linux下开发应⽤程序,⽤C/C++语⾔的居多。
内核卡死调试方法-概述说明以及解释1.引言1.1 概述内核卡死是指操作系统的内核无法继续执行下去,在特定的情景下,系统停止响应并无法正常运行。
这可能会导致系统崩溃、程序无法执行或者无法正常操作。
内核卡死调试方法是帮助我们解决这类问题的一种重要工具。
在本文中,我们将讨论内核卡死调试的方法和技巧,帮助读者更好地定位和解决内核卡死的问题。
首先,我们将介绍内核卡死的原因,包括硬件故障、软件错误和不兼容性等。
然后,我们将探讨内核卡死的常见表现,例如系统停止响应、屏幕冻结和错误信息等。
接着,我们将强调内核卡死调试的重要性。
内核卡死不仅会影响系统的稳定性和性能,还可能导致数据丢失和未完成的任务。
因此,在及时发现和解决内核卡死问题的同时,可以提高系统的可靠性和用户的体验。
最后,我们将总结内核卡死调试的方法和技巧。
这些方法包括使用系统日志和调试工具来分析和追踪系统状态,以及查找和修复可能的错误。
我们还将介绍一些常用的内核卡死调试工具和技术,如调试模式和堆栈跟踪。
通过本文的阅读,读者将能够更好地理解内核卡死调试的重要性和方法,使其能够快速解决内核卡死的问题,并提高系统的稳定性和可靠性。
1.2 文章结构文章结构是指对文章主要内容进行整体的组织和安排,以便读者能够清晰地了解文章的层次结构和脉络。
在讲述内核卡死调试方法的长文中,文章结构应该包括以下几个主要部分:1. 引言:在引言部分,我们将对内核卡死调试方法的重要性和必要性进行概述。
解释为什么需要调试内核卡死问题,以及通过本文能够掌握哪些相关的调试方法。
2. 内核卡死的原因:该部分将详细介绍导致内核卡死的各种原因,如硬件故障、软件错误、驱动冲突等。
通过对这些原因的分析,读者能够更好地理解内核卡死的根本问题。
3. 内核卡死的常见表现:在这一部分,我们将列举内核卡死的一些常见表现,如系统崩溃、黑屏、任务无响应等。
通过对这些表现的描述,读者能够判断出系统是否卡死,并能更好地定位具体问题。
使用ftrace 调试Linux 内核,第 2 部分ftrace 操作概述使用ftrace 提供的跟踪器来调试或者分析内核时需要如下操作:切换到目录/sys/kernel/debug/tracing/ 下查看available_tracers 文件,获取当前内核支持的跟踪器列表关闭ftrace 跟踪,即将0 写入文件tracing_enabled激活ftrace_enabled ,否则function 跟踪器的行为类似于nop;另外,激活该选项还可以让一些跟踪器比如irqsoff 获取更丰富的信息。
建议使用ftrace 时将其激活。
要激活ftrace_enabled ,可以通过proc 文件系统接口来设置:echo 1 > /proc/sys/kernel/ftrace_enabled将所选择的跟踪器的名字写入文件current_tracer将要跟踪的函数写入文件set_ftrace_filter ,将不希望跟踪的函数写入文件set_ftrace_notrace。
通常直接操作文件set_ftrace_filter 就可以了激活ftrace 跟踪,即将 1 写入文件tracing_enabled。
还要确保文件tracing_on 的值也为1,该文件可以控制跟踪的暂停如果是对应用程序进行分析的话,启动应用程序的执行,ftrace 会跟踪应用程序运行期间内核的运作情况通过将0 写入文件tracing_on 来暂停跟踪信息的记录,此时跟踪器还在跟踪内核的运行,只是不再向文件trace 中写入跟踪信息;或者将0 写入文件tracing_enabled 来关闭跟踪查看文件trace 获取跟踪信息,对内核的运行进行分析调试接下来将对跟踪器的使用以及跟踪信息的格式通过实例加以讲解。
回页首fucntion 跟踪器function 跟踪器可以跟踪内核函数的调用情况,可用于调试或者分析bug ,还可用于了解和观察Linux 内核的执行过程。
petalinux(二)开启petalinux内核调试模式描述要调试基于Xilinx SDK的Linux内核模块,必须使能KERNEL_DEBUG_INFO和KERNEL_DEBUGGING。
这篇博文全面记录了在Petalinux中是如何处理的。
解决方案获得基于调试模式的petalinux,需要一些特定的配置设定,有一些特定的配置需要设置为了获取PetaLinux基于内核调试工作。
完整的配置步骤请参考帮助文件:SDK Help Xilinx Software Development Kit (SDK) User Guide Working with Xilinx System Debugger System Debugger Supported Design Flows Attach and Debug using Xilinx System Debugger.下面是配置基于PetaLinux的Linux内核调试模式所涉及到的步骤:1)创建一个Zynq Vivado和导出模板项目硬件SDK。
2)创建一个Linux应用程序在SDK Hello World示例并关闭SDK项目,继续Petalinux项目下一步。
3)与下面的命令创建一个petalinux项目:petalinux-create --type project --template --name4)到petalinux项目目录下,并运行以下命令:petalinux-config --get-hw-descripTIon=指定hw-descripTIon的目录,目录中包含hdf文件( project_name 的。
sdk目录在您之前创建Vivado项目)。
5)如图2所示,到达Linux Components SelecTIon --- and then to kernel (xlnx-4.0)项,选择remote 选项:6)接下来我们需要指定完整的内核源代码的路径,该路径可以Xilinx GitHub页面找到。
Linux操作系统修改内核参数的三种方法详细说明linux内核的参数设置怎么弄呢,Linux 操作系统修改内核参数有以下三种方式:修改 /etc/sysctl.conf 文件;在文件中加入配置项,格式为 key = value,保存修改后的文件,执行命令 sysctl -p 加载新配置。
使用 sysctl 命令临时修改;如:sysctl -w net.ipv4.tcp_mem = “379008 505344 758016”直接修改/proc/sys/ 目录中的文件。
如:echo “379008 505344 758016” 》 /proc/sys/net/ipv4/tcp_mem 注意:第一种方式在重启操作系统后自动永久生效;第二种和第三种方式在重启后失效。
内核参数kernel.core_uses_pi d = 1core_uses_pid 可以控制 core 文件的文件名中是否添加 pid 作为扩展名。
设置为1,表示添加 pid 作为扩展名,生成的 core 文件格式为core.xxx;设置为0(默认),表示生成的 core 文件统一命名为 core。
kernel.core_pat te rn = corecore_pattern 可以控制 core 文件的保存位置和文件格式。
如:kernel.core_pattern = “/corefile/core-%e-%p-%t”,表示将core 文件统一生成到 /corefile 目录下,产生的文件名为 core-命令名-pid-时间戳。
以下是参数列表:%p - insert pid into filename 添加 pid%u - insert current uid into filename 添加当前 uid%g - insert current gid into filename 添加当前 gid%s - insert signal that caused the coredump into the filename 添加导致产生 core 的信号%t - insert UNIX ti me that the coredump occurred into filename 添加 core 文件生成时的 unix 时间%h - insert hostname where the coredump happened into filename 添加主机名%e - insert coredumping executable name into filename 添加命令名kernel.msgmax = 8192进程间的消息传递是在内核的内存中进行的。
Linux内核调试工具Kprobe机制的研究李清干* 邵作之(华北电力大学计算机科学与技术学院,北京 102206)摘 要:在传统内核调试过程中,我们经常使用print k作为内核调试的一种方法,但这种方法执行速度相对较慢,在对响应时间要求比较严格的内核控制路径(如中断)中不宜采用它。
Kprobe(K erne l probe)与2 6内核结合起来提供了一个动态插入pri n t k的轻量级、无干扰而且强大的装置,使用K probe不需要经常重新引导和重新编译内核就可以完成这一任务。
本文重点介绍K probe调试机制原理以及同内核接口。
关键词:L inux内核;K probe;探测点一、Kp robe机制简介K probe是IB M公司开发的一个轻量级调试工具,它允许内核运行时通过加载模块设置探测器,内核运行到探测点时便执行其相应的处理函数,这是以前的所有工具都做不到的。
K probe作为一个动态地收集调试和性能信息的工具,它从Dprobe项目派生而来,是一种非破坏性工具,用户用它几乎可以跟踪任何函数或被执行的指令以及一些异步事件(如ti m er)。
它的基本工作机制是:用户指定一个探测点,并把一个用户定义的处理函数关联到该探测点,当内核执行到该探测点时,相应的关联函数被执行,然后继续执行正常的代码路径。
使用K probe可以轻松地通过收集处理器寄存器和全局数据结构等调试信息。
开发者甚至可以使用K probe来修改寄存器值和全局数据结构的值。
K probe实现了三种类型的探测点:kprobes、j probes和kretprobes(也叫返回探测点)。
kprobes是可以被插入到内核的任何指令位置的探测点,j probes则只能被插入到一个内核函数的入口,而kre t probes则是在指定的内核函数返回时才被执行。
这三种类型可以用在不同情况的上下文中。
二、Kp robe机制实现原理当安装一个kprobes探测点时,K probe首先备份被探测的指令,然后使用断点指令(即在i386和x86_64的i nt3指令)来取代被探测指令的头一个或几个字节。
Linux内核实验报告实验题目:构造新内核同步机制实验实验目的:要设计一组新的内核同步原语,它们具有如下的功能:能够使多个进程阻塞在某一特定的事件上,直到另一进程完成这一事件释放相关资源,给内核发送特定消息然后由内核唤醒这些被阻塞的进程。
如果没有进程阻塞在这个事件上, 则消息被忽略。
可以编写 4 个系统调用来实现这些功能要求:1、生成一个事件的系统调用函数:int myevent_open(int eventNum);生成一个事件,返回该事件的 ID,如果参数为 0,表示是一个新的事件,否则就是一个存在的事件。
2、将进程阻塞到一个事件的系统调用函数:int myevent_wait(int eventNum);进程阻塞到 eventNum 事件,直到该事件完成才被唤醒。
3、唤醒等某事件进程的系统调用函数:int myevent_signal(int eventNum);唤醒所有等 eventNum 事件的进程,如果队列为空,则忽略。
4、撤销一个事件的系统调用函数:int myevent_close(int eventNum);撤销一个参数代表的事件,成功返回 eventNum。
最后重新设计这些系统调用,模拟实现信号量机制。
硬件环境:Pentium(R)*************************软件环境:Ubuntu12.04gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)内核版本:3.0.24实验步骤:1、代码分析结构体:typedef struct __myevent{int eventNum; // 事件号atomic_t value;wait_queue_head_t p; // 系统等待队列首指针struct __myevent *next; // 队列链指针}myevent_t;P操作:asmlinkage int sys_myevent_wait(int eventNum){myevent_t *tmp;myevent_t *prev = NULL;//取出指定事件的等待队列头指针?只是在事件队列上找到对应的事件吧,然后把该事件上的等待队列头指针取出来用if((tmp = scheventNum( eventNum, &prev)) != NULL){printk("[wait]:value is %u",atomic_read(&tmp->value));if (atomic_read(&tmp->value) > 0){ //YJ:有可用资源,减1并立即返回;不然等待atomic_dec(&tmp->value);printk("[wait]:i've dec value to <%u>",atomic_read(&tmp->value));return eventNum;}printk("[wait]:value should be 0 to sleep-->value:%u\n",atomic_read(&tmp->value));DEFINE_WAIT(wait); //初始化等待队列入口//使调用进程进入阻塞状态//prepare_to_wait(&tmp>p,&wait,TASK_INTERRUPTIBLE);set_current_state(TASK_INTERRUPTIBLE);add_wait_queue_exclusive(&tmp->p,&wait); //独占等待,放到队尾并置标志schedule(); //引发系统重新调度finish_wait(&tmp->p,&wait); // 设置当前进程状态为RUNNING,并且从队列中删除之(如果队列非空)printk("[wait]:now i'm back and value is :%u\n",atomic_read(&tmp->value));return eventNum;}return 0;}V操作:asmlinkage int sys_myevent_signal(int eventNum)myevent_t *tmp = NULL;myevent_t *prev = NULL;//取出指定事件的等待队列头指针if((tmp = scheventNum(eventNum,&prev)) != NULL) {if (list_empty(&(tmp->p.task_list))) { //没有进程在队列上atomic_inc(&tmp->value);printk("[signal]:so list is empty and value now is(added):%u\n",atomic_read(&tmp->value));return eventNum;}//唤醒操作,由于独占等待,只会唤醒一个进程,而且DEFINE_W AIT时挂上了autoremove_wake_up方法,进程会自动从队列上删除,wake_up和add_wait_queue这些都自动加spinlock了printk("[signal]:so i'm going to wake up one exclusive process\n");wake_up(&tmp->p);return eventNum;}return 0;}2、设计说明在这里着重说明信号量机制的实现。
内核卡死调试方法全文共四篇示例,供读者参考第一篇示例:内核卡死是指操作系统的内核无响应,导致系统无法正常运行的情况。
这种问题常常会引起用户的困扰,甚至影响到工作和生活。
在遇到内核卡死的情况时,我们需要及时采取有效的调试方法来解决问题,恢复系统的正常运行。
下面我们将介绍一些常用的内核卡死调试方法,帮助大家更好地解决这一类问题。
一、查找问题原因内核卡死可能是由于硬件故障、驱动程序问题、系统资源耗尽或系统异常等原因导致的。
在调试过程中,首先要确定问题的具体原因,只有找准了问题根源,才能有针对性地进行调试。
1.查看系统日志系统日志是记录系统运行状态和错误信息的重要来源,可以通过查看系统日志来了解系统在卡死前的运行情况,帮助定位问题。
常见的系统日志文件包括/var/log/syslog、/var/log/messages等。
2.分析dump文件当系统发生严重错误时,有些系统会自动生成dump文件来记录相关信息,包括系统状态、进程信息、内存内容等。
通过分析dump 文件,可以帮助我们更好地了解系统卡死的原因。
3.使用性能分析工具性能分析工具能够帮助我们监控系统运行状态、资源利用情况以及应用程序的性能指标,例如top、vmstat、iotop等工具。
通过这些工具的分析,有助于找出引起内核卡死的性能瓶颈。
二、排查问题处理找到问题的原因后,接下来就是解决问题了。
根据具体的问题原因采取相应的处理措施,可以采用以下几种方式:1.重启系统如果内核卡死是由临时故障或系统异常引起的,可以尝试通过重启系统的方式来解决问题。
重启系统可以使系统恢复到正常状态,重新启动所有进程,解决系统卡死的问题。
2.更新驱动程序如果内核卡死是由于驱动程序问题引起的,可以尝试更新相关的驱动程序。
有些驱动程序存在bug或兼容性问题,及时更新驱动程序可以解决这类问题。
3.释放系统资源如果系统资源耗尽导致内核卡死,可以通过释放系统资源的方式来解决问题,例如关闭不必要的进程、释放内存、清理硬盘空间等。
Linux内核调试技术——kprobe使用与实现一、kprobes技术背景开发人员在内核或者模块的调试过程中,往往会需要要知道其中的一些函数有无被调用、何时被调用、执行是否正确以及函数的入参和返回值是什么等等。
比较简单的做法是在内核代码对应的函数中添加日志打印信息,但这种方式往往需要重新编译内核或模块,重新启动设备之类的,操作较为复杂甚至可能会破坏原有的代码执行过程。
而利用kprobes技术,用户可以定义自己的回调函数,然后在内核或者模块中几乎所有的函数中(有些函数是不可探测的,例如kprobes自身的相关实现函数,后文会有详细说明)动态的插入探测点,当内核执行流程执行到指定的探测函数时,会调用该回调函数,用户即可收集所需的信息了,同时内核最后还会回到原本的正常执行流程。
如果用户已经收集足够的信息,不再需要继续探测,则同样可以动态的移除探测点。
因此kprobes技术具有对内核执行流程影响小和操作方便的优点。
kprobes技术包括的3种探测手段分别时kprobe、jprobe和kretprobe。
首先kprobe是最基本的探测方式,是实现后两种的基础,它可以在任意的位置放置探测点(就连函数内部的某条指令处也可以),它提供了探测点的调用前、调用后和内存访问出错3种回调方式,分别是pre_handler、post_handler和fault_handler,其中pre_handler函数将在被探测指令被执行前回调,post_handler会在被探测指令执行完毕后回调(注意不是被探测函数),fault_handler会在内存访问出错时被调用;jprobe基于kprobe实现,它用于获取被探测函数的入参值;最后kretprobe从名字种就可以看出其用途了,它同样基于kprobe实现,用于获取被探测函数的返回值。
kprobes的技术原理并不仅仅包含存软件的实现方案,它也需要硬件架构提供支持。
其中涉及硬件架构相关的是CPU的异常处理和单步调试技术,前者用于让程序的执行流程陷入到用户注册的回调函数中去,而后者则用于单步执行被探测点指令,因此并不是所有的架构均支持,目前kprobes技术已经支持多种架构,包括i386、x86_64、ppc64、ia64、sparc64、arm、ppc和mips(有些架构实现可能并不完全,具体可参考内核的Documentation/kprobes.txt)。
1.1 概述TI针对DM6467提供的UBOOT和内核默认都是串口0作为调试串口输出的,但现在我需要使用DM6467的UART0的modem功能,所以修改代码,改变调试串口为串口2。
需要修改的主要有几部分内容:1. UBL 代码(这部分代码在刚上电的时候,初始化CPU和拷贝UBOOT到DDR,打印信息只有很少,所以不做修改)。
2. UBOOT代码。
3. linux内核驱动。
2.1 修改UBOOT代码因为DM6467的串口是符合TL16C550标准的,所以驱动也是使用16550的驱动,默认情况下,我们只需要提供需要配置的串口的基地址和中断号等资源给16550的驱动就可以了,寄存器的配置不需要我们去关心。
要用起DM6467的串口有几个地方的配置一定要注意:1. 引脚复用寄存器(PINMUX0/1);2. VDD3P3V_PWDN寄存器,需要使能UART的相关引脚(bit4~bit9置零)3.CLKCTL,bit24/25置零。
在UBOOT里涉及到上面几个寄存器的配置的是在dm6467_evm.c的初始化部分我的修改如下:1static void davinci_hd_psc_enable ( void )2 {3 unsigned int alwaysonpdnum = 0;45/* Note this function assumes that the Power Domains are alread on */6 REG(PSC_ADDR+0xA00+4*14) |= 0x03; /* EMAC */7 REG(PSC_ADDR+0xA00+4*15) |= 0x03; /* VDCE */8 REG(PSC_ADDR+0xA00+4*16) |= 0x03; /* Video Port */9 REG(PSC_ADDR+0xA00+4*17) |= 0x03; /* Video Port */10 REG(PSC_ADDR+0xA00+4*20) |= 0x03; /* DDR2 */11 REG(PSC_ADDR+0xA00+4*21) |= 0x03; /* EMIFA */12 REG(PSC_ADDR+0xA00+4*26) |= 0x03; /* UART0 */13 REG(PSC_ADDR+0xA00+4*27) |= 0x03; /* UART1 */14 REG(PSC_ADDR+0xA00+4*28) |= 0x03; /* UART2 */15 REG(PSC_ADDR+0xA00+4*31) |= 0x03; /* I2C */16 REG(PSC_ADDR+0xA00+4*33) |= 0x03; /* GPIO */17 REG(PSC_ADDR+0xA00+4*34) |= 0x03; /* TIMER0 */18 REG(PSC_ADDR+0xA00+4*35) |= 0x03; /* TIMER1 */1920/* Set PTCMD.GO to 0x1 to initiate the state transtion for Modules i n21 * the ALWAYSON Power Domain22*/23 REG(PSC_PTCMD) = (1<<alwaysonpdnum);2425/* Wait for PTSTAT.GOSTAT0 to clear to 0x0 */26while(! (((REG(PSC_PTSTAT) >> alwaysonpdnum) & 0x00000001) == 0));2728/* Enable GIO3.3V cells used for EMAC (???) */29 REG(VDD3P3V_PWDN) = (1<<27); //disable clkout03031/* Select UART function on UART0 */32 REG(PINMUX0) &= ~(0x0000003f << 18);34 REG(PINMUX1) = ((1<<4)|(1<<2)|(1<<0));3536/* Enable USB */37 REG(PINMUX0) &= ~(0x80000000);3839/* Set the Bus Priority Register to appropriate value */40 REG(VBPR) = 0x20;41 }接下来还有一个比较重要的地方需要修改,因为DM6467的串口是支持多种模式的,但16550的驱动是默认设备是工作在UART模式的,它没有去配置设备串口的工作模式,所以我们需要去配置一下串口的工作模式。
Linux内核调试方法总结之sysrq
sysrq
【用途】
Sysrq被称为”魔术组合键”,是内建于Linux内核的调试工具。
只要内核没有完全锁住,不管内核在做什么事情,使用这些组合键都可以搜集包括系统内存使用、CPU任务处理、进程运行状态等系统运行信息。
【原理】【内核帮助文档kernel/Documentation/sysrq.txt】
首先,内核配置选项中要使能CONFIG_MAGIC_SYSRQ选项,这样系统启动之后,会生成/proc/sysrq-trigger节点用于调试。
其次,可以在/etc/sysctl.conf中设置kernel.sysrq=1默认使能sysq功能。
也可以通过写/proc/sys/kernel/sysrq节点动态使能sysrq 功能。
写入不同的值使能不同的功能:
#echo m > /proc/sysrq-trigger 导出内存分配信息
#echo t > /proc/sysrq-trigger 导出当前任务状态信息
#echo p > /proc/sysrq-trigger 导出当前CPU寄存器和标志位信息
#echo c > /proc/sysrq-trigger 产生空指针panic事件,人为导致系统崩溃
#echo s > /proc/sysrq-trigger 即时同步所有挂载的文件系统
#echo u > /proc/sysrq-trigger 即时重新挂载所有的文件系统为只读
#echo w > /proc/sysrq-trigger转储处于uninterruptable阻塞状态的任务。
Eclipse CDT + QEMU调试linux内核本篇有关系统环境我要交代一下。
因为在ubuntu下找不到eclipse cdt的源,所以要先apt-get 一个eclipse paltform然后在里面选择更新安装cdt才能安装成功。
但在eclipse platform 里更新比较容易失败,所以我推荐大家安装opensuse 11.0,在这里面只要到下载一个eclipse c/c++ ide ,直接解压便可运行。
文章开始!1.首先我们要从下载内核源码,在这里我选择的是linux-2.6.28.tar.bz2。
我将其下载到我的主目录下,然后在xterm下输入以下命令。
$ cd (回到主目录)$ tar xf linux-2.6.28.tar.bz2 (解压源码)$ mkdir linux-2.6.28-obj (创建一个编译内核的目标文件输出目录)$ cd linux-2.6.28 (进入内核源码树根目录)$ make O=/home/xxx/linux-2.6.28-obj menuconfig (这里我们要配置内核,并在~/linux-2.6.28-obj目录下生成内核配置文件.config) (注意:这里的xxx表示的是你的用户名) 注意在这里我们要选择kernel hacking 配置菜单下的“Compile the kernel with debug info”和“Compile the kernel with frame pointers”如下图:2. 接下来我们打开elicpse,第一次打开时有一个欢迎画面,我们单击右边的workbench图片关掉欢迎画面。
由于eclipse cdt是一个非常强大的c/c++ ide,它默认会自动的解析工程中源程序并编译工程和产生智能提示信息。
但由于我们调试内核过程中暂不会用到这些功能,所以要关闭他们。
首先我们到Window->Preferences->General->Workspace 中将Build Automatically选项去掉。
Linux内核调试⽅法总结之死锁问题分析死锁问题分析死锁就是多个进程(线程)因为等待别的进程已占有的⾃⼰所需要的资源⽽陷⼊阻塞的⼀种状态,死锁状态⼀旦形成,进程本⾝是解决不了的,需要外在的推动,才能解决,最重要的是死锁不仅仅影响进程业务,⽽且还会占⽤系统资源,影响其他进程。
所以内核中设计了内核死锁检测机制,⼀旦发现死锁进程,就重启OS,快⼑斩乱⿇解决问题。
之所以使⽤重启招数,还是在于分布式系统中可以容忍单点崩溃,不能容忍单点进程计算异常,否则进⾏死锁检测重启OS就得不偿失了。
内核提供⾃旋锁、信号量等锁形式的⼯具,具体不再赘述。
Linux内核死锁主要分为分为两种:D状态死锁和R状态死锁。
⼀、D状态死锁检测D状态死锁:进程长时间处于TASK_UNINTERRUPTIBLE⽽不恢复的状态。
进程处于TASK_UNINTERRUPTIBLE状态,不响应其他信号(kill -9),保证⼀些内核原⼦操作不被意外中断。
但这种状态时间长就表⽰进程异常了,需要处理。
内核D状态死锁检测就是hung_task机制,主要代码就在kernel/hung_task.c⽂件。
具体实现原理:1.创建Normal级别的khungtaskd内核线程,在死循环中每隔sysctl_hung_task_timeout_secs时间后check⼀下,⽤schedule_timeout定时(节约定时器浪费的CPU)。
2.调⽤do_each_thread,while_each_thread宏遍历所有的进程信息,如果有D状态进程,则检查最近切换次数和task计算是否⼀致,即最近是否有调度切换,如果⼀致,则没有切换,打印相关信息,并根据sysctl_hung_task_panic开关决定是否重启。
对应⽤户态控制的proc接⼝有:/proc/sys/kernel/hung_task_timeout_secs,hung_task_panic等。
⼆、R状态死锁检测R状态死锁:进程长时间处于TASK_RUNNING 状态抢占CPU⽽不发⽣切换,⼀般是,进程关抢占后⼀直执⾏任务,或者进程关抢占后处于死循环或者睡眠,此时往往会导致多个CPU互锁,整个系统异常。
Linux系统下的软件开发调试技巧在软件开发中,调试是一个非常重要的环节,对于开发人员来说,这是发现和解决错误的关键阶段。
在Linux系统下开发软件,不同于其他操作系统,需要掌握一些专门的调试技巧,这些技巧可以帮助开发人员更加高效地调试程序。
以下是一些Linux系统下的软件开发调试技巧。
1. 充分利用 Linux 内核中的调试工具Linux内核中集成了许多调试工具,如strace、gdb、objdump等等。
可以利用这些工具来分析程序运行过程中出现的问题,比如内存泄漏、死锁等。
其中, GDB是一个强大的调试器,是Linux下最常用的调试工具之一。
他可以帮助开发人员跟踪BUG并捕捉核心转储文件。
使用GDB可以在开发过程中定位程序的错误和异常,并快速地解决问题。
2. 使用makefile来构建程序makefile通过简单的定义来管理程序的构建过程,在Linux的开发环境中很常用。
它可以将构建过程分为多个步骤,并使开发人员能够轻松地修改其中一个步骤而不会影响其他步骤,从而使构建过程更加灵活和可维护。
makefile同时可以管理多个文件的编译以及正确处理链接依赖关系等复杂的构建操作。
3. 利用版本控制工具版本控制工具被广泛用于管理代码并帮助团队协作。
在Linux 下,使用版本控制工具可以很容易地跟踪代码变更,同时也可以帮助开发人员回滚到先前的版本,并更容易地利用分支和标签来管理代码。
使用版本控制工具也有助于团队协作,并且对于故障排除、代码重构和功能追踪非常有用。
4. 使用轻量、快速的编辑器开发人员需要在编写代码时使用轻量、快速的编辑器,以便任务不被中断。
Vim和Emacs这两款编辑器在Linux下有着广泛的应用,它们的优势是快速、可扩展、有强大的功能。
它们能够实现代码高亮、自动缩进、代码补全等特性,从而提高开发人员的生产率。
5. 使用测试自动化工具在强调代码质量和稳定性的现代软件开发过程中,关键是将测试纳入开发周期。
0x00 前言
这段时间开始学习了linux内核提权,也跟进看了一些漏洞。
但是由于linux系统版本、内核版本的不同,驱动模块或者是某个函数的加载地址都是不同的,如果不能自己亲自调试内核,就算给了exp也是无法利用。
之前也没有怎么接触过内核调试,所以这几天找了许多资料开始学习调试内核的方法,总结整理在这。
本文测试系统是Ubuntu12.04 64位。
0x01 准备环境
首先当然是准备需要调试的内核版本,linux的所有历史版本都可以在这里找到。
down下来后进入源码树根目录,开始配置内核,这里使用基于ncurse库编制的图形界面工具:
$ make menuconfig
由于我们需要使用kgdb调试内核,注意下面这几项一定要配置好:
KernelHacking -->
选中Compile the kernel with debug info
选中Compile the kernel with frame pointers
选中KGDB:kernel debugging with remote gdb,其下的全部都选中。
Processor type and features-->
去掉Paravirtualized guest support
KernelHacking-->
去掉Writeprotect kernel read-only data structures(否则不能用软件断点)
保存config文件之后make、make modules_install、make install编译安装就好。
具体安装编译内核可以看我另一篇笔记
0x02 使用kvm、gdb调试内核
先介绍一下现在用得比较多的调试内核方法吧,简单地说就是在linux系统里再装一个kvm虚拟机配置好gdb远程调试支持,然后在linux主机上连接调试。
但是我因为电脑配置不高,装了kvm太卡就放弃了这个方法orz
总之还是讲一下怎么调试吧。
查看cpu是否支持,如果没有输出,要在虚拟机设置里选上Inter VT:
$ grep vmx /proc/cpuinfo
安装:
$ sudo apt-get install kvm qemu libvirt-bin virtinst virt-manager virt-viewer 需要将自己添加进kvm、libvirtd用户组:
$ sudo adduser 用户名 kvm
$ sudo adduser 用户名 libvirtd
$ groups
打开libvirt-bin服务:
$ sudo service libvirt-bin start
然后打开virt-manager开始装虚拟机:
$ gksudo virt-manager
这个图形界面的virt-manager和vmware差不多,就这样直接装虚拟机就好了。
然后添加下面配置使虚拟机支持gdb调试:
<qemu:commandline>
<qemu:arg value='-S'/>
<qemu:arg value='-gdb'/>
<qemu:arg value='tcp::1234'/>
</qemu:commandline>
将要调试的内核源码树复制进虚拟机,准备调试。
之后在主机端进入gdb调试:
$ gdb vmlinux
(gdb) target remote 127.0.0.1:1234 //连接虚拟机,这时虚拟机已经断下
(gdb) b drv_open //在驱动程序的入口函数设置断点
(gdb) c
Countinuing. //让虚拟机重新跑起来
如果要调试驱动模块的话,要在虚拟机里加载该模块:
$ insmod drv.ko
然后再回到主机开始调试。
0x03 用gdb和qemu调试内核
用qemu其实和上面kvm的差不多(qemu也已经在上面那步装好了),这里介绍一个比较快速的方法。
直接在qemu中启动已经编译好的Linux内核,不用再制作完整的启动镜像:
qemu-system-x86_64 -s -S -kernel arch/i386/boot/bzImage -hda /boot/initrd.img -append "root=/dev/hda" -gdb tcp::1234
命令中的bzImage和initrd.img就是内核源码树中对应目录下的文件。
如果不需要图形界面的话可以加上下面的参数:
-nographic
在主机用gdb调试连接:
$ gdb vmlinux
(gdb) target remote:1234
和上面的差不多可以开始调试了。
0x04 用kdb和kgdb调试内核驱动模块
接下来介绍如何用kgdb和gdb来调试内核驱动。
kgdb 是一个在 Linux 内核上提供完整的 gdb 调试器功能的补丁。
通过串口连线以钩子的形式挂入目标调试系统进行工作,然后远程运行 gdb。
使用 kgdb 时需要两个系统——一个用于运行调试器,另一个用于运行待调试的内核。
当然,用两台VM虚拟机也是可以调试内核的,渣电脑开心地都哭了(つд⊂)
首先准备两台VMware虚拟机,直接复制之前配置好的虚拟机来创建一个新的就好。
配置双机通信:
将准备好的两台虚拟机添加串行端口,如果有并行端口记得先删除。
注意箭头处的设置,一个得是客户端一个是服务端。
然后来验证一下是否成功连接。
先在客户机使用下面命令,准备接收消息:
$ cat /dev/ttyS0
然后在目标机(开启服务端的那个)输入下面命令:
$ echo edvison > /dev/ttyS0
如果没有显示就试下ttyS[0~3]
配置串口调试:
两个虚拟机都更改/etc/default/grub文件,在GRUB_CMDLINE_LINUX_DEFAULT这项后面加上kgdboc=ttyS1,115200,如果不需要图形界面启动的话可以加上text(最好目标机使用这个):
然后update-grub一下,重启系统。
进入grub界面,选择要调试的内核版本。
(没有进grub的话去把gurb文件里GRUB_HIDDEN_TIMEOUT这行注释掉)
出现下面的信息就说明配置成功了。
开始调试:
打开目标机,可以看到已经显示命令行界面了(之前配置里加了text)
编译、载入要调试的驱动(这里使用内核ROP的那个栗子,源码在这里可以找到。
打开客户机,使用gdb准备开始连接调试:
编译加载好驱动后,在目标机里查看我们调试的驱动的加载基址,由于我们的驱动程序能直接打印基址,所以用dmesg 命令查看就好:
另外还可以用下面的命令查看模块基址:
cat /proc/modules | grep drv
然后在目标机下输入下面的命令,使目标机进入被调试的假死状态:
# echo g > /proc/sysrq-trigger
接下来就可以在客户机里连接上目标机了:
之后在客户机里加载符号文件,并给驱动的入口函数device_ioctl()和device_open()设置断点:输入c让目标机继续运行。
然后我们在目标机调试trigger程序,来调用内核模块的device_ioctl函数。
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drv.h"
#define DEVICE_PATH "/dev/vulndrv"
int main(int argc, char **argv) {
int fd;
struct drv_req req;
req.offset = atoll(argv[1]);
//map = mmap((void *)..., ..., 3, 0x32, 0, 0);
fd = open(DEVICE_PATH, O_RDONLY);
if (fd == -1) {
perror("open");
}
ioctl(fd, 0, &req);
return 0;
}
在open函数和ioctl下下断:
调试到这里后断下(直接运行./trigger [offset]也能在客户机里断下),可以看到客户机已经进入了驱动程序的调试模式,接下来就可以随意进行调试了;)
0x05 参考链接
/gdb-kgdb-debug-application/
https://qemu.weilnetz.de/doc/qemu-doc.html#direct_005flinux_005fboot
https:///developerworks/cn/linux/1508_zhangdw_gdb/index.html。