[kgtp] r1679 committed - Test Localizing Wiki Content

  • From: kgtp@xxxxxxxxxxxxxx
  • To: kgtp@xxxxxxxxxxxxx
  • Date: Thu, 29 Aug 2013 00:29:47 +0000

Revision: 1679
Author:   teawater
Date:     Thu Aug 29 00:29:29 2013 UTC
Log:      Test Localizing Wiki Content

http://code.google.com/p/kgtp/source/detail?r=1679

Added:
 /wiki/zh-Hans
 /wiki/zh-Hans/HOWTOCN.wiki

=======================================
--- /dev/null
+++ /wiki/zh-Hans/HOWTOCN.wiki  Thu Aug 29 00:29:29 2013 UTC
@@ -0,0 +1,2124 @@
+#labels Phase-QA,Phase-Deploy
+Update in 2013-08-28
+<wiki:toc max_depth="5" />
+= 关于本文 =
+[https://code.google.com/p/kgtp/wiki/HOWTOCN] 是HTML格式的本文最后版本。 <br> +[https://raw.github.com/teawater/kgtp/master/kgtpcn.pdf] 是PDF格式的本文最 后版本。<br> +[https://raw.github.com/teawater/kgtp/release/kgtpcn.pdf] 是PDF格式的本文最 后发布版本。<br>
+= 什么是KGTP =
+*KGTP* 是一个 灵活,轻量级,实时 *Linux* (包括 *Android*) *调试器* 和 *跟 踪器* 。<br> +使用KGTP *不需要* 在Linux内核上打PATCH或者重新编译,只要编译KGTP模块并 insmod就可以。<br>
+<br>
+其让Linux内核提供一个远程GDB调试接口,于是在本地或者远程的主机上的GDB可以在 不需要停止内核的情况下用GDB tracepoint和其他一些功能 *调试* 和 *跟踪* Linux内核和应用程序。<br> +即使板子上没有GDB而且其没有可用的远程接口,KGTP也可以用离线调试的功能调试内 核(见 [http://code.google.com/p/kgtp/wiki/HOWTOCN#/sys/kernel/debug/gtpframe和离线 调试])。<br><br>
+
+KGTP支持 *X86-32* , *X86-64* , *MIPS* 和 *ARM* 。<br>
+KGTP在Linux内核 *2.6.18到upstream* 上都被测试过。<br><br>
+
+*KGTP新用户可以去看一下 [Quickstart] 。*
+
+* 请到 [UPDATE] 去看KGTP的更新信息。*
+
+= 需要帮助或者汇报问题 =
+你可以把问题发到 [http://code.google.com/p/kgtp/issues/list] 或者写信到 kgtp@xxxxxxxxxxxxx 或者写信到 teawater@xxxxxxxxx 。<br>
+KGTP小组将尽全力帮助你。
+
+= GDB调试普通程序和KGTP的区别表 =
+这个表是给在使用过GDB调试程序的人准备的,他可以帮助你理解和记住KGTP的功能。
+|| *功能* || *GDB调试普通程序* || *GDB控制KGTP调试Linux内核* ||
+|| 准备工作 || 系统里安装了GDB。<br>程序用 "-g"选项编译。 || 因为使用了一些 GDB中的新功能,所以KGTP需要和GDB 7.6或者更新的版本。如果你的系统不提供这么新 版本的GDB,你可以到[http://code.google.com/p/gdbt/]取得新版本GDB。同时你可以 在这里取得一步一步编译新版本GDB的介绍。<br>你还需要做一些Linux内核和KGTP的准 备工作,请到 [http://code.google.com/p/kgtp/wiki/HOWTOCN#使用KGTP前的准备工 作] 取得如果做的介绍。 || +|| Attach || 使用命令"gdb -p pid"或者GDB命令"attach pid"可以attach系统中的 某个程序. || 需要先insmod gtp.ko,请看 [https://code.google.com/p/kgtp/wiki/HOWTOCN#如何让GDB连接KGTP]。<br>然后让 GDB连接KGTP,请看[https://code.google.com/p/kgtp/wiki/HOWTOCN#让GDB连接到 KGTP]。<br>请 *注意* GDB连接到KGTP以后,Linux内核不会停止。|| +|| Breakpoints || GDB命令"b place_will_stop",让程序在执行这个命令后执 行,则程序将停止在设置这个断点的地方。|| KGTP不支持断点但是支持tracepoint。 Tracepoints可以被看作一种特殊的断点。其可以设置在Linux kernel中的一些地方然 后定义一些命令到它的action中。当tracepoint开始的时候,他们将会在内核执行到这 些地方的时候执行这些命令。当tracepoint停止的时候,你可以像断点停止程序后你做 的那样用GDB命令分析tracepoint得到的数据。 *区别* 是断点会停止程序但是KGTP中 的tracepoint不会。 请到 [https://code.google.com/p/kgtp/wiki/HOWTOCN#GDB_tracepoint] 看如何使用它。 || +|| 读Memory || GDB停止程序后(也许不需要),它可以用GDB命令"print"或者"x"等应 用程序的内存。 || 你可以在tracepoint中设置特殊的action收集内存到 traceframe中,在tracepoint停止后取得他们的值。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#collect_expr1,_expr2,_...] [http://code.google.com/p/kgtp/wiki/HOWTOCN#用tfind选择trace帧缓存里面的条目 ] <br>或者你可以在内核或者应用程序执行的时候直接读他们的内存。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#在普通模式直接访问当前值] || +|| Step 和 continue || GDB可以用命令"continue"继续程序的执行,用CTRL-C停止 其。|| KGTP不会停止Linux内核,但是tracepoint可以开始和停止。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#启动和停止_tracepoint] <br> 或 者用 while-stepping tracepoint记录一定次数的single-stepping然后让KGTP切换到 回放模式。这样其就支持执行和方向执行命令了。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#使用while-stepping让Linux内核做 单步] || +|| Backtrace || GDB可以用命令"backtrace"打印全部调用栈。|| KGTP也可以。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#如何_backtrace_(stack_dump)]|| +|| Watchpoint || GDB可以用watchpoint让程序在某些内存访问发生的时候停止。|| KGTP可以用watch tracepoint记录内存访问。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#如何用watch_tracepoint控制硬件 断点记录内存访问] || +|| 调用函数 || GDB可以用命令"call function(xx,xx)"调用程序中的函数。 || KGTP可以用插件调用内核中的函数。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#如何增加用C写的插件] ||
+
+= 使用KGTP前的准备工作 =
+
+== Linux内核 ==
+=== 如果你的系统内核是自己编译的 ===
+要使用KGTP,你需要打开下面这些内核选项:
+{{{
+General setup  --->
+       [*] Kprobes
+
+[*] Enable loadable module support  --->
+
+Kernel hacking  --->
+       [*] Debug Filesystem
+       [*] Compile the kernel with debug info
+}}}
+如果你改了Linux内核config的任何项目,请重新编译你的内核。
+
+=== 如果是Android内核 ===
+默认的Android Linux内核config应该不支持KGTP。要使用KGTP,你需要打开下面这些 内核选项:
+{{{
+[*] Enable loadable module support  --->
+General setup  --->
+       [*] Prompt for development and/or incomplete code/drivers
+       [*] Kprobes
+Kernel hacking  --->
+       [*] Debug Filesystem
+       [*] Compile the kernel with debug info
+}}}
+如果你改了Linux内核config的任何项目,请重新编译你的内核。
+
+=== 如果你的系统内核是发行版自带的 ===
+你需要安装一些Linux内核软件包。
+
+==== Ubuntu ====
+===== 安装Linux内核调试镜像的标准方法 =====
+*1)* 增加调试源到Ubuntu源列表。
+ * 在命令行按照下面的命令创建文件 /etc/apt/sources.list.d/ddebs.list:
+{{{
+echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse" | \
+sudo tee -a /etc/apt/sources.list.d/ddebs.list
+}}}
+
+ * 稳定版本(不能是alpha或者betas)需要用命令行增加下面几行:
+{{{
+echo "deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse +deb http://ddebs.ubuntu.com $(lsb_release -cs)-security main restricted universe multiverse +deb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | \
+sudo tee -a /etc/apt/sources.list.d/ddebs.list
+}}}
+
+ * 导入调试符号签名key:
+{{{
+sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 428D7C01
+}}}
+
+ * 运行:
+{{{
+sudo apt-get update
+}}}
+<br>
+*2)* 安装Linux内核调试镜像
+{{{
+sudo apt-get install linux-image-$(uname -r)-dbgsym
+}}}
+于是你可以在"/usr/lib/debug/boot/vmlinux-$(uname -r)"找到内核调试镜像。<br>
+请 *注意* 当内核更新的时候这一步 *安装Linux内核调试镜像* 需要再做一次。
+
+===== 安装Linux内核调试镜像的第二方法 =====
+如果用标准方法出现问题,请用下面这些命令安装Linux内核调试镜像。
+{{{
+wget http://ddebs.ubuntu.com/pool/main/l/linux/linux-image-$(uname -r)-dbgsym_$(dpkg -s linux-image-$(uname -r) | grep ^Version: | sed 's/Version: //')_$(uname -i | sed 's/x86_64/amd64/').ddeb +sudo dpkg -i linux-image-$(uname -r)-dbgsym_$(dpkg -s linux-image-$(uname -r) | grep ^Version: | sed 's/Version: //')_$(uname -i | sed 's/x86_64/amd64/').ddeb
+}}}
+请 *注意* 当内核更新的时候这个方法需要重新做一次。
+
+===== 安装内核头文件包 =====
+{{{
+sudo apt-get install linux-headers-generic
+}}}
+
+===== 安装内核源码 =====
+====== 新方法 ======
+安装需要的软件包:
+{{{
+sudo apt-get install dpkg-dev
+}}}
+<br>
+
+取得源码:
+{{{
+apt-get source linux-image-$(uname -r)
+}}}
+则在当前目录找到内核源码目录。
+<br>
+
+移动这个目录到"/build/buildd/"中。
+====== 老方法 ======
+ * 安装源码包:
+{{{
+sudo apt-get install linux-source
+}}}
+ * 解压缩源码:
+{{{
+sudo mkdir -p /build/buildd/
+sudo tar vxjf /usr/src/linux-source-$(uname -r | sed 's/-.*//').tar.bz2 -C /build/buildd/
+sudo rm -rf /build/buildd/linux-$(uname -r | sed 's/-.*//')
+sudo mv /build/buildd/linux-source-$(uname -r | sed 's/-.*//') /build/buildd/linux-$(uname -r | sed 's/-.*//')
+}}}
+请 *注意* 当内核更新的时候这一步 *安装内核源码* 需要再做一次。
+
+==== Fedora ====
+===== 安装Linux内核调试镜像 =====
+使用下面的命令:
+{{{
+sudo debuginfo-install kernel
+}}}
+或者:
+{{{
+sudo yum --enablerepo=fedora-debuginfo install kernel-debuginfo
+}}}
+于是你可以在"/usr/lib/debug/lib/modules/$(uname -r)/vmlinux"找到内核调试镜 像。
+
+===== 安装Linux内核开发包 =====
+{{{
+sudo yum install kernel-devel-$(uname -r)
+}}}
+请 *注意* 在升级过内核包之后,你可能需要重新调用这个命令。
+
+==== 其他系统 ====
+需要安装Linux内核调试镜像和Linux内核源码包。
+
+=== 确定Linux内核调试镜像是正确的 ===
+因为GDB从Linux内核调试镜像里取得地址信息和调试信息,所以使用正确的Linux内核 调试镜像是非常重要的。所以在使用KGTP前,请先做检查。<br>
+有2个方法进行检查,我建议2个方法都做一次来确保Linux内核调试镜像是正确的。
+<br>
+<br>
+请 *注意* 如果你确定使用了正确的Linux内核调试镜像但是不能通过这个两个方法。 请看 [http://code.google.com/p/kgtp/wiki/HOWTOCN#处理Linux内核调试镜像地址信 息和Linux内核执行时] 。
+
+==== 当前Linux内核调试镜像在哪 ====
+在UBUNTU中,你可以在"/usr/lib/debug/boot/vmlinux-$(uname -r)"找到它。<br>
+在Fedora中,你可以在"/usr/lib/debug/lib/modules/$(uname -r)/vmlinux"找到 它。<br>
+如果你自己编译的内核,你可以在内核编译目录找到vmlinux文件。
+
+==== 使用/proc/kallsyms ====
+在运行着要trace的内核的系统上,用下面的命令取得sys_read和sys_write的地址:
+{{{
+sudo cat /proc/kallsyms | grep sys_read
+ffffffff8117a520 T sys_read
+sudo cat /proc/kallsyms | grep sys_write
+ffffffff8117a5b0 T sys_write
+}}}
+于是我们就可以得到sys_read的地址是0xffffffff8117a520,sys_write的地址是 0xffffffff8117a5b0。<br>
+之后我们用GDB从Linux内核调试镜像中取得sys_read和sys_write的地址:
+{{{
+gdb ./vmlinux
+(gdb) p sys_read
+$1 = {long int (unsigned int, char *, size_t)} 0xffffffff8117a520 <sys_read>
+(gdb) p sys_write
+$2 = {long int (unsigned int, const char *, size_t)} 0xffffffff8117a5b0 <sys_write>
+}}}
+sys_read和sys_write的地址一样,所以Linux内核调试镜像是正确的。
+
+==== 使用linux_banner ====
+{{{
+sudo gdb ./vmlinux
+(gdb) p linux_banner
+$1 = "Linux version 3.4.0-rc4+ (teawater@teawater-Precision-M4600) (gcc version 4.6.3 (GCC) ) #3 SMP Tue Apr 24 13:29:05 CST 2012\n"
+}}}
+linux_banner是Linux内核调试镜像里的内核信息。<br>
+之后,根据 [http://code.google.com/p/kgtp/wiki/HOWTOCN#让GDB连接到KGTP] 里 的方法连接到KGTP上并再次打印linux_banner。
+{{{
+(gdb) target remote /sys/kernel/debug/gtp
+Remote debugging using /sys/kernel/debug/gtp
+0x0000000000000000 in irq_stack_union ()
+(gdb) p linux_banner
+$2 = "Linux version 3.4.0-rc4+ (teawater@teawater-Precision-M4600) (gcc version 4.6.3 (GCC) ) #3 SMP Tue Apr 24 13:29:05 CST 2012\n"
+}}}
+这个linux_banner是KGTP正在trace的内核的内核信息,如果相同,则Linux内核调试 镜像是正确的。
+
+=== 处理Linux内核调试镜像地址信息和Linux内核执行时不同的问题 ===
+在X86_32上,用 [http://code.google.com/p/kgtp/wiki/HOWTOCN#确定Linux内核调 试镜像是正确的] 介绍的方法发现Linux内核调试镜像地址信息和Linux内核执行时不 同,而且确定使用的Linux内核调试镜像是正确的。<br>
+这个问题是因为:
+{{{
+Processor type and features  --->
+       (0x1000000) Physical address where the kernel is loaded
+       (0x100000) Alignment value to which kernel should be aligned
+}}}
+这个两个参数的值不同。请 *注意* "Physical address where the kernel is loaded" 有时不会在配置的时候显示,你可以通过搜索 "PHYSICAL_START" 取得它的 值。<br>
+<br>
+你可以通过修改 "Alignment value to which kernel should be aligned" 的值 和 "Physical address where the kernel is loaded" 来处理这个问题。<br>
+这个问题不影响X86_64。
+
+== 取得KGTP ==
+=== 通过http下载KGTP ===
+请到 [https://github.com/teawater/kgtp] 或者 [UPDATE] 去下载源码包。<br>
+或者你可以访问镜像:
+[https://code.csdn.net/teawater/kgtp/tree/master]<br>
+[https://git.oschina.net/teawater/kgtp]<br>
+[https://www.gitshell.com/teawater/kgtp/]<br>
+
+=== 通过git下载KGTP ===
+下面的命令将让你取得KGTP的最新版本:
+{{{
+git clone https://github.com/teawater/kgtp.git
+}}}
+<br>
+下面的命令将让你取得KGTP最后的发布版本:
+{{{
+https://github.com/teawater/kgtp.git
+git checkout release -b release
+}}}
+
+=== 镜像 ===
+[https://code.csdn.net/teawater/kgtp]<br>
+[https://git.oschina.net/teawater/kgtp]<br>
+[https://www.gitshell.com/teawater/kgtp/]<br>
+
+== 配置KGTP ==
+下面这部分是在KGTP Makefile里的配置。用这个配置,KGTP将自动和当前系统的内核 一起编译。
+{{{
+KERNELDIR := /lib/modules/`uname -r`/build
+CROSS_COMPILE :=
+}}}
+KERELDIR 设置了你要一起编译的内核,默认情况下,KGTP会和当前的内核一起编译。 <br> +请 *注意* 这个目录应该是内核编译目录或者linux-headers目录,而不是内核源码目 录。内核编译目录只有在编译成功后才能使用。<br>
+CROSS_COMPILE 设置编译KGTP的编译器前缀名。留空则使用默认编译器。<br>
+ARCH 是体系结构。<br>
+<br>
+
+或者你可以通过修改KGTP目录里的Makefile选择你要和哪个内核一起编译以及你用什 么编译器编译KGTP。<br>
+例如:
+{{{
+KERNELDIR := /home/teawater/kernel/bamd64
+CROSS_COMPILE :=x86_64-glibc_std-
+ARCH := x86_64
+}}}
+KERNELDIR 设置为 /home/teawater/kernel/bamd64。
+Compiler 设置为 x86_64-glibc_std-gcc。
+
+== 编译KGTP ==
+=== 普通编译 ===
+{{{
+cd kgtp/
+make
+}}}
+在一些编译环境中(例如Android)将出现一些编译应用程序getmod或者getframe的错 误。请忽略这些错误并使用目录中的gtp.ko。<br> +如果你在Fedora上得到出错信息"/usr/bin/ld: cannot find -lc",请用下面的命令 处理其。
+{{{
+sudo yum install glibc-static
+}}}
+
+=== 用一些特殊选项编译KGTP ===
+大部分时候,KGTP可以自动选择正确的参数和和各种版本的Linux内核一起编译。<br>
+但是如果你想配置一些特殊选项,可以按照下面的介绍来做:<br>
+
+用这个选项,KGTP将不自动选择任何编译选项。
+{{{
+make AUTO=0
+}}}
+
+用这个选项,KGTP将使用简单frame替代KGTP ring buffer。<br>
+简单frame不支持gtpframe_pipe,它现在只用来调试KGTP。
+{{{
+make AUTO=0 FRAME_SIMPLE=1
+}}}
+
+用这个选项,$clock将返回rdtsc的值而不是local_clock。
+{{{
+make AUTO=0 CLOCK_CYCLE=1
+}}}
+
+用这个选项,KGTP可以用procfs替代debugfs。
+{{{
+make AUTO=0 USE_PROC=1
+}}}
+
+这些选线可以一起使用,例如:
+{{{
+make AUTO=0 FRAME_SIMPLE=1 CLOCK_CYCLE=1
+}}}
+
+== 安装和卸载 KGTP ==
+因为KGTP可以直接在编译目录里insmod,所以不编译后不安装也可以直接使用(见 [https://code.google.com/p/kgtp/wiki/HOWTOCN#如何让GDB连接KGTP])。但是如果 需要也可以将其安装到系统中。
+安装:
+{{{
+cd kgtp/
+sudo make install
+}}}
+卸载:
+{{{
+cd kgtp/
+sudo make uninstall
+}}}
+
+== 和DKMS一起使用KGTP ==
+如果你需要的话,你还可以让DKMS来使用KGTP。<br>
+下面的命令将拷贝KGTP的文件到DKMS需要的目录中。
+{{{
+cd kgtp/
+sudo make dkms
+}}}
+于是你可以用DKMS命令控制KGTP。请到 http://linux.dell.com/dkms/manpage.html 去看如何使用DKMS。
+
+== 使用KGTP Linux内核patch ==
+大多数时候,你不需要KGTP patch,因为KGTP以一个LKM的形式编译安装更为方便。但 是为了帮助人们集成KGTP到他们自己的内核树,KGTP也提供了patch.
+在KGTP目录中:<br>
+  * *gtp_3.7_to_upstream.patch* 是给Linux kernel 从3.7到upstream的patch。
+  * *gtp_3.0_to_3.6.patch* 是给Linux kernel 从3.0到3.6的patch。
+  * *gtp_2.6.39.patch* 是给Linux kernel 2.6.39的patch。
+  * *gtp_2.6.33_to_2.6.38.patch* 是给Linux kernel 从2.6.33到2.6.38的patch。
+  * *gtp_2.6.20_to_2.6.32.patch* 是给Linux kernel 从2.6.20到2.6.32的patch。
+ * *gtp_older_to_2.6.19.patch* 是给Linux kernel 2.6.19以及更早版本的 patch。
+
+== 安装可以和KGTP一起使用的GDB ==
+早于7.6版本的GDB的tracepoint功能有一些bug,而且还有一些功能做的不是很好。 <br> +所以如果你的GDB小于7.6请到 [https://code.google.com/p/gdbt/] 去安装可以和 KGTP一起使用的GDB。这里提供UBUBTU, CentOS, Fedora, Mandriva, RHEL, SLE, openSUSE源。其他系统还可以下载静态编译版本。<br> +如果你有GDB的问题,请根据这里的信息 [http://code.google.com/p/kgtp/wiki/HOWTOCN#需要帮助或者汇报问题]取得帮助。
+
+
+= 如何让GDB连接KGTP =
+要使用KGTP的功能需要先让GDB连接到KGTP上。
+== 普通Linux ==
+=== 安装KGTP模块 ===
+如果你已经安装了KGTP在你的系统中,你可以:
+{{{
+sudo modprobe gtp
+}}}
+或者你可以直接使用KGTP目录里的文件:
+{{{
+cd kgtp/
+sudo insmod gtp.ko
+}}}
+=== 处理找不到"/sys/kernel/debug/gtp"的问题 ===
+如果你有这个问题,请先确定你的内核config打开了"Debug Filesystem"。 [http://code.google.com/p/kgtp/wiki/HOWTOCN#如果你的系统内核是自己编译的 ]<br>
+
+如果它以及被打开了,请用下面命令mount sysfs。
+{{{
+sudo mount -t sysfs none /sys/
+}}}
+也许你可能会得到一些错误例如"sysfs is already mounted on /sys",请忽略他 们。
+<br>
+
+请用下面命令mount debugfs。
+{{{
+mount -t debugfs none /sys/kernel/debug/
+}}}
+然后你就找到"/sys/kernel/debug/gtp"。
+=== 让GDB连接到KGTP ===
+请 *注意* 让GDB打开正确的vmlinux文件非常重要。请到 [http://code.google.com/p/kgtp/wiki/HOWTOCN#确定Linux内核调试镜像是正确的] 去看下如何做。
+==== GDB在本地主机上 ====
+{{{
+sudo gdb ./vmlinux
+(gdb) target remote /sys/kernel/debug/gtp
+Remote debugging using /sys/kernel/debug/gtp
+0x0000000000000000 in ?? ()
+}}}
+然后你就可以用GDB命令调试和跟踪Linux内核了。
+==== 如果GDB在远程主机上 ====
+用nc把KGTP接口映射到端口1024上。
+{{{
+sudo su
+nc -l 1234 </sys/kernel/debug/gtp >/sys/kernel/debug/gtp
+#(nc -l -p 1234 </sys/kernel/debug/gtp >/sys/kernel/debug/gtp 给老版本的nc)
+}}}
+之后,nc会在那里等待连接。<br>
+让GDB连接1234端口。
+{{{
+gdb-release ./vmlinux
+(gdb) target remote xxx.xxx.xxx.xxx:1234
+}}}
+然后你就可以用GDB命令调试和跟踪Linux内核了。
+
+== Android ==
+这个视频介绍了使用GDB连接Android上KGTP的过程,可访问 [http://www.tudou.com/programs/view/qCumSPhByFI/] 或者 [http://youtu.be/9YMpAvsl37I] 进行观看。
+=== 安装KGTP模块 ===
+*第一步* 确定ADB已经连接到Android上。<br>
+*第二步* 拷贝KGTP模块到Android上。
+{{{
+sudo adb push gtp.ko /
+}}}
+目录 "/" 可能是只读的。你可以选择其他目录或者用命令"sudo adb shell mount -o rw,remount /"把这个目录remount为可写。<br>
+*第三步* 安装KGTP模块。
+{{{
+adb shell insmod /gtp.ko
+}}}
+=== 处理找不到"/sys/kernel/debug/gtp"的问题 ===
+如果你有这个问题,请先确定你的内核config打开了"Debug Filesystem"。 [https://code.google.com/p/kgtp/wiki/HOWTOCN#如果是Android内核]<br>
+
+如果它以及被打开了,请用下面命令mount sysfs。
+{{{
+sudo adb shell mount -t sysfs none /sys/
+}}}
+也许你可能会得到一些错误例如"Device or resource busy",请忽略他们。
+<br>
+
+请用下面命令mount debugfs。
+{{{
+sudo adb shell mount -t debugfs none /sys/kernel/debug/
+}}}
+然后你就找到"/sys/kernel/debug/gtp"。
+=== GDB连接KGTP ===
+用nc将KGTP接口映射到1024端口上。
+{{{
+adb forward tcp:1234 tcp:1234
+adb shell "nc -l -p 1234 </sys/kernel/debug/gtp >/sys/kernel/debug/gtp"
+#(adb shell "nc -l 1234 </sys/kernel/debug/gtp >/sys/kernel/debug/gtp" 给新 版本的nc)
+}}}
+之后,nc会在那里等待连接。<br>
+让GDB连接1234端口。
+{{{
+gdb-release ./vmlinux
+(gdb) target remote :1234
+}}}
+然后你就可以用GDB命令调试和跟踪Linux内核了。
+
+= 增加模块的符号信息到GDB =
+有时你需要添加一个Linux内核模块的符号信息到GDB好调试其。<br>
+手动增加符号信息不太容易,所以KGTP包里包含了GDB Python脚本"getmod.py"和程 序"getmod"可以帮到你。
+
+== 如何使用getmod ==
+"getmod" 是用C写的所以你可以把它用在任何地方即使是一个嵌入式环境。<br>
+例如:
+{{{
+#下面的命令将把Linux内核模块信息以GDB命令的格式保存到文件/tmp/mi。
+sudo getmod >/tmp/mi
+#在GDB那边:
+(gdb) source /tmp/mi
+add symbol table from file "/lib/modules/2.6.39-rc5+/kernel/fs/nls/nls_iso8859-1.ko" at
+       .text_addr = 0xf80de000
+       .note.gnu.build-id_addr = 0xf80de088
+       .exit.text_addr = 0xf80de074
+       .init.text_addr = 0xf8118000
+       .rodata.str1.1_addr = 0xf80de0ac
+       .rodata_addr = 0xf80de0c0
+       __mcount_loc_addr = 0xf80de9c0
+       .data_addr = 0xf80de9e0
+       .gnu.linkonce.this_module_addr = 0xf80dea00
+#这条GDB命令后,所有Linux内核模块信息都被装载进GDB了。
+#After this GDB command, all the Linux Kernel module info is loaded into GDB.
+}}}
+如果你使用远程调试或者离线调试,你可以需要修改基本目录。下面是一个例子:
+{{{
+#/home/teawater/kernel/b26是GDB所在主机上内核模块所在的路径
+sudo ./getmod -r /home/teawater/kernel/b26 >~/tmp/mi
+}}}
+
+== 如何使用getmod.py ==
+请 *注意* [https://code.google.com/p/gdbt/]下载的静态编译GDB不能使用 getmod.py。<br>
+在使用getmod.py前连接到KGTP。
+{{{
+(gdb) source ~/kgtp/getmod.py
+}}}
+于是这个脚本将自动装载Linux内核模块到GDB中。
+
+= 如何使用GDB控制KGTP跟踪和调试Linux内核 =
+== 在普通模式直接访问当前值 ==
+在GDB连到KGTP上以后,如果没有用GDB命令"tfind"选择一条trace帧缓存里面的条 目,GDB就处于 *普通模式*。于是你可以直接访问内存(Linux内核或者用户程序)的值 和trace状态变量的值。<br> +如果你选择了一个trace帧条目,可以用GDB命令"tfind -1"返回到普通模式。请到 [http://code.google.com/p/kgtp/wiki/HOWTOCN#用tfind选择trace帧缓存里面的条目 ]取得GDB命令"tfind"的更多信息。
+
+=== Linux内核的内存 ===
+例如你可以用下面的命令访问"jiffies_64":
+{{{
+(gdb) p jiffies_64
+}}}
+或者你可以用下面的命令访问"static LIST_HEAD(modules)"的第一条记录:
+{{{
+(gdb) p *((struct module *)((char *)modules->next - ((size_t) &(((struct module *)0)->list))))
+}}}
+或者你可以访问"DEFINE_PER_CPU(struct device `*`, mce_device);"CPU0的数据:
+{{{
+p *(struct device *)(__per_cpu_offset[0]+(uint64_t)(&mce_device))
+}}}
+如果想在用一个GDB命令显示多个变量,请使用下面的例子:
+{{{
+(gdb) printf "%4d %4d %4d %4d %4d %4d %18d %lu\n", this_rq->cpu, this_rq->nr_running, this_rq->nr_uninterruptible, nr_active, calc_load_tasks->counter, this_rq->calc_load_active, delta, this_rq->calc_load_update
+2 1 0 0 0 0 673538312 717077240
+}}}
+
+=== 用户程序的内存 ===
+KGTP可以不同停止应用层程序的情况下直接读取其内存,例如:
+{{{
+#连接KGTP(这里和前面介绍的连接方法不同)
+(gdb) target extended-remote /sys/kernel/debug/gtp
+#增加一个新的inferior用来分析应用程序的信息。
+(gdb) add-inferior
+Added inferior 2
+#切换到这个inferior
+(gdb) inferior 2
+[Switching to inferior 2 [<null>] (<noexec>)]
+#转载这个程序的符号文件
+(gdb) file ~/kernel/svn/bak/a.out
+Reading symbols from /home/teawater/kernel/svn/bak/a.out...done.
+#attach到这个进程上(这不会停止这个程序)。
+(gdb) attach 10039
+Attaching to program: /home/teawater/kernel/svn/bak/a.out, Remote target
+Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...(no debugging symbols found)...done.
+Loaded symbols for /lib/x86_64-linux-gnu/libc.so.6
+Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
+Loaded symbols for /lib64/ld-linux-x86-64.so.2
+0x0000000000000000 in ?? ()
+#于是可以读这个程序的内存
+(gdb) p c
+$3 = -1222013392
+(gdb) p c
+$4 = -590910451
+}}}
+在这个例子中,我使用了一个多inferior命令。请到 [http://sourceware.org/gdb/current/onlinedocs/gdb/Inferiors-and-Programs.html] 去取得其更多相关信息。
+
+=== trace状态变量 ===
+你可以使用和访问内存一样的命令访问TSV。
+请到 [http://code.google.com/p/kgtp/wiki/HOWTOCN#如果使用trace状态变量] 取 得更多TSV的信息。
+
+== GDB tracepoint ==
+tracepoint就是GDB定义一些地址和一些动作。在tracepoint启动之后,当Linux内核 执行到那些地址的时候,KGTP将执行这些动作(它们中的有些会收集数据并存入 tracepoint帧缓冲)并把它们发给调试目标(KGTP)。而后,Linux内核将继续执行。<br> +KGTP提供了一些接口可以让GDB或者其他程序取出tracepoint帧缓冲的数据做分析。 <br> +关于这些接口,文档前面已经介绍了"/sys/kernel/debug/gtp",将在后面介 绍"/sys/kernel/debug/gtpframe" 和 "/sys/kernel/debug/gtpframe_pipe"。<br>
+<br>
+GDB tracepoint文档在 [http://sourceware.org/gdb/current/onlinedocs/gdb/Tracepoints.html]。
+
+=== 设置tracepint ===
+trace命令非常类似break命令,它的参数可以是文件行,函数名或者一个地址。 trace将定义一个或者多个地址定义一个tracepoint,KGTP将在这个点做一些动作。 <br>
+
+这是一些使用trace命令的例子:
+{{{
+(gdb) trace foo.c:121    // 一个文件和行号
+
+(gdb) trace +2           // 2行以后
+
+(gdb) trace my_function  // 函数的第一行
+
+(gdb) trace *my_function // 函数的第一个地址
+
+(gdb) trace *0x2117c4    // 一个地址
+}}}
+
+==== 这个函数确实存在但是设置tracepoint到上面会失败如何处理 ====
+GCC为了提高程序执行效率会inline一些static函数。因为目标文件没有inline函数的 符号,所以你不能设置tracepoint在函数名上。<br>
+你可以用"trace 文件:行号"在其上设置断点。
+
+=== 如何设置条件tracepoint ===
+[http://sourceware.org/gdb/current/onlinedocs/gdb/Tracepoint-Conditions.html]<br>
+和breakpoint一样,我们可以设置tracepoint的触发条件。而且因为条件检查是在 KGTP执行的,所以速度比breakpoint的条件检查快很多。<br>
+例如:
+{{{
+(gdb) trace handle_irq if (irq == 47)
+}}}
+tracepoint 1的动作将只在irq是47的时候才被执行。<br><br>
+
+你还可以用GDB命令"condition"设置tracepoint的触发条件。GDB命令"condition N COND"将设置tracepoint N只有条件COND为真的时候执行。<br>
+例如:
+{{{
+(gdb) trace handle_irq
+(gdb) condition 1 (irq == 47)
+}}}
+GDB命令"info tracepoint"将显示tracepoint的ID。<br><br>
+
+$bpnum的值是最后一个GDB tracepoint的ID,所以你可以不取得tracepoint的ID就用 condition来设置最后设置的tracepoint的条件,例如:
+{{{
+(gdb) trace handle_irq
+(gdb) condition $bpnum (irq == 47)
+}}}
+
+==== 如何处理错误 "Unsupported operator (null) (52) in expression." ====
+如果你使用关于字符串的条件tracepoint,你在调用"tstart"的时候可能得到这个出 错信息。<br>
+你可以转化char为int来处理这个问题,例如:
+{{{
+(gdb) p/x 'A'
+$4 = 0x41
+(gdb) condition 1 (buf[0] == 0x41)
+}}}
+
+=== `actions [num]` ===
+这个命令将设置一组action当tracepoint num触发的时候执行。如果没有设置num则将 设置action到最近创建的tracepoint上(因此你可以定义一个tracepoint然后直接输入 actions而不需要参数)。然后就要在后面输入action,最后以end为结束。到目前为 止,支持的action有collect,teval和while-stepping。
+
+==== `collect expr1, expr2, ...` ====
+当tracepoint触发的时候,收集表达式的值。这个命令可接受用逗号分割的一组列 表,这些列表除了可以是全局,局部或者本地变量,还可以是下面的这些参数:
+{{{
+$regs  收集全部寄存器。
+$args  收集函数参数。
+$locals        收集全部局部变量。
+}}}
+请 *注意* collect 一个指针(`collect ptr`)将只能collect这个指针的地址. 在指 针前面增加一个 `*` 将会让action collect指针指向的数据(`collect *ptr`)。
+
+
+==== `teval expr1, expr2, ...` ====
+当tracepoint触发的时候,执行指定的表达式。这个命令可接受用逗号分割的一组列 表。表达式的结果将被删除,所以最主要的作用是把值设置到trace状态变量中 (see [http://code.google.com/p/kgtp/wiki/HOWTOCN#普通trace状态变量]),而不用想 collect一样把这些值存到trace帧中。
+
+==== while-stepping n ====
+请到 [https://code.google.com/p/kgtp/wiki/HOWTOCN#使用while-stepping让 Linux内核做单步] 去看如何使用它。
+
+=== 启动和停止 tracepoint ===
+tracepoint只有在用下面的GDB命令启动后才可以执行action:
+{{{
+(gdb) tstart
+}}}
+它可以用下面的命令停止:
+{{{
+(gdb) tstop
+}}}
+
+=== Enable 和 disable tracepoint ===
+和breakpoint一样,tracepoint可以使用GDB命令 "enable" 和 "disable"。但是请 *注意* 它们只在tracepoint停止的时候有效。
+
+=== 用tfind选择trace帧缓存里面的条目 ===
+tracepoint停止的时候,GDB命令"tfind"可以用来选择trace帧缓存里面的条目。<br>
+当GDB在"tfind"模式的时候,其只能显示tracepoint action collect的存在于这个条 目中的数据。所以GDB将输出一些错误信息如果想打印没有collect的数据例如函数的参 数。这不是bug,不用担心。<br> +如果想选择下一个条目,可以再次使用命令"tfind"。还可以用"tfind 条目ID"去选择 某个条目。<br> +要回到普通模式([http://code.google.com/p/kgtp/wiki/HOWTOCN#在普通模式直接访 问当前值]),请使用GDB命令"tfind -1"。 +请到 [http://sourceware.org/gdb/current/onlinedocs/gdb/tfind.html] 取得它的 详细信息。
+
+==== 如何处理错误 "No such file or directory." 或者 "没有那个文件或目录." ====
+当GDB不能找到Linux内核源码的时候,其就会显示这个错误信息。
+例如:
+{{{
+(gdb) tfind
+Found trace frame 0, tracepoint 1
+#0 vfs_read (file=0xffff8801b6c3a500, buf=0x3f588b8 <Address 0x3f588b8 out of bounds>, count=8192, + pos=0xffff8801eee49f48) at /build/buildd/linux-3.2.0/fs/read_write.c:365
+365    /build/buildd/linux-3.2.0/fs/read_write.c: 没有那个文件或目录.
+}}}
+你可以用GDB命令 "set substitute-path" 处理它。前面这个例子Linux内核源码 在"/build/buildd/test/linux-3.2.0/"但是vmlinux让 GDB在"/build/buildd/linux-3.2.0/"找内核远啊,你可以处理他们:
+{{{
+(gdb) set substitute-path /build/buildd/linux-3.2.0/ /build/buildd/test/linux-3.2.0/
+(gdb) tfind
+Found trace frame 1, tracepoint 1
+#0 vfs_read (file=0xffff8801c36e6400, buf=0x7fff51a8f110 <Address 0x7fff51a8f110 out of bounds>, count=16, + pos=0xffff8801761dff48) at /build/buildd/linux-3.2.0/fs/read_write.c:365
+365    {
+}}}
+GDB还提供其他的命令处理源码问题,请到 [http://sourceware.org/gdb/current/onlinedocs/gdb/Source-Path.html]取得他们 的介绍。
+
+=== 保存trace帧信息到一个文件中 ===
+/sys/kernel/debug/gtpframe是一个当KGTP停止时的tfine格式(GDB可以读取它)的 接口。<br>
+
+请 *注意* 有些"cp"不能很好的处理这个问题,可以用"cat /sys/kernel/debug/gtpframe > ./gtpframe"拷贝它。<br>
+你可以在需要的时候打开文件gtpframe:
+{{{
+(gdb) target tfile ./gtpframe
+Tracepoint 1 at 0xffffffff8114f3dc: file /home/teawater/kernel/linux-2.6/fs/readdir.c, line 24.
+Created tracepoint 1 for target's tracepoint 1 at 0xffffffff8114f3c0.
+(gdb) tfind
+Found trace frame 0, tracepoint 1
+#0 vfs_readdir (file=0xffff880036e8f300, filler=0xffffffff8114f240 <filldir>, buf=0xffff880001e5bf38)
+    at /home/teawater/kernel/linux-2.6/fs/readdir.c:24
+24     {
+}}}
+
+=== 显示和存储tracepoint ===
+你可以用GDB命令"info tracepoints"显示所有的tracepoint。<br>
+你可以用GDB命令"save tracepoints filename"保存所有的设置tracepoint的命令到 文件filename里。于是你可以在之后用GDB命令"source filename"设置重新这些 tracepoint。
+
+=== 删除tracepoint ===
+GDB命令"delete id"将删除tracepoint id。如果"delete"没有参数,则删除所有 tracepoint。
+
+=== 用tracepoint从内核中某点取得寄存器信息 ===
+下面是记录内核调用函数"vfs_readdir"时的寄存器信息的例子:
+{{{
+(gdb) target remote /sys/kernel/debug/gtp
+(gdb) trace vfs_readdir
+Tracepoint 1 at 0xc01a1ac0: file
+/home/teawater/kernel/linux-2.6/fs/readdir.c, line 23.
+(gdb) actions
+Enter actions for tracepoint 1, one per line.
+End with a line saying just "end".
+>collect $reg
+>end
+(gdb) tstart
+(gdb) shell ls
+(gdb) tstop
+(gdb) tfind
+Found trace frame 0, tracepoint 1
+#0 0xc01a1ac1 in vfs_readdir (file=0xc5528d00, filler=0xc01a1900 <filldir64>,
+   buf=0xc0d09f90) at /home/teawater/kernel/linux-2.6/fs/readdir.c:23
+23 /home/teawater/kernel/linux-2.6/fs/readdir.c: No such file or directory.
+       in /home/teawater/kernel/linux-2.6/fs/readdir.c
+(gdb) info reg
+eax            0xc5528d00       -984445696
+ecx            0xc0d09f90       -1060069488
+edx            0xc01a1900       -1072031488
+ebx            0xfffffff7       -9
+esp            0xc0d09f8c       0xc0d09f8c
+ebp            0x0      0x0
+esi            0x8061480        134616192
+edi            0xc5528d00       -984445696
+eip            0xc01a1ac1       0xc01a1ac1 <vfs_readdir+1>
+eflags         0x286    [ PF SF IF ]
+cs             0x60     96
+ss             0x8061480        134616192
+ds             0x7b     123
+es             0x7b     123
+fs             0x0      0
+gs             0x0      0
+(gdb) tfind
+Found trace frame 1, tracepoint 1
+0xc01a1ac1      23      in /home/teawater/kernel/linux-2.6/fs/readdir.c
+(gdb) info reg
+eax            0xc5528d00       -984445696
+ecx            0xc0d09f90       -1060069488
+edx            0xc01a1900       -1072031488
+ebx            0xfffffff7       -9
+esp            0xc0d09f8c       0xc0d09f8c
+ebp            0x0      0x0
+esi            0x8061480        134616192
+edi            0xc5528d00       -984445696
+eip            0xc01a1ac1       0xc01a1ac1 <vfs_readdir+1>
+eflags         0x286    [ PF SF IF ]
+cs             0x60     96
+ss             0x8061480        134616192
+ds             0x7b     123
+es             0x7b     123
+fs             0x0      0
+gs             0x0      0
+}}}
+
+=== 用tracepoint从内核中某点取得变量的值 ===
+下面是记录内核调用函数"vfs_readdir"时"jiffies_64"的值的例子:
+{{{
+(gdb) target remote /sys/kernel/debug/gtp
+(gdb) trace vfs_readdir
+Tracepoint 1 at 0xc01ed740: file /home/teawater/kernel/linux-2.6/fs/readdir.c, line 24.
+(gdb) actions
+Enter actions for tracepoint 1, one per line.
+End with a line saying just "end".
+>collect jiffies_64
+>collect file->f_path.dentry->d_iname
+>end
+(gdb) tstart
+(gdb) shell ls
+arch drivers include kernel mm Module.symvers security System.map virt +block firmware init lib modules.builtin net sound t vmlinux +crypto fs ipc Makefile modules.order scripts source usr vmlinux.o
+(gdb) tstop
+(gdb) tfind
+Found trace frame 0, tracepoint 1
+#0 0xc01ed741 in vfs_readdir (file=0xf4063000, filler=0xc01ed580 <filldir64>, buf=0xd6dfdf90)
+    at /home/teawater/kernel/linux-2.6/fs/readdir.c:24
+24     {
+(gdb) p jiffies_64
+$1 = 4297248706
+(gdb) p file->f_path.dentry->d_iname
+$1 = "b26", '\000' <repeats 28 times>
+}}}
+
+=== 显示当前这一条trace缓存里存储的所有信息 ===
+在用"tfind"选择好一个条目后,你可以用"tdump"。
+{{{
+(gdb) tdump
+Data collected at tracepoint 1, trace frame 0:
+$cr = void
+file->f_path.dentry->d_iname = "gtp\000.google.chrome.g05ZYO\000\235\337\000\000\000\000\200\067k\364\200\067", <incomplete sequence \364>
+jiffies_64 = 4319751455
+}}}
+
+=== 取得 tracepoint 的状态 ===
+请用GDB命令"tstatus"。
+
+=== 设置trace缓存为循环缓存 ===
+[http://sourceware.org/gdb/current/onlinedocs/gdb/Starting-and-Stopping-Trace-Experiments.html]<br>
+帧缓存默认情况下不是循环缓存。当缓存满了的时候,tracepoint将停止。<br>
+下面的命令将设置trace缓存为循环缓存,当缓存满了的时候,其将自动删除最早的数 据并继续trace。
+{{{
+(gdb) set circular-trace-buffer on
+}}}
+
+=== GDB断开的时候不要停止tracepoint ===
+[http://sourceware.org/gdb/current/onlinedocs/gdb/Starting-and-Stopping-Trace-Experiments.html]<br>
+默认情况下,当GDB断开KGTP的时候将自动停止tracepoint并删除trace帧。<br>
+下面的命令将打开KGTP disconnect-trace。在设置之后,当GDB断开KGTP的时 候,KGTP将不停止tracepoint。GDB重新连到KGTP的时候,其可以继续控制KGTP。
+{{{
+(gdb) set disconnected-tracing on
+}}}
+
+=== kprobes-optimization和tracepoint的执行速度 ===
+因为tracepoint是和Linux内核一起执行,所以它的速度将影响到系统执行的速度。 <br> +KGTP tracepoint是基于Linux内核kprobe。因为普通kprobe是基于断点指令,所以它 的速度不是很快。<br><br>
+
+但是如果你的arch是X86_64 或者 X86_32 而且内核配置没有打开"Preemptible Kernel" (PREEMPT),kprobe的速度将被kprobes-optimization (CONFIG_OPTPROBES)提 高很多。<br>
+可以用下面的命令来确认:
+{{{
+sysctl -A | grep kprobe
+debug.kprobes-optimization = 1
+}}}
+这个的意思就是你的系统支持kprobes-optimization。<br>
+请 *注意* 一些KGTP的功能会导致tracepoint只能使用普通kprobe即使系统支持 kprobes-optimization。文档将在介绍这些功能的时候增加提醒,如果你很介意 tracepoint的速度就请避免使用这些功能。
+
+== 如何使用trace状态变量 ==
+[http://sourceware.org/gdb/current/onlinedocs/gdb/Trace-State-Variables.html]<br>
+trace状态变量简称TSV。<br>
+TSV可以在tracepoint action和condition中被访问,并且可以直接被GDB命令访问。 <br> +请 *注意* GDB 7.2.1和更晚的版本直接访问trace状态变量,比他们老的GDB只能通过 命令"info tvariables"取得trace状态变量的值。
+=== 普通trace状态变量 ===
+定义trace状态变量$c.
+{{{
+(gdb) tvariable $c
+}}}
+trace状态变量 $c 被创建并初始化0。
+下面的action将使用$c记录内核里发生了多少次IRQ。
+{{{
+(gdb) target remote /sys/kernel/debug/gtp
+(gdb) trace handle_irq
+(gdb) actions
+Enter actions for tracepoint 3, one per line.
+End with a line saying just "end".
+>collect $c     #Save current value of $c to the trace frame buffer.
+>teval $c=$c+1  #Increase the $c.
+>end
+}}}
+你还可以将某个变量的值传到状态变量里,但是别忘记转化这个值为"uint64_t"。
+{{{
+>teval $c=(uint64_t)a
+}}}
+你可以取得$c的值当trace在运行或者停止的时候。
+{{{
+(gdb) tstart
+(gdb) info tvariables
+$c              0           31554
+(gdb) p $c
+$5 = 33652
+(gdb) tstop
+(gdb) p $c
+$9 = 105559
+}}}
+当使用tfind的时候,你可以分析trace frame buffer。如果trace状态变量被收集 了,你可以把它取出来。
+{{{
+(gdb) tstop
+(gdb) tfind
+(gdb) info tvariables
+$c              0           0
+(gdb) p $c
+$6 = 0
+(gdb) tfind 100
+(gdb) p $c
+$7 = 100
+}}}
+如果需要的时候,访问trace状态变量的tracepoint action将自动加锁,所以其可以 很好的处理trace状态变量的竞态条件问题。<br>
+下面这个例子即使在一个多CPU的环境也可以正常使用。
+{{{
+>teval $c=$c+1
+}}}
+
+=== Per_cpu trace状态变量 ===
+Per_cpu trace状态变量是一种特殊的普通trace状态变量。
+当一个tracepoint action访问到其的时候,其将自动访问这个CPU的Per_cpu trace状 态变量。<br>
+
+它有两个优点:<br>
+1. 访问Per_cpu trace状态变量的tracepoint actions不存在竞态条件问题,所以其 不需要对trace状态变量加锁。所以其在多核的机器上速度更快。
+<br>
+2. 写针对记录某个CPU的tracepoint actions比普通trace状态变量更容易。
+
+==== 如何定义 ====
+Per_cpu trace状态变量有两种类型:
+
+===== 本地CPU变量 =====
+{{{
+"per_cpu_"+string
+}}}
+或者
+{{{
+"p_"+string
+}}}
+例如:
+{{{
+(gdb) tvariable $p_count
+}}}
+在tracepoint action中访问这个trace状态变量的时候,其将返回这个变量在这个 action运行的CPU上的值。
+===== CPU id变量 =====
+{{{
+"per_cpu_"+string+CPU_id
+}}}
+或者
+{{{
+"p_"+string+CPU_id
+}}}
+例如:
+{{{
+(gdb) tvariable $p_count0
+(gdb) tvariable $p_count1
+(gdb) tvariable $p_count2
+(gdb) tvariable $p_count3
+}}}
+在tracepoint action或者GDB命令行中访问这个变量的时候,其将返回这个变量在 CPU CPI_id 上的值。
+<br>
+下面这个例子可以自动这个这台主机上的每个CPU定义CPU id变量。(请 *注意* 用这 些命令之前需要让GDB连上KGTP。)
+{{{
+(gdb) set $tmp=0
+(gdb) while $tmp<$cpu_number
+ >eval "tvariable $p_count%d",$tmp
+ >set $tmp=$tmp+1
+ >end
+}}}
+
+==== 例子1 ====
+这个例子定义了一个记录每个CPU调用多少次vfs_read的tracepoint。
+{{{
+tvariable $p_count
+set $tmp=0
+while $tmp<$cpu_number
+  eval "tvariable $p_count%d",$tmp
+  set $tmp=$tmp+1
+  end
+trace vfs_read
+actions
+  teval $p_count=$p_count+1
+  end
+}}}
+于是你可以在"tstart"后显示每个CPU调用了多少次vfs_read:
+{{{
+(gdb) p $p_count0
+$3 = 44802
+(gdb) p $p_count1
+$4 = 55272
+(gdb) p $p_count2
+$5 = 102085
+(gdb) p $p_count3
+}}}
+
+==== 例子2 ====
+这个例子记录了每个CPU上关闭IRQ时间最长的函数的stack dump。
+{{{
+set pagination off
+
+tvariable $bt=1024
+tvariable $p_count
+tvariable $p_cc
+set $tmp=0
+while $tmp<$cpu_number
+eval "tvariable $p_cc%d",$tmp
+set $tmp=$tmp+1
+end
+
+tvariable $ignore_error=1
+
+trace arch_local_irq_disable
+  commands
+    teval $p_count=$clock
+  end
+trace arch_local_irq_enable if ($p_count && $p_cc < $clock - $p_count)
+  commands
+    teval $p_cc = $clock - $p_count
+    collect $bt
+    collect $p_cc
+    teval $p_count=0
+  end
+
+enable
+set pagination on
+}}}
+
+=== 特殊trace状态变量 $current_task,$current_task_pid,$current_thread_info,$cpu_id,$dump_stack,$printk_level,$printk_format,$printk_tmp,$clock,$hardirq_count,$softirq_count 和 $irq_count === +KGTP特殊trace状态变量$current_task,$current_thread_info,$cpu_id 和 $clock可以很容易的访问各种特殊的值,当你用GDB连到KGTP后就可以访问到他们。
+你可以在tracepoint条件和actions里使用他们。<br>
+在tracepoint条件和actions里访问$current_task可以取得get_current()的返回值。 <br> +在tracepoint条件和actions里访问$current_task_pid可以取得 get_current()->pid的值。<br> +在tracepoint条件和actions里访问$current_thread_info可以取得 current_thread_info()的返回值。<br> +在tracepoint条件和actions里访问$cpu_id可以取得smp_processor_id()的返回值。 <br> +在tracepoint条件和actions里访问$clock可以取得local_clock()的返回值,也就是 取得纳秒为单位的时间戳。<br> +$rdtsc只在体系结构是X86或者X86_64的时候访问的到,任何时候访问它可以取得用指 令RDTSC取得的TSC的值。<br> +在tracepoint条件和actions里访问$hardirq_count可以取得hardirq_count()的返回 值。<br> +在tracepoint条件和actions里访问$softirq_count可以取得softirq_count()的返回 值。<br>
+在tracepoint条件和actions里访问$irq_count可以取得irq_count()的返回值。<br>
+
***The diff for this file has been truncated for email.***

Other related posts:

  • » [kgtp] r1679 committed - Test Localizing Wiki Content - kgtp