Kernel build & debug

来源:互联网 发布:mysql如何分库分表实例 编辑:程序博客网 时间:2024/05/18 07:48

Build & Debug

Build

[steps of build kernel]

Stepsof building Kernel

1.   Run"make ARCH=xxx CROSS_COMPILE=xxx msmxxx_defconfig" to create .configfile.

NOTE:Modify.config (optional)

approach1:“scripts/config --file ${KERNEL_OUTPUT}/.config --enable CONFIG_TIMA_UEVENT”

approach2:make .... menuconfig, then .config is updated

Donot directly and freely modify .config, maybe you break rule of Kconfig

2.    (optional) Run "make menuconfig"and modify some configuare

3.    Run make or make bzImage  (zImage is indeed kernel), like “make-C xxxARCH=xxx CROSS_COMPILE=xxx O=XXX -j8”

如果/KERNEL/Makefile中没有ARCH和CROSS_COMPILE变量,必须在make命令中加入

NOTE1: "Make msmxxx_defconfig" this command does that loadingmsmxxx_defconfig and check all of Kconfig to create final .config, so .configis not fully same as msmxxx_defconfig.

NOTE2: "Make menuconfig" does that loading  .config located in current directory andaccording to all of Kconfig to draw graphic-format KERNEL configuration; If.config is lack, "make menuconfig" should load "default"config.

NOTE3: Review kernel/arch/arm64/boot/Makefile to find out details of zImage orImage.gz

NOTE4:Youcan check out README in /Documentation/kbuild/* forKconfig and Makefile

 

Load ko

 

模块相关命令:

lsmod: see loaded modules

modinfo: see info of module

insmod: load module

modprobe: load module with dependance checking

rmmod: remove module


[About vmlinux & boot.img generation]

BOOT.IMG header

android/system/core/mkbootimg/bootimg.h

28 struct boot_img_hdr

 29 {

 30     unsigned char magic[BOOT_MAGIC_SIZE];

 31

 32     unsigned kernel_size;  /* size in bytes */

 33     unsigned kernel_addr;  /* physicalload addr */

 34

 35     unsigned ramdisk_size; /* size in bytes */

 36     unsigned ramdisk_addr; /* physical loadaddr */

 37

 38     unsigned second_size;  /* size in bytes */

 39     unsigned second_addr;  /* physical load addr */

 40

 41 #ifdef DT_SUPPORT

 42     unsigned dtb_size;     /* size in bytes */

 43     unsigned dtb_addr;     /* physical load addr */

 44 #endif

 45

 46     unsigned tags_addr;    /* physical addr for kernel tags */

 47     unsigned page_size;    /* flash page size we assume */

 48     unsigned unused[2];    /* future expansion: should be 0 */

 49

 50     unsigned char name[BOOT_NAME_SIZE]; /*asciiz product name */

 51

 52     unsigned char cmdline[BOOT_ARGS_SIZE];

 53

 54     unsigned id[8]; /* timestamp / checksum /sha1 / etc */

 55 };

 

TEXT_OFFSET & PAGE_OFFSET

SR:在bootloader中直接将bootimg加载到DDR的物理地址,代码如下:

andr_mmc_pread((unsigned char *)KERNEL_RAM_BASE, 0,bootimg_size + 256, a_nPartId);

其中KERNEL_RAM_BASE是物理地址,数值为0x00000000 + 0xa000000,其中芯片手册讲到:

Memory Map ---- From 0x0000_0000 to 0xFFFF_FFFF

Base Addres             MemoryMap

0x0000_0000             DDR

0x0000_0000             Reserved

0xC002_0000             MMU_VPU

0xC010_0000             DDRConfiguraion

0xC020_0000             ISP

......

 

 

说明从0x0000_0000 到0x8000_0000是给DDR用的。

SR:应该在kernel初始化,会把kernel起始的物理地址传给mmu,以便映射kernel物理内存。具体怎么传的,没有深究,不过bootimg的hdr存储着各个image的physical address

至于PAGE_OFFSET和TEXT_OFFSET什么关系?SR:PAGE_OFFSET等于0xC0000000 - kernel物理地址(其中用到TEXT_OFFSET)

 

#vmlinux生成规则中用到TEXT_OFFSET

TEXT_OFFSET在kernel/arch/arm64/Makefile中定义如下:

TEXT_OFFSET := $(textofs-y)

 40 # The byte offsetof the kernel image in RAM from the start of RAM.

 41 textofs-y       := 0x00080000

 42textofs-$(CONFIG_TEXT_OFFSET_OVERRIDE) := $(CONFIG_TEXT_OFFSET)

 

in kernel/arch/arm/boot/Makefile

19 # Note: the following conditions must always be true:

 20 #   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)

 21 #   PARAMS_PHYS must be within 4MB of ZRELADDR

 22 #   INITRD_PHYS must be in RAM

 23 ZRELADDR    := $(zreladdr-y)

 24 PARAMS_PHYS :=$(params_phys-y)

 25 INITRD_PHYS :=$(initrd_phys-y)

........

最终在打包boot.img时,kernel,ramdisk等的physical addr会写到bootimg的hdr中

vmlinux生成脚本参考

/***
http://blog.csdn.net/richardysteven/article/details/7968002
vmlinux是如何炼成的--kernel makefile
引子
kernel的makefile包含的内容还真是多,我就是想看看要是我自己添加一个目录编译到内核里,要怎么做。
就是这么个不起眼的实验,引发了一堆的故事。
最简单的例子
添加 一个目录,叫test, 添加了test.c 和 Makefile。
文件内容很简单,如下。
cat Makefile
#
# Makefile for the linux kernel makefile experiment.
#
obj-y := test.o
cat test.c
#include <linux/export.h>
int test_global = 0;
然后在主 Makefile中 添加
-core-y         += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y         += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/
最后 make test
make[1]: Nothing to be done for `all'.
  HOSTCC  arch/x86/tools/relocs
  CHK     include/linux/version.h
  CHK     include/generated/utsrelease.h
  CC      kernel/bounds.s
  GEN     include/generated/bounds.h
  CC      arch/x86/kernel/asm-offsets.s
  GEN     include/generated/asm-offsets.h
  CALL    scripts/checksyscalls.sh
  CC      test/test.o
  LD      test/built-in.o
恩,不错,可以了。
vmlinux是如何炼成的
人总是不知足的,我又开始好奇,这个build的过程究竟是怎么个回事。
好吧,我们知道make后,最终的结果叫vmlinux,那我们就找找这个神奇的东西是怎么
产生的吧。
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
ifdef CONFIG_HEADERS_CHECK
    $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
    $(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
    $(Q)$(MAKE) $(build)=Documentation
endif
    +$(call if_changed,link-vmlinux)
vmlinx 基于上面三个目标, 而vmlinux-deps又基于 $(vmlinux-dirs)。 恩,好复杂。
那来看看vmlinux-dirs都包含什么吧。
在主Makefile中看到下面的内容。
core-y        += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/
vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
             $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
             $(net-y) $(net-m) $(libs-y) $(libs-m)))
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@
恩, 我们把vmlinux-dirs的东东打印出来看看。
vmlinux-dris: init usr arch/x86 kernel mm fs ipc security crypto block test drivers sound firmware arch/x86/pci arch/x86/power arch/x86/video arch/x86/oprofile net lib arch/x86/lib
这样,你是不是明白点了呢。 这些都是kernel源代码中子目录。也就是kernel将要挨个的
进入每个子目录,编译~。
那最后这个vmlinux是怎么生成的呢? 怎么样将每个目录下生成的模块链接成一个vmlinux的文件的呢?
看到上面vmlinux目标中,最后一个命令:
+$(call if_changed,link-vmlinux)
哦,原来是调用了cmd_link-vmlinux。这个命令就定义在主Makefile中。
      cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)
打出来看看,长这样。
      /bin/bash $<  ld -m elf_i386 --emit-relocs --build-id
$< 表示第一个以来目标,那么在vmlinux目标中,第一个目标是 scripts/link-vmlinux.sh, 展开后就成为。
/bin/bash scripts/link-vmlinux.sh ld -m elf_i386 --emit-relocs --build-id
额,原来是又调用了一个脚本。。。 好吧, 再进去看看。  发现这么个东东
info LD vmlinux
vmlinux_link "${kallsymso}" vmlinux
vmlinux_link()
{
    local lds="${objtree}/${KBUILD_LDS}"
    if [ "${SRCARCH}" != "um" ]; then
        ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}                  \
            -T ${lds} ${KBUILD_VMLINUX_INIT}                     \
            --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
    else
        ${CC} ${CFLAGS_vmlinux} -o ${2}                              \
            -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT}                 \
            -Wl,--start-group                                    \
                 ${KBUILD_VMLINUX_MAIN}                      \
            -Wl,--end-group                                      \
            -lutil ${1}
        rm -f linux
    fi
}
好吧,原来是调用了这个函数。。。 打出来看看吧。
ld -m elf_i386 --emit-relocs --build-id -o vmlinux -T arch/x86/kernel/head_32.o arch/x86/kernel/head32.o arch/x86/kernel/head.o init/built-in.o --start-group usr/built-in.o arch/x86/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o test/built-in.o lib/lib.a arch/x86/lib/lib.a lib/built-in.o arch/x86/lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o arch/x86/pci/built-in.o arch/x86/power/built-in.o arch/x86/video/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o
恩,原来真相是这样的。 最后把这么多东西链接起来成为vmlinux。 看到我们添加的test目录了么,它也生成了一个built-in.o,最后链接到了vmlinux中。
$ nm vmlinux | grep test_global
c198d284 B test_global
啊哦,还真有这个symbol!
神秘的built-in.o
在最后的链接过程中,我们可以看到,几乎所有的依赖条件中,都会生成一个built-in.o的文件。 那这个文件,是怎么生成的呢?
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@
从这个规则中可以看到,vmlinux-dir目标是通过下面的make来生成的。展开一下看看。 这个build在scripts/Kbuild.include中。
make -f scripts/Makefile.build obj=$@
对应到test目录 那就是
make -f scripts/Makefile.build obj=test
这么看来,就要进到scripts/Makefile.build文件了。
PHONY := __build
__build:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
     $(subdir-ym) $(always)
    @:
__build是这个makefile的第一个目标,也是默认的目标。 这里面藏着一个builtin-target,看着很像,再搜搜。
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
恩 原来这个就是这么多叫built-in.o的原因。但是要生成buit-in.o,必须要以上的这些变量不能全部为空。
那再来看看编译这个built-in.o的规则是什么
quiet_cmd_link_o_target = LD      $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
              $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
              $(cmd_secanalysis),\
              rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
$(builtin-target): $(obj-y) FORCE
    $(call if_changed,link_o_target)
targets += $(builtin-target)
恩,基本明白了,就是当obj-y的内容不为空,那么就用ld来链接成一个built-in.o。
但是我试了一下,如果没有obj-y那么,也会生成一个built-in.o,但是用的是别的命令。
如在i386下,用的是
rm -f test/built-in.o; ar rcsD test/built-in.o
不知道这个是什么高级玩意。
好了,到此为止,基本上一个最上层的框架有了一个概念。 那就先休息一下~


[process of kernel generation]

vmlinux141M

-->(objcopy --strip) Image 13M

-->(gzip) Image.gz 5.8M

-->(add DTB_OBJS) Image.gz-dtb

-->(zintall) Image.gz

-->($kernel/script/mkimage xxx/Image.gz in Samsung buildscript) uImage 5.8M

-->(change name from uImage to kernel in SS buildscript) kernel

 

#NOTE:

64-bit的kernel生成不同于32-bit

即arm64 does not support to make zImage and uImage. So script/mkimageis added for making uImage

scripts/mkimage-A arm64 -O linux -C gzip -a 0x0880000 -e 0x0880000 .....

其中load address to 'addr' (hex) 和 entry point to 'ep' (hex)分别代表kernel加载地址和运行地址,(我认为)加载地址指向的是zImage头部解压代码的地址;而运行地址应该是解压后kernel的地址

uImage= zImage + 0x40 bytes header

在开启MMU之前,使用的是物理地址

 

###生成ELF的LDS脚本对目标文件的内存布局

$kernel/include/asm-generic/vmlinux.lds.h

 

[Built-in to mdoule step]

Takecamera  for an example,

内核编译配置中将所有camera的从*变为M

然后将模块中用到的内核符号进行EXPORT_SYMBOL导出

将各个编译出来的ko按照Makefile中的顺序依次加载。

NOTE:当变成模块后,对应的宏(例如CONFIG_VIDEO_SR030PC30)

要在内核代码中进行搜索,确保于本驱动相关的部分在内核中也相应的改变

Debug tricks

###Howto force panic

BUG_ON(1)  -> panic()

 

###Howto print backtrace(i.e. call stack)

WARN_ON(1)-> dump_stack()

Forexample:

      JDBG("\nWARN_ON(1)START\n");

      WARN_ON(1);

      JDBG("\nWARN_ON(1) END\n");

 

###Usefulinterface for debug

/sys/kernel/debug

/sys/bus/cpu/devices/cpu4/cpufreq

/sys/devices/system/cpu/online# check if cpu is online

 

###Procfilesystem

common sticks: like searching /dev/block/zram0 , you can install busybox and  use "find|grep zram" .....

/proc/kallsyms 内核符号表,如果不01.EXPORT_SYMBOL(符号名); 02.EXPORT_SYMBOL_GPL(符号名),则只有本模块、编译到内核才可以使用

/proc/partitions分区信息

/proc/meminfo

/proc/cmdline

/proc/interrupts

cat /proc/filesystems

/proc/modules

/proc/kallsyms

/proc/devices (系统中注册的设备编号,major and minor number)

/sys/kernel/debug/gpio列出所有注册的控制器,以及当前正在使用中的GPIO的状态

/proc/devices 查看驱动当前支持的所有设备类型,例如ttyUSB都没有的话,一定没有/dev/ttyUSB*设备

 

###Printcurrent process information

#include<linux/sched.h>

//currentis type of “struct task_struct”

printk(KERN_DEBUG"Task name: %s, task ID: %d\n", current->comm, current->pid);

dump_stack();

 

Print log

printk

#echo8 > /proc/sys/kernel/printk

      in kernel/printk.c

      int console_printk[4] = {x, x, x, x}


Enlargekernel log buffer:

modify"$KERNEL/init/Kconfig" (LOG_BUF_SHIFT)

OR

Modifylog_buf array size (i.e. __log_buf[__LOG_BUF_LEN])

 

cmdlinesample “console=ttySAC2 115200 loglevel=1”

tools:“dmesg” or “cat /proc/kmsg”

printon serial port: only above loglevel’s message will be printed.

Dynamic debug (i.e. pr_debug or dev_dbg)

(1)     AddDEBUG macro definition in Makefile in the following two ways

“ccflags-y:= -DDEBUG”

“CFLAGS_pm.o+= -DDEBUG” to open pm.c file seperately

 

NOTE:Need modify console debug level less than 7, i.e. 8, if print via serial port.

 

(2)     ForCONFIG_DYNAMIC_DEBUG,  you can swith openand close in sysfs file,

Followinginstruction in file “Documentation/dynamic-debug-howto.txt”

     

NOTE:  Using “mount” command to check out debugfspath, like this

debugfs/sys/kernel/debug debugfs rw,relatime 0 0

 

Pr_info is printed as default.

Pr_debug should be opened manually. For below example: (openheadset_sec.c file’s all message)

adb shell "echo 'file headset_sec.c +p' >>/sys/kernel/debug/dynamic_debug/control"

 

Customized printf

sample:


START----------------------- 

#defineprint_aksm(x,a...)   if(AKSM_Klog_enabled) printk(x,##a);

 

#if__AKSM_DEBUG__

staticchar AKSM_Klog_enabled=1;

#else

staticchar AKSM_Klog_enabled=0;

#endif

 

staticssize_t AKSM_Klog_enable_store(struct kobject *kobj,

                           struct kobj_attribute *attr,

                           const char *buf, size_t count)

{

      int err;

      unsigned long enableklog;

 

      err = strict_strtoul(buf, 10,&enableklog);

      if (err || enableklog > UINT_MAX)

            return -EINVAL;

 

      AKSM_Klog_enabled = enableklog;

 

      return count;

}

staticssize_t AKSM_Klog_enable_show(struct kobject *kobj,

                         struct kobj_attribute *attr, char *buf)

{

 

            return sprintf(buf,"AKSM_Klog_enabled : %d\n", AKSM_Klog_enabled);

}

END-----------------------

Call Trace

内核态calltrace

内核态有三种出错情况,分别是bug, oops和panic。

bug属于轻微错误,比如在spin_lock期间调用了sleep,导致潜在的死锁问题,等等。

oops代表某一用户进程出现错误,需要杀死用户进程。这时如果用户进程占用了某些信号锁,所以这些信号锁将永远不会得到释放,这会导致系统潜在的不稳定性。

panic是严重错误,代表整个系统崩溃。

 

用户态calltrace

1. 程序崩溃时,都会收到一个信号。Linux系统接收到某些信号时会自动打印call trace。

2. 在用户程序中添加检查点,类似于assert机制,如果检查点的条件不满足,就执行call trace。

OOPS实例分析

(1)

Code: e59f0010 eb412fb6 e3a0200b e3a03000 (e5832000)

Code标号开始的字段记录了模块出错前最后几条机器码,其中被括号括起来的就是oops出错对应的机器码。然后从dump的汇编代码中搜索机器码

(2)

PC is at func_D+0x1c/0x28 [oops]

PC是位于func_D函数标号之后的0x1c处

arm-linux-objdump -D -S oops.ko >log,(或者只加入-D参数,仅仅获得汇编代码;如果-D和-S都用的话,可能出现C代码混乱问题,,-S参数需要结合 arm-linux-gcc编译参数-g)

将模块文件反汇编到log中,使用vim打开该文件log,直接找到func_D标号处

(1)oops出错时,首先搜集到所有oops打印信息,如果模块中本身有很多printk打印语句,首先根据oops开头的打印信息分析出错点的大概位置。

(2)通过Backtrace字段,分析发生oops错误前模块程序的执行路径,将范围缩小到某个函数中。

(3)如果通过前面两步仍无法定位出错点,那么就直接通过PC来定位。查看出错时

oops信息中打印出的PC的值并记录下来。在内核Makefile中加入-g选项,重新编译模块。

(4)通过objdump反汇编该模块。在反汇编得出的汇编混合C语言调试信息的代码中,结合前3步的分析结论,精确定位出错点的位置。

(3) instruction exception

  <0>[  361.028033] C2  3201 (     MsockLoop) Internal error: Oops - bad mode: 0 [#1] PREEMPT SMP

<4>[ 361.028057] C2  3201 (      MsockLoop) Modules linked in: tzddgalcore [last unloaded: msocketk]

<4>[ 361.028073] C2  3201 (      MsockLoop) CPU: 2 PID: 3201 Comm:MsockLoop Tainted: G        W    3.14.0-20150715.111130-eng #81

<4>[ 361.028088] C2  3201 (      MsockLoop) task: ffffffc01032a340 ti: ffffffc0122cc000task.ti: ffffffc0122cc000

<4>[ 361.028102] C2  3201 (      MsockLoop) PC is at 0xffffffbffc001934

<4>[ 361.028113] C2  3201 (      MsockLoop) LR is at 0xffffffbffc001934

  。。。。

  <4>[  361.031181] C2  3201 (     MsockLoop) Call trace:

<4>[ 361.031195] C2  3201 (      MsockLoop) [<ffffffbffc001934>]0xffffffbffc001934

<4>[ 361.031208] C2  3201 (      MsockLoop) [<ffffffbffc004200>]0xffffffbffc004200

<4>[ 361.031237] C2  3201 (      MsockLoop) [<ffffffc00012d904>]vfs_read+0x8c/0x19c

<4>[ 361.031254] C2  3201 (      MsockLoop) [<ffffffc00012e288>]SyS_read+0x40/0xa0

<0>[ 361.031274] C2  3201 (      MsockLoop) Code: bad PC value

 

  这个是指令异常, 取指令的时候,地址非法

  也就是说,ldr的指令(就是机器码)并非是有效的

  一种情况是,代码段被破坏,比如module 已经remove,但是kernel别的地方掉了回调指针;

还有一种情况是栈内溢出,踩了堆栈帧

  或者野指针跑飞了

 

如何把当前上下文的进程名称打印出来:

  Bad mode inSynchronous Abort handler detected

  搜一下这句话是那个函数打印出来的

  在那个函数里面,打印一下current ->comm, dump_stack一把

 

Panic 分析实例

 

以下摘自网络

Beginning-----------------------------------

the below is a example of kernel panic log.

 

[  875.497504] Unableto handle kernel paging request at virtual address 4042a00c

[  875.499110] pgd =c0004000

[  875.501797][4042a00c] *pgd=00000000

[  875.505364]Internal error: Oops: 5 [#1] PREEMPT

[  875.509957] Moduleslinked in: dhd

[  875.513350] CPU:0    Not tainted  (2.6.29 #21)

[  875.517877] PC isat lock_acquire+0x60/0x74

[  875.522024] LR isat 0x0

[  875.524544] pc :[<c0090e10>]    lr :[<00000000>]    psr: 60000093

[  875.524557] sp :c042bea0  ip : c042a000  fp : c042becc

[  875.536004] r10:0000e0cd  r9 : 00000000  r8 : 16027ae8

[  875.541210] r7 :0000036b  r6 : 00000000  r5 : 4042a000 r4 : 60000093

[  875.547717] r3 :00000000  r2 : 00000000  r1 : 00000000 r0 : 00000000

[  875.554230] Flags:nZCv  IRQs off  FIQs on Mode SVC_32  ISA ARM  Segment kernel

[  875.561610]Control: 10c5787d  Table: 1c0ec019  DAC: 00000017

[  875.567337] Processswapper (pid: 0, stack limit = 0xc042a2e0)

[  875.573157] Stack:(0xc042bea0 to 0xc042c000)

[  875.577490] bea0:00000002 00000080 00000000 c00735e4 c0036c9c c04d4b40 c00735e4 1d34ce80

[  875.585737] bec0:c042bef4 c042bed0 c02fcef8 c0090dbc 00000002 00000000 c00735e4 c04d6010

[  875.593984] bee0:0000e0cd c04d4b40 c042bf3c c042bef8 c00735e4 c02fcebc c0082d34 c006d870

[  875.602230] bf00:c042bf60 00000001 c002e518 c045e1a8 c042bf3c 0000e0cd c04d49a0 1d34ce80

[  875.610477] bf20:0000036b 16027ae8 00000000 0000001f c042bf94 c042bf40 c008b1f8 c00735cc

[  875.618724] bf40:00000000 c999a0a0 1d9e6627 0000036b 0000e0cd c00622a4 60000013 c042f318

[  875.626970] bf60:1d9e6627 0000036b 0000001f c002e518 c042a000 c002e518 c045e1a8 16027ae8

[  875.635217] bf80:510f00f2 0000001f c042bfb4 c042bf98 c002e418 c008b028 c0889a90 c045dd64

[  875.643464] bfa0:c0029ea4 c042ec08 c042bfc4 c042bfb8 c02f76a4 c002e3f0 c042bff4 c042bfc8

[  875.651710] bfc0:c0008bc0 c02f7644 c0008514 00000000 00000000 c0029ea4 00000000 10c5387d

[  875.659957] bfe0:c045e25c c002a2a8 00000000 c042bff8 16008034 c000894c 00000000 00000000

[  875.668204]Backtrace:

[  875.670637][<c0090db0>] (lock_acquire+0x0/0x74) from [<c02fcef8>](_spin_lock+0x48/0x58)

[  875.678797]  r6:1d34ce80 r5:c00735e4 r4:c04d4b40

[  875.683397][<c02fceb0>] (_spin_lock+0x0/0x58) from [<c00735e4>](get_next_timer_interrupt+0x24/0x224)

[  875.692684]  r5:c04d4b40 r4:0000e0cd

[  875.696244][<c00735c0>] (get_next_timer_interrupt+0x0/0x224) from [<c008b1f8>](tick_nohz_stop_sched_tick+0x1dc/0x434)

[  875.707004][<c008b01c>] (tick_nohz_stop_sched_tick+0x0/0x434) from[<c002e418>] (cpu_idle+0x34/0x6c)

[  875.716204][<c002e3e4>] (cpu_idle+0x0/0x6c) from [<c02f76a4>](rest_init+0x6c/0x80)

[  875.723937]  r7:c042ec08 r6:c0029ea4 r5:c045dd64r4:c0889a90

[  875.729577][<c02f7638>] (rest_init+0x0/0x80) from [<c0008bc0>](start_kernel+0x280/0x2e4)

[  875.737824][<c0008940>] (start_kernel+0x0/0x2e4) from [<16008034>](0x16008034)

[  875.745197] Code:e58dc008 e59bc00c e58dc00c ebfffdc6 (e595300c)

[  875.751446] Kernelpanic - not syncing: Fatal exception

 

1.

the below is the analysis result:

[  875.497504] Unableto handle kernel paging request at virtual address 4042a00c

the whole description of the panic.

 

2.

Modules linked in: dhd

it just means there is one module whose name is dhd.ko whilepanic happens.

not means the panic is in this module.

 

3.

Process swapper (pid: 0, stack limit = 0xc042a2e0)

pid of the panic process is 0.

 

4.

[  875.517877] PC isat lock_acquire+0x60/0x74

[  875.522024] LR isat 0x0

[  875.524544] pc :[<c0090e10>]    lr :[<00000000>]    psr: 60000093

[  875.524557] sp :c042bea0  ip : c042a000  fp : c042becc

[  875.536004] r10:0000e0cd  r9 : 00000000  r8 : 16027ae8

[  875.541210] r7 :0000036b  r6 : 00000000  r5 : 4042a000 r4 : 60000093

[  875.547717] r3 :00000000  r2 : 00000000  r1 : 00000000 r0 : 0000000

 

the log shows the value of ARM registers.

0x74 means the whole length of lock_acquire() function indisassemble format.

0x60 means the key point while panic happens.

gdb the output file which include lock_acquire() functionand then disassemble the function to make sure which line has issue.

for example.

arm-linux-gdb lockdep.o

disassemble lock_acquire

 

5.

[  875.573157] Stack:(0xc042bea0 to 0xc042c000)

[  875.577490] bea0:00000002 00000080 00000000 c00735e4 c0036c9c c04d4b40 c00735e4 1d34ce80

[  875.585737] bec0:c042bef4 c042bed0 c02fcef8 c0090dbc 00000002 00000000 c00735e4 c04d6010

[  875.593984] bee0:0000e0cd c04d4b40 c042bf3c c042bef8 c00735e4 c02fcebc c0082d34 c006d870

[  875.602230] bf00:c042bf60 00000001 c002e518 c045e1a8 c042bf3c 0000e0cd c04d49a0 1d34ce80

[  875.610477] bf20:0000036b 16027ae8 00000000 0000001f c042bf94 c042bf40 c008b1f8 c00735cc

[  875.618724] bf40:00000000 c999a0a0 1d9e6627 0000036b 0000e0cd c00622a4 60000013 c042f318

[  875.626970] bf60:1d9e6627 0000036b 0000001f c002e518 c042a000 c002e518 c045e1a8 16027ae8

[  875.635217] bf80:510f00f2 0000001f c042bfb4 c042bf98 c002e418 c008b028 c0889a90 c045dd64

[  875.643464] bfa0:c0029ea4 c042ec08 c042bfc4 c042bfb8 c02f76a4 c002e3f0 c042bff4 c042bfc8

[  875.651710] bfc0:c0008bc0 c02f7644 c0008514 00000000 00000000 c0029ea4 00000000 10c5387d

[  875.659957] bfe0:c045e25c c002a2a8 00000000 c042bff8 16008034 c000894c 00000000 00000000

it contains the context of the Stack from 0xc042bea0 to0xc042c000.

 

6.

[  875.668204]Backtrace:

[  875.670637][<c0090db0>] (lock_acquire+0x0/0x74) from [<c02fcef8>](_spin_lock+0x48/0x58)

[  875.678797]  r6:1d34ce80 r5:c00735e4 r4:c04d4b40

[  875.683397][<c02fceb0>] (_spin_lock+0x0/0x58) from [<c00735e4>](get_next_timer_interrupt+0x24/0x224)

[  875.692684]  r5:c04d4b40 r4:0000e0cd

[  875.696244][<c00735c0>] (get_next_timer_interrupt+0x0/0x224) from [<c008b1f8>](tick_nohz_stop_sched_tick+0x1dc/0x434)

[  875.707004][<c008b01c>] (tick_nohz_stop_sched_tick+0x0/0x434) from[<c002e418>] (cpu_idle+0x34/0x6c)

[  875.716204][<c002e3e4>] (cpu_idle+0x0/0x6c) from [<c02f76a4>](rest_init+0x6c/0x80)

[  875.723937]  r7:c042ec08 r6:c0029ea4 r5:c045dd64r4:c0889a90

[  875.729577][<c02f7638>] (rest_init+0x0/0x80) from [<c0008bc0>](start_kernel+0x280/0x2e4)

[  875.737824][<c0008940>] (start_kernel+0x0/0x2e4) from [<16008034>](0x16008034)

it means function call stack. from the above log, the callstack is:

start_kernel() -> rest_init() -> cpu_idle() ->tick_nohz_stop_sched_tick() -> get_next_timer_interrupt() -> _spin_lock()-> lock_acquire().

 

7.

[  875.745197] Code:e58dc008 e59bc00c e58dc00c ebfffdc6 (e595300c)

it means the latest instruction.

e58dc008     str    ip, [sp, #8]

e59bc00c     ldr    ip, [fp, #12]

e58dc00c     str    ip, [sp, #12]

ebfffdc6        ......

End-----------------------------------

 

 

profiling tool (性能分析工具)

 

Background

影响系统性能的因素

cpu多核上下线,cpu/gpu/ddr的频率,各类cache(cpu(L1/L2),磁盘等

硬件cache,硬件特性之流水线,硬件特性之分支预测,verbose system call, process switch

 

PMU

Performance monitor unit(PMU) ——很多处理器厂商在硬件中加入了PMU单元,PMU允许软件对某些硬件事件设置counter,此后处理器便开始统计该事件的发生次数,当发生的次数超过counter内设置的值后,便产生中断。比如cache miss达到某个值后,PMU便能产生相应的中断,捕获这些中断,便可以考察程序对这些硬件特性的利用效率了。例如,以 cache miss 事件触发采样便可以知道 cache miss 的分布,即cache 失效经常发生在哪些程序代码中。如此等等。

 

Tracepoints

Tracepoint 是散落在内核源代码中的一些hook,一旦使能,它们便可以在特定的代码被运行到时被触发,这一特性可以被各种trace/debug 工具所使用。Perf 就是该特性的用户之一。

假如您想知道在应用程序运行期间,内核内存管理模块的行为,便可以利用潜伏在slab 分配器中的 tracepoint。当内核运行到这些 tracepoint 时,便会通知perf。

Perf 将 tracepoint 产生的事件记录下来,生成报告,通过分析这些报告,调优人员便可以了解程序运行时期内核的种种细节,对性能症状作出更准确的诊断。

See more in Documentation/trace/tracepoints.txt和 samples/tracepoints

查看可供使用的tracepoints # cat/sys/kernel/debug/tracing/available_events

profiling tool概述

性能分析指的是,分析各个程序(进程)执行各个阶段(线程或者例程)消耗的系统资源(CPU,内存、I/O)和占用的时间,以便来找出性能瓶颈,进而优化程序,最终提高系统的整体运行性能。

常见的profiler有,ARM Streamline 性能分析器,Linux的GNU的profiling tools,like trace-cmd,Ftrace,oprofile,gprof

 

profiler(分析器)的基本原理

Ø  基于时间(time based)的采样(sampling)

主要通过周期性的时钟(tick)中断,来纪录相关的性能信息,如处理器指令指针、线程id、处理器id和事件计数器等。这种方法开销小,精确度高。在Linux系统中,比较常见的有Oprofile和Intel VTune性能分析器等。 

Ø  基于插桩的采样

即可以使用直接的二进制插桩,也可以通过编译器在应用中插入分析代码。这种方式与自己在应用中增加计时函数类似,同时带来的开销大,但提供了更多的功能,如调用树,调用次数和函数开销等。在Linux系统中,比较常见的有gprof和IntelVTune性能分析器等。

Ø  基于事件(event based)的采样

类似于钩子回调机制,在kernel中所有的回调接口,尤其是系统调用接口中放置采样点。like Oprofile。

 

 

 

gprof

gprof可以做哪些事情?

GNU gprof能够打印出程序运行中各个函数消耗的时间,可以帮助程序员找出众多函数中耗时最多的函数。产生程序运行时候的函数调用关系,包括调用次数,可以帮助程序员分析程序的运行流程。尤其是对于代码量巨大的工程而言,大大提高了理顺程序运行流程的工作效率,这点对于理解代码也有很重要的意义,尤其应用在阅读Opensource的情况。

 

gprof是GNU工具之一,它在编译的时候在每个函数的出入口加入了profiling的代码,运行时统计程序在用户态的执行信息,可以得到每个函数的调用次数、执行时间、调用关系等信息,简单易懂。适合于查找用户级程序的性能瓶颈,对于很多时间都在内核态执行的程序,gprof不适合。 

 

/***************************************

以下参考链接地址:

http://web.eecs.umich.edu/~sugih/pointers/gprof_quick.html

gprof Quick-Start Guide

gprof is a type of tool called a profiler. Profiling allowsyou to learn where your program spent its time and which functions called whichother functions while it was executing. This information can show you whichpieces of your program are slower than you expected and might be candidates forrewriting to make your program execute faster.

 

In this QuickStart guide, we will focus on finding thebottleneck (the part of the code that takes the longest to run) in a program.As an example, we will use the kruse program from Programming Assignment 1.

 

    Compiling forprofiling

    Before you canprofile your program, you must first recompile it specifically for profiling.To do so, add the -pg argument to the compiler's command line.

 

          unix% g++ -g-pg -o kruse kruse.cc

         

 

    This creates anexecutable called kruse from the source file kruse.cc with debugging andprofiling turned on.

 

    Another way to dothis is to add -pg to the CFLAGS line in the file called Makefile.

 

    Creating gmon.out

    Once your programhas been compiled with profiling turned on, running the program to completioncauses a file named gmon.out to be created in the current directory. gprofworks by analyzing data collected during the execution of your program afteryour program has finished running. gmon.out holds this data in a gprof-readableformat.

 

    Things to keep inmind:

        If gmon.outalready exists, it will be overwritten.

        The programmust exit normally. Pressing control-c or killing the process is not a normalexit.

        Since you aretrying to analyze your program in a real-world situation, you should run theprogram exactly the same way as you normally would (same inputs, command linearguments, etc.).

 

    Running gprof

    Run gprof likethis:

 

          unix% gprofprogram-name [ data-file ] [ > output-file ] 

         

 

    If you don'tspecify the name of a data file, gmon.out is assumed. Following the gprofcommand with "> output-file" causes the output of gprof to besaved to output-file so you can examine it later.

 

    For this example,the program name is kruse and we will save the output into a file calledkruse.output:

 

          unix% gprofkruse > kruse.output 

         

 

    Analyzing gprof'soutput

    After completingthe last step, the gprof's analysis has been saved into the kruse.output file.You can use your favorite text editor to examine this file. By default, twokinds of analysis are performed: the flat profile and the call graph. Bothtypes are explained in the following sections.

 

    Interpreting theflat profile

    The flat profileshows the total amount of time your program spent executing each function. Atthe end of the profile, you will see a legend describing what each of thecolumns of numbers means. Here is some of the output from the flat profile:

 

          Flat profile:

 

          Each samplecounts as 0.01 seconds.

            %   cumulative  self              self     total

           time   seconds  seconds    calls  us/call us/call  name

           37.50      0.15    0.15    48000     3.12    3.12  Life::neighbor_count(int,int)

           17.50      0.22    0.07                            _IO_do_write

           10.00      0.26    0.04                            __overflow

            7.50      0.29    0.03                            _IO_file_overflow

            7.50      0.32    0.03                            _IO_putc

            5.00      0.34    0.02       12  1666.67 14166.67  Life::update(void)

            5.00      0.36    0.02                            stdiobuf::overflow(int)

            5.00      0.38    0.02                            stdiobuf::sys_write(char const *, int)

            2.50      0.39    0.01                            ostream::operator<<(char)

            2.50      0.40    0.01                             internal_mcount

            0.00      0.40    0.00       12     0.00    0.00  Life::print(void)

            0.00      0.40    0.00       12     0.00    0.00  to_continue(void)

            0.00      0.40    0.00        1     0.00    0.00  Life::initialize(void)

            0.00      0.40    0.00        1     0.00    0.00  instructions(void)

            0.00      0.40    0.00        1     0.00 170000.00  main

         

    Note that thefunctions mcount and profil (profil does not appear in this listing) are partof the profiling aparatus; their time gives a measure of the amount of overheaddue to profiling. Also note that functions like stdiobuf::sys_write and_IO_do_write are part of the system libraries and not directly part of yourcode.

 

    In this output, wecan see that 37.5% of kruse's execution time is spent in Life::neighbor_count.This is the highest percentage for any function in the program. It is alsoworthwhile to note that it gets called 48,000 times. This is our first hintthat Life::neighbor_count might be the biggest bottleneck in kruse.

 

    Interpreting thecall graph

    The call graphshows how much time was spent in each function and its children. From thisinformation, you can find functions that, while they themselves may not haveused much time, called other functions that did use unusual amounts of time.Like for the flat profile, a legend appears after the call graph describingwhat each of the columns of numbers means.

 

    Here is some ofthe output from the call graph:

 

                                 Call graph(explanation follows)

 

 

           granularity: each sample hit covers 4 byte(s) for 2.50% of 0.40 seconds

 

            index %time    self  children   called     name

                           0.02    0.15      12/12          main [2]

            [1]     42.5   0.02    0.15      12        Life::update(void) [1]

                           0.15    0.00   48000/48000       Life::neighbor_count(int, int) [4]

           -----------------------

 

****************************************/

perf

reference : Perf -- Linux下的系统性能调优工具

http://www.ibm.com/developerworks/cn/linux/l-cn-perf1/

http://www.ibm.com/developerworks/cn/linux/l-cn-perf2/

 

perf类似于git那样,有一堆子命令,比较常用的有record,report,annotate,stat等.

perf event 是一款随Linux 内核代码一同发布和维护的性能诊断工具,由内核社区维护和发展。perf 不仅可以用于应用程序的性能统计分析,也可以应用于内核代码的性能统计和分析。

 

perf的简单命令使用如下:

(1)perf list

使用 perf list 命令可以列出所有能够触发 perf 采样点的事件;

Hardware Event 是由 PMU 硬件产生的事件,比如 cache 命中,当您需要了解程序对硬件特性的使用情况时,便需要对这些事件进行采样;

Software Event 是内核软件产生的事件,比如进程切换,tick数等 ;

Tracepoint event 是内核中的静态 tracepoint 所触发的事件,这些tracepoint 用来判断程序运行期间内核的行为细节,比如 slab 分配器的分配次数等。

(2)perf stat

$gcc – o t1 – g test.c

$perf stat ./t1

$perf stat ./t1

 Performance counterstats for './t1':

 262.738415task-clock-msecs # 0.991 CPUs

 2 context-switches #0.000 M/sec

 1 CPU-migrations # 0.000M/sec

 81 page-faults #0.000 M/sec

 9478851 cycles #36.077 M/sec (scaled from 98.24%)

 6771 instructions #0.001 IPC (scaled from 98.99%)

 111114049 branches #422.908 M/sec (scaled from 99.37%)

 8495 branch-misses #0.008 % (scaled from 95.91%)

 12152161cache-references # 46.252 M/sec (scaled from 96.16%)

 7245338 cache-misses# 27.576 M/sec (scaled from 95.49%)

  0.265238069 secondstime elapsed

上面告诉我们,程序 t1 是一个 CPU bound 型,因为task-clock-msecs 接近 1。

 

perf stat 还给出了其他几个最常用的统计信息:

Task-clock-msecs:CPU 利用率,该值高,说明程序的多数时间花费在 CPU 计算上而非IO。

Context-switches:进程切换次数,记录了程序运行过程中发生了多少次进程切换,频繁的进程切换是应该避免的。

Cache-misses:程序运行过程中总体的cache 利用情况,如果该值过高,说明程序的 cache 利用不好

CPU-migrations:表示进程 t1 运行过程中发生了多少次 CPU 迁移,即被调度器从一个CPU 转移到另外一个 CPU 上运行。

Cycles:处理器时钟,一条机器指令可能需要多个 cycles,

Instructions: 机器指令数目。

IPC:是 Instructions/Cycles 的比值,该值越大越好,说明程序充分利用了处理器的特性。

Cache-references: cache 命中的次数

Cache-misses: cache 失效的次数。

通过指定 -e 选项,您可以改变 perf stat 的缺省事件 ( 关于事件,在上一小节已经说明,可以通过 perf list 来查看 )。假如您已经有很多的调优经验,可能会使用 -e 选项来查看您所感兴趣的特殊的事件。

 

(3)perf top

Perf top 用于实时显示当前系统的性能统计信息。该命令主要用来观察整个系统当前的状态,比如可以通过查看该命令的输出来查看当前系统最耗时的内核函数或某个用户进程。

下面是 perf top 的可能输出:

 

 PerfTop: 705 irqs/seckernel:60.4% [1000Hz cycles]

 --------------------------------------------------

 sampl pcnt functionDSO

 1503.00 49.2% t2

 72.00 2.2%pthread_mutex_lock /lib/libpthread-2.12.so

 68.00 2.1% delay_tsc[kernel.kallsyms]

 55.00 1.7%aes_dec_blk [aes_i586]

 55.00 1.7%drm_clflush_pages [drm]

 52.00 1.6%system_call [kernel.kallsyms]

 49.00 1.5% __memcpy_ssse3/lib/libc-2.12.so

 48.00 1.4%__strstr_ia32 /lib/libc-2.12.so

 46.00 1.4% unix_poll[kernel.kallsyms]

 42.00 1.3%__ieee754_pow /lib/libm-2.12.so

 41.00 1.2% do_select[kernel.kallsyms]

 40.00 1.2%pixman_rasterize_edges libpixman-1.so.0.18.0

 37.00 1.1%_raw_spin_lock_irqsave [kernel.kallsyms]

 36.00 1.1%_int_malloc /lib/libc-2.12.so

 ^C

 

(4) perf record

这便需要使用 perf record 记录单个函数级别的统计信息,并使用 perf report 来显示统计结果。

perf record – e cpu-clock ./t1

perf report

 

使用 perf 的 -g 选项便可以得到需要的信息:

 

 perf record – ecpu-clock – g ./t1

 perf report

 

(5) 指定tracepoint

用 ls 命令来演示 sys_enter 这个tracepoint 的使用

[root@ovispoly /]# perf stat -e raw_syscalls:sys_enter ls

 bin dbg etc  lib media opt root  selinux sys usr

 boot dev homelost+found mnt proc sbin srv  tmp var

 

  Performance counterstats for 'ls':

 

 101raw_syscalls:sys_enter

 

  0.003434730 secondstime elapsed

 

 

 [root@ovispoly /]#perf record -e raw_syscalls:sys_enter ls

 

 [root@ovispoly /]#perf report

 Failed to open.lib/ld-2.12.so, continuing without symbols

 # Samples: 70

 #

 # Overhead CommandShared Object Symbol

 # ....................... ............... ......

 #

 97.14% ls ld-2.12.so[.] 0x0000000001629d

 2.86% ls [vdso] [.]0x00000000421424

 #

 # (For a higher leveloverview, try: perf report --sort comm,dso)

 #这个报告详细说明了在 ls 运行期间发生了多少次系统调用( 上例中有 101 次 ),多数系统调用都发生在哪些地方 (97% 都发生在 ld-2.12.so 中 )。

(6)perf probe

动态加入观察点

[root@ovispoly perftest]# perf probe schedule:12 cpu

 Added new event:

 probe:schedule (onschedule+52 with cpu)

 

 You can now use it onall perf tools, such as:

 

   perf record -eprobe:schedule -a sleep 1

 

 [root@ovispolyperftest]# perf record -e probe:schedule -a sleep 1

 Error, output fileperf.data exists, use -A to append or -f to overwrite.

 

 [root@ovispolyperftest]# perf record -f -e probe:schedule -a sleep 1

 [ perf record: Wokenup 1 times to write data ]

 [ perf record:Captured and wrote 0.270 MB perf.data (~11811 samples) ]

 [root@ovispolyperftest]# perf report

 # Samples: 40

 #

 # Overhead CommandShared Object Symbol

 # ....................... ................. ......

 #

 57.50% init 0 [k]0000000000000000

 30.00% firefox [vdso][.] 0x0000000029c424

 5.00% sleep [vdso][.] 0x00000000ca7424

 5.00% perf.2.6.33.3-8[vdso] [.] 0x00000000ca7424

 2.50% ksoftirqd/0[kernel] [k] 0000000000000000

 #

 # (For a higher leveloverview, try: perf report --sort comm,dso)

 #上例利用 probe 命令在内核函数 schedule() 的第 12 行处加入了一个动态 probe 点,和 tracepoint 的功能一样,内核一旦运行到该probe 点时,便会通知 perf。可以理解为动态增加了一个新的 tracepoint。此后便可以用record 命令的 -e 选项选择该 probe 点,最后用 perf report 查看报表。

(7) perf lock

统计锁的使用情况

(8) perf timechart

likely bootchart

(9) See more in original webpage

OProfile

reference: http://oprofile.sourceforge.net/doc/index.html

 

OProfile利用硬件支持来profile系统或者application. 与gprof不同,OProfile不会在binary中添加指令。

 

oprofile也是一个开源的profiling工具,它使用硬件调试寄存器来统计信息,进行 profiling的开销比较小,而且可以对内核进行profiling。它统计的信息非常的多,可以得到cache

的缺失率,memory的访存信息,分支预测错误率等等,这些信息gprof是得不到的,但是对于函数调用次数,它是不能够得到的。

简单来说,gprof简单,适合于查找用户级程序的瓶颈,而oprofile稍显复杂,但是得到的信息更多,更适合调试系统软件。

 

The following attachment tell us detailed implementation ofOprofile in kernel side.


strace

strace - trace system calls and signals

strace不仅可以调试一个新开始的程序,也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上 面)。

For example,

strace -o output.txt -T -tt -e trace=all -p28979

上面的含义是 跟踪28979进程的所有系统调用(-e trace=all),并统计系统调用的花费时间,以及开始时间(并以可视化的时分秒格式显示),最后将记录结果存在output.txt文件里面。

 

用strace调试程序,实例:

strace -f -F -o ~/dcop-strace.txt dcopserver

......

27207 bind(3, {sin_family=AF_UNIX,path="/tmp/.ICE-unix/dcop27207-1066844596"}, 38) = -1 EACCES(Permission denied)

27207 write(2, "_KDE_IceTrans",13) = 13

可见调用bind系统调用时权限问题

 

限制strace只跟踪特定的系统调用

如果你已经知道你要找什么,你可以让strace只跟踪一些类型的系统调用。例如,你需要看看在configure脚本里面执行的程序,你需要监视的系统调 用就是execve。让strace只记录execve的调用用这个命令:

strace -f -o configure-strace.txt -e execve./configure

ftrace

利用tracepoint来monistor system的一个工具

For example,

echo function > current_tracer

echo cpu_maps_update_begin  cpu_maps_update_done > set_ftrace_filter

echo 1 > tracing_on

touch for a while

echo 0 > tracing_on crash debug

Disk I/O debug

cat /sys/block/mmcblk0/stat

details in kernel/Documentation/block/stat.txt

 

cat /proc/$pid/io switch on "CONFIG_TASK_IO_ACCOUNTING"

details in Documentation/filesystems/proc.txt

MM debug

Android tools

/sytem/bin/procrank

/system/bin/dumpsys meminfo

/system/bin/dumpsys meminfo $pid

(Tips: dumpsys meminfo -h to view more instructions)

 

adb shell getprop | grep dalvik.vm.heapgrowthlimit    //OOM阈值

 

Linux tools

pmap //check virtual memory for specific process

cat /proc/meminfo

free -m

cat /proc/$(PID)/maps //virtual address map list, include heap and stack(或许是已经用的/map的,而非全部)

top

uptime

vmstat 1           //参看虚拟内存的命令, like vmstat 5 10

 

ulimit

ulimit命令:

 

ulimit -a :显示系统各种状态

 

其中core filesize表示程序dump的文件大小,即内核出错函数

 

ulimit -c 1024:设置1024个block给dump文件用

 

然后执行程序,程序出错后,会产生core文件

 

执行者gdb./exception core,然后进入gdb,

 

使用where命令,可以看到程序调用stack,然后定位程序

gdb

常用命令:file(打开源代码)quitrun(运行程序)print(打印变量值) list(查看源程序) break(设置断点)watch(观察变量值) help …..

 

另外,对应的内核kdb,只能以汇编代码为单元的调试,也可以单步和断点

DDD调试

 

GNU DDD是命令行调试程序,如GDB、DBX、WDB、Ladebug、JDB、XDB、PerlDebugger或Python Debugger的可视化图形前端。

0 0