Commit aeaae7d6 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo-20160408' of...

Merge tag 'perf-core-for-mingo-20160408' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

- Beautify more syscall arguments in 'perf trace', using the type column in
  tracepoint /format fields to attach, for instance, a pid_t resolver to the
  thread COMM, also attach a mode_t beautifier in the same fashion
  (Arnaldo Carvalho de Melo)

- Build the syscall table id <-> name resolver using the same .tbl file
  used in the kernel to generate headers, to avoid the delay in getting
  new syscalls supported in the audit-libs external dependency, done so
  far only for x86_64 (Arnaldo Carvalho de Melo)

- Improve the documentation of event specifications (Andi Kleen)

- Process update events in 'perf script', fixing up this use case:

    # perf stat -a -I 1000 -e cycles record | perf script -s script.py

- Shared object symbol adjustment fixes, fixing symbol resolution in
  Android (Wang Nan)

Infrastructure changes:

- Add dedicated unwind addr_space member into thread struct, to allow
  tools to use thread->priv, noticed while working on having callchains
  in 'perf trace' (Jiri Olsa)

Build fixes:

- Fix the build in Ubuntu 12.04 (Arnaldo Carvalho de Melo, Vinson Lee)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 889fac6d 99e87f7b
...@@ -30,6 +30,7 @@ endef ...@@ -30,6 +30,7 @@ endef
FEATURE_TESTS_BASIC := \ FEATURE_TESTS_BASIC := \
backtrace \ backtrace \
dwarf \ dwarf \
dwarf_getlocations \
fortify-source \ fortify-source \
sync-compare-and-swap \ sync-compare-and-swap \
glibc \ glibc \
...@@ -78,6 +79,7 @@ endif ...@@ -78,6 +79,7 @@ endif
FEATURE_DISPLAY ?= \ FEATURE_DISPLAY ?= \
dwarf \ dwarf \
dwarf_getlocations \
glibc \ glibc \
gtk2 \ gtk2 \
libaudit \ libaudit \
......
...@@ -3,6 +3,7 @@ FILES= \ ...@@ -3,6 +3,7 @@ FILES= \
test-backtrace.bin \ test-backtrace.bin \
test-bionic.bin \ test-bionic.bin \
test-dwarf.bin \ test-dwarf.bin \
test-dwarf_getlocations.bin \
test-fortify-source.bin \ test-fortify-source.bin \
test-sync-compare-and-swap.bin \ test-sync-compare-and-swap.bin \
test-glibc.bin \ test-glibc.bin \
...@@ -82,6 +83,9 @@ endif ...@@ -82,6 +83,9 @@ endif
$(OUTPUT)test-dwarf.bin: $(OUTPUT)test-dwarf.bin:
$(BUILD) $(DWARFLIBS) $(BUILD) $(DWARFLIBS)
$(OUTPUT)test-dwarf_getlocations.bin:
$(BUILD) $(DWARFLIBS)
$(OUTPUT)test-libelf-mmap.bin: $(OUTPUT)test-libelf-mmap.bin:
$(BUILD) -lelf $(BUILD) -lelf
......
...@@ -41,6 +41,10 @@ ...@@ -41,6 +41,10 @@
# include "test-dwarf.c" # include "test-dwarf.c"
#undef main #undef main
#define main main_test_dwarf_getlocations
# include "test-dwarf_getlocations.c"
#undef main
#define main main_test_libelf_getphdrnum #define main main_test_libelf_getphdrnum
# include "test-libelf-getphdrnum.c" # include "test-libelf-getphdrnum.c"
#undef main #undef main
...@@ -143,6 +147,7 @@ int main(int argc, char *argv[]) ...@@ -143,6 +147,7 @@ int main(int argc, char *argv[])
main_test_libelf_mmap(); main_test_libelf_mmap();
main_test_glibc(); main_test_glibc();
main_test_dwarf(); main_test_dwarf();
main_test_dwarf_getlocations();
main_test_libelf_getphdrnum(); main_test_libelf_getphdrnum();
main_test_libunwind(); main_test_libunwind();
main_test_libaudit(); main_test_libaudit();
......
#include <stdlib.h>
#include <elfutils/libdw.h>
int main(void)
{
Dwarf_Addr base, start, end;
Dwarf_Attribute attr;
Dwarf_Op *op;
size_t nops;
ptrdiff_t offset = 0;
return (int)dwarf_getlocations(&attr, offset, &base, &start, &end, &op, &nops);
}
...@@ -93,6 +93,67 @@ raw encoding of 0x1A8 can be used: ...@@ -93,6 +93,67 @@ raw encoding of 0x1A8 can be used:
You should refer to the processor specific documentation for getting these You should refer to the processor specific documentation for getting these
details. Some of them are referenced in the SEE ALSO section below. details. Some of them are referenced in the SEE ALSO section below.
ARBITRARY PMUS
--------------
perf also supports an extended syntax for specifying raw parameters
to PMUs. Using this typically requires looking up the specific event
in the CPU vendor specific documentation.
The available PMUs and their raw parameters can be listed with
ls /sys/devices/*/format
For example the raw event "LSD.UOPS" core pmu event above could
be specified as
perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=1/ ...
PER SOCKET PMUS
---------------
Some PMUs are not associated with a core, but with a whole CPU socket.
Events on these PMUs generally cannot be sampled, but only counted globally
with perf stat -a. They can be bound to one logical CPU, but will measure
all the CPUs in the same socket.
This example measures memory bandwidth every second
on the first memory controller on socket 0 of a Intel Xeon system
perf stat -C 0 -a uncore_imc_0/cas_count_read/,uncore_imc_0/cas_count_write/ -I 1000 ...
Each memory controller has its own PMU. Measuring the complete system
bandwidth would require specifying all imc PMUs (see perf list output),
and adding the values together.
This example measures the combined core power every second
perf stat -I 1000 -e power/energy-cores/ -a
ACCESS RESTRICTIONS
-------------------
For non root users generally only context switched PMU events are available.
This is normally only the events in the cpu PMU, the predefined events
like cycles and instructions and some software events.
Other PMUs and global measurements are normally root only.
Some event qualifiers, such as "any", are also root only.
This can be overriden by setting the kernel.perf_event_paranoid
sysctl to -1, which allows non root to use these events.
For accessing trace point events perf needs to have read access to
/sys/kernel/debug/tracing, even when perf_event_paranoid is in a relaxed
setting.
TRACING
-------
Some PMUs control advanced hardware tracing capabilities, such as Intel PT,
that allows low overhead execution tracing. These are described in a separate
intel-pt.txt document.
PARAMETERIZED EVENTS PARAMETERIZED EVENTS
-------------------- --------------------
...@@ -106,6 +167,50 @@ also be supplied. For example: ...@@ -106,6 +167,50 @@ also be supplied. For example:
perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ...
EVENT GROUPS
------------
Perf supports time based multiplexing of events, when the number of events
active exceeds the number of hardware performance counters. Multiplexing
can cause measurement errors when the workload changes its execution
profile.
When metrics are computed using formulas from event counts, it is useful to
ensure some events are always measured together as a group to minimize multiplexing
errors. Event groups can be specified using { }.
perf stat -e '{instructions,cycles}' ...
The number of available performance counters depend on the CPU. A group
cannot contain more events than available counters.
For example Intel Core CPUs typically have four generic performance counters
for the core, plus three fixed counters for instructions, cycles and
ref-cycles. Some special events have restrictions on which counter they
can schedule, and may not support multiple instances in a single group.
When too many events are specified in the group none of them will not
be measured.
Globally pinned events can limit the number of counters available for
other groups. On x86 systems, the NMI watchdog pins a counter by default.
The nmi watchdog can be disabled as root with
echo 0 > /proc/sys/kernel/nmi_watchdog
Events from multiple different PMUs cannot be mixed in a group, with
some exceptions for software events.
LEADER SAMPLING
---------------
perf also supports group leader sampling using the :S specifier.
perf record -e '{cycles,instructions}:S' ...
perf report --group
Normally all events in a event group sample, but with :S only
the first event (the leader) samples, and it only reads the values of the
other events in the group.
OPTIONS OPTIONS
------- -------
...@@ -143,5 +248,5 @@ SEE ALSO ...@@ -143,5 +248,5 @@ SEE ALSO
-------- --------
linkperf:perf-stat[1], linkperf:perf-top[1], linkperf:perf-stat[1], linkperf:perf-top[1],
linkperf:perf-record[1], linkperf:perf-record[1],
http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide], http://www.intel.com/sdm/[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide],
http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming] http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming]
...@@ -183,6 +183,11 @@ endif ...@@ -183,6 +183,11 @@ endif
include config/Makefile include config/Makefile
endif endif
ifeq ($(config),0)
include $(srctree)/tools/scripts/Makefile.arch
-include arch/$(ARCH)/Makefile
endif
# The FEATURE_DUMP_EXPORT holds location of the actual # The FEATURE_DUMP_EXPORT holds location of the actual
# FEATURE_DUMP file to be used to bypass feature detection # FEATURE_DUMP file to be used to bypass feature detection
# (for bpf or any other subproject) # (for bpf or any other subproject)
...@@ -297,8 +302,6 @@ endif ...@@ -297,8 +302,6 @@ endif
# because maintaining the nesting to match is a pain. If # because maintaining the nesting to match is a pain. If
# we had "elif" things would have been much nicer... # we had "elif" things would have been much nicer...
-include arch/$(ARCH)/Makefile
ifneq ($(OUTPUT),) ifneq ($(OUTPUT),)
CFLAGS += -I$(OUTPUT) CFLAGS += -I$(OUTPUT)
endif endif
...@@ -390,7 +393,7 @@ endif ...@@ -390,7 +393,7 @@ endif
__build-dir = $(subst $(OUTPUT),,$(dir $@)) __build-dir = $(subst $(OUTPUT),,$(dir $@))
build-dir = $(if $(__build-dir),$(__build-dir),.) build-dir = $(if $(__build-dir),$(__build-dir),.)
prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep archheaders
$(OUTPUT)%.o: %.c prepare FORCE $(OUTPUT)%.o: %.c prepare FORCE
$(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
...@@ -430,7 +433,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) ...@@ -430,7 +433,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h)
LIBPERF_IN := $(OUTPUT)libperf-in.o LIBPERF_IN := $(OUTPUT)libperf-in.o
$(LIBPERF_IN): fixdep FORCE $(LIBPERF_IN): prepare fixdep FORCE
$(Q)$(MAKE) $(build)=libperf $(Q)$(MAKE) $(build)=libperf
$(LIB_FILE): $(LIBPERF_IN) $(LIB_FILE): $(LIBPERF_IN)
...@@ -625,7 +628,7 @@ config-clean: ...@@ -625,7 +628,7 @@ config-clean:
$(call QUIET_CLEAN, config) $(call QUIET_CLEAN, config)
$(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
$(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
$(Q)$(RM) $(OUTPUT).config-detected $(Q)$(RM) $(OUTPUT).config-detected
...@@ -662,5 +665,5 @@ FORCE: ...@@ -662,5 +665,5 @@ FORCE:
.PHONY: all install clean config-clean strip install-gtk .PHONY: all install clean config-clean strip install-gtk
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare
.PHONY: libtraceevent_plugins .PHONY: libtraceevent_plugins archheaders
...@@ -4,3 +4,26 @@ endif ...@@ -4,3 +4,26 @@ endif
HAVE_KVM_STAT_SUPPORT := 1 HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
PERF_HAVE_JITDUMP := 1 PERF_HAVE_JITDUMP := 1
###
# Syscall table generation
#
out := $(OUTPUT)arch/x86/include/generated/asm
header := $(out)/syscalls_64.c
sys := $(srctree)/tools/perf/arch/x86/entry/syscalls
systbl := $(sys)/syscalltbl.sh
# Create output directory if not already present
_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
$(header): $(sys)/syscall_64.tbl $(systbl)
@(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \
(diff -B arch/x86/entry/syscalls/syscall_64.tbl ../../arch/x86/entry/syscalls/syscall_64.tbl >/dev/null) \
|| echo "Warning: x86_64's syscall_64.tbl differs from kernel" >&2 )) || true
$(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@
clean::
rm -f $(header)
archheaders: $(header)
#
# 64-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The abi is "common", "64" or "x32" for this file.
#
0 common read sys_read
1 common write sys_write
2 common open sys_open
3 common close sys_close
4 common stat sys_newstat
5 common fstat sys_newfstat
6 common lstat sys_newlstat
7 common poll sys_poll
8 common lseek sys_lseek
9 common mmap sys_mmap
10 common mprotect sys_mprotect
11 common munmap sys_munmap
12 common brk sys_brk
13 64 rt_sigaction sys_rt_sigaction
14 common rt_sigprocmask sys_rt_sigprocmask
15 64 rt_sigreturn sys_rt_sigreturn/ptregs
16 64 ioctl sys_ioctl
17 common pread64 sys_pread64
18 common pwrite64 sys_pwrite64
19 64 readv sys_readv
20 64 writev sys_writev
21 common access sys_access
22 common pipe sys_pipe
23 common select sys_select
24 common sched_yield sys_sched_yield
25 common mremap sys_mremap
26 common msync sys_msync
27 common mincore sys_mincore
28 common madvise sys_madvise
29 common shmget sys_shmget
30 common shmat sys_shmat
31 common shmctl sys_shmctl
32 common dup sys_dup
33 common dup2 sys_dup2
34 common pause sys_pause
35 common nanosleep sys_nanosleep
36 common getitimer sys_getitimer
37 common alarm sys_alarm
38 common setitimer sys_setitimer
39 common getpid sys_getpid
40 common sendfile sys_sendfile64
41 common socket sys_socket
42 common connect sys_connect
43 common accept sys_accept
44 common sendto sys_sendto
45 64 recvfrom sys_recvfrom
46 64 sendmsg sys_sendmsg
47 64 recvmsg sys_recvmsg
48 common shutdown sys_shutdown
49 common bind sys_bind
50 common listen sys_listen
51 common getsockname sys_getsockname
52 common getpeername sys_getpeername
53 common socketpair sys_socketpair
54 64 setsockopt sys_setsockopt
55 64 getsockopt sys_getsockopt
56 common clone sys_clone/ptregs
57 common fork sys_fork/ptregs
58 common vfork sys_vfork/ptregs
59 64 execve sys_execve/ptregs
60 common exit sys_exit
61 common wait4 sys_wait4
62 common kill sys_kill
63 common uname sys_newuname
64 common semget sys_semget
65 common semop sys_semop
66 common semctl sys_semctl
67 common shmdt sys_shmdt
68 common msgget sys_msgget
69 common msgsnd sys_msgsnd
70 common msgrcv sys_msgrcv
71 common msgctl sys_msgctl
72 common fcntl sys_fcntl
73 common flock sys_flock
74 common fsync sys_fsync
75 common fdatasync sys_fdatasync
76 common truncate sys_truncate
77 common ftruncate sys_ftruncate
78 common getdents sys_getdents
79 common getcwd sys_getcwd
80 common chdir sys_chdir
81 common fchdir sys_fchdir
82 common rename sys_rename
83 common mkdir sys_mkdir
84 common rmdir sys_rmdir
85 common creat sys_creat
86 common link sys_link
87 common unlink sys_unlink
88 common symlink sys_symlink
89 common readlink sys_readlink
90 common chmod sys_chmod
91 common fchmod sys_fchmod
92 common chown sys_chown
93 common fchown sys_fchown
94 common lchown sys_lchown
95 common umask sys_umask
96 common gettimeofday sys_gettimeofday
97 common getrlimit sys_getrlimit
98 common getrusage sys_getrusage
99 common sysinfo sys_sysinfo
100 common times sys_times
101 64 ptrace sys_ptrace
102 common getuid sys_getuid
103 common syslog sys_syslog
104 common getgid sys_getgid
105 common setuid sys_setuid
106 common setgid sys_setgid
107 common geteuid sys_geteuid
108 common getegid sys_getegid
109 common setpgid sys_setpgid
110 common getppid sys_getppid
111 common getpgrp sys_getpgrp
112 common setsid sys_setsid
113 common setreuid sys_setreuid
114 common setregid sys_setregid
115 common getgroups sys_getgroups
116 common setgroups sys_setgroups
117 common setresuid sys_setresuid
118 common getresuid sys_getresuid
119 common setresgid sys_setresgid
120 common getresgid sys_getresgid
121 common getpgid sys_getpgid
122 common setfsuid sys_setfsuid
123 common setfsgid sys_setfsgid
124 common getsid sys_getsid
125 common capget sys_capget
126 common capset sys_capset
127 64 rt_sigpending sys_rt_sigpending
128 64 rt_sigtimedwait sys_rt_sigtimedwait
129 64 rt_sigqueueinfo sys_rt_sigqueueinfo
130 common rt_sigsuspend sys_rt_sigsuspend
131 64 sigaltstack sys_sigaltstack
132 common utime sys_utime
133 common mknod sys_mknod
134 64 uselib
135 common personality sys_personality
136 common ustat sys_ustat
137 common statfs sys_statfs
138 common fstatfs sys_fstatfs
139 common sysfs sys_sysfs
140 common getpriority sys_getpriority
141 common setpriority sys_setpriority
142 common sched_setparam sys_sched_setparam
143 common sched_getparam sys_sched_getparam
144 common sched_setscheduler sys_sched_setscheduler
145 common sched_getscheduler sys_sched_getscheduler
146 common sched_get_priority_max sys_sched_get_priority_max
147 common sched_get_priority_min sys_sched_get_priority_min
148 common sched_rr_get_interval sys_sched_rr_get_interval
149 common mlock sys_mlock
150 common munlock sys_munlock
151 common mlockall sys_mlockall
152 common munlockall sys_munlockall
153 common vhangup sys_vhangup
154 common modify_ldt sys_modify_ldt
155 common pivot_root sys_pivot_root
156 64 _sysctl sys_sysctl
157 common prctl sys_prctl
158 common arch_prctl sys_arch_prctl
159 common adjtimex sys_adjtimex
160 common setrlimit sys_setrlimit
161 common chroot sys_chroot
162 common sync sys_sync
163 common acct sys_acct
164 common settimeofday sys_settimeofday
165 common mount sys_mount
166 common umount2 sys_umount
167 common swapon sys_swapon
168 common swapoff sys_swapoff
169 common reboot sys_reboot
170 common sethostname sys_sethostname
171 common setdomainname sys_setdomainname
172 common iopl sys_iopl/ptregs
173 common ioperm sys_ioperm
174 64 create_module
175 common init_module sys_init_module
176 common delete_module sys_delete_module
177 64 get_kernel_syms
178 64 query_module
179 common quotactl sys_quotactl
180 64 nfsservctl
181 common getpmsg
182 common putpmsg
183 common afs_syscall
184 common tuxcall
185 common security
186 common gettid sys_gettid
187 common readahead sys_readahead
188 common setxattr sys_setxattr
189 common lsetxattr sys_lsetxattr
190 common fsetxattr sys_fsetxattr
191 common getxattr sys_getxattr
192 common lgetxattr sys_lgetxattr
193 common fgetxattr sys_fgetxattr
194 common listxattr sys_listxattr
195 common llistxattr sys_llistxattr
196 common flistxattr sys_flistxattr
197 common removexattr sys_removexattr
198 common lremovexattr sys_lremovexattr
199 common fremovexattr sys_fremovexattr
200 common tkill sys_tkill
201 common time sys_time
202 common futex sys_futex
203 common sched_setaffinity sys_sched_setaffinity
204 common sched_getaffinity sys_sched_getaffinity
205 64 set_thread_area
206 64 io_setup sys_io_setup
207 common io_destroy sys_io_destroy
208 common io_getevents sys_io_getevents
209 64 io_submit sys_io_submit
210 common io_cancel sys_io_cancel
211 64 get_thread_area
212 common lookup_dcookie sys_lookup_dcookie
213 common epoll_create sys_epoll_create
214 64 epoll_ctl_old
215 64 epoll_wait_old
216 common remap_file_pages sys_remap_file_pages
217 common getdents64 sys_getdents64
218 common set_tid_address sys_set_tid_address
219 common restart_syscall sys_restart_syscall
220 common semtimedop sys_semtimedop
221 common fadvise64 sys_fadvise64
222 64 timer_create sys_timer_create
223 common timer_settime sys_timer_settime
224 common timer_gettime sys_timer_gettime
225 common timer_getoverrun sys_timer_getoverrun
226 common timer_delete sys_timer_delete
227 common clock_settime sys_clock_settime
228 common clock_gettime sys_clock_gettime
229 common clock_getres sys_clock_getres
230 common clock_nanosleep sys_clock_nanosleep
231 common exit_group sys_exit_group
232 common epoll_wait sys_epoll_wait
233 common epoll_ctl sys_epoll_ctl
234 common tgkill sys_tgkill
235 common utimes sys_utimes
236 64 vserver
237 common mbind sys_mbind
238 common set_mempolicy sys_set_mempolicy
239 common get_mempolicy sys_get_mempolicy
240 common mq_open sys_mq_open
241 common mq_unlink sys_mq_unlink
242 common mq_timedsend sys_mq_timedsend
243 common mq_timedreceive sys_mq_timedreceive
244 64 mq_notify sys_mq_notify
245 common mq_getsetattr sys_mq_getsetattr
246 64 kexec_load sys_kexec_load
247 64 waitid sys_waitid
248 common add_key sys_add_key
249 common request_key sys_request_key
250 common keyctl sys_keyctl
251 common ioprio_set sys_ioprio_set
252 common ioprio_get sys_ioprio_get
253 common inotify_init sys_inotify_init
254 common inotify_add_watch sys_inotify_add_watch
255 common inotify_rm_watch sys_inotify_rm_watch
256 common migrate_pages sys_migrate_pages
257 common openat sys_openat
258 common mkdirat sys_mkdirat
259 common mknodat sys_mknodat
260 common fchownat sys_fchownat
261 common futimesat sys_futimesat
262 common newfstatat sys_newfstatat
263 common unlinkat sys_unlinkat
264 common renameat sys_renameat
265 common linkat sys_linkat
266 common symlinkat sys_symlinkat
267 common readlinkat sys_readlinkat
268 common fchmodat sys_fchmodat
269 common faccessat sys_faccessat
270 common pselect6 sys_pselect6
271 common ppoll sys_ppoll
272 common unshare sys_unshare
273 64 set_robust_list sys_set_robust_list
274 64 get_robust_list sys_get_robust_list
275 common splice sys_splice
276 common tee sys_tee
277 common sync_file_range sys_sync_file_range
278 64 vmsplice sys_vmsplice
279 64 move_pages sys_move_pages
280 common utimensat sys_utimensat
281 common epoll_pwait sys_epoll_pwait
282 common signalfd sys_signalfd
283 common timerfd_create sys_timerfd_create
284 common eventfd sys_eventfd
285 common fallocate sys_fallocate
286 common timerfd_settime sys_timerfd_settime
287 common timerfd_gettime sys_timerfd_gettime
288 common accept4 sys_accept4
289 common signalfd4 sys_signalfd4
290 common eventfd2 sys_eventfd2
291 common epoll_create1 sys_epoll_create1
292 common dup3 sys_dup3
293 common pipe2 sys_pipe2
294 common inotify_init1 sys_inotify_init1
295 64 preadv sys_preadv
296 64 pwritev sys_pwritev
297 64 rt_tgsigqueueinfo sys_rt_tgsigqueueinfo
298 common perf_event_open sys_perf_event_open
299 64 recvmmsg sys_recvmmsg
300 common fanotify_init sys_fanotify_init
301 common fanotify_mark sys_fanotify_mark
302 common prlimit64 sys_prlimit64
303 common name_to_handle_at sys_name_to_handle_at
304 common open_by_handle_at sys_open_by_handle_at
305 common clock_adjtime sys_clock_adjtime
306 common syncfs sys_syncfs
307 64 sendmmsg sys_sendmmsg
308 common setns sys_setns
309 common getcpu sys_getcpu
310 64 process_vm_readv sys_process_vm_readv
311 64 process_vm_writev sys_process_vm_writev
312 common kcmp sys_kcmp
313 common finit_module sys_finit_module
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2
317 common seccomp sys_seccomp
318 common getrandom sys_getrandom
319 common memfd_create sys_memfd_create
320 common kexec_file_load sys_kexec_file_load
321 common bpf sys_bpf
322 64 execveat sys_execveat/ptregs
323 common userfaultfd sys_userfaultfd
324 common membarrier sys_membarrier
325 common mlock2 sys_mlock2
326 common copy_file_range sys_copy_file_range
#
# x32-specific system call numbers start at 512 to avoid cache impact
# for native 64-bit operation.
#
512 x32 rt_sigaction compat_sys_rt_sigaction
513 x32 rt_sigreturn sys32_x32_rt_sigreturn
514 x32 ioctl compat_sys_ioctl
515 x32 readv compat_sys_readv
516 x32 writev compat_sys_writev
517 x32 recvfrom compat_sys_recvfrom
518 x32 sendmsg compat_sys_sendmsg
519 x32 recvmsg compat_sys_recvmsg
520 x32 execve compat_sys_execve/ptregs
521 x32 ptrace compat_sys_ptrace
522 x32 rt_sigpending compat_sys_rt_sigpending
523 x32 rt_sigtimedwait compat_sys_rt_sigtimedwait
524 x32 rt_sigqueueinfo compat_sys_rt_sigqueueinfo
525 x32 sigaltstack compat_sys_sigaltstack
526 x32 timer_create compat_sys_timer_create
527 x32 mq_notify compat_sys_mq_notify
528 x32 kexec_load compat_sys_kexec_load
529 x32 waitid compat_sys_waitid
530 x32 set_robust_list compat_sys_set_robust_list
531 x32 get_robust_list compat_sys_get_robust_list
532 x32 vmsplice compat_sys_vmsplice
533 x32 move_pages compat_sys_move_pages
534 x32 preadv compat_sys_preadv64
535 x32 pwritev compat_sys_pwritev64
536 x32 rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
537 x32 recvmmsg compat_sys_recvmmsg
538 x32 sendmmsg compat_sys_sendmmsg
539 x32 process_vm_readv compat_sys_process_vm_readv
540 x32 process_vm_writev compat_sys_process_vm_writev
541 x32 setsockopt compat_sys_setsockopt
542 x32 getsockopt compat_sys_getsockopt
543 x32 io_setup compat_sys_io_setup
544 x32 io_submit compat_sys_io_submit
545 x32 execveat compat_sys_execveat/ptregs
#!/bin/sh
in="$1"
arch="$2"
syscall_macro() {
nr="$1"
name="$2"
echo " [$nr] = \"$name\","
}
emit() {
nr="$1"
entry="$2"
syscall_macro "$nr" "$entry"
}
echo "static const char *syscalltbl_${arch}[] = {"
sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX)
grep '^[0-9]' "$in" | sort -n > $sorted_table
max_nr=0
while read nr abi name entry compat; do
if [ $nr -ge 512 ] ; then # discard compat sycalls
break
fi
emit "$nr" "$name"
max_nr=$nr
done < $sorted_table
rm -f $sorted_table
echo "};"
echo "#define SYSCALLTBL_${arch}_MAX_ID ${max_nr}"
...@@ -1961,6 +1961,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1961,6 +1961,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.attr = process_attr, .attr = process_attr,
.event_update = perf_event__process_event_update,
.tracing_data = perf_event__process_tracing_data, .tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.id_index = perf_event__process_id_index, .id_index = perf_event__process_id_index,
......
...@@ -34,8 +34,9 @@ ...@@ -34,8 +34,9 @@
#include "trace-event.h" #include "trace-event.h"
#include "util/parse-events.h" #include "util/parse-events.h"
#include "util/bpf-loader.h" #include "util/bpf-loader.h"
#include "syscalltbl.h"
#include <libaudit.h> #include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
#include <stdlib.h> #include <stdlib.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <linux/futex.h> #include <linux/futex.h>
...@@ -112,6 +113,56 @@ ...@@ -112,6 +113,56 @@
# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
#endif #endif
struct trace {
struct perf_tool tool;
struct syscalltbl *sctbl;
struct {
int max;
struct syscall *table;
struct {
struct perf_evsel *sys_enter,
*sys_exit;
} events;
} syscalls;
struct record_opts opts;
struct perf_evlist *evlist;
struct machine *host;
struct thread *current;
u64 base_time;
FILE *output;
unsigned long nr_events;
struct strlist *ev_qualifier;
struct {
size_t nr;
int *entries;
} ev_qualifier_ids;
struct intlist *tid_list;
struct intlist *pid_list;
struct {
size_t nr;
pid_t *entries;
} filter_pids;
double duration_filter;
double runtime_ms;
struct {
u64 vfs_getname,
proc_getname;
} stats;
bool not_ev_qualifier;
bool live;
bool full_time;
bool sched;
bool multiple_threads;
bool summary;
bool summary_only;
bool show_comm;
bool show_tool_stats;
bool trace_syscalls;
bool force;
bool vfs_getname;
int trace_pgfaults;
int open_id;
};
struct tp_field { struct tp_field {
int offset; int offset;
...@@ -1073,12 +1124,18 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, ...@@ -1073,12 +1124,18 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
.arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
.arg_parm = { [arg] = &strarray__##array, } .arg_parm = { [arg] = &strarray__##array, }
#include "trace/beauty/pid.c"
#include "trace/beauty/mode_t.c"
#include "trace/beauty/sched_policy.c"
#include "trace/beauty/waitid_options.c"
static struct syscall_fmt { static struct syscall_fmt {
const char *name; const char *name;
const char *alias; const char *alias;
size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg); size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
void *arg_parm[6]; void *arg_parm[6];
bool errmsg; bool errmsg;
bool errpid;
bool timeout; bool timeout;
bool hexret; bool hexret;
} syscall_fmts[] = { } syscall_fmts[] = {
...@@ -1096,6 +1153,7 @@ static struct syscall_fmt { ...@@ -1096,6 +1153,7 @@ static struct syscall_fmt {
{ .name = "chroot", .errmsg = true, { .name = "chroot", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
{ .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
{ .name = "clone", .errpid = true, },
{ .name = "close", .errmsg = true, { .name = "close", .errmsg = true,
.arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
{ .name = "connect", .errmsg = true, }, { .name = "connect", .errmsg = true, },
...@@ -1161,6 +1219,9 @@ static struct syscall_fmt { ...@@ -1161,6 +1219,9 @@ static struct syscall_fmt {
{ .name = "getdents64", .errmsg = true, { .name = "getdents64", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
{ .name = "getpid", .errpid = true, },
{ .name = "getpgid", .errpid = true, },
{ .name = "getppid", .errpid = true, },
{ .name = "getrandom", .errmsg = true, { .name = "getrandom", .errmsg = true,
.arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, }, .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
{ .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
...@@ -1304,6 +1365,8 @@ static struct syscall_fmt { ...@@ -1304,6 +1365,8 @@ static struct syscall_fmt {
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
{ .name = "rt_tgsigqueueinfo", .errmsg = true, { .name = "rt_tgsigqueueinfo", .errmsg = true,
.arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
{ .name = "sched_setscheduler", .errmsg = true,
.arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
{ .name = "seccomp", .errmsg = true, { .name = "seccomp", .errmsg = true,
.arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */ .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
[1] = SCA_SECCOMP_FLAGS, /* flags */ }, }, [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
...@@ -1317,7 +1380,9 @@ static struct syscall_fmt { ...@@ -1317,7 +1380,9 @@ static struct syscall_fmt {
{ .name = "sendto", .errmsg = true, { .name = "sendto", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ .arg_scnprintf = { [0] = SCA_FD, /* fd */
[3] = SCA_MSG_FLAGS, /* flags */ }, }, [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "set_tid_address", .errpid = true, },
{ .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
{ .name = "setpgid", .errmsg = true, },
{ .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
{ .name = "setxattr", .errmsg = true, { .name = "setxattr", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
...@@ -1360,6 +1425,10 @@ static struct syscall_fmt { ...@@ -1360,6 +1425,10 @@ static struct syscall_fmt {
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
{ .name = "vmsplice", .errmsg = true, { .name = "vmsplice", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "wait4", .errpid = true,
.arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
{ .name = "waitid", .errpid = true,
.arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
{ .name = "write", .errmsg = true, { .name = "write", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "writev", .errmsg = true, { .name = "writev", .errmsg = true,
...@@ -1471,59 +1540,6 @@ static struct thread_trace *thread__trace(struct thread *thread, FILE *fp) ...@@ -1471,59 +1540,6 @@ static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
static const size_t trace__entry_str_size = 2048; static const size_t trace__entry_str_size = 2048;
struct trace {
struct perf_tool tool;
struct {
int machine;
int open_id;
} audit;
struct {
int max;
struct syscall *table;
struct {
struct perf_evsel *sys_enter,
*sys_exit;
} events;
} syscalls;
struct record_opts opts;
struct perf_evlist *evlist;
struct machine *host;
struct thread *current;
u64 base_time;
FILE *output;
unsigned long nr_events;
struct strlist *ev_qualifier;
struct {
size_t nr;
int *entries;
} ev_qualifier_ids;
struct intlist *tid_list;
struct intlist *pid_list;
struct {
size_t nr;
pid_t *entries;
} filter_pids;
double duration_filter;
double runtime_ms;
struct {
u64 vfs_getname,
proc_getname;
} stats;
bool not_ev_qualifier;
bool live;
bool full_time;
bool sched;
bool multiple_threads;
bool summary;
bool summary_only;
bool show_comm;
bool show_tool_stats;
bool trace_syscalls;
bool force;
bool vfs_getname;
int trace_pgfaults;
};
static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
{ {
struct thread_trace *ttrace = thread__priv(thread); struct thread_trace *ttrace = thread__priv(thread);
...@@ -1749,6 +1765,10 @@ static int syscall__set_arg_fmts(struct syscall *sc) ...@@ -1749,6 +1765,10 @@ static int syscall__set_arg_fmts(struct syscall *sc)
sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
else if (field->flags & FIELD_IS_POINTER) else if (field->flags & FIELD_IS_POINTER)
sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
else if (strcmp(field->type, "pid_t") == 0)
sc->arg_scnprintf[idx] = SCA_PID;
else if (strcmp(field->type, "umode_t") == 0)
sc->arg_scnprintf[idx] = SCA_MODE_T;
++idx; ++idx;
} }
...@@ -1759,7 +1779,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) ...@@ -1759,7 +1779,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
{ {
char tp_name[128]; char tp_name[128];
struct syscall *sc; struct syscall *sc;
const char *name = audit_syscall_to_name(id, trace->audit.machine); const char *name = syscalltbl__name(trace->sctbl, id);
if (name == NULL) if (name == NULL)
return -1; return -1;
...@@ -1834,7 +1854,7 @@ static int trace__validate_ev_qualifier(struct trace *trace) ...@@ -1834,7 +1854,7 @@ static int trace__validate_ev_qualifier(struct trace *trace)
strlist__for_each(pos, trace->ev_qualifier) { strlist__for_each(pos, trace->ev_qualifier) {
const char *sc = pos->s; const char *sc = pos->s;
int id = audit_name_to_syscall(sc, trace->audit.machine); int id = syscalltbl__id(trace->sctbl, sc);
if (id < 0) { if (id < 0) {
if (err == 0) { if (err == 0) {
...@@ -2116,7 +2136,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ...@@ -2116,7 +2136,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
ret = perf_evsel__sc_tp_uint(evsel, ret, sample); ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) { if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
trace__set_fd_pathname(thread, ret, ttrace->filename.name); trace__set_fd_pathname(thread, ret, ttrace->filename.name);
ttrace->filename.pending_open = false; ttrace->filename.pending_open = false;
++trace->stats.vfs_getname; ++trace->stats.vfs_getname;
...@@ -2147,7 +2167,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ...@@ -2147,7 +2167,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
if (sc->fmt == NULL) { if (sc->fmt == NULL) {
signed_print: signed_print:
fprintf(trace->output, ") = %ld", ret); fprintf(trace->output, ") = %ld", ret);
} else if (ret < 0 && sc->fmt->errmsg) { } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
char bf[STRERR_BUFSIZE]; char bf[STRERR_BUFSIZE];
const char *emsg = strerror_r(-ret, bf, sizeof(bf)), const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
*e = audit_errno_to_name(-ret); *e = audit_errno_to_name(-ret);
...@@ -2157,7 +2177,16 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ...@@ -2157,7 +2177,16 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
fprintf(trace->output, ") = 0 Timeout"); fprintf(trace->output, ") = 0 Timeout");
else if (sc->fmt->hexret) else if (sc->fmt->hexret)
fprintf(trace->output, ") = %#lx", ret); fprintf(trace->output, ") = %#lx", ret);
else else if (sc->fmt->errpid) {
struct thread *child = machine__find_thread(trace->host, ret, ret);
if (child != NULL) {
fprintf(trace->output, ") = %ld", ret);
if (child->comm_set)
fprintf(trace->output, " (%s)", thread__comm_str(child));
thread__put(child);
}
} else
goto signed_print; goto signed_print;
fputc('\n', trace->output); fputc('\n', trace->output);
...@@ -3159,10 +3188,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -3159,10 +3188,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
NULL NULL
}; };
struct trace trace = { struct trace trace = {
.audit = {
.machine = audit_detect_machine(),
.open_id = audit_name_to_syscall("open", trace.audit.machine),
},
.syscalls = { .syscalls = {
. max = -1, . max = -1,
}, },
...@@ -3237,8 +3262,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -3237,8 +3262,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
signal(SIGFPE, sighandler_dump_stack); signal(SIGFPE, sighandler_dump_stack);
trace.evlist = perf_evlist__new(); trace.evlist = perf_evlist__new();
trace.sctbl = syscalltbl__new();
if (trace.evlist == NULL) { if (trace.evlist == NULL || trace.sctbl == NULL) {
pr_err("Not enough memory to run!\n"); pr_err("Not enough memory to run!\n");
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -3276,6 +3302,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -3276,6 +3302,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
} }
} }
trace.open_id = syscalltbl__id(trace.sctbl, "open");
if (ev_qualifier_str != NULL) { if (ev_qualifier_str != NULL) {
const char *s = ev_qualifier_str; const char *s = ev_qualifier_str;
struct strlist_config slist_config = { struct strlist_config slist_config = {
......
...@@ -27,7 +27,7 @@ NO_PERF_REGS := 1 ...@@ -27,7 +27,7 @@ NO_PERF_REGS := 1
ifeq ($(ARCH),x86) ifeq ($(ARCH),x86)
$(call detected,CONFIG_X86) $(call detected,CONFIG_X86)
ifeq (${IS_64_BIT}, 1) ifeq (${IS_64_BIT}, 1)
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
$(call detected,CONFIG_X86_64) $(call detected,CONFIG_X86_64)
...@@ -268,6 +268,12 @@ else ...@@ -268,6 +268,12 @@ else
ifneq ($(feature-dwarf), 1) ifneq ($(feature-dwarf), 1)
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
NO_DWARF := 1 NO_DWARF := 1
else
ifneq ($(feature-dwarf_getlocations), 1)
msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157);
else
CFLAGS += -DHAVE_DWARF_GETLOCATIONS
endif # dwarf_getlocations
endif # Dwarf support endif # Dwarf support
endif # libelf support endif # libelf support
endif # NO_LIBELF endif # NO_LIBELF
...@@ -289,9 +295,6 @@ ifndef NO_LIBELF ...@@ -289,9 +295,6 @@ ifndef NO_LIBELF
CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
endif endif
# include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile
ifndef NO_DWARF ifndef NO_DWARF
ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
......
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* From include/linux/stat.h */
#ifndef S_IRWXUGO
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
#endif
#ifndef S_IALLUGO
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#endif
#ifndef S_IRUGO
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
#endif
#ifndef S_IWUGO
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
#endif
#ifndef S_IXUGO
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
#endif
static size_t syscall_arg__scnprintf_mode_t(char *bf, size_t size, struct syscall_arg *arg)
{
int printed = 0, mode = arg->val;
#define P_MODE(n) \
if ((mode & S_##n) == S_##n) { \
printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
mode &= ~S_##n; \
}
P_MODE(IALLUGO);
P_MODE(IRWXUGO);
P_MODE(IRUGO);
P_MODE(IWUGO);
P_MODE(IXUGO);
P_MODE(IFMT);
P_MODE(IFSOCK);
P_MODE(IFLNK);
P_MODE(IFREG);
P_MODE(IFBLK);
P_MODE(IFDIR);
P_MODE(IFCHR);
P_MODE(IFIFO);
P_MODE(ISUID);
P_MODE(ISGID);
P_MODE(ISVTX);
P_MODE(IRWXU);
P_MODE(IRUSR);
P_MODE(IWUSR);
P_MODE(IXUSR);
P_MODE(IRWXG);
P_MODE(IRGRP);
P_MODE(IWGRP);
P_MODE(IXGRP);
P_MODE(IRWXO);
P_MODE(IROTH);
P_MODE(IWOTH);
P_MODE(IXOTH);
#undef P_MODE
if (mode)
printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", mode);
return printed;
}
#define SCA_MODE_T syscall_arg__scnprintf_mode_t
static size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg)
{
int pid = arg->val;
struct trace *trace = arg->trace;
size_t printed = scnprintf(bf, size, "%d", pid);
struct thread *thread = machine__find_thread(trace->host, pid, pid);
if (thread != NULL) {
if (thread->comm_set)
printed += scnprintf(bf + printed, size - printed,
" (%s)", thread__comm_str(thread));
thread__put(thread);
}
return printed;
}
#define SCA_PID syscall_arg__scnprintf_pid
#include <sched.h>
/*
* Not defined anywhere else, probably, just to make sure we
* catch future flags
*/
#define SCHED_POLICY_MASK 0xff
#ifndef SCHED_DEADLINE
#define SCHED_DEADLINE 6
#endif
static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size,
struct syscall_arg *arg)
{
const char *policies[] = {
"NORMAL", "FIFO", "RR", "BATCH", "ISO", "IDLE", "DEADLINE",
};
size_t printed;
int policy = arg->val,
flags = policy & ~SCHED_POLICY_MASK;
policy &= SCHED_POLICY_MASK;
if (policy <= SCHED_DEADLINE)
printed = scnprintf(bf, size, "%s", policies[policy]);
else
printed = scnprintf(bf, size, "%#x", policy);
#define P_POLICY_FLAG(n) \
if (flags & SCHED_##n) { \
printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
flags &= ~SCHED_##n; \
}
P_POLICY_FLAG(RESET_ON_FORK);
#undef P_POLICY_FLAG
if (flags)
printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
return printed;
}
#define SCA_SCHED_POLICY syscall_arg__scnprintf_sched_policy
#include <sys/types.h>
#include <sys/wait.h>
static size_t syscall_arg__scnprintf_waitid_options(char *bf, size_t size,
struct syscall_arg *arg)
{
int printed = 0, options = arg->val;
#define P_OPTION(n) \
if (options & W##n) { \
printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
options &= ~W##n; \
}
P_OPTION(NOHANG);
P_OPTION(UNTRACED);
P_OPTION(CONTINUED);
#undef P_OPTION
if (options)
printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", options);
return printed;
}
#define SCA_WAITID_OPTIONS syscall_arg__scnprintf_waitid_options
...@@ -1607,9 +1607,8 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows ...@@ -1607,9 +1607,8 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
dummy_hpp.buf[ret] = '\0'; dummy_hpp.buf[ret] = '\0';
rtrim(dummy_hpp.buf);
start = ltrim(dummy_hpp.buf); start = trim(dummy_hpp.buf);
ret = strlen(start); ret = strlen(start);
if (start != dummy_hpp.buf) if (start != dummy_hpp.buf)
......
...@@ -569,9 +569,8 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, ...@@ -569,9 +569,8 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
first_col = false; first_col = false;
fmt->header(fmt, hpp, hists_to_evsel(hists)); fmt->header(fmt, hpp, hists_to_evsel(hists));
rtrim(hpp->buf);
header_width += fprintf(fp, "%s", ltrim(hpp->buf)); header_width += fprintf(fp, "%s", trim(hpp->buf));
} }
} }
......
...@@ -38,6 +38,7 @@ libperf-y += machine.o ...@@ -38,6 +38,7 @@ libperf-y += machine.o
libperf-y += map.o libperf-y += map.o
libperf-y += pstack.o libperf-y += pstack.o
libperf-y += session.o libperf-y += session.o
libperf-$(CONFIG_AUDIT) += syscalltbl.o
libperf-y += ordered-events.o libperf-y += ordered-events.o
libperf-y += comm.o libperf-y += comm.o
libperf-y += thread.o libperf-y += thread.o
...@@ -147,6 +148,10 @@ CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ET ...@@ -147,6 +148,10 @@ CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ET
CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
CFLAGS_parse-events.o += -Wno-redundant-decls CFLAGS_parse-events.o += -Wno-redundant-decls
$(OUTPUT)util/syscalltbl.o: util/syscalltbl.c arch/x86/entry/syscalls/syscall_64.tbl $(OUTPUT)arch/x86/include/generated/asm/syscalls_64.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
$(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
$(call rule_mkdir) $(call rule_mkdir)
$(call if_changed_dep,cc_o_c) $(call if_changed_dep,cc_o_c)
......
...@@ -381,11 +381,11 @@ static int perf_buildid_config(const char *var, const char *value) ...@@ -381,11 +381,11 @@ static int perf_buildid_config(const char *var, const char *value)
{ {
/* same dir for all commands */ /* same dir for all commands */
if (!strcmp(var, "buildid.dir")) { if (!strcmp(var, "buildid.dir")) {
const char *dirname = perf_config_dirname(var, value); const char *dir = perf_config_dirname(var, value);
if (!dirname) if (!dir)
return -1; return -1;
strncpy(buildid_dir, dirname, MAXPATHLEN-1); strncpy(buildid_dir, dir, MAXPATHLEN-1);
buildid_dir[MAXPATHLEN-1] = '\0'; buildid_dir[MAXPATHLEN-1] = '\0';
} }
......
...@@ -959,6 +959,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) ...@@ -959,6 +959,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf)
return 0; return 0;
} }
#ifdef HAVE_DWARF_GETLOCATIONS
/** /**
* die_get_var_innermost_scope - Get innermost scope range of given variable DIE * die_get_var_innermost_scope - Get innermost scope range of given variable DIE
* @sp_die: a subprogram DIE * @sp_die: a subprogram DIE
...@@ -1080,3 +1081,11 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) ...@@ -1080,3 +1081,11 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf)
return ret; return ret;
} }
#else
int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
Dwarf_Die *vr_die __maybe_unused,
struct strbuf *buf __maybe_unused)
{
return -ENOTSUP;
}
#endif
...@@ -431,6 +431,13 @@ u64 map__rip_2objdump(struct map *map, u64 rip) ...@@ -431,6 +431,13 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
if (map->dso->rel) if (map->dso->rel)
return rip - map->pgoff; return rip - map->pgoff;
/*
* kernel modules also have DSO_TYPE_USER in dso->kernel,
* but all kernel modules are ET_REL, so won't get here.
*/
if (map->dso->kernel == DSO_TYPE_USER)
return rip + map->dso->text_offset;
return map->unmap_ip(map, rip) - map->reloc; return map->unmap_ip(map, rip) - map->reloc;
} }
...@@ -454,6 +461,13 @@ u64 map__objdump_2mem(struct map *map, u64 ip) ...@@ -454,6 +461,13 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
if (map->dso->rel) if (map->dso->rel)
return map->unmap_ip(map, ip + map->pgoff); return map->unmap_ip(map, ip + map->pgoff);
/*
* kernel modules also have DSO_TYPE_USER in dso->kernel,
* but all kernel modules are ET_REL, so won't get here.
*/
if (map->dso->kernel == DSO_TYPE_USER)
return map->unmap_ip(map, ip - map->dso->text_offset);
return ip + map->reloc; return ip + map->reloc;
} }
......
...@@ -283,18 +283,27 @@ static SV *perl_process_callchain(struct perf_sample *sample, ...@@ -283,18 +283,27 @@ static SV *perl_process_callchain(struct perf_sample *sample,
if (!elem) if (!elem)
goto exit; goto exit;
hv_stores(elem, "ip", newSVuv(node->ip)); if (!hv_stores(elem, "ip", newSVuv(node->ip))) {
hv_undef(elem);
goto exit;
}
if (node->sym) { if (node->sym) {
HV *sym = newHV(); HV *sym = newHV();
if (!sym) if (!sym) {
hv_undef(elem);
goto exit;
}
if (!hv_stores(sym, "start", newSVuv(node->sym->start)) ||
!hv_stores(sym, "end", newSVuv(node->sym->end)) ||
!hv_stores(sym, "binding", newSVuv(node->sym->binding)) ||
!hv_stores(sym, "name", newSVpvn(node->sym->name,
node->sym->namelen)) ||
!hv_stores(elem, "sym", newRV_noinc((SV*)sym))) {
hv_undef(sym);
hv_undef(elem);
goto exit; goto exit;
hv_stores(sym, "start", newSVuv(node->sym->start)); }
hv_stores(sym, "end", newSVuv(node->sym->end));
hv_stores(sym, "binding", newSVuv(node->sym->binding));
hv_stores(sym, "name", newSVpvn(node->sym->name,
node->sym->namelen));
hv_stores(elem, "sym", newRV_noinc((SV*)sym));
} }
if (node->map) { if (node->map) {
...@@ -306,7 +315,10 @@ static SV *perl_process_callchain(struct perf_sample *sample, ...@@ -306,7 +315,10 @@ static SV *perl_process_callchain(struct perf_sample *sample,
else if (map->dso->name) else if (map->dso->name)
dsoname = map->dso->name; dsoname = map->dso->name;
} }
hv_stores(elem, "dso", newSVpv(dsoname,0)); if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) {
hv_undef(elem);
goto exit;
}
} }
callchain_cursor_advance(&callchain_cursor); callchain_cursor_advance(&callchain_cursor);
......
...@@ -709,17 +709,10 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, ...@@ -709,17 +709,10 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
if (ss->opdshdr.sh_type != SHT_PROGBITS) if (ss->opdshdr.sh_type != SHT_PROGBITS)
ss->opdsec = NULL; ss->opdsec = NULL;
if (dso->kernel == DSO_TYPE_USER) { if (dso->kernel == DSO_TYPE_USER)
GElf_Shdr shdr; ss->adjust_symbols = true;
ss->adjust_symbols = (ehdr.e_type == ET_EXEC || else
ehdr.e_type == ET_REL ||
dso__is_vdso(dso) ||
elf_section_by_name(elf, &ehdr, &shdr,
".gnu.prelink_undo",
NULL) != NULL);
} else {
ss->adjust_symbols = elf__needs_adjust_symbols(ehdr); ss->adjust_symbols = elf__needs_adjust_symbols(ehdr);
}
ss->name = strdup(name); ss->name = strdup(name);
if (!ss->name) { if (!ss->name) {
......
/*
* System call table mapper
*
* (C) 2016 Arnaldo Carvalho de Melo <acme@redhat.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include "syscalltbl.h"
#include <stdlib.h>
#ifdef HAVE_SYSCALL_TABLE
#include <linux/compiler.h>
#include <string.h>
#include "util.h"
#if defined(__x86_64__)
#include <asm/syscalls_64.c>
const int syscalltbl_native_max_id = SYSCALLTBL_x86_64_MAX_ID;
static const char **syscalltbl_native = syscalltbl_x86_64;
#endif
struct syscall {
int id;
const char *name;
};
static int syscallcmpname(const void *vkey, const void *ventry)
{
const char *key = vkey;
const struct syscall *entry = ventry;
return strcmp(key, entry->name);
}
static int syscallcmp(const void *va, const void *vb)
{
const struct syscall *a = va, *b = vb;
return strcmp(a->name, b->name);
}
static int syscalltbl__init_native(struct syscalltbl *tbl)
{
int nr_entries = 0, i, j;
struct syscall *entries;
for (i = 0; i <= syscalltbl_native_max_id; ++i)
if (syscalltbl_native[i])
++nr_entries;
entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries);
if (tbl->syscalls.entries == NULL)
return -1;
for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) {
if (syscalltbl_native[i]) {
entries[j].name = syscalltbl_native[i];
entries[j].id = i;
++j;
}
}
qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp);
tbl->syscalls.nr_entries = nr_entries;
return 0;
}
struct syscalltbl *syscalltbl__new(void)
{
struct syscalltbl *tbl = malloc(sizeof(*tbl));
if (tbl) {
if (syscalltbl__init_native(tbl)) {
free(tbl);
return NULL;
}
}
return tbl;
}
void syscalltbl__delete(struct syscalltbl *tbl)
{
zfree(&tbl->syscalls.entries);
free(tbl);
}
const char *syscalltbl__name(const struct syscalltbl *tbl __maybe_unused, int id)
{
return id <= syscalltbl_native_max_id ? syscalltbl_native[id]: NULL;
}
int syscalltbl__id(struct syscalltbl *tbl, const char *name)
{
struct syscall *sc = bsearch(name, tbl->syscalls.entries,
tbl->syscalls.nr_entries, sizeof(*sc),
syscallcmpname);
return sc ? sc->id : -1;
}
#else /* HAVE_SYSCALL_TABLE */
#include <libaudit.h>
struct syscalltbl *syscalltbl__new(void)
{
struct syscalltbl *tbl = malloc(sizeof(*tbl));
if (tbl)
tbl->audit_machine = audit_detect_machine();
return tbl;
}
void syscalltbl__delete(struct syscalltbl *tbl)
{
free(tbl);
}
const char *syscalltbl__name(const struct syscalltbl *tbl, int id)
{
return audit_syscall_to_name(id, tbl->audit_machine);
}
int syscalltbl__id(struct syscalltbl *tbl, const char *name)
{
return audit_name_to_syscall(name, tbl->audit_machine);
}
#endif /* HAVE_SYSCALL_TABLE */
#ifndef __PERF_SYSCALLTBL_H
#define __PERF_SYSCALLTBL_H
struct syscalltbl {
union {
int audit_machine;
struct {
int nr_entries;
void *entries;
} syscalls;
};
};
struct syscalltbl *syscalltbl__new(void);
void syscalltbl__delete(struct syscalltbl *tbl);
const char *syscalltbl__name(const struct syscalltbl *tbl, int id);
int syscalltbl__id(struct syscalltbl *tbl, const char *name);
#endif /* __PERF_SYSCALLTBL_H */
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
#include "symbol.h" #include "symbol.h"
#include <strlist.h> #include <strlist.h>
#include <intlist.h> #include <intlist.h>
#ifdef HAVE_LIBUNWIND_SUPPORT
#include <libunwind.h>
#endif
struct thread_stack; struct thread_stack;
...@@ -32,6 +35,9 @@ struct thread { ...@@ -32,6 +35,9 @@ struct thread {
void *priv; void *priv;
struct thread_stack *ts; struct thread_stack *ts;
#ifdef HAVE_LIBUNWIND_SUPPORT
unw_addr_space_t addr_space;
#endif
}; };
struct machine; struct machine;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "symbol.h" #include "symbol.h"
#include "util.h" #include "util.h"
#include "debug.h" #include "debug.h"
#include "asm/bug.h"
extern int extern int
UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
...@@ -580,43 +581,33 @@ static unw_accessors_t accessors = { ...@@ -580,43 +581,33 @@ static unw_accessors_t accessors = {
int unwind__prepare_access(struct thread *thread) int unwind__prepare_access(struct thread *thread)
{ {
unw_addr_space_t addr_space;
if (callchain_param.record_mode != CALLCHAIN_DWARF) if (callchain_param.record_mode != CALLCHAIN_DWARF)
return 0; return 0;
addr_space = unw_create_addr_space(&accessors, 0); thread->addr_space = unw_create_addr_space(&accessors, 0);
if (!addr_space) { if (!thread->addr_space) {
pr_err("unwind: Can't create unwind address space.\n"); pr_err("unwind: Can't create unwind address space.\n");
return -ENOMEM; return -ENOMEM;
} }
unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL);
thread__set_priv(thread, addr_space);
return 0; return 0;
} }
void unwind__flush_access(struct thread *thread) void unwind__flush_access(struct thread *thread)
{ {
unw_addr_space_t addr_space;
if (callchain_param.record_mode != CALLCHAIN_DWARF) if (callchain_param.record_mode != CALLCHAIN_DWARF)
return; return;
addr_space = thread__priv(thread); unw_flush_cache(thread->addr_space, 0, 0);
unw_flush_cache(addr_space, 0, 0);
} }
void unwind__finish_access(struct thread *thread) void unwind__finish_access(struct thread *thread)
{ {
unw_addr_space_t addr_space;
if (callchain_param.record_mode != CALLCHAIN_DWARF) if (callchain_param.record_mode != CALLCHAIN_DWARF)
return; return;
addr_space = thread__priv(thread); unw_destroy_addr_space(thread->addr_space);
unw_destroy_addr_space(addr_space);
} }
static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
...@@ -639,7 +630,9 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, ...@@ -639,7 +630,9 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
* unwind itself. * unwind itself.
*/ */
if (max_stack - 1 > 0) { if (max_stack - 1 > 0) {
addr_space = thread__priv(ui->thread); WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL");
addr_space = ui->thread->addr_space;
if (addr_space == NULL) if (addr_space == NULL)
return -1; return -1;
......
...@@ -254,6 +254,11 @@ int hex2u64(const char *ptr, u64 *val); ...@@ -254,6 +254,11 @@ int hex2u64(const char *ptr, u64 *val);
char *ltrim(char *s); char *ltrim(char *s);
char *rtrim(char *s); char *rtrim(char *s);
static inline char *trim(char *s)
{
return ltrim(rtrim(s));
}
void dump_stack(void); void dump_stack(void);
void sighandler_dump_stack(int sig); void sighandler_dump_stack(int sig);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment