├── .gitignore ├── Makefile ├── README.md ├── UPDATE ├── add-ons ├── cma_free.py ├── gtpwin.py ├── gtpwin_example.py ├── hotcode.py ├── pe.py └── tfind.py ├── dkms.conf ├── dkms_others_install.sh ├── dkms_others_uninstall.sh ├── getframe.c ├── getgtprsp.pl ├── getmod.c ├── getmod.py ├── gtp.c ├── gtp.h ├── gtp_2.6.20_to_2.6.32.patch ├── gtp_2.6.33_to_2.6.38.patch ├── gtp_2.6.39.patch ├── gtp_3.0_to_3.6.patch ├── gtp_3.7_to_upstream.patch ├── gtp_older_to_2.6.19.patch ├── gtp_rb.c ├── kgtp.py ├── perf_event.c ├── plugin_example.c ├── putgtprsp.c ├── ring_buffer.c └── ring_buffer.h /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore the compiled files and other stuff 2 | getmod 3 | getframe 4 | putgtprsp 5 | *.o 6 | *.ko 7 | .tmp_versions/ 8 | Module.symvers 9 | 10 | .gtp.ko.cmd 11 | .gtp.mod.o.cmd 12 | .gtp.o.cmd 13 | gtp.mod.c 14 | gtp.mod.o 15 | modules.order 16 | 17 | .DS_Store 18 | 19 | .plugin_example.ko.cmd 20 | .plugin_example.mod.o.cmd 21 | .plugin_example.o.cmd 22 | plugin_example.mod.c 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(P),1) 2 | obj-m := gtp.o plugin_example.o 3 | else 4 | obj-m := gtp.o 5 | endif 6 | 7 | MODULEVERSION := 20140510+ 8 | 9 | KERNELVERSION ?= $(shell uname -r) 10 | KERNELDIR ?= /lib/modules/$(KERNELVERSION)/build/ 11 | CROSS_COMPILE ?= 12 | MODULEDIR ?= /lib/modules/$(KERNELVERSION)/lib/ 13 | #ARCH ?= i386 14 | #ARCH ?= x86_64 15 | #ARCH ?= mips 16 | #ARCH ?= arm 17 | 18 | export CONFIG_DEBUG_INFO=y 19 | 20 | PWD := $(shell pwd) 21 | ifeq ($(D),1) 22 | EXTRA_CFLAGS += -DGTPDEBUG 23 | endif 24 | ifeq ($(AUTO),0) 25 | EXTRA_CFLAGS += -DGTP_NO_AUTO_BUILD 26 | endif 27 | ifeq ($(FRAME_ALLOC_RECORD),1) 28 | EXTRA_CFLAGS += -DFRAME_ALLOC_RECORD 29 | endif 30 | ifeq ($(FRAME_SIMPLE),1) 31 | EXTRA_CFLAGS += -DGTP_FRAME_SIMPLE 32 | endif 33 | ifeq ($(CLOCK_CYCLE),1) 34 | EXTRA_CFLAGS += -DGTP_CLOCK_CYCLE 35 | endif 36 | ifeq ($(USE_PROC),1) 37 | EXTRA_CFLAGS += -DUSE_PROC 38 | endif 39 | ifeq ($(NO_WARNING),1) 40 | EXTRA_CFLAGS += -DNO_WARNING 41 | endif 42 | 43 | DKMS_FILES := Makefile dkms.conf dkms_others_install.sh \ 44 | dkms_others_uninstall.sh gtp.c gtp_rb.c ring_buffer.c \ 45 | ring_buffer.h getmod.c getframe.c putgtprsp.c getgtprsp.pl \ 46 | howto.txt 47 | 48 | default: gtp.ko getmod getframe putgtprsp 49 | 50 | clean: 51 | rm -rf getmod 52 | rm -rf getframe 53 | rm -rf putgtprsp 54 | rm -rf *.o 55 | rm -rf *.ko 56 | rm -rf .tmp_versions/ 57 | rm -rf Module.symvers 58 | 59 | install: module_install others_install 60 | 61 | uninstall: module_uninstall others_uninstall 62 | 63 | dkms: 64 | mkdir -p /usr/src/kgtp-$(MODULEVERSION)/ 65 | cp $(DKMS_FILES) /usr/src/kgtp-$(MODULEVERSION)/ 66 | 67 | module_install: gtp.ko 68 | mkdir -p $(MODULEDIR) 69 | cp gtp.ko $(MODULEDIR) 70 | depmod -a 71 | 72 | module_uninstall: 73 | rm -rf $(MODULEDIR)gtp.ko 74 | depmod -a 75 | 76 | others_install: program_install 77 | 78 | others_uninstall: program_uninstall 79 | 80 | program_install: getmod getframe putgtprsp 81 | cp getmod /sbin/ 82 | chmod 700 /sbin/getmod 83 | cp getframe /sbin/ 84 | chmod 700 /sbin/getframe 85 | cp putgtprsp /sbin/ 86 | chmod 700 /sbin/putgtprsp 87 | cp getgtprsp.pl /bin/ 88 | chmod 755 /bin/getgtprsp.pl 89 | cp getmod.py /bin/ 90 | chmod 644 /bin/getmod.py 91 | 92 | program_uninstall: 93 | rm -rf /sbin/getmod 94 | rm -rf /sbin/getframe 95 | rm -rf /sbin/putgtprsp 96 | rm -rf /bin/getgtprsp.pl 97 | 98 | gtp.ko: gtp.c gtp_rb.c ring_buffer.c ring_buffer.h perf_event.c 99 | ifneq ($(ARCH),) 100 | $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules 101 | else 102 | $(MAKE) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules 103 | endif 104 | 105 | getmod: getmod.c 106 | ifeq ($(D),1) 107 | $(CROSS_COMPILE)gcc -g -static -o getmod getmod.c 108 | else 109 | $(CROSS_COMPILE)gcc -O2 -static -o getmod getmod.c 110 | endif 111 | 112 | getframe: getframe.c 113 | ifeq ($(D),1) 114 | $(CROSS_COMPILE)gcc -g -static -o getframe getframe.c 115 | else 116 | $(CROSS_COMPILE)gcc -O2 -static -o getframe getframe.c 117 | endif 118 | 119 | putgtprsp: putgtprsp.c 120 | ifeq ($(D),1) 121 | $(CROSS_COMPILE)gcc -g -static -o putgtprsp putgtprsp.c 122 | else 123 | $(CROSS_COMPILE)gcc -O2 -static -o putgtprsp putgtprsp.c 124 | endif 125 | 126 | plugin_example.ko: plugin_example.c gtp_plugin.h 127 | ifneq ($(ARCH),) 128 | $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules 129 | else 130 | $(MAKE) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules 131 | endif 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [KGTP](http://teawater.github.io/kgtp/) 2 | ==== 3 | 4 | #### What is KGTP? 5 | 6 | KGTP is a comprehensive dynamic tracer for analysing Linux kernel and application (including Android) problems on production systems in real time. 7 | 8 | To use it, you don't need patch or rebuild the Linux kernel. Just build KGTP module and insmod it is OK. 9 | 10 | It makes Linux Kernel supply a GDB remote debug interface. Then GDB in current machine or remote machine can debug and trace Linux kernel and user space program through GDB tracepoint and some other functions without stopping the Linux Kernel. 11 | And even if the board doesn't have GDB on it and doesn't have interface for remote debug. It can debug the Linux Kernel using offline debug (See /sys/kernel/debug/gtpframe and offline debug). 12 | 13 | KGTP supports X86-32, X86-64, MIPS and ARM. 14 | 15 | KGTP supports most versions of the kernel (from 2.6.18 to upstream). 16 | 17 | http://www.youtube.com/watch?v=7nfGAbNsEZY or http://www.tudou.com/programs/view/fPu_koiKo38/ is the video that introduced KGTP in English. 18 | 19 | http://www.infoq.com/cn/presentations/gdb-sharp-knife-kgtp-linux-kernel is the video that introduced KGTP in Chinese. 20 | 21 | Refer more details about `KGTP` in *Chinese* [here](http://teawater.github.io/kgtp/indexcn.html). 22 | 23 | #### How to use KGTP? 24 | 25 | Refer to the source code blow. 26 | 27 | ``` python 28 | #kgtp.py will auto setup and start KGTP and GDB in current machine. 29 | #The first time you use this script needs to wait for a while because there are some packages to download. 30 | wget https://raw.githubusercontent.com/teawater/kgtp/master/kgtp.py 31 | sudo python kgtp.py 32 | #Access memory of Linux kernel. 33 | (gdb) p jiffies_64 34 | $2 = 5081634360 35 | #Set tracepoint in function vfs_read to collect its backtrace. 36 | (gdb) trace vfs_read 37 | Tracepoint 1 at 0xffffffff811b8c70: file fs/read_write.c, line 382. 38 | (gdb) actions 39 | Enter actions for tracepoint 1, one per line. 40 | End with a line saying just "end". 41 | >collect $bt 42 | >end 43 | (gdb) tstart 44 | (gdb) tstop 45 | (gdb) tfind 46 | Found trace frame 0, tracepoint 1 47 | #0 vfs_read (file=file@entry=0xffff88022017b000, 48 | buf=buf@entry=0x7fff0fdd80f0
, 49 | count=count@entry=16, pos=pos@entry=0xffff8800626aff50) at fs/read_write.c:382 50 | 382 { 51 | (gdb) bt 52 | #0 vfs_read (file=file@entry=0xffff88022017b000, 53 | buf=buf@entry=0x7fff0fdd80f0
, 54 | count=count@entry=16, pos=pos@entry=0xffff8800626aff50) at fs/read_write.c:382 55 | #1 0xffffffff811b9819 in SYSC_read (count=16, 56 | buf=0x7fff0fdd80f0
, fd=) 57 | at fs/read_write.c:506 58 | ``` 59 | -------------------------------------------------------------------------------- /UPDATE: -------------------------------------------------------------------------------- 1 | *** 20140510+ 2 | 3 | * Lihang Li 4 | Fix build warning in 32-bit. 5 | 6 | * Linyu Zhu 7 | Lihang Li 8 | Fix some issues of doc. 9 | 10 | * Linyu Zhu 11 | Fix GTP_RB_RELEASE macro's issue in KGTP's ring buffer. 12 | 13 | * Hui Zhu 14 | Fix some issues of kgtp.py with Fedora. 15 | 16 | *** 20140510 17 | 18 | * https://lkml.org/lkml/2014/5/11/395 19 | 20 | * Remove txt documents because KGTP has pdf version documents now. 21 | 22 | * Update doc "Get help or report issues". 23 | http://teawater.github.io/kgtp/kgtp.html#__RefHeading__11582_1935127565 24 | http://teawater.github.io/kgtp/kgtpcn.html#__RefHeading__3899_71337508 25 | 26 | * Update doc "Get KGTP through git". 27 | http://teawater.github.io/kgtp/kgtp.html#__RefHeading__4098_695897485 28 | http://teawater.github.io/kgtp/kgtpcn.html#__RefHeading__10760_71337508 29 | 30 | * Update doc "Get KGTP through http". 31 | http://teawater.github.io/kgtp/kgtp.html#__RefHeading__4096_695897485 32 | http://teawater.github.io/kgtp/kgtpcn.html#__RefHeading__10758_71337508 33 | 34 | * Remove line that access $no_self_trace in hotcode.py. 35 | 36 | * Remove "doc_install" and "doc_uninstall" in Makefile to handle error 37 | of "make install". 38 | 39 | * Add TSV $task_pt_regs. 40 | 41 | * Fix the build failed with the Linux kernel that newer than 3.13. 42 | 43 | * Add python script kgtp.py that can auto setup and start KGTP and GDB 44 | in current machine. 45 | 46 | * Update doc. 47 | Change "Preparatory work before use KGTP", "How to let GDB connect to KGTP" and "Add module symbols to GDB" as appendix. 48 | http://teawater.github.io/kgtp/kgtp.html#__RefHeading__11428_1305468286 49 | http://teawater.github.io/kgtp/kgtp.html#__RefHeading__4433_1176671169 50 | http://teawater.github.io/kgtp/kgtp.html#__RefHeading__4828_1369842245 51 | http://teawater.github.io/kgtp/kgtpcn.html#__RefHeading__11597_1305468286 52 | http://teawater.github.io/kgtp/kgtpcn.html#__RefHeading__11575_71337508 53 | http://teawater.github.io/kgtp/kgtpcn.html#__RefHeading__11597_71337508 54 | Add "Quick config and start KGTP". 55 | http://teawater.github.io/kgtp/kgtp.html#__RefHeading__11364_1305468286 56 | http://teawater.github.io/kgtp/kgtpcn.html#__RefHeading__11595_1305468286 57 | 58 | * Remove quickstart.txt. 59 | 60 | *** 20131220 61 | 62 | * Get in github: 63 | Get through https: 64 | https://github.com/teawater/kgtp/archive/20131220.tar.gz 65 | Get through git: 66 | git clone https://github.com/teawater/kgtp.git 67 | git checkout 20131220 -b 20131220 68 | 69 | * Get in CSDN: 70 | Get through https: 71 | https://code.csdn.net/teawater/kgtp/repository/archive?ref=20131220 72 | Get through git: 73 | git clone git://code.csdn.net/teawater/kgtp.git 74 | git checkout 20131220 -b 20131220 75 | 76 | * Update doc "What is KGTP". 77 | https://code.google.com/p/kgtp/wiki/HOWTO#What_is_KGTP 78 | https://code.google.com/p/kgtp/wiki/HOWTOCN#什么是KGTP 79 | 80 | * Fix build error from Linux kernel 3.5 to Linux kernel 3.9. 81 | Thanks report from 钱凯 82 | 83 | * Update doc "Trace user applications". 84 | https://code.google.com/p/kgtp/wiki/HOWTO#Trace_user_applications 85 | https://code.google.com/p/kgtp/wiki/HOWTOCN#Trace用户程序 86 | 87 | *** 20131218 88 | 89 | * https://lkml.org/lkml/2013/12/18/931 90 | 91 | * Get in github: 92 | Get through https: 93 | https://github.com/teawater/kgtp/archive/20131218.tar.gz 94 | Get through git: 95 | git clone https://github.com/teawater/kgtp.git 96 | git checkout 20131218 -b 20131218 97 | 98 | * Get in CSDN: 99 | Get through https: 100 | https://code.csdn.net/teawater/kgtp/repository/archive?ref=20131218 101 | Get through git: 102 | git clone git://code.csdn.net/teawater/kgtp.git 103 | git checkout 20131218 -b 20131218 104 | 105 | * Add uprobe support. Then KGTP can trace user applications. 106 | https://code.google.com/p/kgtp/wiki/HOWTO#Trace_user_applications 107 | https://code.google.com/p/kgtp/wiki/HOWTOCN#Trace用户程序 108 | 109 | * Fix https://github.com/teawater/kgtp/issues/9 110 | A multiprocess bug about packets "?" and "Hg". 111 | 112 | * Fix https://github.com/teawater/kgtp/issues/8 113 | A TSV check bug. 114 | 115 | * Add "monitor disable" and KGTP address disable list to handle the 116 | issue that GDB cannot disable one tracepoint of a same number tracepoints 117 | list. 118 | 119 | * Update doc "Where is the current Linux kernel debug image" to make it more clear. 120 | https://code.google.com/p/kgtp/wiki/HOWTO#Where_is_the_current_Linux_kernel_debug_image 121 | https://code.google.com/p/kgtp/wiki/HOWTOCN#当前Linux内核调试镜像在哪 122 | 123 | * Update doc add section "Load Linux kernel debug image to GDB". 124 | https://code.google.com/p/kgtp/wiki/HOWTO#Load_Linux_kernel_debug_image_to_GDB 125 | https://code.google.com/p/kgtp/wiki/HOWTOCN#装载Linux内核调试镜像到GDB 126 | 127 | * Add support for preempt_count_add and preempt_count_sub to make KGTP 128 | can build with Linux Kernel 3.13. 129 | Thanks help from Chen Gang. 130 | 131 | * Update doc "Use KGTP with user applications". 132 | https://code.google.com/p/kgtp/wiki/HOWTO#Use_KGTP_with_user_applications 133 | https://code.google.com/p/kgtp/wiki/HOWTOCN#和用户程序一起使用KGTP 134 | 135 | * Update doc "What is KGTP". 136 | Thanks help from Xi Yang. 137 | https://code.google.com/p/kgtp/wiki/HOWTO#What_is_KGTP 138 | https://code.google.com/p/kgtp/wiki/HOWTOCN#什么是KGTP 139 | 140 | *** 20130915 141 | 142 | * https://lkml.org/lkml/2013/9/15/12 143 | 144 | * Get through https: 145 | https://github.com/teawater/kgtp/archive/20130915.tar.gz 146 | Get through git: 147 | git clone https://github.com/teawater/kgtp.git 148 | git checkout 20130915 -b 20130915 149 | 150 | * Remove gtp_taobao.patch because we can post pull request to ali_kernel 151 | in github directly. 152 | 153 | * Fix https://code.google.com/p/kgtp/issues/detail?id=149 that cannot 154 | get right value of x86_32 $ebp. 155 | Thanks report from wangwangwar. 156 | 157 | * Fix https://github.com/teawater/kgtp/issues/1 158 | Thanks report from Tao Ma and Yanhai Zhu. 159 | 160 | * Add howto pdf files: 161 | https://raw.github.com/teawater/kgtp/master/kgtp.pdf 162 | https://raw.github.com/teawater/kgtp/master/kgtpcn.pdf 163 | 164 | * Add "new way" to "Install the Linux kernel source". 165 | https://code.google.com/p/kgtp/wiki/HOWTO#New_way 166 | https://code.google.com/p/kgtp/wiki/HOWTOCN#新方法 167 | 168 | * Fix https://github.com/teawater/kgtp/issues/2 169 | Thanks report from Brad Dixon. 170 | Let kunmap use "page" as its argument. 171 | 172 | * The .config inside UBUNTU linux-headers close CONFIG_DEBUG_INFO=y. 173 | It will make KGTP module will not build with "-g" in UBUNTU that 174 | will make KGTP module doesn't have debug info. 175 | To handle this isssue, add "export CONFIG_DEBUG_INFO=y" to Makefile 176 | to make KGTP module can build with -g in UBUNTU. 177 | 178 | * Fix https://github.com/teawater/kgtp/issues/3 179 | Thanks report from Brad Dixon. 180 | Fix 2 bugs: 181 | 1. gtp_get_user_page doesn't check the return of find_vma. 182 | 2. The way that get x86_32's user space program sp is wrong. 183 | 184 | * Fix https://github.com/teawater/kgtp/issues/6 185 | Fix 2 bugs: 186 | 1. Let gtp_gdbrsp_qxfer_traceframe_info_read return error if it in *no tfind* mode or in replay mode. 187 | 2. Let gtp_gdbrsp_m copy memory value to right address. 188 | 189 | * Fix a bug that use KGTP from remote with normal way and offline debug together. 190 | https://github.com/teawater/kgtp/commit/403f14dde39d5304b38b1c5014712aff8e2f1fc3 191 | 192 | * Update doc add section "About this document". 193 | https://code.google.com/p/kgtp/wiki/HOWTO#About_this_document 194 | https://code.google.com/p/kgtp/wiki/HOWTOCN#关于本文 195 | 196 | * Update doc "Get KGTP". 197 | https://code.google.com/p/kgtp/wiki/HOWTO#Get_KGTP 198 | https://code.google.com/p/kgtp/wiki/HOWTOCN#取得KGTP 199 | 200 | * Update doc "Get help or report issues" 201 | https://code.google.com/p/kgtp/wiki/HOWTO#Get_help_or_report_issues 202 | https://code.google.com/p/kgtp/wiki/HOWTOCN#需要帮助或者汇报问题 203 | 204 | *** 20130706 205 | 206 | * https://lkml.org/lkml/2013/7/6/34 207 | 208 | * https://kgtp.googlecode.com/files/kgtp_20130706.tar.bz2 209 | svn checkout https://kgtp.googlecode.com/svn/tags/20130706 210 | 211 | * Fix build issue with Linux kernel 2.6.37. 212 | Thanks report from D___linux. 213 | 214 | * Fix build issue with Linux kernel 2.6.32-358.el6. 215 | Thanks report from Dong Zhu. 216 | 217 | * Fix bug with functions return value. 218 | 219 | * Fix dead lock with dynamic watch tracepoint. 220 | https://code.google.com/p/kgtp/source/detail?r=1626 221 | 222 | * Add build warning if KGTP build with Linux kernel that open the runtime 223 | locking correctness validator (CONFIG_LOCKDEP). 224 | Because trace function about locks with Linux kernel that open 225 | CONFIG_LOCKDEP will deadlock. 226 | 227 | * Add $watch_prev_val to show the previous value that watch tracepoint is watching on. 228 | https://code.google.com/p/kgtp/wiki/HOWTO#Howto_use_watch_tracepoint_control_hardware_breakpoints_to_recor 229 | https://code.google.com/p/kgtp/wiki/HOWTOCN#如何用watch_tracepoint控制硬件断点记录内存访问 230 | 231 | * Update doc add section about use KGTP with Android. 232 | https://code.google.com/p/kgtp/wiki/HOWTO#If_use_with_Linux_kernel_of_Android 233 | https://code.google.com/p/kgtp/wiki/HOWTOCN#如果是Android内核 234 | https://code.google.com/p/kgtp/wiki/HOWTO#Android 235 | https://code.google.com/p/kgtp/wiki/HOWTOCN#Android 236 | 237 | * Update doc add "The second method of install the Linux kernel debug image" for UBUNTU. 238 | https://code.google.com/p/kgtp/wiki/HOWTO#The_second_method_of_install_the_Linux_kernel_debug_image 239 | https://code.google.com/p/kgtp/wiki/HOWTOCN#安装Linux内核调试镜像的第二方法 240 | 241 | * Update doc "Install GDB for KGTP". 242 | https://code.google.com/p/kgtp/wiki/HOWTO#Install_GDB_for_KGTP 243 | https://code.google.com/p/kgtp/wiki/HOWTOCN#安装可以和KGTP一起使用的GDB 244 | 245 | * Update doc "How to use getmod.py". 246 | https://code.google.com/p/kgtp/wiki/HOWTO#How_to_use_getmod.py 247 | https://code.google.com/p/kgtp/wiki/HOWTOCN#如何使用getmod.py 248 | 249 | * Let $current can be set to support some special Linux kernel functions. 250 | https://code.google.com/p/kgtp/wiki/HOWTO#collect_stack_(for_backtrace)_of_user_space_program_in_tracepoin 251 | https://code.google.com/p/kgtp/wiki/HOWTOCN#在tracepoint收集用户层程序的栈信息(可用来做backt 252 | 253 | * Update doc "Normal compile" add introduce about howto handle the build error in Fedora. 254 | https://code.google.com/p/kgtp/wiki/HOWTO#Normal_compile 255 | https://code.google.com/p/kgtp/wiki/HOWTOCN#普通编译 256 | 257 | * Update doc "Get KGTP through svn" add introduce about get the last release version of KGTP. 258 | https://code.google.com/p/kgtp/wiki/HOWTO#Get_KGTP_through_svn 259 | https://code.google.com/p/kgtp/wiki/HOWTOCN#通过svn下载KGTP 260 | 261 | * Update doc "Install the Linux kernel debug image" add debuginfo-install. 262 | https://code.google.com/p/kgtp/wiki/HOWTO#Install_the_Linux_kernel_debug_image 263 | https://code.google.com/p/kgtp/wiki/HOWTOCN#安装Linux内核调试镜像 264 | 265 | * Update doc "Install the Linux kernel devel package" add a note. 266 | https://code.google.com/p/kgtp/wiki/HOWTO#Install_the_Linux_kernel_devel_package 267 | https://code.google.com/p/kgtp/wiki/HOWTOCN#安装Linux内核开发包 268 | 269 | * Update doc add "Get the way that access the variable that has been out through parse ASM code". 270 | https://code.google.com/p/kgtp/wiki/HOWTO#Get_the_way_that_access_the_variable_that_has_been__out_through 271 | https://code.google.com/p/kgtp/wiki/HOWTOCN#通过分析汇编代码取得访问被优化掉变量的方法 272 | 273 | *** 20130508 274 | 275 | * https://lkml.org/lkml/2013/5/8/86 276 | 277 | * http://kgtp.googlecode.com/files/kgtp_20130508.tar.bz2 278 | svn checkout https://kgtp.googlecode.com/svn/tags/20130508 279 | 280 | * Add "Where is the current Linux kernel debug image" to howto. 281 | http://code.google.com/p/kgtp/wiki/HOWTO#Where_is_the_current_Linux_kernel_debug_image 282 | http://code.google.com/p/kgtp/wiki/HOWTOCN#当前Linux内核调试镜像在哪 283 | 284 | * Add "Table of different between GDB debug normal program and KGTP" to howto. 285 | https://code.google.com/p/kgtp/wiki/HOWTO#Table_of_different_between_GDB_debug_normal_program_and_KGTP 286 | https://code.google.com/p/kgtp/wiki/HOWTOCN#GDB调试普通程序和KGTP的区别表 287 | 288 | * Add check if $kret use with while-stepping or watch. Make them cannot work together. 289 | 290 | * Change $no_self_trace to $self_trace. 291 | https://code.google.com/p/kgtp/wiki/HOWTO#Special_trace_state_variable_$self_trace 292 | https://code.google.com/p/kgtp/wiki/HOWTOCN#特殊trace状态变量_$self_trace 293 | 294 | * Update getmod. 295 | Add a '#' at the beginning make the output as comments if this output does not mean getmod will error quit. 296 | Add a '#' at the beginning make the add-symbol-file that cannot find module file as comments. 297 | 298 | * Complete the support of while-stepping. KGTP can let Linux kernel do single step now. 299 | https://code.google.com/p/kgtp/wiki/HOWTO#Use_while-stepping_let_Linux_kernel_do_single_step 300 | https://code.google.com/p/kgtp/wiki/HOWTOCN#使用while-stepping让Linux内核做单步 301 | 302 | *** 20130218 303 | 304 | * https://lkml.org/lkml/2013/2/18/145 305 | 306 | * http://kgtp.googlecode.com/files/kgtp_20130218.tar.bz2 307 | svn checkout https://kgtp.googlecode.com/svn/tags/20130218 308 | 309 | * Add watch tracepoint control hardware breakpoints to record memory access. 310 | http://code.google.com/p/kgtp/wiki/HOWTO#Howto_use_watch_tracepoint_control_hardware_breakpoints_to_recor 311 | http://code.google.com/p/kgtp/wiki/HOWTOCN#如何用watch_tracepoint控制硬件断点记录内存访问 312 | 313 | * Update 314 | http://code.google.com/p/kgtp/wiki/HOWTOCN#/sys/kernel/debug/gtpframe和离线调试 315 | http://code.google.com/p/kgtp/wiki/HOWTO#/sys/kernel/debug/gtpframe_and_offline_debug 316 | add a workaround to handle issue 136. 317 | 318 | * Update usage of putgtprsp. 319 | http://code.google.com/p/kgtp/wiki/HOWTOCN#/sys/kernel/debug/gtpframe和离线调试 320 | http://code.google.com/p/kgtp/wiki/HOWTO#/sys/kernel/debug/gtpframe_and_offline_debug 321 | 322 | * Fix memory leak of output the value directly function. 323 | 324 | * Make $cpu_id can be access by tracepoint action. 325 | 326 | *** 20121204 327 | 328 | * https://lkml.org/lkml/2012/12/9/156 329 | 330 | * http://kgtp.googlecode.com/files/kgtp_20121204.tar.bz2 331 | svn checkout https://kgtp.googlecode.com/svn/tags/20121204 332 | 333 | * Remove __exit from gtp_exit to fix a section mismatch. 334 | 335 | * Add "Direct access the current value in normal mode" to make tfind 336 | more clear. 337 | http://code.google.com/p/kgtp/wiki/HOWTO#Direct_access_the_current_value_in_normal_mode 338 | http://code.google.com/p/kgtp/wiki/HOWTOCN#在普通模式直接访问当前值 339 | 340 | * Add "Save the trace frame info to a file" to doc. 341 | http://code.google.com/p/kgtp/wiki/HOWTO#Save_the_trace_frame_info_to_a_file 342 | http://code.google.com/p/kgtp/wiki/HOWTOCN#保存trace帧信息到一个文件中\ 343 | 344 | * Make getgtprsp.pl generate files that the last char is not "\n" that 345 | will make "cat gtpstart > /sys/kernel/debug/gtp" get error. 346 | 347 | * Show CPU id in $printk_level function. 348 | 349 | * Show CPU id in $dump_stack function. 350 | 351 | * Make $printk_level function show right val name. 352 | 353 | * Add "putgtprsp" to handle the offline debug GDB command line file. 354 | Thanks report from alex.zhu.az. 355 | http://code.google.com/p/kgtp/wiki/HOWTO#/sys/kernel/debug/gtpframe_and_offline_debug 356 | http://code.google.com/p/kgtp/wiki/HOWTOCN#/sys/kernel/debug/gtpframe和离线调试 357 | 358 | * Fix issue 130. Thanks help from bergwolf. 359 | 360 | * Fix issue 131. Thanks report from Oliver Yang. 361 | 362 | * Add How to handle error "No such file or directory." to howto. 363 | http://code.google.com/p/kgtp/wiki/HOWTO#How_to_handle_error_"No_such_file_or_directory." 364 | http://code.google.com/p/kgtp/wiki/HOWTOCN#如何处理错误_"No_such_file_or_directory."_或者 365 | 366 | * Add Handle the issue that cannot find any file in "/sys/" or "/sys/kernel/debug/" to howto. 367 | Thanks report from Oliver Yang. 368 | http://code.google.com/p/kgtp/wiki/HOWTO#Handle_the_issue_that_cannot_find_any_file_in_"/sys/" 369 | http://code.google.com/p/kgtp/wiki/HOWTOCN#处理不能在"/sys/"或者"/sys/kernel/debug/&q 370 | 371 | *** 20120920 372 | 373 | * https://lkml.org/lkml/2012/9/20/697 374 | 375 | * http://kgtp.googlecode.com/files/kgtp_20120920.tar.bz2 376 | svn checkout https://kgtp.googlecode.com/svn/tags/20120920 377 | 378 | * Add KGTP_API_VERSION to patch and gtp.c to help gtp.c know which 379 | KGTP API is support by current kernel. 380 | 381 | * Set KGTP_API_VERSION to 20120917, it include API: 382 | __flush_anon_page(Just just available on ARM Linux kernel 2.6.20 383 | and newer version) 384 | Following function is just available on Linux kernel that have perf: 385 | perf_event_disable and perf_event_enable (Only available older 386 | than 3.3.0 because 3.3.0 and newer already have it.) 387 | local_perf_event_disable 388 | local_perf_event_enable 389 | perf_event_set 390 | 391 | * Add $disable and $enable to disable and enable tracepoint in tracepoint 392 | action. 393 | 394 | * Fix bug that complex conditon or action that access special TSV get error 395 | with function gtp_check_x_simple or gtp_check_x_loop. 396 | 397 | * Fix a long size line bug of getmod. 398 | 399 | * Update howto for "How to set tracepoint condition". 400 | http://code.google.com/p/kgtp/wiki/HOWTO#How_to_set_tracepoint_condition 401 | http://code.google.com/p/kgtp/wiki/HOWTOCN#如何设置条件tracepoint 402 | 403 | * Update How to handle "Unsupported operator (null) (52) in expression." 404 | http://code.google.com/p/kgtp/wiki/HOWTO#How_to_handle_"Unsupported_operator_(null)_(52)_in_expressi 405 | http://code.google.com/p/kgtp/wiki/HOWTOCN#如何处理_"Unsupported_operator_(null)_(52)_in_expressio 406 | 407 | * Add introduce for collect ptr and collect *ptr to howto. 408 | http://code.google.com/p/kgtp/wiki/HOWTO#collect_expr1,_expr2,_... 409 | http://code.google.com/p/kgtp/wiki/HOWTOCN#collect_expr1,_expr2,_... 410 | 411 | * Fix memleak of gtp_traceframe_info and gtp_modules_traceframe_info. 412 | 413 | * Change the format of per_cpu TSR from "pc_" to "p_" 414 | and change the usage of it. 415 | http://code.google.com/p/kgtp/wiki/HOWTO#Per_cpu_trace_state_variables 416 | http://code.google.com/p/kgtp/wiki/HOWTOCN#Per_cpu_trace状态变量 417 | 418 | * To follow the change of per_cpu TSR update, change $pc_pe_en to $p_pe_en. 419 | http://code.google.com/p/kgtp/wiki/HOWTO#Enable_and_disable_all_the_perf_event_in_a_CPU_with_$p_pe_en 420 | http://code.google.com/p/kgtp/wiki/HOWTOCN#用$p_pe_en打开和关闭一个CPU上所有的perf_event 421 | 422 | * Add new option "-n" to getmod. 423 | 424 | * Rename gtp_older_to_2.6.32.patch to gtp_2.6.20_to_2.6.32.patch. 425 | Add gtp_older_to_2.6.19.patch. 426 | 427 | * Add plugin support. 428 | http://code.google.com/p/kgtp/wiki/HOWTO#How_to_add_plugin_in_C 429 | http://code.google.com/p/kgtp/wiki/HOWTOCN#如何增加用C写的插件 430 | 431 | *** 20120806 432 | 433 | * http://sourceware.org/ml/gdb/2012-08/msg00014.html 434 | 435 | * http://kgtp.googlecode.com/files/kgtp_20120806.tar.bz2 436 | svn checkout https://kgtp.googlecode.com/svn/tags/20120806 437 | 438 | * When "make clean" with new Linux kernel. Linux kernel will clean itself. 439 | So change "make clean" to "rm" to handle it. 440 | 441 | * Remove S_IFIFO from debugfs_create_file because new Kernel doesn't 442 | like it. 443 | 444 | * Fix a bug of gtp_task_read. This bug will make this function can 445 | sleep sometimes. This bug is dangerous when tracepoint access user 446 | space memory. 447 | 448 | * Support enable and disable when tracepoint is running. 449 | 450 | * Fix build error with RHEL 6.3. 451 | 452 | *** 20120605 453 | 454 | * https://lkml.org/lkml/2012/6/5/67 455 | 456 | * http://kgtp.googlecode.com/files/kgtp_20120605.tar.bz2 457 | svn checkout https://kgtp.googlecode.com/svn/tags/20120605 458 | 459 | * Add "Make sure current Linux kernel debug image is right" to howto. 460 | http://code.google.com/p/kgtp/wiki/HOWTO#Make_sure_current_Linux_kernel_debug_image_is_right 461 | http://code.google.com/p/kgtp/wiki/HOWTOCN#确定Linux内核调试镜像是正确的 462 | 463 | * Update "tfind" in howto to make it more clear. 464 | http://code.google.com/p/kgtp/wiki/HOWTO#tfind 465 | http://code.google.com/p/kgtp/wiki/HOWTOCN#tfind 466 | 467 | * Add "Show and save the tracepoint" to howto. 468 | http://code.google.com/p/kgtp/wiki/HOWTO#Show_and_save_the_tracepoint 469 | http://code.google.com/p/kgtp/wiki/HOWTOCN#显示和存储tracepoint 470 | 471 | * Add "Handle the issue that Linux kernel debug image's address info is not 472 | same with Linux kernel when it running" to howto. 473 | http://code.google.com/p/kgtp/wiki/HOWTO#Handle_the_issue_that_Linux_kernel_debug_image's_address_in 474 | http://code.google.com/p/kgtp/wiki/HOWTOCN#处理Linux内核调试镜像地址信息和Linux内核执行时 475 | 476 | * Add "Howto handle the function is there but set tracepoint on it got fail" to howto. 477 | http://code.google.com/p/kgtp/wiki/HOWTO#Howto_handle_the_function_is_there_but_set_tracepoint_on_it_got 478 | http://code.google.com/p/kgtp/wiki/HOWTOCN#这个函数确实存在但是设置tracepoint到上面会失败 479 | 480 | * Fix bug of getmod.py with new GDB. 481 | 482 | * Add new function "Read memory of user space program directly" 483 | http://code.google.com/p/kgtp/wiki/HOWTO#Read_memory_of_user_space_program_directly 484 | http://code.google.com/p/kgtp/wiki/HOWTOCN#直接读用户层程序的内存 485 | 486 | * Add new function "collect stack (for backtrace) of user space program in tracepoint" 487 | http://code.google.com/p/kgtp/wiki/HOWTO#collect_stack_(for_backtrace)_of_user_space_program_in_tracepoin 488 | http://code.google.com/p/kgtp/wiki/HOWTOCN#在tracepoint收集用户层程序的栈信息(可用来做backt 489 | 490 | * Add new introduce about howto show more than one variable with one GDB commands in "Access memory directly" of howto. 491 | http://code.google.com/p/kgtp/wiki/HOWTO#Access_memory_directly 492 | http://code.google.com/p/kgtp/wiki/HOWTOCN#直接访问内存 493 | Thanks help from qw.hust. 494 | 495 | * Update some sections of howto to make it more clear. 496 | 497 | * Fix bug in getmod.c. Thanks report from scorpionfish. 498 | 499 | *** 20120424 500 | 501 | * https://lkml.org/lkml/2012/4/24/194 502 | https://lkml.org/lkml/2012/4/24/195 503 | https://lkml.org/lkml/2012/4/24/196 504 | https://lkml.org/lkml/2012/4/24/197 505 | 506 | * http://kgtp.googlecode.com/files/kgtp_20120424.tar.bz2 507 | svn checkout https://kgtp.googlecode.com/svn/tags/20120424 508 | 509 | * Update "How to use /sys/kernel/debug/gtpframe_pipe" in howto. 510 | http://code.google.com/p/kgtp/wiki/HOWTO#How_to_use_/sys/kernel/debug/gtpframe_pipe 511 | 512 | * Add How to handle "Unsupported operator (null) (52) in expression." to howto. 513 | http://code.google.com/p/kgtp/wiki/HOWTO#How_to_handle_"Unsupported_operator_(null)_(52)_in_expressi 514 | 515 | * Separate actions and actions src to handle the status 516 | that will delete some actions. 517 | 518 | * Add $bt to collect the stack and update the stack dump in the howto to make 519 | it more clear. 520 | http://code.google.com/p/kgtp/wiki/HOWTO#Howto_backtrace_(stack_dump) 521 | 522 | * Update the format of example in the HOWTO to make it more clear. 523 | 524 | * Remove the crc check and suport QStartNoAckMode+. 525 | 526 | * Add Chinese howto. 527 | http://code.google.com/p/kgtp/wiki/HOWTOCN 528 | 529 | * Update a lot of parts of howto to make it more clear. 530 | http://code.google.com/p/kgtp/wiki/HOWTO 531 | http://code.google.com/p/kgtp/wiki/HOWTOCN 532 | 533 | * Add introduce of $_ret to howto. 534 | http://code.google.com/p/kgtp/wiki/HOWTO#Collect_stack_of_current_function's_caller_with_$_ret 535 | 536 | *** 20120406 537 | 538 | * https://lkml.org/lkml/2012/4/7/35 539 | 540 | * http://kgtp.googlecode.com/files/kgtp_20120406.tar.bz2 541 | svn checkout https://kgtp.googlecode.com/svn/tags/20120406 542 | 543 | * Fix build error with Linux kernel that older than 2.6.34 in ARM. 544 | Thanks report and help from Adam Huang (sniperpr). 545 | 546 | * Update howto.txt (http://code.google.com/p/kgtp/wiki/HOWTO) to 547 | make it more clear. 548 | 549 | * Update the GDB in http://code.google.com/p/gdbt/ (add static binary 550 | and change the source of code) to make people use it easily. 551 | 552 | * Fix bug of add-ons/hotcode.py when it use with user space task. 553 | 554 | * add-ons/hotcode.py output hot code info to html file. 555 | 556 | * getmod.py auto call "set pagination off". 557 | 558 | *** 20120319 559 | 560 | * https://lkml.org/lkml/2012/3/19/210 561 | 562 | * http://kgtp.googlecode.com/files/kgtp_20120319.tar.bz2 563 | svn checkout https://kgtp.googlecode.com/svn/tags/20120319 564 | 565 | * Fix bug with GDB RSP package sum check. 566 | 567 | * Increase the speed of access to trace state variables. 568 | 569 | * Increase the speed of agent code execution. 570 | 571 | * Remove the current agent code "printf" support because GDB will support new 572 | format of agent code "printf". 573 | 574 | * Fix bug about access $current_task_pid. 575 | 576 | * Add new debug switch GTP_DEBUG_V (just for developer). 577 | 578 | * Add new add-ons hotcode.py. It can show the hotest code line 579 | in the Kernel or user space program through parse and record 580 | the pc address in the interrupt handler. 581 | 582 | *** 20120224 583 | 584 | * https://lkml.org/lkml/2012/2/26/127 585 | 586 | * http://kgtp.googlecode.com/files/kgtp_20120224.tar.bz2 587 | svn checkout https://kgtp.googlecode.com/svn/tags/20120224 588 | 589 | * Fix build error with Linux Kernel 3.0.x version. 590 | Thanks for report from sam.wanshan. 591 | 592 | * Make getgtprsp.pl support all special trace state variables. 593 | 594 | * Fix the bug that set the id of FID_PAGE_BEGIN inside gtp_rb. 595 | 596 | * Change code to ignore the task that read the /sys/kernel/debug/gtpframe_pipe 597 | in default. And add special trace state variable $pipe_trace to control it. 598 | 599 | * Fix error of doc about $ignore_error. 600 | 601 | * Add $current_task_pid to access to get_current()->pid. 602 | 603 | * Remove GTP_VAR_NOT_GETV, GTP_VAR_NOT_SETV and GTP_VAR_NOT_TRACEV. 604 | 605 | * Fix bug in gtp_frame_file_header that affect stack when src of conditon 606 | or action is bigger than 200. 607 | 608 | *** 20120131 609 | 610 | * https://lkml.org/lkml/2012/1/31/215 611 | 612 | * http://kgtp.googlecode.com/files/kgtp_20120131.tar.bz2 613 | svn checkout https://kgtp.googlecode.com/svn/tags/20120131 614 | 615 | * Add ignore gtp.ko function to getmod.py. 616 | 617 | * Add support for GDB rsp package "qXfer:traceframe-info:read". 618 | Then tfind mode will show the memory that is not in traceframe 619 | as "". It is more accurate than before. 620 | It fixed issue 1 and Issue 101. 621 | 622 | * Fix bug of gtp_rb page release in function gtp_rb_page_free. 623 | 624 | * Fix bug of gtp_rb_put_page that is used by gtpframe_pipe. 625 | 626 | * Add define for perf_event_enable and perf_event_disable in gtp.c 627 | and perf_event.c because both of them EXPORT_SYMBOL_GPL in Linux Kernel 3.3. 628 | 629 | *** 20111218 630 | 631 | * https://lkml.org/lkml/2011/12/18/36 632 | 633 | * http://kgtp.googlecode.com/files/kgtp_20111218.tar.bz2 634 | svn checkout https://kgtp.googlecode.com/svn/tags/20111218 635 | 636 | * Add gtp_rb to be the new frame buffer to make trace record speed up and more 637 | friendly to the older version Linux kernel. 638 | 639 | * Rename gtp.patch to gtp_for_review.patch. 640 | 641 | * Add Linux Kernel patch gtp_3.0_to_upstream.patch(3.0 to upstream), 642 | gtp_2.6.39.patch(2.6.39), gtp_2.6.33_to_2.6.38.patch(2.6.33 to 2.6.38) 643 | and gtp_older_to_2.6.32.patch(older to 2.6.32). 644 | Then you can include KGTP in your Kernel source tree. 645 | 646 | * Add special trace state variable $gtp_version to show the version of KGTP. 647 | 648 | * Fix some build errors of gtp_for_review.patch. 649 | 650 | * Fix some build errors in ARM. 651 | 652 | * Update doc. 653 | 654 | *** 20111111 655 | 656 | * https://lkml.org/lkml/2011/11/14/4 657 | 658 | * http://kgtp.googlecode.com/files/kgtp_20111111.tar.bz2 659 | svn checkout https://kgtp.googlecode.com/svn/tags/20111111 660 | 661 | * post_handler will make kprobes-optimization cannot be used. So make 662 | gtp_kp_post_handler be call only when tpe->step is true. 663 | 664 | * Make rdtsc_current to x86 special. 665 | 666 | * Register easy Kprobe handler to speed up it when no tracepoint access 667 | $cooked_clock, $cooked_rdtsc or "pc_pe_" tvariable. 668 | 669 | * Fix a bug of ARM build. 670 | 671 | * Add a doc for use KGTP with Android in 672 | https://code.google.com/p/kgtp/wiki/HowToUseKGTPinAndroid 673 | 674 | -------------------------------------------------------------------------------- /add-ons/cma_free.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import gdb 4 | 5 | MAX_ORDER = 11 6 | NR_FREE_CMA_PAGES = int(gdb.parse_and_eval("NR_FREE_CMA_PAGES")) 7 | NR_FREE_PAGES = int(gdb.parse_and_eval("NR_FREE_PAGES")) 8 | 9 | def print_zone(num): 10 | print str(gdb.parse_and_eval("contig_page_data->node_zones[" + str(num) + "]->name")) 11 | print "NR_FREE_CMA_PAGES = " + str(gdb.parse_and_eval("contig_page_data->node_zones[" + str(num) + "]->vm_stat[" + str(NR_FREE_CMA_PAGES) + "]")) 12 | count = 0 13 | print "cma_nr_free" 14 | for i in range(0, MAX_ORDER): 15 | page = int(gdb.parse_and_eval("contig_page_data->node_zones[" + str(num) + "]->free_area[" + str(i) + "].cma_nr_free")) 16 | print i, page, page << i 17 | count += page << i 18 | print count 19 | print "" 20 | print "NR_FREE_PAGES = " + str(gdb.parse_and_eval("contig_page_data->node_zones[" + str(num) + "]->vm_stat[" + str(NR_FREE_PAGES) + "]")) 21 | count = 0 22 | print "nr_free" 23 | for i in range(0, MAX_ORDER): 24 | page = int(gdb.parse_and_eval("contig_page_data->node_zones[" + str(num) + "]->free_area[" + str(i) + "].nr_free")) 25 | print i, page, page << i 26 | count += page << i 27 | print count 28 | print "" 29 | 30 | print_zone(0) 31 | print_zone(1) 32 | -------------------------------------------------------------------------------- /add-ons/gtpwin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import gtk 4 | import glib 5 | import traceback 6 | 7 | version = '20120605+' 8 | 9 | def modelName(): 10 | return __name__ 11 | 12 | def run(): 13 | gtk.main() 14 | 15 | class gtpline: 16 | def __init__(self, name): 17 | self.name = name 18 | self.val = [] 19 | self.y = [] 20 | 21 | def val_number(self): 22 | return len(self.val) 23 | 24 | def add(self, val): 25 | self.val.append(val) 26 | self.y.append(-1) 27 | 28 | def remove_head(self, num): 29 | if self.val_number() > 0: 30 | if num == 0: 31 | del(self.val[0:]) 32 | del(self.y[0:]) 33 | else: 34 | del(self.val[0:num]) 35 | del(self.y[0:num]) 36 | 37 | def load_new_val(self): 38 | '''GUI will auto call this function each sec that you set. Use this function call self.add to add new val to this line. 39 | If really got value, add and return it. If not, add and return 0.''' 40 | self.add(0) 41 | return 0 42 | 43 | class gtpwin(gtk.Window): 44 | def __init__(self, lines, title = "", sec = 1, width = 10, remove_first = False, button_each_line = 4): 45 | """lines: the line class list to show. 46 | title: the window title. 47 | sec: the load new entry wait second. 48 | width: the width of each entry. 49 | remove_first :true then remove the first entry because it already record a big value. 50 | button_each_line: the number of button of each line. 51 | """ 52 | super(gtpwin, self).__init__() 53 | 54 | self.entry_width = width 55 | 56 | self.max_value = 0 57 | self.prev_width = 0 58 | self.prev_height = 0 59 | self.y_ratio = 0 60 | self.logfd = False 61 | 62 | #Setup lines 63 | color_limit = (0xffb0ff, 0x006000) 64 | num = len(lines) 65 | block = (color_limit[0] - color_limit[1]) / float(num) 66 | color = color_limit[1] 67 | for e in lines: 68 | e.bcolor = gtk.gdk.Color("#"+ "%06x" % int(color)) 69 | e.lcolor = ((((int(color) >> 16) / float(0xff) * 1), ((int(color) >> 8 & 0xff) / float(0xff) * 1), ((int(color) & 0xff) / float(0xff) * 1))) 70 | color += block 71 | self.lines = lines 72 | 73 | #Set window 74 | self.set_title(title) 75 | self.connect("destroy", gtk.main_quit) 76 | 77 | #Create button 78 | bhbox = gtk.HBox(False, 0) 79 | self.button_hboxes = [bhbox] 80 | num = 0 81 | for line in self.lines: 82 | line.button = gtk.ToggleButton(line.name) 83 | self.set_button_color(line.button, line.bcolor) 84 | line.button.line = line 85 | line.button.connect("clicked", self.button_click) 86 | line.entry = gtk.Entry() 87 | line.entry.set_editable(False) 88 | hbox = gtk.HBox(False, 0) 89 | hbox.pack_start(line.button, False, False, 0) 90 | hbox.pack_start(line.entry, False, False, 0) 91 | bhbox.pack_start(hbox, True, False, 0) 92 | num += 1 93 | if num >= button_each_line: 94 | bhbox = gtk.HBox(False, 0) 95 | self.button_hboxes.append(bhbox) 96 | num = 0 97 | 98 | #Create self.darea 99 | self.darea = gtk.DrawingArea() 100 | self.darea.connect("expose-event", self.expose) 101 | self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color("#FFFFFF")) 102 | 103 | #menubar 104 | mb = gtk.MenuBar() 105 | #file 106 | filemenu = gtk.Menu() 107 | filem = gtk.MenuItem("File") 108 | filem.set_submenu(filemenu) 109 | save = gtk.CheckMenuItem("Save log to a CSV file") 110 | save.connect("activate", self.mb_save) 111 | save.set_active(False) 112 | clean = gtk.MenuItem("Clean") 113 | clean.connect("activate", self.mb_clean) 114 | exit = gtk.MenuItem("Exit") 115 | exit.connect("activate", gtk.main_quit) 116 | filemenu.append(save) 117 | filemenu.append(clean) 118 | filemenu.append(gtk.SeparatorMenuItem()) 119 | filemenu.append(exit) 120 | mb.append(filem) 121 | #set 122 | setmenu = gtk.Menu() 123 | setm = gtk.MenuItem("Settings") 124 | setm.set_submenu(setmenu) 125 | show_buttons = gtk.CheckMenuItem("Show buttons") 126 | show_buttons.set_active(True) 127 | show_buttons.connect("activate", self.show_buttons) 128 | setmenu.append(show_buttons) 129 | mb.append(setm) 130 | 131 | #Put widgets to window 132 | vbox = gtk.VBox(False, 0) 133 | vbox.pack_start(mb, False, False, 0) 134 | vbox.pack_start(self.darea, True, True, 0) 135 | for e in self.button_hboxes: 136 | vbox.pack_start(e, False, False, 0) 137 | self.add(vbox) 138 | 139 | self.show_all() 140 | gtk.Window.maximize(self) 141 | 142 | #Set each button to same width 143 | button_size_max = 0 144 | entry_size_max = 0 145 | for line in self.lines: 146 | if line.button.allocation.width > button_size_max: 147 | button_size_max = line.button.allocation.width 148 | if line.entry.allocation.width > entry_size_max: 149 | entry_size_max = line.entry.allocation.width 150 | for line in self.lines: 151 | line.button.set_size_request(button_size_max, -1) 152 | line.entry.set_size_request(entry_size_max, -1) 153 | 154 | #Add timer 155 | glib.timeout_add(int(sec * 1000), self.timer_cb) 156 | if remove_first: 157 | glib.timeout_add(int(sec * 1100), self.timer_remove_first_record) 158 | 159 | def __del__(self): 160 | if self.logfd: 161 | self.logfd.close() 162 | self.logfd = False 163 | super(gtpwin, self).__del__() 164 | 165 | def each_lines(self, callback, argument = 0): 166 | for line in self.lines: 167 | callback(line, argument) 168 | 169 | #DrawingArea --------------------------------------------------- 170 | def expose(self, widget, event): 171 | cr = widget.window.cairo_create() 172 | 173 | #y 174 | if self.prev_height != self.darea.allocation.height: 175 | self.height_change = True 176 | self.prev_height = self.darea.allocation.height 177 | else: 178 | self.height_change = False 179 | if self.max_value > 0 and (self.height_change or self.y_ratio == 0): 180 | self.max_value += 100 - self.max_value % 100 181 | self.y_ratio = float(self.prev_height)/self.max_value 182 | self.height_change = True 183 | 184 | #x 185 | entry_number = 0 186 | if self.entry_width * self.lines[0].val_number() > self.darea.allocation.width: 187 | self.entry_number = self.darea.allocation.width // self.entry_width 188 | for line in self.lines: 189 | if line.val_number() > self.entry_number: 190 | line.remove_head(line.val_number() - self.entry_number) 191 | 192 | #dash 193 | cr.set_source_rgb(0, 0, 0) 194 | cr.set_dash((1, 5)) 195 | #dash line for x 196 | x = 0 197 | while x < self.darea.allocation.width: 198 | x += self.entry_width * 10 199 | cr.move_to(x, 0) 200 | cr.line_to(x, self.prev_height) 201 | #dash line for y 202 | cr.move_to(0, 10) 203 | cr.show_text(str(self.max_value)) 204 | cr.move_to(0, self.darea.allocation.height/4*3) 205 | cr.show_text(str(self.max_value/4)) 206 | cr.line_to(self.darea.allocation.width, self.darea.allocation.height/4*3) 207 | cr.move_to(0, self.darea.allocation.height/2) 208 | cr.show_text(str(self.max_value/2)) 209 | cr.line_to(self.darea.allocation.width, self.darea.allocation.height/2) 210 | cr.move_to(0, self.darea.allocation.height/4) 211 | cr.show_text(str(self.max_value/4*3)) 212 | cr.line_to(self.darea.allocation.width, self.darea.allocation.height/4) 213 | cr.stroke() 214 | cr.set_dash(()) 215 | 216 | #lines 217 | self.line_max = 0 218 | self.each_lines(self.draw_line, cr) 219 | if (self.line_max > 0 and (self.line_max * 2 < self.max_value or self.line_max > self.max_value)) or self.max_value == 0: 220 | self.max_value = self.line_max 221 | self.y_ratio = 0 222 | self.height_change = False 223 | 224 | def draw_line(self, line, cr): 225 | if line.button.get_active(): 226 | return 227 | if line.val_number() < 2: 228 | return 229 | 230 | cr.set_source_rgb(line.lcolor[0], line.lcolor[1], line.lcolor[2]) 231 | x = 0 232 | for num in range(0, line.val_number()): 233 | if self.height_change or line.y[num] < 0: 234 | line.y[num] = self.prev_height - line.val[num] * self.y_ratio 235 | if line.val[num] > self.line_max: 236 | self.line_max = line.val[num] 237 | if num == 0: 238 | cr.move_to(x, line.y[num]) 239 | else: 240 | cr.line_to(x, line.y[num]) 241 | x += self.entry_width 242 | cr.stroke() 243 | 244 | #Timer --------------------------------------------------------- 245 | def timer_cb(self): 246 | for line in self.lines: 247 | val = 0 248 | try: 249 | val = line.load_new_val() 250 | except: 251 | print("Load new value from "+line.name+" fail because:") 252 | traceback.print_exc() 253 | line.entry.set_text(str(val)) 254 | if self.logfd: 255 | self.write_csv(str(val)+",") 256 | if self.logfd: 257 | self.write_csv("\n") 258 | self.darea.queue_draw() 259 | return True 260 | 261 | def timer_remove_first_record(self): 262 | if self.lines[0].val_number() > 0: 263 | for line in self.lines: 264 | line.remove_head(1) 265 | return False 266 | else: 267 | return True 268 | 269 | def write_csv(self, msg): 270 | try: 271 | self.logfd.write(msg) 272 | except: 273 | self.dialog_error("Writ CSV file got error") 274 | widget.set_active(False) 275 | self.logfd.close() 276 | self.logfd = False 277 | 278 | #Menubar ------------------------------------------------------- 279 | def mb_save(self, widget): 280 | if widget.active: 281 | md = gtk.FileChooserDialog(title="Save log to a CSV file", action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OK, gtk.RESPONSE_OK)) 282 | md.set_do_overwrite_confirmation(True) 283 | md.set_current_name("pe.csv") 284 | if md.run() == gtk.RESPONSE_OK: 285 | try: 286 | self.logfd = open(md.get_filename(), "w") 287 | for line in self.lines: 288 | self.logfd.write(line.name + ",") 289 | self.logfd.write("\n") 290 | for i in range(0, self.lines[0].val_number()): 291 | for line in self.lines: 292 | self.logfd.write(str(line.val[i]) + ",") 293 | self.logfd.write("\n") 294 | except: 295 | if self.logfd: 296 | self.logfd.close() 297 | self.logfd = False 298 | self.dialog_error("Try to open file "+md.get_filename()+" got error") 299 | widget.set_active(False) 300 | else: 301 | widget.set_active(False) 302 | md.destroy() 303 | else: 304 | if self.logfd: 305 | self.logfd.close() 306 | self.logfd = False 307 | 308 | def mb_clean(self, widget): 309 | for line in self.lines: 310 | line.remove_head(0) 311 | self.darea.queue_draw() 312 | 313 | def show_buttons(self, widget): 314 | if widget.active: 315 | for e in self.button_hboxes: 316 | e.show() 317 | else: 318 | for e in self.button_hboxes: 319 | e.hide() 320 | 321 | #Button -------------------------------------------------------- 322 | def button_click(self, widget): 323 | if widget.get_active(): 324 | self.set_button_color(widget, gtk.gdk.Color("#FFFFFF")) 325 | else: 326 | self.set_button_color(widget, widget.line.bcolor) 327 | for val in widget.line.val: 328 | if val > self.max_value: 329 | self.max_value = val 330 | self.y_ratio = 0 331 | self.darea.queue_draw() 332 | 333 | def set_button_color(self, button, color): 334 | style = button.get_style().copy() 335 | style.bg[gtk.STATE_NORMAL] = color 336 | style.bg[gtk.STATE_ACTIVE] = color 337 | style.bg[gtk.STATE_PRELIGHT] = color 338 | style.bg[gtk.STATE_SELECTED] = color 339 | style.bg[gtk.STATE_INSENSITIVE] = color 340 | button.set_style(style) 341 | 342 | #Dialog ------------------------------------------------------- 343 | def dialog_error(self, msg): 344 | md = gtk.MessageDialog(self,gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) 345 | md.run() 346 | md.destroy() 347 | -------------------------------------------------------------------------------- /add-ons/gtpwin_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | #To use inside GDB, need set the dir of gtpwin.py to this part. 5 | sys.path.append('/home/teawater/kernel/svn/trunk/add-ons') 6 | 7 | import gtpwin 8 | 9 | nnn = 100 10 | 11 | class example(gtpwin.gtpline): 12 | def load_new_val(self): 13 | global nnn 14 | nnn += 20 15 | self.add(nnn) 16 | return nnn 17 | 18 | l = [example("a"), example("b")] 19 | l.append(example("wwwwwwww")) 20 | l.append(example("wwwwwwww11")) 21 | l.append(example("wwwwwwww")) 22 | l.append(example("wwwwwwww")) 23 | l.append(example("wwwwwwww")) 24 | l.append(example("wwwwwwww")) 25 | l.append(example("wwwwwwww")) 26 | win = gtpwin.gtpwin(l, "test") 27 | gtpwin.run() 28 | del(win) 29 | -------------------------------------------------------------------------------- /add-ons/hotcode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This script is used to find the hotcode in some tasks 4 | # GPL 5 | # Copyright(C) Hui Zhu (teawater@gmail.com), 2012 6 | 7 | import gdb 8 | import tempfile 9 | import os 10 | import signal 11 | import sys 12 | import traceback 13 | import time 14 | 15 | class hotcode_list: 16 | def __init__(self): 17 | self.function_list = {} 18 | self.file_list = {} 19 | self.line_list = {} 20 | self.function_list_line = {} 21 | self.file_list_line = {} 22 | self.num = 0 23 | 24 | class task: 25 | def __init__(self, fid, user_dir): 26 | self.fid = fid 27 | self.user_dir = user_dir 28 | self.kernel = hotcode_list() 29 | self.user = hotcode_list() 30 | 31 | debug_dir = "/usr/lib/debug/" 32 | task_list = {} 33 | no_task = False 34 | kernel_hotcode_list = hotcode_list() 35 | 36 | output_html = True 37 | output_html_file = "./hotcode.html" 38 | show_line_number_default = 20 39 | show_line_number = show_line_number_default 40 | 41 | #-------------------------------------------------------------------------------------------------- 42 | #For signal handler 43 | 44 | from operator import itemgetter 45 | def dict_sort(d, reverse=False): 46 | #proposed in PEP 265, using the itemgetter 47 | return sorted(d.iteritems(), key=itemgetter(1), reverse=True) 48 | 49 | def hotcode_show_code_list(string, code_list): 50 | if len(code_list) > 0: 51 | print "\t", string 52 | i = 1 53 | for c in dict_sort(code_list): 54 | print "\t", c[0], "\t\t", c[1] 55 | i += 1 56 | if i > show_line_number: 57 | break 58 | print 59 | 60 | def hotcode_show(): 61 | if no_task: 62 | hotcode_show_code_list("Hotest function", kernel_hotcode_list.function_list) 63 | hotcode_show_code_list("Hotest file", kernel_hotcode_list.file_list) 64 | hotcode_show_code_list("Hotest line", kernel_hotcode_list.line_list) 65 | else: 66 | for pid in task_list: 67 | print "task", str(pid), task_list[pid].user_dir 68 | print "Kernel hotcode:" 69 | hotcode_show_code_list("Hotest function", task_list[pid].kernel.function_list) 70 | hotcode_show_code_list("Hotest file", task_list[pid].kernel.file_list) 71 | hotcode_show_code_list("Hotest line", task_list[pid].kernel.line_list) 72 | print "User hotcode:" 73 | hotcode_show_code_list("Hotest function", task_list[pid].user.function_list) 74 | hotcode_show_code_list("Hotest file", task_list[pid].user.file_list) 75 | hotcode_show_code_list("Hotest line", task_list[pid].user.line_list) 76 | print 77 | 78 | html_id = 0 79 | 80 | def hotcode_list_to_output_html_fd_1(llist, tlist, fd): 81 | global html_id 82 | i = 1 83 | for c in dict_sort(llist): 84 | if tlist != None: 85 | fd.write(''''''+str(c[0])+''''''+str(c[1])+'''''') 86 | fd.write('''''') 87 | for d in dict_sort(tlist[c[0]]): 88 | fd.write("") 89 | fd.write('
" + str(d[0]) + '''''' + str(d[1]) + "
') 90 | else: 91 | fd.write(''+str(c[0])+''''''+str(c[1])+'''''') 92 | i += 1 93 | html_id += 1 94 | if i > show_line_number: 95 | break 96 | 97 | def hotcode_list_to_output_html_fd(hlist, fd): 98 | global html_id 99 | fd.write('''Hot functions list''') 100 | hotcode_list_to_output_html_fd_1(hlist.function_list, hlist.function_list_line, fd) 101 | 102 | fd.write('''Hot file list''') 103 | hotcode_list_to_output_html_fd_1(hlist.file_list, hlist.file_list_line, fd) 104 | 105 | fd.write('''Hot line list''') 106 | hotcode_list_to_output_html_fd_1(hlist.line_list, None, fd) 107 | 108 | def hotcode_to_output_html_file(): 109 | global html_id 110 | html_id = 0 111 | fd = open(output_html_file, "w") 112 | fd.write(''' 113 | Hotcode 114 | 127 | 128 |
This file is generated by KGTP (http://code.google.com/p/kgtp/) in ''' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '''.
129 |
Click the function name or file name to see the detailed info.
''') 130 | if show_line_number > 0: 131 | fd.write('''
Just show top 20 of each list.
''') 132 | if no_task: 133 | fd.write('

') 134 | fd.write('''''') 135 | fd.write('''''') 136 | hotcode_list_to_output_html_fd(kernel_hotcode_list, fd) 137 | fd.write('
Kernel space hotcode list'''+str(kernel_hotcode_list.num)+'''
') 138 | else: 139 | for pid in task_list: 140 | fd.write('

') 141 | fd.write('''''') 142 | fd.write('''") 143 | if trace_user: 144 | fd.write('''''') 145 | fd.write('''''') 146 | hotcode_list_to_output_html_fd(task_list[pid].user, fd) 147 | if trace_kernel: 148 | if trace_user: 149 | fd.write('''''') 150 | fd.write('''''') 151 | hotcode_list_to_output_html_fd(task_list[pid].kernel, fd) 152 | fd.write('
pid:''' + str(pid) + " " + task_list[pid].user_dir + "
User space hotcode list
User space hotcode list'''+str(task_list[pid].user.num)+'''
Kernel space hotcode list'''+str(task_list[pid].kernel.num)+'''
') 153 | fd.write('') 154 | fd.close() 155 | print "Save", html_id, "entries." 156 | 157 | def sigint_handler(num, e): 158 | if output_html: 159 | hotcode_to_output_html_file() 160 | else: 161 | hotcode_show() 162 | try: 163 | s = raw_input('Conitnue? [(y)es], (n)o:') 164 | except: 165 | s = 'y' 166 | finally: 167 | if s[0:1] != 'n' and s[0:1] != 'N': 168 | return; 169 | #gdb.execute("inferior 1") 170 | try: 171 | gdb.execute("tfind -1", True, False) 172 | gdb.execute("target remote /sys/kernel/debug/gtp", True, False) 173 | gdb.execute("set disconnected-tracing off", True, False) 174 | except: 175 | print "Try to stop GTP got error, please use command \"sudo rmmod gtp.ko\" stop it." 176 | exit(1); 177 | #-------------------------------------------------------------------------------------------------- 178 | #init 179 | 180 | def add_inferior(): 181 | fid = gdb.execute("add-inferior", False, True) 182 | if fid.find("Added inferior ") != 0: 183 | return -1 184 | fid = int(fid[len("Added inferior "):]) 185 | return fid 186 | 187 | gdb.execute("set target-async on", True, False) 188 | gdb.execute("set pagination off", True, False) 189 | gdb.execute("set confirm off", True, False) 190 | gdb.execute("set circular-trace-buffer on", True, False) 191 | gdb.execute("set debug-file-directory "+debug_dir, True, False) 192 | try: 193 | gdb.execute("kill", True, False) 194 | except: 195 | pass 196 | 197 | trace_user = True 198 | trace_kernel = True 199 | while 1: 200 | tmp = "both" 201 | try: 202 | tmp = raw_input('Which part of code you want trace? [(b)oth], (u)ser, (k)ernel:') 203 | except: 204 | continue 205 | if tmp[0:1] == 'U' or tmp[0:1] == 'u': 206 | trace_kernel = False 207 | elif tmp[0:1] == 'K' or tmp[0:1] == 'k': 208 | trace_user = False 209 | break 210 | 211 | #Get which task pid why want to trace 212 | print("Please input the pid of task that you want to trace - one per line.") 213 | print("If not set any task, will trace all code in the Linux kernel.") 214 | while 1: 215 | pid = -1 216 | try: 217 | pid = input('task pid (use empty to stop pid input):') 218 | except: 219 | pass 220 | if pid <= 0: 221 | break 222 | if pid in task_list: 223 | print("This pid already in the list.") 224 | continue 225 | user_dir = "" 226 | fid = 0 227 | if trace_user: 228 | try: 229 | orig_user_dir = user_dir = os.path.realpath("/proc/"+str(pid)+"/exe") 230 | except: 231 | #maybe this is the kernel task 232 | print "Cannot get the user code info of this pid, will not parse the user level code symbol" 233 | task_list[pid] = task(fid, user_dir) 234 | continue 235 | if os.path.exists(debug_dir+user_dir): 236 | user_dir = debug_dir+user_dir 237 | while 1: 238 | tmp = "" 239 | try: 240 | tmp = raw_input('Please input the debug binary of task if you want to change it ['+user_dir+']:') 241 | except: 242 | continue 243 | if tmp != "": 244 | user_dir = os.path.realpath(tmp) 245 | break 246 | if not os.path.exists(user_dir): 247 | print "Cannot get the user code info of this pid, will not parse the user level code symbol" 248 | task_list[pid] = task(fid, user_dir) 249 | continue 250 | print "Use "+user_dir+" as debug binary." 251 | fid = add_inferior() 252 | if fid < 0: 253 | print "Try to load task got error." 254 | continue 255 | gdb.execute("inferior "+str(fid)) 256 | pfile = open("/proc/"+str(pid)+"/maps", "r") 257 | tmplist = pfile.read().split(os.linesep) 258 | pfile.close() 259 | for c in tmplist: 260 | c_list = c.split(" ") 261 | filename = c_list[-1].strip() 262 | if filename != orig_user_dir and os.path.exists(filename) and len(c_list) > 2 and len(c_list[1]) > 3 and c_list[1][2] == 'x': 263 | addr = "0x"+c_list[0][0:c.find('-')] 264 | gdb.execute("file "+filename) 265 | info_files = gdb.execute("info files", True, True) 266 | info_files_list = info_files.split(os.linesep) 267 | text_offset = "0x0" 268 | for line in info_files_list: 269 | line_list = line.split(" is ") 270 | if len(line_list) == 2 and line_list[1].strip() == ".text": 271 | line_list[0] = line_list[0].strip() 272 | text_offset = line_list[0][0:line_list[0].find(' - ')] 273 | print ("add-symbol-file "+filename+" ("+addr+"+"+text_offset+")") 274 | gdb.execute("add-symbol-file "+filename+" ("+addr+"+"+text_offset+")") 275 | gdb.execute("file "+user_dir) 276 | gdb.execute("inferior 1") 277 | task_list[pid] = task(fid, user_dir) 278 | 279 | def get_addr_range_list(fun): 280 | buf = gdb.execute("info line "+fun, False, True) 281 | line_list = buf.split(os.linesep) 282 | ret = [] 283 | begin = -1 284 | end = -1 285 | for line in line_list: 286 | addr_begin = line.find("starts at address ") 287 | if addr_begin >= 0: 288 | line = line[addr_begin + len("starts at address "):] 289 | addr_end = line.find(" <"+fun) 290 | if addr_end >= 0: 291 | begin = int(line[:addr_end], 0) 292 | line = line[addr_end + len(" <"+fun):] 293 | addr_begin = line.find("ends at ") 294 | if addr_begin >= 0: 295 | line = line[addr_begin + len("ends at "):] 296 | addr_end = line.find(" <"+fun) 297 | if addr_end > 0: 298 | end = int(line[:addr_end], 0) 299 | if begin != -1: 300 | ret.append([begin, end]) 301 | begin = -1 302 | end = -1 303 | 304 | if len(ret) > 0: 305 | buf = gdb.execute("disassemble "+fun, False, True) 306 | line_list = buf.split(os.linesep) 307 | line_list.reverse() 308 | end = 0 309 | for line in line_list: 310 | addr_begin = line.find("0x") 311 | if addr_begin >= 0: 312 | line = line[addr_begin:] 313 | addr_end = line.find(" <+") 314 | if addr_end > 0: 315 | end = int(line[:addr_end], 0) + 1 316 | break 317 | if end != 0: 318 | offset = 0 319 | for c in ret: 320 | if c[1] < end: 321 | if offset == 0 or offset > (end - c[1]): 322 | offset = end - c[1] 323 | for c in ret: 324 | c[1] += offset 325 | 326 | return ret 327 | 328 | def get_ignore_str(function): 329 | ret = "" 330 | try: 331 | s = raw_input('Do you want to ignore function \"'+function+'\"? [(y)es], (n)o:') 332 | except: 333 | s = 'y' 334 | if s[0:1] != 'n' and s[0:1] != 'N': 335 | r_list = get_addr_range_list(function) 336 | for r in r_list: 337 | if ret != "": 338 | ret += " && " 339 | else: 340 | ret += "&& (" 341 | #(regs->ip < r[0] || regs->ip > r[1]) 342 | ret += "($p_ip < "+str(r[0])+" || $p_ip > "+str(r[1])+")" 343 | if ret != "": 344 | ret += ")" 345 | return ret 346 | 347 | if len(task_list) == 0: 348 | trace_user = False 349 | trace_kernel = True 350 | no_task = True 351 | 352 | try: 353 | s = raw_input('Which way you want to output hotcode info when ctrl-c? [(h)tml], (t)ty:') 354 | except: 355 | s = 'h' 356 | if s[0:1] == 't' or s[0:1] == 'T': 357 | output_html = False 358 | else: 359 | output_html = True 360 | 361 | if output_html: 362 | while 1: 363 | try: 364 | s = raw_input('Which file you want to save the html output? [' + output_html_file + ']:') 365 | if os.path.exists(s): 366 | if os.path.isfile(s): 367 | s = raw_input('File ' + s +' exist, do you want to over write it? (y)es, [(n)o]:') 368 | if s[0:1] != 'y' and s[0:1] != 'Y': 369 | continue 370 | else: 371 | print 'File ' + s +' exist, but it cannot be written. Please choice another file.' 372 | continue 373 | except: 374 | continue 375 | if len(s) > 0: 376 | output_html_file = s 377 | break 378 | 379 | try: 380 | show_line_number = input('Show line number (0 meas all)? ['+str(show_line_number)+']:') 381 | except: 382 | show_line_number = show_line_number_default 383 | 384 | #Set tracepoint 385 | gdb.execute("target remote /sys/kernel/debug/gtp", True, False) 386 | 387 | try: 388 | gdb.execute("tstop", True, False) 389 | gdb.execute("delete", True, False) 390 | except: 391 | pass 392 | 393 | 394 | def getmod(): 395 | #following code is get from ../getmod.py 396 | #use the code directly because sys.argv = [''] inside GDB 397 | def format_file(name): 398 | tmp = "" 399 | for c in name: 400 | if c == "_": 401 | c = "-" 402 | tmp += c 403 | return tmp 404 | 405 | #Check if the target is available 406 | if str(gdb.selected_thread()) == "None": 407 | raise gdb.error("Please connect to Linux Kernel before use the script.") 408 | 409 | #Output the help 410 | print "Use GDB command \"set $mod_search_dir=dir\" to set an directory for search the modules." 411 | 412 | ignore_gtp_ko = gdb.parse_and_eval("$ignore_gtp_ko") 413 | if ignore_gtp_ko.type.code == gdb.TYPE_CODE_INT: 414 | ignore_gtp_ko = int(ignore_gtp_ko) 415 | else: 416 | ignore_gtp_ko = 1 417 | 418 | #Get the mod_search_dir 419 | mod_search_dir_list = [] 420 | #Get dir from $mod_search_dir 421 | tmp_dir = gdb.parse_and_eval("$mod_search_dir") 422 | if tmp_dir.type.code == gdb.TYPE_CODE_ARRAY: 423 | tmp_dir = str(tmp_dir) 424 | tmp_dir = tmp_dir[1:len(tmp_dir)] 425 | tmp_dir = tmp_dir[0:tmp_dir.index("\"")] 426 | mod_search_dir_list.append(tmp_dir) 427 | #Get dir that same with current vmlinux 428 | tmp_dir = str(gdb.execute("info files", False, True)) 429 | tmp_dir = tmp_dir[tmp_dir.index("Symbols from \"")+len("Symbols from \""):len(tmp_dir)] 430 | tmp_dir = tmp_dir[0:tmp_dir.index("\"")] 431 | tmp_dir = tmp_dir[0:tmp_dir.rindex("/")] 432 | mod_search_dir_list.append(tmp_dir) 433 | #Get the dir of current Kernel 434 | tmp_dir = "/lib/modules/" + str(os.uname()[2]) 435 | if os.path.isdir(tmp_dir): 436 | mod_search_dir_list.append(tmp_dir) 437 | #Let user choice dir 438 | mod_search_dir = "" 439 | while mod_search_dir == "": 440 | for i in range(0, len(mod_search_dir_list)): 441 | print str(i)+". "+mod_search_dir_list[i] 442 | try: 443 | s = input('Select a directory for search the modules [0]:') 444 | except SyntaxError: 445 | s = 0 446 | except: 447 | continue 448 | if s < 0 or s >= len(mod_search_dir_list): 449 | continue 450 | mod_search_dir = mod_search_dir_list[s] 451 | 452 | mod_list_offset = long(gdb.parse_and_eval("((size_t) &(((struct module *)0)->list))")) 453 | mod_list = long(gdb.parse_and_eval("(&modules)")) 454 | mod_list_current = mod_list 455 | 456 | while 1: 457 | mod_list_current = long(gdb.parse_and_eval("((struct list_head *) "+str(mod_list_current)+")->next")) 458 | 459 | #check if need break the loop 460 | if mod_list == mod_list_current: 461 | break 462 | 463 | mod = mod_list_current - mod_list_offset 464 | 465 | #get mod_name 466 | mod_name = str(gdb.parse_and_eval("((struct module *)"+str(mod)+")->name")) 467 | mod_name = mod_name[mod_name.index("\"")+1:len(mod_name)] 468 | mod_name = mod_name[0:mod_name.index("\"")] 469 | if mod_name == "fglrx": 470 | contiue 471 | mod_name += ".ko" 472 | mod_name = format_file(mod_name) 473 | 474 | #get mod_dir_name 475 | mod_dir_name = "" 476 | for root, dirs, files in os.walk(mod_search_dir): 477 | for afile in files: 478 | tmp_file = format_file(afile) 479 | if tmp_file == mod_name: 480 | mod_dir_name = os.path.join(root,afile) 481 | break 482 | if mod_dir_name != "": 483 | break 484 | 485 | command = " " 486 | 487 | #Add module_core to command 488 | command += str(gdb.parse_and_eval("((struct module *)"+str(mod)+")->module_core")) 489 | 490 | #Add each sect_attrs->attrs to command 491 | #get nsections 492 | nsections = int(gdb.parse_and_eval("((struct module *)"+str(mod)+")->sect_attrs->nsections")) 493 | sect_attrs = long(gdb.parse_and_eval("(u64)((struct module *)"+str(mod)+")->sect_attrs")) 494 | for i in range(0, nsections): 495 | command += " -s" 496 | tmp = str(gdb.parse_and_eval("((struct module_sect_attrs *)"+str(sect_attrs)+")->attrs["+str(i)+"].name")) 497 | tmp = tmp[tmp.index("\"")+1:len(tmp)] 498 | tmp = tmp[0:tmp.index("\"")] 499 | command += " "+tmp 500 | tmp = str(gdb.parse_and_eval("((struct module_sect_attrs *)"+str(sect_attrs)+")->attrs["+str(i)+"].address")) 501 | command += " "+tmp 502 | 503 | if mod_dir_name == "": 504 | print "Cannot find out",mod_name,"from directory." 505 | print "Please use following command load the symbols from it:" 506 | print "add-symbol-file some_dir/"+mod_name+command 507 | else: 508 | if ignore_gtp_ko and mod_name == "gtp.ko": 509 | pass 510 | else: 511 | #print "add-symbol-file "+mod_dir_name+command 512 | gdb.execute("add-symbol-file "+mod_dir_name+command, False, False) 513 | 514 | if trace_kernel: 515 | try: 516 | s = raw_input('Do you load the symbol from LKM? (y)es, [(n)o]:') 517 | except: 518 | s = 'n' 519 | if s[0:1] == 'y' or s[0:1] == 'Y': 520 | getmod() 521 | 522 | cpu_number = int(gdb.parse_and_eval("$cpu_number")) 523 | tempfilename = tempfile.mktemp() 524 | tempfile = open(tempfilename, "w") 525 | if no_task: 526 | ignore_str = "" 527 | #Setup first tracepoint 528 | ignore_str += get_ignore_str("arch_local_irq_enable") 529 | ignore_str += get_ignore_str("intel_idle") 530 | # GDB have bug with long conditon so close them 531 | #ignore_str += get_ignore_str("__do_softirq") 532 | #ignore_str += get_ignore_str("_raw_spin_unlock_irqrestore") 533 | 534 | tempfile.write("tvariable $p_ip\n") 535 | tempfile.write("tvariable $p_cs\n") 536 | tempfile.write("trace handle_irq\n") 537 | tempfile.write("commands\n") 538 | tempfile.write("teval $p_ip=(u64)regs->ip\n") 539 | tempfile.write("teval $p_cs=(u64)regs->cs\n") 540 | tempfile.write("end\n") 541 | #Setup second tracepoint 542 | tempfile.write("trace handle_irq\n") 543 | cond_str = " (($p_cs & 3) == 0)" 544 | tempfile.write("condition $bpnum "+cond_str+ignore_str+"\n") 545 | tempfile.write("commands\n") 546 | #tempfile.write("collect $no_self_trace\n") 547 | tempfile.write("collect $p_ip\n") 548 | tempfile.write("end\n") 549 | tempfile.write("trace smp_apic_timer_interrupt\n") 550 | tempfile.write("commands\n") 551 | tempfile.write("teval $p_ip=(u64)regs->ip\n") 552 | tempfile.write("teval $p_cs=(u64)regs->cs\n") 553 | tempfile.write("end\n") 554 | #Setup second tracepoint 555 | tempfile.write("trace smp_apic_timer_interrupt\n") 556 | cond_str = " (($p_cs & 3) == 0)" 557 | tempfile.write("condition $bpnum "+cond_str+ignore_str+"\n") 558 | tempfile.write("commands\n") 559 | #tempfile.write("collect $no_self_trace\n") 560 | tempfile.write("collect $p_ip\n") 561 | tempfile.write("end\n") 562 | else: 563 | pid_str = "" 564 | for pid in task_list: 565 | if pid_str != "": 566 | pid_str += " || " 567 | else: 568 | pid_str += "(" 569 | pid_str += "($current_task_pid == "+str(pid)+") " 570 | if pid_str != "": 571 | pid_str += ")" 572 | cond_str = "" 573 | if not trace_user: 574 | if pid_str != "": 575 | cond_str += " && " 576 | cond_str += " ((regs->cs & 3) == 0)" 577 | elif not trace_kernel: 578 | if pid_str != "": 579 | cond_str += "&&" 580 | cond_str += " ((regs->cs & 3) == 3)" 581 | tempfile.write("trace handle_irq\n") 582 | tempfile.write("condition $bpnum "+pid_str+cond_str+"\n") 583 | tempfile.write("commands\n") 584 | tempfile.write("collect regs->ip\n") 585 | if trace_user and trace_kernel: 586 | tempfile.write("collect regs->cs\n") 587 | tempfile.write("collect $current_task_pid\n") 588 | tempfile.write("end\n") 589 | tempfile.write("trace smp_apic_timer_interrupt\n") 590 | tempfile.write("condition $bpnum "+pid_str+cond_str+"\n") 591 | tempfile.write("commands\n") 592 | tempfile.write("collect regs->ip\n") 593 | if trace_user and trace_kernel: 594 | tempfile.write("collect regs->cs\n") 595 | tempfile.write("collect $current_task_pid\n") 596 | tempfile.write("end\n") 597 | tempfile.close() 598 | tempfile = open(tempfilename, "r") 599 | print "Tracepoint command:" 600 | print tempfile.read() 601 | tempfile.close() 602 | gdb.execute("source "+tempfilename, True, False) 603 | os.remove(tempfilename) 604 | gdb.execute("set disconnected-tracing on", True, False) 605 | gdb.execute("tstart") 606 | gdb.execute("kill", True, False) 607 | 608 | signal.signal(signal.SIGINT, sigint_handler); 609 | signal.siginterrupt(signal.SIGINT, False); 610 | 611 | #Connect to pipe 612 | gdb.execute("target tfile /sys/kernel/debug/gtpframe_pipe") 613 | 614 | #-------------------------------------------------------------------------------------------------- 615 | #cycle 616 | 617 | def add_line_to_list(line, line_list): 618 | if line in line_list: 619 | line_list[line] += 1 620 | else: 621 | line_list[line] = 1 622 | 623 | #info[0] line_num, info[1] file_name, info[2] function_name 624 | def add_info_to_code_list(info, code_list): 625 | line = str(info[1]) + ":" + str(info[0]) 626 | #function_list 627 | if info[2] in code_list.function_list: 628 | code_list.function_list[info[2]] += 1 629 | else: 630 | code_list.function_list[info[2]] = 1 631 | code_list.function_list_line[info[2]] = {} 632 | add_line_to_list(line, code_list.function_list_line[info[2]]) 633 | #file_list 634 | if info[1] in code_list.file_list: 635 | code_list.file_list[info[1]] += 1 636 | else: 637 | code_list.file_list[info[1]] = 1 638 | code_list.file_list_line[info[1]] = {} 639 | add_line_to_list(line, code_list.file_list_line[info[1]]) 640 | #line_list 641 | add_line_to_list(line, code_list.line_list) 642 | #num 643 | code_list.num += 1 644 | 645 | def task_list_add_line(is_user, pid, info): 646 | global task_list 647 | if no_task: 648 | add_info_to_code_list (info, kernel_hotcode_list) 649 | else: 650 | if is_user: 651 | add_info_to_code_list (info, task_list[pid].user) 652 | else: 653 | add_info_to_code_list (info, task_list[pid].kernel) 654 | 655 | def get_line_from_sym(sym): 656 | sym = sym.rstrip(os.linesep) 657 | 658 | #Get line_num and file_name 659 | begin = sym.find("Line ") 660 | end = sym.find("\" starts at address") 661 | line_num = None 662 | file_name = None 663 | if begin >= 0 and end > 0 and begin + len("Line ") < end: 664 | line = sym[begin + len("Line "):end] 665 | line = line.split(" of \"") 666 | if len(line) == 2: 667 | line_num = line[0] 668 | file_name = line[1] 669 | sym = sym[end:] 670 | 671 | #Get function_name 672 | begin = sym.find("<") 673 | end = sym.find(">") 674 | if begin >= 0 and end > 0 and begin + 1 < end: 675 | function_name = sym[begin + 1:end] 676 | end = function_name.rfind("+") 677 | if end > 0: 678 | function_name = function_name[:end] 679 | sym = gdb.execute("info symbol "+function_name, True, True).rstrip(os.linesep) 680 | begin = sym.rfind(" of ") 681 | if begin > 0: 682 | begin += len(" of ") 683 | function_name = sym[begin:] + ":" + function_name 684 | else: 685 | function_name = None 686 | return (line_num, file_name, function_name) 687 | 688 | if no_task: 689 | while 1: 690 | try: 691 | gdb.execute("tfind 0", False, True) 692 | sym = gdb.execute("info line *($p_ip - 1)", True, True) 693 | line = get_line_from_sym(sym) 694 | task_list_add_line(False, 0, line) 695 | except gdb.error, x: 696 | print("Drop one entry because:") 697 | for file, lineno, function, text in traceback.extract_tb(sys.exc_info()[2]): 698 | print file, lineno, function, text 699 | except gdb.MemoryError, x: 700 | print("Drop one entry because:") 701 | for file, lineno, function, text in traceback.extract_tb(sys.exc_info()[2]): 702 | print file, lineno, function, text 703 | try: 704 | gdb.execute("tfind 1", False, True) 705 | except: 706 | pass 707 | else: 708 | while 1: 709 | try: 710 | gdb.execute("tfind 0", False, True) 711 | is_user = False 712 | pid = long(gdb.parse_and_eval("$current_task_pid")) 713 | if not pid in task_list: 714 | raise gdb.error ("Cannot find inferior for pid "+ str(pid) +", drop one entry.") 715 | if trace_user and (not trace_kernel or long(gdb.parse_and_eval("regs->cs & 3")) == 3): 716 | is_user = True 717 | ip = long(gdb.parse_and_eval("regs->ip - 1")) 718 | gdb.execute("inferior "+str(task_list[pid].fid), False, True) 719 | sym = gdb.execute("info line *"+str(ip), True, True) 720 | else: 721 | sym = gdb.execute("info line *(regs->ip - 1)", True, True) 722 | line = get_line_from_sym(sym) 723 | if is_user: 724 | gdb.execute("inferior 1", False, True) 725 | task_list_add_line(is_user, pid, line) 726 | except gdb.error, x: 727 | print("Drop one entry because:") 728 | for file, lineno, function, text in traceback.extract_tb(sys.exc_info()[2]): 729 | print file, lineno, function, text 730 | try: 731 | gdb.execute("inferior 1", False, True) 732 | except: 733 | pass 734 | except gdb.MemoryError, x: 735 | print("Drop one entry because:") 736 | for file, lineno, function, text in traceback.extract_tb(sys.exc_info()[2]): 737 | print file, lineno, function, text 738 | try: 739 | gdb.execute("inferior 1", False, True) 740 | except: 741 | pass 742 | try: 743 | gdb.execute("tfind 1", False, True) 744 | except: 745 | pass 746 | -------------------------------------------------------------------------------- /add-ons/pe.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This script is used to show the performance counters in graph mode 4 | # GPL 5 | # Copyright(C) Hui Zhu (teawater@gmail.com), 2011 6 | 7 | 8 | pe_list = [] 9 | #0 type, 1 config, 2 name 10 | #typt and config can get from https://code.google.com/p/kgtp/wiki/HOWTO#How_to_use_performance_counters 11 | pe_list.append(["0","0", "CPU_CYCLES"]) 12 | pe_list.append(["0","1", "INSTRUCTIONS"]) 13 | pe_list.append(["0","2", "CACHE_REFERENCES"]) 14 | pe_list.append(["0","3", "CACHE_MISSES"]) 15 | pe_list.append(["0","4", "BRANCH_INSTRUCTIONS"]) 16 | pe_list.append(["0","5", "BRANCH_MISSES"]) 17 | pe_list.append(["0","6", "BUS_CYCLES"]) 18 | #pe_list.append(["3","0", "L1D_READ_ACCESS"]) 19 | #pe_list.append(["3","1", "L1I_READ_ACCESS"]) 20 | 21 | #sleep time 22 | sleep_sec = 1 23 | 24 | #0 text 1 gtk 25 | gui_type = 1 26 | 27 | in_gdb = False 28 | 29 | 30 | pe_list_type = 0 31 | pe_list_config = 1 32 | pe_list_name = 2 33 | pe_list_prev = 3 34 | pe_list_qtv = 4 35 | 36 | if in_gdb: 37 | import gdb 38 | else: 39 | import os 40 | 41 | 42 | class kgtp: 43 | fd = -1 44 | retry_count = 3 45 | buf_max = 1024 46 | tvariable = {} 47 | tvariable_next_number = 0 48 | 49 | def __init__(self): 50 | #Open fd 51 | try: 52 | self.fd = os.open("/sys/kernel/debug/gtp", os.O_RDWR) 53 | except: 54 | print "Please do not forget insmod and sudo." 55 | exit(0) 56 | 57 | def __del__(self): 58 | if self.fd >= 0: 59 | os.close(self.fd) 60 | 61 | def read_fd(self): 62 | try: 63 | buf = os.read(self.fd, self.buf_max) 64 | except: 65 | return False 66 | return buf 67 | 68 | def write_fd(self, msg): 69 | try: 70 | buf = os.write(self.fd, msg) 71 | except: 72 | return False 73 | return True 74 | 75 | def read(self): 76 | for i in range(0, self.retry_count): 77 | if i != 0: 78 | self.write_fd("-") 79 | 80 | buf = self.read_fd() 81 | if buf == False: 82 | continue 83 | buf_len = len(buf) 84 | if buf_len < 4: 85 | continue 86 | 87 | csum = 0 88 | for i in range(0, buf_len - 2): 89 | if i == 0: 90 | if buf[i] != "$": 91 | retry = True 92 | break 93 | elif buf[i] == '#': 94 | break 95 | else: 96 | csum += ord(buf[i]) 97 | if i == 0 or buf[i] != "#": 98 | continue 99 | if int("0x"+buf[i+1:i+3], 16) != (csum & 0xff): 100 | continue 101 | buf = buf[1:i] 102 | self.write_fd("+") 103 | 104 | #print "KGTP read: "+buf 105 | return buf 106 | 107 | print "KGTP read got error" 108 | return False 109 | 110 | def write(self, msg): 111 | for i in range(0, self.retry_count): 112 | if i != 0: 113 | self.write_fd("-") 114 | 115 | csum = 0 116 | for c in msg: 117 | csum += ord(c) 118 | msg = "$"+msg+"#"+"%02x" % (csum & 0xff) 119 | 120 | if self.write_fd(msg) == False: 121 | continue 122 | if self.read_fd() != "+": 123 | continue 124 | 125 | #print "KGTP write: "+msg 126 | return True 127 | 128 | print "KGTP write got error" 129 | return False 130 | 131 | def simple_cmd(self, cmd): 132 | if gtp.write(cmd) == False: 133 | return False 134 | if gtp.read() != "OK": 135 | return False 136 | return True 137 | 138 | def tvariable_init(self): 139 | tvariable = {} 140 | tvariable_next_number = 0 141 | 142 | if gtp.write("qTfV") == False: 143 | return False 144 | ret = gtp.read() 145 | while 1: 146 | if ret == False: 147 | return False 148 | if ret == "l": 149 | return True 150 | ret = ret.split(":") 151 | if len(ret) < 4: 152 | print "KGTP GDBRSP package format error" 153 | return False 154 | if len(ret[3]) % 2 != 0: 155 | print "KGTP GDBRSP package format error" 156 | return False 157 | 158 | #Get name 159 | letter = "" 160 | name = "" 161 | for c in ret[3]: 162 | letter += c 163 | if len(letter) == 2: 164 | name += chr(int("0x"+letter, 16)) 165 | letter = "" 166 | 167 | number = int("0x"+ret[0], 16) 168 | self.tvariable[name] = number 169 | if (number >= self.tvariable_next_number): 170 | self.tvariable_next_number = number + 1 171 | 172 | if gtp.write("qTsV") == False: 173 | return False 174 | ret = gtp.read() 175 | 176 | def tvariable_val(self, number): 177 | return self.tvariable_val_raw("qTV:"+"%x" % number) 178 | 179 | def tvariable_val_raw(self, buf): 180 | if gtp.write(buf) == False: 181 | return 182 | ret = gtp.read() 183 | if ret == False: 184 | return 185 | if ret[0] != "V": 186 | return 187 | 188 | return long("0x"+ret[1:], 16) 189 | 190 | def tvariable_add(self, name, val): 191 | if self.tvariable_next_number == 0: 192 | print "Must call tvariable_init before add tvariable" 193 | return 194 | 195 | buf = "QTDV:" + "%x" % self.tvariable_next_number + ":" + "%x" % val + ":0:" 196 | for c in name: 197 | buf += "%02x" % ord(c) 198 | if gtp.write(buf) == False: 199 | return 200 | if gtp.read() != "OK": 201 | print "Get something wrong when add tvariable to KGTP" 202 | return 203 | 204 | self.tvariable_next_number += 1 205 | return (self.tvariable_next_number - 1) 206 | 207 | def qtinit(self): 208 | return self.simple_cmd("QTinit") 209 | 210 | def tstart(self): 211 | return self.simple_cmd("QTStart") 212 | 213 | def tstop(self): 214 | return self.simple_cmd("QTStop") 215 | 216 | 217 | def each_entry(callback): 218 | global pe_list, cpu_number 219 | for i in range(0, cpu_number): 220 | for e in pe_list: 221 | callback(i, e) 222 | 223 | 224 | def init_pe(i, e): 225 | if (len(e) < pe_list_prev + 1): 226 | e.append([]) 227 | e[pe_list_prev].append(0) 228 | if (len(e) < pe_list_qtv + 1): 229 | e.append([]) 230 | 231 | if in_gdb: 232 | gdb.execute("tvariable $p_pe_type_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i)+"="+e[pe_list_type], True, False) 233 | gdb.execute("tvariable $p_pe_config_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i)+"="+e[pe_list_config], True, False) 234 | gdb.execute("tvariable $p_pe_val_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i)+"=0", True, False) 235 | gdb.execute("tvariable $p_pe_en_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i)+"=1", True, False) 236 | else: 237 | if gtp.tvariable_add("p_pe_type_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i), int(e[pe_list_type])) == None: 238 | exit(0) 239 | if gtp.tvariable_add("p_pe_config_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i), int(e[pe_list_config])) == None: 240 | exit(0) 241 | number = gtp.tvariable_add("p_pe_val_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i), 0) 242 | if number == None: 243 | exit(0) 244 | if gtp.tvariable_add("p_pe_en_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i), 1) == None: 245 | exit(0) 246 | e[pe_list_qtv].append("qTV:"+"%x" % number) 247 | 248 | def init_kgtp(): 249 | global cpu_number 250 | 251 | if in_gdb: 252 | cpu_number = int(gdb.parse_and_eval("$cpu_number")) 253 | #Set the empty tracepoint 254 | gdb.execute("delete tracepoints", False, False) 255 | gdb.execute("trace *0", True, False) 256 | else: 257 | cpu_number = gtp.tvariable_val(gtp.tvariable["cpu_number"]) 258 | if cpu_number == None: 259 | exit(0) 260 | 261 | #Set the pe 262 | each_entry(init_pe) 263 | 264 | import signal 265 | def sigint_handler(num, e): 266 | if in_gdb: 267 | gdb.execute("tstop", True, False) 268 | else: 269 | gtp.tstop() 270 | exit(0) 271 | 272 | 273 | if in_gdb: 274 | #close pagination 275 | gdb.execute("set pagination off", True, False); 276 | #Connect to KGTP if need 277 | if str(gdb.selected_thread()) == "None": 278 | gdb.execute("target remote /sys/kernel/debug/gtp", True, False) 279 | else: 280 | gtp = kgtp() 281 | if gtp.qtinit == False: 282 | exit(0) 283 | if gtp.tvariable_init() == False: 284 | exit(0) 285 | 286 | #Init the status to KGTP 287 | cpu_number = 0 288 | init_kgtp() 289 | signal.signal(signal.SIGINT, sigint_handler) 290 | 291 | 292 | #start 293 | if in_gdb: 294 | gdb.execute("tstart", True, False) 295 | else: 296 | gtp.tstart() 297 | 298 | 299 | #text gui --------------------------------------------------------------------- 300 | #pe_list will be set to:type, config, name, prev_value_list 301 | if gui_type == 0: 302 | import time 303 | def output_pe(i, e): 304 | if in_gdb: 305 | current_value = long(gdb.parse_and_eval("$p_pe_val_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i))) 306 | else: 307 | current_value = gtp.tvariable_val_raw(e[pe_list_qtv][i]) 308 | if current_value == None: 309 | print "Fail when get val from KGTP" 310 | exit(0) 311 | print "cpu"+str(i),e[pe_list_name],current_value-e[pe_list_prev][i] 312 | e[pe_list_prev][i] = current_value 313 | 314 | while 1: 315 | each_entry(output_pe) 316 | print 317 | time.sleep(sleep_sec) 318 | 319 | 320 | #gtk gui ---------------------------------------------------------------------- 321 | #pe_list will be set to:0 type, 1 config, 2 name, 3 prev_value_list, 322 | # 4 value_list, 5 x_list, 6 button_list, 323 | # 7 button_color_list, 8 line_color_list 324 | if gui_type == 1: 325 | #This script need python-gtk2 326 | import gtk 327 | import glib 328 | 329 | pe_list_value = 5 330 | pe_list_x = 6 331 | pe_list_button = 7 332 | pe_list_bcolor = 8 333 | pe_list_lcolor = 9 334 | 335 | pe_color = (0xffb0ff, 0x006000) 336 | 337 | class PyApp(gtk.Window): 338 | #Init ---------------------------------------------------------- 339 | def __init__(self): 340 | global pe_list, cpu_number 341 | 342 | super(PyApp, self).__init__() 343 | 344 | self.max_value = 0 345 | self.prev_width = 0 346 | self.prev_height = 0 347 | self.y_ratio = 0 348 | self.entry_width = 10 349 | self.logfd = False 350 | 351 | #Set the pe 352 | each_entry(self.pe_init_callback) 353 | 354 | #Set the color 355 | num = len(pe_list) * cpu_number 356 | block = (pe_color[0] - pe_color[1]) / float(num) 357 | color = pe_color[1] 358 | for i in range(0, cpu_number): 359 | for e in pe_list: 360 | e[pe_list_bcolor].append(gtk.gdk.Color("#"+ "%06x" % int(color))) 361 | e[pe_list_lcolor].append((((int(color) >> 16) / float(0xff) * 1), ((int(color) >> 8 & 0xff) / float(0xff) * 1), ((int(color) & 0xff) / float(0xff) * 1))) 362 | color += block 363 | 364 | #Set window 365 | self.set_title("KGTP") 366 | self.connect("destroy", gtk.main_quit) 367 | gtk.Window.maximize(self) 368 | 369 | #menubar 370 | mb = gtk.MenuBar() 371 | #file 372 | filemenu = gtk.Menu() 373 | filem = gtk.MenuItem("File") 374 | filem.set_submenu(filemenu) 375 | save = gtk.CheckMenuItem("Save log to a CSV file") 376 | save.connect("activate", self.mb_save) 377 | save.set_active(False) 378 | exit = gtk.MenuItem("Exit") 379 | exit.connect("activate", gtk.main_quit) 380 | filemenu.append(save) 381 | filemenu.append(gtk.SeparatorMenuItem()) 382 | filemenu.append(exit) 383 | mb.append(filem) 384 | #set 385 | setmenu = gtk.Menu() 386 | setm = gtk.MenuItem("Settings") 387 | setm.set_submenu(setmenu) 388 | show_buttons = gtk.CheckMenuItem("Show buttons") 389 | show_buttons.set_active(True) 390 | show_buttons.connect("activate", self.show_buttons) 391 | setmenu.append(show_buttons) 392 | mb.append(setm) 393 | 394 | #Widget 395 | #Creat self.darea 396 | self.darea = gtk.DrawingArea() 397 | self.darea.connect("expose-event", self.expose) 398 | self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color("#FFFFFF")) 399 | #Creat all ToggleButton for each pe 400 | each_entry(self.pe_gtk_creat_button) 401 | #Creat button_hboxes 402 | self.button_hboxes = self.pe_gtk_creat_button_hboxes_first() 403 | 404 | #Add mb and widget to window 405 | self.vbox = gtk.VBox(False, 0) 406 | self.vbox.pack_start(mb, False, False, 0) 407 | self.vbox.pack_start(self.darea, True, True, 0) 408 | for e in self.button_hboxes: 409 | self.vbox.pack_start(e, False, False, 0) 410 | self.add(self.vbox) 411 | 412 | #First show to get the right size 413 | self.show_all() 414 | size = self.pe_gtk_get_size() 415 | 416 | #Reset the button_hboxes 417 | each_entry(self.pe_gtk_remove_creat_button_hboxes) 418 | for e in self.button_hboxes: 419 | self.vbox.remove(e) 420 | self.button_hboxes = self.pe_gtk_creat_button_hboxes_second(size) 421 | for e in self.button_hboxes: 422 | self.vbox.pack_start(e, False, False, 0) 423 | self.show_all() 424 | 425 | #Reset the value of each button 426 | each_entry(self.button_reset) 427 | 428 | #Add timer 429 | glib.timeout_add(int(sleep_sec * 1000), self.timer_cb) 430 | #Remove the first entry because it already record a big value 431 | glib.timeout_add(int(sleep_sec * 1100), self.timer_remove_first_record) 432 | 433 | def __del__(self): 434 | if self.logfd: 435 | self.logfd.close() 436 | self.logfd = False 437 | 438 | def pe_init_callback(self, i, e): 439 | if (len(e) < pe_list_value + 1): 440 | e.append([]) 441 | e[pe_list_value].append([]) 442 | if (len(e) < pe_list_x + 1): 443 | e.append([]) 444 | e[pe_list_x].append([]) 445 | if (len(e) < pe_list_button + 1): 446 | e.append([]) 447 | if (len(e) < pe_list_button + 1): 448 | e.append([]) 449 | if (len(e) < pe_list_bcolor + 1): 450 | e.append([]) 451 | if (len(e) < pe_list_lcolor + 1): 452 | e.append([]) 453 | 454 | def pe_gtk_creat_button(self, i, e): 455 | e[pe_list_button].append(gtk.ToggleButton(e[pe_list_name]+":"+str(18446744073709551615))) 456 | self.set_button_color(e[pe_list_button][i], e[pe_list_bcolor][i]) 457 | e[pe_list_button][i].connect("clicked", self.button_click) 458 | 459 | def pe_gtk_creat_button_hboxes_first(self): 460 | global pe_list, cpu_number 461 | 462 | hboxes = [] 463 | self.label_list = [] 464 | for i in range(0, cpu_number): 465 | hboxes.append(gtk.HBox(False, 0)) 466 | self.label_list.append(gtk.Label("CPU"+str(i))) 467 | hboxes[i].pack_start(self.label_list[i], False, False, 0) 468 | for e in pe_list: 469 | hboxes[i].pack_start(e[pe_list_button][i], False, False, 0) 470 | 471 | return hboxes 472 | 473 | def pe_gtk_get_size(self): 474 | global pe_list, cpu_number 475 | 476 | #0 label size 1 button size 477 | size = ([],[]) 478 | for i in range(0, cpu_number): 479 | size[0].append(self.label_list[i].allocation.width) 480 | size[1].append([]) 481 | for e in pe_list: 482 | size[1][i].append(e[pe_list_button][i].allocation.width) 483 | 484 | return size 485 | 486 | def pe_gtk_remove_creat_button_hboxes(self, i, e): 487 | self.button_hboxes[i].remove(e[pe_list_button][i]) 488 | 489 | def pe_gtk_creat_button_hboxes_second(self, size): 490 | global pe_list, cpu_number 491 | 492 | hboxes = [] 493 | hbox_id = -1 494 | for i in range(0, cpu_number): 495 | keep_going = True 496 | prev_entry_id = 0 497 | while keep_going == True: 498 | width = self.allocation.width 499 | keep_going = False 500 | hbox_id += 1 501 | hboxes.append(gtk.HBox(False, 0)) 502 | width -= size[0][i] 503 | hboxes[hbox_id].pack_start(gtk.Label("CPU"+str(i)), False, False, 0) 504 | for j in range(prev_entry_id, len(pe_list)): 505 | if width - size[1][i][j] <= 0: 506 | prev_entry_id = j 507 | keep_going = True 508 | break 509 | width -= size[1][i][j] + 200 510 | hboxes[hbox_id].pack_start(pe_list[j][pe_list_button][i], False, False, 0) 511 | 512 | return hboxes 513 | 514 | def button_reset(self, i, e): 515 | e[pe_list_button][i].set_label(e[pe_list_name]+":0") 516 | 517 | #Dialog ------------------------------------------------------- 518 | def dialog_error(self, msg): 519 | md = gtk.MessageDialog(self,gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) 520 | md.run() 521 | md.destroy() 522 | 523 | #Menubar ------------------------------------------------------- 524 | def show_buttons(self, widget): 525 | if widget.active: 526 | for e in self.button_hboxes: 527 | e.show() 528 | else: 529 | for e in self.button_hboxes: 530 | e.hide() 531 | 532 | def log_write_name(self, i, e): 533 | self.logfd.write("CPU"+str(i)+" "+e[pe_list_name]+",") 534 | 535 | def mb_save(self, widget): 536 | if widget.active: 537 | md = gtk.FileChooserDialog(title="Save log to a CSV file", action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OK, gtk.RESPONSE_OK)) 538 | md.set_do_overwrite_confirmation(True) 539 | md.set_current_name("pe.csv") 540 | if md.run() == gtk.RESPONSE_OK: 541 | try: 542 | self.logfd = open(md.get_filename(), "w") 543 | each_entry(self.log_write_name) 544 | self.logfd.write("\n") 545 | except: 546 | self.dialog_error("Try to open file "+md.get_filename()+" got error") 547 | widget.set_active(False) 548 | if self.logfd: 549 | self.logfd.close() 550 | self.logfd = False 551 | else: 552 | widget.set_active(False) 553 | md.destroy() 554 | else: 555 | if self.logfd: 556 | self.logfd.close() 557 | self.logfd = False 558 | 559 | #Button -------------------------------------------------------- 560 | def refind_max_value(self, i, e): 561 | if e[pe_list_button][i].get_active(): 562 | return 563 | for i in e[pe_list_value][i]: 564 | if i > self.max_value: 565 | self.max_value = i 566 | self.y_ratio = 0 567 | 568 | def set_button_color(self, button, color): 569 | style = button.get_style().copy() 570 | style.bg[gtk.STATE_NORMAL] = color 571 | style.bg[gtk.STATE_ACTIVE] = color 572 | style.bg[gtk.STATE_PRELIGHT] = color 573 | style.bg[gtk.STATE_SELECTED] = color 574 | style.bg[gtk.STATE_INSENSITIVE] = color 575 | button.set_style(style) 576 | 577 | def button_click(self, widget): 578 | if widget.get_active(): 579 | self.set_button_color(widget, gtk.gdk.Color("#FFFFFF")) 580 | else: 581 | color = False 582 | for i in range(0, cpu_number): 583 | for e in pe_list: 584 | if e[pe_list_button][i] == widget: 585 | color = e[pe_list_bcolor][i] 586 | break 587 | if color: 588 | break 589 | if color: 590 | self.set_button_color(widget, color) 591 | each_entry(self.refind_max_value) 592 | self.darea.queue_draw() 593 | 594 | #Timer --------------------------------------------------------- 595 | def write_csv(self, msg): 596 | try: 597 | self.logfd.write(msg) 598 | except: 599 | self.dialog_error("Writ CSV file got error") 600 | widget.set_active(False) 601 | self.logfd.close() 602 | self.logfd = False 603 | 604 | def pe_gtk_add(self, i, e): 605 | if in_gdb: 606 | current_value = long(gdb.parse_and_eval("$p_pe_val_"+e[pe_list_type]+e[pe_list_config]+"_"+str(i))) 607 | else: 608 | current_value = gtp.tvariable_val_raw(e[pe_list_qtv][i]) 609 | if current_value == None: 610 | print "Fail when get val from KGTP" 611 | exit(0) 612 | this_value = current_value-e[pe_list_prev][i] 613 | e[pe_list_value][i].append(this_value) 614 | if this_value > self.max_value and not e[pe_list_button][i].get_active(): 615 | self.max_value = this_value 616 | self.y_ratio = 0 617 | e[pe_list_x][i].append(-1) 618 | e[pe_list_prev][i] = current_value 619 | e[pe_list_button][i].set_label(e[pe_list_name]+":"+str(this_value)) 620 | if self.logfd: 621 | write_csv(str(this_value)+",") 622 | 623 | def timer_cb(self): 624 | each_entry(self.pe_gtk_add) 625 | if self.logfd: 626 | write_csv("\n") 627 | self.darea.queue_draw() 628 | return True 629 | 630 | def timer_remove_first_record(self): 631 | if len(pe_list[0][pe_list_value][0]) >= 1: 632 | self.pe_remove_entry_num = 1 633 | each_entry(self.pe_remove_entry) 634 | return False 635 | else: 636 | return True 637 | 638 | #DrawingArea --------------------------------------------------- 639 | def pe_gtk_line(self, i, e): 640 | if len(e[pe_list_value][i]) < 2: 641 | return 642 | if e[pe_list_button][i].get_active(): 643 | return 644 | 645 | self.cr.set_source_rgb(e[pe_list_lcolor][i][0], e[pe_list_lcolor][i][1], e[pe_list_lcolor][i][2]) 646 | x = 0 647 | for num in range(0, len(e[pe_list_value][i])): 648 | if e[pe_list_value][i][num] > self.line_max: 649 | self.line_max = e[pe_list_value][i][num] 650 | if self.height_change or e[pe_list_x][i][num] < 0: 651 | e[pe_list_x][i][num] = self.prev_height - e[pe_list_value][i][num] * self.y_ratio 652 | if num == 0: 653 | self.cr.move_to(x, e[pe_list_x][i][num]) 654 | else: 655 | self.cr.line_to(x, e[pe_list_x][i][num]) 656 | x += self.entry_width 657 | self.cr.stroke() 658 | 659 | def pe_remove_entry(self, i, e): 660 | del(e[pe_list_value][i][0:self.pe_remove_entry_num]) 661 | del(e[pe_list_x][i][0:self.pe_remove_entry_num]) 662 | 663 | def expose(self, widget, event): 664 | self.cr = widget.window.cairo_create() 665 | 666 | #y 667 | if self.prev_height != self.darea.allocation.height: 668 | self.height_change = True 669 | self.prev_height = self.darea.allocation.height 670 | else: 671 | self.height_change = False 672 | if self.max_value > 0 and (self.height_change or self.y_ratio == 0): 673 | self.max_value += 100 - self.max_value % 100 674 | self.y_ratio = float(self.prev_height)/self.max_value 675 | self.height_change = True 676 | 677 | #x 678 | x_size = len(pe_list[0][pe_list_value][0]) 679 | entry_number = 0 680 | if self.entry_width * x_size > self.darea.allocation.width: 681 | entry_number = self.darea.allocation.width // self.entry_width 682 | self.pe_remove_entry_num = x_size - entry_number 683 | each_entry(self.pe_remove_entry) 684 | 685 | #dash 686 | self.cr.set_source_rgb(0, 0, 0) 687 | self.cr.set_dash((1, 5)) 688 | #dash line for x 689 | if entry_number == 0: 690 | entry_number = self.darea.allocation.width // self.entry_width 691 | x = 0 692 | while x < self.darea.allocation.width: 693 | x += self.entry_width * 10 694 | self.cr.move_to(x, 0) 695 | self.cr.line_to(x, self.prev_height) 696 | #dash line for y 697 | self.cr.move_to(0, 10) 698 | self.cr.show_text(str(self.max_value)) 699 | 700 | self.cr.move_to(0, self.darea.allocation.height/4*3) 701 | self.cr.show_text(str(self.max_value/4*3)) 702 | self.cr.line_to(self.darea.allocation.width, self.darea.allocation.height/4*3) 703 | 704 | self.cr.move_to(0, self.darea.allocation.height/2) 705 | self.cr.show_text(str(self.max_value/2)) 706 | self.cr.line_to(self.darea.allocation.width, self.darea.allocation.height/2) 707 | 708 | self.cr.move_to(0, self.darea.allocation.height/4) 709 | self.cr.show_text(str(self.max_value/4)) 710 | self.cr.line_to(self.darea.allocation.width, self.darea.allocation.height/4) 711 | 712 | self.cr.stroke() 713 | self.cr.set_dash(()) 714 | 715 | self.line_max = 0 716 | each_entry(self.pe_gtk_line) 717 | if self.line_max > 0 and self.line_max * 2 < self.max_value: 718 | self.max_value = self.line_max 719 | self.y_ratio = 0 720 | 721 | self.height_change = False 722 | 723 | PyApp() 724 | gtk.main() 725 | if in_gdb: 726 | gdb.execute("tstop", True, False) 727 | else: 728 | gtp.tstop() 729 | exit(0) 730 | -------------------------------------------------------------------------------- /add-ons/tfind.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import gdb 4 | #import re 5 | 6 | #gdb.execute("tfind -1", False, True) 7 | #cpu_number = int(gdb.parse_and_eval("$cpu_number")) 8 | #str(gdb.execute("p $rip", False, True)) 9 | 10 | #frame_count = gdb.execute("tstatus", False, True) 11 | #frame_count = re.findall("Collected \d+ trace frames", frame_count) 12 | #frame_count = re.findall("\d+", frame_count[0]) 13 | #frame_count = int(frame_count[0]) 14 | 15 | gdb.execute("set pagination off", True, False) 16 | 17 | #for i in range(frame_count - 1, -1, -1): 18 | while True: 19 | gdb.execute("tfind", True, False) 20 | #print gdb.parse_and_eval("$trace_frame") 21 | if long(gdb.parse_and_eval("work")) == 0x0: 22 | break 23 | 24 | -------------------------------------------------------------------------------- /dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="gtp" 2 | PACKAGE_VERSION="20140510+" 3 | CLEAN="make clean" 4 | MAKE[0]="make gtp.ko KERNELVERSION=$kernelver" 5 | BUILT_MODULE_NAME[0]="gtp" 6 | DEST_MODULE_LOCATION[0]="/kernel/lib" 7 | POST_INSTALL="dkms_others_install.sh" 8 | POST_REMOVE="dkms_others_uninstall.sh" 9 | AUTOINSTALL="yes" 10 | -------------------------------------------------------------------------------- /dkms_others_install.sh: -------------------------------------------------------------------------------- 1 | make others_install 2 | make clean -------------------------------------------------------------------------------- /dkms_others_uninstall.sh: -------------------------------------------------------------------------------- 1 | make others_uninstall 2 | 3 | -------------------------------------------------------------------------------- /getframe.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Get the trace frame of KGTP and save it in tfile. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | * 18 | * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2011 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define GTP_FRAME_PIPE_DIR "/sys/kernel/debug/gtpframe_pipe" 34 | 35 | int free_size_g = 2; 36 | int keep_running = 1; 37 | int entry_number = 1000; 38 | 39 | /* 40 | Return true if current disk avaial is small than fs_avail. 41 | */ 42 | int 43 | check_disk_size(void) 44 | { 45 | struct statfs info; 46 | 47 | if (statfs("./", &info) < 0) { 48 | perror("statfs"); 49 | exit(-errno); 50 | } 51 | 52 | if (info.f_bavail * info.f_bsize / 1024 / 1024/ 1024 < free_size_g) 53 | return 1; 54 | 55 | return 0; 56 | } 57 | 58 | int 59 | file_is_exist(char *name) 60 | { 61 | struct stat info; 62 | 63 | if (stat(name, &info) < 0) 64 | return 0; 65 | 66 | return 1; 67 | } 68 | 69 | static void 70 | sig_int(int signo) 71 | { 72 | int c; 73 | 74 | printf("Quit?(y or n):"); 75 | c = getchar(); 76 | if (c == 'Y' || c == 'y' ) 77 | keep_running = 0; 78 | } 79 | 80 | static void 81 | sig_term(int signo) 82 | { 83 | keep_running = 0; 84 | } 85 | 86 | void 87 | print_usage(char *arg) 88 | { 89 | printf("Get the trace frame of KGTP and save them in current \n" 90 | "directory with tfile format.\n" 91 | "Usage: %s [option]\n\n" 92 | 93 | " -g n Set the minimum free size limit to n G.\n" 94 | " When free size of current disk is smaller than n G,\n" 95 | " %s will exit (-q) or wait some seconds (-w).\n" 96 | " The default value of it is 2 G.\n\n" 97 | 98 | " -q Quit when current disk is smaller than\n" 99 | " minimum free size limit (-g).\n\n" 100 | 101 | " -w n Wait n seconds when current disk is smaller\n" 102 | " than minimum free size limit (-g).\n\n" 103 | 104 | " -e n Set the entry number of each tfile to n.\n" 105 | " The default value of it is 1000.\n\n" 106 | 107 | " -h Display this information.\n", 108 | arg, arg); 109 | 110 | exit(0); 111 | } 112 | 113 | int 114 | main(int argc,char *argv[],char *envp[]) 115 | { 116 | int c; 117 | int pipe; 118 | int quit_if_full = 0; 119 | int wait_second = 30; 120 | int rec_id = 0; 121 | char frame_name[64]; 122 | struct sigaction act; 123 | 124 | while ((c = getopt(argc, argv, "g:qw:e:h")) != -1) { 125 | switch (c) { 126 | case 'g': 127 | free_size_g = atoi(optarg); 128 | if (free_size_g < 1) { 129 | fprintf(stderr, "The %d is too small.\n", 130 | free_size_g); 131 | exit(-1); 132 | } 133 | break; 134 | case 'q': 135 | quit_if_full = 1; 136 | break; 137 | case 'w': 138 | wait_second = atoi(optarg); 139 | if (wait_second <= 0) { 140 | fprintf(stderr, "The %d is too small.\n", 141 | wait_second); 142 | exit(-1); 143 | } 144 | break; 145 | case 'e': 146 | entry_number = atoi(optarg); 147 | if (entry_number <= 0) { 148 | fprintf(stderr, "The %d is too small.\n", 149 | wait_second); 150 | exit(-1); 151 | } 152 | break; 153 | case 'h': 154 | default: 155 | print_usage(argv[0]); 156 | break; 157 | } 158 | } 159 | 160 | for(; 1; rec_id++) { 161 | snprintf(frame_name, 64, "%d.gtp", rec_id); 162 | if (!file_is_exist(frame_name)) 163 | break; 164 | } 165 | 166 | pipe = open(GTP_FRAME_PIPE_DIR, O_RDONLY); 167 | if (pipe < 0) { 168 | perror(GTP_FRAME_PIPE_DIR); 169 | exit(-errno); 170 | } 171 | 172 | act.sa_handler = sig_int; 173 | act.sa_flags = 0; 174 | if (sigaction(SIGINT, &act, NULL)< 0) { 175 | perror("sigaction"); 176 | exit(-errno); 177 | } 178 | act.sa_handler = sig_term; 179 | act.sa_flags = 0; 180 | if (sigaction(SIGTERM, &act, NULL)< 0) { 181 | perror("sigaction"); 182 | exit(-errno); 183 | } 184 | 185 | while (keep_running) { 186 | int fd; 187 | char tmp_name[] = ".gtpframe.XXXXXX"; 188 | int num; 189 | ssize_t buf_size; 190 | char buf[8192]; 191 | 192 | /* Check size. */ 193 | if (check_disk_size()) { 194 | printf("Free disk size is smaller than %dG.\n", 195 | free_size_g); 196 | if (quit_if_full) 197 | exit(0); 198 | else { 199 | printf("Wait %d seconds.\n", wait_second); 200 | sleep(wait_second); 201 | continue; 202 | } 203 | } 204 | 205 | re_open: 206 | if (mkstemp(tmp_name) == -1) { 207 | perror("mkstemp"); 208 | exit(-errno); 209 | } 210 | fd = open(tmp_name, O_WRONLY | O_CREAT | O_EXCL, S_IRWXU); 211 | if (fd < 0) { 212 | if (errno == EEXIST || (errno == EINTR && keep_running)) 213 | goto re_open; 214 | perror(tmp_name); 215 | exit(-errno); 216 | } 217 | 218 | if (lseek(pipe, 0, SEEK_SET) < 0) { 219 | perror("lseek"); 220 | exit(-errno); 221 | } 222 | 223 | for (num = 0; num < entry_number + 1; num++) { 224 | re_read: 225 | buf_size = read(pipe, buf, 8192); 226 | if (buf_size <= 0) { 227 | if (errno == EINTR) { 228 | if (keep_running) 229 | goto re_read; 230 | else 231 | break; 232 | } 233 | perror(GTP_FRAME_PIPE_DIR); 234 | exit(-errno); 235 | } 236 | re_write: 237 | if (write(fd, buf, buf_size) != buf_size) { 238 | if (errno == EINTR) 239 | goto re_write; 240 | perror("write"); 241 | if (num > 0) 242 | break; 243 | exit(-errno); 244 | } 245 | } 246 | 247 | memset(buf, 0, 2); 248 | re_write_2: 249 | if (write(fd, buf, 2) != 2) { 250 | if (errno == EINTR) 251 | goto re_write_2; 252 | perror("Write tail"); 253 | } 254 | close(fd); 255 | 256 | if (num < 2) 257 | unlink(tmp_name); 258 | else { 259 | for(; 1; rec_id++) { 260 | snprintf(frame_name, 64, "%d.gtp", rec_id); 261 | if (!file_is_exist(frame_name)) 262 | break; 263 | } 264 | if (rename(tmp_name, frame_name) < 0) { 265 | perror("rename"); 266 | exit(-errno); 267 | } 268 | printf("Save KGTP trace frame buffer to file %s.\n", 269 | frame_name); 270 | } 271 | } 272 | 273 | return 0; 274 | } 275 | -------------------------------------------------------------------------------- /getgtprsp.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # This script to get the GDB tracepoint RSP package and save it 4 | # to ./gtpstart and ./gtpstop file. 5 | # GPL 6 | # Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010-2013 7 | 8 | binmode STDIN, ":raw"; 9 | $| = 1; 10 | 11 | $status = 0; 12 | $circular = 0; 13 | $var_count = 0; 14 | 15 | while (1) { 16 | sysread STDIN, $c, 1 or next; 17 | if ($c eq '') { 18 | next; 19 | } elsif ($c eq '+' || $c eq '-') { 20 | $c = ''; 21 | } 22 | 23 | sysread STDIN, $line, 1024 or next; 24 | print '+'; 25 | $line = $c.$line; 26 | 27 | open(LOG, ">>./log"); 28 | print LOG $line."\n"; 29 | close (LOG); 30 | 31 | if ($status == 0) { 32 | if ($line eq '$?#3f') { 33 | print '$S05#b8'; 34 | } elsif ($line eq '$g#67') { 35 | print '$00000000#80'; 36 | } elsif ($line eq '$k#6b') { 37 | exit; 38 | } elsif ($line =~ /^\$m/ || $line =~ /^\$p/) { 39 | print '$00000000#80'; 40 | } elsif ($line eq '$qTStatus#49') { 41 | print '$T0;tnotrun:0;tframes:0;tcreated:0;tsize:'; 42 | print '500000;tfree:500000;circular:0;disconn:0#d1'; 43 | } elsif ($line eq '$QTBuffer:circular:1#f9') { 44 | print '$OK#9a'; 45 | $circular = 1; 46 | } elsif ($line eq '$QTBuffer:circular:0#f8') { 47 | print '$OK#9a'; 48 | $circular = 0; 49 | } elsif ($line eq '$QTStop#4b') { 50 | print '$OK#9a'; 51 | } elsif ($line =~ /^\$qSupported/) { 52 | print '$ConditionalTracepoints+;TracepointSource+#1b'; 53 | } elsif ($line eq '$QTinit#59') { 54 | $status = 1; 55 | open(STARTFILE, ">./gtpstart"); 56 | print STARTFILE '$QTDisconnected:1#e3'."\n"; 57 | if ($circular) { 58 | print STARTFILE '$QTBuffer:circular:1#f9'; 59 | } else { 60 | print STARTFILE '$QTBuffer:circular:0#f8'; 61 | } 62 | } elsif ($line eq '$qTfV#81') { 63 | print '$18:0:1:6972715f636f756e74#ca'; 64 | } elsif ($line eq '$qTsV#8e') { 65 | #Support from GTP_VAR_VERSION_ID(0x1) to GTP_STEP_ID_ID(0x2d) 66 | if ($var_count == 0) { 67 | print '$17:0:1:736f66746972715f636f756e74#a6'; 68 | } elsif ($var_count == 1) { 69 | print '$16:0:1:686172646972715f636f756e74#70'; 70 | } elsif ($var_count == 2) { 71 | print '$15:0:1:6c6173745f6572726e6f#59'; 72 | } elsif ($var_count == 3) { 73 | print '$14:0:1:69676e6f72655f6572726f72#38'; 74 | } elsif ($var_count == 4) { 75 | print '$13:0:1:7874696d655f6e736563#35'; 76 | } elsif ($var_count == 5) { 77 | print '$12:0:1:7874696d655f736563#99'; 78 | } elsif ($var_count == 6) { 79 | print '$11:0:1:6b726574#48'; 80 | } elsif ($var_count == 7) { 81 | print '$10:0:1:705f70655f656e#e5'; 82 | } elsif ($var_count == 8) { 83 | print '$f:0:1:6370755f6e756d626572#29'; 84 | } elsif ($var_count == 9) { 85 | print '$e:0:1:73656c665f7472616365#f8'; 86 | } elsif ($var_count == 10) { 87 | print '$d:0:1:64756d705f737461636b#22'; 88 | } elsif ($var_count == 11) { 89 | print '$c:0:1:7072696e746b5f666f726d6174#c7'; 90 | } elsif ($var_count == 12) { 91 | print '$b:8:1:7072696e746b5f6c6576656c#66'; 92 | } elsif ($var_count == 13) { 93 | print '$a:0:1:7072696e746b5f746d70#54'; 94 | } elsif ($var_count == 14) { 95 | print '$9:0:1:6774705f72625f646973636172645f706167655f6e756d626572#2d'; 96 | } elsif ($var_count == 15) { 97 | print '$8:0:1:636f6f6b65645f7264747363#01'; 98 | } elsif ($var_count == 16) { 99 | print '$7:0:1:7264747363#57'; 100 | } elsif ($var_count == 17) { 101 | print '$6:0:1:636f6f6b65645f636c6f636b#8d'; 102 | } elsif ($var_count == 18) { 103 | print '$5:0:1:636c6f636b#e3'; 104 | } elsif ($var_count == 19) { 105 | print '$4:0:1:63757272656e745f7468726561645f696e666f#21'; 106 | } elsif ($var_count == 20) { 107 | print '$3:0:1:63757272656e745f7461736b#c9'; 108 | } elsif ($var_count == 21) { 109 | print '$2:0:1:6370755f6964#f1'; 110 | } elsif ($var_count == 22) { 111 | print '$1:bfe30fc:1:6774705f76657273696f6e#94'; 112 | } elsif ($var_count == 23) { 113 | print '$19:0:1:706970655f7472616365#cb'; 114 | } elsif ($var_count == 24) { 115 | print '$1a:0:1:63757272656e745f7461736b5f706964#03'; 116 | } elsif ($var_count == 25) { 117 | print '$1d:200:1:6274#d9'; 118 | } elsif ($var_count == 26) { 119 | print '$1b:0:1:63757272656e745f7461736b5f75736572#6e'; 120 | } elsif ($var_count == 27) { 121 | print '$1c:0:1:63757272656e74#bb'; 122 | } elsif ($var_count == 28) { 123 | print '$1f:0:1:64697361626c65#bc'; 124 | } elsif ($var_count == 29) { 125 | print '$1e:0:1:656e61626c65#7e'; 126 | } elsif ($var_count == 30) { 127 | print '$18:0:1:6972715f636f756e74#ca'; 128 | } elsif ($var_count == 31) { 129 | print '$20:0:1:77617463685f737461746963#a2'; 130 | } elsif ($var_count == 32) { 131 | print '$21:0:1:77617463685f74797065#d1'; 132 | } elsif ($var_count == 33) { 133 | print '$22:1:1:77617463685f73697a65#02'; 134 | } elsif ($var_count == 34) { 135 | print '$23:0:1:77617463685f7365745f6964#da'; 136 | } elsif ($var_count == 35) { 137 | print '$24:0:1:77617463685f7365745f61646472#a6'; 138 | } elsif ($var_count == 36) { 139 | print '$25:0:1:77617463685f7374617274#38'; 140 | } elsif ($var_count == 37) { 141 | print '$26:0:1:77617463685f73746f70#01'; 142 | } elsif ($var_count == 38) { 143 | print '$27:0:1:77617463685f74726163655f6e756d#75'; 144 | } elsif ($var_count == 39) { 145 | print '$28:0:1:77617463685f74726163655f61646472#79'; 146 | } elsif ($var_count == 40) { 147 | print '$29:0:1:77617463685f61646472#d0'; 148 | } elsif ($var_count == 41) { 149 | print '$2a:0:1:77617463685f76616c#c1'; 150 | } elsif ($var_count == 42) { 151 | print '$2b:0:1:77617463685f636f756e74#cc'; 152 | } elsif ($var_count == 43) { 153 | print '$2c:0:1:737465705f636f756e74#5d'; 154 | } elsif ($var_count == 44) { 155 | print '$2d:0:1:737465705f6964#c0'; 156 | } else { 157 | print '$l#6c'; 158 | } 159 | $var_count++; 160 | } else { 161 | print '$#00'; 162 | } 163 | } 164 | 165 | if ($status == 1) { 166 | print '$OK#9a'; 167 | 168 | if (length($line) > 0) { 169 | print STARTFILE "\n".$line; 170 | } 171 | 172 | if ($line eq '$QTStart#b3') { 173 | $status = 0; 174 | 175 | close(STARTFILE); 176 | 177 | open(STOPFILE, ">./gtpstop"); 178 | print STOPFILE '$QTStop#4b'; 179 | close(STOPFILE); 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /getmod.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Output Linux Kernel modules info in GDB add-symbol-file format. 3 | * 4 | * Copyright(C) KGTP team (https://kgtp.googlecode.com), 2011-2013 5 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define MOD_DIR "/lib/modules" 21 | #define PROC_MOD "/proc/modules" 22 | #define SYS_MOD "/sys/module" 23 | 24 | #define SDIR_MAX 16 25 | 26 | int sdir_number = 0; 27 | char *sdir[SDIR_MAX]; 28 | 29 | int rdir_number = 0; 30 | int rdir_current = 0; 31 | char *rdir[SDIR_MAX]; 32 | 33 | char got_dir[512]; 34 | 35 | int no_search_mod = 0; 36 | 37 | int 38 | search_mod_1(char *dir, char *file) 39 | { 40 | DIR *dp; 41 | struct dirent *ptr; 42 | int ret = 0; 43 | 44 | dp = opendir(dir); 45 | if (!dp) { 46 | fprintf(stderr, "#Cannot open %s: %s.\n", dir, 47 | strerror(errno)); 48 | ret = -1; 49 | goto out; 50 | } 51 | while ((ptr = readdir(dp)) != NULL) { 52 | char cdir[512]; 53 | 54 | if (ptr->d_type == DT_DIR) { 55 | if (strcmp(ptr->d_name, ".") == 0) 56 | continue; 57 | if (strcmp(ptr->d_name, "..") == 0) 58 | continue; 59 | snprintf(cdir, 512, "%s/%s", dir, ptr->d_name); 60 | if (search_mod_1(cdir, file)) { 61 | ret = 1; 62 | break; 63 | } 64 | } else { 65 | int i; 66 | 67 | snprintf(cdir, 512, "%s", ptr->d_name); 68 | for (i = 0; i < strlen(cdir); i++) { 69 | if (cdir[i] == '_') 70 | cdir[i] = '-'; 71 | } 72 | if (strcmp(cdir, file) == 0) { 73 | snprintf(got_dir, 512, "%s/%s", dir, 74 | ptr->d_name); 75 | ret = 1; 76 | break; 77 | } 78 | } 79 | } 80 | closedir(dp); 81 | 82 | out: 83 | return ret; 84 | } 85 | 86 | int 87 | search_mod(char *dir, char *file) 88 | { 89 | int ret; 90 | char tmp_dir[512]; 91 | 92 | ret = search_mod_1(dir, file); 93 | if (ret <= 0) 94 | return ret; 95 | 96 | if (rdir_number == 0) 97 | return 1; 98 | 99 | if (rdir_current >= rdir_number) 100 | rdir_current--; 101 | 102 | strcpy(tmp_dir, got_dir); 103 | snprintf(got_dir, 512, "%s%s", rdir[rdir_current], 104 | tmp_dir + strlen(dir)); 105 | 106 | rdir_current++; 107 | return 1; 108 | } 109 | 110 | void 111 | print_mod(char *name, char *addr) 112 | { 113 | int i; 114 | char mod_dir[256]; 115 | struct stat sbuf; 116 | char file[64]; 117 | DIR *dp; 118 | struct dirent *ptr; 119 | 120 | snprintf(file, 64, "%s.ko", name); 121 | 122 | if (no_search_mod) 123 | printf("add-symbol-file %s %s", file, addr); 124 | else { 125 | for (i = 0; i < strlen(file); i++) { 126 | if (file[i] == '_') 127 | file[i] = '-'; 128 | } 129 | for (i = 0; i < sdir_number; i++) { 130 | int ret; 131 | 132 | if (sdir[i] == NULL) 133 | continue; 134 | ret = search_mod(sdir[i], file); 135 | if (ret < 0) 136 | sdir[i] = NULL; 137 | if (ret > 0) 138 | break; 139 | } 140 | if (i >= sdir_number) { 141 | for (i = 0; i < sdir_number; i++) { 142 | if (sdir[i]) 143 | break; 144 | } 145 | if (i >= sdir_number) { 146 | no_search_mod = 1; 147 | fprintf(stderr, 148 | "#Cannot open any module search directories. Auto open -n.\n"); 149 | } else 150 | fprintf(stderr, 151 | "#Cannot find file %s in the module search directories. Just output the command with filename.\n", 152 | file); 153 | printf("#add-symbol-file %s %s", file, addr); 154 | } else 155 | printf("add-symbol-file %s %s", got_dir, addr); 156 | } 157 | 158 | snprintf(mod_dir, 256, "%s/%s/sections", SYS_MOD, name); 159 | /* Check mod_dir. */ 160 | if (stat(mod_dir, &sbuf) || !S_ISDIR(sbuf.st_mode)) { 161 | fprintf(stderr, "%s is not a right directory.\n", mod_dir); 162 | exit(-1); 163 | } 164 | 165 | dp = opendir(mod_dir); 166 | if (!dp) { 167 | fprintf(stderr, "Cannot open %s: %s.\n", mod_dir, 168 | strerror(errno)); 169 | exit(-errno); 170 | } 171 | while ((ptr = readdir(dp)) != NULL) { 172 | if (ptr->d_type == DT_REG) { 173 | char section_file_name[512]; 174 | FILE *fp; 175 | char line[256]; 176 | size_t size; 177 | 178 | if (strcmp(ptr->d_name, ".text") == 0 179 | || strcmp(ptr->d_name, ".symtab") == 0 180 | || strcmp(ptr->d_name, ".strtab") == 0) 181 | continue; 182 | 183 | snprintf(section_file_name, 512, "%s/%s", mod_dir, 184 | ptr->d_name); 185 | fp = fopen(section_file_name, "r"); 186 | if (!fp) { 187 | perror(section_file_name); 188 | exit(-errno); 189 | } 190 | if (fgets(line, 256, fp) == NULL) { 191 | perror(section_file_name); 192 | exit(-errno); 193 | } 194 | fclose(fp); 195 | size = strlen(line); 196 | if (size == 0) { 197 | fprintf(stderr, "format of %s is not right.\n", 198 | section_file_name); 199 | exit(-errno); 200 | } 201 | if (line[size - 1] == '\n') 202 | line[size - 1] = '\0'; 203 | printf(" -s %s %s", ptr->d_name, line); 204 | } 205 | } 206 | closedir(dp); 207 | 208 | printf("\n"); 209 | } 210 | 211 | int 212 | check_sdir(char *dir) 213 | { 214 | struct stat sbuf; 215 | 216 | if (stat(dir, &sbuf) || !S_ISDIR(sbuf.st_mode)) { 217 | fprintf(stderr, 218 | "#%s is not a right directory. Ignore it.\n", 219 | dir); 220 | return 0; 221 | } 222 | 223 | return 1; 224 | } 225 | 226 | void 227 | add_sdir(char *dir) 228 | { 229 | if (sdir_number < SDIR_MAX) { 230 | if (check_sdir(dir)) { 231 | sdir[sdir_number] = dir; 232 | sdir_number++; 233 | } 234 | } else { 235 | fprintf(stderr, "Set too much module search directory."); 236 | exit(-1); 237 | } 238 | } 239 | 240 | void 241 | add_rdir(char *dir) 242 | { 243 | if (rdir_number < SDIR_MAX) { 244 | rdir[rdir_number] = dir; 245 | rdir_number++; 246 | } else { 247 | fprintf(stderr, "Set too much module search directory."); 248 | exit(-1); 249 | } 250 | } 251 | 252 | char * 253 | get_default_sdir(void) 254 | { 255 | static int need_init = 1; 256 | static char dir[512]; 257 | 258 | if (need_init) { 259 | struct utsname ubuf; 260 | 261 | if (uname(&ubuf)) { 262 | fprintf(stderr, "Fail to get kernel version."); 263 | exit(-errno); 264 | } 265 | snprintf(dir, 512, "%s/%s/kernel", MOD_DIR, ubuf.release); 266 | } 267 | 268 | return dir; 269 | } 270 | 271 | void 272 | print_usage(char *arg) 273 | { 274 | printf("Output LKM info in GDB add-symbol-file format.\n" 275 | "Usage: %s [option]\n\n" 276 | 277 | " -s dir Add dir to module search directory list.\n" 278 | " This options can use more than once.\n\n" 279 | 280 | " -S Add %s to module search directory list.\n\n" 281 | 282 | " -r dir Add dir to replace the directory.\n" 283 | " This options can use more than once.\n\n" 284 | 285 | " -n No search the directory of the module\n" 286 | " file directory.\n\n" 287 | 288 | " -h Display this information.\n", 289 | arg, get_default_sdir()); 290 | 291 | exit(0); 292 | } 293 | 294 | int 295 | main(int argc, char *argv[], char *envp[]) 296 | { 297 | struct stat sbuf; 298 | FILE *fp; 299 | char line[4096]; 300 | int c; 301 | int default_sdir_isset = 0; 302 | 303 | if (geteuid() != 0) { 304 | fprintf(stderr, 305 | "Only root can get the right address of modules.\n"); 306 | exit(-1); 307 | } 308 | 309 | while ((c = getopt(argc, argv, "s:Sr:nh")) != -1) { 310 | switch (c) { 311 | case 's': 312 | add_sdir(optarg); 313 | break; 314 | case 'S': 315 | if (!default_sdir_isset) 316 | add_sdir(get_default_sdir()); 317 | break; 318 | case 'r': 319 | add_rdir(optarg); 320 | break; 321 | case 'n': 322 | no_search_mod = 1; 323 | break; 324 | case 'h': 325 | default: 326 | print_usage(argv[0]); 327 | break; 328 | } 329 | } 330 | 331 | if (!no_search_mod && sdir_number == 0) 332 | add_sdir(get_default_sdir()); 333 | if (!no_search_mod && sdir_number == 0) { 334 | no_search_mod = 1; 335 | fprintf(stderr, 336 | "#Cannot open any module search directories. Auto open -n.\n"); 337 | } 338 | 339 | /* Check PROC_MOD. */ 340 | if (stat(PROC_MOD, &sbuf) || !S_ISREG(sbuf.st_mode)) { 341 | fprintf(stderr, "%s is not right.\n", PROC_MOD); 342 | exit(-1); 343 | } 344 | 345 | /* Get module name and address from PROC_MOD. */ 346 | fp = fopen(PROC_MOD, "r"); 347 | if (!fp) { 348 | perror(PROC_MOD); 349 | exit(-errno); 350 | } 351 | while (fgets(line, 4096, fp)) { 352 | int i; 353 | size_t size = strlen(line); 354 | int is_not_digit = 0; 355 | 356 | if (line[size - 1] != '\n') { 357 | fprintf(stderr, 358 | "line:%s is too big to parse by getmod.\n", 359 | line); 360 | exit(-1); 361 | } 362 | 363 | /* This part get the name. */ 364 | for (i = 0; i < size; i++) { 365 | if (line[i] == ' ') { 366 | line[i] = '\0'; 367 | break; 368 | } 369 | } 370 | /* Following part will get the addr. */ 371 | if (i == size) { 372 | fprintf(stderr, 373 | "The format of \"%s\" is not right.\n", line); 374 | exit(-1); 375 | } 376 | if (line[size - 1] == '\n') 377 | line[size - 1] = '\0'; 378 | for (i = size - 2; i >= 0; i--) { 379 | if (line[i] == ' ') { 380 | if (is_not_digit) { 381 | line[i] = '\0'; 382 | is_not_digit = 0; 383 | } else 384 | break; 385 | } else { 386 | if (line[i] != 'x' && line[i] != 'X' 387 | && (line[i] < '0' || line[i] > '9') 388 | && (line[i] < 'a' || line[i] > 'f') 389 | && (line[i] < 'A' || line[i] > 'F')) 390 | is_not_digit = 1; 391 | } 392 | } 393 | if (i < 0) { 394 | fprintf(stderr, "The format of \"%s\" is not right.\n", 395 | line); 396 | exit(-1); 397 | } 398 | print_mod(line, line + i + 1); 399 | } 400 | if (ferror(fp)) { 401 | perror(PROC_MOD); 402 | exit(-errno); 403 | } 404 | fclose(fp); 405 | 406 | return 0; 407 | } 408 | -------------------------------------------------------------------------------- /getmod.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This script is used by GDB to load the symbols from Linux kernel modules 4 | # Copyright(C) KGTP team (https://kgtp.googlecode.com), 2011-2013 5 | # Licensed under the GNU General Public License, version 2.0 (GPLv2) 6 | 7 | #Set special mod_search_dir 8 | #set $mod_search_dir="dir" 9 | #Clear special mod_search_dir 10 | #set $mod_search_dir=(void)1 11 | #Not ignore gtp.ko 12 | #set $ignore_gtp_ko=0 13 | 14 | import gdb 15 | import os 16 | 17 | def get_pagination(): 18 | buf = gdb.execute("show pagination", False, True) 19 | begin = buf.find("State of pagination is ") + len("State of pagination is ") 20 | if begin < 0: 21 | raise NotImplementedError("Cannot get pagination") 22 | buf = buf[begin:] 23 | end = buf.rfind(".") 24 | buf = buf[:end] 25 | 26 | return buf 27 | 28 | pagination = get_pagination() 29 | gdb.execute("set pagination off", False, False) 30 | 31 | def format_file(name): 32 | tmp = "" 33 | for c in name: 34 | if c == "_": 35 | c = "-" 36 | tmp += c 37 | return tmp 38 | 39 | def get_mod_dir_name(name, search_dir): 40 | #get mod_dir_name 41 | full_name = "" 42 | for root, dirs, files in os.walk(search_dir): 43 | for afile in files: 44 | tmp_file = format_file(afile) 45 | if tmp_file == name: 46 | full_name = os.path.join(root,afile) 47 | break 48 | if full_name != "": 49 | break 50 | return full_name 51 | 52 | #Check if the target is available 53 | if str(gdb.selected_thread()) == "None": 54 | raise gdb.error("Please connect to Linux Kernel before use the script.") 55 | 56 | #Output the help 57 | print "Use GDB command \"set $mod_search_dir=dir\" to set an directory for search the modules." 58 | 59 | ignore_gtp_ko = gdb.parse_and_eval("$ignore_gtp_ko") 60 | if ignore_gtp_ko.type.code == gdb.TYPE_CODE_INT: 61 | ignore_gtp_ko = int(ignore_gtp_ko) 62 | else: 63 | ignore_gtp_ko = 1 64 | 65 | #Get the mod_search_dir 66 | mod_search_dir_list = [] 67 | #Get dir from $mod_search_dir 68 | tmp_dir = gdb.parse_and_eval("$mod_search_dir") 69 | if tmp_dir.type.code == gdb.TYPE_CODE_ARRAY: 70 | tmp_dir = str(tmp_dir) 71 | tmp_dir = tmp_dir[1:len(tmp_dir)] 72 | tmp_dir = tmp_dir[0:tmp_dir.index("\"")] 73 | mod_search_dir_list.append(tmp_dir) 74 | #Get dir that same with current vmlinux 75 | tmp_dir = str(gdb.execute("info files", False, True)) 76 | tmp_dir = tmp_dir[tmp_dir.index("Symbols from \"")+len("Symbols from \""):len(tmp_dir)] 77 | tmp_dir = tmp_dir[0:tmp_dir.index("\"")] 78 | tmp_dir = tmp_dir[0:tmp_dir.rindex("/")] 79 | mod_search_dir_list.append(tmp_dir) 80 | #Get the dir of current Kernel 81 | tmp_dir = "/lib/modules/" + str(os.uname()[2]) 82 | if os.path.isdir(tmp_dir): 83 | mod_search_dir_list.append(tmp_dir) 84 | #Let user choice dir 85 | mod_search_dir = "" 86 | while mod_search_dir == "": 87 | for i in range(0, len(mod_search_dir_list)): 88 | print str(i)+". "+mod_search_dir_list[i] 89 | try: 90 | s = input('Select a directory for search the modules [0]:') 91 | except SyntaxError: 92 | s = 0 93 | except: 94 | continue 95 | if s < 0 or s >= len(mod_search_dir_list): 96 | continue 97 | mod_search_dir = mod_search_dir_list[s] 98 | 99 | mod_list_offset = long(gdb.parse_and_eval("((size_t) &(((struct module *)0)->list))")) 100 | mod_list = long(gdb.parse_and_eval("(&modules)")) 101 | mod_list_current = mod_list 102 | 103 | while 1: 104 | mod_list_current = long(gdb.parse_and_eval("((struct list_head *) "+str(mod_list_current)+")->next")) 105 | 106 | #check if need break the loop 107 | if mod_list == mod_list_current: 108 | break 109 | 110 | mod = mod_list_current - mod_list_offset 111 | 112 | #get mod_name 113 | mod_name = str(gdb.parse_and_eval("((struct module *)"+str(mod)+")->name")) 114 | mod_name = mod_name[mod_name.index("\"")+1:len(mod_name)] 115 | mod_name = mod_name[0:mod_name.index("\"")] 116 | mod_name += ".ko" 117 | mod_name = format_file(mod_name) 118 | 119 | mod_dir_name = get_mod_dir_name(mod_name, mod_search_dir); 120 | 121 | #Some Linux distrubutions may use different module name for debug binaries 122 | #Give another try for RHEL/CentOS here 123 | if mod_dir_name == "": 124 | mod_name_debug = mod_name + ".debug" 125 | mod_dir_name = get_mod_dir_name(mod_name_debug, mod_search_dir); 126 | 127 | command = " " 128 | 129 | #Add module_core to command 130 | tmp = str(gdb.parse_and_eval("((struct module *)"+str(mod)+")->module_core")) 131 | if tmp.find('<') >= 0: 132 | tmp = tmp[:tmp.index('<')] 133 | command += tmp 134 | 135 | #Add each sect_attrs->attrs to command 136 | #get nsections 137 | nsections = int(gdb.parse_and_eval("((struct module *)"+str(mod)+")->sect_attrs->nsections")) 138 | sect_attrs = long(gdb.parse_and_eval("(u64)((struct module *)"+str(mod)+")->sect_attrs")) 139 | for i in range(0, nsections): 140 | command += " -s" 141 | tmp = str(gdb.parse_and_eval("((struct module_sect_attrs *)"+str(sect_attrs)+")->attrs["+str(i)+"].name")) 142 | tmp = tmp[tmp.index("\"")+1:len(tmp)] 143 | tmp = tmp[0:tmp.index("\"")] 144 | command += " "+tmp 145 | tmp = str(gdb.parse_and_eval("((struct module_sect_attrs *)"+str(sect_attrs)+")->attrs["+str(i)+"].address")) 146 | command += " "+tmp 147 | 148 | if mod_dir_name == "": 149 | print "Cannot find out",mod_name,"from directory." 150 | print "Please use following command load the symbols from it:" 151 | print "add-symbol-file some_dir/"+mod_name+command 152 | else: 153 | if ignore_gtp_ko and mod_name == "gtp.ko": 154 | print "gtp.ko is ignored. You can use command \"set $ignore_gtp_ko=0\" to close this ignore." 155 | print "Or you can use following command load the symbols from it:" 156 | print "add-symbol-file "+mod_dir_name+command 157 | else: 158 | #print "add-symbol-file "+mod_dir_name+command 159 | gdb.execute("add-symbol-file "+mod_dir_name+command, False, False) 160 | 161 | gdb.execute("set pagination " + pagination, False, False) 162 | -------------------------------------------------------------------------------- /gtp.h: -------------------------------------------------------------------------------- 1 | #ifndef _GTP_PLUGIN_H_ 2 | #define _GTP_PLUGIN_H_ 3 | 4 | /* Follow part for ARCH. */ 5 | #ifdef CONFIG_X86 6 | #define ULONGEST uint64_t 7 | #define LONGEST int64_t 8 | #define CORE_ADDR unsigned long 9 | 10 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) 11 | #define GTP_REGS_PC(regs) ((regs)->ip) 12 | #else 13 | #ifdef CONFIG_X86_32 14 | #define GTP_REGS_PC(regs) ((regs)->eip) 15 | #else 16 | #define GTP_REGS_PC(regs) ((regs)->rip) 17 | #endif 18 | #endif 19 | 20 | #ifdef CONFIG_X86_32 21 | #define GTP_REG_ASCII_SIZE 128 22 | #define GTP_REG_BIN_SIZE 64 23 | 24 | #define GTP_SP_NUM 4 25 | #define GTP_PC_NUM 8 26 | #else 27 | #define GTP_REG_ASCII_SIZE 296 28 | #define GTP_REG_BIN_SIZE 148 29 | 30 | #define GTP_SP_NUM 7 31 | #define GTP_PC_NUM 16 32 | #endif 33 | 34 | #define GTP_X86_NEED_ADJUST_PC(gts) (!(gts)->step && !(gts)->hwb && (gts)->tpe->type != gtp_entry_uprobe) 35 | #endif 36 | 37 | #ifdef CONFIG_MIPS 38 | #define ULONGEST uint64_t 39 | #define LONGEST int64_t 40 | #define CORE_ADDR unsigned long 41 | 42 | #define GTP_REGS_PC(regs) ((regs)->cp0_epc) 43 | 44 | #ifdef CONFIG_32BIT 45 | #define GTP_REG_ASCII_SIZE 304 46 | #define GTP_REG_BIN_SIZE 152 47 | #else 48 | #define GTP_REG_ASCII_SIZE 608 49 | #define GTP_REG_BIN_SIZE 304 50 | #endif 51 | 52 | #define GTP_SP_NUM 29 53 | #define GTP_PC_NUM 37 54 | #endif 55 | 56 | #ifdef CONFIG_ARM 57 | #define ULONGEST uint64_t 58 | #define LONGEST int64_t 59 | #define CORE_ADDR unsigned long 60 | 61 | #define GTP_REGS_PC(regs) ((regs)->uregs[15]) 62 | 63 | #define GTP_REG_ASCII_SIZE 336 64 | #define GTP_REG_BIN_SIZE 168 65 | 66 | #define GTP_SP_NUM 13 67 | #define GTP_PC_NUM 15 68 | #endif 69 | 70 | struct gtp_var; 71 | 72 | struct gtp_trace_s { 73 | struct gtp_entry *tpe; 74 | struct pt_regs *regs; 75 | 76 | #ifdef CONFIG_X86_32 77 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) 78 | unsigned long x86_32_sp; 79 | #else 80 | long x86_32_sp; 81 | #endif 82 | #endif 83 | 84 | long (*read_memory)(void *dst, 85 | void *src, 86 | size_t size); 87 | #ifdef GTP_FRAME_SIMPLE 88 | /* Next part set it to prev part. */ 89 | char **next; 90 | #endif 91 | #ifdef GTP_FTRACE_RING_BUFFER 92 | /* NULL means doesn't have head. */ 93 | char *next; 94 | #endif 95 | #ifdef GTP_RB 96 | /* rb of current cpu. */ 97 | struct gtp_rb_s *next; 98 | u64 id; 99 | #endif 100 | 101 | /* Not 0 if this is step action. 102 | Its value is step number that need exec (include current step). 103 | For example, if a tracepoint have 1 step, 104 | its step action gts->step will be 1. */ 105 | int step; 106 | 107 | struct kretprobe_instance *ri; 108 | int *run; 109 | struct timespec xtime; 110 | 111 | /* $watch_id will set to WATCH_TPE. */ 112 | struct gtp_entry *watch_tpe; 113 | /* $watch_type will set to WATCH_TYPE. */ 114 | int watch_type; 115 | /* $watch_size will set to WATCH_SIZE. */ 116 | int watch_size; 117 | /* The return of $watch_start or $watch_stop. 118 | 0 is success. */ 119 | int watch_start_ret; 120 | int watch_stop_ret; 121 | 122 | /* If this is a session is for a hardware breakpoint. 123 | HWB point to the struct. 124 | If not, it will set to NULL. */ 125 | struct gtp_hwb_s *hwb; 126 | /* hwb_current_val have the value of hwb address watch 127 | when hwb_current_val_gotten is true. */ 128 | int64_t hwb_current_val; 129 | int hwb_current_val_gotten; 130 | 131 | /* For set $current. */ 132 | struct pt_regs *tmp_regs; 133 | 134 | int64_t printk_tmp; 135 | unsigned int printk_level; 136 | unsigned int printk_format; 137 | struct gtpsrc *printk_str; 138 | }; 139 | 140 | struct gtp_var_hooks { 141 | int (*gdb_set_val)(struct gtp_trace_s *unused, struct gtp_var *var, 142 | int64_t val); 143 | int (*gdb_get_val)(struct gtp_trace_s *unused, struct gtp_var *var, 144 | int64_t *val); 145 | int (*agent_set_val)(struct gtp_trace_s *gts, struct gtp_var *var, 146 | int64_t val); 147 | int (*agent_get_val)(struct gtp_trace_s *gts, struct gtp_var *var, 148 | int64_t *val); 149 | }; 150 | 151 | extern int gtp_plugin_mod_register(struct module *mod); 152 | extern int gtp_plugin_mod_unregister(struct module *mod); 153 | 154 | extern struct gtp_var *gtp_plugin_var_add(char *name, int64_t val, 155 | struct gtp_var_hooks *hooks); 156 | extern int gtp_plugin_var_del(struct gtp_var *var); 157 | 158 | extern ULONGEST gtp_action_reg_read(struct gtp_trace_s *gts, int num); 159 | 160 | #endif /* _GTP_PLUGIN_H_ */ 161 | -------------------------------------------------------------------------------- /gtp_rb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Ring buffer of kernel GDB tracepoint module. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | * 18 | * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2011, 2012 19 | * 20 | */ 21 | 22 | /* Following macros is for page of ring buffer. */ 23 | #define ADDR_SIZE sizeof(size_t) 24 | #define GTP_RB_HEAD(addr) ((void *)((size_t)(addr) & PAGE_MASK)) 25 | #define GTP_RB_DATA(addr) (GTP_RB_HEAD(addr) + ADDR_SIZE) 26 | #define GTP_RB_END(addr) (GTP_RB_HEAD(addr) + PAGE_SIZE - ADDR_SIZE) 27 | #define GTP_RB_PREV(addr) (*(void **)GTP_RB_HEAD(addr)) 28 | #define GTP_RB_NEXT(addr) (*(void **)GTP_RB_END(addr)) 29 | #define GTP_RB_DATA_MAX (PAGE_SIZE - ADDR_SIZE - ADDR_SIZE - FID_SIZE \ 30 | - sizeof(u64)) 31 | 32 | struct gtp_rb_s { 33 | spinlock_t lock; 34 | 35 | /* Pointer to the prev frame entry head. 36 | */ 37 | void *prev_frame; 38 | 39 | /* When write, this is the next address to be write. 40 | When read, this is the end of read. */ 41 | void *w; 42 | 43 | /* When alloc memory from rb, record prev value W to PREV_W. 44 | When this memory doesn't need, set W back to PREV_W to release 45 | this memroy. */ 46 | void *prev_w; 47 | 48 | /* Point to the begin of ring buffer. Read will begin from R. */ 49 | void *r; 50 | 51 | /* Point to the trace frame entry head of current read. */ 52 | void *rp; 53 | 54 | /* This the id of rp point to. 55 | 0 means rp doesn't point to a trace frame entry. 56 | So it need call gtp_rb_walk first. */ 57 | u64 rp_id; 58 | 59 | /* The cpu id. */ 60 | int cpu; 61 | }; 62 | 63 | static struct gtp_rb_s __percpu *gtp_rb; 64 | #if defined(CONFIG_ARM) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) 65 | static atomic_t gtp_rb_count; 66 | #else 67 | static atomic64_t gtp_rb_count; 68 | #endif 69 | static unsigned int gtp_rb_page_count; 70 | static atomic_t gtp_rb_discard_page_number; 71 | 72 | static int 73 | gtp_rb_init(void) 74 | { 75 | int cpu; 76 | 77 | gtp_rb = alloc_percpu(struct gtp_rb_s); 78 | if (!gtp_rb) 79 | return -ENOMEM; 80 | 81 | for_each_possible_cpu(cpu) { 82 | struct gtp_rb_s *rb 83 | = (struct gtp_rb_s *)per_cpu_ptr(gtp_rb, cpu); 84 | memset(rb, 0, sizeof(struct gtp_rb_s)); 85 | rb->lock = __SPIN_LOCK_UNLOCKED(rb->lock); 86 | rb->cpu = cpu; 87 | } 88 | gtp_rb_page_count = 0; 89 | atomic_set(>p_rb_discard_page_number, 0); 90 | 91 | return 0; 92 | } 93 | 94 | static void 95 | gtp_rb_release(void) 96 | { 97 | if (gtp_rb) { 98 | free_percpu(gtp_rb); 99 | gtp_rb = NULL; 100 | } 101 | } 102 | 103 | static void 104 | gtp_rb_reset(void) 105 | { 106 | int cpu; 107 | 108 | for_each_possible_cpu(cpu) { 109 | struct gtp_rb_s *rb 110 | = (struct gtp_rb_s *)per_cpu_ptr(gtp_rb, cpu); 111 | rb->w = GTP_RB_DATA(rb->w); 112 | rb->r = rb->w; 113 | rb->rp = NULL; 114 | rb->rp_id = 0; 115 | rb->prev_frame = NULL; 116 | } 117 | 118 | #if defined(CONFIG_ARM) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) 119 | atomic_set(>p_rb_count, 0); 120 | #else 121 | atomic64_set(>p_rb_count, 0); 122 | #endif 123 | atomic_set(>p_rb_discard_page_number, 0); 124 | } 125 | 126 | static inline u64 127 | gtp_rb_clock(void) 128 | { 129 | u64 ret; 130 | 131 | re_inc: 132 | #if defined(CONFIG_ARM) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) 133 | ret = (u64)atomic_inc_return(>p_rb_count); 134 | #else 135 | ret = atomic64_inc_return(>p_rb_count); 136 | #endif 137 | if (ret == 0) 138 | goto re_inc; 139 | 140 | return ret; 141 | } 142 | 143 | #define GTP_RB_PAGE_IS_EMPTY (gtp_rb_page_count == 0) 144 | 145 | static int 146 | gtp_rb_page_alloc(int size) 147 | { 148 | int cpu; 149 | 150 | for_each_possible_cpu(cpu) { 151 | struct gtp_rb_s *rb 152 | = (struct gtp_rb_s *)per_cpu_ptr(gtp_rb, cpu); 153 | void *last = NULL, *next = NULL; 154 | struct page *page; 155 | int current_size; 156 | 157 | gtp_rb_page_count = 0; 158 | current_size = size; 159 | 160 | while (1) { 161 | if (current_size > 0) 162 | current_size -= PAGE_SIZE; 163 | else 164 | break; 165 | 166 | page = alloc_pages_node(cpu_to_node(cpu), 167 | GFP_KERNEL, 0); 168 | if (!page) 169 | return -1; 170 | gtp_rb_page_count++; 171 | rb->w = GTP_RB_DATA(page_address(page)); 172 | GTP_RB_NEXT(rb->w) = next; 173 | if (next) 174 | GTP_RB_PREV(next) = rb->w; 175 | next = rb->w; 176 | if (!last) 177 | last = rb->w; 178 | } 179 | 180 | GTP_RB_NEXT(last) = next; 181 | GTP_RB_PREV(next) = last; 182 | rb->r = rb->w; 183 | 184 | if (gtp_rb_page_count < 3) 185 | return -1; 186 | } 187 | 188 | return 0; 189 | } 190 | 191 | static void 192 | gtp_rb_page_free(void) 193 | { 194 | int cpu; 195 | 196 | for_each_possible_cpu(cpu) { 197 | struct gtp_rb_s *rb 198 | = (struct gtp_rb_s *)per_cpu_ptr(gtp_rb, cpu); 199 | void *need_free = NULL; 200 | int is_first = 1; 201 | 202 | for (rb->r = rb->w = GTP_RB_DATA(rb->w); 203 | is_first || rb->w != rb->r; 204 | rb->w = GTP_RB_NEXT(rb->w)) { 205 | if (need_free) 206 | free_page((unsigned long)need_free); 207 | need_free = GTP_RB_HEAD(rb->w); 208 | is_first = 0; 209 | } 210 | if (need_free) 211 | free_page((unsigned long)need_free); 212 | } 213 | 214 | gtp_rb_page_count = 0; 215 | } 216 | 217 | #define GTP_RB_LOCK(r) spin_lock(&r->lock) 218 | #define GTP_RB_UNLOCK(r) spin_unlock(&r->lock) 219 | #define GTP_RB_LOCK_IRQ(r, flags) spin_lock_irqsave(&r->lock, flags) 220 | #define GTP_RB_UNLOCK_IRQ(r, flags) spin_unlock_irqrestore(&r->lock, flags) 221 | #define GTP_RB_RELEASE(r) (r->w = r->prev_w) 222 | 223 | static inline void * 224 | gtp_rb_prev_frame_get(struct gtp_rb_s *rb) 225 | { 226 | return rb->prev_frame; 227 | } 228 | 229 | static inline void 230 | gtp_rb_prev_frame_set(struct gtp_rb_s *rb, void *prev_frame) 231 | { 232 | rb->prev_frame = prev_frame; 233 | } 234 | 235 | /* Return the max size for next gtp_rb_alloc. */ 236 | static inline size_t 237 | gtp_rb_alloc_max(struct gtp_rb_s *rb) 238 | { 239 | return GTP_RB_END(rb->w) - rb->w; 240 | } 241 | 242 | static void * 243 | gtp_rb_alloc(struct gtp_rb_s *rb, size_t size, u64 id) 244 | { 245 | void *ret; 246 | 247 | size = FRAME_ALIGN(size); 248 | 249 | if (size > GTP_RB_DATA_MAX) { 250 | printk(KERN_WARNING "gtp_rb_alloc: The size %zu is too big" 251 | "for the KGTP ring buffer. " 252 | "The max size that KGTP ring buffer " 253 | "support is %lu (Need sub some size for " 254 | "inside structure).\n", size, GTP_RB_DATA_MAX); 255 | return NULL; 256 | } 257 | 258 | rb->prev_w = rb->w; 259 | 260 | if (rb->w + size > GTP_RB_END(rb->w)) { 261 | /* Don't have enough size in current page, insert a 262 | FID_PAGE_END and try to get next page. */ 263 | if (GTP_RB_END(rb->w) - rb->w >= FID_SIZE) 264 | FID(rb->w) = FID_PAGE_END; 265 | 266 | if (GTP_RB_HEAD(GTP_RB_NEXT(rb->w)) == GTP_RB_HEAD(rb->r)) { 267 | if (gtp_circular) { 268 | rb->r = GTP_RB_NEXT(rb->r); 269 | atomic_inc(>p_rb_discard_page_number); 270 | } else 271 | return NULL; 272 | } 273 | rb->w = GTP_RB_NEXT(rb->w); 274 | 275 | if (id) { 276 | /* Need insert a FID_PAGE_BEGIN. */ 277 | FID(rb->w) = FID_PAGE_BEGIN; 278 | *((u64 *)(rb->w + FID_SIZE)) = id; 279 | rb->w += FRAME_ALIGN(GTP_FRAME_PAGE_BEGIN_SIZE); 280 | } 281 | } 282 | 283 | ret = rb->w; 284 | rb->w += size; 285 | 286 | return ret; 287 | } 288 | 289 | enum gtp_rb_walk_reason { 290 | gtp_rb_walk_end = 0, 291 | gtp_rb_walk_end_page, 292 | gtp_rb_walk_end_entry, 293 | gtp_rb_walk_new_entry, 294 | gtp_rb_walk_type, 295 | gtp_rb_walk_step, 296 | gtp_rb_walk_error, 297 | }; 298 | 299 | /* Check *end. */ 300 | #define GTP_RB_WALK_CHECK_END 0x1 301 | 302 | /* When to the end of a page, goto next one. */ 303 | #define GTP_RB_WALK_PASS_PAGE 0x2 304 | 305 | /* When to the end of a entry, goto next one. 306 | If not set, stop in the first address of next entry and 307 | set S->REASON to gtp_rb_walk_new_entry. */ 308 | #define GTP_RB_WALK_PASS_ENTRY 0x4 309 | 310 | /* Check with id and FID_PAGE_BEGIN to make sure this is the current frame. */ 311 | #define GTP_RB_WALK_CHECK_ID 0x8 312 | 313 | /* Return and set S->REASON to gtp_rb_walk_type if type is same entry type. */ 314 | #define GTP_RB_WALK_CHECK_TYPE 0x10 315 | 316 | /* Walk STEP step in ring_buffer, just record FID_REG, FID_MEM, FID_VAR. */ 317 | #define GTP_RB_WALK_STEP 0x20 318 | 319 | struct gtp_rb_walk_s { 320 | unsigned int flags; 321 | 322 | /* Reason for return. */ 323 | enum gtp_rb_walk_reason reason; 324 | 325 | /* GTP_RB_WALK_CHECK_END, 326 | it will point to the end of this ring buffer. */ 327 | void *end; 328 | 329 | /* GTP_RB_WALK_CHECK_ID */ 330 | u64 id; 331 | 332 | /* GTP_RB_WALK_CHECK_TYPE */ 333 | FID_TYPE type; 334 | 335 | /* GTP_RB_WALK_STEP */ 336 | int step; 337 | }; 338 | 339 | /* Walk in ring buffer RET according to S. And return the new pointer. */ 340 | 341 | static void * 342 | gtp_rb_walk(struct gtp_rb_walk_s *s, void *ret) 343 | { 344 | int step; 345 | void *page_end = GTP_RB_END(ret); 346 | 347 | if (s->flags & GTP_RB_WALK_STEP) 348 | step = 0; 349 | 350 | while (1) { 351 | FID_TYPE fid; 352 | 353 | if ((s->flags & GTP_RB_WALK_CHECK_END) && ret == s->end) { 354 | s->reason = gtp_rb_walk_end; 355 | break; 356 | } 357 | 358 | if (ret == page_end || page_end - ret < FID_SIZE 359 | || FID(ret) == FID_PAGE_END) { 360 | if (!(s->flags & GTP_RB_WALK_PASS_PAGE)) { 361 | s->reason = gtp_rb_walk_end_page; 362 | break; 363 | } 364 | ret = GTP_RB_NEXT(ret); 365 | page_end = GTP_RB_END(ret); 366 | continue; 367 | } 368 | 369 | fid = FID(ret); 370 | 371 | if ((s->flags & GTP_RB_WALK_CHECK_TYPE) && s->type == fid) { 372 | s->reason = gtp_rb_walk_type; 373 | break; 374 | } 375 | 376 | if ((s->flags & GTP_RB_WALK_STEP) 377 | && (fid == FID_REG || fid == FID_MEM || fid == FID_VAR)) { 378 | if (step >= s->step) { 379 | s->reason = gtp_rb_walk_step; 380 | break; 381 | } 382 | step++; 383 | } 384 | 385 | switch (fid) { 386 | case FID_HEAD: 387 | if (!(s->flags & GTP_RB_WALK_PASS_ENTRY)) { 388 | s->reason = gtp_rb_walk_new_entry; 389 | goto out; 390 | } 391 | ret += FRAME_ALIGN(GTP_FRAME_HEAD_SIZE); 392 | break; 393 | case FID_REG: 394 | ret += FRAME_ALIGN(GTP_FRAME_REG_SIZE); 395 | break; 396 | case FID_MEM: { 397 | struct gtp_frame_mem *gfm; 398 | 399 | gfm = (struct gtp_frame_mem *) (ret + FID_SIZE); 400 | ret += FRAME_ALIGN(GTP_FRAME_MEM_SIZE 401 | + gfm->size); 402 | } 403 | break; 404 | case FID_VAR: 405 | ret += FRAME_ALIGN(GTP_FRAME_VAR_SIZE); 406 | break; 407 | case FID_PAGE_BEGIN: 408 | if ((s->flags & GTP_RB_WALK_CHECK_ID) 409 | && s->id != *(u64 *)(ret + FID_SIZE)) { 410 | s->reason = gtp_rb_walk_end_entry; 411 | goto out; 412 | } 413 | ret += FRAME_ALIGN(GTP_FRAME_PAGE_BEGIN_SIZE); 414 | break; 415 | default: 416 | printk(KERN_WARNING 417 | "Walk in gtp ring buffer got error id 0x%x " 418 | "in 0x%p.\n", 419 | fid, ret); 420 | s->reason = gtp_rb_walk_error; 421 | goto out; 422 | break; 423 | } 424 | } 425 | 426 | out: 427 | return ret; 428 | } 429 | 430 | static void * 431 | gtp_rb_walk_reverse(void *buf, void *begin) 432 | { 433 | if (buf == begin) 434 | return NULL; 435 | buf = *(void **)(buf + FID_SIZE + sizeof(u64) + sizeof(ULONGEST)); 436 | 437 | return buf; 438 | } 439 | 440 | static struct gtp_rb_s *gtp_frame_current_rb; 441 | static u64 gtp_frame_current_id; 442 | static struct pt_regs *gtp_frame_current_regs; 443 | 444 | static void 445 | gtp_rb_read_reset(void) 446 | { 447 | int cpu; 448 | 449 | for_each_possible_cpu(cpu) { 450 | struct gtp_rb_s *rb 451 | = (struct gtp_rb_s *)per_cpu_ptr(gtp_rb, cpu); 452 | 453 | rb->rp = rb->r; 454 | rb->rp_id = 0; 455 | } 456 | gtp_frame_current_num = -1; 457 | gtp_frame_current_rb = NULL; 458 | } 459 | 460 | static void 461 | gtp_rb_update_gtp_frame_current(void) 462 | { 463 | gtp_frame_current_id = *(u64 *)(gtp_frame_current_rb->rp + FID_SIZE); 464 | gtp_frame_current_tpe = *(ULONGEST *)(gtp_frame_current_rb->rp 465 | + FID_SIZE + sizeof(u64)); 466 | gtp_frame_current_rb->rp += FRAME_ALIGN(GTP_FRAME_HEAD_SIZE); 467 | gtp_frame_current_regs = NULL; 468 | } 469 | 470 | static int 471 | gtp_rb_read(void) 472 | { 473 | int cpu; 474 | u64 min_id = ULLONG_MAX; 475 | struct gtp_rb_walk_s rbws; 476 | 477 | gtp_frame_current_rb = NULL; 478 | 479 | rbws.flags = GTP_RB_WALK_PASS_PAGE | GTP_RB_WALK_CHECK_END; 480 | 481 | for_each_possible_cpu(cpu) { 482 | struct gtp_rb_s *rb 483 | = (struct gtp_rb_s *)per_cpu_ptr(gtp_rb, cpu); 484 | 485 | if (rb->rp == NULL) 486 | rb->rp = rb->r; 487 | 488 | if (rb->rp_id == 0) { 489 | rbws.end = rb->w; 490 | rb->rp = gtp_rb_walk(&rbws, rb->rp); 491 | if (rbws.reason != gtp_rb_walk_new_entry) 492 | continue; 493 | rb->rp_id = *(u64 *)(rb->rp + FID_SIZE); 494 | } 495 | if (rb->rp_id < min_id) { 496 | min_id = rb->rp_id; 497 | gtp_frame_current_rb = rb; 498 | } 499 | } 500 | 501 | if (gtp_frame_current_rb == NULL) { 502 | gtp_rb_read_reset(); 503 | return -1; 504 | } 505 | 506 | gtp_frame_current_rb->rp_id = 0; 507 | gtp_rb_update_gtp_frame_current(); 508 | gtp_frame_current_num += 1; 509 | 510 | return 0; 511 | } 512 | 513 | static void * 514 | gtp_rb_get_page(struct gtp_rb_s *rb) 515 | { 516 | void *ret = NULL; 517 | unsigned long flags; 518 | 519 | GTP_RB_LOCK_IRQ(rb, flags); 520 | 521 | if (GTP_RB_HEAD(rb->r) == GTP_RB_HEAD(rb->w)) { 522 | if (rb->r == rb->w) 523 | goto out; 524 | /* Move rb->w to next page. */ 525 | if (GTP_RB_END(rb->w) - rb->w >= FID_SIZE) 526 | FID(rb->w) = FID_PAGE_END; 527 | rb->w = GTP_RB_NEXT(rb->w); 528 | } 529 | 530 | ret = rb->r; 531 | { 532 | /* Move this page out of ring. */ 533 | void *prev = GTP_RB_PREV(rb->r); 534 | void *next = GTP_RB_NEXT(rb->r); 535 | 536 | GTP_RB_NEXT(prev) = next; 537 | GTP_RB_PREV(next) = prev; 538 | rb->r = next; 539 | } 540 | 541 | out: 542 | GTP_RB_UNLOCK_IRQ(rb, flags); 543 | return ret; 544 | } 545 | 546 | static void 547 | gtp_rb_put_page(struct gtp_rb_s *rb, void *page, int page_is_empty) 548 | { 549 | void *prev, *next; 550 | unsigned long flags; 551 | 552 | GTP_RB_LOCK_IRQ(rb, flags); 553 | 554 | if (page_is_empty) { 555 | page = GTP_RB_DATA(page); 556 | if (rb->w == GTP_RB_DATA(rb->w)) { 557 | /* Set page before rb->w and set it as rb->w. 558 | If need, set it as rb->r. */ 559 | prev = GTP_RB_PREV(rb->w); 560 | next = rb->w; 561 | if (rb->r == rb->w) 562 | rb->r = page; 563 | rb->w = page; 564 | } else { 565 | /* Set page after rb->w. */ 566 | prev = GTP_RB_DATA(rb->w); 567 | next = GTP_RB_NEXT(rb->w); 568 | } 569 | } else { 570 | if (rb->r == GTP_RB_DATA(rb->r)) { 571 | /* Current rb->r page is point to the begin of a page. 572 | Set page before rb->r and set it as rb->r. */ 573 | prev = GTP_RB_PREV(rb->r); 574 | next = rb->r; 575 | } else { 576 | /* Current rb->r page is not point to the begin of a 577 | page, give up this data. 578 | Set page after rb->r and set it as rb->r. */ 579 | prev = GTP_RB_DATA(rb->r); 580 | next = GTP_RB_NEXT(rb->r); 581 | } 582 | rb->r = page; 583 | } 584 | 585 | GTP_RB_NEXT(prev) = GTP_RB_DATA(page); 586 | GTP_RB_PREV(next) = GTP_RB_DATA(page); 587 | GTP_RB_PREV(page) = prev; 588 | GTP_RB_NEXT(page) = next; 589 | 590 | GTP_RB_UNLOCK_IRQ(rb, flags); 591 | } 592 | -------------------------------------------------------------------------------- /perf_event.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Following part is base on kernel/events/core.c 3 | * commit 9985c20f9e4aee6857c08246b273a3695a52b929 4 | * Following part is base on kernel/events/internal.h 5 | * commit a8b0ca17b80e92faab46ee7179ba9e99ccb61233 6 | * Following part is base on kernel/events/ring_buffer.c 7 | * commit a7ac67ea021b4603095d2aa458bc41641238f22c 8 | */ 9 | 10 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)) 11 | 12 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 13 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 14 | struct ring_buffer { 15 | atomic_t refcount; 16 | struct rcu_head rcu_head; 17 | #ifdef CONFIG_PERF_USE_VMALLOC 18 | struct work_struct work; 19 | int page_order; /* allocation order */ 20 | #endif 21 | int nr_pages; /* nr of data pages */ 22 | int writable; /* are we writable */ 23 | 24 | atomic_t poll; /* POLL_ for wakeups */ 25 | 26 | local_t head; /* write position */ 27 | local_t nest; /* nested writers */ 28 | local_t events; /* event limit */ 29 | local_t wakeup; /* wakeup stamp */ 30 | local_t lost; /* nr records lost */ 31 | 32 | long watermark; /* wakeup watermark */ 33 | 34 | struct perf_event_mmap_page *user_page; 35 | void *data_pages[0]; 36 | }; 37 | #endif 38 | 39 | static inline u64 perf_clock(void) 40 | { 41 | return GTP_LOCAL_CLOCK; 42 | } 43 | 44 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) \ 45 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 46 | static inline struct perf_cpu_context * 47 | __get_cpu_context(struct perf_event_context *ctx) 48 | { 49 | return this_cpu_ptr(ctx->pmu->pmu_cpu_context); 50 | } 51 | #else 52 | static DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context); 53 | #endif 54 | 55 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 56 | static inline int is_cgroup_event(struct perf_event *event) 57 | { 58 | return 0; 59 | } 60 | 61 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 62 | static inline bool 63 | perf_cgroup_match(struct perf_event *event) 64 | { 65 | return true; 66 | } 67 | 68 | /* 69 | * Update the record of the current time in a context. 70 | */ 71 | static void update_context_time(struct perf_event_context *ctx) 72 | { 73 | u64 now = perf_clock(); 74 | 75 | ctx->time += now - ctx->timestamp; 76 | ctx->timestamp = now; 77 | } 78 | 79 | static u64 perf_event_time(struct perf_event *event) 80 | { 81 | struct perf_event_context *ctx = event->ctx; 82 | 83 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 84 | /* 85 | if (is_cgroup_event(event)) 86 | return perf_cgroup_event_time(event); 87 | */ 88 | 89 | return ctx ? ctx->time : 0; 90 | } 91 | 92 | /* 93 | * Update the total_time_enabled and total_time_running fields for a event. 94 | */ 95 | static void update_event_times(struct perf_event *event) 96 | { 97 | struct perf_event_context *ctx = event->ctx; 98 | u64 run_end; 99 | 100 | if (event->state < PERF_EVENT_STATE_INACTIVE || 101 | event->group_leader->state < PERF_EVENT_STATE_INACTIVE) 102 | return; 103 | /* 104 | * in cgroup mode, time_enabled represents 105 | * the time the event was enabled AND active 106 | * tasks were in the monitored cgroup. This is 107 | * independent of the activity of the context as 108 | * there may be a mix of cgroup and non-cgroup events. 109 | * 110 | * That is why we treat cgroup events differently 111 | * here. 112 | */ 113 | if (is_cgroup_event(event)) 114 | run_end = perf_event_time(event); 115 | else if (ctx->is_active) 116 | run_end = ctx->time; 117 | else 118 | run_end = event->tstamp_stopped; 119 | 120 | event->total_time_enabled = run_end - event->tstamp_enabled; 121 | 122 | if (event->state == PERF_EVENT_STATE_INACTIVE) 123 | run_end = event->tstamp_stopped; 124 | else 125 | run_end = perf_event_time(event); 126 | 127 | event->total_time_running = run_end - event->tstamp_running; 128 | 129 | } 130 | 131 | static inline int 132 | event_filter_match(struct perf_event *event) 133 | { 134 | return (event->cpu == -1 || event->cpu == smp_processor_id()) 135 | && perf_cgroup_match(event); 136 | } 137 | 138 | static void 139 | event_sched_out(struct perf_event *event, 140 | struct perf_cpu_context *cpuctx, 141 | struct perf_event_context *ctx) 142 | { 143 | u64 tstamp = perf_event_time(event); 144 | u64 delta; 145 | /* 146 | * An event which could not be activated because of 147 | * filter mismatch still needs to have its timings 148 | * maintained, otherwise bogus information is return 149 | * via read() for time_enabled, time_running: 150 | */ 151 | if (event->state == PERF_EVENT_STATE_INACTIVE 152 | && !event_filter_match(event)) { 153 | delta = tstamp - event->tstamp_stopped; 154 | event->tstamp_running += delta; 155 | event->tstamp_stopped = tstamp; 156 | } 157 | 158 | if (event->state != PERF_EVENT_STATE_ACTIVE) 159 | return; 160 | 161 | event->state = PERF_EVENT_STATE_INACTIVE; 162 | if (event->pending_disable) { 163 | event->pending_disable = 0; 164 | event->state = PERF_EVENT_STATE_OFF; 165 | } 166 | event->tstamp_stopped = tstamp; 167 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) \ 168 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 169 | event->pmu->del(event, 0); 170 | #else 171 | event->pmu->disable(event); 172 | #endif 173 | event->oncpu = -1; 174 | 175 | if (!is_software_event(event)) 176 | cpuctx->active_oncpu--; 177 | ctx->nr_active--; 178 | if (event->attr.exclusive || !cpuctx->active_oncpu) 179 | cpuctx->exclusive = 0; 180 | } 181 | 182 | /* 183 | * Put a event into inactive state and update time fields. 184 | * Enabling the leader of a group effectively enables all 185 | * the group members that aren't explicitly disabled, so we 186 | * have to update their ->tstamp_enabled also. 187 | * Note: this works for group members as well as group leaders 188 | * since the non-leader members' sibling_lists will be empty. 189 | */ 190 | static void __perf_event_mark_enabled(struct perf_event *event, 191 | struct perf_event_context *ctx) 192 | { 193 | struct perf_event *sub; 194 | u64 tstamp = perf_event_time(event); 195 | 196 | event->state = PERF_EVENT_STATE_INACTIVE; 197 | event->tstamp_enabled = tstamp - event->total_time_enabled; 198 | list_for_each_entry(sub, &event->sibling_list, group_entry) { 199 | if (sub->state >= PERF_EVENT_STATE_INACTIVE) 200 | sub->tstamp_enabled = tstamp - sub->total_time_enabled; 201 | } 202 | } 203 | 204 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) \ 205 | && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,1)) 206 | /* 207 | * Return 1 for a group consisting entirely of software events, 208 | * 0 if the group contains any hardware events. 209 | */ 210 | static int is_software_only_group(struct perf_event *leader) 211 | { 212 | struct perf_event *event; 213 | 214 | if (!is_software_event(leader)) 215 | return 0; 216 | 217 | list_for_each_entry(event, &leader->sibling_list, group_entry) 218 | if (!is_software_event(event)) 219 | return 0; 220 | 221 | return 1; 222 | } 223 | #endif 224 | 225 | /* 226 | * Work out whether we can put this event group on the CPU now. 227 | */ 228 | static int group_can_go_on(struct perf_event *event, 229 | struct perf_cpu_context *cpuctx, 230 | int can_add_hw) 231 | { 232 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) \ 233 | && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,1)) 234 | /* 235 | * Groups consisting entirely of software events can always go on. 236 | */ 237 | if (is_software_only_group(event)) 238 | return 1; 239 | #else 240 | /* 241 | * Groups consisting entirely of software events can always go on. 242 | */ 243 | if (event->group_flags & PERF_GROUP_SOFTWARE) 244 | return 1; 245 | #endif 246 | 247 | /* 248 | * If an exclusive group is already on, no other hardware 249 | * events can go on. 250 | */ 251 | if (cpuctx->exclusive) 252 | return 0; 253 | /* 254 | * If this group is exclusive and there are already 255 | * events on the CPU, it can't go on. 256 | */ 257 | if (event->attr.exclusive && cpuctx->active_oncpu) 258 | return 0; 259 | /* 260 | * Otherwise, try to add it if all previous groups were able 261 | * to go on. 262 | */ 263 | return can_add_hw; 264 | } 265 | 266 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 267 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 268 | #ifndef CONFIG_PERF_USE_VMALLOC 269 | static inline int page_order(struct ring_buffer *rb) 270 | { 271 | return 0; 272 | } 273 | #else 274 | /* 275 | * Back perf_mmap() with vmalloc memory. 276 | * 277 | * Required for architectures that have d-cache aliasing issues. 278 | */ 279 | 280 | static inline int page_order(struct ring_buffer *rb) 281 | { 282 | return rb->page_order; 283 | } 284 | #endif 285 | #else 286 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) \ 287 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 288 | #ifndef CONFIG_PERF_USE_VMALLOC 289 | static inline int page_order(struct perf_buffer *buffer) 290 | { 291 | return 0; 292 | } 293 | #else 294 | static inline int page_order(struct perf_buffer *buffer) 295 | { 296 | return buffer->page_order; 297 | } 298 | #endif 299 | #else 300 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) 301 | #ifndef CONFIG_PERF_USE_VMALLOC 302 | static inline int page_order(struct perf_mmap_data *data) 303 | { 304 | return 0; 305 | } 306 | #else 307 | static inline int page_order(struct perf_mmap_data *data) 308 | { 309 | return data->page_order; 310 | } 311 | #endif 312 | #else 313 | static inline int page_order(struct perf_mmap_data *data) 314 | { 315 | return data->data_order; 316 | } 317 | #endif 318 | #endif 319 | #endif 320 | 321 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) \ 322 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 323 | __always_inline void perf_output_copy(struct perf_output_handle *handle, 324 | const void *buf, unsigned int len) 325 | { 326 | do { 327 | unsigned long size = min_t(unsigned long, handle->size, len); 328 | 329 | memcpy(handle->addr, buf, size); 330 | 331 | len -= size; 332 | handle->addr += size; 333 | buf += size; 334 | handle->size -= size; 335 | if (!handle->size) { 336 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 337 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 338 | struct ring_buffer *buffer = handle->rb; 339 | #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) \ 340 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 341 | struct perf_buffer *buffer = handle->buffer; 342 | #else 343 | struct perf_mmap_data *buffer = handle->data; 344 | #endif 345 | 346 | handle->page++; 347 | handle->page &= buffer->nr_pages - 1; 348 | handle->addr = buffer->data_pages[handle->page]; 349 | handle->size = PAGE_SIZE << page_order(buffer); 350 | } 351 | } while (len); 352 | } 353 | #else 354 | void perf_output_copy(struct perf_output_handle *handle, 355 | const void *buf, unsigned int len) 356 | { 357 | unsigned int pages_mask; 358 | unsigned long offset; 359 | unsigned int size; 360 | void **pages; 361 | 362 | offset = handle->offset; 363 | pages_mask = handle->data->nr_pages - 1; 364 | pages = handle->data->data_pages; 365 | 366 | do { 367 | unsigned long page_offset; 368 | unsigned long page_size; 369 | int nr; 370 | 371 | nr = (offset >> PAGE_SHIFT) & pages_mask; 372 | page_size = 1UL << (handle->data->data_order + PAGE_SHIFT); 373 | page_offset = offset & (page_size - 1); 374 | size = min_t(unsigned int, page_size - page_offset, len); 375 | 376 | memcpy(pages[nr] + page_offset, buf, size); 377 | 378 | len -= size; 379 | buf += size; 380 | offset += size; 381 | } while (len); 382 | 383 | handle->offset = offset; 384 | 385 | /* 386 | * Check we didn't copy past our reservation window, taking the 387 | * possible unsigned int wrap into account. 388 | */ 389 | WARN_ON_ONCE(((long)(handle->head - handle->offset)) < 0); 390 | } 391 | #endif 392 | 393 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) 394 | 395 | /* 396 | * If we inherit events we want to return the parent event id 397 | * to userspace. 398 | */ 399 | static u64 primary_event_id(struct perf_event *event) 400 | { 401 | u64 id = event->id; 402 | 403 | if (event->parent) 404 | id = event->parent->id; 405 | 406 | return id; 407 | } 408 | 409 | static u32 perf_event_pid(struct perf_event *event, struct task_struct *p) 410 | { 411 | /* 412 | * only top level events have the pid namespace they were created in 413 | */ 414 | if (event->parent) 415 | event = event->parent; 416 | 417 | return task_tgid_nr_ns(p, event->ns); 418 | } 419 | 420 | static u32 perf_event_tid(struct perf_event *event, struct task_struct *p) 421 | { 422 | /* 423 | * only top level events have the pid namespace they were created in 424 | */ 425 | if (event->parent) 426 | event = event->parent; 427 | 428 | return task_pid_nr_ns(p, event->ns); 429 | } 430 | 431 | static void __perf_event_header__init_id(struct perf_event_header *header, 432 | struct perf_sample_data *data, 433 | struct perf_event *event) 434 | { 435 | u64 sample_type = event->attr.sample_type; 436 | 437 | data->type = sample_type; 438 | header->size += event->id_header_size; 439 | 440 | if (sample_type & PERF_SAMPLE_TID) { 441 | /* namespace issues */ 442 | data->tid_entry.pid = perf_event_pid(event, current); 443 | data->tid_entry.tid = perf_event_tid(event, current); 444 | } 445 | 446 | if (sample_type & PERF_SAMPLE_TIME) 447 | data->time = perf_clock(); 448 | 449 | if (sample_type & PERF_SAMPLE_ID) 450 | data->id = primary_event_id(event); 451 | 452 | if (sample_type & PERF_SAMPLE_STREAM_ID) 453 | data->stream_id = event->id; 454 | 455 | if (sample_type & PERF_SAMPLE_CPU) { 456 | data->cpu_entry.cpu = raw_smp_processor_id(); 457 | data->cpu_entry.reserved = 0; 458 | } 459 | } 460 | 461 | static void __perf_event__output_id_sample(struct perf_output_handle *handle, 462 | struct perf_sample_data *data) 463 | { 464 | u64 sample_type = data->type; 465 | 466 | if (sample_type & PERF_SAMPLE_TID) 467 | perf_output_put(handle, data->tid_entry); 468 | 469 | if (sample_type & PERF_SAMPLE_TIME) 470 | perf_output_put(handle, data->time); 471 | 472 | if (sample_type & PERF_SAMPLE_ID) 473 | perf_output_put(handle, data->id); 474 | 475 | if (sample_type & PERF_SAMPLE_STREAM_ID) 476 | perf_output_put(handle, data->stream_id); 477 | 478 | if (sample_type & PERF_SAMPLE_CPU) 479 | perf_output_put(handle, data->cpu_entry); 480 | } 481 | 482 | static void perf_event_header__init_id(struct perf_event_header *header, 483 | struct perf_sample_data *data, 484 | struct perf_event *event) 485 | { 486 | if (event->attr.sample_id_all) 487 | __perf_event_header__init_id(header, data, event); 488 | } 489 | 490 | static void perf_event__output_id_sample(struct perf_event *event, 491 | struct perf_output_handle *handle, 492 | struct perf_sample_data *sample) 493 | { 494 | if (event->attr.sample_id_all) 495 | __perf_event__output_id_sample(handle, sample); 496 | } 497 | 498 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)) \ 499 | && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,4)) 500 | static void gtp_perf_event_wakeup(struct perf_event *event) 501 | { 502 | wake_up_all(&event->waitq); 503 | 504 | if (event->pending_kill) { 505 | kill_fasync(&event->fasync, SIGIO, event->pending_kill); 506 | event->pending_kill = 0; 507 | } 508 | } 509 | #endif 510 | 511 | static void perf_output_wakeup(struct perf_output_handle *handle) 512 | { 513 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 514 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 515 | atomic_set(&handle->rb->poll, POLL_IN); 516 | #else 517 | atomic_set(&handle->buffer->poll, POLL_IN); 518 | #endif 519 | 520 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)) \ 521 | && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,4)) 522 | if (handle->nmi) { 523 | #endif 524 | handle->event->pending_wakeup = 1; 525 | irq_work_queue(&handle->event->pending); 526 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)) \ 527 | && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,4)) 528 | } else 529 | gtp_perf_event_wakeup(handle->event); 530 | #endif 531 | } 532 | 533 | static void perf_output_put_handle(struct perf_output_handle *handle) 534 | { 535 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 536 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 537 | struct ring_buffer *buffer = handle->rb; 538 | #else 539 | struct perf_buffer *buffer = handle->buffer; 540 | #endif 541 | unsigned long head; 542 | 543 | again: 544 | head = local_read(&buffer->head); 545 | 546 | /* 547 | * IRQ/NMI can happen here, which means we can miss a head update. 548 | */ 549 | 550 | if (!local_dec_and_test(&buffer->nest)) 551 | goto out; 552 | 553 | /* 554 | * Publish the known good head. Rely on the full barrier implied 555 | * by atomic_dec_and_test() order the buffer->head read and this 556 | * write. 557 | */ 558 | buffer->user_page->data_head = head; 559 | 560 | /* 561 | * Now check if we missed an update, rely on the (compiler) 562 | * barrier in atomic_dec_and_test() to re-read buffer->head. 563 | */ 564 | if (unlikely(head != local_read(&buffer->head))) { 565 | local_inc(&buffer->nest); 566 | goto again; 567 | } 568 | 569 | if (handle->wakeup != local_read(&buffer->wakeup)) 570 | perf_output_wakeup(handle); 571 | 572 | out: 573 | preempt_enable(); 574 | } 575 | 576 | static void gtp_perf_output_end(struct perf_output_handle *handle) 577 | { 578 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)) \ 579 | && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,4)) 580 | struct perf_event *event = handle->event; 581 | struct perf_buffer *buffer = handle->buffer; 582 | 583 | int wakeup_events = event->attr.wakeup_events; 584 | 585 | if (handle->sample && wakeup_events) { 586 | int events = local_inc_return(&buffer->events); 587 | if (events >= wakeup_events) { 588 | local_sub(wakeup_events, &buffer->events); 589 | local_inc(&buffer->wakeup); 590 | } 591 | } 592 | #endif 593 | 594 | perf_output_put_handle(handle); 595 | rcu_read_unlock(); 596 | } 597 | 598 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 599 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 600 | static unsigned long perf_data_size(struct ring_buffer *buffer) 601 | #else 602 | static unsigned long perf_data_size(struct perf_buffer *buffer) 603 | #endif 604 | { 605 | return buffer->nr_pages << (PAGE_SHIFT + page_order(buffer)); 606 | } 607 | 608 | /* 609 | * Output 610 | */ 611 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 612 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 613 | static bool perf_output_space(struct ring_buffer *buffer, unsigned long tail, 614 | unsigned long offset, unsigned long head) 615 | #else 616 | static bool perf_output_space(struct perf_buffer *buffer, unsigned long tail, 617 | unsigned long offset, unsigned long head) 618 | #endif 619 | { 620 | unsigned long mask; 621 | 622 | if (!buffer->writable) 623 | return true; 624 | 625 | mask = perf_data_size(buffer) - 1; 626 | 627 | offset = (offset - tail) & mask; 628 | head = (head - tail) & mask; 629 | 630 | if ((int)(head - offset) < 0) 631 | return false; 632 | 633 | return true; 634 | } 635 | 636 | /* 637 | * We need to ensure a later event_id doesn't publish a head when a former 638 | * event isn't done writing. However since we need to deal with NMIs we 639 | * cannot fully serialize things. 640 | * 641 | * We only publish the head (and generate a wakeup) when the outer-most 642 | * event completes. 643 | */ 644 | static void perf_output_get_handle(struct perf_output_handle *handle) 645 | { 646 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 647 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 648 | struct ring_buffer *buffer = handle->rb; 649 | #else 650 | struct perf_buffer *buffer = handle->buffer; 651 | #endif 652 | 653 | preempt_disable(); 654 | local_inc(&buffer->nest); 655 | handle->wakeup = local_read(&buffer->wakeup); 656 | } 657 | 658 | static int gtp_perf_output_begin(struct perf_output_handle *handle, 659 | struct perf_event *event, unsigned int size, 660 | int nmi, int sample) 661 | { 662 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 663 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 664 | struct ring_buffer *buffer; 665 | #else 666 | struct perf_buffer *buffer; 667 | #endif 668 | unsigned long tail, offset, head; 669 | int have_lost; 670 | struct perf_sample_data sample_data; 671 | struct { 672 | struct perf_event_header header; 673 | u64 id; 674 | u64 lost; 675 | } lost_event; 676 | 677 | rcu_read_lock(); 678 | /* 679 | * For inherited events we send all the output towards the parent. 680 | */ 681 | if (event->parent) 682 | event = event->parent; 683 | 684 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 685 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 686 | buffer = rcu_dereference(event->rb); 687 | #else 688 | buffer = rcu_dereference(event->buffer); 689 | #endif 690 | if (!buffer) 691 | goto out; 692 | 693 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) \ 694 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) 695 | handle->rb = buffer; 696 | #else 697 | handle->buffer = buffer; 698 | #endif 699 | handle->event = event; 700 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)) \ 701 | && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,4)) 702 | handle->nmi = nmi; 703 | handle->sample = sample; 704 | #endif 705 | 706 | if (!buffer->nr_pages) 707 | goto out; 708 | 709 | have_lost = local_read(&buffer->lost); 710 | if (have_lost) { 711 | lost_event.header.size = sizeof(lost_event); 712 | perf_event_header__init_id(&lost_event.header, &sample_data, 713 | event); 714 | size += lost_event.header.size; 715 | } 716 | 717 | perf_output_get_handle(handle); 718 | 719 | do { 720 | /* 721 | * Userspace could choose to issue a mb() before updating the 722 | * tail pointer. So that all reads will be completed before the 723 | * write is issued. 724 | */ 725 | tail = ACCESS_ONCE(buffer->user_page->data_tail); 726 | smp_rmb(); 727 | offset = head = local_read(&buffer->head); 728 | head += size; 729 | if (unlikely(!perf_output_space(buffer, tail, offset, head))) 730 | goto fail; 731 | } while (local_cmpxchg(&buffer->head, offset, head) != offset); 732 | 733 | if (head - local_read(&buffer->wakeup) > buffer->watermark) 734 | local_add(buffer->watermark, &buffer->wakeup); 735 | 736 | handle->page = offset >> (PAGE_SHIFT + page_order(buffer)); 737 | handle->page &= buffer->nr_pages - 1; 738 | handle->size = offset & ((PAGE_SIZE << page_order(buffer)) - 1); 739 | handle->addr = buffer->data_pages[handle->page]; 740 | handle->addr += handle->size; 741 | handle->size = (PAGE_SIZE << page_order(buffer)) - handle->size; 742 | 743 | if (have_lost) { 744 | lost_event.header.type = PERF_RECORD_LOST; 745 | lost_event.header.misc = 0; 746 | lost_event.id = event->id; 747 | lost_event.lost = local_xchg(&buffer->lost, 0); 748 | 749 | perf_output_put(handle, lost_event); 750 | perf_event__output_id_sample(event, handle, &sample_data); 751 | } 752 | 753 | return 0; 754 | 755 | fail: 756 | local_inc(&buffer->lost); 757 | perf_output_put_handle(handle); 758 | out: 759 | rcu_read_unlock(); 760 | 761 | return -ENOSPC; 762 | } 763 | 764 | /* 765 | * IRQ throttle logging 766 | */ 767 | 768 | static void perf_log_throttle(struct perf_event *event, int enable) 769 | { 770 | struct perf_output_handle handle; 771 | struct perf_sample_data sample; 772 | int ret; 773 | 774 | struct { 775 | struct perf_event_header header; 776 | u64 time; 777 | u64 id; 778 | u64 stream_id; 779 | } throttle_event = { 780 | .header = { 781 | .type = PERF_RECORD_THROTTLE, 782 | .misc = 0, 783 | .size = sizeof(throttle_event), 784 | }, 785 | .time = perf_clock(), 786 | .id = primary_event_id(event), 787 | .stream_id = event->id, 788 | }; 789 | 790 | if (enable) 791 | throttle_event.header.type = PERF_RECORD_UNTHROTTLE; 792 | 793 | perf_event_header__init_id(&throttle_event.header, &sample, event); 794 | 795 | ret = gtp_perf_output_begin(&handle, event, 796 | throttle_event.header.size, 1, 0); 797 | if (ret) 798 | return; 799 | 800 | perf_output_put(&handle, throttle_event); 801 | perf_event__output_id_sample(event, &handle, &sample); 802 | gtp_perf_output_end(&handle); 803 | } 804 | #endif 805 | 806 | static void perf_set_shadow_time(struct perf_event *event, 807 | struct perf_event_context *ctx, 808 | u64 tstamp) 809 | { 810 | /* 811 | * use the correct time source for the time snapshot 812 | * 813 | * We could get by without this by leveraging the 814 | * fact that to get to this function, the caller 815 | * has most likely already called update_context_time() 816 | * and update_cgrp_time_xx() and thus both timestamp 817 | * are identical (or very close). Given that tstamp is, 818 | * already adjusted for cgroup, we could say that: 819 | * tstamp - ctx->timestamp 820 | * is equivalent to 821 | * tstamp - cgrp->timestamp. 822 | * 823 | * Then, in perf_output_read(), the calculation would 824 | * work with no changes because: 825 | * - event is guaranteed scheduled in 826 | * - no scheduled out in between 827 | * - thus the timestamp would be the same 828 | * 829 | * But this is a bit hairy. 830 | * 831 | * So instead, we have an explicit cgroup call to remain 832 | * within the time time source all along. We believe it 833 | * is cleaner and simpler to understand. 834 | */ 835 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 836 | #if 0 837 | if (is_cgroup_event(event)) 838 | perf_cgroup_set_shadow_time(event, tstamp); 839 | else 840 | #endif 841 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) \ 842 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 843 | event->shadow_ctx_time = tstamp - ctx->timestamp; 844 | #endif 845 | } 846 | 847 | #define MAX_INTERRUPTS (~0ULL) 848 | 849 | static int 850 | event_sched_in(struct perf_event *event, 851 | struct perf_cpu_context *cpuctx, 852 | struct perf_event_context *ctx) 853 | { 854 | u64 tstamp = perf_event_time(event); 855 | 856 | if (event->state <= PERF_EVENT_STATE_OFF) 857 | return 0; 858 | 859 | event->state = PERF_EVENT_STATE_ACTIVE; 860 | event->oncpu = smp_processor_id(); 861 | 862 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) 863 | /* 864 | * Unthrottle events, since we scheduled we might have missed several 865 | * ticks already, also for a heavily scheduling task there is little 866 | * guarantee it'll get a tick in a timely manner. 867 | */ 868 | if (unlikely(event->hw.interrupts == MAX_INTERRUPTS)) { 869 | perf_log_throttle(event, 1); 870 | event->hw.interrupts = 0; 871 | } 872 | #endif 873 | 874 | /* 875 | * The new state must be visible before we turn it on in the hardware: 876 | */ 877 | smp_wmb(); 878 | 879 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) \ 880 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 881 | if (event->pmu->add(event, PERF_EF_START)) { 882 | #else 883 | if (event->pmu->enable(event)) { 884 | #endif 885 | event->state = PERF_EVENT_STATE_INACTIVE; 886 | event->oncpu = -1; 887 | return -EAGAIN; 888 | } 889 | 890 | event->tstamp_running += tstamp - event->tstamp_stopped; 891 | 892 | perf_set_shadow_time(event, ctx, tstamp); 893 | 894 | if (!is_software_event(event)) 895 | cpuctx->active_oncpu++; 896 | ctx->nr_active++; 897 | 898 | if (event->attr.exclusive) 899 | cpuctx->exclusive = 1; 900 | 901 | return 0; 902 | } 903 | 904 | /* 905 | * Cross CPU call to enable a performance event 906 | */ 907 | static int __gtp_perf_event_enable(void *info) 908 | { 909 | struct perf_event *event = info; 910 | struct perf_event_context *ctx = event->ctx; 911 | struct perf_event *leader = event->group_leader; 912 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) \ 913 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 914 | struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); 915 | #else 916 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); 917 | #endif 918 | int err; 919 | 920 | if (WARN_ON_ONCE(!ctx->is_active)) 921 | return -EINVAL; 922 | 923 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)) 924 | raw_spin_lock(&ctx->lock); 925 | #else 926 | spin_lock(&ctx->lock); 927 | #endif 928 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) 929 | ctx->is_active = 1; 930 | #endif 931 | update_context_time(ctx); 932 | 933 | if (event->state >= PERF_EVENT_STATE_INACTIVE) 934 | goto unlock; 935 | 936 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 937 | /* 938 | * set current task's cgroup time reference point 939 | */ 940 | /* perf_cgroup_set_timestamp(current, ctx); */ 941 | 942 | __perf_event_mark_enabled(event, ctx); 943 | 944 | if (!event_filter_match(event)) { 945 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 946 | /* 947 | if (is_cgroup_event(event)) 948 | perf_cgroup_defer_enabled(event); 949 | */ 950 | goto unlock; 951 | } 952 | 953 | /* 954 | * If the event is in a group and isn't the group leader, 955 | * then don't put it on unless the group is on. 956 | */ 957 | if (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE) 958 | goto unlock; 959 | 960 | if (!group_can_go_on(event, cpuctx, 1)) { 961 | err = -EEXIST; 962 | } else { 963 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 964 | /* 965 | if (event == leader) 966 | err = group_sched_in(event, cpuctx, ctx); 967 | else 968 | */ 969 | err = event_sched_in(event, cpuctx, ctx); 970 | } 971 | 972 | /* KGTP doesn't support group. */ 973 | #if 0 974 | if (err) { 975 | /* 976 | * If this event can't go on and it's part of a 977 | * group, then the whole group has to come off. 978 | */ 979 | if (leader != event) 980 | group_sched_out(leader, cpuctx, ctx); 981 | if (leader->attr.pinned) { 982 | update_group_times(leader); 983 | leader->state = PERF_EVENT_STATE_ERROR; 984 | } 985 | } 986 | #endif 987 | 988 | unlock: 989 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)) 990 | raw_spin_unlock(&ctx->lock); 991 | #else 992 | spin_unlock(&ctx->lock); 993 | #endif 994 | 995 | return 0; 996 | } 997 | 998 | /* 999 | * Cross CPU call to disable a performance event 1000 | */ 1001 | static int __gtp_perf_event_disable(void *info) 1002 | { 1003 | struct perf_event *event = info; 1004 | struct perf_event_context *ctx = event->ctx; 1005 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) \ 1006 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 1007 | struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); 1008 | #else 1009 | struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); 1010 | #endif 1011 | 1012 | /* 1013 | * If this is a per-task event, need to check whether this 1014 | * event's task is the current task on this cpu. 1015 | * 1016 | * Can trigger due to concurrent perf_event_context_sched_out() 1017 | * flipping contexts around. 1018 | */ 1019 | if (ctx->task && cpuctx->task_ctx != ctx) 1020 | return -EINVAL; 1021 | 1022 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)) 1023 | raw_spin_lock(&ctx->lock); 1024 | #else 1025 | spin_lock(&ctx->lock); 1026 | #endif 1027 | 1028 | /* 1029 | * If the event is on, turn it off. 1030 | * If it is in error state, leave it in error state. 1031 | */ 1032 | if (event->state >= PERF_EVENT_STATE_INACTIVE) { 1033 | update_context_time(ctx); 1034 | /* KGTP doesn't support PERF_FLAG_PID_CGROUP */ 1035 | /* update_cgrp_time_from_event(event); */ 1036 | update_event_times(event); 1037 | /* KGTP doesn't support group. */ 1038 | /* 1039 | update_group_times(event); 1040 | if (event == event->group_leader) 1041 | group_sched_out(event, cpuctx, ctx); 1042 | else 1043 | */ 1044 | event_sched_out(event, cpuctx, ctx); 1045 | event->state = PERF_EVENT_STATE_OFF; 1046 | } 1047 | 1048 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)) 1049 | raw_spin_unlock(&ctx->lock); 1050 | #else 1051 | spin_unlock(&ctx->lock); 1052 | #endif 1053 | 1054 | return 0; 1055 | } 1056 | 1057 | /** 1058 | * cpu_function_call - call a function on the cpu 1059 | * @func: the function to be called 1060 | * @info: the function call argument 1061 | * 1062 | * Calls the function @func on the remote cpu. 1063 | * 1064 | * returns: @func return value or -ENXIO when the cpu is offline 1065 | */ 1066 | struct remote_function_call { 1067 | struct task_struct *p; 1068 | int (*func)(void *info); 1069 | void *info; 1070 | int ret; 1071 | }; 1072 | 1073 | static void remote_function(void *data) 1074 | { 1075 | struct remote_function_call *tfc = data; 1076 | 1077 | #if 0 1078 | struct task_struct *p = tfc->p; 1079 | 1080 | if (p) { 1081 | tfc->ret = -EAGAIN; 1082 | if (task_cpu(p) != smp_processor_id() || !task_curr(p)) 1083 | return; 1084 | } 1085 | #endif 1086 | 1087 | tfc->ret = tfc->func(tfc->info); 1088 | } 1089 | 1090 | static int cpu_function_call(int cpu, int (*func) (void *info), void *info) 1091 | { 1092 | struct remote_function_call data = { 1093 | .p = NULL, 1094 | .func = func, 1095 | .info = info, 1096 | .ret = -ENXIO, /* No such CPU */ 1097 | }; 1098 | 1099 | smp_call_function_single(cpu, remote_function, &data, 1); 1100 | 1101 | return data.ret; 1102 | } 1103 | 1104 | static int 1105 | gtp_perf_event_enable(struct perf_event *event) 1106 | { 1107 | if (event->cpu == smp_processor_id()) 1108 | return __gtp_perf_event_enable(event); 1109 | else 1110 | return cpu_function_call(event->cpu, 1111 | __gtp_perf_event_enable, event); 1112 | } 1113 | 1114 | static int 1115 | gtp_perf_event_disable(struct perf_event *event) 1116 | { 1117 | if (event->cpu == smp_processor_id()) 1118 | return __gtp_perf_event_disable(event); 1119 | else 1120 | return cpu_function_call(event->cpu, 1121 | __gtp_perf_event_disable, event); 1122 | } 1123 | 1124 | #endif 1125 | 1126 | /* 1127 | This function get from perf_event_reset. 1128 | */ 1129 | 1130 | static void gtp_perf_event_set(struct perf_event *event, u64 val) 1131 | { 1132 | u64 enabled, running; 1133 | 1134 | /* (void)perf_event_read(event); */ 1135 | perf_event_read_value(event, &enabled, &running); 1136 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) \ 1137 | || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) 1138 | local64_set(&event->count, val); 1139 | #else 1140 | atomic64_set(&event->count, val); 1141 | #endif 1142 | /*XXX: it need be handle later. */ 1143 | /* perf_event_update_userpage(event); */ 1144 | } 1145 | -------------------------------------------------------------------------------- /plugin_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "gtp.h" 7 | 8 | /* This include just for sprint_backtrace. */ 9 | #include 10 | 11 | static void plugin_example_exit(void); 12 | 13 | struct gtp_var *test1 = NULL, *test2 = NULL, *test3 = NULL, *test4 = NULL; 14 | 15 | static int64_t test2_val = 20; 16 | 17 | static int 18 | test2_hooks_get_val(struct gtp_trace_s *unused1, struct gtp_var *unused2, 19 | int64_t *val) 20 | { 21 | *val = test2_val; 22 | return 0; 23 | } 24 | 25 | static int 26 | test2_hooks_set_val(struct gtp_trace_s *unused1, 27 | struct gtp_var *unused2, int64_t val) 28 | { 29 | test2_val = val; 30 | return 0; 31 | } 32 | 33 | static struct gtp_var_hooks test2_hooks = { 34 | .gdb_get_val = test2_hooks_get_val, 35 | .gdb_set_val = test2_hooks_set_val, 36 | .agent_get_val = test2_hooks_get_val, 37 | .agent_set_val = test2_hooks_set_val, 38 | }; 39 | 40 | static int 41 | test3_hooks_set_val(struct gtp_trace_s *unused1, 42 | struct gtp_var *unused2, int64_t val) 43 | { 44 | char sym[KSYM_SYMBOL_LEN]; 45 | 46 | sprint_symbol(sym, (unsigned long)val); 47 | printk(KERN_WARNING "<%lu> %s\n", (unsigned long)val, sym); 48 | return 0; 49 | } 50 | 51 | static struct gtp_var_hooks test3_hooks = { 52 | .agent_set_val = test3_hooks_set_val, 53 | }; 54 | 55 | static int 56 | test4_hooks_set_val(struct gtp_trace_s *gts, 57 | struct gtp_var *unused, int64_t val) 58 | { 59 | char sym[KSYM_SYMBOL_LEN]; 60 | unsigned long addr = (unsigned long)gtp_action_reg_read(gts, 61 | GTP_PC_NUM); 62 | 63 | sprint_symbol(sym, (unsigned long)addr); 64 | printk(KERN_WARNING "<%lu> %s\n", (unsigned long)addr, sym); 65 | return 0; 66 | } 67 | 68 | static struct gtp_var_hooks test4_hooks = { 69 | .agent_set_val = test4_hooks_set_val, 70 | }; 71 | 72 | static int 73 | plugin_example_init(void) 74 | { 75 | int ret = 0; 76 | 77 | ret = gtp_plugin_mod_register(THIS_MODULE); 78 | if (ret) 79 | return ret; 80 | 81 | test1 = gtp_plugin_var_add("test1", 10, NULL); 82 | if (IS_ERR(test1)) { 83 | ret = PTR_ERR(test1); 84 | test1 = NULL; 85 | goto out; 86 | } 87 | test2 = gtp_plugin_var_add("test2", test2_val, &test2_hooks); 88 | if (IS_ERR(test2)) { 89 | ret = PTR_ERR(test2); 90 | test2 = NULL; 91 | goto out; 92 | } 93 | /* Action example: 94 | teval $test3=(int64_t)$rip */ 95 | test3 = gtp_plugin_var_add("test3", 0, &test3_hooks); 96 | if (IS_ERR(test3)) { 97 | ret = PTR_ERR(test3); 98 | test3 = NULL; 99 | goto out; 100 | } 101 | test4 = gtp_plugin_var_add("test4", 0, &test4_hooks); 102 | if (IS_ERR(test4)) { 103 | ret = PTR_ERR(test4); 104 | test4 = NULL; 105 | goto out; 106 | } 107 | 108 | out: 109 | if (ret != 0) 110 | plugin_example_exit(); 111 | return ret; 112 | } 113 | 114 | static void 115 | plugin_example_exit(void) 116 | { 117 | if (test1) 118 | gtp_plugin_var_del(test1); 119 | if (test2) 120 | gtp_plugin_var_del(test2); 121 | if (test3) 122 | gtp_plugin_var_del(test3); 123 | if (test4) 124 | gtp_plugin_var_del(test4); 125 | 126 | gtp_plugin_mod_unregister(THIS_MODULE); 127 | } 128 | 129 | module_init(plugin_example_init) 130 | module_exit(plugin_example_exit) 131 | 132 | MODULE_LICENSE("GPL"); 133 | -------------------------------------------------------------------------------- /putgtprsp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Put gtprsp comand file to KGTP interface. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | * 18 | * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2012 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define GTP_RW_MAX 16384 30 | 31 | #define GTP_FILE "/sys/kernel/debug/gtp" 32 | 33 | int 34 | main(int argc, char *argv[], char *envp[]) 35 | { 36 | FILE *fd; 37 | char buf[GTP_RW_MAX]; 38 | int gtp; 39 | 40 | if (argc != 2 && argc != 3) { 41 | printf("Usage: %s gtprsp_file [gtp]\n", argv[0]); 42 | return -1; 43 | } 44 | 45 | fd = fopen(argv[1], "r"); 46 | if (fd == NULL) { 47 | perror(argv[1]); 48 | exit(-errno); 49 | } 50 | if (argc == 2) 51 | gtp = open(GTP_FILE, O_WRONLY); 52 | else 53 | gtp = open(argv[2], O_WRONLY); 54 | 55 | while (fgets(buf, GTP_RW_MAX, fd)) { 56 | int i; 57 | int buf_size; 58 | 59 | buf_size = strnlen(buf, GTP_RW_MAX); 60 | 61 | /* Try to find $ */ 62 | for (i = 0; i < buf_size; i++) { 63 | if (buf[i] == '$') 64 | break; 65 | } 66 | if (i >= buf_size) { 67 | fprintf(stderr, "Drop line \"%s\"\n", buf); 68 | continue; 69 | } 70 | 71 | /* Try to find # */ 72 | for (i = buf_size - 1; i >= 0; i--) { 73 | if (buf[i] == '#') 74 | break; 75 | } 76 | if (i < 0) { 77 | fprintf(stderr, "Drop line \"%s\"\n", buf); 78 | continue; 79 | } 80 | 81 | if (write(gtp, buf, strlen(buf)) <= 0) 82 | fprintf(stderr, "Write line \"%s\" fail\n", buf); 83 | } 84 | 85 | fclose(fd); 86 | close(gtp); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /ring_buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file base on include/linux/ring_buffer.h 3 | * commit 750912fa366312e9c5bc83eab352898a26750401 4 | */ 5 | 6 | #ifndef _LINUX_RING_BUFFER_H 7 | #define _LINUX_RING_BUFFER_H 8 | 9 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)) 10 | #include 11 | #endif 12 | #include 13 | #include 14 | 15 | struct ring_buffer; 16 | struct ring_buffer_iter; 17 | 18 | /* 19 | * Don't refer to this struct directly, use functions below. 20 | */ 21 | struct ring_buffer_event { 22 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)) 23 | kmemcheck_bitfield_begin(bitfield); 24 | #endif 25 | u32 type_len:5, time_delta:27; 26 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)) 27 | kmemcheck_bitfield_end(bitfield); 28 | #endif 29 | 30 | u32 array[]; 31 | }; 32 | 33 | /** 34 | * enum ring_buffer_type - internal ring buffer types 35 | * 36 | * @RINGBUF_TYPE_PADDING: Left over page padding or discarded event 37 | * If time_delta is 0: 38 | * array is ignored 39 | * size is variable depending on how much 40 | * padding is needed 41 | * If time_delta is non zero: 42 | * array[0] holds the actual length 43 | * size = 4 + length (bytes) 44 | * 45 | * @RINGBUF_TYPE_TIME_EXTEND: Extend the time delta 46 | * array[0] = time delta (28 .. 59) 47 | * size = 8 bytes 48 | * 49 | * @RINGBUF_TYPE_TIME_STAMP: Sync time stamp with external clock 50 | * array[0] = tv_nsec 51 | * array[1..2] = tv_sec 52 | * size = 16 bytes 53 | * 54 | * <= @RINGBUF_TYPE_DATA_TYPE_LEN_MAX: 55 | * Data record 56 | * If type_len is zero: 57 | * array[0] holds the actual length 58 | * array[1..(length+3)/4] holds data 59 | * size = 4 + length (bytes) 60 | * else 61 | * length = type_len << 2 62 | * array[0..(length+3)/4-1] holds data 63 | * size = 4 + length (bytes) 64 | */ 65 | enum ring_buffer_type { 66 | RINGBUF_TYPE_DATA_TYPE_LEN_MAX = 28, 67 | RINGBUF_TYPE_PADDING, 68 | RINGBUF_TYPE_TIME_EXTEND, 69 | /* FIXME: RINGBUF_TYPE_TIME_STAMP not implemented */ 70 | RINGBUF_TYPE_TIME_STAMP, 71 | }; 72 | 73 | unsigned ring_buffer_event_length(struct ring_buffer_event *event); 74 | void *ring_buffer_event_data(struct ring_buffer_event *event); 75 | 76 | /* 77 | * ring_buffer_discard_commit will remove an event that has not 78 | * ben committed yet. If this is used, then ring_buffer_unlock_commit 79 | * must not be called on the discarded event. This function 80 | * will try to remove the event from the ring buffer completely 81 | * if another event has not been written after it. 82 | * 83 | * Example use: 84 | * 85 | * if (some_condition) 86 | * ring_buffer_discard_commit(buffer, event); 87 | * else 88 | * ring_buffer_unlock_commit(buffer, event); 89 | */ 90 | void ring_buffer_discard_commit(struct ring_buffer *buffer, 91 | struct ring_buffer_event *event); 92 | 93 | /* 94 | * size is in bytes for each per CPU buffer. 95 | */ 96 | struct ring_buffer * 97 | __ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *key); 98 | 99 | /* 100 | * Because the ring buffer is generic, if other users of the ring buffer get 101 | * traced by ftrace, it can produce lockdep warnings. We need to keep each 102 | * ring buffer's lock class separate. 103 | */ 104 | #define ring_buffer_alloc(size, flags) \ 105 | ({ \ 106 | static struct lock_class_key __key; \ 107 | __ring_buffer_alloc((size), (flags), &__key); \ 108 | }) 109 | 110 | void ring_buffer_free(struct ring_buffer *buffer); 111 | 112 | int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size); 113 | 114 | void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val); 115 | 116 | struct ring_buffer_event *ring_buffer_lock_reserve(struct ring_buffer *buffer, 117 | unsigned long length); 118 | int ring_buffer_unlock_commit(struct ring_buffer *buffer, 119 | struct ring_buffer_event *event); 120 | int ring_buffer_write(struct ring_buffer *buffer, 121 | unsigned long length, void *data); 122 | 123 | struct ring_buffer_event * 124 | ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts, 125 | unsigned long *lost_events); 126 | struct ring_buffer_event * 127 | ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts, 128 | unsigned long *lost_events); 129 | 130 | struct ring_buffer_iter * 131 | ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu); 132 | void ring_buffer_read_prepare_sync(void); 133 | void ring_buffer_read_start(struct ring_buffer_iter *iter); 134 | void ring_buffer_read_finish(struct ring_buffer_iter *iter); 135 | 136 | struct ring_buffer_event * 137 | ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts); 138 | struct ring_buffer_event * 139 | ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts); 140 | void ring_buffer_iter_reset(struct ring_buffer_iter *iter); 141 | int ring_buffer_iter_empty(struct ring_buffer_iter *iter); 142 | 143 | unsigned long ring_buffer_size(struct ring_buffer *buffer); 144 | 145 | void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu); 146 | void ring_buffer_reset(struct ring_buffer *buffer); 147 | 148 | #ifdef CONFIG_RING_BUFFER_ALLOW_SWAP 149 | int ring_buffer_swap_cpu(struct ring_buffer *buffer_a, 150 | struct ring_buffer *buffer_b, int cpu); 151 | #else 152 | static inline int 153 | ring_buffer_swap_cpu(struct ring_buffer *buffer_a, 154 | struct ring_buffer *buffer_b, int cpu) 155 | { 156 | return -ENODEV; 157 | } 158 | #endif 159 | 160 | int ring_buffer_empty(struct ring_buffer *buffer); 161 | int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu); 162 | 163 | void ring_buffer_record_disable(struct ring_buffer *buffer); 164 | void ring_buffer_record_enable(struct ring_buffer *buffer); 165 | void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu); 166 | void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); 167 | 168 | unsigned long ring_buffer_entries(struct ring_buffer *buffer); 169 | unsigned long ring_buffer_overruns(struct ring_buffer *buffer); 170 | unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu); 171 | unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); 172 | unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu); 173 | 174 | u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu); 175 | void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer, 176 | int cpu, u64 *ts); 177 | void ring_buffer_set_clock(struct ring_buffer *buffer, 178 | u64 (*clock)(void)); 179 | 180 | size_t ring_buffer_page_len(void *page); 181 | 182 | 183 | void *ring_buffer_alloc_read_page(struct ring_buffer *buffer); 184 | void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data); 185 | int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, 186 | size_t len, int cpu, int full); 187 | 188 | struct trace_seq; 189 | 190 | int ring_buffer_print_entry_header(struct trace_seq *s); 191 | int ring_buffer_print_page_header(struct trace_seq *s); 192 | 193 | enum ring_buffer_flags { 194 | RB_FL_OVERWRITE = 1 << 0, 195 | }; 196 | 197 | #endif /* _LINUX_RING_BUFFER_H */ 198 | --------------------------------------------------------------------------------