├── .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("" + str(d[0]) + ''' | ''' + str(d[1]) + " | ")
89 | fd.write(' ')
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 |
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('''Kernel space hotcode list | '''+str(kernel_hotcode_list.num)+''' |
''')
136 | hotcode_list_to_output_html_fd(kernel_hotcode_list, fd)
137 | fd.write('
')
138 | else:
139 | for pid in task_list:
140 | fd.write('
')
141 | fd.write('''''')
142 | fd.write('''pid:''' + str(pid) + " " + task_list[pid].user_dir + " |
")
143 | if trace_user:
144 | fd.write('''User space hotcode list |
''')
145 | fd.write('''User space hotcode list | '''+str(task_list[pid].user.num)+''' |
''')
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('''Kernel space hotcode list | '''+str(task_list[pid].kernel.num)+''' |
''')
151 | hotcode_list_to_output_html_fd(task_list[pid].kernel, fd)
152 | fd.write('
')
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 |
--------------------------------------------------------------------------------