mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf tooling updates form Ingo Molnar: "A final batch of perf tooling changes: mostly fixes and small improvements" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (29 commits) perf session: Add comment for perf_session__register_idle_thread() perf thread-stack: Fix thread stack processing for the idle task perf thread-stack: Allocate an array of thread stacks perf thread-stack: Factor out thread_stack__init() perf thread-stack: Allow for a thread stack array perf thread-stack: Avoid direct reference to the thread's stack perf thread-stack: Tidy thread_stack__bottom() usage perf thread-stack: Simplify some code in thread_stack__process() tools gpio: Allow overriding CFLAGS tools power turbostat: Override CFLAGS assignments and add LDFLAGS to build command tools thermal tmon: Allow overriding CFLAGS assignments tools power x86_energy_perf_policy: Override CFLAGS assignments and add LDFLAGS to build command perf c2c: Increase the HITM ratio limit for displayed cachelines perf c2c: Change the default coalesce setup perf trace beauty ioctl: Beautify USBDEVFS_ commands perf trace beauty: Export function to get the files for a thread perf trace: Wire up ioctl's USBDEBFS_ cmd table generator perf beauty ioctl: Add generator for USBDEVFS_ ioctl commands tools headers uapi: Grab a copy of usbdevice_fs.h perf trace: Store the major number for a file when storing its pathname ...
This commit is contained in:
		
						commit
						ac5eed2b41
					
				
					 27 changed files with 623 additions and 169 deletions
				
			
		| 
						 | 
					@ -82,8 +82,8 @@ FEATURE_TESTS_EXTRA :=                  \
 | 
				
			||||||
         cplus-demangle                 \
 | 
					         cplus-demangle                 \
 | 
				
			||||||
         hello                          \
 | 
					         hello                          \
 | 
				
			||||||
         libbabeltrace                  \
 | 
					         libbabeltrace                  \
 | 
				
			||||||
         liberty                        \
 | 
					         libbfd-liberty                 \
 | 
				
			||||||
         liberty-z                      \
 | 
					         libbfd-liberty-z               \
 | 
				
			||||||
         libunwind-debug-frame          \
 | 
					         libunwind-debug-frame          \
 | 
				
			||||||
         libunwind-debug-frame-arm      \
 | 
					         libunwind-debug-frame-arm      \
 | 
				
			||||||
         libunwind-debug-frame-aarch64  \
 | 
					         libunwind-debug-frame-aarch64  \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,8 +17,8 @@ FILES=                                          \
 | 
				
			||||||
         test-libbfd.bin                        \
 | 
					         test-libbfd.bin                        \
 | 
				
			||||||
         test-disassembler-four-args.bin        \
 | 
					         test-disassembler-four-args.bin        \
 | 
				
			||||||
         test-reallocarray.bin			\
 | 
					         test-reallocarray.bin			\
 | 
				
			||||||
         test-liberty.bin                       \
 | 
					         test-libbfd-liberty.bin                \
 | 
				
			||||||
         test-liberty-z.bin                     \
 | 
					         test-libbfd-liberty-z.bin              \
 | 
				
			||||||
         test-cplus-demangle.bin                \
 | 
					         test-cplus-demangle.bin                \
 | 
				
			||||||
         test-libelf.bin                        \
 | 
					         test-libelf.bin                        \
 | 
				
			||||||
         test-libelf-getphdrnum.bin             \
 | 
					         test-libelf-getphdrnum.bin             \
 | 
				
			||||||
| 
						 | 
					@ -210,7 +210,7 @@ $(OUTPUT)test-libpython-version.bin:
 | 
				
			||||||
	$(BUILD)
 | 
						$(BUILD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OUTPUT)test-libbfd.bin:
 | 
					$(OUTPUT)test-libbfd.bin:
 | 
				
			||||||
	$(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
 | 
						$(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OUTPUT)test-disassembler-four-args.bin:
 | 
					$(OUTPUT)test-disassembler-four-args.bin:
 | 
				
			||||||
	$(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes
 | 
						$(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes
 | 
				
			||||||
| 
						 | 
					@ -218,10 +218,10 @@ $(OUTPUT)test-disassembler-four-args.bin:
 | 
				
			||||||
$(OUTPUT)test-reallocarray.bin:
 | 
					$(OUTPUT)test-reallocarray.bin:
 | 
				
			||||||
	$(BUILD)
 | 
						$(BUILD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OUTPUT)test-liberty.bin:
 | 
					$(OUTPUT)test-libbfd-liberty.bin:
 | 
				
			||||||
	$(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
 | 
						$(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OUTPUT)test-liberty-z.bin:
 | 
					$(OUTPUT)test-libbfd-liberty-z.bin:
 | 
				
			||||||
	$(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
 | 
						$(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OUTPUT)test-cplus-demangle.bin:
 | 
					$(OUTPUT)test-cplus-demangle.bin:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@ endif
 | 
				
			||||||
# (this improves performance and avoids hard-to-debug behaviour);
 | 
					# (this improves performance and avoids hard-to-debug behaviour);
 | 
				
			||||||
MAKEFLAGS += -r
 | 
					MAKEFLAGS += -r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 | 
					override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
 | 
					ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
 | 
				
			||||||
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
 | 
					ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										201
									
								
								tools/include/uapi/linux/usbdevice_fs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								tools/include/uapi/linux/usbdevice_fs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,201 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
 | 
				
			||||||
 | 
					/*****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *	usbdevice_fs.h  --  USB device file system.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Copyright (C) 2000
 | 
				
			||||||
 | 
					 *          Thomas Sailer (sailer@ife.ee.ethz.ch)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *	it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *	the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *	(at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	This program is distributed in the hope that 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *	along with this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  History:
 | 
				
			||||||
 | 
					 *   0.1  04.01.2000  Created
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _UAPI_LINUX_USBDEVICE_FS_H
 | 
				
			||||||
 | 
					#define _UAPI_LINUX_USBDEVICE_FS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					#include <linux/magic.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* --------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* usbdevfs ioctl codes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_ctrltransfer {
 | 
				
			||||||
 | 
						__u8 bRequestType;
 | 
				
			||||||
 | 
						__u8 bRequest;
 | 
				
			||||||
 | 
						__u16 wValue;
 | 
				
			||||||
 | 
						__u16 wIndex;
 | 
				
			||||||
 | 
						__u16 wLength;
 | 
				
			||||||
 | 
						__u32 timeout;  /* in milliseconds */
 | 
				
			||||||
 | 
					 	void __user *data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_bulktransfer {
 | 
				
			||||||
 | 
						unsigned int ep;
 | 
				
			||||||
 | 
						unsigned int len;
 | 
				
			||||||
 | 
						unsigned int timeout; /* in milliseconds */
 | 
				
			||||||
 | 
						void __user *data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_setinterface {
 | 
				
			||||||
 | 
						unsigned int interface;
 | 
				
			||||||
 | 
						unsigned int altsetting;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_disconnectsignal {
 | 
				
			||||||
 | 
						unsigned int signr;
 | 
				
			||||||
 | 
						void __user *context;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBDEVFS_MAXDRIVERNAME 255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_getdriver {
 | 
				
			||||||
 | 
						unsigned int interface;
 | 
				
			||||||
 | 
						char driver[USBDEVFS_MAXDRIVERNAME + 1];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_connectinfo {
 | 
				
			||||||
 | 
						unsigned int devnum;
 | 
				
			||||||
 | 
						unsigned char slow;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_SHORT_NOT_OK	0x01
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_ISO_ASAP		0x02
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_BULK_CONTINUATION	0x04
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_NO_FSBR		0x20	/* Not used */
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_ZERO_PACKET	0x40
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_NO_INTERRUPT	0x80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_TYPE_ISO		   0
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_TYPE_INTERRUPT	   1
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_TYPE_CONTROL	   2
 | 
				
			||||||
 | 
					#define USBDEVFS_URB_TYPE_BULK		   3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_iso_packet_desc {
 | 
				
			||||||
 | 
						unsigned int length;
 | 
				
			||||||
 | 
						unsigned int actual_length;
 | 
				
			||||||
 | 
						unsigned int status;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_urb {
 | 
				
			||||||
 | 
						unsigned char type;
 | 
				
			||||||
 | 
						unsigned char endpoint;
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
						unsigned int flags;
 | 
				
			||||||
 | 
						void __user *buffer;
 | 
				
			||||||
 | 
						int buffer_length;
 | 
				
			||||||
 | 
						int actual_length;
 | 
				
			||||||
 | 
						int start_frame;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							int number_of_packets;	/* Only used for isoc urbs */
 | 
				
			||||||
 | 
							unsigned int stream_id;	/* Only used with bulk streams */
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						int error_count;
 | 
				
			||||||
 | 
						unsigned int signr;	/* signal to be sent on completion,
 | 
				
			||||||
 | 
									  or 0 if none should be sent. */
 | 
				
			||||||
 | 
						void __user *usercontext;
 | 
				
			||||||
 | 
						struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ioctls for talking directly to drivers */
 | 
				
			||||||
 | 
					struct usbdevfs_ioctl {
 | 
				
			||||||
 | 
						int	ifno;		/* interface 0..N ; negative numbers reserved */
 | 
				
			||||||
 | 
						int	ioctl_code;	/* MUST encode size + direction of data so the
 | 
				
			||||||
 | 
									 * macros in <asm/ioctl.h> give correct values */
 | 
				
			||||||
 | 
						void __user *data;	/* param buffer (in, or out) */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* You can do most things with hubs just through control messages,
 | 
				
			||||||
 | 
					 * except find out what device connects to what port. */
 | 
				
			||||||
 | 
					struct usbdevfs_hub_portinfo {
 | 
				
			||||||
 | 
						char nports;		/* number of downstream ports in this hub */
 | 
				
			||||||
 | 
						char port [127];	/* e.g. port 3 connects to device 27 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* System and bus capability flags */
 | 
				
			||||||
 | 
					#define USBDEVFS_CAP_ZERO_PACKET		0x01
 | 
				
			||||||
 | 
					#define USBDEVFS_CAP_BULK_CONTINUATION		0x02
 | 
				
			||||||
 | 
					#define USBDEVFS_CAP_NO_PACKET_SIZE_LIM		0x04
 | 
				
			||||||
 | 
					#define USBDEVFS_CAP_BULK_SCATTER_GATHER	0x08
 | 
				
			||||||
 | 
					#define USBDEVFS_CAP_REAP_AFTER_DISCONNECT	0x10
 | 
				
			||||||
 | 
					#define USBDEVFS_CAP_MMAP			0x20
 | 
				
			||||||
 | 
					#define USBDEVFS_CAP_DROP_PRIVILEGES		0x40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USBDEVFS_DISCONNECT_CLAIM flags & struct */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* disconnect-and-claim if the driver matches the driver field */
 | 
				
			||||||
 | 
					#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER	0x01
 | 
				
			||||||
 | 
					/* disconnect-and-claim except when the driver matches the driver field */
 | 
				
			||||||
 | 
					#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER	0x02
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_disconnect_claim {
 | 
				
			||||||
 | 
						unsigned int interface;
 | 
				
			||||||
 | 
						unsigned int flags;
 | 
				
			||||||
 | 
						char driver[USBDEVFS_MAXDRIVERNAME + 1];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbdevfs_streams {
 | 
				
			||||||
 | 
						unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
 | 
				
			||||||
 | 
						unsigned int num_eps;
 | 
				
			||||||
 | 
						unsigned char eps[0];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * USB_SPEED_* values returned by USBDEVFS_GET_SPEED are defined in
 | 
				
			||||||
 | 
					 * linux/usb/ch9.h
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
 | 
				
			||||||
 | 
					#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
 | 
				
			||||||
 | 
					#define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
 | 
				
			||||||
 | 
					#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
 | 
				
			||||||
 | 
					#define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
 | 
				
			||||||
 | 
					#define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
 | 
				
			||||||
 | 
					#define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
 | 
				
			||||||
 | 
					#define USBDEVFS_GETDRIVER         _IOW('U', 8, struct usbdevfs_getdriver)
 | 
				
			||||||
 | 
					#define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
 | 
				
			||||||
 | 
					#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
 | 
				
			||||||
 | 
					#define USBDEVFS_DISCARDURB        _IO('U', 11)
 | 
				
			||||||
 | 
					#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
 | 
				
			||||||
 | 
					#define USBDEVFS_REAPURB32         _IOW('U', 12, __u32)
 | 
				
			||||||
 | 
					#define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
 | 
				
			||||||
 | 
					#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, __u32)
 | 
				
			||||||
 | 
					#define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
 | 
				
			||||||
 | 
					#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
 | 
				
			||||||
 | 
					#define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
 | 
				
			||||||
 | 
					#define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
 | 
				
			||||||
 | 
					#define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
 | 
				
			||||||
 | 
					#define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
 | 
				
			||||||
 | 
					#define USBDEVFS_IOCTL32           _IOWR('U', 18, struct usbdevfs_ioctl32)
 | 
				
			||||||
 | 
					#define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
 | 
				
			||||||
 | 
					#define USBDEVFS_RESET             _IO('U', 20)
 | 
				
			||||||
 | 
					#define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
 | 
				
			||||||
 | 
					#define USBDEVFS_DISCONNECT        _IO('U', 22)
 | 
				
			||||||
 | 
					#define USBDEVFS_CONNECT           _IO('U', 23)
 | 
				
			||||||
 | 
					#define USBDEVFS_CLAIM_PORT        _IOR('U', 24, unsigned int)
 | 
				
			||||||
 | 
					#define USBDEVFS_RELEASE_PORT      _IOR('U', 25, unsigned int)
 | 
				
			||||||
 | 
					#define USBDEVFS_GET_CAPABILITIES  _IOR('U', 26, __u32)
 | 
				
			||||||
 | 
					#define USBDEVFS_DISCONNECT_CLAIM  _IOR('U', 27, struct usbdevfs_disconnect_claim)
 | 
				
			||||||
 | 
					#define USBDEVFS_ALLOC_STREAMS     _IOR('U', 28, struct usbdevfs_streams)
 | 
				
			||||||
 | 
					#define USBDEVFS_FREE_STREAMS      _IOR('U', 29, struct usbdevfs_streams)
 | 
				
			||||||
 | 
					#define USBDEVFS_DROP_PRIVILEGES   _IOW('U', 30, __u32)
 | 
				
			||||||
 | 
					#define USBDEVFS_GET_SPEED         _IO('U', 31)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _UAPI_LINUX_USBDEVICE_FS_H */
 | 
				
			||||||
| 
						 | 
					@ -702,18 +702,20 @@ endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(feature-libbfd), 1)
 | 
					ifeq ($(feature-libbfd), 1)
 | 
				
			||||||
  EXTLIBS += -lbfd
 | 
					  EXTLIBS += -lbfd
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					  # we are on a system that requires -liberty and (maybe) -lz
 | 
				
			||||||
 | 
					  # to link against -lbfd; test each case individually here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # call all detections now so we get correct
 | 
					  # call all detections now so we get correct
 | 
				
			||||||
  # status in VF output
 | 
					  # status in VF output
 | 
				
			||||||
  $(call feature_check,liberty)
 | 
					  $(call feature_check,libbfd-liberty)
 | 
				
			||||||
  $(call feature_check,liberty-z)
 | 
					  $(call feature_check,libbfd-liberty-z)
 | 
				
			||||||
  $(call feature_check,cplus-demangle)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ifeq ($(feature-liberty), 1)
 | 
					  ifeq ($(feature-libbfd-liberty), 1)
 | 
				
			||||||
    EXTLIBS += -liberty
 | 
					    EXTLIBS += -lbfd -liberty
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    ifeq ($(feature-liberty-z), 1)
 | 
					    ifeq ($(feature-libbfd-liberty-z), 1)
 | 
				
			||||||
      EXTLIBS += -liberty -lz
 | 
					      EXTLIBS += -lbfd -liberty -lz
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
  endif
 | 
					  endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					@ -723,23 +725,23 @@ ifdef NO_DEMANGLE
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
  ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
 | 
					  ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
 | 
				
			||||||
    EXTLIBS += -liberty
 | 
					    EXTLIBS += -liberty
 | 
				
			||||||
    CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
 | 
					 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    ifneq ($(feature-libbfd), 1)
 | 
					    ifeq ($(filter -liberty,$(EXTLIBS)),)
 | 
				
			||||||
      ifneq ($(feature-liberty), 1)
 | 
					      $(call feature_check,cplus-demangle)
 | 
				
			||||||
        ifneq ($(feature-liberty-z), 1)
 | 
					
 | 
				
			||||||
      # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT
 | 
					      # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT
 | 
				
			||||||
      # or any of 'bfd iberty z' trinity
 | 
					      # or any of 'bfd iberty z' trinity
 | 
				
			||||||
      ifeq ($(feature-cplus-demangle), 1)
 | 
					      ifeq ($(feature-cplus-demangle), 1)
 | 
				
			||||||
        EXTLIBS += -liberty
 | 
					        EXTLIBS += -liberty
 | 
				
			||||||
            CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
 | 
					 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling)
 | 
					        msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling)
 | 
				
			||||||
        CFLAGS += -DNO_DEMANGLE
 | 
					        CFLAGS += -DNO_DEMANGLE
 | 
				
			||||||
      endif
 | 
					      endif
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
  endif
 | 
					  endif
 | 
				
			||||||
    endif
 | 
					
 | 
				
			||||||
 | 
					  ifneq ($(filter -liberty,$(EXTLIBS)),)
 | 
				
			||||||
 | 
					    CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
 | 
				
			||||||
  endif
 | 
					  endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -497,6 +497,12 @@ prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh
 | 
				
			||||||
$(prctl_option_array): $(prctl_hdr_dir)/prctl.h $(prctl_option_tbl)
 | 
					$(prctl_option_array): $(prctl_hdr_dir)/prctl.h $(prctl_option_tbl)
 | 
				
			||||||
	$(Q)$(SHELL) '$(prctl_option_tbl)' $(prctl_hdr_dir) > $@
 | 
						$(Q)$(SHELL) '$(prctl_option_tbl)' $(prctl_hdr_dir) > $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usbdevfs_ioctl_array := $(beauty_ioctl_outdir)/usbdevfs_ioctl_array.c
 | 
				
			||||||
 | 
					usbdevfs_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/usbdevfs_ioctl.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(usbdevfs_ioctl_array): $(linux_uapi_dir)/usbdevice_fs.h $(usbdevfs_ioctl_tbl)
 | 
				
			||||||
 | 
						$(Q)$(SHELL) '$(usbdevfs_ioctl_tbl)' $(linux_uapi_dir) > $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
x86_arch_prctl_code_array := $(beauty_outdir)/x86_arch_prctl_code_array.c
 | 
					x86_arch_prctl_code_array := $(beauty_outdir)/x86_arch_prctl_code_array.c
 | 
				
			||||||
x86_arch_prctl_code_tbl := $(srctree)/tools/perf/trace/beauty/x86_arch_prctl.sh
 | 
					x86_arch_prctl_code_tbl := $(srctree)/tools/perf/trace/beauty/x86_arch_prctl.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -624,6 +630,7 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
 | 
				
			||||||
	$(mount_flags_array) \
 | 
						$(mount_flags_array) \
 | 
				
			||||||
	$(perf_ioctl_array) \
 | 
						$(perf_ioctl_array) \
 | 
				
			||||||
	$(prctl_option_array) \
 | 
						$(prctl_option_array) \
 | 
				
			||||||
 | 
						$(usbdevfs_ioctl_array) \
 | 
				
			||||||
	$(x86_arch_prctl_code_array) \
 | 
						$(x86_arch_prctl_code_array) \
 | 
				
			||||||
	$(rename_flags_array) \
 | 
						$(rename_flags_array) \
 | 
				
			||||||
	$(arch_errno_name_array)
 | 
						$(arch_errno_name_array)
 | 
				
			||||||
| 
						 | 
					@ -923,6 +930,7 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
 | 
				
			||||||
		$(OUTPUT)$(vhost_virtio_ioctl_array) \
 | 
							$(OUTPUT)$(vhost_virtio_ioctl_array) \
 | 
				
			||||||
		$(OUTPUT)$(perf_ioctl_array) \
 | 
							$(OUTPUT)$(perf_ioctl_array) \
 | 
				
			||||||
		$(OUTPUT)$(prctl_option_array) \
 | 
							$(OUTPUT)$(prctl_option_array) \
 | 
				
			||||||
 | 
							$(OUTPUT)$(usbdevfs_ioctl_array) \
 | 
				
			||||||
		$(OUTPUT)$(x86_arch_prctl_code_array) \
 | 
							$(OUTPUT)$(x86_arch_prctl_code_array) \
 | 
				
			||||||
		$(OUTPUT)$(rename_flags_array) \
 | 
							$(OUTPUT)$(rename_flags_array) \
 | 
				
			||||||
		$(OUTPUT)$(arch_errno_name_array)
 | 
							$(OUTPUT)$(arch_errno_name_array)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,7 +68,7 @@ struct c2c_hist_entry {
 | 
				
			||||||
	struct hist_entry	he;
 | 
						struct hist_entry	he;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char const *coalesce_default = "pid,iaddr";
 | 
					static char const *coalesce_default = "iaddr";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct perf_c2c {
 | 
					struct perf_c2c {
 | 
				
			||||||
	struct perf_tool	tool;
 | 
						struct perf_tool	tool;
 | 
				
			||||||
| 
						 | 
					@ -1878,7 +1878,7 @@ static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
 | 
				
			||||||
	return hpp_list__parse(&c2c_hists->list, output, sort);
 | 
						return hpp_list__parse(&c2c_hists->list, output, sort);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DISPLAY_LINE_LIMIT  0.0005
 | 
					#define DISPLAY_LINE_LIMIT  0.001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
 | 
					static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1073,9 +1073,18 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Print final block upto sample
 | 
						 * Print final block upto sample
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Due to pipeline delays the LBRs might be missing a branch
 | 
				
			||||||
 | 
						 * or two, which can result in very large or negative blocks
 | 
				
			||||||
 | 
						 * between final branch and sample. When this happens just
 | 
				
			||||||
 | 
						 * continue walking after the last TO until we hit a branch.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	start = br->entries[0].to;
 | 
						start = br->entries[0].to;
 | 
				
			||||||
	end = sample->ip;
 | 
						end = sample->ip;
 | 
				
			||||||
 | 
						if (end < start) {
 | 
				
			||||||
 | 
							/* Missing jump. Scan 128 bytes for the next branch */
 | 
				
			||||||
 | 
							end = start + 128;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true);
 | 
						len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true);
 | 
				
			||||||
	printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
 | 
						printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
 | 
				
			||||||
	if (len <= 0) {
 | 
						if (len <= 0) {
 | 
				
			||||||
| 
						 | 
					@ -1084,7 +1093,6 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
 | 
				
			||||||
			      machine, thread, &x.is64bit, &x.cpumode, false);
 | 
								      machine, thread, &x.is64bit, &x.cpumode, false);
 | 
				
			||||||
		if (len <= 0)
 | 
							if (len <= 0)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip,
 | 
							printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip,
 | 
				
			||||||
			dump_insn(&x, sample->ip, buffer, len, NULL));
 | 
								dump_insn(&x, sample->ip, buffer, len, NULL));
 | 
				
			||||||
		if (PRINT_FIELD(SRCCODE))
 | 
							if (PRINT_FIELD(SRCCODE))
 | 
				
			||||||
| 
						 | 
					@ -1096,6 +1104,13 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
 | 
				
			||||||
				   dump_insn(&x, start + off, buffer + off, len - off, &ilen));
 | 
									   dump_insn(&x, start + off, buffer + off, len - off, &ilen));
 | 
				
			||||||
		if (ilen == 0)
 | 
							if (ilen == 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							if (arch_is_branch(buffer + off, len - off, x.is64bit) && start + off != sample->ip) {
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * Hit a missing branch. Just stop.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								printed += fprintf(fp, "\t... not reaching sample ...\n");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (PRINT_FIELD(SRCCODE))
 | 
							if (PRINT_FIELD(SRCCODE))
 | 
				
			||||||
			print_srccode(thread, x.cpumode, start + off);
 | 
								print_srccode(thread, x.cpumode, start + off);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1167,7 +1182,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
 | 
				
			||||||
					   struct addr_location *al, FILE *fp)
 | 
										   struct addr_location *al, FILE *fp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct perf_event_attr *attr = &evsel->attr;
 | 
						struct perf_event_attr *attr = &evsel->attr;
 | 
				
			||||||
	size_t depth = thread_stack__depth(thread);
 | 
						size_t depth = thread_stack__depth(thread, sample->cpu);
 | 
				
			||||||
	const char *name = NULL;
 | 
						const char *name = NULL;
 | 
				
			||||||
	static int spacing;
 | 
						static int spacing;
 | 
				
			||||||
	int len = 0;
 | 
						int len = 0;
 | 
				
			||||||
| 
						 | 
					@ -1701,7 +1716,7 @@ static bool show_event(struct perf_sample *sample,
 | 
				
			||||||
		       struct thread *thread,
 | 
							       struct thread *thread,
 | 
				
			||||||
		       struct addr_location *al)
 | 
							       struct addr_location *al)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int depth = thread_stack__depth(thread);
 | 
						int depth = thread_stack__depth(thread, sample->cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!symbol_conf.graph_function)
 | 
						if (!symbol_conf.graph_function)
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,6 +60,7 @@
 | 
				
			||||||
#include <linux/stringify.h>
 | 
					#include <linux/stringify.h>
 | 
				
			||||||
#include <linux/time64.h>
 | 
					#include <linux/time64.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <sys/sysmacros.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "sane_ctype.h"
 | 
					#include "sane_ctype.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,8 +113,9 @@ struct trace {
 | 
				
			||||||
	} stats;
 | 
						} stats;
 | 
				
			||||||
	unsigned int		max_stack;
 | 
						unsigned int		max_stack;
 | 
				
			||||||
	unsigned int		min_stack;
 | 
						unsigned int		min_stack;
 | 
				
			||||||
	bool			sort_events;
 | 
						int			raw_augmented_syscalls_args_size;
 | 
				
			||||||
	bool			raw_augmented_syscalls;
 | 
						bool			raw_augmented_syscalls;
 | 
				
			||||||
 | 
						bool			sort_events;
 | 
				
			||||||
	bool			not_ev_qualifier;
 | 
						bool			not_ev_qualifier;
 | 
				
			||||||
	bool			live;
 | 
						bool			live;
 | 
				
			||||||
	bool			full_time;
 | 
						bool			full_time;
 | 
				
			||||||
| 
						 | 
					@ -283,12 +285,17 @@ static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel)
 | 
				
			||||||
	return -ENOENT;
 | 
						return -ENOENT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel)
 | 
					static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel, struct perf_evsel *tp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
 | 
						struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (evsel->priv != NULL) {       /* field, sizeof_field, offsetof_field */
 | 
						if (evsel->priv != NULL) {
 | 
				
			||||||
		if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap))
 | 
							struct tep_format_field *syscall_id = perf_evsel__field(tp, "id");
 | 
				
			||||||
 | 
							if (syscall_id == NULL)
 | 
				
			||||||
 | 
								syscall_id = perf_evsel__field(tp, "__syscall_nr");
 | 
				
			||||||
 | 
							if (syscall_id == NULL)
 | 
				
			||||||
 | 
								goto out_delete;
 | 
				
			||||||
 | 
							if (__tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
 | 
				
			||||||
			goto out_delete;
 | 
								goto out_delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
| 
						 | 
					@ -975,8 +982,8 @@ struct thread_trace {
 | 
				
			||||||
	} filename;
 | 
						} filename;
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		int	      max;
 | 
							int	      max;
 | 
				
			||||||
		char	  **table;
 | 
							struct file   *table;
 | 
				
			||||||
	} paths;
 | 
						} files;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct intlist *syscall_stats;
 | 
						struct intlist *syscall_stats;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -986,7 +993,7 @@ static struct thread_trace *thread_trace__new(void)
 | 
				
			||||||
	struct thread_trace *ttrace =  zalloc(sizeof(struct thread_trace));
 | 
						struct thread_trace *ttrace =  zalloc(sizeof(struct thread_trace));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ttrace)
 | 
						if (ttrace)
 | 
				
			||||||
		ttrace->paths.max = -1;
 | 
							ttrace->files.max = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ttrace->syscall_stats = intlist__new(NULL);
 | 
						ttrace->syscall_stats = intlist__new(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1030,30 +1037,48 @@ void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const size_t trace__entry_str_size = 2048;
 | 
					static const size_t trace__entry_str_size = 2048;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct file *thread_trace__files_entry(struct thread_trace *ttrace, int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (fd > ttrace->files.max) {
 | 
				
			||||||
 | 
							struct file *nfiles = realloc(ttrace->files.table, (fd + 1) * sizeof(struct file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nfiles == NULL)
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ttrace->files.max != -1) {
 | 
				
			||||||
 | 
								memset(nfiles + ttrace->files.max + 1, 0,
 | 
				
			||||||
 | 
								       (fd - ttrace->files.max) * sizeof(struct file));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								memset(nfiles, 0, (fd + 1) * sizeof(struct file));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ttrace->files.table = nfiles;
 | 
				
			||||||
 | 
							ttrace->files.max   = fd;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ttrace->files.table + fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct file *thread__files_entry(struct thread *thread, int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return thread_trace__files_entry(thread__priv(thread), fd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
				
			||||||
 | 
						struct file *file = thread_trace__files_entry(ttrace, fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fd > ttrace->paths.max) {
 | 
						if (file != NULL) {
 | 
				
			||||||
		char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
 | 
							struct stat st;
 | 
				
			||||||
 | 
							if (stat(pathname, &st) == 0)
 | 
				
			||||||
 | 
								file->dev_maj = major(st.st_rdev);
 | 
				
			||||||
 | 
							file->pathname = strdup(pathname);
 | 
				
			||||||
 | 
							if (file->pathname)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (npath == NULL)
 | 
					 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ttrace->paths.max != -1) {
 | 
					 | 
				
			||||||
			memset(npath + ttrace->paths.max + 1, 0,
 | 
					 | 
				
			||||||
			       (fd - ttrace->paths.max) * sizeof(char *));
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			memset(npath, 0, (fd + 1) * sizeof(char *));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ttrace->paths.table = npath;
 | 
					 | 
				
			||||||
		ttrace->paths.max   = fd;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ttrace->paths.table[fd] = strdup(pathname);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ttrace->paths.table[fd] != NULL ? 0 : -1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int thread__read_fd_path(struct thread *thread, int fd)
 | 
					static int thread__read_fd_path(struct thread *thread, int fd)
 | 
				
			||||||
| 
						 | 
					@ -1093,7 +1118,7 @@ static const char *thread__fd_path(struct thread *thread, int fd,
 | 
				
			||||||
	if (fd < 0)
 | 
						if (fd < 0)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
 | 
						if ((fd > ttrace->files.max || ttrace->files.table[fd].pathname == NULL)) {
 | 
				
			||||||
		if (!trace->live)
 | 
							if (!trace->live)
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		++trace->stats.proc_getname;
 | 
							++trace->stats.proc_getname;
 | 
				
			||||||
| 
						 | 
					@ -1101,7 +1126,7 @@ static const char *thread__fd_path(struct thread *thread, int fd,
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ttrace->paths.table[fd];
 | 
						return ttrace->files.table[fd].pathname;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
 | 
					size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
 | 
				
			||||||
| 
						 | 
					@ -1140,8 +1165,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
 | 
				
			||||||
	size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
 | 
						size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
 | 
				
			||||||
	struct thread_trace *ttrace = thread__priv(arg->thread);
 | 
						struct thread_trace *ttrace = thread__priv(arg->thread);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
 | 
						if (ttrace && fd >= 0 && fd <= ttrace->files.max)
 | 
				
			||||||
		zfree(&ttrace->paths.table[fd]);
 | 
							zfree(&ttrace->files.table[fd].pathname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return printed;
 | 
						return printed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1768,16 +1793,16 @@ static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
 | 
				
			||||||
	return printed;
 | 
						return printed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, bool raw_augmented)
 | 
					static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, int raw_augmented_args_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *augmented_args = NULL;
 | 
						void *augmented_args = NULL;
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter
 | 
						 * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter
 | 
				
			||||||
	 * and there we get all 6 syscall args plus the tracepoint common
 | 
						 * and there we get all 6 syscall args plus the tracepoint common fields
 | 
				
			||||||
	 * fields (sizeof(long)) and the syscall_nr (another long). So we check
 | 
						 * that gets calculated at the start and the syscall_nr (another long).
 | 
				
			||||||
	 * if that is the case and if so don't look after the sc->args_size,
 | 
						 * So we check if that is the case and if so don't look after the
 | 
				
			||||||
	 * but always after the full raw_syscalls:sys_enter payload, which is
 | 
						 * sc->args_size but always after the full raw_syscalls:sys_enter payload,
 | 
				
			||||||
	 * fixed.
 | 
						 * which is fixed.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * We'll revisit this later to pass s->args_size to the BPF augmenter
 | 
						 * We'll revisit this later to pass s->args_size to the BPF augmenter
 | 
				
			||||||
	 * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it
 | 
						 * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it
 | 
				
			||||||
| 
						 | 
					@ -1785,7 +1810,7 @@ static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sam
 | 
				
			||||||
	 * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace
 | 
						 * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace
 | 
				
			||||||
	 * traffic to just what is needed for each syscall.
 | 
						 * traffic to just what is needed for each syscall.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	int args_size = raw_augmented ? (8 * (int)sizeof(long)) : sc->args_size;
 | 
						int args_size = raw_augmented_args_size ?: sc->args_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*augmented_args_size = sample->raw_size - args_size;
 | 
						*augmented_args_size = sample->raw_size - args_size;
 | 
				
			||||||
	if (*augmented_args_size > 0)
 | 
						if (*augmented_args_size > 0)
 | 
				
			||||||
| 
						 | 
					@ -1839,7 +1864,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 | 
				
			||||||
	 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
 | 
						 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (evsel != trace->syscalls.events.sys_enter)
 | 
						if (evsel != trace->syscalls.events.sys_enter)
 | 
				
			||||||
		augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls);
 | 
							augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
 | 
				
			||||||
	ttrace->entry_time = sample->time;
 | 
						ttrace->entry_time = sample->time;
 | 
				
			||||||
	msg = ttrace->entry_str;
 | 
						msg = ttrace->entry_str;
 | 
				
			||||||
	printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
 | 
						printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
 | 
				
			||||||
| 
						 | 
					@ -1897,7 +1922,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evse
 | 
				
			||||||
		goto out_put;
 | 
							goto out_put;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	args = perf_evsel__sc_tp_ptr(evsel, args, sample);
 | 
						args = perf_evsel__sc_tp_ptr(evsel, args, sample);
 | 
				
			||||||
	augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls);
 | 
						augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
 | 
				
			||||||
	syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
 | 
						syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
 | 
				
			||||||
	fprintf(trace->output, "%s", msg);
 | 
						fprintf(trace->output, "%s", msg);
 | 
				
			||||||
	err = 0;
 | 
						err = 0;
 | 
				
			||||||
| 
						 | 
					@ -2686,7 +2711,9 @@ static int trace__set_ev_qualifier_filter(struct trace *trace)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (trace->syscalls.map)
 | 
						if (trace->syscalls.map)
 | 
				
			||||||
		return trace__set_ev_qualifier_bpf_filter(trace);
 | 
							return trace__set_ev_qualifier_bpf_filter(trace);
 | 
				
			||||||
 | 
						if (trace->syscalls.events.sys_enter)
 | 
				
			||||||
		return trace__set_ev_qualifier_tp_filter(trace);
 | 
							return trace__set_ev_qualifier_tp_filter(trace);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bpf_map__set_filter_pids(struct bpf_map *map __maybe_unused,
 | 
					static int bpf_map__set_filter_pids(struct bpf_map *map __maybe_unused,
 | 
				
			||||||
| 
						 | 
					@ -3812,13 +3839,6 @@ int cmd_trace(int argc, const char **argv)
 | 
				
			||||||
	 * syscall.
 | 
						 * syscall.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (trace.syscalls.events.augmented) {
 | 
						if (trace.syscalls.events.augmented) {
 | 
				
			||||||
		evsel = trace.syscalls.events.augmented;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (perf_evsel__init_augmented_syscall_tp(evsel) ||
 | 
					 | 
				
			||||||
		    perf_evsel__init_augmented_syscall_tp_args(evsel))
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		evsel->handler = trace__sys_enter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		evlist__for_each_entry(trace.evlist, evsel) {
 | 
							evlist__for_each_entry(trace.evlist, evsel) {
 | 
				
			||||||
			bool raw_syscalls_sys_exit = strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_exit") == 0;
 | 
								bool raw_syscalls_sys_exit = strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_exit") == 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3827,9 +3847,41 @@ int cmd_trace(int argc, const char **argv)
 | 
				
			||||||
				goto init_augmented_syscall_tp;
 | 
									goto init_augmented_syscall_tp;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_enter") == 0) {
 | 
				
			||||||
 | 
									struct perf_evsel *augmented = trace.syscalls.events.augmented;
 | 
				
			||||||
 | 
									if (perf_evsel__init_augmented_syscall_tp(augmented, evsel) ||
 | 
				
			||||||
 | 
									    perf_evsel__init_augmented_syscall_tp_args(augmented))
 | 
				
			||||||
 | 
										goto out;
 | 
				
			||||||
 | 
									augmented->handler = trace__sys_enter;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) {
 | 
								if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) {
 | 
				
			||||||
 | 
									struct syscall_tp *sc;
 | 
				
			||||||
init_augmented_syscall_tp:
 | 
					init_augmented_syscall_tp:
 | 
				
			||||||
				perf_evsel__init_augmented_syscall_tp(evsel);
 | 
									if (perf_evsel__init_augmented_syscall_tp(evsel, evsel))
 | 
				
			||||||
 | 
										goto out;
 | 
				
			||||||
 | 
									sc = evsel->priv;
 | 
				
			||||||
 | 
									/*
 | 
				
			||||||
 | 
									 * For now with BPF raw_augmented we hook into
 | 
				
			||||||
 | 
									 * raw_syscalls:sys_enter and there we get all
 | 
				
			||||||
 | 
									 * 6 syscall args plus the tracepoint common
 | 
				
			||||||
 | 
									 * fields and the syscall_nr (another long).
 | 
				
			||||||
 | 
									 * So we check if that is the case and if so
 | 
				
			||||||
 | 
									 * don't look after the sc->args_size but
 | 
				
			||||||
 | 
									 * always after the full raw_syscalls:sys_enter
 | 
				
			||||||
 | 
									 * payload, which is fixed.
 | 
				
			||||||
 | 
									 *
 | 
				
			||||||
 | 
									 * We'll revisit this later to pass
 | 
				
			||||||
 | 
									 * s->args_size to the BPF augmenter (now
 | 
				
			||||||
 | 
									 * tools/perf/examples/bpf/augmented_raw_syscalls.c,
 | 
				
			||||||
 | 
									 * so that it copies only what we need for each
 | 
				
			||||||
 | 
									 * syscall, like what happens when we use
 | 
				
			||||||
 | 
									 * syscalls:sys_enter_NAME, so that we reduce
 | 
				
			||||||
 | 
									 * the kernel/userspace traffic to just what is
 | 
				
			||||||
 | 
									 * needed for each syscall.
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									if (trace.raw_augmented_syscalls)
 | 
				
			||||||
 | 
										trace.raw_augmented_syscalls_args_size = (6 + 1) * sizeof(long) + sc->id.offset;
 | 
				
			||||||
				perf_evsel__init_augmented_syscall_tp_ret(evsel);
 | 
									perf_evsel__init_augmented_syscall_tp_ret(evsel);
 | 
				
			||||||
				evsel->handler = trace__sys_exit;
 | 
									evsel->handler = trace__sys_exit;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ include/uapi/linux/perf_event.h
 | 
				
			||||||
include/uapi/linux/prctl.h
 | 
					include/uapi/linux/prctl.h
 | 
				
			||||||
include/uapi/linux/sched.h
 | 
					include/uapi/linux/sched.h
 | 
				
			||||||
include/uapi/linux/stat.h
 | 
					include/uapi/linux/stat.h
 | 
				
			||||||
 | 
					include/uapi/linux/usbdevice_fs.h
 | 
				
			||||||
include/uapi/linux/vhost.h
 | 
					include/uapi/linux/vhost.h
 | 
				
			||||||
include/uapi/sound/asound.h
 | 
					include/uapi/sound/asound.h
 | 
				
			||||||
include/linux/bits.h
 | 
					include/linux/bits.h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,13 @@ size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, boo
 | 
				
			||||||
struct trace;
 | 
					struct trace;
 | 
				
			||||||
struct thread;
 | 
					struct thread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct file {
 | 
				
			||||||
 | 
						char *pathname;
 | 
				
			||||||
 | 
						int  dev_maj;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct file *thread__files_entry(struct thread *thread, int fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct strarrays {
 | 
					struct strarrays {
 | 
				
			||||||
	int		nr_entries;
 | 
						int		nr_entries;
 | 
				
			||||||
	struct strarray **entries;
 | 
						struct strarray **entries;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,6 +112,17 @@ static size_t ioctl__scnprintf_perf_cmd(int nr, int dir, char *bf, size_t size)
 | 
				
			||||||
	return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
 | 
						return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t ioctl__scnprintf_usbdevfs_cmd(int nr, int dir, char *bf, size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#include "trace/beauty/generated/ioctl/usbdevfs_ioctl_array.c"
 | 
				
			||||||
 | 
						static DEFINE_STRARRAY(usbdevfs_ioctl_cmds, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nr < strarray__usbdevfs_ioctl_cmds.nr_entries && strarray__usbdevfs_ioctl_cmds.entries[nr] != NULL)
 | 
				
			||||||
 | 
							return scnprintf(bf, size, "USBDEVFS_%s", strarray__usbdevfs_ioctl_cmds.entries[nr]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return scnprintf(bf, size, "(%c, %#x, %#x)", 'U', nr, dir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix)
 | 
					static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *prefix = "_IOC_";
 | 
						const char *prefix = "_IOC_";
 | 
				
			||||||
| 
						 | 
					@ -157,9 +168,20 @@ static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, boo
 | 
				
			||||||
	return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz);
 | 
						return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USB_DEVICE_MAJOR
 | 
				
			||||||
 | 
					#define USB_DEVICE_MAJOR 189
 | 
				
			||||||
 | 
					#endif // USB_DEVICE_MAJOR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg)
 | 
					size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long cmd = arg->val;
 | 
						unsigned long cmd = arg->val;
 | 
				
			||||||
 | 
						unsigned int fd = syscall_arg__val(arg, 0);
 | 
				
			||||||
 | 
						struct file *file = thread__files_entry(arg->thread, fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (file != NULL) {
 | 
				
			||||||
 | 
							if (file->dev_maj == USB_DEVICE_MAJOR)
 | 
				
			||||||
 | 
								return ioctl__scnprintf_usbdevfs_cmd(_IOC_NR(cmd), _IOC_DIR(cmd), bf, size);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix);
 | 
						return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,8 +18,8 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	P_MMAP_PROT(READ);
 | 
						P_MMAP_PROT(READ);
 | 
				
			||||||
	P_MMAP_PROT(EXEC);
 | 
					 | 
				
			||||||
	P_MMAP_PROT(WRITE);
 | 
						P_MMAP_PROT(WRITE);
 | 
				
			||||||
 | 
						P_MMAP_PROT(EXEC);
 | 
				
			||||||
	P_MMAP_PROT(SEM);
 | 
						P_MMAP_PROT(SEM);
 | 
				
			||||||
	P_MMAP_PROT(GROWSDOWN);
 | 
						P_MMAP_PROT(GROWSDOWN);
 | 
				
			||||||
	P_MMAP_PROT(GROWSUP);
 | 
						P_MMAP_PROT(GROWSUP);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@
 | 
				
			||||||
static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
 | 
					static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool show_prefix = arg->show_string_prefix;
 | 
						bool show_prefix = arg->show_string_prefix;
 | 
				
			||||||
	const char *prefix = "SECOMP_SET_MODE_";
 | 
						const char *prefix = "SECCOMP_SET_MODE_";
 | 
				
			||||||
	int op = arg->val;
 | 
						int op = arg->val;
 | 
				
			||||||
	size_t printed = 0;
 | 
						size_t printed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,7 @@ static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
 | 
				
			||||||
						   struct syscall_arg *arg)
 | 
											   struct syscall_arg *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool show_prefix = arg->show_string_prefix;
 | 
						bool show_prefix = arg->show_string_prefix;
 | 
				
			||||||
	const char *prefix = "SECOMP_FILTER_FLAG_";
 | 
						const char *prefix = "SECCOMP_FILTER_FLAG_";
 | 
				
			||||||
	int printed = 0, flags = arg->val;
 | 
						int printed = 0, flags = arg->val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define	P_FLAG(n) \
 | 
					#define	P_FLAG(n) \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								tools/perf/trace/beauty/usbdevfs_ioctl.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										19
									
								
								tools/perf/trace/beauty/usbdevfs_ioctl.sh
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: LGPL-2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					printf "static const char *usbdevfs_ioctl_cmds[] = {\n"
 | 
				
			||||||
 | 
					regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)[[:space:]]+_IO[WR]{0,2}\([[:space:]]*'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*"
 | 
				
			||||||
 | 
					egrep $regex ${header_dir}/usbdevice_fs.h | egrep -v 'USBDEVFS_\w+32[[:space:]]' | \
 | 
				
			||||||
 | 
						sed -r "s/$regex/\2 \1/g"	| \
 | 
				
			||||||
 | 
						sort | xargs printf "\t[%s] = \"%s\",\n"
 | 
				
			||||||
 | 
					printf "};\n\n"
 | 
				
			||||||
 | 
					printf "#if 0\n"
 | 
				
			||||||
 | 
					printf "static const char *usbdevfs_ioctl_32_cmds[] = {\n"
 | 
				
			||||||
 | 
					regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)[[:space:]]+_IO[WR]{0,2}\([[:space:]]*'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*"
 | 
				
			||||||
 | 
					egrep $regex ${header_dir}/usbdevice_fs.h | egrep 'USBDEVFS_\w+32[[:space:]]' | \
 | 
				
			||||||
 | 
						sed -r "s/$regex/\2 \1/g"	| \
 | 
				
			||||||
 | 
						sort | xargs printf "\t[%s] = \"%s\",\n"
 | 
				
			||||||
 | 
					printf "};\n"
 | 
				
			||||||
 | 
					printf "#endif\n"
 | 
				
			||||||
| 
						 | 
					@ -13,3 +13,11 @@ const char *dump_insn(struct perf_insn *x __maybe_unused,
 | 
				
			||||||
		*lenp = 0;
 | 
							*lenp = 0;
 | 
				
			||||||
	return "?";
 | 
						return "?";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__weak
 | 
				
			||||||
 | 
					int arch_is_branch(const unsigned char *buf __maybe_unused,
 | 
				
			||||||
 | 
							   size_t len __maybe_unused,
 | 
				
			||||||
 | 
							   int x86_64 __maybe_unused)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,4 +20,6 @@ struct perf_insn {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *dump_insn(struct perf_insn *x, u64 ip,
 | 
					const char *dump_insn(struct perf_insn *x, u64 ip,
 | 
				
			||||||
		      u8 *inbuf, int inlen, int *lenp);
 | 
							      u8 *inbuf, int inlen, int *lenp);
 | 
				
			||||||
 | 
					int arch_is_branch(const unsigned char *buf, size_t len, int x86_64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -451,7 +451,7 @@ static int intel_bts_process_buffer(struct intel_bts_queue *btsq,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		intel_bts_get_branch_type(btsq, branch);
 | 
							intel_bts_get_branch_type(btsq, branch);
 | 
				
			||||||
		if (btsq->bts->synth_opts.thread_stack)
 | 
							if (btsq->bts->synth_opts.thread_stack)
 | 
				
			||||||
			thread_stack__event(thread, btsq->sample_flags,
 | 
								thread_stack__event(thread, btsq->cpu, btsq->sample_flags,
 | 
				
			||||||
					    le64_to_cpu(branch->from),
 | 
										    le64_to_cpu(branch->from),
 | 
				
			||||||
					    le64_to_cpu(branch->to),
 | 
										    le64_to_cpu(branch->to),
 | 
				
			||||||
					    btsq->intel_pt_insn.length,
 | 
										    btsq->intel_pt_insn.length,
 | 
				
			||||||
| 
						 | 
					@ -523,7 +523,7 @@ static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp)
 | 
				
			||||||
	    !btsq->bts->synth_opts.thread_stack && thread &&
 | 
						    !btsq->bts->synth_opts.thread_stack && thread &&
 | 
				
			||||||
	    (!old_buffer || btsq->bts->sampling_mode ||
 | 
						    (!old_buffer || btsq->bts->sampling_mode ||
 | 
				
			||||||
	     (btsq->bts->snapshot_mode && !buffer->consecutive)))
 | 
						     (btsq->bts->snapshot_mode && !buffer->consecutive)))
 | 
				
			||||||
		thread_stack__set_trace_nr(thread, buffer->buffer_nr + 1);
 | 
							thread_stack__set_trace_nr(thread, btsq->cpu, buffer->buffer_nr + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = intel_bts_process_buffer(btsq, buffer, thread);
 | 
						err = intel_bts_process_buffer(btsq, buffer, thread);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -180,6 +180,14 @@ int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int arch_is_branch(const unsigned char *buf, size_t len, int x86_64)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct intel_pt_insn in;
 | 
				
			||||||
 | 
						if (intel_pt_get_insn(buf, len, x86_64, &in) < 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						return in.branch != INTEL_PT_BR_NO_BRANCH;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
 | 
					const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
 | 
				
			||||||
		      u8 *inbuf, int inlen, int *lenp)
 | 
							      u8 *inbuf, int inlen, int *lenp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1174,7 +1174,7 @@ static void intel_pt_prep_sample(struct intel_pt *pt,
 | 
				
			||||||
	intel_pt_prep_b_sample(pt, ptq, event, sample);
 | 
						intel_pt_prep_b_sample(pt, ptq, event, sample);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pt->synth_opts.callchain) {
 | 
						if (pt->synth_opts.callchain) {
 | 
				
			||||||
		thread_stack__sample(ptq->thread, ptq->chain,
 | 
							thread_stack__sample(ptq->thread, ptq->cpu, ptq->chain,
 | 
				
			||||||
				     pt->synth_opts.callchain_sz + 1,
 | 
									     pt->synth_opts.callchain_sz + 1,
 | 
				
			||||||
				     sample->ip, pt->kernel_start);
 | 
									     sample->ip, pt->kernel_start);
 | 
				
			||||||
		sample->callchain = ptq->chain;
 | 
							sample->callchain = ptq->chain;
 | 
				
			||||||
| 
						 | 
					@ -1526,11 +1526,11 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pt->synth_opts.callchain || pt->synth_opts.thread_stack)
 | 
						if (pt->synth_opts.callchain || pt->synth_opts.thread_stack)
 | 
				
			||||||
		thread_stack__event(ptq->thread, ptq->flags, state->from_ip,
 | 
							thread_stack__event(ptq->thread, ptq->cpu, ptq->flags, state->from_ip,
 | 
				
			||||||
				    state->to_ip, ptq->insn_len,
 | 
									    state->to_ip, ptq->insn_len,
 | 
				
			||||||
				    state->trace_nr);
 | 
									    state->trace_nr);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		thread_stack__set_trace_nr(ptq->thread, state->trace_nr);
 | 
							thread_stack__set_trace_nr(ptq->thread, ptq->cpu, state->trace_nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pt->sample_branches) {
 | 
						if (pt->sample_branches) {
 | 
				
			||||||
		err = intel_pt_synth_branch_sample(ptq);
 | 
							err = intel_pt_synth_branch_sample(ptq);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -939,7 +939,8 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		file = PyFile_FromFile(fp, "perf", "r", NULL);
 | 
							file = PyFile_FromFile(fp, "perf", "r", NULL);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
		file = PyFile_FromFd(evlist->pollfd.entries[i].fd, "perf", "r", -1, NULL, NULL, NULL, 1);
 | 
							file = PyFile_FromFd(evlist->pollfd.entries[i].fd, "perf", "r", -1,
 | 
				
			||||||
 | 
									     NULL, NULL, NULL, 0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		if (file == NULL)
 | 
							if (file == NULL)
 | 
				
			||||||
			goto free_list;
 | 
								goto free_list;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1527,6 +1527,13 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
 | 
				
			||||||
	return machine__findnew_thread(&session->machines.host, -1, pid);
 | 
						return machine__findnew_thread(&session->machines.host, -1, pid);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Threads are identified by pid and tid, and the idle task has pid == tid == 0.
 | 
				
			||||||
 | 
					 * So here a single thread is created for that, but actually there is a separate
 | 
				
			||||||
 | 
					 * idle task per cpu, so there should be one 'struct thread' per cpu, but there
 | 
				
			||||||
 | 
					 * is only 1. That causes problems for some tools, requiring workarounds. For
 | 
				
			||||||
 | 
					 * example get_idle_thread() in builtin-sched.c, or thread_stack__per_cpu().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int perf_session__register_idle_thread(struct perf_session *session)
 | 
					int perf_session__register_idle_thread(struct perf_session *session)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct thread *thread;
 | 
						struct thread *thread;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/rbtree.h>
 | 
					#include <linux/rbtree.h>
 | 
				
			||||||
#include <linux/list.h>
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/log2.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include "thread.h"
 | 
					#include "thread.h"
 | 
				
			||||||
#include "event.h"
 | 
					#include "event.h"
 | 
				
			||||||
| 
						 | 
					@ -60,6 +61,7 @@ struct thread_stack_entry {
 | 
				
			||||||
 * @last_time: last timestamp
 | 
					 * @last_time: last timestamp
 | 
				
			||||||
 * @crp: call/return processor
 | 
					 * @crp: call/return processor
 | 
				
			||||||
 * @comm: current comm
 | 
					 * @comm: current comm
 | 
				
			||||||
 | 
					 * @arr_sz: size of array if this is the first element of an array
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct thread_stack {
 | 
					struct thread_stack {
 | 
				
			||||||
	struct thread_stack_entry *stack;
 | 
						struct thread_stack_entry *stack;
 | 
				
			||||||
| 
						 | 
					@ -71,8 +73,19 @@ struct thread_stack {
 | 
				
			||||||
	u64 last_time;
 | 
						u64 last_time;
 | 
				
			||||||
	struct call_return_processor *crp;
 | 
						struct call_return_processor *crp;
 | 
				
			||||||
	struct comm *comm;
 | 
						struct comm *comm;
 | 
				
			||||||
 | 
						unsigned int arr_sz;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Assume pid == tid == 0 identifies the idle task as defined by
 | 
				
			||||||
 | 
					 * perf_session__register_idle_thread(). The idle task is really 1 task per cpu,
 | 
				
			||||||
 | 
					 * and therefore requires a stack for each cpu.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline bool thread_stack__per_cpu(struct thread *thread)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return !(thread->tid || thread->pid_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int thread_stack__grow(struct thread_stack *ts)
 | 
					static int thread_stack__grow(struct thread_stack *ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct thread_stack_entry *new_stack;
 | 
						struct thread_stack_entry *new_stack;
 | 
				
			||||||
| 
						 | 
					@ -91,19 +104,14 @@ static int thread_stack__grow(struct thread_stack *ts)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct thread_stack *thread_stack__new(struct thread *thread,
 | 
					static int thread_stack__init(struct thread_stack *ts, struct thread *thread,
 | 
				
			||||||
			      struct call_return_processor *crp)
 | 
								      struct call_return_processor *crp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct thread_stack *ts;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ts = zalloc(sizeof(struct thread_stack));
 | 
						err = thread_stack__grow(ts);
 | 
				
			||||||
	if (!ts)
 | 
						if (err)
 | 
				
			||||||
		return NULL;
 | 
							return err;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (thread_stack__grow(ts)) {
 | 
					 | 
				
			||||||
		free(ts);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (thread->mg && thread->mg->machine)
 | 
						if (thread->mg && thread->mg->machine)
 | 
				
			||||||
		ts->kernel_start = machine__kernel_start(thread->mg->machine);
 | 
							ts->kernel_start = machine__kernel_start(thread->mg->machine);
 | 
				
			||||||
| 
						 | 
					@ -111,9 +119,72 @@ static struct thread_stack *thread_stack__new(struct thread *thread,
 | 
				
			||||||
		ts->kernel_start = 1ULL << 63;
 | 
							ts->kernel_start = 1ULL << 63;
 | 
				
			||||||
	ts->crp = crp;
 | 
						ts->crp = crp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct thread_stack *thread_stack__new(struct thread *thread, int cpu,
 | 
				
			||||||
 | 
										      struct call_return_processor *crp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct thread_stack *ts = thread->ts, *new_ts;
 | 
				
			||||||
 | 
						unsigned int old_sz = ts ? ts->arr_sz : 0;
 | 
				
			||||||
 | 
						unsigned int new_sz = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (thread_stack__per_cpu(thread) && cpu > 0)
 | 
				
			||||||
 | 
							new_sz = roundup_pow_of_two(cpu + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ts || new_sz > old_sz) {
 | 
				
			||||||
 | 
							new_ts = calloc(new_sz, sizeof(*ts));
 | 
				
			||||||
 | 
							if (!new_ts)
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							if (ts)
 | 
				
			||||||
 | 
								memcpy(new_ts, ts, old_sz * sizeof(*ts));
 | 
				
			||||||
 | 
							new_ts->arr_sz = new_sz;
 | 
				
			||||||
 | 
							zfree(&thread->ts);
 | 
				
			||||||
 | 
							thread->ts = new_ts;
 | 
				
			||||||
 | 
							ts = new_ts;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (thread_stack__per_cpu(thread) && cpu > 0 &&
 | 
				
			||||||
 | 
						    (unsigned int)cpu < ts->arr_sz)
 | 
				
			||||||
 | 
							ts += cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ts->stack &&
 | 
				
			||||||
 | 
						    thread_stack__init(ts, thread, crp))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ts;
 | 
						return ts;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct thread_stack *thread__cpu_stack(struct thread *thread, int cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct thread_stack *ts = thread->ts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cpu < 0)
 | 
				
			||||||
 | 
							cpu = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ts || (unsigned int)cpu >= ts->arr_sz)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts += cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ts->stack)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct thread_stack *thread__stack(struct thread *thread,
 | 
				
			||||||
 | 
											    int cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!thread)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (thread_stack__per_cpu(thread))
 | 
				
			||||||
 | 
							return thread__cpu_stack(thread, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return thread->ts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int thread_stack__push(struct thread_stack *ts, u64 ret_addr,
 | 
					static int thread_stack__push(struct thread_stack *ts, u64 ret_addr,
 | 
				
			||||||
			      bool trace_end)
 | 
								      bool trace_end)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -226,25 +297,37 @@ static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int thread_stack__flush(struct thread *thread)
 | 
					int thread_stack__flush(struct thread *thread)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (thread->ts)
 | 
						struct thread_stack *ts = thread->ts;
 | 
				
			||||||
		return __thread_stack__flush(thread, thread->ts);
 | 
						unsigned int pos;
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						if (ts) {
 | 
				
			||||||
 | 
							for (pos = 0; pos < ts->arr_sz; pos++) {
 | 
				
			||||||
 | 
								int ret = __thread_stack__flush(thread, ts + pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (ret)
 | 
				
			||||||
 | 
									err = ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int thread_stack__event(struct thread *thread, int cpu, u32 flags, u64 from_ip,
 | 
				
			||||||
			u64 to_ip, u16 insn_len, u64 trace_nr)
 | 
								u64 to_ip, u16 insn_len, u64 trace_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct thread_stack *ts = thread__stack(thread, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!thread)
 | 
						if (!thread)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!thread->ts) {
 | 
						if (!ts) {
 | 
				
			||||||
		thread->ts = thread_stack__new(thread, NULL);
 | 
							ts = thread_stack__new(thread, cpu, NULL);
 | 
				
			||||||
		if (!thread->ts) {
 | 
							if (!ts) {
 | 
				
			||||||
			pr_warning("Out of memory: no thread stack\n");
 | 
								pr_warning("Out of memory: no thread stack\n");
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		thread->ts->trace_nr = trace_nr;
 | 
							ts->trace_nr = trace_nr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -252,14 +335,14 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 | 
				
			||||||
	 * the stack might be completely invalid.  Better to report nothing than
 | 
						 * the stack might be completely invalid.  Better to report nothing than
 | 
				
			||||||
	 * to report something misleading, so flush the stack.
 | 
						 * to report something misleading, so flush the stack.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (trace_nr != thread->ts->trace_nr) {
 | 
						if (trace_nr != ts->trace_nr) {
 | 
				
			||||||
		if (thread->ts->trace_nr)
 | 
							if (ts->trace_nr)
 | 
				
			||||||
			__thread_stack__flush(thread, thread->ts);
 | 
								__thread_stack__flush(thread, ts);
 | 
				
			||||||
		thread->ts->trace_nr = trace_nr;
 | 
							ts->trace_nr = trace_nr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Stop here if thread_stack__process() is in use */
 | 
						/* Stop here if thread_stack__process() is in use */
 | 
				
			||||||
	if (thread->ts->crp)
 | 
						if (ts->crp)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flags & PERF_IP_FLAG_CALL) {
 | 
						if (flags & PERF_IP_FLAG_CALL) {
 | 
				
			||||||
| 
						 | 
					@ -270,7 +353,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 | 
				
			||||||
		ret_addr = from_ip + insn_len;
 | 
							ret_addr = from_ip + insn_len;
 | 
				
			||||||
		if (ret_addr == to_ip)
 | 
							if (ret_addr == to_ip)
 | 
				
			||||||
			return 0; /* Zero-length calls are excluded */
 | 
								return 0; /* Zero-length calls are excluded */
 | 
				
			||||||
		return thread_stack__push(thread->ts, ret_addr,
 | 
							return thread_stack__push(ts, ret_addr,
 | 
				
			||||||
					  flags & PERF_IP_FLAG_TRACE_END);
 | 
										  flags & PERF_IP_FLAG_TRACE_END);
 | 
				
			||||||
	} else if (flags & PERF_IP_FLAG_TRACE_BEGIN) {
 | 
						} else if (flags & PERF_IP_FLAG_TRACE_BEGIN) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
| 
						 | 
					@ -280,32 +363,52 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 | 
				
			||||||
		 * address, so try to pop that. Also, do not expect a call made
 | 
							 * address, so try to pop that. Also, do not expect a call made
 | 
				
			||||||
		 * when the trace ended, to return, so pop that.
 | 
							 * when the trace ended, to return, so pop that.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		thread_stack__pop(thread->ts, to_ip);
 | 
							thread_stack__pop(ts, to_ip);
 | 
				
			||||||
		thread_stack__pop_trace_end(thread->ts);
 | 
							thread_stack__pop_trace_end(ts);
 | 
				
			||||||
	} else if ((flags & PERF_IP_FLAG_RETURN) && from_ip) {
 | 
						} else if ((flags & PERF_IP_FLAG_RETURN) && from_ip) {
 | 
				
			||||||
		thread_stack__pop(thread->ts, to_ip);
 | 
							thread_stack__pop(ts, to_ip);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
 | 
					void thread_stack__set_trace_nr(struct thread *thread, int cpu, u64 trace_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!thread || !thread->ts)
 | 
						struct thread_stack *ts = thread__stack(thread, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ts)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trace_nr != thread->ts->trace_nr) {
 | 
						if (trace_nr != ts->trace_nr) {
 | 
				
			||||||
		if (thread->ts->trace_nr)
 | 
							if (ts->trace_nr)
 | 
				
			||||||
			__thread_stack__flush(thread, thread->ts);
 | 
								__thread_stack__flush(thread, ts);
 | 
				
			||||||
		thread->ts->trace_nr = trace_nr;
 | 
							ts->trace_nr = trace_nr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __thread_stack__free(struct thread *thread, struct thread_stack *ts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__thread_stack__flush(thread, ts);
 | 
				
			||||||
 | 
						zfree(&ts->stack);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void thread_stack__reset(struct thread *thread, struct thread_stack *ts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int arr_sz = ts->arr_sz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__thread_stack__free(thread, ts);
 | 
				
			||||||
 | 
						memset(ts, 0, sizeof(*ts));
 | 
				
			||||||
 | 
						ts->arr_sz = arr_sz;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void thread_stack__free(struct thread *thread)
 | 
					void thread_stack__free(struct thread *thread)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (thread->ts) {
 | 
						struct thread_stack *ts = thread->ts;
 | 
				
			||||||
		__thread_stack__flush(thread, thread->ts);
 | 
						unsigned int pos;
 | 
				
			||||||
		zfree(&thread->ts->stack);
 | 
					
 | 
				
			||||||
 | 
						if (ts) {
 | 
				
			||||||
 | 
							for (pos = 0; pos < ts->arr_sz; pos++)
 | 
				
			||||||
 | 
								__thread_stack__free(thread, ts + pos);
 | 
				
			||||||
		zfree(&thread->ts);
 | 
							zfree(&thread->ts);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -315,9 +418,11 @@ static inline u64 callchain_context(u64 ip, u64 kernel_start)
 | 
				
			||||||
	return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL;
 | 
						return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
 | 
					void thread_stack__sample(struct thread *thread, int cpu,
 | 
				
			||||||
 | 
								  struct ip_callchain *chain,
 | 
				
			||||||
			  size_t sz, u64 ip, u64 kernel_start)
 | 
								  size_t sz, u64 ip, u64 kernel_start)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct thread_stack *ts = thread__stack(thread, cpu);
 | 
				
			||||||
	u64 context = callchain_context(ip, kernel_start);
 | 
						u64 context = callchain_context(ip, kernel_start);
 | 
				
			||||||
	u64 last_context;
 | 
						u64 last_context;
 | 
				
			||||||
	size_t i, j;
 | 
						size_t i, j;
 | 
				
			||||||
| 
						 | 
					@ -330,15 +435,15 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
 | 
				
			||||||
	chain->ips[0] = context;
 | 
						chain->ips[0] = context;
 | 
				
			||||||
	chain->ips[1] = ip;
 | 
						chain->ips[1] = ip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!thread || !thread->ts) {
 | 
						if (!ts) {
 | 
				
			||||||
		chain->nr = 2;
 | 
							chain->nr = 2;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	last_context = context;
 | 
						last_context = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 2, j = 1; i < sz && j <= thread->ts->cnt; i++, j++) {
 | 
						for (i = 2, j = 1; i < sz && j <= ts->cnt; i++, j++) {
 | 
				
			||||||
		ip = thread->ts->stack[thread->ts->cnt - j].ret_addr;
 | 
							ip = ts->stack[ts->cnt - j].ret_addr;
 | 
				
			||||||
		context = callchain_context(ip, kernel_start);
 | 
							context = callchain_context(ip, kernel_start);
 | 
				
			||||||
		if (context != last_context) {
 | 
							if (context != last_context) {
 | 
				
			||||||
			if (i >= sz - 1)
 | 
								if (i >= sz - 1)
 | 
				
			||||||
| 
						 | 
					@ -449,7 +554,7 @@ static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
 | 
					static int thread_stack__bottom(struct thread_stack *ts,
 | 
				
			||||||
				struct perf_sample *sample,
 | 
									struct perf_sample *sample,
 | 
				
			||||||
				struct addr_location *from_al,
 | 
									struct addr_location *from_al,
 | 
				
			||||||
				struct addr_location *to_al, u64 ref)
 | 
									struct addr_location *to_al, u64 ref)
 | 
				
			||||||
| 
						 | 
					@ -474,7 +579,7 @@ static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
 | 
				
			||||||
	if (!cp)
 | 
						if (!cp)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp,
 | 
						return thread_stack__push_cp(ts, ip, sample->time, ref, cp,
 | 
				
			||||||
				     true, false);
 | 
									     true, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -590,24 +695,19 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
 | 
				
			||||||
			  struct addr_location *to_al, u64 ref,
 | 
								  struct addr_location *to_al, u64 ref,
 | 
				
			||||||
			  struct call_return_processor *crp)
 | 
								  struct call_return_processor *crp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct thread_stack *ts = thread->ts;
 | 
						struct thread_stack *ts = thread__stack(thread, sample->cpu);
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ts) {
 | 
						if (ts && !ts->crp) {
 | 
				
			||||||
		if (!ts->crp) {
 | 
					 | 
				
			||||||
		/* Supersede thread_stack__event() */
 | 
							/* Supersede thread_stack__event() */
 | 
				
			||||||
			thread_stack__free(thread);
 | 
							thread_stack__reset(thread, ts);
 | 
				
			||||||
			thread->ts = thread_stack__new(thread, crp);
 | 
							ts = NULL;
 | 
				
			||||||
			if (!thread->ts)
 | 
					 | 
				
			||||||
				return -ENOMEM;
 | 
					 | 
				
			||||||
			ts = thread->ts;
 | 
					 | 
				
			||||||
			ts->comm = comm;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	} else {
 | 
					
 | 
				
			||||||
		thread->ts = thread_stack__new(thread, crp);
 | 
						if (!ts) {
 | 
				
			||||||
		if (!thread->ts)
 | 
							ts = thread_stack__new(thread, sample->cpu, crp);
 | 
				
			||||||
 | 
							if (!ts)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		ts = thread->ts;
 | 
					 | 
				
			||||||
		ts->comm = comm;
 | 
							ts->comm = comm;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -621,8 +721,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the stack is empty, put the current symbol on the stack */
 | 
						/* If the stack is empty, put the current symbol on the stack */
 | 
				
			||||||
	if (!ts->cnt) {
 | 
						if (!ts->cnt) {
 | 
				
			||||||
		err = thread_stack__bottom(thread, ts, sample, from_al, to_al,
 | 
							err = thread_stack__bottom(ts, sample, from_al, to_al, ref);
 | 
				
			||||||
					   ref);
 | 
					 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -671,9 +770,11 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t thread_stack__depth(struct thread *thread)
 | 
					size_t thread_stack__depth(struct thread *thread, int cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!thread->ts)
 | 
						struct thread_stack *ts = thread__stack(thread, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ts)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return thread->ts->cnt;
 | 
						return ts->cnt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,14 +80,14 @@ struct call_return_processor {
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 | 
					int thread_stack__event(struct thread *thread, int cpu, u32 flags, u64 from_ip,
 | 
				
			||||||
			u64 to_ip, u16 insn_len, u64 trace_nr);
 | 
								u64 to_ip, u16 insn_len, u64 trace_nr);
 | 
				
			||||||
void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);
 | 
					void thread_stack__set_trace_nr(struct thread *thread, int cpu, u64 trace_nr);
 | 
				
			||||||
void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
 | 
					void thread_stack__sample(struct thread *thread, int cpu, struct ip_callchain *chain,
 | 
				
			||||||
			  size_t sz, u64 ip, u64 kernel_start);
 | 
								  size_t sz, u64 ip, u64 kernel_start);
 | 
				
			||||||
int thread_stack__flush(struct thread *thread);
 | 
					int thread_stack__flush(struct thread *thread);
 | 
				
			||||||
void thread_stack__free(struct thread *thread);
 | 
					void thread_stack__free(struct thread *thread);
 | 
				
			||||||
size_t thread_stack__depth(struct thread *thread);
 | 
					size_t thread_stack__depth(struct thread *thread, int cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct call_return_processor *
 | 
					struct call_return_processor *
 | 
				
			||||||
call_return_processor__new(int (*process)(struct call_return *cr, void *data),
 | 
					call_return_processor__new(int (*process)(struct call_return *cr, void *data),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,13 +9,13 @@ ifeq ("$(origin O)", "command line")
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
turbostat : turbostat.c
 | 
					turbostat : turbostat.c
 | 
				
			||||||
CFLAGS +=	-Wall
 | 
					override CFLAGS +=	-Wall
 | 
				
			||||||
CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 | 
					override CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 | 
				
			||||||
CFLAGS +=	-DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
 | 
					override CFLAGS +=	-DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%: %.c
 | 
					%: %.c
 | 
				
			||||||
	@mkdir -p $(BUILD_OUTPUT)
 | 
						@mkdir -p $(BUILD_OUTPUT)
 | 
				
			||||||
	$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
 | 
						$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY : clean
 | 
					.PHONY : clean
 | 
				
			||||||
clean :
 | 
					clean :
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,12 +9,12 @@ ifeq ("$(origin O)", "command line")
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
x86_energy_perf_policy : x86_energy_perf_policy.c
 | 
					x86_energy_perf_policy : x86_energy_perf_policy.c
 | 
				
			||||||
CFLAGS +=	-Wall
 | 
					override CFLAGS +=	-Wall
 | 
				
			||||||
CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 | 
					override CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%: %.c
 | 
					%: %.c
 | 
				
			||||||
	@mkdir -p $(BUILD_OUTPUT)
 | 
						@mkdir -p $(BUILD_OUTPUT)
 | 
				
			||||||
	$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
 | 
						$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY : clean
 | 
					.PHONY : clean
 | 
				
			||||||
clean :
 | 
					clean :
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,13 +6,13 @@ VERSION = 1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BINDIR=usr/bin
 | 
					BINDIR=usr/bin
 | 
				
			||||||
WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
 | 
					WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
 | 
				
			||||||
CFLAGS+= -O1 ${WARNFLAGS}
 | 
					override CFLAGS+= -O1 ${WARNFLAGS}
 | 
				
			||||||
# Add "-fstack-protector" only if toolchain supports it.
 | 
					# Add "-fstack-protector" only if toolchain supports it.
 | 
				
			||||||
CFLAGS+= $(call cc-option,-fstack-protector)
 | 
					override CFLAGS+= $(call cc-option,-fstack-protector-strong)
 | 
				
			||||||
CC?= $(CROSS_COMPILE)gcc
 | 
					CC?= $(CROSS_COMPILE)gcc
 | 
				
			||||||
PKG_CONFIG?= pkg-config
 | 
					PKG_CONFIG?= pkg-config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS+=-D VERSION=\"$(VERSION)\"
 | 
					override CFLAGS+=-D VERSION=\"$(VERSION)\"
 | 
				
			||||||
LDFLAGS+=
 | 
					LDFLAGS+=
 | 
				
			||||||
TARGET=tmon
 | 
					TARGET=tmon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ TMON_LIBS += $(shell $(PKG_CONFIG) --libs $(STATIC) panelw ncursesw 2> /dev/null
 | 
				
			||||||
		     $(PKG_CONFIG) --libs $(STATIC) panel ncurses 2> /dev/null || \
 | 
							     $(PKG_CONFIG) --libs $(STATIC) panel ncurses 2> /dev/null || \
 | 
				
			||||||
		     echo -lpanel -lncurses)
 | 
							     echo -lpanel -lncurses)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS    += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
 | 
					override CFLAGS += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
 | 
				
			||||||
		     $(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null)
 | 
							     $(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJS = tmon.o tui.o sysfs.o pid.o
 | 
					OBJS = tmon.o tui.o sysfs.o pid.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue