2018-04-25 15:18:03 +03:00
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Traceprobe fetch helper inlines
*/
static nokprobe_inline void
fetch_store_raw ( unsigned long val , struct fetch_insn * code , void * buf )
{
switch ( code - > size ) {
case 1 :
* ( u8 * ) buf = ( u8 ) val ;
break ;
case 2 :
* ( u16 * ) buf = ( u16 ) val ;
break ;
case 4 :
* ( u32 * ) buf = ( u32 ) val ;
break ;
case 8 :
//TBD: 32bit signed
* ( u64 * ) buf = ( u64 ) val ;
break ;
default :
* ( unsigned long * ) buf = val ;
}
}
static nokprobe_inline void
fetch_apply_bitfield ( struct fetch_insn * code , void * buf )
{
switch ( code - > basesize ) {
case 1 :
* ( u8 * ) buf < < = code - > lshift ;
* ( u8 * ) buf > > = code - > rshift ;
break ;
case 2 :
* ( u16 * ) buf < < = code - > lshift ;
* ( u16 * ) buf > > = code - > rshift ;
break ;
case 4 :
* ( u32 * ) buf < < = code - > lshift ;
* ( u32 * ) buf > > = code - > rshift ;
break ;
case 8 :
* ( u64 * ) buf < < = code - > lshift ;
* ( u64 * ) buf > > = code - > rshift ;
break ;
}
}
2018-04-25 15:19:01 +03:00
/*
* This must be defined for each callsite .
* Return consumed dynamic data size ( > = 0 ) , or error ( < 0 ) .
* If dest is NULL , don ' t store result and return required dynamic data size .
*/
2018-04-25 15:18:03 +03:00
static int
process_fetch_insn ( struct fetch_insn * code , struct pt_regs * regs ,
2018-04-25 15:19:01 +03:00
void * dest , void * base ) ;
2018-04-25 15:18:03 +03:00
/* Sum up total data length for dynamic arraies (strings) */
static nokprobe_inline int
__get_data_size ( struct trace_probe * tp , struct pt_regs * regs )
{
struct probe_arg * arg ;
2018-04-25 15:19:01 +03:00
int i , len , ret = 0 ;
2018-04-25 15:18:03 +03:00
for ( i = 0 ; i < tp - > nr_args ; i + + ) {
arg = tp - > args + i ;
if ( unlikely ( arg - > dynamic ) ) {
2018-04-25 15:19:01 +03:00
len = process_fetch_insn ( arg - > code , regs , NULL , NULL ) ;
if ( len > 0 )
ret + = len ;
2018-04-25 15:18:03 +03:00
}
}
return ret ;
}
/* Store the value of each argument */
static nokprobe_inline void
2018-04-25 15:19:01 +03:00
store_trace_args ( void * data , struct trace_probe * tp , struct pt_regs * regs ,
int header_size , int maxlen )
2018-04-25 15:18:03 +03:00
{
struct probe_arg * arg ;
2018-04-25 15:19:01 +03:00
void * base = data - header_size ;
void * dyndata = data + tp - > size ;
u32 * dl ; /* Data location */
int ret , i ;
2018-04-25 15:18:03 +03:00
for ( i = 0 ; i < tp - > nr_args ; i + + ) {
arg = tp - > args + i ;
2018-04-25 15:19:01 +03:00
dl = data + arg - > offset ;
/* Point the dynamic data area if needed */
if ( unlikely ( arg - > dynamic ) )
* dl = make_data_loc ( maxlen , dyndata - base ) ;
ret = process_fetch_insn ( arg - > code , regs , dl , base ) ;
if ( unlikely ( ret < 0 & & arg - > dynamic ) )
* dl = make_data_loc ( 0 , dyndata - base ) ;
else
dyndata + = ret ;
2018-04-25 15:18:03 +03:00
}
}
static inline int
print_probe_args ( struct trace_seq * s , struct probe_arg * args , int nr_args ,
u8 * data , void * field )
{
int i ;
for ( i = 0 ; i < nr_args ; i + + ) {
trace_seq_printf ( s , " %s= " , args [ i ] . name ) ;
if ( ! args [ i ] . type - > print ( s , data + args [ i ] . offset , field ) )
return - ENOMEM ;
}
return 0 ;
}