diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-07 14:27:30 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-07 14:27:30 -0500 |
commit | a3b072cd180c12e8fe0ece9487b9065808327640 (patch) | |
tree | 62b982041be84748852d77cdf6ca5639ef40858f /tools | |
parent | 75a1ba5b2c529db60ca49626bcaf0bddf4548438 (diff) | |
parent | 081cd62a010f97b5bc1d2b0cd123c5abc692b68a (diff) |
Merge tag 'efi-urgent' into x86/urgent
* Avoid WARN_ON() when mapping BGRT on Baytrail (EFI 32-bit).
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'tools')
30 files changed, 2843 insertions, 242 deletions
diff --git a/tools/Makefile b/tools/Makefile index 927cd46d36dc..feec3ad5fd09 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -3,6 +3,7 @@ include scripts/Makefile.include | |||
3 | help: | 3 | help: |
4 | @echo 'Possible targets:' | 4 | @echo 'Possible targets:' |
5 | @echo '' | 5 | @echo '' |
6 | @echo ' acpi - ACPI tools' | ||
6 | @echo ' cgroup - cgroup tools' | 7 | @echo ' cgroup - cgroup tools' |
7 | @echo ' cpupower - a tool for all things x86 CPU power' | 8 | @echo ' cpupower - a tool for all things x86 CPU power' |
8 | @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' | 9 | @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' |
@@ -33,6 +34,9 @@ help: | |||
33 | @echo ' the respective build directory.' | 34 | @echo ' the respective build directory.' |
34 | @echo ' clean: a summary clean target to clean _all_ folders' | 35 | @echo ' clean: a summary clean target to clean _all_ folders' |
35 | 36 | ||
37 | acpi: FORCE | ||
38 | $(call descend,power/$@) | ||
39 | |||
36 | cpupower: FORCE | 40 | cpupower: FORCE |
37 | $(call descend,power/$@) | 41 | $(call descend,power/$@) |
38 | 42 | ||
@@ -54,6 +58,9 @@ turbostat x86_energy_perf_policy: FORCE | |||
54 | tmon: FORCE | 58 | tmon: FORCE |
55 | $(call descend,thermal/$@) | 59 | $(call descend,thermal/$@) |
56 | 60 | ||
61 | acpi_install: | ||
62 | $(call descend,power/$(@:_install=),install) | ||
63 | |||
57 | cpupower_install: | 64 | cpupower_install: |
58 | $(call descend,power/$(@:_install=),install) | 65 | $(call descend,power/$(@:_install=),install) |
59 | 66 | ||
@@ -69,11 +76,14 @@ turbostat_install x86_energy_perf_policy_install: | |||
69 | tmon_install: | 76 | tmon_install: |
70 | $(call descend,thermal/$(@:_install=),install) | 77 | $(call descend,thermal/$(@:_install=),install) |
71 | 78 | ||
72 | install: cgroup_install cpupower_install firewire_install lguest_install \ | 79 | install: acpi_install cgroup_install cpupower_install firewire_install lguest_install \ |
73 | perf_install selftests_install turbostat_install usb_install \ | 80 | perf_install selftests_install turbostat_install usb_install \ |
74 | virtio_install vm_install net_install x86_energy_perf_policy_install \ | 81 | virtio_install vm_install net_install x86_energy_perf_policy_install \ |
75 | tmon | 82 | tmon |
76 | 83 | ||
84 | acpi_clean: | ||
85 | $(call descend,power/acpi,clean) | ||
86 | |||
77 | cpupower_clean: | 87 | cpupower_clean: |
78 | $(call descend,power/cpupower,clean) | 88 | $(call descend,power/cpupower,clean) |
79 | 89 | ||
@@ -95,8 +105,8 @@ turbostat_clean x86_energy_perf_policy_clean: | |||
95 | tmon_clean: | 105 | tmon_clean: |
96 | $(call descend,thermal/tmon,clean) | 106 | $(call descend,thermal/tmon,clean) |
97 | 107 | ||
98 | clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \ | 108 | clean: acpi_clean cgroup_clean cpupower_clean firewire_clean lguest_clean \ |
99 | selftests_clean turbostat_clean usb_clean virtio_clean \ | 109 | perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \ |
100 | vm_clean net_clean x86_energy_perf_policy_clean tmon_clean | 110 | vm_clean net_clean x86_energy_perf_policy_clean tmon_clean |
101 | 111 | ||
102 | .PHONY: FORCE | 112 | .PHONY: FORCE |
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index b8d6d541d854..4088b816a3ee 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <sys/socket.h> | 26 | #include <sys/socket.h> |
27 | #include <sys/poll.h> | 27 | #include <sys/poll.h> |
28 | #include <sys/utsname.h> | 28 | #include <sys/utsname.h> |
29 | #include <linux/types.h> | ||
30 | #include <stdio.h> | 29 | #include <stdio.h> |
31 | #include <stdlib.h> | 30 | #include <stdlib.h> |
32 | #include <unistd.h> | 31 | #include <unistd.h> |
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 8bcb04096eb2..520de3304571 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <sys/socket.h> | 22 | #include <sys/socket.h> |
23 | #include <sys/poll.h> | 23 | #include <sys/poll.h> |
24 | #include <sys/ioctl.h> | 24 | #include <sys/ioctl.h> |
25 | #include <linux/types.h> | ||
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
27 | #include <stdio.h> | 26 | #include <stdio.h> |
28 | #include <mntent.h> | 27 | #include <mntent.h> |
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 56d52a33a3df..005c9cc06935 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -63,7 +63,7 @@ endif | |||
63 | endif | 63 | endif |
64 | 64 | ||
65 | ifeq ($(set_plugin_dir),1) | 65 | ifeq ($(set_plugin_dir),1) |
66 | PLUGIN_DIR = -DPLUGIN_DIR="$(DESTDIR)/$(plugin_dir)" | 66 | PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)" |
67 | PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' | 67 | PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' |
68 | endif | 68 | endif |
69 | 69 | ||
diff --git a/tools/net/Makefile b/tools/net/Makefile index b4444d53b73f..004cd74734b6 100644 --- a/tools/net/Makefile +++ b/tools/net/Makefile | |||
@@ -1,15 +1,34 @@ | |||
1 | prefix = /usr | 1 | prefix = /usr |
2 | 2 | ||
3 | CC = gcc | 3 | CC = gcc |
4 | LEX = flex | ||
5 | YACC = bison | ||
4 | 6 | ||
5 | all : bpf_jit_disasm | 7 | %.yacc.c: %.y |
8 | $(YACC) -o $@ -d $< | ||
9 | |||
10 | %.lex.c: %.l | ||
11 | $(LEX) -o $@ $< | ||
12 | |||
13 | all : bpf_jit_disasm bpf_dbg bpf_asm | ||
6 | 14 | ||
7 | bpf_jit_disasm : CFLAGS = -Wall -O2 | 15 | bpf_jit_disasm : CFLAGS = -Wall -O2 |
8 | bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl | 16 | bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl |
9 | bpf_jit_disasm : bpf_jit_disasm.o | 17 | bpf_jit_disasm : bpf_jit_disasm.o |
10 | 18 | ||
19 | bpf_dbg : CFLAGS = -Wall -O2 | ||
20 | bpf_dbg : LDLIBS = -lreadline | ||
21 | bpf_dbg : bpf_dbg.o | ||
22 | |||
23 | bpf_asm : CFLAGS = -Wall -O2 -I. | ||
24 | bpf_asm : LDLIBS = | ||
25 | bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o | ||
26 | bpf_exp.lex.o : bpf_exp.yacc.c | ||
27 | |||
11 | clean : | 28 | clean : |
12 | rm -rf *.o bpf_jit_disasm | 29 | rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.* |
13 | 30 | ||
14 | install : | 31 | install : |
15 | install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm | 32 | install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm |
33 | install bpf_dbg $(prefix)/bin/bpf_dbg | ||
34 | install bpf_asm $(prefix)/bin/bpf_asm | ||
diff --git a/tools/net/bpf_asm.c b/tools/net/bpf_asm.c new file mode 100644 index 000000000000..c15aef097b04 --- /dev/null +++ b/tools/net/bpf_asm.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Minimal BPF assembler | ||
3 | * | ||
4 | * Instead of libpcap high-level filter expressions, it can be quite | ||
5 | * useful to define filters in low-level BPF assembler (that is kept | ||
6 | * close to Steven McCanne and Van Jacobson's original BPF paper). | ||
7 | * In particular for BPF JIT implementors, JIT security auditors, or | ||
8 | * just for defining BPF expressions that contain extensions which are | ||
9 | * not supported by compilers. | ||
10 | * | ||
11 | * How to get into it: | ||
12 | * | ||
13 | * 1) read Documentation/networking/filter.txt | ||
14 | * 2) Run `bpf_asm [-c] <filter-prog file>` to translate into binary | ||
15 | * blob that is loadable with xt_bpf, cls_bpf et al. Note: -c will | ||
16 | * pretty print a C-like construct. | ||
17 | * | ||
18 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
19 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
20 | */ | ||
21 | |||
22 | #include <stdbool.h> | ||
23 | #include <stdio.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | extern void bpf_asm_compile(FILE *fp, bool cstyle); | ||
27 | |||
28 | int main(int argc, char **argv) | ||
29 | { | ||
30 | FILE *fp = stdin; | ||
31 | bool cstyle = false; | ||
32 | int i; | ||
33 | |||
34 | for (i = 1; i < argc; i++) { | ||
35 | if (!strncmp("-c", argv[i], 2)) { | ||
36 | cstyle = true; | ||
37 | continue; | ||
38 | } | ||
39 | |||
40 | fp = fopen(argv[i], "r"); | ||
41 | if (!fp) { | ||
42 | fp = stdin; | ||
43 | continue; | ||
44 | } | ||
45 | |||
46 | break; | ||
47 | } | ||
48 | |||
49 | bpf_asm_compile(fp, cstyle); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
diff --git a/tools/net/bpf_dbg.c b/tools/net/bpf_dbg.c new file mode 100644 index 000000000000..65dc757f7f7b --- /dev/null +++ b/tools/net/bpf_dbg.c | |||
@@ -0,0 +1,1404 @@ | |||
1 | /* | ||
2 | * Minimal BPF debugger | ||
3 | * | ||
4 | * Minimal BPF debugger that mimics the kernel's engine (w/o extensions) | ||
5 | * and allows for single stepping through selected packets from a pcap | ||
6 | * with a provided user filter in order to facilitate verification of a | ||
7 | * BPF program. Besides others, this is useful to verify BPF programs | ||
8 | * before attaching to a live system, and can be used in socket filters, | ||
9 | * cls_bpf, xt_bpf, team driver and e.g. PTP code; in particular when a | ||
10 | * single more complex BPF program is being used. Reasons for a more | ||
11 | * complex BPF program are likely primarily to optimize execution time | ||
12 | * for making a verdict when multiple simple BPF programs are combined | ||
13 | * into one in order to prevent parsing same headers multiple times. | ||
14 | * | ||
15 | * More on how to debug BPF opcodes see Documentation/networking/filter.txt | ||
16 | * which is the main document on BPF. Mini howto for getting started: | ||
17 | * | ||
18 | * 1) `./bpf_dbg` to enter the shell (shell cmds denoted with '>'): | ||
19 | * 2) > load bpf 6,40 0 0 12,21 0 3 20... (output from `bpf_asm` or | ||
20 | * `tcpdump -iem1 -ddd port 22 | tr '\n' ','` to load as filter) | ||
21 | * 3) > load pcap foo.pcap | ||
22 | * 4) > run <n>/disassemble/dump/quit (self-explanatory) | ||
23 | * 5) > breakpoint 2 (sets bp at loaded BPF insns 2, do `run` then; | ||
24 | * multiple bps can be set, of course, a call to `breakpoint` | ||
25 | * w/o args shows currently loaded bps, `breakpoint reset` for | ||
26 | * resetting all breakpoints) | ||
27 | * 6) > select 3 (`run` etc will start from the 3rd packet in the pcap) | ||
28 | * 7) > step [-<n>, +<n>] (performs single stepping through the BPF) | ||
29 | * | ||
30 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
31 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
32 | */ | ||
33 | |||
34 | #include <stdio.h> | ||
35 | #include <unistd.h> | ||
36 | #include <stdlib.h> | ||
37 | #include <ctype.h> | ||
38 | #include <stdbool.h> | ||
39 | #include <stdarg.h> | ||
40 | #include <setjmp.h> | ||
41 | #include <linux/filter.h> | ||
42 | #include <linux/if_packet.h> | ||
43 | #include <readline/readline.h> | ||
44 | #include <readline/history.h> | ||
45 | #include <sys/types.h> | ||
46 | #include <sys/socket.h> | ||
47 | #include <sys/stat.h> | ||
48 | #include <sys/mman.h> | ||
49 | #include <fcntl.h> | ||
50 | #include <errno.h> | ||
51 | #include <signal.h> | ||
52 | #include <arpa/inet.h> | ||
53 | #include <net/ethernet.h> | ||
54 | |||
55 | #define TCPDUMP_MAGIC 0xa1b2c3d4 | ||
56 | |||
57 | #define BPF_LDX_B (BPF_LDX | BPF_B) | ||
58 | #define BPF_LDX_W (BPF_LDX | BPF_W) | ||
59 | #define BPF_JMP_JA (BPF_JMP | BPF_JA) | ||
60 | #define BPF_JMP_JEQ (BPF_JMP | BPF_JEQ) | ||
61 | #define BPF_JMP_JGT (BPF_JMP | BPF_JGT) | ||
62 | #define BPF_JMP_JGE (BPF_JMP | BPF_JGE) | ||
63 | #define BPF_JMP_JSET (BPF_JMP | BPF_JSET) | ||
64 | #define BPF_ALU_ADD (BPF_ALU | BPF_ADD) | ||
65 | #define BPF_ALU_SUB (BPF_ALU | BPF_SUB) | ||
66 | #define BPF_ALU_MUL (BPF_ALU | BPF_MUL) | ||
67 | #define BPF_ALU_DIV (BPF_ALU | BPF_DIV) | ||
68 | #define BPF_ALU_MOD (BPF_ALU | BPF_MOD) | ||
69 | #define BPF_ALU_NEG (BPF_ALU | BPF_NEG) | ||
70 | #define BPF_ALU_AND (BPF_ALU | BPF_AND) | ||
71 | #define BPF_ALU_OR (BPF_ALU | BPF_OR) | ||
72 | #define BPF_ALU_XOR (BPF_ALU | BPF_XOR) | ||
73 | #define BPF_ALU_LSH (BPF_ALU | BPF_LSH) | ||
74 | #define BPF_ALU_RSH (BPF_ALU | BPF_RSH) | ||
75 | #define BPF_MISC_TAX (BPF_MISC | BPF_TAX) | ||
76 | #define BPF_MISC_TXA (BPF_MISC | BPF_TXA) | ||
77 | #define BPF_LD_B (BPF_LD | BPF_B) | ||
78 | #define BPF_LD_H (BPF_LD | BPF_H) | ||
79 | #define BPF_LD_W (BPF_LD | BPF_W) | ||
80 | |||
81 | #ifndef array_size | ||
82 | # define array_size(x) (sizeof(x) / sizeof((x)[0])) | ||
83 | #endif | ||
84 | |||
85 | #ifndef __check_format_printf | ||
86 | # define __check_format_printf(pos_fmtstr, pos_fmtargs) \ | ||
87 | __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs)))) | ||
88 | #endif | ||
89 | |||
90 | #define CMD(_name, _func) { .name = _name, .func = _func, } | ||
91 | #define OP(_op, _name) [_op] = _name | ||
92 | |||
93 | enum { | ||
94 | CMD_OK, | ||
95 | CMD_ERR, | ||
96 | CMD_EX, | ||
97 | }; | ||
98 | |||
99 | struct shell_cmd { | ||
100 | const char *name; | ||
101 | int (*func)(char *args); | ||
102 | }; | ||
103 | |||
104 | struct pcap_filehdr { | ||
105 | uint32_t magic; | ||
106 | uint16_t version_major; | ||
107 | uint16_t version_minor; | ||
108 | int32_t thiszone; | ||
109 | uint32_t sigfigs; | ||
110 | uint32_t snaplen; | ||
111 | uint32_t linktype; | ||
112 | }; | ||
113 | |||
114 | struct pcap_timeval { | ||
115 | int32_t tv_sec; | ||
116 | int32_t tv_usec; | ||
117 | }; | ||
118 | |||
119 | struct pcap_pkthdr { | ||
120 | struct pcap_timeval ts; | ||
121 | uint32_t caplen; | ||
122 | uint32_t len; | ||
123 | }; | ||
124 | |||
125 | struct bpf_regs { | ||
126 | uint32_t A; | ||
127 | uint32_t X; | ||
128 | uint32_t M[BPF_MEMWORDS]; | ||
129 | uint32_t R; | ||
130 | bool Rs; | ||
131 | uint16_t Pc; | ||
132 | }; | ||
133 | |||
134 | static struct sock_filter bpf_image[BPF_MAXINSNS + 1]; | ||
135 | static unsigned int bpf_prog_len = 0; | ||
136 | |||
137 | static int bpf_breakpoints[64]; | ||
138 | static struct bpf_regs bpf_regs[BPF_MAXINSNS + 1]; | ||
139 | static struct bpf_regs bpf_curr; | ||
140 | static unsigned int bpf_regs_len = 0; | ||
141 | |||
142 | static int pcap_fd = -1; | ||
143 | static unsigned int pcap_packet = 0; | ||
144 | static size_t pcap_map_size = 0; | ||
145 | static char *pcap_ptr_va_start, *pcap_ptr_va_curr; | ||
146 | |||
147 | static const char * const op_table[] = { | ||
148 | OP(BPF_ST, "st"), | ||
149 | OP(BPF_STX, "stx"), | ||
150 | OP(BPF_LD_B, "ldb"), | ||
151 | OP(BPF_LD_H, "ldh"), | ||
152 | OP(BPF_LD_W, "ld"), | ||
153 | OP(BPF_LDX, "ldx"), | ||
154 | OP(BPF_LDX_B, "ldxb"), | ||
155 | OP(BPF_JMP_JA, "ja"), | ||
156 | OP(BPF_JMP_JEQ, "jeq"), | ||
157 | OP(BPF_JMP_JGT, "jgt"), | ||
158 | OP(BPF_JMP_JGE, "jge"), | ||
159 | OP(BPF_JMP_JSET, "jset"), | ||
160 | OP(BPF_ALU_ADD, "add"), | ||
161 | OP(BPF_ALU_SUB, "sub"), | ||
162 | OP(BPF_ALU_MUL, "mul"), | ||
163 | OP(BPF_ALU_DIV, "div"), | ||
164 | OP(BPF_ALU_MOD, "mod"), | ||
165 | OP(BPF_ALU_NEG, "neg"), | ||
166 | OP(BPF_ALU_AND, "and"), | ||
167 | OP(BPF_ALU_OR, "or"), | ||
168 | OP(BPF_ALU_XOR, "xor"), | ||
169 | OP(BPF_ALU_LSH, "lsh"), | ||
170 | OP(BPF_ALU_RSH, "rsh"), | ||
171 | OP(BPF_MISC_TAX, "tax"), | ||
172 | OP(BPF_MISC_TXA, "txa"), | ||
173 | OP(BPF_RET, "ret"), | ||
174 | }; | ||
175 | |||
176 | static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...) | ||
177 | { | ||
178 | int ret; | ||
179 | va_list vl; | ||
180 | |||
181 | va_start(vl, fmt); | ||
182 | ret = vfprintf(rl_outstream, fmt, vl); | ||
183 | va_end(vl); | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static int matches(const char *cmd, const char *pattern) | ||
189 | { | ||
190 | int len = strlen(cmd); | ||
191 | |||
192 | if (len > strlen(pattern)) | ||
193 | return -1; | ||
194 | |||
195 | return memcmp(pattern, cmd, len); | ||
196 | } | ||
197 | |||
198 | static void hex_dump(const uint8_t *buf, size_t len) | ||
199 | { | ||
200 | int i; | ||
201 | |||
202 | rl_printf("%3u: ", 0); | ||
203 | for (i = 0; i < len; i++) { | ||
204 | if (i && !(i % 16)) | ||
205 | rl_printf("\n%3u: ", i); | ||
206 | rl_printf("%02x ", buf[i]); | ||
207 | } | ||
208 | rl_printf("\n"); | ||
209 | } | ||
210 | |||
211 | static bool bpf_prog_loaded(void) | ||
212 | { | ||
213 | if (bpf_prog_len == 0) | ||
214 | rl_printf("no bpf program loaded!\n"); | ||
215 | |||
216 | return bpf_prog_len > 0; | ||
217 | } | ||
218 | |||
219 | static void bpf_disasm(const struct sock_filter f, unsigned int i) | ||
220 | { | ||
221 | const char *op, *fmt; | ||
222 | int val = f.k; | ||
223 | char buf[256]; | ||
224 | |||
225 | switch (f.code) { | ||
226 | case BPF_RET | BPF_K: | ||
227 | op = op_table[BPF_RET]; | ||
228 | fmt = "#%#x"; | ||
229 | break; | ||
230 | case BPF_RET | BPF_A: | ||
231 | op = op_table[BPF_RET]; | ||
232 | fmt = "a"; | ||
233 | break; | ||
234 | case BPF_RET | BPF_X: | ||
235 | op = op_table[BPF_RET]; | ||
236 | fmt = "x"; | ||
237 | break; | ||
238 | case BPF_MISC_TAX: | ||
239 | op = op_table[BPF_MISC_TAX]; | ||
240 | fmt = ""; | ||
241 | break; | ||
242 | case BPF_MISC_TXA: | ||
243 | op = op_table[BPF_MISC_TXA]; | ||
244 | fmt = ""; | ||
245 | break; | ||
246 | case BPF_ST: | ||
247 | op = op_table[BPF_ST]; | ||
248 | fmt = "M[%d]"; | ||
249 | break; | ||
250 | case BPF_STX: | ||
251 | op = op_table[BPF_STX]; | ||
252 | fmt = "M[%d]"; | ||
253 | break; | ||
254 | case BPF_LD_W | BPF_ABS: | ||
255 | op = op_table[BPF_LD_W]; | ||
256 | fmt = "[%d]"; | ||
257 | break; | ||
258 | case BPF_LD_H | BPF_ABS: | ||
259 | op = op_table[BPF_LD_H]; | ||
260 | fmt = "[%d]"; | ||
261 | break; | ||
262 | case BPF_LD_B | BPF_ABS: | ||
263 | op = op_table[BPF_LD_B]; | ||
264 | fmt = "[%d]"; | ||
265 | break; | ||
266 | case BPF_LD_W | BPF_LEN: | ||
267 | op = op_table[BPF_LD_W]; | ||
268 | fmt = "#len"; | ||
269 | break; | ||
270 | case BPF_LD_W | BPF_IND: | ||
271 | op = op_table[BPF_LD_W]; | ||
272 | fmt = "[x+%d]"; | ||
273 | break; | ||
274 | case BPF_LD_H | BPF_IND: | ||
275 | op = op_table[BPF_LD_H]; | ||
276 | fmt = "[x+%d]"; | ||
277 | break; | ||
278 | case BPF_LD_B | BPF_IND: | ||
279 | op = op_table[BPF_LD_B]; | ||
280 | fmt = "[x+%d]"; | ||
281 | break; | ||
282 | case BPF_LD | BPF_IMM: | ||
283 | op = op_table[BPF_LD_W]; | ||
284 | fmt = "#%#x"; | ||
285 | break; | ||
286 | case BPF_LDX | BPF_IMM: | ||
287 | op = op_table[BPF_LDX]; | ||
288 | fmt = "#%#x"; | ||
289 | break; | ||
290 | case BPF_LDX_B | BPF_MSH: | ||
291 | op = op_table[BPF_LDX_B]; | ||
292 | fmt = "4*([%d]&0xf)"; | ||
293 | break; | ||
294 | case BPF_LD | BPF_MEM: | ||
295 | op = op_table[BPF_LD_W]; | ||
296 | fmt = "M[%d]"; | ||
297 | break; | ||
298 | case BPF_LDX | BPF_MEM: | ||
299 | op = op_table[BPF_LDX]; | ||
300 | fmt = "M[%d]"; | ||
301 | break; | ||
302 | case BPF_JMP_JA: | ||
303 | op = op_table[BPF_JMP_JA]; | ||
304 | fmt = "%d"; | ||
305 | val = i + 1 + f.k; | ||
306 | break; | ||
307 | case BPF_JMP_JGT | BPF_X: | ||
308 | op = op_table[BPF_JMP_JGT]; | ||
309 | fmt = "x"; | ||
310 | break; | ||
311 | case BPF_JMP_JGT | BPF_K: | ||
312 | op = op_table[BPF_JMP_JGT]; | ||
313 | fmt = "#%#x"; | ||
314 | break; | ||
315 | case BPF_JMP_JGE | BPF_X: | ||
316 | op = op_table[BPF_JMP_JGE]; | ||
317 | fmt = "x"; | ||
318 | break; | ||
319 | case BPF_JMP_JGE | BPF_K: | ||
320 | op = op_table[BPF_JMP_JGE]; | ||
321 | fmt = "#%#x"; | ||
322 | break; | ||
323 | case BPF_JMP_JEQ | BPF_X: | ||
324 | op = op_table[BPF_JMP_JEQ]; | ||
325 | fmt = "x"; | ||
326 | break; | ||
327 | case BPF_JMP_JEQ | BPF_K: | ||
328 | op = op_table[BPF_JMP_JEQ]; | ||
329 | fmt = "#%#x"; | ||
330 | break; | ||
331 | case BPF_JMP_JSET | BPF_X: | ||
332 | op = op_table[BPF_JMP_JSET]; | ||
333 | fmt = "x"; | ||
334 | break; | ||
335 | case BPF_JMP_JSET | BPF_K: | ||
336 | op = op_table[BPF_JMP_JSET]; | ||
337 | fmt = "#%#x"; | ||
338 | break; | ||
339 | case BPF_ALU_NEG: | ||
340 | op = op_table[BPF_ALU_NEG]; | ||
341 | fmt = ""; | ||
342 | break; | ||
343 | case BPF_ALU_LSH | BPF_X: | ||
344 | op = op_table[BPF_ALU_LSH]; | ||
345 | fmt = "x"; | ||
346 | break; | ||
347 | case BPF_ALU_LSH | BPF_K: | ||
348 | op = op_table[BPF_ALU_LSH]; | ||
349 | fmt = "#%d"; | ||
350 | break; | ||
351 | case BPF_ALU_RSH | BPF_X: | ||
352 | op = op_table[BPF_ALU_RSH]; | ||
353 | fmt = "x"; | ||
354 | break; | ||
355 | case BPF_ALU_RSH | BPF_K: | ||
356 | op = op_table[BPF_ALU_RSH]; | ||
357 | fmt = "#%d"; | ||
358 | break; | ||
359 | case BPF_ALU_ADD | BPF_X: | ||
360 | op = op_table[BPF_ALU_ADD]; | ||
361 | fmt = "x"; | ||
362 | break; | ||
363 | case BPF_ALU_ADD | BPF_K: | ||
364 | op = op_table[BPF_ALU_ADD]; | ||
365 | fmt = "#%d"; | ||
366 | break; | ||
367 | case BPF_ALU_SUB | BPF_X: | ||
368 | op = op_table[BPF_ALU_SUB]; | ||
369 | fmt = "x"; | ||
370 | break; | ||
371 | case BPF_ALU_SUB | BPF_K: | ||
372 | op = op_table[BPF_ALU_SUB]; | ||
373 | fmt = "#%d"; | ||
374 | break; | ||
375 | case BPF_ALU_MUL | BPF_X: | ||
376 | op = op_table[BPF_ALU_MUL]; | ||
377 | fmt = "x"; | ||
378 | break; | ||
379 | case BPF_ALU_MUL | BPF_K: | ||
380 | op = op_table[BPF_ALU_MUL]; | ||
381 | fmt = "#%d"; | ||
382 | break; | ||
383 | case BPF_ALU_DIV | BPF_X: | ||
384 | op = op_table[BPF_ALU_DIV]; | ||
385 | fmt = "x"; | ||
386 | break; | ||
387 | case BPF_ALU_DIV | BPF_K: | ||
388 | op = op_table[BPF_ALU_DIV]; | ||
389 | fmt = "#%d"; | ||
390 | break; | ||
391 | case BPF_ALU_MOD | BPF_X: | ||
392 | op = op_table[BPF_ALU_MOD]; | ||
393 | fmt = "x"; | ||
394 | break; | ||
395 | case BPF_ALU_MOD | BPF_K: | ||
396 | op = op_table[BPF_ALU_MOD]; | ||
397 | fmt = "#%d"; | ||
398 | break; | ||
399 | case BPF_ALU_AND | BPF_X: | ||
400 | op = op_table[BPF_ALU_AND]; | ||
401 | fmt = "x"; | ||
402 | break; | ||
403 | case BPF_ALU_AND | BPF_K: | ||
404 | op = op_table[BPF_ALU_AND]; | ||
405 | fmt = "#%#x"; | ||
406 | break; | ||
407 | case BPF_ALU_OR | BPF_X: | ||
408 | op = op_table[BPF_ALU_OR]; | ||
409 | fmt = "x"; | ||
410 | break; | ||
411 | case BPF_ALU_OR | BPF_K: | ||
412 | op = op_table[BPF_ALU_OR]; | ||
413 | fmt = "#%#x"; | ||
414 | break; | ||
415 | case BPF_ALU_XOR | BPF_X: | ||
416 | op = op_table[BPF_ALU_XOR]; | ||
417 | fmt = "x"; | ||
418 | break; | ||
419 | case BPF_ALU_XOR | BPF_K: | ||
420 | op = op_table[BPF_ALU_XOR]; | ||
421 | fmt = "#%#x"; | ||
422 | break; | ||
423 | default: | ||
424 | op = "nosup"; | ||
425 | fmt = "%#x"; | ||
426 | val = f.code; | ||
427 | break; | ||
428 | } | ||
429 | |||
430 | memset(buf, 0, sizeof(buf)); | ||
431 | snprintf(buf, sizeof(buf), fmt, val); | ||
432 | buf[sizeof(buf) - 1] = 0; | ||
433 | |||
434 | if ((BPF_CLASS(f.code) == BPF_JMP && BPF_OP(f.code) != BPF_JA)) | ||
435 | rl_printf("l%d:\t%s %s, l%d, l%d\n", i, op, buf, | ||
436 | i + 1 + f.jt, i + 1 + f.jf); | ||
437 | else | ||
438 | rl_printf("l%d:\t%s %s\n", i, op, buf); | ||
439 | } | ||
440 | |||
441 | static void bpf_dump_curr(struct bpf_regs *r, struct sock_filter *f) | ||
442 | { | ||
443 | int i, m = 0; | ||
444 | |||
445 | rl_printf("pc: [%u]\n", r->Pc); | ||
446 | rl_printf("code: [%u] jt[%u] jf[%u] k[%u]\n", | ||
447 | f->code, f->jt, f->jf, f->k); | ||
448 | rl_printf("curr: "); | ||
449 | bpf_disasm(*f, r->Pc); | ||
450 | |||
451 | if (f->jt || f->jf) { | ||
452 | rl_printf("jt: "); | ||
453 | bpf_disasm(*(f + f->jt + 1), r->Pc + f->jt + 1); | ||
454 | rl_printf("jf: "); | ||
455 | bpf_disasm(*(f + f->jf + 1), r->Pc + f->jf + 1); | ||
456 | } | ||
457 | |||
458 | rl_printf("A: [%#08x][%u]\n", r->A, r->A); | ||
459 | rl_printf("X: [%#08x][%u]\n", r->X, r->X); | ||
460 | if (r->Rs) | ||
461 | rl_printf("ret: [%#08x][%u]!\n", r->R, r->R); | ||
462 | |||
463 | for (i = 0; i < BPF_MEMWORDS; i++) { | ||
464 | if (r->M[i]) { | ||
465 | m++; | ||
466 | rl_printf("M[%d]: [%#08x][%u]\n", i, r->M[i], r->M[i]); | ||
467 | } | ||
468 | } | ||
469 | if (m == 0) | ||
470 | rl_printf("M[0,%d]: [%#08x][%u]\n", BPF_MEMWORDS - 1, 0, 0); | ||
471 | } | ||
472 | |||
473 | static void bpf_dump_pkt(uint8_t *pkt, uint32_t pkt_caplen, uint32_t pkt_len) | ||
474 | { | ||
475 | if (pkt_caplen != pkt_len) | ||
476 | rl_printf("cap: %u, len: %u\n", pkt_caplen, pkt_len); | ||
477 | else | ||
478 | rl_printf("len: %u\n", pkt_len); | ||
479 | |||
480 | hex_dump(pkt, pkt_caplen); | ||
481 | } | ||
482 | |||
483 | static void bpf_disasm_all(const struct sock_filter *f, unsigned int len) | ||
484 | { | ||
485 | unsigned int i; | ||
486 | |||
487 | for (i = 0; i < len; i++) | ||
488 | bpf_disasm(f[i], i); | ||
489 | } | ||
490 | |||
491 | static void bpf_dump_all(const struct sock_filter *f, unsigned int len) | ||
492 | { | ||
493 | unsigned int i; | ||
494 | |||
495 | rl_printf("/* { op, jt, jf, k }, */\n"); | ||
496 | for (i = 0; i < len; i++) | ||
497 | rl_printf("{ %#04x, %2u, %2u, %#010x },\n", | ||
498 | f[i].code, f[i].jt, f[i].jf, f[i].k); | ||
499 | } | ||
500 | |||
501 | static bool bpf_runnable(struct sock_filter *f, unsigned int len) | ||
502 | { | ||
503 | int sock, ret, i; | ||
504 | struct sock_fprog bpf = { | ||
505 | .filter = f, | ||
506 | .len = len, | ||
507 | }; | ||
508 | |||
509 | sock = socket(AF_INET, SOCK_DGRAM, 0); | ||
510 | if (sock < 0) { | ||
511 | rl_printf("cannot open socket!\n"); | ||
512 | return false; | ||
513 | } | ||
514 | ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); | ||
515 | close(sock); | ||
516 | if (ret < 0) { | ||
517 | rl_printf("program not allowed to run by kernel!\n"); | ||
518 | return false; | ||
519 | } | ||
520 | for (i = 0; i < len; i++) { | ||
521 | if (BPF_CLASS(f[i].code) == BPF_LD && | ||
522 | f[i].k > SKF_AD_OFF) { | ||
523 | rl_printf("extensions currently not supported!\n"); | ||
524 | return false; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | return true; | ||
529 | } | ||
530 | |||
531 | static void bpf_reset_breakpoints(void) | ||
532 | { | ||
533 | int i; | ||
534 | |||
535 | for (i = 0; i < array_size(bpf_breakpoints); i++) | ||
536 | bpf_breakpoints[i] = -1; | ||
537 | } | ||
538 | |||
539 | static void bpf_set_breakpoints(unsigned int where) | ||
540 | { | ||
541 | int i; | ||
542 | bool set = false; | ||
543 | |||
544 | for (i = 0; i < array_size(bpf_breakpoints); i++) { | ||
545 | if (bpf_breakpoints[i] == (int) where) { | ||
546 | rl_printf("breakpoint already set!\n"); | ||
547 | set = true; | ||
548 | break; | ||
549 | } | ||
550 | |||
551 | if (bpf_breakpoints[i] == -1 && set == false) { | ||
552 | bpf_breakpoints[i] = where; | ||
553 | set = true; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | if (!set) | ||
558 | rl_printf("too many breakpoints set, reset first!\n"); | ||
559 | } | ||
560 | |||
561 | static void bpf_dump_breakpoints(void) | ||
562 | { | ||
563 | int i; | ||
564 | |||
565 | rl_printf("breakpoints: "); | ||
566 | |||
567 | for (i = 0; i < array_size(bpf_breakpoints); i++) { | ||
568 | if (bpf_breakpoints[i] < 0) | ||
569 | continue; | ||
570 | rl_printf("%d ", bpf_breakpoints[i]); | ||
571 | } | ||
572 | |||
573 | rl_printf("\n"); | ||
574 | } | ||
575 | |||
576 | static void bpf_reset(void) | ||
577 | { | ||
578 | bpf_regs_len = 0; | ||
579 | |||
580 | memset(bpf_regs, 0, sizeof(bpf_regs)); | ||
581 | memset(&bpf_curr, 0, sizeof(bpf_curr)); | ||
582 | } | ||
583 | |||
584 | static void bpf_safe_regs(void) | ||
585 | { | ||
586 | memcpy(&bpf_regs[bpf_regs_len++], &bpf_curr, sizeof(bpf_curr)); | ||
587 | } | ||
588 | |||
589 | static bool bpf_restore_regs(int off) | ||
590 | { | ||
591 | unsigned int index = bpf_regs_len - 1 + off; | ||
592 | |||
593 | if (index == 0) { | ||
594 | bpf_reset(); | ||
595 | return true; | ||
596 | } else if (index < bpf_regs_len) { | ||
597 | memcpy(&bpf_curr, &bpf_regs[index], sizeof(bpf_curr)); | ||
598 | bpf_regs_len = index; | ||
599 | return true; | ||
600 | } else { | ||
601 | rl_printf("reached bottom of register history stack!\n"); | ||
602 | return false; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | static uint32_t extract_u32(uint8_t *pkt, uint32_t off) | ||
607 | { | ||
608 | uint32_t r; | ||
609 | |||
610 | memcpy(&r, &pkt[off], sizeof(r)); | ||
611 | |||
612 | return ntohl(r); | ||
613 | } | ||
614 | |||
615 | static uint16_t extract_u16(uint8_t *pkt, uint32_t off) | ||
616 | { | ||
617 | uint16_t r; | ||
618 | |||
619 | memcpy(&r, &pkt[off], sizeof(r)); | ||
620 | |||
621 | return ntohs(r); | ||
622 | } | ||
623 | |||
624 | static uint8_t extract_u8(uint8_t *pkt, uint32_t off) | ||
625 | { | ||
626 | return pkt[off]; | ||
627 | } | ||
628 | |||
629 | static void set_return(struct bpf_regs *r) | ||
630 | { | ||
631 | r->R = 0; | ||
632 | r->Rs = true; | ||
633 | } | ||
634 | |||
635 | static void bpf_single_step(struct bpf_regs *r, struct sock_filter *f, | ||
636 | uint8_t *pkt, uint32_t pkt_caplen, | ||
637 | uint32_t pkt_len) | ||
638 | { | ||
639 | uint32_t K = f->k; | ||
640 | int d; | ||
641 | |||
642 | switch (f->code) { | ||
643 | case BPF_RET | BPF_K: | ||
644 | r->R = K; | ||
645 | r->Rs = true; | ||
646 | break; | ||
647 | case BPF_RET | BPF_A: | ||
648 | r->R = r->A; | ||
649 | r->Rs = true; | ||
650 | break; | ||
651 | case BPF_RET | BPF_X: | ||
652 | r->R = r->X; | ||
653 | r->Rs = true; | ||
654 | break; | ||
655 | case BPF_MISC_TAX: | ||
656 | r->X = r->A; | ||
657 | break; | ||
658 | case BPF_MISC_TXA: | ||
659 | r->A = r->X; | ||
660 | break; | ||
661 | case BPF_ST: | ||
662 | r->M[K] = r->A; | ||
663 | break; | ||
664 | case BPF_STX: | ||
665 | r->M[K] = r->X; | ||
666 | break; | ||
667 | case BPF_LD_W | BPF_ABS: | ||
668 | d = pkt_caplen - K; | ||
669 | if (d >= sizeof(uint32_t)) | ||
670 | r->A = extract_u32(pkt, K); | ||
671 | else | ||
672 | set_return(r); | ||
673 | break; | ||
674 | case BPF_LD_H | BPF_ABS: | ||
675 | d = pkt_caplen - K; | ||
676 | if (d >= sizeof(uint16_t)) | ||
677 | r->A = extract_u16(pkt, K); | ||
678 | else | ||
679 | set_return(r); | ||
680 | break; | ||
681 | case BPF_LD_B | BPF_ABS: | ||
682 | d = pkt_caplen - K; | ||
683 | if (d >= sizeof(uint8_t)) | ||
684 | r->A = extract_u8(pkt, K); | ||
685 | else | ||
686 | set_return(r); | ||
687 | break; | ||
688 | case BPF_LD_W | BPF_IND: | ||
689 | d = pkt_caplen - (r->X + K); | ||
690 | if (d >= sizeof(uint32_t)) | ||
691 | r->A = extract_u32(pkt, r->X + K); | ||
692 | break; | ||
693 | case BPF_LD_H | BPF_IND: | ||
694 | d = pkt_caplen - (r->X + K); | ||
695 | if (d >= sizeof(uint16_t)) | ||
696 | r->A = extract_u16(pkt, r->X + K); | ||
697 | else | ||
698 | set_return(r); | ||
699 | break; | ||
700 | case BPF_LD_B | BPF_IND: | ||
701 | d = pkt_caplen - (r->X + K); | ||
702 | if (d >= sizeof(uint8_t)) | ||
703 | r->A = extract_u8(pkt, r->X + K); | ||
704 | else | ||
705 | set_return(r); | ||
706 | break; | ||
707 | case BPF_LDX_B | BPF_MSH: | ||
708 | d = pkt_caplen - K; | ||
709 | if (d >= sizeof(uint8_t)) { | ||
710 | r->X = extract_u8(pkt, K); | ||
711 | r->X = (r->X & 0xf) << 2; | ||
712 | } else | ||
713 | set_return(r); | ||
714 | break; | ||
715 | case BPF_LD_W | BPF_LEN: | ||
716 | r->A = pkt_len; | ||
717 | break; | ||
718 | case BPF_LDX_W | BPF_LEN: | ||
719 | r->A = pkt_len; | ||
720 | break; | ||
721 | case BPF_LD | BPF_IMM: | ||
722 | r->A = K; | ||
723 | break; | ||
724 | case BPF_LDX | BPF_IMM: | ||
725 | r->X = K; | ||
726 | break; | ||
727 | case BPF_LD | BPF_MEM: | ||
728 | r->A = r->M[K]; | ||
729 | break; | ||
730 | case BPF_LDX | BPF_MEM: | ||
731 | r->X = r->M[K]; | ||
732 | break; | ||
733 | case BPF_JMP_JA: | ||
734 | r->Pc += K; | ||
735 | break; | ||
736 | case BPF_JMP_JGT | BPF_X: | ||
737 | r->Pc += r->A > r->X ? f->jt : f->jf; | ||
738 | break; | ||
739 | case BPF_JMP_JGT | BPF_K: | ||
740 | r->Pc += r->A > K ? f->jt : f->jf; | ||
741 | break; | ||
742 | case BPF_JMP_JGE | BPF_X: | ||
743 | r->Pc += r->A >= r->X ? f->jt : f->jf; | ||
744 | break; | ||
745 | case BPF_JMP_JGE | BPF_K: | ||
746 | r->Pc += r->A >= K ? f->jt : f->jf; | ||
747 | break; | ||
748 | case BPF_JMP_JEQ | BPF_X: | ||
749 | r->Pc += r->A == r->X ? f->jt : f->jf; | ||
750 | break; | ||
751 | case BPF_JMP_JEQ | BPF_K: | ||
752 | r->Pc += r->A == K ? f->jt : f->jf; | ||
753 | break; | ||
754 | case BPF_JMP_JSET | BPF_X: | ||
755 | r->Pc += r->A & r->X ? f->jt : f->jf; | ||
756 | break; | ||
757 | case BPF_JMP_JSET | BPF_K: | ||
758 | r->Pc += r->A & K ? f->jt : f->jf; | ||
759 | break; | ||
760 | case BPF_ALU_NEG: | ||
761 | r->A = -r->A; | ||
762 | break; | ||
763 | case BPF_ALU_LSH | BPF_X: | ||
764 | r->A <<= r->X; | ||
765 | break; | ||
766 | case BPF_ALU_LSH | BPF_K: | ||
767 | r->A <<= K; | ||
768 | break; | ||
769 | case BPF_ALU_RSH | BPF_X: | ||
770 | r->A >>= r->X; | ||
771 | break; | ||
772 | case BPF_ALU_RSH | BPF_K: | ||
773 | r->A >>= K; | ||
774 | break; | ||
775 | case BPF_ALU_ADD | BPF_X: | ||
776 | r->A += r->X; | ||
777 | break; | ||
778 | case BPF_ALU_ADD | BPF_K: | ||
779 | r->A += K; | ||
780 | break; | ||
781 | case BPF_ALU_SUB | BPF_X: | ||
782 | r->A -= r->X; | ||
783 | break; | ||
784 | case BPF_ALU_SUB | BPF_K: | ||
785 | r->A -= K; | ||
786 | break; | ||
787 | case BPF_ALU_MUL | BPF_X: | ||
788 | r->A *= r->X; | ||
789 | break; | ||
790 | case BPF_ALU_MUL | BPF_K: | ||
791 | r->A *= K; | ||
792 | break; | ||
793 | case BPF_ALU_DIV | BPF_X: | ||
794 | case BPF_ALU_MOD | BPF_X: | ||
795 | if (r->X == 0) { | ||
796 | set_return(r); | ||
797 | break; | ||
798 | } | ||
799 | goto do_div; | ||
800 | case BPF_ALU_DIV | BPF_K: | ||
801 | case BPF_ALU_MOD | BPF_K: | ||
802 | if (K == 0) { | ||
803 | set_return(r); | ||
804 | break; | ||
805 | } | ||
806 | do_div: | ||
807 | switch (f->code) { | ||
808 | case BPF_ALU_DIV | BPF_X: | ||
809 | r->A /= r->X; | ||
810 | break; | ||
811 | case BPF_ALU_DIV | BPF_K: | ||
812 | r->A /= K; | ||
813 | break; | ||
814 | case BPF_ALU_MOD | BPF_X: | ||
815 | r->A %= r->X; | ||
816 | break; | ||
817 | case BPF_ALU_MOD | BPF_K: | ||
818 | r->A %= K; | ||
819 | break; | ||
820 | } | ||
821 | break; | ||
822 | case BPF_ALU_AND | BPF_X: | ||
823 | r->A &= r->X; | ||
824 | break; | ||
825 | case BPF_ALU_AND | BPF_K: | ||
826 | r->A &= r->X; | ||
827 | break; | ||
828 | case BPF_ALU_OR | BPF_X: | ||
829 | r->A |= r->X; | ||
830 | break; | ||
831 | case BPF_ALU_OR | BPF_K: | ||
832 | r->A |= K; | ||
833 | break; | ||
834 | case BPF_ALU_XOR | BPF_X: | ||
835 | r->A ^= r->X; | ||
836 | break; | ||
837 | case BPF_ALU_XOR | BPF_K: | ||
838 | r->A ^= K; | ||
839 | break; | ||
840 | } | ||
841 | } | ||
842 | |||
843 | static bool bpf_pc_has_breakpoint(uint16_t pc) | ||
844 | { | ||
845 | int i; | ||
846 | |||
847 | for (i = 0; i < array_size(bpf_breakpoints); i++) { | ||
848 | if (bpf_breakpoints[i] < 0) | ||
849 | continue; | ||
850 | if (bpf_breakpoints[i] == pc) | ||
851 | return true; | ||
852 | } | ||
853 | |||
854 | return false; | ||
855 | } | ||
856 | |||
857 | static bool bpf_handle_breakpoint(struct bpf_regs *r, struct sock_filter *f, | ||
858 | uint8_t *pkt, uint32_t pkt_caplen, | ||
859 | uint32_t pkt_len) | ||
860 | { | ||
861 | rl_printf("-- register dump --\n"); | ||
862 | bpf_dump_curr(r, &f[r->Pc]); | ||
863 | rl_printf("-- packet dump --\n"); | ||
864 | bpf_dump_pkt(pkt, pkt_caplen, pkt_len); | ||
865 | rl_printf("(breakpoint)\n"); | ||
866 | return true; | ||
867 | } | ||
868 | |||
869 | static int bpf_run_all(struct sock_filter *f, uint16_t bpf_len, uint8_t *pkt, | ||
870 | uint32_t pkt_caplen, uint32_t pkt_len) | ||
871 | { | ||
872 | bool stop = false; | ||
873 | |||
874 | while (bpf_curr.Rs == false && stop == false) { | ||
875 | bpf_safe_regs(); | ||
876 | |||
877 | if (bpf_pc_has_breakpoint(bpf_curr.Pc)) | ||
878 | stop = bpf_handle_breakpoint(&bpf_curr, f, pkt, | ||
879 | pkt_caplen, pkt_len); | ||
880 | |||
881 | bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen, | ||
882 | pkt_len); | ||
883 | bpf_curr.Pc++; | ||
884 | } | ||
885 | |||
886 | return stop ? -1 : bpf_curr.R; | ||
887 | } | ||
888 | |||
889 | static int bpf_run_stepping(struct sock_filter *f, uint16_t bpf_len, | ||
890 | uint8_t *pkt, uint32_t pkt_caplen, | ||
891 | uint32_t pkt_len, int next) | ||
892 | { | ||
893 | bool stop = false; | ||
894 | int i = 1; | ||
895 | |||
896 | while (bpf_curr.Rs == false && stop == false) { | ||
897 | bpf_safe_regs(); | ||
898 | |||
899 | if (i++ == next) | ||
900 | stop = bpf_handle_breakpoint(&bpf_curr, f, pkt, | ||
901 | pkt_caplen, pkt_len); | ||
902 | |||
903 | bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen, | ||
904 | pkt_len); | ||
905 | bpf_curr.Pc++; | ||
906 | } | ||
907 | |||
908 | return stop ? -1 : bpf_curr.R; | ||
909 | } | ||
910 | |||
911 | static bool pcap_loaded(void) | ||
912 | { | ||
913 | if (pcap_fd < 0) | ||
914 | rl_printf("no pcap file loaded!\n"); | ||
915 | |||
916 | return pcap_fd >= 0; | ||
917 | } | ||
918 | |||
919 | static struct pcap_pkthdr *pcap_curr_pkt(void) | ||
920 | { | ||
921 | return (void *) pcap_ptr_va_curr; | ||
922 | } | ||
923 | |||
924 | static bool pcap_next_pkt(void) | ||
925 | { | ||
926 | struct pcap_pkthdr *hdr = pcap_curr_pkt(); | ||
927 | |||
928 | if (pcap_ptr_va_curr + sizeof(*hdr) - | ||
929 | pcap_ptr_va_start >= pcap_map_size) | ||
930 | return false; | ||
931 | if (hdr->caplen == 0 || hdr->len == 0 || hdr->caplen > hdr->len) | ||
932 | return false; | ||
933 | if (pcap_ptr_va_curr + sizeof(*hdr) + hdr->caplen - | ||
934 | pcap_ptr_va_start >= pcap_map_size) | ||
935 | return false; | ||
936 | |||
937 | pcap_ptr_va_curr += (sizeof(*hdr) + hdr->caplen); | ||
938 | return true; | ||
939 | } | ||
940 | |||
941 | static void pcap_reset_pkt(void) | ||
942 | { | ||
943 | pcap_ptr_va_curr = pcap_ptr_va_start + sizeof(struct pcap_filehdr); | ||
944 | } | ||
945 | |||
946 | static int try_load_pcap(const char *file) | ||
947 | { | ||
948 | struct pcap_filehdr *hdr; | ||
949 | struct stat sb; | ||
950 | int ret; | ||
951 | |||
952 | pcap_fd = open(file, O_RDONLY); | ||
953 | if (pcap_fd < 0) { | ||
954 | rl_printf("cannot open pcap [%s]!\n", strerror(errno)); | ||
955 | return CMD_ERR; | ||
956 | } | ||
957 | |||
958 | ret = fstat(pcap_fd, &sb); | ||
959 | if (ret < 0) { | ||
960 | rl_printf("cannot fstat pcap file!\n"); | ||
961 | return CMD_ERR; | ||
962 | } | ||
963 | |||
964 | if (!S_ISREG(sb.st_mode)) { | ||
965 | rl_printf("not a regular pcap file, duh!\n"); | ||
966 | return CMD_ERR; | ||
967 | } | ||
968 | |||
969 | pcap_map_size = sb.st_size; | ||
970 | if (pcap_map_size <= sizeof(struct pcap_filehdr)) { | ||
971 | rl_printf("pcap file too small!\n"); | ||
972 | return CMD_ERR; | ||
973 | } | ||
974 | |||
975 | pcap_ptr_va_start = mmap(NULL, pcap_map_size, PROT_READ, | ||
976 | MAP_SHARED | MAP_LOCKED, pcap_fd, 0); | ||
977 | if (pcap_ptr_va_start == MAP_FAILED) { | ||
978 | rl_printf("mmap of file failed!"); | ||
979 | return CMD_ERR; | ||
980 | } | ||
981 | |||
982 | hdr = (void *) pcap_ptr_va_start; | ||
983 | if (hdr->magic != TCPDUMP_MAGIC) { | ||
984 | rl_printf("wrong pcap magic!\n"); | ||
985 | return CMD_ERR; | ||
986 | } | ||
987 | |||
988 | pcap_reset_pkt(); | ||
989 | |||
990 | return CMD_OK; | ||
991 | |||
992 | } | ||
993 | |||
994 | static void try_close_pcap(void) | ||
995 | { | ||
996 | if (pcap_fd >= 0) { | ||
997 | munmap(pcap_ptr_va_start, pcap_map_size); | ||
998 | close(pcap_fd); | ||
999 | |||
1000 | pcap_ptr_va_start = pcap_ptr_va_curr = NULL; | ||
1001 | pcap_map_size = 0; | ||
1002 | pcap_packet = 0; | ||
1003 | pcap_fd = -1; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | static int cmd_load_bpf(char *bpf_string) | ||
1008 | { | ||
1009 | char sp, *token, separator = ','; | ||
1010 | unsigned short bpf_len, i = 0; | ||
1011 | struct sock_filter tmp; | ||
1012 | |||
1013 | bpf_prog_len = 0; | ||
1014 | memset(bpf_image, 0, sizeof(bpf_image)); | ||
1015 | |||
1016 | if (sscanf(bpf_string, "%hu%c", &bpf_len, &sp) != 2 || | ||
1017 | sp != separator || bpf_len > BPF_MAXINSNS || bpf_len == 0) { | ||
1018 | rl_printf("syntax error in head length encoding!\n"); | ||
1019 | return CMD_ERR; | ||
1020 | } | ||
1021 | |||
1022 | token = bpf_string; | ||
1023 | while ((token = strchr(token, separator)) && (++token)[0]) { | ||
1024 | if (i >= bpf_len) { | ||
1025 | rl_printf("program exceeds encoded length!\n"); | ||
1026 | return CMD_ERR; | ||
1027 | } | ||
1028 | |||
1029 | if (sscanf(token, "%hu %hhu %hhu %u,", | ||
1030 | &tmp.code, &tmp.jt, &tmp.jf, &tmp.k) != 4) { | ||
1031 | rl_printf("syntax error at instruction %d!\n", i); | ||
1032 | return CMD_ERR; | ||
1033 | } | ||
1034 | |||
1035 | bpf_image[i].code = tmp.code; | ||
1036 | bpf_image[i].jt = tmp.jt; | ||
1037 | bpf_image[i].jf = tmp.jf; | ||
1038 | bpf_image[i].k = tmp.k; | ||
1039 | |||
1040 | i++; | ||
1041 | } | ||
1042 | |||
1043 | if (i != bpf_len) { | ||
1044 | rl_printf("syntax error exceeding encoded length!\n"); | ||
1045 | return CMD_ERR; | ||
1046 | } else | ||
1047 | bpf_prog_len = bpf_len; | ||
1048 | if (!bpf_runnable(bpf_image, bpf_prog_len)) | ||
1049 | bpf_prog_len = 0; | ||
1050 | |||
1051 | return CMD_OK; | ||
1052 | } | ||
1053 | |||
1054 | static int cmd_load_pcap(char *file) | ||
1055 | { | ||
1056 | char *file_trim, *tmp; | ||
1057 | |||
1058 | file_trim = strtok_r(file, " ", &tmp); | ||
1059 | if (file_trim == NULL) | ||
1060 | return CMD_ERR; | ||
1061 | |||
1062 | try_close_pcap(); | ||
1063 | |||
1064 | return try_load_pcap(file_trim); | ||
1065 | } | ||
1066 | |||
1067 | static int cmd_load(char *arg) | ||
1068 | { | ||
1069 | char *subcmd, *cont, *tmp = strdup(arg); | ||
1070 | int ret = CMD_OK; | ||
1071 | |||
1072 | subcmd = strtok_r(tmp, " ", &cont); | ||
1073 | if (subcmd == NULL) | ||
1074 | goto out; | ||
1075 | if (matches(subcmd, "bpf") == 0) { | ||
1076 | bpf_reset(); | ||
1077 | bpf_reset_breakpoints(); | ||
1078 | |||
1079 | ret = cmd_load_bpf(cont); | ||
1080 | } else if (matches(subcmd, "pcap") == 0) { | ||
1081 | ret = cmd_load_pcap(cont); | ||
1082 | } else { | ||
1083 | out: | ||
1084 | rl_printf("bpf <code>: load bpf code\n"); | ||
1085 | rl_printf("pcap <file>: load pcap file\n"); | ||
1086 | ret = CMD_ERR; | ||
1087 | } | ||
1088 | |||
1089 | free(tmp); | ||
1090 | return ret; | ||
1091 | } | ||
1092 | |||
1093 | static int cmd_step(char *num) | ||
1094 | { | ||
1095 | struct pcap_pkthdr *hdr; | ||
1096 | int steps, ret; | ||
1097 | |||
1098 | if (!bpf_prog_loaded() || !pcap_loaded()) | ||
1099 | return CMD_ERR; | ||
1100 | |||
1101 | steps = strtol(num, NULL, 10); | ||
1102 | if (steps == 0 || strlen(num) == 0) | ||
1103 | steps = 1; | ||
1104 | if (steps < 0) { | ||
1105 | if (!bpf_restore_regs(steps)) | ||
1106 | return CMD_ERR; | ||
1107 | steps = 1; | ||
1108 | } | ||
1109 | |||
1110 | hdr = pcap_curr_pkt(); | ||
1111 | ret = bpf_run_stepping(bpf_image, bpf_prog_len, | ||
1112 | (uint8_t *) hdr + sizeof(*hdr), | ||
1113 | hdr->caplen, hdr->len, steps); | ||
1114 | if (ret >= 0 || bpf_curr.Rs) { | ||
1115 | bpf_reset(); | ||
1116 | if (!pcap_next_pkt()) { | ||
1117 | rl_printf("(going back to first packet)\n"); | ||
1118 | pcap_reset_pkt(); | ||
1119 | } else { | ||
1120 | rl_printf("(next packet)\n"); | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1124 | return CMD_OK; | ||
1125 | } | ||
1126 | |||
1127 | static int cmd_select(char *num) | ||
1128 | { | ||
1129 | unsigned int which, i; | ||
1130 | struct pcap_pkthdr *hdr; | ||
1131 | bool have_next = true; | ||
1132 | |||
1133 | if (!pcap_loaded() || strlen(num) == 0) | ||
1134 | return CMD_ERR; | ||
1135 | |||
1136 | which = strtoul(num, NULL, 10); | ||
1137 | if (which == 0) { | ||
1138 | rl_printf("packet count starts with 1, clamping!\n"); | ||
1139 | which = 1; | ||
1140 | } | ||
1141 | |||
1142 | pcap_reset_pkt(); | ||
1143 | bpf_reset(); | ||
1144 | |||
1145 | for (i = 0; i < which && (have_next = pcap_next_pkt()); i++) | ||
1146 | /* noop */; | ||
1147 | if (!have_next || (hdr = pcap_curr_pkt()) == NULL) { | ||
1148 | rl_printf("no packet #%u available!\n", which); | ||
1149 | pcap_reset_pkt(); | ||
1150 | return CMD_ERR; | ||
1151 | } | ||
1152 | |||
1153 | return CMD_OK; | ||
1154 | } | ||
1155 | |||
1156 | static int cmd_breakpoint(char *subcmd) | ||
1157 | { | ||
1158 | if (!bpf_prog_loaded()) | ||
1159 | return CMD_ERR; | ||
1160 | if (strlen(subcmd) == 0) | ||
1161 | bpf_dump_breakpoints(); | ||
1162 | else if (matches(subcmd, "reset") == 0) | ||
1163 | bpf_reset_breakpoints(); | ||
1164 | else { | ||
1165 | unsigned int where = strtoul(subcmd, NULL, 10); | ||
1166 | |||
1167 | if (where < bpf_prog_len) { | ||
1168 | bpf_set_breakpoints(where); | ||
1169 | rl_printf("breakpoint at: "); | ||
1170 | bpf_disasm(bpf_image[where], where); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | return CMD_OK; | ||
1175 | } | ||
1176 | |||
1177 | static int cmd_run(char *num) | ||
1178 | { | ||
1179 | static uint32_t pass = 0, fail = 0; | ||
1180 | struct pcap_pkthdr *hdr; | ||
1181 | bool has_limit = true; | ||
1182 | int ret, pkts = 0, i = 0; | ||
1183 | |||
1184 | if (!bpf_prog_loaded() || !pcap_loaded()) | ||
1185 | return CMD_ERR; | ||
1186 | |||
1187 | pkts = strtol(num, NULL, 10); | ||
1188 | if (pkts == 0 || strlen(num) == 0) | ||
1189 | has_limit = false; | ||
1190 | |||
1191 | do { | ||
1192 | hdr = pcap_curr_pkt(); | ||
1193 | ret = bpf_run_all(bpf_image, bpf_prog_len, | ||
1194 | (uint8_t *) hdr + sizeof(*hdr), | ||
1195 | hdr->caplen, hdr->len); | ||
1196 | if (ret > 0) | ||
1197 | pass++; | ||
1198 | else if (ret == 0) | ||
1199 | fail++; | ||
1200 | else | ||
1201 | return CMD_OK; | ||
1202 | bpf_reset(); | ||
1203 | } while (pcap_next_pkt() && (!has_limit || (has_limit && ++i < pkts))); | ||
1204 | |||
1205 | rl_printf("bpf passes:%u fails:%u\n", pass, fail); | ||
1206 | |||
1207 | pcap_reset_pkt(); | ||
1208 | bpf_reset(); | ||
1209 | |||
1210 | pass = fail = 0; | ||
1211 | return CMD_OK; | ||
1212 | } | ||
1213 | |||
1214 | static int cmd_disassemble(char *line_string) | ||
1215 | { | ||
1216 | bool single_line = false; | ||
1217 | unsigned long line; | ||
1218 | |||
1219 | if (!bpf_prog_loaded()) | ||
1220 | return CMD_ERR; | ||
1221 | if (strlen(line_string) > 0 && | ||
1222 | (line = strtoul(line_string, NULL, 10)) < bpf_prog_len) | ||
1223 | single_line = true; | ||
1224 | if (single_line) | ||
1225 | bpf_disasm(bpf_image[line], line); | ||
1226 | else | ||
1227 | bpf_disasm_all(bpf_image, bpf_prog_len); | ||
1228 | |||
1229 | return CMD_OK; | ||
1230 | } | ||
1231 | |||
1232 | static int cmd_dump(char *dontcare) | ||
1233 | { | ||
1234 | if (!bpf_prog_loaded()) | ||
1235 | return CMD_ERR; | ||
1236 | |||
1237 | bpf_dump_all(bpf_image, bpf_prog_len); | ||
1238 | |||
1239 | return CMD_OK; | ||
1240 | } | ||
1241 | |||
1242 | static int cmd_quit(char *dontcare) | ||
1243 | { | ||
1244 | return CMD_EX; | ||
1245 | } | ||
1246 | |||
1247 | static const struct shell_cmd cmds[] = { | ||
1248 | CMD("load", cmd_load), | ||
1249 | CMD("select", cmd_select), | ||
1250 | CMD("step", cmd_step), | ||
1251 | CMD("run", cmd_run), | ||
1252 | CMD("breakpoint", cmd_breakpoint), | ||
1253 | CMD("disassemble", cmd_disassemble), | ||
1254 | CMD("dump", cmd_dump), | ||
1255 | CMD("quit", cmd_quit), | ||
1256 | }; | ||
1257 | |||
1258 | static int execf(char *arg) | ||
1259 | { | ||
1260 | char *cmd, *cont, *tmp = strdup(arg); | ||
1261 | int i, ret = 0, len; | ||
1262 | |||
1263 | cmd = strtok_r(tmp, " ", &cont); | ||
1264 | if (cmd == NULL) | ||
1265 | goto out; | ||
1266 | len = strlen(cmd); | ||
1267 | for (i = 0; i < array_size(cmds); i++) { | ||
1268 | if (len != strlen(cmds[i].name)) | ||
1269 | continue; | ||
1270 | if (strncmp(cmds[i].name, cmd, len) == 0) { | ||
1271 | ret = cmds[i].func(cont); | ||
1272 | break; | ||
1273 | } | ||
1274 | } | ||
1275 | out: | ||
1276 | free(tmp); | ||
1277 | return ret; | ||
1278 | } | ||
1279 | |||
1280 | static char *shell_comp_gen(const char *buf, int state) | ||
1281 | { | ||
1282 | static int list_index, len; | ||
1283 | const char *name; | ||
1284 | |||
1285 | if (!state) { | ||
1286 | list_index = 0; | ||
1287 | len = strlen(buf); | ||
1288 | } | ||
1289 | |||
1290 | for (; list_index < array_size(cmds); ) { | ||
1291 | name = cmds[list_index].name; | ||
1292 | list_index++; | ||
1293 | |||
1294 | if (strncmp(name, buf, len) == 0) | ||
1295 | return strdup(name); | ||
1296 | } | ||
1297 | |||
1298 | return NULL; | ||
1299 | } | ||
1300 | |||
1301 | static char **shell_completion(const char *buf, int start, int end) | ||
1302 | { | ||
1303 | char **matches = NULL; | ||
1304 | |||
1305 | if (start == 0) | ||
1306 | matches = rl_completion_matches(buf, shell_comp_gen); | ||
1307 | |||
1308 | return matches; | ||
1309 | } | ||
1310 | |||
1311 | static void intr_shell(int sig) | ||
1312 | { | ||
1313 | if (rl_end) | ||
1314 | rl_kill_line(-1, 0); | ||
1315 | |||
1316 | rl_crlf(); | ||
1317 | rl_refresh_line(0, 0); | ||
1318 | rl_free_line_state(); | ||
1319 | } | ||
1320 | |||
1321 | static void init_shell(FILE *fin, FILE *fout) | ||
1322 | { | ||
1323 | char file[128]; | ||
1324 | |||
1325 | memset(file, 0, sizeof(file)); | ||
1326 | snprintf(file, sizeof(file) - 1, | ||
1327 | "%s/.bpf_dbg_history", getenv("HOME")); | ||
1328 | |||
1329 | read_history(file); | ||
1330 | |||
1331 | memset(file, 0, sizeof(file)); | ||
1332 | snprintf(file, sizeof(file) - 1, | ||
1333 | "%s/.bpf_dbg_init", getenv("HOME")); | ||
1334 | |||
1335 | rl_instream = fin; | ||
1336 | rl_outstream = fout; | ||
1337 | |||
1338 | rl_readline_name = "bpf_dbg"; | ||
1339 | rl_terminal_name = getenv("TERM"); | ||
1340 | |||
1341 | rl_catch_signals = 0; | ||
1342 | rl_catch_sigwinch = 1; | ||
1343 | |||
1344 | rl_attempted_completion_function = shell_completion; | ||
1345 | |||
1346 | rl_bind_key('\t', rl_complete); | ||
1347 | |||
1348 | rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap); | ||
1349 | rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap); | ||
1350 | |||
1351 | rl_read_init_file(file); | ||
1352 | rl_prep_terminal(0); | ||
1353 | rl_set_signals(); | ||
1354 | |||
1355 | signal(SIGINT, intr_shell); | ||
1356 | } | ||
1357 | |||
1358 | static void exit_shell(void) | ||
1359 | { | ||
1360 | char file[128]; | ||
1361 | |||
1362 | memset(file, 0, sizeof(file)); | ||
1363 | snprintf(file, sizeof(file) - 1, | ||
1364 | "%s/.bpf_dbg_history", getenv("HOME")); | ||
1365 | |||
1366 | write_history(file); | ||
1367 | clear_history(); | ||
1368 | rl_deprep_terminal(); | ||
1369 | |||
1370 | try_close_pcap(); | ||
1371 | } | ||
1372 | |||
1373 | static int run_shell_loop(FILE *fin, FILE *fout) | ||
1374 | { | ||
1375 | char *buf; | ||
1376 | int ret; | ||
1377 | |||
1378 | init_shell(fin, fout); | ||
1379 | |||
1380 | while ((buf = readline("> ")) != NULL) { | ||
1381 | ret = execf(buf); | ||
1382 | if (ret == CMD_EX) | ||
1383 | break; | ||
1384 | if (ret == CMD_OK && strlen(buf) > 0) | ||
1385 | add_history(buf); | ||
1386 | |||
1387 | free(buf); | ||
1388 | } | ||
1389 | |||
1390 | exit_shell(); | ||
1391 | return 0; | ||
1392 | } | ||
1393 | |||
1394 | int main(int argc, char **argv) | ||
1395 | { | ||
1396 | FILE *fin = NULL, *fout = NULL; | ||
1397 | |||
1398 | if (argc >= 2) | ||
1399 | fin = fopen(argv[1], "r"); | ||
1400 | if (argc >= 3) | ||
1401 | fout = fopen(argv[2], "w"); | ||
1402 | |||
1403 | return run_shell_loop(fin ? : stdin, fout ? : stdout); | ||
1404 | } | ||
diff --git a/tools/net/bpf_exp.l b/tools/net/bpf_exp.l new file mode 100644 index 000000000000..bf7be77ddd62 --- /dev/null +++ b/tools/net/bpf_exp.l | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * BPF asm code lexer | ||
3 | * | ||
4 | * This program is free software; you can distribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published | ||
6 | * by the Free Software Foundation; either version 2 of the License, | ||
7 | * or (at your option) any later version. | ||
8 | * | ||
9 | * Syntax kept close to: | ||
10 | * | ||
11 | * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new | ||
12 | * architecture for user-level packet capture. In Proceedings of the | ||
13 | * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993 | ||
14 | * Conference Proceedings (USENIX'93). USENIX Association, Berkeley, | ||
15 | * CA, USA, 2-2. | ||
16 | * | ||
17 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
18 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
19 | */ | ||
20 | |||
21 | %{ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <stdint.h> | ||
25 | #include <stdlib.h> | ||
26 | |||
27 | #include "bpf_exp.yacc.h" | ||
28 | |||
29 | extern void yyerror(const char *str); | ||
30 | |||
31 | %} | ||
32 | |||
33 | %option align | ||
34 | %option ecs | ||
35 | |||
36 | %option nounput | ||
37 | %option noreject | ||
38 | %option noinput | ||
39 | %option noyywrap | ||
40 | |||
41 | %option 8bit | ||
42 | %option caseless | ||
43 | %option yylineno | ||
44 | |||
45 | %% | ||
46 | |||
47 | "ldb" { return OP_LDB; } | ||
48 | "ldh" { return OP_LDH; } | ||
49 | "ld" { return OP_LD; } | ||
50 | "ldi" { return OP_LDI; } | ||
51 | "ldx" { return OP_LDX; } | ||
52 | "ldxi" { return OP_LDXI; } | ||
53 | "ldxb" { return OP_LDXB; } | ||
54 | "st" { return OP_ST; } | ||
55 | "stx" { return OP_STX; } | ||
56 | "jmp" { return OP_JMP; } | ||
57 | "ja" { return OP_JMP; } | ||
58 | "jeq" { return OP_JEQ; } | ||
59 | "jneq" { return OP_JNEQ; } | ||
60 | "jne" { return OP_JNEQ; } | ||
61 | "jlt" { return OP_JLT; } | ||
62 | "jle" { return OP_JLE; } | ||
63 | "jgt" { return OP_JGT; } | ||
64 | "jge" { return OP_JGE; } | ||
65 | "jset" { return OP_JSET; } | ||
66 | "add" { return OP_ADD; } | ||
67 | "sub" { return OP_SUB; } | ||
68 | "mul" { return OP_MUL; } | ||
69 | "div" { return OP_DIV; } | ||
70 | "mod" { return OP_MOD; } | ||
71 | "neg" { return OP_NEG; } | ||
72 | "and" { return OP_AND; } | ||
73 | "xor" { return OP_XOR; } | ||
74 | "or" { return OP_OR; } | ||
75 | "lsh" { return OP_LSH; } | ||
76 | "rsh" { return OP_RSH; } | ||
77 | "ret" { return OP_RET; } | ||
78 | "tax" { return OP_TAX; } | ||
79 | "txa" { return OP_TXA; } | ||
80 | |||
81 | "#"?("len") { return K_PKT_LEN; } | ||
82 | "#"?("proto") { return K_PROTO; } | ||
83 | "#"?("type") { return K_TYPE; } | ||
84 | "#"?("poff") { return K_POFF; } | ||
85 | "#"?("ifidx") { return K_IFIDX; } | ||
86 | "#"?("nla") { return K_NLATTR; } | ||
87 | "#"?("nlan") { return K_NLATTR_NEST; } | ||
88 | "#"?("mark") { return K_MARK; } | ||
89 | "#"?("queue") { return K_QUEUE; } | ||
90 | "#"?("hatype") { return K_HATYPE; } | ||
91 | "#"?("rxhash") { return K_RXHASH; } | ||
92 | "#"?("cpu") { return K_CPU; } | ||
93 | "#"?("vlan_tci") { return K_VLANT; } | ||
94 | "#"?("vlan_pr") { return K_VLANP; } | ||
95 | |||
96 | ":" { return ':'; } | ||
97 | "," { return ','; } | ||
98 | "#" { return '#'; } | ||
99 | "%" { return '%'; } | ||
100 | "[" { return '['; } | ||
101 | "]" { return ']'; } | ||
102 | "(" { return '('; } | ||
103 | ")" { return ')'; } | ||
104 | "x" { return 'x'; } | ||
105 | "a" { return 'a'; } | ||
106 | "+" { return '+'; } | ||
107 | "M" { return 'M'; } | ||
108 | "*" { return '*'; } | ||
109 | "&" { return '&'; } | ||
110 | |||
111 | ([0][x][a-fA-F0-9]+) { | ||
112 | yylval.number = strtoul(yytext, NULL, 16); | ||
113 | return number; | ||
114 | } | ||
115 | ([0][b][0-1]+) { | ||
116 | yylval.number = strtol(yytext + 2, NULL, 2); | ||
117 | return number; | ||
118 | } | ||
119 | (([0])|([-+]?[1-9][0-9]*)) { | ||
120 | yylval.number = strtol(yytext, NULL, 10); | ||
121 | return number; | ||
122 | } | ||
123 | ([0][0-9]+) { | ||
124 | yylval.number = strtol(yytext + 1, NULL, 8); | ||
125 | return number; | ||
126 | } | ||
127 | [a-zA-Z_][a-zA-Z0-9_]+ { | ||
128 | yylval.label = strdup(yytext); | ||
129 | return label; | ||
130 | } | ||
131 | |||
132 | "/*"([^\*]|\*[^/])*"*/" { /* NOP */ } | ||
133 | ";"[^\n]* { /* NOP */ } | ||
134 | ^#.* { /* NOP */ } | ||
135 | [ \t]+ { /* NOP */ } | ||
136 | [ \n]+ { /* NOP */ } | ||
137 | |||
138 | . { | ||
139 | printf("unknown character \'%s\'", yytext); | ||
140 | yyerror("lex unknown character"); | ||
141 | } | ||
142 | |||
143 | %% | ||
diff --git a/tools/net/bpf_exp.y b/tools/net/bpf_exp.y new file mode 100644 index 000000000000..d15efc989ef5 --- /dev/null +++ b/tools/net/bpf_exp.y | |||
@@ -0,0 +1,762 @@ | |||
1 | /* | ||
2 | * BPF asm code parser | ||
3 | * | ||
4 | * This program is free software; you can distribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published | ||
6 | * by the Free Software Foundation; either version 2 of the License, | ||
7 | * or (at your option) any later version. | ||
8 | * | ||
9 | * Syntax kept close to: | ||
10 | * | ||
11 | * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new | ||
12 | * architecture for user-level packet capture. In Proceedings of the | ||
13 | * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993 | ||
14 | * Conference Proceedings (USENIX'93). USENIX Association, Berkeley, | ||
15 | * CA, USA, 2-2. | ||
16 | * | ||
17 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
18 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
19 | */ | ||
20 | |||
21 | %{ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <string.h> | ||
25 | #include <stdint.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <stdbool.h> | ||
28 | #include <unistd.h> | ||
29 | #include <errno.h> | ||
30 | #include <assert.h> | ||
31 | #include <linux/filter.h> | ||
32 | |||
33 | #include "bpf_exp.yacc.h" | ||
34 | |||
35 | enum jmp_type { JTL, JFL, JKL }; | ||
36 | |||
37 | extern FILE *yyin; | ||
38 | extern int yylex(void); | ||
39 | extern void yyerror(const char *str); | ||
40 | |||
41 | extern void bpf_asm_compile(FILE *fp, bool cstyle); | ||
42 | static void bpf_set_curr_instr(uint16_t op, uint8_t jt, uint8_t jf, uint32_t k); | ||
43 | static void bpf_set_curr_label(char *label); | ||
44 | static void bpf_set_jmp_label(char *label, enum jmp_type type); | ||
45 | |||
46 | %} | ||
47 | |||
48 | %union { | ||
49 | char *label; | ||
50 | uint32_t number; | ||
51 | } | ||
52 | |||
53 | %token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE | ||
54 | %token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH | ||
55 | %token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI | ||
56 | %token OP_LDXI | ||
57 | |||
58 | %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE | ||
59 | %token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF | ||
60 | |||
61 | %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' | ||
62 | |||
63 | %token number label | ||
64 | |||
65 | %type <label> label | ||
66 | %type <number> number | ||
67 | |||
68 | %% | ||
69 | |||
70 | prog | ||
71 | : line | ||
72 | | prog line | ||
73 | ; | ||
74 | |||
75 | line | ||
76 | : instr | ||
77 | | labelled_instr | ||
78 | ; | ||
79 | |||
80 | labelled_instr | ||
81 | : labelled instr | ||
82 | ; | ||
83 | |||
84 | instr | ||
85 | : ldb | ||
86 | | ldh | ||
87 | | ld | ||
88 | | ldi | ||
89 | | ldx | ||
90 | | ldxi | ||
91 | | st | ||
92 | | stx | ||
93 | | jmp | ||
94 | | jeq | ||
95 | | jneq | ||
96 | | jlt | ||
97 | | jle | ||
98 | | jgt | ||
99 | | jge | ||
100 | | jset | ||
101 | | add | ||
102 | | sub | ||
103 | | mul | ||
104 | | div | ||
105 | | mod | ||
106 | | neg | ||
107 | | and | ||
108 | | or | ||
109 | | xor | ||
110 | | lsh | ||
111 | | rsh | ||
112 | | ret | ||
113 | | tax | ||
114 | | txa | ||
115 | ; | ||
116 | |||
117 | labelled | ||
118 | : label ':' { bpf_set_curr_label($1); } | ||
119 | ; | ||
120 | |||
121 | ldb | ||
122 | : OP_LDB '[' 'x' '+' number ']' { | ||
123 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $5); } | ||
124 | | OP_LDB '[' '%' 'x' '+' number ']' { | ||
125 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); } | ||
126 | | OP_LDB '[' number ']' { | ||
127 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); } | ||
128 | | OP_LDB K_PROTO { | ||
129 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
130 | SKF_AD_OFF + SKF_AD_PROTOCOL); } | ||
131 | | OP_LDB K_TYPE { | ||
132 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
133 | SKF_AD_OFF + SKF_AD_PKTTYPE); } | ||
134 | | OP_LDB K_IFIDX { | ||
135 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
136 | SKF_AD_OFF + SKF_AD_IFINDEX); } | ||
137 | | OP_LDB K_NLATTR { | ||
138 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
139 | SKF_AD_OFF + SKF_AD_NLATTR); } | ||
140 | | OP_LDB K_NLATTR_NEST { | ||
141 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
142 | SKF_AD_OFF + SKF_AD_NLATTR_NEST); } | ||
143 | | OP_LDB K_MARK { | ||
144 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
145 | SKF_AD_OFF + SKF_AD_MARK); } | ||
146 | | OP_LDB K_QUEUE { | ||
147 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
148 | SKF_AD_OFF + SKF_AD_QUEUE); } | ||
149 | | OP_LDB K_HATYPE { | ||
150 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
151 | SKF_AD_OFF + SKF_AD_HATYPE); } | ||
152 | | OP_LDB K_RXHASH { | ||
153 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
154 | SKF_AD_OFF + SKF_AD_RXHASH); } | ||
155 | | OP_LDB K_CPU { | ||
156 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
157 | SKF_AD_OFF + SKF_AD_CPU); } | ||
158 | | OP_LDB K_VLANT { | ||
159 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
160 | SKF_AD_OFF + SKF_AD_VLAN_TAG); } | ||
161 | | OP_LDB K_VLANP { | ||
162 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
163 | SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } | ||
164 | | OP_LDB K_POFF { | ||
165 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
166 | SKF_AD_OFF + SKF_AD_PAY_OFFSET); } | ||
167 | ; | ||
168 | |||
169 | ldh | ||
170 | : OP_LDH '[' 'x' '+' number ']' { | ||
171 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); } | ||
172 | | OP_LDH '[' '%' 'x' '+' number ']' { | ||
173 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); } | ||
174 | | OP_LDH '[' number ']' { | ||
175 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); } | ||
176 | | OP_LDH K_PROTO { | ||
177 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
178 | SKF_AD_OFF + SKF_AD_PROTOCOL); } | ||
179 | | OP_LDH K_TYPE { | ||
180 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
181 | SKF_AD_OFF + SKF_AD_PKTTYPE); } | ||
182 | | OP_LDH K_IFIDX { | ||
183 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
184 | SKF_AD_OFF + SKF_AD_IFINDEX); } | ||
185 | | OP_LDH K_NLATTR { | ||
186 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
187 | SKF_AD_OFF + SKF_AD_NLATTR); } | ||
188 | | OP_LDH K_NLATTR_NEST { | ||
189 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
190 | SKF_AD_OFF + SKF_AD_NLATTR_NEST); } | ||
191 | | OP_LDH K_MARK { | ||
192 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
193 | SKF_AD_OFF + SKF_AD_MARK); } | ||
194 | | OP_LDH K_QUEUE { | ||
195 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
196 | SKF_AD_OFF + SKF_AD_QUEUE); } | ||
197 | | OP_LDH K_HATYPE { | ||
198 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
199 | SKF_AD_OFF + SKF_AD_HATYPE); } | ||
200 | | OP_LDH K_RXHASH { | ||
201 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
202 | SKF_AD_OFF + SKF_AD_RXHASH); } | ||
203 | | OP_LDH K_CPU { | ||
204 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
205 | SKF_AD_OFF + SKF_AD_CPU); } | ||
206 | | OP_LDH K_VLANT { | ||
207 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
208 | SKF_AD_OFF + SKF_AD_VLAN_TAG); } | ||
209 | | OP_LDH K_VLANP { | ||
210 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
211 | SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } | ||
212 | | OP_LDH K_POFF { | ||
213 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
214 | SKF_AD_OFF + SKF_AD_PAY_OFFSET); } | ||
215 | ; | ||
216 | |||
217 | ldi | ||
218 | : OP_LDI '#' number { | ||
219 | bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); } | ||
220 | | OP_LDI number { | ||
221 | bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); } | ||
222 | ; | ||
223 | |||
224 | ld | ||
225 | : OP_LD '#' number { | ||
226 | bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); } | ||
227 | | OP_LD K_PKT_LEN { | ||
228 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); } | ||
229 | | OP_LD K_PROTO { | ||
230 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
231 | SKF_AD_OFF + SKF_AD_PROTOCOL); } | ||
232 | | OP_LD K_TYPE { | ||
233 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
234 | SKF_AD_OFF + SKF_AD_PKTTYPE); } | ||
235 | | OP_LD K_IFIDX { | ||
236 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
237 | SKF_AD_OFF + SKF_AD_IFINDEX); } | ||
238 | | OP_LD K_NLATTR { | ||
239 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
240 | SKF_AD_OFF + SKF_AD_NLATTR); } | ||
241 | | OP_LD K_NLATTR_NEST { | ||
242 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
243 | SKF_AD_OFF + SKF_AD_NLATTR_NEST); } | ||
244 | | OP_LD K_MARK { | ||
245 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
246 | SKF_AD_OFF + SKF_AD_MARK); } | ||
247 | | OP_LD K_QUEUE { | ||
248 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
249 | SKF_AD_OFF + SKF_AD_QUEUE); } | ||
250 | | OP_LD K_HATYPE { | ||
251 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
252 | SKF_AD_OFF + SKF_AD_HATYPE); } | ||
253 | | OP_LD K_RXHASH { | ||
254 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
255 | SKF_AD_OFF + SKF_AD_RXHASH); } | ||
256 | | OP_LD K_CPU { | ||
257 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
258 | SKF_AD_OFF + SKF_AD_CPU); } | ||
259 | | OP_LD K_VLANT { | ||
260 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
261 | SKF_AD_OFF + SKF_AD_VLAN_TAG); } | ||
262 | | OP_LD K_VLANP { | ||
263 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
264 | SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } | ||
265 | | OP_LD K_POFF { | ||
266 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
267 | SKF_AD_OFF + SKF_AD_PAY_OFFSET); } | ||
268 | | OP_LD 'M' '[' number ']' { | ||
269 | bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } | ||
270 | | OP_LD '[' 'x' '+' number ']' { | ||
271 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); } | ||
272 | | OP_LD '[' '%' 'x' '+' number ']' { | ||
273 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); } | ||
274 | | OP_LD '[' number ']' { | ||
275 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); } | ||
276 | ; | ||
277 | |||
278 | ldxi | ||
279 | : OP_LDXI '#' number { | ||
280 | bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); } | ||
281 | | OP_LDXI number { | ||
282 | bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); } | ||
283 | ; | ||
284 | |||
285 | ldx | ||
286 | : OP_LDX '#' number { | ||
287 | bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); } | ||
288 | | OP_LDX K_PKT_LEN { | ||
289 | bpf_set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); } | ||
290 | | OP_LDX 'M' '[' number ']' { | ||
291 | bpf_set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); } | ||
292 | | OP_LDXB number '*' '(' '[' number ']' '&' number ')' { | ||
293 | if ($2 != 4 || $9 != 0xf) { | ||
294 | fprintf(stderr, "ldxb offset not supported!\n"); | ||
295 | exit(0); | ||
296 | } else { | ||
297 | bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } } | ||
298 | | OP_LDX number '*' '(' '[' number ']' '&' number ')' { | ||
299 | if ($2 != 4 || $9 != 0xf) { | ||
300 | fprintf(stderr, "ldxb offset not supported!\n"); | ||
301 | exit(0); | ||
302 | } else { | ||
303 | bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } } | ||
304 | ; | ||
305 | |||
306 | st | ||
307 | : OP_ST 'M' '[' number ']' { | ||
308 | bpf_set_curr_instr(BPF_ST, 0, 0, $4); } | ||
309 | ; | ||
310 | |||
311 | stx | ||
312 | : OP_STX 'M' '[' number ']' { | ||
313 | bpf_set_curr_instr(BPF_STX, 0, 0, $4); } | ||
314 | ; | ||
315 | |||
316 | jmp | ||
317 | : OP_JMP label { | ||
318 | bpf_set_jmp_label($2, JKL); | ||
319 | bpf_set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); } | ||
320 | ; | ||
321 | |||
322 | jeq | ||
323 | : OP_JEQ '#' number ',' label ',' label { | ||
324 | bpf_set_jmp_label($5, JTL); | ||
325 | bpf_set_jmp_label($7, JFL); | ||
326 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } | ||
327 | | OP_JEQ 'x' ',' label ',' label { | ||
328 | bpf_set_jmp_label($4, JTL); | ||
329 | bpf_set_jmp_label($6, JFL); | ||
330 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
331 | | OP_JEQ '%' 'x' ',' label ',' label { | ||
332 | bpf_set_jmp_label($5, JTL); | ||
333 | bpf_set_jmp_label($7, JFL); | ||
334 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
335 | | OP_JEQ '#' number ',' label { | ||
336 | bpf_set_jmp_label($5, JTL); | ||
337 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } | ||
338 | | OP_JEQ 'x' ',' label { | ||
339 | bpf_set_jmp_label($4, JTL); | ||
340 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
341 | | OP_JEQ '%' 'x' ',' label { | ||
342 | bpf_set_jmp_label($5, JTL); | ||
343 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
344 | ; | ||
345 | |||
346 | jneq | ||
347 | : OP_JNEQ '#' number ',' label { | ||
348 | bpf_set_jmp_label($5, JFL); | ||
349 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } | ||
350 | | OP_JNEQ 'x' ',' label { | ||
351 | bpf_set_jmp_label($4, JFL); | ||
352 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
353 | | OP_JNEQ '%' 'x' ',' label { | ||
354 | bpf_set_jmp_label($5, JFL); | ||
355 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
356 | ; | ||
357 | |||
358 | jlt | ||
359 | : OP_JLT '#' number ',' label { | ||
360 | bpf_set_jmp_label($5, JFL); | ||
361 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } | ||
362 | | OP_JLT 'x' ',' label { | ||
363 | bpf_set_jmp_label($4, JFL); | ||
364 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
365 | | OP_JLT '%' 'x' ',' label { | ||
366 | bpf_set_jmp_label($5, JFL); | ||
367 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
368 | ; | ||
369 | |||
370 | jle | ||
371 | : OP_JLE '#' number ',' label { | ||
372 | bpf_set_jmp_label($5, JFL); | ||
373 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } | ||
374 | | OP_JLE 'x' ',' label { | ||
375 | bpf_set_jmp_label($4, JFL); | ||
376 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
377 | | OP_JLE '%' 'x' ',' label { | ||
378 | bpf_set_jmp_label($5, JFL); | ||
379 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
380 | ; | ||
381 | |||
382 | jgt | ||
383 | : OP_JGT '#' number ',' label ',' label { | ||
384 | bpf_set_jmp_label($5, JTL); | ||
385 | bpf_set_jmp_label($7, JFL); | ||
386 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } | ||
387 | | OP_JGT 'x' ',' label ',' label { | ||
388 | bpf_set_jmp_label($4, JTL); | ||
389 | bpf_set_jmp_label($6, JFL); | ||
390 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
391 | | OP_JGT '%' 'x' ',' label ',' label { | ||
392 | bpf_set_jmp_label($5, JTL); | ||
393 | bpf_set_jmp_label($7, JFL); | ||
394 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
395 | | OP_JGT '#' number ',' label { | ||
396 | bpf_set_jmp_label($5, JTL); | ||
397 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } | ||
398 | | OP_JGT 'x' ',' label { | ||
399 | bpf_set_jmp_label($4, JTL); | ||
400 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
401 | | OP_JGT '%' 'x' ',' label { | ||
402 | bpf_set_jmp_label($5, JTL); | ||
403 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
404 | ; | ||
405 | |||
406 | jge | ||
407 | : OP_JGE '#' number ',' label ',' label { | ||
408 | bpf_set_jmp_label($5, JTL); | ||
409 | bpf_set_jmp_label($7, JFL); | ||
410 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } | ||
411 | | OP_JGE 'x' ',' label ',' label { | ||
412 | bpf_set_jmp_label($4, JTL); | ||
413 | bpf_set_jmp_label($6, JFL); | ||
414 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
415 | | OP_JGE '%' 'x' ',' label ',' label { | ||
416 | bpf_set_jmp_label($5, JTL); | ||
417 | bpf_set_jmp_label($7, JFL); | ||
418 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
419 | | OP_JGE '#' number ',' label { | ||
420 | bpf_set_jmp_label($5, JTL); | ||
421 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } | ||
422 | | OP_JGE 'x' ',' label { | ||
423 | bpf_set_jmp_label($4, JTL); | ||
424 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
425 | | OP_JGE '%' 'x' ',' label { | ||
426 | bpf_set_jmp_label($5, JTL); | ||
427 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
428 | ; | ||
429 | |||
430 | jset | ||
431 | : OP_JSET '#' number ',' label ',' label { | ||
432 | bpf_set_jmp_label($5, JTL); | ||
433 | bpf_set_jmp_label($7, JFL); | ||
434 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); } | ||
435 | | OP_JSET 'x' ',' label ',' label { | ||
436 | bpf_set_jmp_label($4, JTL); | ||
437 | bpf_set_jmp_label($6, JFL); | ||
438 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
439 | | OP_JSET '%' 'x' ',' label ',' label { | ||
440 | bpf_set_jmp_label($5, JTL); | ||
441 | bpf_set_jmp_label($7, JFL); | ||
442 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
443 | | OP_JSET '#' number ',' label { | ||
444 | bpf_set_jmp_label($5, JTL); | ||
445 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); } | ||
446 | | OP_JSET 'x' ',' label { | ||
447 | bpf_set_jmp_label($4, JTL); | ||
448 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
449 | | OP_JSET '%' 'x' ',' label { | ||
450 | bpf_set_jmp_label($5, JTL); | ||
451 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
452 | ; | ||
453 | |||
454 | add | ||
455 | : OP_ADD '#' number { | ||
456 | bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); } | ||
457 | | OP_ADD 'x' { | ||
458 | bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); } | ||
459 | | OP_ADD '%' 'x' { | ||
460 | bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); } | ||
461 | ; | ||
462 | |||
463 | sub | ||
464 | : OP_SUB '#' number { | ||
465 | bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); } | ||
466 | | OP_SUB 'x' { | ||
467 | bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); } | ||
468 | | OP_SUB '%' 'x' { | ||
469 | bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); } | ||
470 | ; | ||
471 | |||
472 | mul | ||
473 | : OP_MUL '#' number { | ||
474 | bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); } | ||
475 | | OP_MUL 'x' { | ||
476 | bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); } | ||
477 | | OP_MUL '%' 'x' { | ||
478 | bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); } | ||
479 | ; | ||
480 | |||
481 | div | ||
482 | : OP_DIV '#' number { | ||
483 | bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); } | ||
484 | | OP_DIV 'x' { | ||
485 | bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); } | ||
486 | | OP_DIV '%' 'x' { | ||
487 | bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); } | ||
488 | ; | ||
489 | |||
490 | mod | ||
491 | : OP_MOD '#' number { | ||
492 | bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); } | ||
493 | | OP_MOD 'x' { | ||
494 | bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); } | ||
495 | | OP_MOD '%' 'x' { | ||
496 | bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); } | ||
497 | ; | ||
498 | |||
499 | neg | ||
500 | : OP_NEG { | ||
501 | bpf_set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); } | ||
502 | ; | ||
503 | |||
504 | and | ||
505 | : OP_AND '#' number { | ||
506 | bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); } | ||
507 | | OP_AND 'x' { | ||
508 | bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); } | ||
509 | | OP_AND '%' 'x' { | ||
510 | bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); } | ||
511 | ; | ||
512 | |||
513 | or | ||
514 | : OP_OR '#' number { | ||
515 | bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); } | ||
516 | | OP_OR 'x' { | ||
517 | bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); } | ||
518 | | OP_OR '%' 'x' { | ||
519 | bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); } | ||
520 | ; | ||
521 | |||
522 | xor | ||
523 | : OP_XOR '#' number { | ||
524 | bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); } | ||
525 | | OP_XOR 'x' { | ||
526 | bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); } | ||
527 | | OP_XOR '%' 'x' { | ||
528 | bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); } | ||
529 | ; | ||
530 | |||
531 | lsh | ||
532 | : OP_LSH '#' number { | ||
533 | bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); } | ||
534 | | OP_LSH 'x' { | ||
535 | bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); } | ||
536 | | OP_LSH '%' 'x' { | ||
537 | bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); } | ||
538 | ; | ||
539 | |||
540 | rsh | ||
541 | : OP_RSH '#' number { | ||
542 | bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); } | ||
543 | | OP_RSH 'x' { | ||
544 | bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); } | ||
545 | | OP_RSH '%' 'x' { | ||
546 | bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); } | ||
547 | ; | ||
548 | |||
549 | ret | ||
550 | : OP_RET 'a' { | ||
551 | bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); } | ||
552 | | OP_RET '%' 'a' { | ||
553 | bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); } | ||
554 | | OP_RET 'x' { | ||
555 | bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); } | ||
556 | | OP_RET '%' 'x' { | ||
557 | bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); } | ||
558 | | OP_RET '#' number { | ||
559 | bpf_set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); } | ||
560 | ; | ||
561 | |||
562 | tax | ||
563 | : OP_TAX { | ||
564 | bpf_set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); } | ||
565 | ; | ||
566 | |||
567 | txa | ||
568 | : OP_TXA { | ||
569 | bpf_set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); } | ||
570 | ; | ||
571 | |||
572 | %% | ||
573 | |||
574 | static int curr_instr = 0; | ||
575 | static struct sock_filter out[BPF_MAXINSNS]; | ||
576 | static char **labels, **labels_jt, **labels_jf, **labels_k; | ||
577 | |||
578 | static void bpf_assert_max(void) | ||
579 | { | ||
580 | if (curr_instr >= BPF_MAXINSNS) { | ||
581 | fprintf(stderr, "only max %u insns allowed!\n", BPF_MAXINSNS); | ||
582 | exit(0); | ||
583 | } | ||
584 | } | ||
585 | |||
586 | static void bpf_set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf, | ||
587 | uint32_t k) | ||
588 | { | ||
589 | bpf_assert_max(); | ||
590 | out[curr_instr].code = code; | ||
591 | out[curr_instr].jt = jt; | ||
592 | out[curr_instr].jf = jf; | ||
593 | out[curr_instr].k = k; | ||
594 | curr_instr++; | ||
595 | } | ||
596 | |||
597 | static void bpf_set_curr_label(char *label) | ||
598 | { | ||
599 | bpf_assert_max(); | ||
600 | labels[curr_instr] = label; | ||
601 | } | ||
602 | |||
603 | static void bpf_set_jmp_label(char *label, enum jmp_type type) | ||
604 | { | ||
605 | bpf_assert_max(); | ||
606 | switch (type) { | ||
607 | case JTL: | ||
608 | labels_jt[curr_instr] = label; | ||
609 | break; | ||
610 | case JFL: | ||
611 | labels_jf[curr_instr] = label; | ||
612 | break; | ||
613 | case JKL: | ||
614 | labels_k[curr_instr] = label; | ||
615 | break; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | static int bpf_find_insns_offset(const char *label) | ||
620 | { | ||
621 | int i, max = curr_instr, ret = -ENOENT; | ||
622 | |||
623 | for (i = 0; i < max; i++) { | ||
624 | if (labels[i] && !strcmp(label, labels[i])) { | ||
625 | ret = i; | ||
626 | break; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | if (ret == -ENOENT) { | ||
631 | fprintf(stderr, "no such label \'%s\'!\n", label); | ||
632 | exit(0); | ||
633 | } | ||
634 | |||
635 | return ret; | ||
636 | } | ||
637 | |||
638 | static void bpf_stage_1_insert_insns(void) | ||
639 | { | ||
640 | yyparse(); | ||
641 | } | ||
642 | |||
643 | static void bpf_reduce_k_jumps(void) | ||
644 | { | ||
645 | int i; | ||
646 | |||
647 | for (i = 0; i < curr_instr; i++) { | ||
648 | if (labels_k[i]) { | ||
649 | int off = bpf_find_insns_offset(labels_k[i]); | ||
650 | out[i].k = (uint32_t) (off - i - 1); | ||
651 | } | ||
652 | } | ||
653 | } | ||
654 | |||
655 | static void bpf_reduce_jt_jumps(void) | ||
656 | { | ||
657 | int i; | ||
658 | |||
659 | for (i = 0; i < curr_instr; i++) { | ||
660 | if (labels_jt[i]) { | ||
661 | int off = bpf_find_insns_offset(labels_jt[i]); | ||
662 | out[i].jt = (uint8_t) (off - i -1); | ||
663 | } | ||
664 | } | ||
665 | } | ||
666 | |||
667 | static void bpf_reduce_jf_jumps(void) | ||
668 | { | ||
669 | int i; | ||
670 | |||
671 | for (i = 0; i < curr_instr; i++) { | ||
672 | if (labels_jf[i]) { | ||
673 | int off = bpf_find_insns_offset(labels_jf[i]); | ||
674 | out[i].jf = (uint8_t) (off - i - 1); | ||
675 | } | ||
676 | } | ||
677 | } | ||
678 | |||
679 | static void bpf_stage_2_reduce_labels(void) | ||
680 | { | ||
681 | bpf_reduce_k_jumps(); | ||
682 | bpf_reduce_jt_jumps(); | ||
683 | bpf_reduce_jf_jumps(); | ||
684 | } | ||
685 | |||
686 | static void bpf_pretty_print_c(void) | ||
687 | { | ||
688 | int i; | ||
689 | |||
690 | for (i = 0; i < curr_instr; i++) | ||
691 | printf("{ %#04x, %2u, %2u, %#010x },\n", out[i].code, | ||
692 | out[i].jt, out[i].jf, out[i].k); | ||
693 | } | ||
694 | |||
695 | static void bpf_pretty_print(void) | ||
696 | { | ||
697 | int i; | ||
698 | |||
699 | printf("%u,", curr_instr); | ||
700 | for (i = 0; i < curr_instr; i++) | ||
701 | printf("%u %u %u %u,", out[i].code, | ||
702 | out[i].jt, out[i].jf, out[i].k); | ||
703 | printf("\n"); | ||
704 | } | ||
705 | |||
706 | static void bpf_init(void) | ||
707 | { | ||
708 | memset(out, 0, sizeof(out)); | ||
709 | |||
710 | labels = calloc(BPF_MAXINSNS, sizeof(*labels)); | ||
711 | assert(labels); | ||
712 | labels_jt = calloc(BPF_MAXINSNS, sizeof(*labels_jt)); | ||
713 | assert(labels_jt); | ||
714 | labels_jf = calloc(BPF_MAXINSNS, sizeof(*labels_jf)); | ||
715 | assert(labels_jf); | ||
716 | labels_k = calloc(BPF_MAXINSNS, sizeof(*labels_k)); | ||
717 | assert(labels_k); | ||
718 | } | ||
719 | |||
720 | static void bpf_destroy_labels(void) | ||
721 | { | ||
722 | int i; | ||
723 | |||
724 | for (i = 0; i < curr_instr; i++) { | ||
725 | free(labels_jf[i]); | ||
726 | free(labels_jt[i]); | ||
727 | free(labels_k[i]); | ||
728 | free(labels[i]); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | static void bpf_destroy(void) | ||
733 | { | ||
734 | bpf_destroy_labels(); | ||
735 | free(labels_jt); | ||
736 | free(labels_jf); | ||
737 | free(labels_k); | ||
738 | free(labels); | ||
739 | } | ||
740 | |||
741 | void bpf_asm_compile(FILE *fp, bool cstyle) | ||
742 | { | ||
743 | yyin = fp; | ||
744 | |||
745 | bpf_init(); | ||
746 | bpf_stage_1_insert_insns(); | ||
747 | bpf_stage_2_reduce_labels(); | ||
748 | bpf_destroy(); | ||
749 | |||
750 | if (cstyle) | ||
751 | bpf_pretty_print_c(); | ||
752 | else | ||
753 | bpf_pretty_print(); | ||
754 | |||
755 | if (fp != stdin) | ||
756 | fclose(yyin); | ||
757 | } | ||
758 | |||
759 | void yyerror(const char *str) | ||
760 | { | ||
761 | exit(1); | ||
762 | } | ||
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 652af0b66a62..25526d6eae59 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -1045,6 +1045,9 @@ static void write_svg_file(struct timechart *tchart, const char *filename) | |||
1045 | thresh /= 10; | 1045 | thresh /= 10; |
1046 | } while (!process_filter && thresh && count < tchart->proc_num); | 1046 | } while (!process_filter && thresh && count < tchart->proc_num); |
1047 | 1047 | ||
1048 | if (!tchart->proc_num) | ||
1049 | count = 0; | ||
1050 | |||
1048 | open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); | 1051 | open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); |
1049 | 1052 | ||
1050 | svg_time_grid(); | 1053 | svg_time_grid(); |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index d604e50fc167..c48d44958172 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -600,5 +600,5 @@ perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | |||
600 | # Otherwise we install plugins into the global $(libdir). | 600 | # Otherwise we install plugins into the global $(libdir). |
601 | ifdef DESTDIR | 601 | ifdef DESTDIR |
602 | plugindir=$(libdir)/traceevent/plugins | 602 | plugindir=$(libdir)/traceevent/plugins |
603 | plugindir_SQ= $(subst ','\'',$(prefix)/$(plugindir)) | 603 | plugindir_SQ= $(subst ','\'',$(plugindir)) |
604 | endif | 604 | endif |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 3c2f213e979d..7daa806d9050 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -132,6 +132,13 @@ | |||
132 | #define CPUINFO_PROC "CPU" | 132 | #define CPUINFO_PROC "CPU" |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | #ifdef __xtensa__ | ||
136 | #define mb() asm volatile("memw" ::: "memory") | ||
137 | #define wmb() asm volatile("memw" ::: "memory") | ||
138 | #define rmb() asm volatile("" ::: "memory") | ||
139 | #define CPUINFO_PROC "core ID" | ||
140 | #endif | ||
141 | |||
135 | #define barrier() asm volatile ("" ::: "memory") | 142 | #define barrier() asm volatile ("" ::: "memory") |
136 | 143 | ||
137 | #ifndef cpu_relax | 144 | #ifndef cpu_relax |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 40bd2c04df8a..59ef2802fcf6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -1003,9 +1003,12 @@ void perf_evlist__close(struct perf_evlist *evlist) | |||
1003 | struct perf_evsel *evsel; | 1003 | struct perf_evsel *evsel; |
1004 | int ncpus = cpu_map__nr(evlist->cpus); | 1004 | int ncpus = cpu_map__nr(evlist->cpus); |
1005 | int nthreads = thread_map__nr(evlist->threads); | 1005 | int nthreads = thread_map__nr(evlist->threads); |
1006 | int n; | ||
1006 | 1007 | ||
1007 | evlist__for_each_reverse(evlist, evsel) | 1008 | evlist__for_each_reverse(evlist, evsel) { |
1008 | perf_evsel__close(evsel, ncpus, nthreads); | 1009 | n = evsel->cpus ? evsel->cpus->nr : ncpus; |
1010 | perf_evsel__close(evsel, n, nthreads); | ||
1011 | } | ||
1009 | } | 1012 | } |
1010 | 1013 | ||
1011 | int perf_evlist__open(struct perf_evlist *evlist) | 1014 | int perf_evlist__open(struct perf_evlist *evlist) |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 22e18a26b7e6..55407c594b87 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1081,7 +1081,6 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
1081 | 1081 | ||
1082 | perf_evsel__close_fd(evsel, ncpus, nthreads); | 1082 | perf_evsel__close_fd(evsel, ncpus, nthreads); |
1083 | perf_evsel__free_fd(evsel); | 1083 | perf_evsel__free_fd(evsel); |
1084 | evsel->fd = NULL; | ||
1085 | } | 1084 | } |
1086 | 1085 | ||
1087 | static struct { | 1086 | static struct { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index bb3e0ede6183..893f8e2df928 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -930,7 +930,7 @@ static int write_topo_node(int fd, int node) | |||
930 | /* skip over invalid lines */ | 930 | /* skip over invalid lines */ |
931 | if (!strchr(buf, ':')) | 931 | if (!strchr(buf, ':')) |
932 | continue; | 932 | continue; |
933 | if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2) | 933 | if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2) |
934 | goto done; | 934 | goto done; |
935 | if (!strcmp(field, "MemTotal:")) | 935 | if (!strcmp(field, "MemTotal:")) |
936 | mem_total = mem; | 936 | mem_total = mem; |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 9b9bd719aa19..3b97513f0e77 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -69,7 +69,7 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
69 | map->ino = ino; | 69 | map->ino = ino; |
70 | map->ino_generation = ino_gen; | 70 | map->ino_generation = ino_gen; |
71 | 71 | ||
72 | if (anon) { | 72 | if ((anon || no_dso) && type == MAP__FUNCTION) { |
73 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); | 73 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); |
74 | filename = newfilename; | 74 | filename = newfilename; |
75 | } | 75 | } |
@@ -93,7 +93,7 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
93 | * functions still return NULL, and we avoid the | 93 | * functions still return NULL, and we avoid the |
94 | * unnecessary map__load warning. | 94 | * unnecessary map__load warning. |
95 | */ | 95 | */ |
96 | if (no_dso) | 96 | if (type != MAP__FUNCTION) |
97 | dso__set_loaded(dso, map->type); | 97 | dso__set_loaded(dso, map->type); |
98 | } | 98 | } |
99 | } | 99 | } |
@@ -386,7 +386,8 @@ struct symbol *map_groups__find_symbol(struct map_groups *mg, | |||
386 | { | 386 | { |
387 | struct map *map = map_groups__find(mg, type, addr); | 387 | struct map *map = map_groups__find(mg, type, addr); |
388 | 388 | ||
389 | if (map != NULL) { | 389 | /* Ensure map is loaded before using map->map_ip */ |
390 | if (map != NULL && map__load(map, filter) >= 0) { | ||
390 | if (mapp != NULL) | 391 | if (mapp != NULL) |
391 | *mapp = map; | 392 | *mapp = map; |
392 | return map__find_symbol(map, map->map_ip(map, addr), filter); | 393 | return map__find_symbol(map, map->map_ip(map, addr), filter); |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a7f1b6a91fdd..d248fca6d7ed 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -635,7 +635,7 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
635 | struct perf_event_attr attr; | 635 | struct perf_event_attr attr; |
636 | struct perf_pmu *pmu; | 636 | struct perf_pmu *pmu; |
637 | struct perf_evsel *evsel; | 637 | struct perf_evsel *evsel; |
638 | char *unit; | 638 | const char *unit; |
639 | double scale; | 639 | double scale; |
640 | 640 | ||
641 | pmu = perf_pmu__find(name); | 641 | pmu = perf_pmu__find(name); |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index d9cab4d27192..b752ecb40d86 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -105,7 +105,7 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * | |||
105 | char scale[128]; | 105 | char scale[128]; |
106 | int fd, ret = -1; | 106 | int fd, ret = -1; |
107 | char path[PATH_MAX]; | 107 | char path[PATH_MAX]; |
108 | char *lc; | 108 | const char *lc; |
109 | 109 | ||
110 | snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); | 110 | snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); |
111 | 111 | ||
@@ -609,7 +609,7 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, | |||
609 | 609 | ||
610 | 610 | ||
611 | static int check_unit_scale(struct perf_pmu_alias *alias, | 611 | static int check_unit_scale(struct perf_pmu_alias *alias, |
612 | char **unit, double *scale) | 612 | const char **unit, double *scale) |
613 | { | 613 | { |
614 | /* | 614 | /* |
615 | * Only one term in event definition can | 615 | * Only one term in event definition can |
@@ -634,14 +634,18 @@ static int check_unit_scale(struct perf_pmu_alias *alias, | |||
634 | * defined for the alias | 634 | * defined for the alias |
635 | */ | 635 | */ |
636 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | 636 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
637 | char **unit, double *scale) | 637 | const char **unit, double *scale) |
638 | { | 638 | { |
639 | struct parse_events_term *term, *h; | 639 | struct parse_events_term *term, *h; |
640 | struct perf_pmu_alias *alias; | 640 | struct perf_pmu_alias *alias; |
641 | int ret; | 641 | int ret; |
642 | 642 | ||
643 | /* | ||
644 | * Mark unit and scale as not set | ||
645 | * (different from default values, see below) | ||
646 | */ | ||
643 | *unit = NULL; | 647 | *unit = NULL; |
644 | *scale = 0; | 648 | *scale = 0.0; |
645 | 649 | ||
646 | list_for_each_entry_safe(term, h, head_terms, list) { | 650 | list_for_each_entry_safe(term, h, head_terms, list) { |
647 | alias = pmu_find_alias(pmu, term); | 651 | alias = pmu_find_alias(pmu, term); |
@@ -658,6 +662,18 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | |||
658 | list_del(&term->list); | 662 | list_del(&term->list); |
659 | free(term); | 663 | free(term); |
660 | } | 664 | } |
665 | |||
666 | /* | ||
667 | * if no unit or scale foundin aliases, then | ||
668 | * set defaults as for evsel | ||
669 | * unit cannot left to NULL | ||
670 | */ | ||
671 | if (*unit == NULL) | ||
672 | *unit = ""; | ||
673 | |||
674 | if (*scale == 0.0) | ||
675 | *scale = 1.0; | ||
676 | |||
661 | return 0; | 677 | return 0; |
662 | } | 678 | } |
663 | 679 | ||
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 9183380e2038..8b64125a9281 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -29,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats, | |||
29 | struct perf_event_attr *attr, | 29 | struct perf_event_attr *attr, |
30 | struct list_head *head_terms); | 30 | struct list_head *head_terms); |
31 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | 31 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
32 | char **unit, double *scale); | 32 | const char **unit, double *scale); |
33 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | 33 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, |
34 | struct list_head *head_terms); | 34 | struct list_head *head_terms); |
35 | int perf_pmu_wrap(void); | 35 | int perf_pmu_wrap(void); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7acc03e8f3b2..0b39a48e5110 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1573,7 +1573,7 @@ next: | |||
1573 | int perf_session__cpu_bitmap(struct perf_session *session, | 1573 | int perf_session__cpu_bitmap(struct perf_session *session, |
1574 | const char *cpu_list, unsigned long *cpu_bitmap) | 1574 | const char *cpu_list, unsigned long *cpu_bitmap) |
1575 | { | 1575 | { |
1576 | int i; | 1576 | int i, err = -1; |
1577 | struct cpu_map *map; | 1577 | struct cpu_map *map; |
1578 | 1578 | ||
1579 | for (i = 0; i < PERF_TYPE_MAX; ++i) { | 1579 | for (i = 0; i < PERF_TYPE_MAX; ++i) { |
@@ -1602,13 +1602,17 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
1602 | if (cpu >= MAX_NR_CPUS) { | 1602 | if (cpu >= MAX_NR_CPUS) { |
1603 | pr_err("Requested CPU %d too large. " | 1603 | pr_err("Requested CPU %d too large. " |
1604 | "Consider raising MAX_NR_CPUS\n", cpu); | 1604 | "Consider raising MAX_NR_CPUS\n", cpu); |
1605 | return -1; | 1605 | goto out_delete_map; |
1606 | } | 1606 | } |
1607 | 1607 | ||
1608 | set_bit(cpu, cpu_bitmap); | 1608 | set_bit(cpu, cpu_bitmap); |
1609 | } | 1609 | } |
1610 | 1610 | ||
1611 | return 0; | 1611 | err = 0; |
1612 | |||
1613 | out_delete_map: | ||
1614 | cpu_map__delete(map); | ||
1615 | return err; | ||
1612 | } | 1616 | } |
1613 | 1617 | ||
1614 | void perf_session__fprintf_info(struct perf_session *session, FILE *fp, | 1618 | void perf_session__fprintf_info(struct perf_session *session, FILE *fp, |
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile index bafeb8d662a3..d9186a2fdf06 100644 --- a/tools/power/acpi/Makefile +++ b/tools/power/acpi/Makefile | |||
@@ -1,18 +1,143 @@ | |||
1 | PROG= acpidump | 1 | # tools/power/acpi/Makefile - ACPI tool Makefile |
2 | SRCS= acpidump.c | 2 | # |
3 | # Copyright (c) 2013, Intel Corporation | ||
4 | # Author: Lv Zheng <lv.zheng@intel.com> | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or | ||
7 | # modify it under the terms of the GNU General Public License | ||
8 | # as published by the Free Software Foundation; version 2 | ||
9 | # of the License. | ||
10 | |||
11 | OUTPUT=./ | ||
12 | ifeq ("$(origin O)", "command line") | ||
13 | OUTPUT := $(O)/ | ||
14 | endif | ||
15 | |||
16 | ifneq ($(OUTPUT),) | ||
17 | # check that the output directory actually exists | ||
18 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | ||
19 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | ||
20 | endif | ||
21 | |||
22 | # --- CONFIGURATION BEGIN --- | ||
23 | |||
24 | # Set the following to `true' to make a unstripped, unoptimized | ||
25 | # binary. Leave this set to `false' for production use. | ||
26 | DEBUG ?= true | ||
27 | |||
28 | # make the build silent. Set this to something else to make it noisy again. | ||
29 | V ?= false | ||
30 | |||
31 | # Prefix to the directories we're installing to | ||
32 | DESTDIR ?= | ||
33 | |||
34 | # --- CONFIGURATION END --- | ||
35 | |||
36 | # Directory definitions. These are default and most probably | ||
37 | # do not need to be changed. Please note that DESTDIR is | ||
38 | # added in front of any of them | ||
39 | |||
40 | bindir ?= /usr/bin | ||
41 | sbindir ?= /usr/sbin | ||
42 | mandir ?= /usr/man | ||
43 | |||
44 | # Toolchain: what tools do we use, and what options do they need: | ||
45 | |||
46 | INSTALL = /usr/bin/install -c | ||
47 | INSTALL_PROGRAM = ${INSTALL} | ||
48 | INSTALL_DATA = ${INSTALL} -m 644 | ||
49 | INSTALL_SCRIPT = ${INSTALL_PROGRAM} | ||
50 | |||
51 | # If you are running a cross compiler, you may want to set this | ||
52 | # to something more interesting, like "arm-linux-". If you want | ||
53 | # to compile vs uClibc, that can be done here as well. | ||
54 | CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- | ||
55 | CC = $(CROSS)gcc | ||
56 | LD = $(CROSS)gcc | ||
57 | STRIP = $(CROSS)strip | ||
58 | HOSTCC = gcc | ||
59 | |||
60 | # check if compiler option is supported | ||
61 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} | ||
62 | |||
63 | # use '-Os' optimization if available, else use -O2 | ||
64 | OPTIMIZATION := $(call cc-supports,-Os,-O2) | ||
65 | |||
66 | WARNINGS := -Wall | ||
67 | WARNINGS += $(call cc-supports,-Wstrict-prototypes) | ||
68 | WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) | ||
69 | |||
3 | KERNEL_INCLUDE := ../../../include | 70 | KERNEL_INCLUDE := ../../../include |
4 | CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) | 71 | CFLAGS += -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) |
72 | CFLAGS += $(WARNINGS) | ||
73 | |||
74 | ifeq ($(strip $(V)),false) | ||
75 | QUIET=@ | ||
76 | ECHO=@echo | ||
77 | else | ||
78 | QUIET= | ||
79 | ECHO=@\# | ||
80 | endif | ||
81 | export QUIET ECHO | ||
82 | |||
83 | # if DEBUG is enabled, then we do not strip or optimize | ||
84 | ifeq ($(strip $(DEBUG)),true) | ||
85 | CFLAGS += -O1 -g -DDEBUG | ||
86 | STRIPCMD = /bin/true -Since_we_are_debugging | ||
87 | else | ||
88 | CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer | ||
89 | STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment | ||
90 | endif | ||
91 | |||
92 | # if DEBUG is enabled, then we do not strip or optimize | ||
93 | ifeq ($(strip $(DEBUG)),true) | ||
94 | CFLAGS += -O1 -g -DDEBUG | ||
95 | STRIPCMD = /bin/true -Since_we_are_debugging | ||
96 | else | ||
97 | CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer | ||
98 | STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment | ||
99 | endif | ||
100 | |||
101 | # --- ACPIDUMP BEGIN --- | ||
102 | |||
103 | vpath %.c \ | ||
104 | tools/acpidump | ||
105 | |||
106 | DUMP_OBJS = \ | ||
107 | acpidump.o | ||
108 | |||
109 | DUMP_OBJS := $(addprefix $(OUTPUT)tools/acpidump/,$(DUMP_OBJS)) | ||
110 | |||
111 | $(OUTPUT)acpidump: $(DUMP_OBJS) | ||
112 | $(ECHO) " LD " $@ | ||
113 | $(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $(DUMP_OBJS) -L$(OUTPUT) -o $@ | ||
114 | $(QUIET) $(STRIPCMD) $@ | ||
115 | |||
116 | $(OUTPUT)tools/acpidump/%.o: %.c | ||
117 | $(ECHO) " CC " $@ | ||
118 | $(QUIET) $(CC) -c $(CFLAGS) -o $@ $< | ||
119 | |||
120 | # --- ACPIDUMP END --- | ||
121 | |||
122 | all: $(OUTPUT)acpidump | ||
123 | echo $(OUTPUT) | ||
124 | |||
125 | clean: | ||
126 | -find $(OUTPUT) \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ | ||
127 | | xargs rm -f | ||
128 | -rm -f $(OUTPUT)acpidump | ||
5 | 129 | ||
6 | all: acpidump | 130 | install-tools: |
7 | $(PROG) : $(SRCS) | 131 | $(INSTALL) -d $(DESTDIR)${bindir} |
8 | $(CC) $(CFLAGS) $(SRCS) -o $(PROG) | 132 | $(INSTALL_PROGRAM) $(OUTPUT)acpidump $(DESTDIR)${sbindir} |
9 | 133 | ||
10 | CLEANFILES= $(PROG) | 134 | install-man: |
135 | $(INSTALL_DATA) -D man/acpidump.8 $(DESTDIR)${mandir}/man8/acpidump.8 | ||
11 | 136 | ||
12 | clean : | 137 | install: all install-tools install-man |
13 | rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ | ||
14 | 138 | ||
15 | install : | 139 | uninstall: |
16 | install acpidump /usr/sbin/acpidump | 140 | - rm -f $(DESTDIR)${sbindir}/acpidump |
17 | install acpidump.8 /usr/share/man/man8 | 141 | - rm -f $(DESTDIR)${mandir}/man8/acpidump.8 |
18 | 142 | ||
143 | .PHONY: all utils install-tools install-man install uninstall clean | ||
diff --git a/tools/power/acpi/acpidump.8 b/tools/power/acpi/man/acpidump.8 index adfa99166e5e..adfa99166e5e 100644 --- a/tools/power/acpi/acpidump.8 +++ b/tools/power/acpi/man/acpidump.8 | |||
diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/tools/acpidump/acpidump.c index a84553a0e0df..a84553a0e0df 100644 --- a/tools/power/acpi/acpidump.c +++ b/tools/power/acpi/tools/acpidump/acpidump.c | |||
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c index 66cace601e57..0f10b81e3322 100644 --- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | |||
@@ -25,12 +25,9 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | 28 | #include <linux/acpi.h> | |
29 | #include <asm/io.h> | 29 | #include <asm/io.h> |
30 | 30 | ||
31 | #include <acpi/acpi_bus.h> | ||
32 | #include <acpi/acpi_drivers.h> | ||
33 | |||
34 | static int pm_tmr_ioport = 0; | 31 | static int pm_tmr_ioport = 0; |
35 | 32 | ||
36 | /*helper function to safely read acpi pm timesource*/ | 33 | /*helper function to safely read acpi pm timesource*/ |
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index dd1539eb8c63..a416de80c55e 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c | |||
@@ -257,7 +257,7 @@ int cmd_freq_set(int argc, char **argv) | |||
257 | print_unknown_arg(); | 257 | print_unknown_arg(); |
258 | return -EINVAL; | 258 | return -EINVAL; |
259 | } | 259 | } |
260 | if ((sscanf(optarg, "%s", gov)) != 1) { | 260 | if ((sscanf(optarg, "%19s", gov)) != 1) { |
261 | print_unknown_arg(); | 261 | print_unknown_arg(); |
262 | return -EINVAL; | 262 | return -EINVAL; |
263 | } | 263 | } |
diff --git a/tools/power/x86/turbostat/.gitignore b/tools/power/x86/turbostat/.gitignore new file mode 100644 index 000000000000..7521370d3568 --- /dev/null +++ b/tools/power/x86/turbostat/.gitignore | |||
@@ -0,0 +1 @@ | |||
turbostat | |||
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile index f09641da40d4..d1b3a361e526 100644 --- a/tools/power/x86/turbostat/Makefile +++ b/tools/power/x86/turbostat/Makefile | |||
@@ -5,7 +5,7 @@ DESTDIR := | |||
5 | 5 | ||
6 | turbostat : turbostat.c | 6 | turbostat : turbostat.c |
7 | CFLAGS += -Wall | 7 | CFLAGS += -Wall |
8 | CFLAGS += -I../../../../arch/x86/include/uapi/ | 8 | CFLAGS += -DMSRHEADER='"../../../../arch/x86/include/uapi/asm/msr-index.h"' |
9 | 9 | ||
10 | %: %.c | 10 | %: %.c |
11 | @mkdir -p $(BUILD_OUTPUT) | 11 | @mkdir -p $(BUILD_OUTPUT) |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 9d77f13c2d25..77eb130168da 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -20,8 +20,10 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #define _GNU_SOURCE | 22 | #define _GNU_SOURCE |
23 | #include <asm/msr.h> | 23 | #include MSRHEADER |
24 | #include <stdarg.h> | ||
24 | #include <stdio.h> | 25 | #include <stdio.h> |
26 | #include <err.h> | ||
25 | #include <unistd.h> | 27 | #include <unistd.h> |
26 | #include <sys/types.h> | 28 | #include <sys/types.h> |
27 | #include <sys/wait.h> | 29 | #include <sys/wait.h> |
@@ -35,13 +37,16 @@ | |||
35 | #include <string.h> | 37 | #include <string.h> |
36 | #include <ctype.h> | 38 | #include <ctype.h> |
37 | #include <sched.h> | 39 | #include <sched.h> |
40 | #include <cpuid.h> | ||
38 | 41 | ||
39 | char *proc_stat = "/proc/stat"; | 42 | char *proc_stat = "/proc/stat"; |
40 | unsigned int interval_sec = 5; /* set with -i interval_sec */ | 43 | unsigned int interval_sec = 5; /* set with -i interval_sec */ |
41 | unsigned int verbose; /* set with -v */ | 44 | unsigned int verbose; /* set with -v */ |
42 | unsigned int rapl_verbose; /* set with -R */ | 45 | unsigned int rapl_verbose; /* set with -R */ |
46 | unsigned int rapl_joules; /* set with -J */ | ||
43 | unsigned int thermal_verbose; /* set with -T */ | 47 | unsigned int thermal_verbose; /* set with -T */ |
44 | unsigned int summary_only; /* set with -s */ | 48 | unsigned int summary_only; /* set with -S */ |
49 | unsigned int dump_only; /* set with -s */ | ||
45 | unsigned int skip_c0; | 50 | unsigned int skip_c0; |
46 | unsigned int skip_c1; | 51 | unsigned int skip_c1; |
47 | unsigned int do_nhm_cstates; | 52 | unsigned int do_nhm_cstates; |
@@ -77,14 +82,32 @@ unsigned int tcc_activation_temp_override; | |||
77 | double rapl_power_units, rapl_energy_units, rapl_time_units; | 82 | double rapl_power_units, rapl_energy_units, rapl_time_units; |
78 | double rapl_joule_counter_range; | 83 | double rapl_joule_counter_range; |
79 | 84 | ||
80 | #define RAPL_PKG (1 << 0) | 85 | #define RAPL_PKG (1 << 0) |
81 | #define RAPL_CORES (1 << 1) | 86 | /* 0x610 MSR_PKG_POWER_LIMIT */ |
82 | #define RAPL_GFX (1 << 2) | 87 | /* 0x611 MSR_PKG_ENERGY_STATUS */ |
83 | #define RAPL_DRAM (1 << 3) | 88 | #define RAPL_PKG_PERF_STATUS (1 << 1) |
84 | #define RAPL_PKG_PERF_STATUS (1 << 4) | 89 | /* 0x613 MSR_PKG_PERF_STATUS */ |
85 | #define RAPL_DRAM_PERF_STATUS (1 << 5) | 90 | #define RAPL_PKG_POWER_INFO (1 << 2) |
86 | #define RAPL_PKG_POWER_INFO (1 << 6) | 91 | /* 0x614 MSR_PKG_POWER_INFO */ |
87 | #define RAPL_CORE_POLICY (1 << 7) | 92 | |
93 | #define RAPL_DRAM (1 << 3) | ||
94 | /* 0x618 MSR_DRAM_POWER_LIMIT */ | ||
95 | /* 0x619 MSR_DRAM_ENERGY_STATUS */ | ||
96 | /* 0x61c MSR_DRAM_POWER_INFO */ | ||
97 | #define RAPL_DRAM_PERF_STATUS (1 << 4) | ||
98 | /* 0x61b MSR_DRAM_PERF_STATUS */ | ||
99 | |||
100 | #define RAPL_CORES (1 << 5) | ||
101 | /* 0x638 MSR_PP0_POWER_LIMIT */ | ||
102 | /* 0x639 MSR_PP0_ENERGY_STATUS */ | ||
103 | #define RAPL_CORE_POLICY (1 << 6) | ||
104 | /* 0x63a MSR_PP0_POLICY */ | ||
105 | |||
106 | |||
107 | #define RAPL_GFX (1 << 7) | ||
108 | /* 0x640 MSR_PP1_POWER_LIMIT */ | ||
109 | /* 0x641 MSR_PP1_ENERGY_STATUS */ | ||
110 | /* 0x642 MSR_PP1_POLICY */ | ||
88 | #define TJMAX_DEFAULT 100 | 111 | #define TJMAX_DEFAULT 100 |
89 | 112 | ||
90 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) | 113 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
@@ -234,7 +257,7 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) | |||
234 | close(fd); | 257 | close(fd); |
235 | 258 | ||
236 | if (retval != sizeof *msr) { | 259 | if (retval != sizeof *msr) { |
237 | fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset); | 260 | fprintf(stderr, "%s offset 0x%llx read failed\n", pathname, (unsigned long long)offset); |
238 | return -1; | 261 | return -1; |
239 | } | 262 | } |
240 | 263 | ||
@@ -296,70 +319,92 @@ void print_header(void) | |||
296 | outp += sprintf(outp, " %%pc10"); | 319 | outp += sprintf(outp, " %%pc10"); |
297 | } | 320 | } |
298 | 321 | ||
299 | if (do_rapl & RAPL_PKG) | 322 | if (do_rapl && !rapl_joules) { |
300 | outp += sprintf(outp, " Pkg_W"); | 323 | if (do_rapl & RAPL_PKG) |
301 | if (do_rapl & RAPL_CORES) | 324 | outp += sprintf(outp, " Pkg_W"); |
302 | outp += sprintf(outp, " Cor_W"); | 325 | if (do_rapl & RAPL_CORES) |
303 | if (do_rapl & RAPL_GFX) | 326 | outp += sprintf(outp, " Cor_W"); |
304 | outp += sprintf(outp, " GFX_W"); | 327 | if (do_rapl & RAPL_GFX) |
305 | if (do_rapl & RAPL_DRAM) | 328 | outp += sprintf(outp, " GFX_W"); |
306 | outp += sprintf(outp, " RAM_W"); | 329 | if (do_rapl & RAPL_DRAM) |
307 | if (do_rapl & RAPL_PKG_PERF_STATUS) | 330 | outp += sprintf(outp, " RAM_W"); |
308 | outp += sprintf(outp, " PKG_%%"); | 331 | if (do_rapl & RAPL_PKG_PERF_STATUS) |
309 | if (do_rapl & RAPL_DRAM_PERF_STATUS) | 332 | outp += sprintf(outp, " PKG_%%"); |
310 | outp += sprintf(outp, " RAM_%%"); | 333 | if (do_rapl & RAPL_DRAM_PERF_STATUS) |
334 | outp += sprintf(outp, " RAM_%%"); | ||
335 | } else { | ||
336 | if (do_rapl & RAPL_PKG) | ||
337 | outp += sprintf(outp, " Pkg_J"); | ||
338 | if (do_rapl & RAPL_CORES) | ||
339 | outp += sprintf(outp, " Cor_J"); | ||
340 | if (do_rapl & RAPL_GFX) | ||
341 | outp += sprintf(outp, " GFX_J"); | ||
342 | if (do_rapl & RAPL_DRAM) | ||
343 | outp += sprintf(outp, " RAM_W"); | ||
344 | if (do_rapl & RAPL_PKG_PERF_STATUS) | ||
345 | outp += sprintf(outp, " PKG_%%"); | ||
346 | if (do_rapl & RAPL_DRAM_PERF_STATUS) | ||
347 | outp += sprintf(outp, " RAM_%%"); | ||
348 | outp += sprintf(outp, " time"); | ||
311 | 349 | ||
350 | } | ||
312 | outp += sprintf(outp, "\n"); | 351 | outp += sprintf(outp, "\n"); |
313 | } | 352 | } |
314 | 353 | ||
315 | int dump_counters(struct thread_data *t, struct core_data *c, | 354 | int dump_counters(struct thread_data *t, struct core_data *c, |
316 | struct pkg_data *p) | 355 | struct pkg_data *p) |
317 | { | 356 | { |
318 | fprintf(stderr, "t %p, c %p, p %p\n", t, c, p); | 357 | outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p); |
319 | 358 | ||
320 | if (t) { | 359 | if (t) { |
321 | fprintf(stderr, "CPU: %d flags 0x%x\n", t->cpu_id, t->flags); | 360 | outp += sprintf(outp, "CPU: %d flags 0x%x\n", |
322 | fprintf(stderr, "TSC: %016llX\n", t->tsc); | 361 | t->cpu_id, t->flags); |
323 | fprintf(stderr, "aperf: %016llX\n", t->aperf); | 362 | outp += sprintf(outp, "TSC: %016llX\n", t->tsc); |
324 | fprintf(stderr, "mperf: %016llX\n", t->mperf); | 363 | outp += sprintf(outp, "aperf: %016llX\n", t->aperf); |
325 | fprintf(stderr, "c1: %016llX\n", t->c1); | 364 | outp += sprintf(outp, "mperf: %016llX\n", t->mperf); |
326 | fprintf(stderr, "msr0x%x: %08llX\n", | 365 | outp += sprintf(outp, "c1: %016llX\n", t->c1); |
366 | outp += sprintf(outp, "msr0x%x: %08llX\n", | ||
327 | extra_delta_offset32, t->extra_delta32); | 367 | extra_delta_offset32, t->extra_delta32); |
328 | fprintf(stderr, "msr0x%x: %016llX\n", | 368 | outp += sprintf(outp, "msr0x%x: %016llX\n", |
329 | extra_delta_offset64, t->extra_delta64); | 369 | extra_delta_offset64, t->extra_delta64); |
330 | fprintf(stderr, "msr0x%x: %08llX\n", | 370 | outp += sprintf(outp, "msr0x%x: %08llX\n", |
331 | extra_msr_offset32, t->extra_msr32); | 371 | extra_msr_offset32, t->extra_msr32); |
332 | fprintf(stderr, "msr0x%x: %016llX\n", | 372 | outp += sprintf(outp, "msr0x%x: %016llX\n", |
333 | extra_msr_offset64, t->extra_msr64); | 373 | extra_msr_offset64, t->extra_msr64); |
334 | if (do_smi) | 374 | if (do_smi) |
335 | fprintf(stderr, "SMI: %08X\n", t->smi_count); | 375 | outp += sprintf(outp, "SMI: %08X\n", t->smi_count); |
336 | } | 376 | } |
337 | 377 | ||
338 | if (c) { | 378 | if (c) { |
339 | fprintf(stderr, "core: %d\n", c->core_id); | 379 | outp += sprintf(outp, "core: %d\n", c->core_id); |
340 | fprintf(stderr, "c3: %016llX\n", c->c3); | 380 | outp += sprintf(outp, "c3: %016llX\n", c->c3); |
341 | fprintf(stderr, "c6: %016llX\n", c->c6); | 381 | outp += sprintf(outp, "c6: %016llX\n", c->c6); |
342 | fprintf(stderr, "c7: %016llX\n", c->c7); | 382 | outp += sprintf(outp, "c7: %016llX\n", c->c7); |
343 | fprintf(stderr, "DTS: %dC\n", c->core_temp_c); | 383 | outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c); |
344 | } | 384 | } |
345 | 385 | ||
346 | if (p) { | 386 | if (p) { |
347 | fprintf(stderr, "package: %d\n", p->package_id); | 387 | outp += sprintf(outp, "package: %d\n", p->package_id); |
348 | fprintf(stderr, "pc2: %016llX\n", p->pc2); | 388 | outp += sprintf(outp, "pc2: %016llX\n", p->pc2); |
349 | fprintf(stderr, "pc3: %016llX\n", p->pc3); | 389 | outp += sprintf(outp, "pc3: %016llX\n", p->pc3); |
350 | fprintf(stderr, "pc6: %016llX\n", p->pc6); | 390 | outp += sprintf(outp, "pc6: %016llX\n", p->pc6); |
351 | fprintf(stderr, "pc7: %016llX\n", p->pc7); | 391 | outp += sprintf(outp, "pc7: %016llX\n", p->pc7); |
352 | fprintf(stderr, "pc8: %016llX\n", p->pc8); | 392 | outp += sprintf(outp, "pc8: %016llX\n", p->pc8); |
353 | fprintf(stderr, "pc9: %016llX\n", p->pc9); | 393 | outp += sprintf(outp, "pc9: %016llX\n", p->pc9); |
354 | fprintf(stderr, "pc10: %016llX\n", p->pc10); | 394 | outp += sprintf(outp, "pc10: %016llX\n", p->pc10); |
355 | fprintf(stderr, "Joules PKG: %0X\n", p->energy_pkg); | 395 | outp += sprintf(outp, "Joules PKG: %0X\n", p->energy_pkg); |
356 | fprintf(stderr, "Joules COR: %0X\n", p->energy_cores); | 396 | outp += sprintf(outp, "Joules COR: %0X\n", p->energy_cores); |
357 | fprintf(stderr, "Joules GFX: %0X\n", p->energy_gfx); | 397 | outp += sprintf(outp, "Joules GFX: %0X\n", p->energy_gfx); |
358 | fprintf(stderr, "Joules RAM: %0X\n", p->energy_dram); | 398 | outp += sprintf(outp, "Joules RAM: %0X\n", p->energy_dram); |
359 | fprintf(stderr, "Throttle PKG: %0X\n", p->rapl_pkg_perf_status); | 399 | outp += sprintf(outp, "Throttle PKG: %0X\n", |
360 | fprintf(stderr, "Throttle RAM: %0X\n", p->rapl_dram_perf_status); | 400 | p->rapl_pkg_perf_status); |
361 | fprintf(stderr, "PTM: %dC\n", p->pkg_temp_c); | 401 | outp += sprintf(outp, "Throttle RAM: %0X\n", |
402 | p->rapl_dram_perf_status); | ||
403 | outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c); | ||
362 | } | 404 | } |
405 | |||
406 | outp += sprintf(outp, "\n"); | ||
407 | |||
363 | return 0; | 408 | return 0; |
364 | } | 409 | } |
365 | 410 | ||
@@ -527,19 +572,39 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
527 | fmt6 = " %4.0f**"; | 572 | fmt6 = " %4.0f**"; |
528 | } | 573 | } |
529 | 574 | ||
530 | if (do_rapl & RAPL_PKG) | 575 | if (do_rapl && !rapl_joules) { |
531 | outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float); | 576 | if (do_rapl & RAPL_PKG) |
532 | if (do_rapl & RAPL_CORES) | 577 | outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float); |
533 | outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float); | 578 | if (do_rapl & RAPL_CORES) |
534 | if (do_rapl & RAPL_GFX) | 579 | outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float); |
535 | outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float); | 580 | if (do_rapl & RAPL_GFX) |
536 | if (do_rapl & RAPL_DRAM) | 581 | outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float); |
537 | outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float); | 582 | if (do_rapl & RAPL_DRAM) |
538 | if (do_rapl & RAPL_PKG_PERF_STATUS ) | 583 | outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float); |
539 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); | 584 | if (do_rapl & RAPL_PKG_PERF_STATUS) |
540 | if (do_rapl & RAPL_DRAM_PERF_STATUS ) | 585 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); |
541 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); | 586 | if (do_rapl & RAPL_DRAM_PERF_STATUS) |
587 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); | ||
588 | } else { | ||
589 | if (do_rapl & RAPL_PKG) | ||
590 | outp += sprintf(outp, fmt6, | ||
591 | p->energy_pkg * rapl_energy_units); | ||
592 | if (do_rapl & RAPL_CORES) | ||
593 | outp += sprintf(outp, fmt6, | ||
594 | p->energy_cores * rapl_energy_units); | ||
595 | if (do_rapl & RAPL_GFX) | ||
596 | outp += sprintf(outp, fmt5, | ||
597 | p->energy_gfx * rapl_energy_units); | ||
598 | if (do_rapl & RAPL_DRAM) | ||
599 | outp += sprintf(outp, fmt5, | ||
600 | p->energy_dram * rapl_energy_units); | ||
601 | if (do_rapl & RAPL_PKG_PERF_STATUS) | ||
602 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); | ||
603 | if (do_rapl & RAPL_DRAM_PERF_STATUS) | ||
604 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); | ||
605 | outp += sprintf(outp, fmt5, interval_float); | ||
542 | 606 | ||
607 | } | ||
543 | done: | 608 | done: |
544 | outp += sprintf(outp, "\n"); | 609 | outp += sprintf(outp, "\n"); |
545 | 610 | ||
@@ -622,12 +687,10 @@ delta_thread(struct thread_data *new, struct thread_data *old, | |||
622 | old->tsc = new->tsc - old->tsc; | 687 | old->tsc = new->tsc - old->tsc; |
623 | 688 | ||
624 | /* check for TSC < 1 Mcycles over interval */ | 689 | /* check for TSC < 1 Mcycles over interval */ |
625 | if (old->tsc < (1000 * 1000)) { | 690 | if (old->tsc < (1000 * 1000)) |
626 | fprintf(stderr, "Insanely slow TSC rate, TSC stops in idle?\n"); | 691 | errx(-3, "Insanely slow TSC rate, TSC stops in idle?\n" |
627 | fprintf(stderr, "You can disable all c-states by booting with \"idle=poll\"\n"); | 692 | "You can disable all c-states by booting with \"idle=poll\"\n" |
628 | fprintf(stderr, "or just the deep ones with \"processor.max_cstate=1\"\n"); | 693 | "or just the deep ones with \"processor.max_cstate=1\""); |
629 | exit(-3); | ||
630 | } | ||
631 | 694 | ||
632 | old->c1 = new->c1 - old->c1; | 695 | old->c1 = new->c1 - old->c1; |
633 | 696 | ||
@@ -1173,24 +1236,43 @@ void free_all_buffers(void) | |||
1173 | } | 1236 | } |
1174 | 1237 | ||
1175 | /* | 1238 | /* |
1239 | * Open a file, and exit on failure | ||
1240 | */ | ||
1241 | FILE *fopen_or_die(const char *path, const char *mode) | ||
1242 | { | ||
1243 | FILE *filep = fopen(path, "r"); | ||
1244 | if (!filep) | ||
1245 | err(1, "%s: open failed", path); | ||
1246 | return filep; | ||
1247 | } | ||
1248 | |||
1249 | /* | ||
1250 | * Parse a file containing a single int. | ||
1251 | */ | ||
1252 | int parse_int_file(const char *fmt, ...) | ||
1253 | { | ||
1254 | va_list args; | ||
1255 | char path[PATH_MAX]; | ||
1256 | FILE *filep; | ||
1257 | int value; | ||
1258 | |||
1259 | va_start(args, fmt); | ||
1260 | vsnprintf(path, sizeof(path), fmt, args); | ||
1261 | va_end(args); | ||
1262 | filep = fopen_or_die(path, "r"); | ||
1263 | if (fscanf(filep, "%d", &value) != 1) | ||
1264 | err(1, "%s: failed to parse number from file", path); | ||
1265 | fclose(filep); | ||
1266 | return value; | ||
1267 | } | ||
1268 | |||
1269 | /* | ||
1176 | * cpu_is_first_sibling_in_core(cpu) | 1270 | * cpu_is_first_sibling_in_core(cpu) |
1177 | * return 1 if given CPU is 1st HT sibling in the core | 1271 | * return 1 if given CPU is 1st HT sibling in the core |
1178 | */ | 1272 | */ |
1179 | int cpu_is_first_sibling_in_core(int cpu) | 1273 | int cpu_is_first_sibling_in_core(int cpu) |
1180 | { | 1274 | { |
1181 | char path[64]; | 1275 | return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); |
1182 | FILE *filep; | ||
1183 | int first_cpu; | ||
1184 | |||
1185 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); | ||
1186 | filep = fopen(path, "r"); | ||
1187 | if (filep == NULL) { | ||
1188 | perror(path); | ||
1189 | exit(1); | ||
1190 | } | ||
1191 | fscanf(filep, "%d", &first_cpu); | ||
1192 | fclose(filep); | ||
1193 | return (cpu == first_cpu); | ||
1194 | } | 1276 | } |
1195 | 1277 | ||
1196 | /* | 1278 | /* |
@@ -1199,53 +1281,17 @@ int cpu_is_first_sibling_in_core(int cpu) | |||
1199 | */ | 1281 | */ |
1200 | int cpu_is_first_core_in_package(int cpu) | 1282 | int cpu_is_first_core_in_package(int cpu) |
1201 | { | 1283 | { |
1202 | char path[64]; | 1284 | return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); |
1203 | FILE *filep; | ||
1204 | int first_cpu; | ||
1205 | |||
1206 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); | ||
1207 | filep = fopen(path, "r"); | ||
1208 | if (filep == NULL) { | ||
1209 | perror(path); | ||
1210 | exit(1); | ||
1211 | } | ||
1212 | fscanf(filep, "%d", &first_cpu); | ||
1213 | fclose(filep); | ||
1214 | return (cpu == first_cpu); | ||
1215 | } | 1285 | } |
1216 | 1286 | ||
1217 | int get_physical_package_id(int cpu) | 1287 | int get_physical_package_id(int cpu) |
1218 | { | 1288 | { |
1219 | char path[80]; | 1289 | return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); |
1220 | FILE *filep; | ||
1221 | int pkg; | ||
1222 | |||
1223 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); | ||
1224 | filep = fopen(path, "r"); | ||
1225 | if (filep == NULL) { | ||
1226 | perror(path); | ||
1227 | exit(1); | ||
1228 | } | ||
1229 | fscanf(filep, "%d", &pkg); | ||
1230 | fclose(filep); | ||
1231 | return pkg; | ||
1232 | } | 1290 | } |
1233 | 1291 | ||
1234 | int get_core_id(int cpu) | 1292 | int get_core_id(int cpu) |
1235 | { | 1293 | { |
1236 | char path[80]; | 1294 | return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); |
1237 | FILE *filep; | ||
1238 | int core; | ||
1239 | |||
1240 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); | ||
1241 | filep = fopen(path, "r"); | ||
1242 | if (filep == NULL) { | ||
1243 | perror(path); | ||
1244 | exit(1); | ||
1245 | } | ||
1246 | fscanf(filep, "%d", &core); | ||
1247 | fclose(filep); | ||
1248 | return core; | ||
1249 | } | 1295 | } |
1250 | 1296 | ||
1251 | int get_num_ht_siblings(int cpu) | 1297 | int get_num_ht_siblings(int cpu) |
@@ -1257,11 +1303,7 @@ int get_num_ht_siblings(int cpu) | |||
1257 | char character; | 1303 | char character; |
1258 | 1304 | ||
1259 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); | 1305 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); |
1260 | filep = fopen(path, "r"); | 1306 | filep = fopen_or_die(path, "r"); |
1261 | if (filep == NULL) { | ||
1262 | perror(path); | ||
1263 | exit(1); | ||
1264 | } | ||
1265 | /* | 1307 | /* |
1266 | * file format: | 1308 | * file format: |
1267 | * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4) | 1309 | * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4) |
@@ -1331,17 +1373,11 @@ int for_all_proc_cpus(int (func)(int)) | |||
1331 | int cpu_num; | 1373 | int cpu_num; |
1332 | int retval; | 1374 | int retval; |
1333 | 1375 | ||
1334 | fp = fopen(proc_stat, "r"); | 1376 | fp = fopen_or_die(proc_stat, "r"); |
1335 | if (fp == NULL) { | ||
1336 | perror(proc_stat); | ||
1337 | exit(1); | ||
1338 | } | ||
1339 | 1377 | ||
1340 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); | 1378 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); |
1341 | if (retval != 0) { | 1379 | if (retval != 0) |
1342 | perror("/proc/stat format"); | 1380 | err(1, "%s: failed to parse format", proc_stat); |
1343 | exit(1); | ||
1344 | } | ||
1345 | 1381 | ||
1346 | while (1) { | 1382 | while (1) { |
1347 | retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); | 1383 | retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); |
@@ -1445,19 +1481,15 @@ void check_dev_msr() | |||
1445 | { | 1481 | { |
1446 | struct stat sb; | 1482 | struct stat sb; |
1447 | 1483 | ||
1448 | if (stat("/dev/cpu/0/msr", &sb)) { | 1484 | if (stat("/dev/cpu/0/msr", &sb)) |
1449 | fprintf(stderr, "no /dev/cpu/0/msr\n"); | 1485 | err(-5, "no /dev/cpu/0/msr\n" |
1450 | fprintf(stderr, "Try \"# modprobe msr\"\n"); | 1486 | "Try \"# modprobe msr\""); |
1451 | exit(-5); | ||
1452 | } | ||
1453 | } | 1487 | } |
1454 | 1488 | ||
1455 | void check_super_user() | 1489 | void check_super_user() |
1456 | { | 1490 | { |
1457 | if (getuid() != 0) { | 1491 | if (getuid() != 0) |
1458 | fprintf(stderr, "must be root\n"); | 1492 | errx(-6, "must be root"); |
1459 | exit(-6); | ||
1460 | } | ||
1461 | } | 1493 | } |
1462 | 1494 | ||
1463 | int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | 1495 | int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) |
@@ -1479,7 +1511,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | |||
1479 | case 0x3A: /* IVB */ | 1511 | case 0x3A: /* IVB */ |
1480 | case 0x3E: /* IVB Xeon */ | 1512 | case 0x3E: /* IVB Xeon */ |
1481 | case 0x3C: /* HSW */ | 1513 | case 0x3C: /* HSW */ |
1482 | case 0x3F: /* HSW */ | 1514 | case 0x3F: /* HSX */ |
1483 | case 0x45: /* HSW */ | 1515 | case 0x45: /* HSW */ |
1484 | case 0x46: /* HSW */ | 1516 | case 0x46: /* HSW */ |
1485 | case 0x37: /* BYT */ | 1517 | case 0x37: /* BYT */ |
@@ -1595,11 +1627,13 @@ void rapl_probe(unsigned int family, unsigned int model) | |||
1595 | case 0x2A: | 1627 | case 0x2A: |
1596 | case 0x3A: | 1628 | case 0x3A: |
1597 | case 0x3C: /* HSW */ | 1629 | case 0x3C: /* HSW */ |
1598 | case 0x3F: /* HSW */ | ||
1599 | case 0x45: /* HSW */ | 1630 | case 0x45: /* HSW */ |
1600 | case 0x46: /* HSW */ | 1631 | case 0x46: /* HSW */ |
1601 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO; | 1632 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO; |
1602 | break; | 1633 | break; |
1634 | case 0x3F: /* HSX */ | ||
1635 | do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO; | ||
1636 | break; | ||
1603 | case 0x2D: | 1637 | case 0x2D: |
1604 | case 0x3E: | 1638 | case 0x3E: |
1605 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS | RAPL_PKG_POWER_INFO; | 1639 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS | RAPL_PKG_POWER_INFO; |
@@ -1978,7 +2012,7 @@ void check_cpuid() | |||
1978 | 2012 | ||
1979 | eax = ebx = ecx = edx = 0; | 2013 | eax = ebx = ecx = edx = 0; |
1980 | 2014 | ||
1981 | asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0)); | 2015 | __get_cpuid(0, &max_level, &ebx, &ecx, &edx); |
1982 | 2016 | ||
1983 | if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) | 2017 | if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) |
1984 | genuine_intel = 1; | 2018 | genuine_intel = 1; |
@@ -1987,7 +2021,7 @@ void check_cpuid() | |||
1987 | fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", | 2021 | fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", |
1988 | (char *)&ebx, (char *)&edx, (char *)&ecx); | 2022 | (char *)&ebx, (char *)&edx, (char *)&ecx); |
1989 | 2023 | ||
1990 | asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); | 2024 | __get_cpuid(1, &fms, &ebx, &ecx, &edx); |
1991 | family = (fms >> 8) & 0xf; | 2025 | family = (fms >> 8) & 0xf; |
1992 | model = (fms >> 4) & 0xf; | 2026 | model = (fms >> 4) & 0xf; |
1993 | stepping = fms & 0xf; | 2027 | stepping = fms & 0xf; |
@@ -1998,10 +2032,8 @@ void check_cpuid() | |||
1998 | fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", | 2032 | fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", |
1999 | max_level, family, model, stepping, family, model, stepping); | 2033 | max_level, family, model, stepping, family, model, stepping); |
2000 | 2034 | ||
2001 | if (!(edx & (1 << 5))) { | 2035 | if (!(edx & (1 << 5))) |
2002 | fprintf(stderr, "CPUID: no MSR\n"); | 2036 | errx(1, "CPUID: no MSR"); |
2003 | exit(1); | ||
2004 | } | ||
2005 | 2037 | ||
2006 | /* | 2038 | /* |
2007 | * check max extended function levels of CPUID. | 2039 | * check max extended function levels of CPUID. |
@@ -2009,31 +2041,27 @@ void check_cpuid() | |||
2009 | * This check is valid for both Intel and AMD. | 2041 | * This check is valid for both Intel and AMD. |
2010 | */ | 2042 | */ |
2011 | ebx = ecx = edx = 0; | 2043 | ebx = ecx = edx = 0; |
2012 | asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000)); | 2044 | __get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx); |
2013 | 2045 | ||
2014 | if (max_level < 0x80000007) { | 2046 | if (max_level < 0x80000007) |
2015 | fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level); | 2047 | errx(1, "CPUID: no invariant TSC (max_level 0x%x)", max_level); |
2016 | exit(1); | ||
2017 | } | ||
2018 | 2048 | ||
2019 | /* | 2049 | /* |
2020 | * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 | 2050 | * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 |
2021 | * this check is valid for both Intel and AMD | 2051 | * this check is valid for both Intel and AMD |
2022 | */ | 2052 | */ |
2023 | asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007)); | 2053 | __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); |
2024 | has_invariant_tsc = edx & (1 << 8); | 2054 | has_invariant_tsc = edx & (1 << 8); |
2025 | 2055 | ||
2026 | if (!has_invariant_tsc) { | 2056 | if (!has_invariant_tsc) |
2027 | fprintf(stderr, "No invariant TSC\n"); | 2057 | errx(1, "No invariant TSC"); |
2028 | exit(1); | ||
2029 | } | ||
2030 | 2058 | ||
2031 | /* | 2059 | /* |
2032 | * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 | 2060 | * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 |
2033 | * this check is valid for both Intel and AMD | 2061 | * this check is valid for both Intel and AMD |
2034 | */ | 2062 | */ |
2035 | 2063 | ||
2036 | asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); | 2064 | __get_cpuid(0x6, &eax, &ebx, &ecx, &edx); |
2037 | has_aperf = ecx & (1 << 0); | 2065 | has_aperf = ecx & (1 << 0); |
2038 | do_dts = eax & (1 << 0); | 2066 | do_dts = eax & (1 << 0); |
2039 | do_ptm = eax & (1 << 6); | 2067 | do_ptm = eax & (1 << 6); |
@@ -2047,7 +2075,7 @@ void check_cpuid() | |||
2047 | has_epb ? ", EPB": ""); | 2075 | has_epb ? ", EPB": ""); |
2048 | 2076 | ||
2049 | if (!has_aperf) | 2077 | if (!has_aperf) |
2050 | exit(-1); | 2078 | errx(-1, "No APERF"); |
2051 | 2079 | ||
2052 | do_nehalem_platform_info = genuine_intel && has_invariant_tsc; | 2080 | do_nehalem_platform_info = genuine_intel && has_invariant_tsc; |
2053 | do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ | 2081 | do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ |
@@ -2067,9 +2095,8 @@ void check_cpuid() | |||
2067 | 2095 | ||
2068 | void usage() | 2096 | void usage() |
2069 | { | 2097 | { |
2070 | fprintf(stderr, "%s: [-v][-R][-T][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", | 2098 | errx(1, "%s: [-v][-R][-T][-p|-P|-S][-c MSR#][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", |
2071 | progname); | 2099 | progname); |
2072 | exit(1); | ||
2073 | } | 2100 | } |
2074 | 2101 | ||
2075 | 2102 | ||
@@ -2112,19 +2139,15 @@ void topology_probe() | |||
2112 | fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num); | 2139 | fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num); |
2113 | 2140 | ||
2114 | cpus = calloc(1, (topo.max_cpu_num + 1) * sizeof(struct cpu_topology)); | 2141 | cpus = calloc(1, (topo.max_cpu_num + 1) * sizeof(struct cpu_topology)); |
2115 | if (cpus == NULL) { | 2142 | if (cpus == NULL) |
2116 | perror("calloc cpus"); | 2143 | err(1, "calloc cpus"); |
2117 | exit(1); | ||
2118 | } | ||
2119 | 2144 | ||
2120 | /* | 2145 | /* |
2121 | * Allocate and initialize cpu_present_set | 2146 | * Allocate and initialize cpu_present_set |
2122 | */ | 2147 | */ |
2123 | cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1)); | 2148 | cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1)); |
2124 | if (cpu_present_set == NULL) { | 2149 | if (cpu_present_set == NULL) |
2125 | perror("CPU_ALLOC"); | 2150 | err(3, "CPU_ALLOC"); |
2126 | exit(3); | ||
2127 | } | ||
2128 | cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); | 2151 | cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); |
2129 | CPU_ZERO_S(cpu_present_setsize, cpu_present_set); | 2152 | CPU_ZERO_S(cpu_present_setsize, cpu_present_set); |
2130 | for_all_proc_cpus(mark_cpu_present); | 2153 | for_all_proc_cpus(mark_cpu_present); |
@@ -2133,10 +2156,8 @@ void topology_probe() | |||
2133 | * Allocate and initialize cpu_affinity_set | 2156 | * Allocate and initialize cpu_affinity_set |
2134 | */ | 2157 | */ |
2135 | cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1)); | 2158 | cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1)); |
2136 | if (cpu_affinity_set == NULL) { | 2159 | if (cpu_affinity_set == NULL) |
2137 | perror("CPU_ALLOC"); | 2160 | err(3, "CPU_ALLOC"); |
2138 | exit(3); | ||
2139 | } | ||
2140 | cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); | 2161 | cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); |
2141 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); | 2162 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); |
2142 | 2163 | ||
@@ -2220,8 +2241,7 @@ allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data | |||
2220 | 2241 | ||
2221 | return; | 2242 | return; |
2222 | error: | 2243 | error: |
2223 | perror("calloc counters"); | 2244 | err(1, "calloc counters"); |
2224 | exit(1); | ||
2225 | } | 2245 | } |
2226 | /* | 2246 | /* |
2227 | * init_counter() | 2247 | * init_counter() |
@@ -2276,12 +2296,10 @@ int initialize_counters(int cpu_id) | |||
2276 | 2296 | ||
2277 | void allocate_output_buffer() | 2297 | void allocate_output_buffer() |
2278 | { | 2298 | { |
2279 | output_buffer = calloc(1, (1 + topo.num_cpus) * 256); | 2299 | output_buffer = calloc(1, (1 + topo.num_cpus) * 1024); |
2280 | outp = output_buffer; | 2300 | outp = output_buffer; |
2281 | if (outp == NULL) { | 2301 | if (outp == NULL) |
2282 | perror("calloc"); | 2302 | err(-1, "calloc output buffer"); |
2283 | exit(-1); | ||
2284 | } | ||
2285 | } | 2303 | } |
2286 | 2304 | ||
2287 | void setup_all_buffers(void) | 2305 | void setup_all_buffers(void) |
@@ -2292,6 +2310,7 @@ void setup_all_buffers(void) | |||
2292 | allocate_output_buffer(); | 2310 | allocate_output_buffer(); |
2293 | for_all_proc_cpus(initialize_counters); | 2311 | for_all_proc_cpus(initialize_counters); |
2294 | } | 2312 | } |
2313 | |||
2295 | void turbostat_init() | 2314 | void turbostat_init() |
2296 | { | 2315 | { |
2297 | check_cpuid(); | 2316 | check_cpuid(); |
@@ -2335,17 +2354,13 @@ int fork_it(char **argv) | |||
2335 | } else { | 2354 | } else { |
2336 | 2355 | ||
2337 | /* parent */ | 2356 | /* parent */ |
2338 | if (child_pid == -1) { | 2357 | if (child_pid == -1) |
2339 | perror("fork"); | 2358 | err(1, "fork"); |
2340 | exit(1); | ||
2341 | } | ||
2342 | 2359 | ||
2343 | signal(SIGINT, SIG_IGN); | 2360 | signal(SIGINT, SIG_IGN); |
2344 | signal(SIGQUIT, SIG_IGN); | 2361 | signal(SIGQUIT, SIG_IGN); |
2345 | if (waitpid(child_pid, &status, 0) == -1) { | 2362 | if (waitpid(child_pid, &status, 0) == -1) |
2346 | perror("wait"); | 2363 | err(status, "waitpid"); |
2347 | exit(status); | ||
2348 | } | ||
2349 | } | 2364 | } |
2350 | /* | 2365 | /* |
2351 | * n.b. fork_it() does not check for errors from for_all_cpus() | 2366 | * n.b. fork_it() does not check for errors from for_all_cpus() |
@@ -2364,13 +2379,30 @@ int fork_it(char **argv) | |||
2364 | return status; | 2379 | return status; |
2365 | } | 2380 | } |
2366 | 2381 | ||
2382 | int get_and_dump_counters(void) | ||
2383 | { | ||
2384 | int status; | ||
2385 | |||
2386 | status = for_all_cpus(get_counters, ODD_COUNTERS); | ||
2387 | if (status) | ||
2388 | return status; | ||
2389 | |||
2390 | status = for_all_cpus(dump_counters, ODD_COUNTERS); | ||
2391 | if (status) | ||
2392 | return status; | ||
2393 | |||
2394 | flush_stdout(); | ||
2395 | |||
2396 | return status; | ||
2397 | } | ||
2398 | |||
2367 | void cmdline(int argc, char **argv) | 2399 | void cmdline(int argc, char **argv) |
2368 | { | 2400 | { |
2369 | int opt; | 2401 | int opt; |
2370 | 2402 | ||
2371 | progname = argv[0]; | 2403 | progname = argv[0]; |
2372 | 2404 | ||
2373 | while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:RT:")) != -1) { | 2405 | while ((opt = getopt(argc, argv, "+pPsSvi:c:C:m:M:RJT:")) != -1) { |
2374 | switch (opt) { | 2406 | switch (opt) { |
2375 | case 'p': | 2407 | case 'p': |
2376 | show_core_only++; | 2408 | show_core_only++; |
@@ -2378,6 +2410,9 @@ void cmdline(int argc, char **argv) | |||
2378 | case 'P': | 2410 | case 'P': |
2379 | show_pkg_only++; | 2411 | show_pkg_only++; |
2380 | break; | 2412 | break; |
2413 | case 's': | ||
2414 | dump_only++; | ||
2415 | break; | ||
2381 | case 'S': | 2416 | case 'S': |
2382 | summary_only++; | 2417 | summary_only++; |
2383 | break; | 2418 | break; |
@@ -2405,6 +2440,10 @@ void cmdline(int argc, char **argv) | |||
2405 | case 'T': | 2440 | case 'T': |
2406 | tcc_activation_temp_override = atoi(optarg); | 2441 | tcc_activation_temp_override = atoi(optarg); |
2407 | break; | 2442 | break; |
2443 | case 'J': | ||
2444 | rapl_joules++; | ||
2445 | break; | ||
2446 | |||
2408 | default: | 2447 | default: |
2409 | usage(); | 2448 | usage(); |
2410 | } | 2449 | } |
@@ -2416,11 +2455,15 @@ int main(int argc, char **argv) | |||
2416 | cmdline(argc, argv); | 2455 | cmdline(argc, argv); |
2417 | 2456 | ||
2418 | if (verbose) | 2457 | if (verbose) |
2419 | fprintf(stderr, "turbostat v3.5 April 26, 2013" | 2458 | fprintf(stderr, "turbostat v3.6 Dec 2, 2013" |
2420 | " - Len Brown <lenb@kernel.org>\n"); | 2459 | " - Len Brown <lenb@kernel.org>\n"); |
2421 | 2460 | ||
2422 | turbostat_init(); | 2461 | turbostat_init(); |
2423 | 2462 | ||
2463 | /* dump counters and exit */ | ||
2464 | if (dump_only) | ||
2465 | return get_and_dump_counters(); | ||
2466 | |||
2424 | /* | 2467 | /* |
2425 | * if any params left, it must be a command to fork | 2468 | * if any params left, it must be a command to fork |
2426 | */ | 2469 | */ |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 9f3eae290900..32487ed18354 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -9,6 +9,7 @@ TARGETS += ptrace | |||
9 | TARGETS += timers | 9 | TARGETS += timers |
10 | TARGETS += vm | 10 | TARGETS += vm |
11 | TARGETS += powerpc | 11 | TARGETS += powerpc |
12 | TARGETS += user | ||
12 | 13 | ||
13 | all: | 14 | all: |
14 | for TARGET in $(TARGETS); do \ | 15 | for TARGET in $(TARGETS); do \ |
diff --git a/tools/testing/selftests/user/Makefile b/tools/testing/selftests/user/Makefile new file mode 100644 index 000000000000..396255bd720e --- /dev/null +++ b/tools/testing/selftests/user/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # Makefile for user memory selftests | ||
2 | |||
3 | # No binaries, but make sure arg-less "make" doesn't trigger "run_tests" | ||
4 | all: | ||
5 | |||
6 | run_tests: all | ||
7 | @if /sbin/modprobe test_user_copy ; then \ | ||
8 | rmmod test_user_copy; \ | ||
9 | echo "user_copy: ok"; \ | ||
10 | else \ | ||
11 | echo "user_copy: [FAIL]"; \ | ||
12 | exit 1; \ | ||
13 | fi | ||