2016-10-03 01:35:53 +03:00
/*
* Check verbose decoding of perf_event_open syscall .
*
* Copyright ( c ) 2016 Eugene Syromyatnikov < evgsyr @ gmail . com >
2018-02-13 22:00:00 +00:00
* Copyright ( c ) 2016 - 2018 The strace developers .
2016-10-03 01:35:53 +03:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "tests.h"
# include <asm/unistd.h>
# if defined(__NR_perf_event_open) && defined(HAVE_LINUX_PERF_EVENT_H)
# include <inttypes.h>
# include <limits.h>
# include <stddef.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <linux / perf_event.h>
# include "xlat.h"
# include "xlat / perf_event_open_flags.h"
# include "xlat / perf_attr_size.h"
# if ULONG_MAX > UINT_MAX /* Poor man's "whether long is 8 bytes?" */
# define LONG_STR_PREFIX "ffffffff"
# else /* !(ULONG_MAX > UINT_MAX) */
# define LONG_STR_PREFIX ""
# endif /* ULONG_MAX > UINT_MAX */
# ifndef PERF_TYPE_BREAKPOINT
# define PERF_TYPE_BREAKPOINT 5
# endif
struct s32_val_str {
int32_t val ;
const char * str ;
} ;
struct u32_val_str {
uint32_t val ;
const char * str ;
} ;
struct u64_val_str {
uint64_t val ;
const char * str ;
} ;
2017-06-16 22:54:04 +00:00
/* In order to avoid endianness-specific hackery. */
2016-10-03 01:35:53 +03:00
struct pea_flags {
2017-06-17 22:23:09 +00:00
uint64_t disabled : 1 ,
inherit : 1 ,
pinned : 1 ,
exclusive : 1 ,
exclude_user : 1 ,
exclude_kernel : 1 ,
exclude_hv : 1 ,
exclude_idle : 1 ,
mmap : 1 ,
comm : 1 ,
freq : 1 ,
inherit_stat : 1 ,
enable_on_exec : 1 ,
task : 1 ,
watermark : 1 ,
precise_ip : 2 ,
mmap_data : 1 ,
sample_id_all : 1 ,
exclude_host : 1 ,
exclude_guest : 1 ,
exclude_callchain_kernel : 1 ,
exclude_callchain_user : 1 ,
mmap2 : 1 ,
comm_exec : 1 ,
use_clockid : 1 ,
context_switch : 1 ,
write_backward : 1 ,
2018-01-08 19:48:42 +01:00
namespaces : 1 ,
__reserved_1 : 35 ;
2016-10-03 01:35:53 +03:00
} ;
static const char *
printaddr ( void * ptr )
{
static char buf [ sizeof ( " 0x " ) + sizeof ( void * ) * 2 ] ;
if ( ptr = = NULL )
return " NULL " ;
snprintf ( buf , sizeof ( buf ) , " %#lx " , ( unsigned long ) ptr ) ;
return buf ;
}
/*
* Checklist :
*
* type - 8 IDs
* config - 13 IDs ( 0. .11 + random ) , depends on type
* sample type - bitmask , up to 20 bits
* read_format - 5 IDs
* bp_type - 6 , weird semantics ( invalid / unknown )
* branch_sample_type - bitmask , 16 bits
* clockid - 13 values
*
* Unions :
* sample_period / sample_freq
* wakeup_event / wakeup_watermark
* bp_addr / config1
* bp_len / config2
*/
/*
* The main idea behind all those numerous ifdefs is checking against version of
* structure provided in kernel headers and not use one defined in strace
* headers ( assume the case when suddenly we add flag without proper update of
* __reserved_1 field or something like this ) .
*/
static void
print_event_attr ( struct perf_event_attr * attr_ptr , size_t size ,
const char * type , const char * config , const char * sample_type ,
const char * read_format , const char * precise_ip_desc ,
const char * bp_type , const char * branch_sample_type ,
const char * clockid , uint32_t available_size )
{
/*
* Currently , strace supports version 5 of the structure , which is
* 112 bytes in size .
*/
enum {
STRACE_PEA_ABBREV_SIZE =
offsetof ( struct perf_event_attr , config ) +
sizeof ( attr_ptr - > config ) ,
STRACE_PEA_SIZE = 112 ,
} ;
uint32_t read_size ;
struct perf_event_attr * attr ;
# if VERBOSE
uint32_t cutoff ;
uint64_t val ;
uint64_t use_clockid ;
union {
struct pea_flags flags ;
uint64_t raw ;
} flags_data ;
# endif
read_size =
# if !VERBOSE
STRACE_PEA_ABBREV_SIZE ;
# else
size < STRACE_PEA_SIZE ?
( size ? size : PERF_ATTR_SIZE_VER0 ) : STRACE_PEA_SIZE ;
# endif
if ( read_size > available_size ) {
printf ( " %s " , printaddr ( attr_ptr ) ) ;
return ;
}
/*
* Replicate kernel ' s behaviour regarding copying structure from
* userspace .
*/
attr = calloc ( 1 , STRACE_PEA_SIZE ) ;
if ( ! attr )
error_msg_and_fail ( " calloc " ) ;
memcpy ( attr , attr_ptr , read_size ) ;
if ( size & & ( size < PERF_ATTR_SIZE_VER0 ) ) {
printf ( " %s " , printaddr ( attr_ptr ) ) ;
free ( attr ) ;
return ;
}
printf ( " {type=%s, size= " , type ) ;
if ( size ! = attr - > size ) {
printxval ( perf_attr_size , size , " PERF_ATTR_SIZE_??? " ) ;
printf ( " => " ) ;
}
printxval ( perf_attr_size , attr - > size , " PERF_ATTR_SIZE_??? " ) ;
printf ( " , config=%s, " , config ) ;
if ( ! size )
size = PERF_ATTR_SIZE_VER0 ;
# if !VERBOSE
printf ( " ...} " ) ;
# else /* !VERBOSE */
printf ( " %s=% " PRI__u64 " , sample_type=%s, read_format=%s " ,
attr - > freq ? " sample_freq " : " sample_period " ,
attr - > freq ? attr - > sample_freq : attr - > sample_period ,
sample_type , read_format ) ;
printf ( " , disabled=%u "
" , inherit=%u "
" , pinned=%u "
" , exclusive=%u "
" , exclusive_user=%u "
" , exclude_kernel=%u "
" , exclude_hv=%u "
" , exclude_idle=%u "
" , mmap=%u "
" , comm=%u "
" , freq=%u "
" , inherit_stat=%u "
" , enable_on_exec=%u "
" , task=%u "
" , watermark=%u " ,
attr - > disabled ,
attr - > inherit ,
attr - > pinned ,
attr - > exclusive ,
attr - > exclude_user ,
attr - > exclude_kernel ,
attr - > exclude_hv ,
attr - > exclude_idle ,
attr - > mmap ,
attr - > comm ,
attr - > freq ,
attr - > inherit_stat ,
attr - > enable_on_exec ,
attr - > task ,
attr - > watermark ) ;
flags_data . raw = ( ( uint64_t * ) attr ) [ 5 ] ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_PRECISE_IP
attr - > precise_ip ;
# else
flags_data . flags . precise_ip ;
# endif
printf ( " , precise_ip=% " PRIu64 " /* %s */ " , val , precise_ip_desc ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_MMAP_DATA
attr - > mmap_data ;
# else
flags_data . flags . mmap_data ;
# endif
printf ( " , mmap_data=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_ID_ALL
attr - > sample_id_all ;
# else
flags_data . flags . sample_id_all ;
# endif
printf ( " , sample_id_all=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_HOST
attr - > exclude_host ;
# else
flags_data . flags . exclude_host ;
# endif
printf ( " , exclude_host=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_GUEST
attr - > exclude_guest ;
# else
flags_data . flags . exclude_guest ;
# endif
printf ( " , exclude_guest=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_CALLCHAIN_KERNEL
attr - > exclude_callchain_kernel ;
# else
flags_data . flags . exclude_callchain_kernel ;
# endif
printf ( " , exclude_callchain_kernel=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_CALLCHAIN_USER
attr - > exclude_callchain_user ;
# else
flags_data . flags . exclude_callchain_user ;
# endif
printf ( " , exclude_callchain_user=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_MMAP2
attr - > mmap2 ;
# else
flags_data . flags . mmap2 ;
# endif
printf ( " , mmap2=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_COMM_EXEC
attr - > comm_exec ;
# else
flags_data . flags . comm_exec ;
# endif
printf ( " , comm_exec=% " PRIu64 , val ) ;
use_clockid = val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_USE_CLOCKID
attr - > use_clockid ;
# else
flags_data . flags . use_clockid ;
# endif
printf ( " , use_clockid=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CONTEXT_SWITCH
attr - > context_switch ;
# else
flags_data . flags . context_switch ;
# endif
printf ( " , context_switch=% " PRIu64 , val ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_WRITE_BACKWARD
attr - > write_backward ;
# else
flags_data . flags . write_backward ;
# endif
printf ( " , write_backward=% " PRIu64 , val ) ;
2018-01-08 19:48:42 +01:00
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_NAMESPACES
attr - > namespaces ;
# else
flags_data . flags . namespaces ;
# endif
printf ( " , namespaces=% " PRIu64 , val ) ;
2016-10-03 01:35:53 +03:00
val = flags_data . flags . __reserved_1 ;
if ( val )
2018-01-08 19:48:42 +01:00
printf ( " , __reserved_1=%# " PRIx64 " /* Bits 63..29 */ " , val ) ;
2016-10-03 01:35:53 +03:00
printf ( " , %s=%u " ,
attr - > watermark ? " wakeup_watermark " : " wakeup_events " ,
attr - > watermark ? attr - > wakeup_watermark : attr - > wakeup_events ) ;
if ( attr - > type = = PERF_TYPE_BREAKPOINT )
printf ( " , bp_type=%s " , bp_type ) ;
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CONFIG1
attr - > config1 ;
# else
( ( uint64_t * ) attr ) [ 56 / sizeof ( uint64_t ) ] ;
# endif
printf ( " , %s=%# " PRIx64 ,
attr - > type = = PERF_TYPE_BREAKPOINT ? " bp_addr " : " config1 " ,
val ) ;
/* End of version 0 of the structure */
if ( size < = 64 ) {
cutoff = 64 ;
goto end ;
}
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CONFIG2
attr - > config2 ;
# else
( ( uint64_t * ) attr ) [ 64 / sizeof ( uint64_t ) ] ;
# endif
if ( attr - > type = = PERF_TYPE_BREAKPOINT )
printf ( " , bp_len=% " PRIu64 , val ) ;
else
printf ( " , config2=%# " PRIx64 , val ) ;
/* End of version 1 of the structure */
if ( size < = 72 ) {
cutoff = 72 ;
goto end ;
}
/*
* Print branch sample type only in case PERF_SAMPLE_BRANCH_STACK
* is set in the sample_type field .
*/
if ( attr - > sample_type & ( 1 < < 11 ) )
printf ( " , branch_sample_type=%s " , branch_sample_type ) ;
/* End of version 2 of the structure */
if ( size < = 80 ) {
cutoff = 80 ;
goto end ;
}
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_REGS_USER
attr - > sample_regs_user ;
# else
( ( uint64_t * ) attr ) [ 80 / sizeof ( uint64_t ) ] ;
# endif
printf ( " , sample_regs_user=%# " PRIx64 , val ) ;
if ( size < = 88 ) {
cutoff = 88 ;
goto end ;
}
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_STACK_USER
attr - > sample_stack_user ;
# else
( ( uint32_t * ) attr ) [ 88 / sizeof ( uint32_t ) ] ;
# endif
/*
* Print branch sample type only in case PERF_SAMPLE_STACK_USER
* is set in the sample_type field .
*/
if ( attr - > sample_type & ( 1 < < 13 ) )
printf ( " , sample_stack_user=%# " PRIx32 , ( uint32_t ) val ) ;
if ( size < = 92 ) {
cutoff = 92 ;
goto end ;
}
if ( use_clockid )
printf ( " , clockid=%s " , clockid ) ;
/* End of version 3 of the structure */
if ( size < = 96 ) {
cutoff = 96 ;
goto end ;
}
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_REGS_INTR
attr - > sample_regs_intr ;
# else
( ( uint64_t * ) attr ) [ 96 / sizeof ( uint64_t ) ] ;
# endif
printf ( " , sample_regs_intr=%# " PRIx64 , val ) ;
/* End of version 4 of the structure */
if ( size < = 104 ) {
2017-06-17 22:23:09 +00:00
cutoff = 104 ;
2016-10-03 01:35:53 +03:00
goto end ;
}
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_AUX_WATERMARK
attr - > aux_watermark ;
# else
( ( uint32_t * ) attr ) [ 104 / sizeof ( uint32_t ) ] ;
# endif
printf ( " , aux_watermark=% " PRIu32 , ( uint32_t ) val ) ;
if ( size < = 108 ) {
2017-06-17 22:23:09 +00:00
cutoff = 108 ;
2016-10-03 01:35:53 +03:00
goto end ;
}
val =
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_MAX_STACK
attr - > sample_max_stack ;
# else
( ( uint16_t * ) attr ) [ 108 / sizeof ( uint16_t ) ] ;
# endif
printf ( " , sample_max_stack=% " PRIu16 , ( uint16_t ) val ) ;
if ( size < = 110 ) {
2017-06-17 22:23:09 +00:00
cutoff = 110 ;
2016-10-03 01:35:53 +03:00
goto end ;
}
cutoff = STRACE_PEA_SIZE ;
end :
if ( size > cutoff )
printf ( " , ... " ) ;
printf ( " } " ) ;
# endif /* !VERBOSE */
free ( attr ) ;
}
/* These require aligned access, so no byte-grain checks possible */
# if defined SPARC || defined SPARC64 || defined POWERPC || defined POWERPC64
# define ATTR_REC(sz) { tail_alloc((sz + 7) & ~7), sz }
# else
# define ATTR_REC(sz) { tail_alloc(sz), sz }
# endif
# define BRANCH_TYPE_ALL \
" PERF_SAMPLE_BRANCH_USER| " \
" PERF_SAMPLE_BRANCH_KERNEL| " \
" PERF_SAMPLE_BRANCH_HV| " \
" PERF_SAMPLE_BRANCH_ANY| " \
" PERF_SAMPLE_BRANCH_ANY_CALL| " \
" PERF_SAMPLE_BRANCH_ANY_RETURN| " \
" PERF_SAMPLE_BRANCH_IND_CALL| " \
" PERF_SAMPLE_BRANCH_ABORT_TX| " \
" PERF_SAMPLE_BRANCH_IN_TX| " \
" PERF_SAMPLE_BRANCH_NO_TX| " \
" PERF_SAMPLE_BRANCH_COND| " \
" PERF_SAMPLE_BRANCH_CALL_STACK| " \
" PERF_SAMPLE_BRANCH_IND_JUMP| " \
" PERF_SAMPLE_BRANCH_CALL| " \
" PERF_SAMPLE_BRANCH_NO_FLAGS| " \
2018-01-08 19:52:23 +01:00
" PERF_SAMPLE_BRANCH_NO_CYCLES| " \
" PERF_SAMPLE_BRANCH_TYPE_SAVE "
2016-10-03 01:35:53 +03:00
int
main ( void )
{
static const size_t attr_small_size = PERF_ATTR_SIZE_VER0 - 8 ;
static const size_t attr_v0_size = PERF_ATTR_SIZE_VER0 ;
static const size_t attr_v1_size = PERF_ATTR_SIZE_VER1 ;
static const size_t attr_v2_size = PERF_ATTR_SIZE_VER2 ;
static const size_t attr_v2_5_size = PERF_ATTR_SIZE_VER2 + 8 ;
static const size_t attr_v2_75_size = PERF_ATTR_SIZE_VER2 + 12 ;
static const size_t attr_v3_size = PERF_ATTR_SIZE_VER3 ;
static const size_t attr_v4_size = PERF_ATTR_SIZE_VER4 ;
static const size_t attr_v4_5_size = PERF_ATTR_SIZE_VER4 + 4 ;
static const size_t attr_v4_625_size = PERF_ATTR_SIZE_VER4 + 5 ;
static const size_t attr_v4_875_size = PERF_ATTR_SIZE_VER4 + 7 ;
static const size_t attr_v5_size = PERF_ATTR_SIZE_VER5 ;
static const size_t attr_big_size = PERF_ATTR_SIZE_VER5 + 32 ;
static const struct u64_val_str attr_types [ ] = {
{ ARG_STR ( PERF_TYPE_HARDWARE ) } ,
{ ARG_STR ( PERF_TYPE_SOFTWARE ) } ,
{ ARG_STR ( PERF_TYPE_TRACEPOINT ) } ,
{ ARG_STR ( PERF_TYPE_HW_CACHE ) } ,
{ ARG_STR ( PERF_TYPE_RAW ) } ,
{ ARG_STR ( PERF_TYPE_BREAKPOINT ) } ,
{ ARG_STR ( 0x6 ) " /* PERF_TYPE_??? */ " } ,
{ ARG_STR ( 0xdeadc0de ) " /* PERF_TYPE_??? */ " } ,
} ;
static const struct u64_val_str
attr_configs [ ARRAY_SIZE ( attr_types ) ] [ 3 ] = {
/* PERF_TYPE_HARDWARE */ {
{ 9 , " PERF_COUNT_HW_REF_CPU_CYCLES " } ,
{ 10 , " 0xa /* PERF_COUNT_HW_??? */ " } ,
{ ARG_ULL_STR ( 0xfaceca75deadb0d4 )
" /* PERF_COUNT_HW_??? */ " } ,
} ,
/* PERF_TYPE_SOFTWARE */ {
{ 10 , " PERF_COUNT_SW_BPF_OUTPUT " } ,
{ 11 , " 0xb /* PERF_COUNT_SW_??? */ " } ,
{ ARG_ULL_STR ( 0xdec0ded1dec0ded2 )
" /* PERF_COUNT_SW_??? */ " } ,
} ,
/* PERF_TYPE_TRACEPOINT */ {
{ ARG_STR ( 0 ) } ,
{ 4207856245U , " 4207856245 " } ,
{ ARG_ULL_STR ( 16051074073505095380 ) } ,
} ,
/* PERF_TYPE_HW_CACHE */ {
{ 0 , " PERF_COUNT_HW_CACHE_L1D| "
" PERF_COUNT_HW_CACHE_OP_READ<<8| "
" PERF_COUNT_HW_CACHE_RESULT_ACCESS<<16 " } ,
{ 0x020207 , " 0x7 /* PERF_COUNT_HW_CACHE_??? */| "
" PERF_COUNT_HW_CACHE_OP_PREFETCH<<8| "
" 0x2 /* PERF_COUNT_HW_CACHE_RESULT_??? */<<16 " } ,
{ 0xdeadf157ed010306ULL , " PERF_COUNT_HW_CACHE_NODE| "
" 0x3 /* PERF_COUNT_HW_CACHE_OP_??? */<<8| "
" PERF_COUNT_HW_CACHE_RESULT_MISS<<16| "
" 0xdeadf157ed<<24 "
" /* PERF_COUNT_HW_CACHE_??? */ " } ,
} ,
/* PERF_TYPE_RAW */ {
{ ARG_STR ( 0 ) } ,
{ ARG_STR ( 0xda7a1057 ) } ,
{ ARG_ULL_STR ( 0xdec0ded7dec0ded8 ) } ,
} ,
/* PERF_TYPE_BREAKPOINT */ {
{ ARG_STR ( 0 ) } ,
{ ARG_STR ( 0xbadc0ded ) } ,
{ ARG_ULL_STR ( 0xdec0ded9dec0deda ) } ,
} ,
/* invalid 1 */ {
{ ARG_STR ( 0 ) } ,
{ ARG_STR ( 0xbeeff00d ) } ,
{ ARG_ULL_STR ( 0xdec0dedbdec0dedc ) } ,
} ,
/* invalid 2 */ {
{ ARG_STR ( 0 ) } ,
{ ARG_STR ( 0xca75dead ) } ,
{ ARG_ULL_STR ( 0xdec0dedddec0dede ) } ,
} ,
} ;
static const struct u64_val_str sample_types [ ] = {
{ ARG_STR ( 0 ) } ,
{ 0x800 , " PERF_SAMPLE_BRANCH_STACK " } ,
2018-01-08 19:52:23 +01:00
{ ARG_ULL_STR ( 0xdeadc0deda700000 ) " /* PERF_SAMPLE_??? */ " } ,
2016-10-03 01:35:53 +03:00
{ 0xffffffffffffffffULL ,
" PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_TIME| "
" PERF_SAMPLE_ADDR|PERF_SAMPLE_READ| "
" PERF_SAMPLE_CALLCHAIN|PERF_SAMPLE_ID|PERF_SAMPLE_CPU| "
" PERF_SAMPLE_PERIOD|PERF_SAMPLE_STREAM_ID| "
" PERF_SAMPLE_RAW|PERF_SAMPLE_BRANCH_STACK| "
" PERF_SAMPLE_REGS_USER|PERF_SAMPLE_STACK_USER| "
" PERF_SAMPLE_WEIGHT|PERF_SAMPLE_DATA_SRC| "
" PERF_SAMPLE_IDENTIFIER|PERF_SAMPLE_TRANSACTION| "
2018-01-08 19:52:23 +01:00
" PERF_SAMPLE_REGS_INTR|PERF_SAMPLE_PHYS_ADDR| "
" 0xfffffffffff00000 " } ,
2016-10-03 01:35:53 +03:00
} ;
static const struct u64_val_str read_formats [ ] = {
{ ARG_STR ( 0 ) } ,
{ ARG_STR ( PERF_FORMAT_TOTAL_TIME_ENABLED ) } ,
{ 0xf , " PERF_FORMAT_TOTAL_TIME_ENABLED| "
" PERF_FORMAT_TOTAL_TIME_RUNNING| "
" PERF_FORMAT_ID|PERF_FORMAT_GROUP " } ,
{ ARG_ULL_STR ( 0xdeadf157dec0ded0 ) " /* PERF_FORMAT_??? */ " } ,
{ 0xffffffffffffffffULL ,
" PERF_FORMAT_TOTAL_TIME_ENABLED| "
" PERF_FORMAT_TOTAL_TIME_RUNNING| "
" PERF_FORMAT_ID|PERF_FORMAT_GROUP| "
" 0xfffffffffffffff0 " } ,
} ;
static const char * precise_ip_descs [ ] = {
" arbitrary skid " ,
" constant skid " ,
" requested to have 0 skid " ,
" must have 0 skid " ,
} ;
static const struct u32_val_str bp_types [ ] = {
{ 0 , " HW_BREAKPOINT_EMPTY " } ,
{ 1 , " HW_BREAKPOINT_R " } ,
{ 3 , " HW_BREAKPOINT_RW " } ,
{ 5 , " 0x5 /* HW_BREAKPOINT_INVALID */ " } ,
{ 8 , " 0x8 /* HW_BREAKPOINT_??? */ " } ,
{ ARG_STR ( 0xface1e55 ) " /* HW_BREAKPOINT_??? */ " } ,
} ;
static const struct u64_val_str branch_sample_types [ ] = {
{ ARG_STR ( 0 ) } ,
{ 0x80 , " PERF_SAMPLE_BRANCH_ABORT_TX " } ,
2018-01-08 19:52:23 +01:00
{ 0x1ffff , BRANCH_TYPE_ALL } ,
{ ARG_ULL_STR ( 0xdeadcaffeeec0000 )
2016-10-03 01:35:53 +03:00
" /* PERF_SAMPLE_BRANCH_??? */ " } ,
{ 0xffffffffffffffffULL ,
2018-01-08 19:52:23 +01:00
BRANCH_TYPE_ALL " |0xfffffffffffe0000 " }
2016-10-03 01:35:53 +03:00
} ;
static const struct s32_val_str clockids [ ] = {
{ 11 , " CLOCK_TAI " } ,
{ ARG_STR ( 0xc ) " /* CLOCK_??? */ " } ,
{ ARG_STR ( 0xbeeffeed ) " /* CLOCK_??? */ " } ,
} ;
struct {
struct perf_event_attr * ptr ;
size_t size ;
} attrs [ ] = {
ATTR_REC ( sizeof ( struct perf_event_attr ) ) ,
ATTR_REC ( attr_v0_size ) ,
ATTR_REC ( attr_v1_size ) ,
ATTR_REC ( attr_v2_size ) ,
ATTR_REC ( attr_v2_5_size ) ,
ATTR_REC ( attr_v2_75_size ) ,
ATTR_REC ( attr_v3_size ) ,
ATTR_REC ( attr_v4_size ) ,
ATTR_REC ( attr_v4_5_size ) ,
ATTR_REC ( attr_v4_625_size ) ,
ATTR_REC ( attr_v4_875_size ) ,
ATTR_REC ( attr_v5_size ) ,
ATTR_REC ( attr_big_size ) ,
} ;
2017-03-16 13:46:36 +00:00
TAIL_ALLOC_OBJECT_CONST_PTR ( struct perf_event_attr , small_attr ) ;
2016-10-03 01:35:53 +03:00
struct {
struct perf_event_attr * attr ;
pid_t pid ;
int cpu ;
int group_fd ;
unsigned long flags ;
const char * flags_str ;
} args [ ] = {
{ NULL , 0xfacef00d , 0xbadabba7 , - 1 ,
( unsigned long ) 0xFFFFFFFFFFFFFFFFLLU ,
" PERF_FLAG_FD_NO_GROUP|PERF_FLAG_FD_OUTPUT| "
" PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC| "
" 0x " LONG_STR_PREFIX " fffffff0 "
} ,
{ small_attr + 1 , 0 , 0 , 0 ,
0 , " 0 " } ,
{ small_attr , - 1 , - 1 , 1 ,
PERF_FLAG_FD_NO_GROUP | PERF_FLAG_FD_OUTPUT |
PERF_FLAG_PID_CGROUP | PERF_FLAG_FD_CLOEXEC ,
" PERF_FLAG_FD_NO_GROUP|PERF_FLAG_FD_OUTPUT| "
" PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC " } ,
{ ( struct perf_event_attr * ) ( uintptr_t ) 0xfffffacefffffeedULL ,
- 100 , 100 , 0xface1e55 ,
PERF_FLAG_FD_CLOEXEC , " PERF_FLAG_FD_CLOEXEC " } ,
} ;
size_t i ;
int rc ;
2017-01-04 22:17:26 +00:00
fill_memory ( small_attr , sizeof ( * small_attr ) ) ;
2016-10-03 01:35:53 +03:00
small_attr - > size = attr_small_size ;
for ( i = 0 ; i < ARRAY_SIZE ( args ) ; i + + ) {
rc = syscall ( __NR_perf_event_open , args [ i ] . attr , args [ i ] . pid ,
2017-06-17 22:23:09 +00:00
args [ i ] . cpu , args [ i ] . group_fd , args [ i ] . flags ) ;
2016-10-03 01:35:53 +03:00
printf ( " perf_event_open(%s, %d, %d, %d, %s) = %s \n " ,
printaddr ( args [ i ] . attr ) , args [ i ] . pid , args [ i ] . cpu ,
args [ i ] . group_fd , args [ i ] . flags_str , sprintrc ( rc ) ) ;
}
for ( i = 0 ; i < ARRAY_SIZE ( attrs ) * ARRAY_SIZE ( attr_types ) *
ARRAY_SIZE ( attr_configs [ 0 ] ) + 1 ; i + + ) {
struct perf_event_attr * attr = attrs [ i % ARRAY_SIZE ( attrs ) ] . ptr ;
uint32_t size = attrs [ i % ARRAY_SIZE ( attrs ) ] . size ;
unsigned char fill_start = 0x80 + i ;
size_t type_idx = i % ARRAY_SIZE ( attr_types ) ;
size_t config_idx = i % ARRAY_SIZE ( attr_configs [ 0 ] ) ;
size_t sample_type_idx = i % ARRAY_SIZE ( sample_types ) ;
size_t read_format_idx = i % ARRAY_SIZE ( read_formats ) ;
size_t bp_type_idx = ( i / ARRAY_SIZE ( attr_configs [ 0 ] ) ) %
ARRAY_SIZE ( bp_types ) ;
size_t branch_sample_type_idx = ( i / ARRAY_SIZE ( sample_types ) ) %
ARRAY_SIZE ( branch_sample_types ) ;
size_t clockid_idx = i % ARRAY_SIZE ( clockids ) ;
size_t args_idx = i % ARRAY_SIZE ( args ) ;
const char * ip_desc_str ;
2017-01-04 22:17:26 +00:00
fill_memory_ex ( attr , size , fill_start , 0xff ) ;
2016-10-03 01:35:53 +03:00
attr - > type = attr_types [ type_idx ] . val ;
attr - > size = size ;
attr - > config = attr_configs [ type_idx ] [ config_idx ] . val ;
attr - > sample_type = sample_types [ sample_type_idx ] . val ;
attr - > read_format = read_formats [ read_format_idx ] . val ;
if ( ( i % 11 ) = = 5 )
attr - > __reserved_1 = 0 ;
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_BP_TYPE
attr - > bp_type =
# else
( ( uint32_t * ) attr ) [ 52 / sizeof ( uint32_t ) ] =
# endif
bp_types [ bp_type_idx ] . val ;
if ( size > = 80 )
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_BRANCH_SAMPLE_TYPE
attr - > branch_sample_type =
# else
( ( uint64_t * ) attr ) [ 72 / sizeof ( uint64_t ) ] =
# endif
branch_sample_types [ branch_sample_type_idx ] . val ;
if ( size > = 96 )
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CLOCKID
attr - > clockid =
# else
( ( uint32_t * ) attr ) [ 92 / sizeof ( uint32_t ) ] =
# endif
clockids [ clockid_idx ] . val ;
# ifdef HAVE_STRUCT_PERF_EVENT_ATTR_PRECISE_IP
ip_desc_str = precise_ip_descs [ attr - > precise_ip ] ;
# else
union {
struct pea_flags flags ;
uint64_t raw ;
} flags_data = { . raw = ( ( uint64_t * ) attr ) [ 5 ] } ;
ip_desc_str = precise_ip_descs [ flags_data . flags . precise_ip ] ;
# endif
if ( i = = 0 )
attr - > size = size + 8 ;
if ( i = = 1 )
attr - > size = 0 ;
rc = syscall ( __NR_perf_event_open , attr , args [ args_idx ] . pid ,
2017-06-17 22:23:09 +00:00
args [ args_idx ] . cpu , args [ args_idx ] . group_fd ,
args [ args_idx ] . flags ) ;
2016-10-03 01:35:53 +03:00
printf ( " perf_event_open( " ) ;
print_event_attr ( attr , i ? ( ( i = = 1 ) ? 0 : size ) : size + 8 ,
2017-06-17 22:23:09 +00:00
attr_types [ type_idx ] . str ,
attr_configs [ type_idx ] [ config_idx ] . str ,
sample_types [ sample_type_idx ] . str ,
read_formats [ read_format_idx ] . str ,
ip_desc_str ,
bp_types [ bp_type_idx ] . str ,
branch_sample_types [ branch_sample_type_idx ] . str ,
clockids [ clockid_idx ] . str , size ) ;
2016-10-03 01:35:53 +03:00
printf ( " , %d, %d, %d, %s) = %s \n " , args [ args_idx ] . pid ,
args [ args_idx ] . cpu , args [ args_idx ] . group_fd ,
args [ args_idx ] . flags_str , sprintrc ( rc ) ) ;
}
puts ( " +++ exited with 0 +++ " ) ;
return 0 ;
}
# else
SKIP_MAIN_UNDEFINED ( " __NR_perf_event_open && HAVE_LINUX_PERF_EVENT_H " ) ;
# endif